In mature project development, the base package will provide some common functional components of the project, so that each project will not duplicate the wheel. This project encapsulates basic functions commonly used in Springboot project development. At present, this package has unified dependency management, exception handling, response packet packaging, unified log management, sensitive data encryption and decryption and other functions. Support pluggable mode, as long as the introduction of dependencies to have the above functions.

Making address github.com/chenxuancod… Here is how to implement ~~~ (star star star)

Unified dependency Management

Common dependencies are summarized into the basic package to facilitate subsequent component management (such as upgrade or vulnerability repair). The principle of component dependency in the basic package is stability and minimum dependency. At present, Base includes the following components, which basically meet the basic functions of springboot project development. The dependency of the base package of each project is centrally managed by Base. You only need to import the Base module, and the feature package is imported by each project. The current base pack already integrates common base components such as Mybatis – Plus Swagger

Component name version
spring-boot-starter-validation 2.3.12. RELEASE
spring-boot-starter-web 2.3.12. RELEASE
spring-boot-starter-test 2.3.12. RELEASE
spring-boot-starter-aop 2.3.12. RELEASE
mysql-connector-java 8.0.16
mybatis-plus 3.4.0
springfox-swagger2 2.8.0
springfox-swagger-ui 2.8.0
swagger-bootstrap-ui 1.8.5
lombok 1.18.20
hutool-all 5.7.14

Exception handling

A unified global exception handler is defined to encourage exception catching in business code and to throw all exceptions from the DAO, Service, and Controller layers to the upper layer. Reduce the intrusion of try-catch on service code If you want to return a specified error message on an interface, you can throw a customized AiException

throw new ApiException("Two different passwords entered.");
Copy the code

Realize the principle of

Use @RestControllerAdvice to enable global exception catching. Define a method that uses the ExceptionHandler annotation and defines the type of exception to catch.

@Slf4j
@RestControllerAdvice
public class ExceptionControllerAdvice {

    @ExceptionHandler(ApiException.class)
    public ResultVO<String> apiExceptionHandler(ApiException e) {
        log.error("Interface request exception: {}{}",e.getResultCode(),e.getMsg());
        return new ResultVO<>(e.getResultCode(), e.getMsg());
    }

    @ExceptionHandler
    public ResultVO unknownException(Exception e) {
        log.error("An unknown exception has occurred.", e);
        return new ResultVO<>(ResultCode.ERROR, "System error, please contact webmaster!");
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResultVO<String> methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
        // Get the ObjectError object from the exception object
        ObjectError objectError = e.getBindingResult().getAllErrors().get(0);
        return newResultVO<>(ResultCode.VALIDATE_FAILED, objectError.getDefaultMessage()); }}Copy the code

Other exceptions that are not explicitly thrown are automatically recognized as unknown errors by the outer exception handler and returned to the front end

Log processing

In SpringBoot projects, the Logback component is typically used for log management. Therefore, if each service writes its own Logback configuration file, various log formats and log paths will inevitably result in difficult management. Therefore, log processing is handled by the basic package. The following points need to be considered in log processing: How to print logs, split logs, and collect logs

Print entry and exit parameter logs

The Controller method uses @weblog to print request and response messages

@PostMapping("/register")
@apiOperation (value = "register ")
@WebLog
public String register(@RequestBody @Validated RegisterParam param) {
    userService.register(param);
    return "Operation successful";
}
Copy the code

Realize the principle of

Define log section LogAspect,

public class LogAspect {

    @Pointcut("@annotation(com.sleeper.common.base.annotate.WebLog)")
    public void webLog(a) {}


    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        log.info("IP:{} Class Method:{}.{} Request Args: {}",request.getRemoteAddr(),joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName(), new Gson().toJson(joinPoint.getArgs()));
    }

 
    @Around("webLog()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = proceedingJoinPoint.proceed();
        log.info("Response Args : {} Time-Consuming : {} ms".new Gson().toJson(result),System.currentTimeMillis() - startTime);
        returnresult; }}Copy the code

The WebLog comment

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface WebLog {

}
Copy the code

Split and Save logs

Log splitting is configured using logback. Current logs are split into error logs and common logs. Each file type is split on a daily basis. Specific rules below ${LOG_ERROR_HOME} / ${springAppName} – % d – the dd} {yyyy – MM. The % i.l og ${LOG_INFO_HOME} / ${springAppName} – % d – the dd} {yyyy – MM. The % i.l og |

Use AsyncAppender to output logs asynchronously. For complete logback logs, see:

Link to track

At present, link tracing is realized by MDC, which is an important tool to realize distributed multithreaded log data transmission in Slf4J logging system. An introduction to MDC can be found at juejin.cn/post/690122…

Implementation Principle The interceptor intercepts requests, generates traceId, and sets the traceId to THreadLocalMap through the MDC PUT interface

public class LogInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String traceId = request.getHeader("traceId");
        if (traceId == null) {
            traceId = IdUtil.getSnowflake().nextIdStr();
        }
        MDC.put("traceId", traceId);
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
            throws Exception {}@Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        MDC.remove("TRACE_ID");
    }
Copy the code

Add %X{traceId} to logback-spring. XML

<property name="PATTERN" value="%red(%d{yyyy-MM-dd HH:mm:ss.SSS}) %X{traceId} %yellow(%-5level) %highlight([%t]) %boldMagenta([%C]).%green(%method[%L]): %m%n"/>
Copy the code

Automatic encapsulation of response packets

Generally, the interface needs to return a certain structure, including the encoding of service processing result, corresponding text information, and return value. You can use @RestControllerAdvice to enhance Controller to automatically encapsulate response packets

@RestControllerAdvice("com.sleeper")
public class ResponseControllerAdvice implements ResponseBodyAdvice<Object> {
    @Override
    public boolean supports(MethodParameter returnType, Class
       > aClass) {
        // If the interface returns a type that is itself ResultVO there is no need for additional operations, return false
        return! returnType.getParameterType().equals(ResultVO.class) || returnType.hasMethodAnnotation(NotResponseWrap.class); }@Override
    public Object beforeBodyWrite(Object data, MethodParameter returnType, MediaType mediaType, Class
       > aClass, ServerHttpRequest request, ServerHttpResponse response) {
        // The String type cannot be wrapped directly, so something special needs to be done
        if (returnType.getGenericParameterType().equals(String.class)) {
            ObjectMapper objectMapper = new ObjectMapper();
            try {
                // After wrapping the data in ResultVO, it is converted into JSON string response to the front-end
                return objectMapper.writeValueAsString(new ResultVO<>(data));
            } catch (JsonProcessingException e) {
                throw new ApiException("Mandatory String Type error"); }}// Wrap the original data in ResultVO
        return newResultVO<>(data); }}Copy the code

For interfaces that do not want to automatically encapsulate the results, use the @notresponseWrap annotation to mark the method

PS

Since there is no upload to The Maven central repository, you need to install or deploy the code down to your own private server and import it

<dependency> <groupId>com.sleeper</groupId> <artifactId> <version>1.0.0</version> </dependency>Copy the code