[Spring Boot quick start] 20. Spring Boot implements logging based on AOP annotations

Keywords: Java Spring Boot Back-end Interview

preface

  in many background management systems, there are clear permissions and role control, and of course, there is no lack of operation log records. This article will develop a logging function based on the AOP feature of Spring. Let's record the whole development project

Quick start

   using the AOP feature of Spring, first understand what AOP is. AOP refers to aspect oriented programming in the process of program development, and realizes program functions through precompiling and dynamic agents. AOP mainly includes tangent point, facet, connection point, target group, notification, weaving mode, etc. Notification types commonly include pre notification, surround notification, post notification, etc. surround notification is generally used in the process of logging. Specific AOP related concepts that you are not familiar with can be queried.

Version information

  this Spring Boot implements logging based on AOP annotations. The main version information is as follows:

Spring Boot 2.3.0.RELEASE
aspectjweaver 1.9.6
maven 3
 Copy code

  the main dependency introduced is aspectjweaver. If the aspectjweaver and Spring Boot versions are inconsistent, it may report that the tangent point and other related exceptions cannot be found, which can be solved by replacing the bit related version.

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.6</version>
</dependency>
Copy code

Basic information

   realize the log recording function, which is mainly to record the operation log in the database or search engine for convenient query. The log needs to record the operator, operation time, requested parameters, requested ip, requested connection, operation type and other information. The table creation SQL of this example is as follows:

CREATE TABLE `log_info` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `model` varchar(255) DEFAULT NULL COMMENT 'modular',
  `log_type` tinyint(4) DEFAULT NULL COMMENT 'Type 0=other,1=newly added,2=modify,3=delete,4=to grant authorization,5=export,6=Import,7=Strong regression,8=Sign in,9=wipe data ,10 query',
  `url` varchar(255) DEFAULT NULL COMMENT 'Request link',
  `method` varchar(255) DEFAULT NULL COMMENT 'Request method',
  `class_name` varchar(255) DEFAULT NULL COMMENT 'Class name',
  `method_name` varchar(255) DEFAULT NULL COMMENT 'Method name',
  `params` varchar(500) DEFAULT NULL COMMENT 'Request parameters',
  `ip` varchar(255) DEFAULT NULL COMMENT 'ip address',
  `user_id` int(11) DEFAULT NULL COMMENT 'Operator id',
  `user_name` varchar(255) DEFAULT NULL COMMENT 'Operator',
  `sys_info` varchar(255) DEFAULT NULL COMMENT 'system information ',
  `create_user` varchar(200) CHARACTER SET utf8 DEFAULT NULL COMMENT 'Creator',
  `create_time` datetime DEFAULT NULL COMMENT 'Creation time',
  `update_user` varchar(200) CHARACTER SET utf8 DEFAULT NULL COMMENT 'Updater',
  `update_time` datetime DEFAULT NULL COMMENT 'Update time',
  `data_state` tinyint(4) NOT NULL DEFAULT '1' COMMENT '0 Delete 1 not deleted',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;
Copy code

  this time, the operation types are divided into 11 categories: package login, exit, add, delete, modify query, import, export, empty and other related log operation categories.

@Getter
@AllArgsConstructor
public enum LogTypeEnum {
    /**
     * 0=Others: 1 = add, 2 = modify, 3 = delete, 4 = authorize, 5 = export, 6 = import, 7 = forced return, 8 = login, 9 = clear data, 10 query
     * */
    OTHER(0,"other"),
    ADD(1,"newly added"),
    UPDATE(2,"modify"),
    DEL(3,"delete"),
    AUTH(4,"to grant authorization"),
    EXPORT(5,"export"),
    IMPORT(6,"Import"),
    QUIT(7,"Strong regression"),
    GENERATE_CODE(8,"Sign in"),
    CLEAR(9,"empty"),
    QUERY(10,"query"),
    ;


    @EnumValue
    private int value;

    private String desc;
}
Copy code

Log annotation

  after data initialization is completed, write a user-defined Log annotation. The annotation used this time is mainly for methods. The details are as follows:

  • @Target: the target location of the annotation, mainly including interfaces, classes, enumerations, fields, methods, constructors, packages, etc. It can be configured as needed. The method used in the log is based on annotation.
  • @Retention: refers to the location where annotations are retained, which can be in source code, class and running. This log operation record must be used during operation, so select RUNTIME.
  • @Documented: literally means document, which means that the annotation will be included in javadoc.
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
    /**
     * modular
     * */
    String model() default "";

    /**
     * operation
     * */
    LogTypeEnum logType() default LogTypeEnum.OTHER;
}

Copy code

LogAspect

  define the LogAspect Aspect of a log. You need to use @ Aspect and @ Component in the class to indicate that this is an Aspect method to scan the package during operation. It should be noted that the Aspect and notification type need to be defined in this method. Finally, the information required by the operation log is queried according to the information in the annotation and request parameters. Since there is no need to log in to the direct interface request this time, the default values of operator and operation id are used in the demonstration. This example only extracts some operation log information. There are many log information to be added in the project, which can be modified as required.

@Aspect
@Component
public class LogAspect {

    @Resource
    private LogInfoMapper logInfoMapper;

    /**
     * @ClassName logPointCut
     * @Description:tangency point 
     * @Author JavaZhan @Official account: Java full stack architect
     * @Version V1.0
     **/
    @Pointcut("@annotation(com.example.demo.log.Log)")
    public void logPointCut(){

    }

    /**
     * @ClassName aroundForLog
     * @Description:Around Advice 
     * @Author JavaZhan @Official account: Java full stack architect
     * @Version V1.0
     **/
    @Around("logPointCut()")
    public Object aroundForLog(ProceedingJoinPoint point) throws Throwable {
        long beginTime = System.currentTimeMillis();
        Object result = point.proceed();
        saveSmsLog(point);
        return result;
    }


    /**
     * @ClassName saveLogInfo
     * @Description: Save operation log
     * @Author JavaZhan @Official account: Java full stack architect
     * @Version V1.0
     **/
    private void saveLogInfo(ProceedingJoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        LogInfo logInfo = new LogInfo();
        logInfo.setClassName(joinPoint.getTarget().getClass().getName());
        logInfo.setMethodName(signature.getName());
        Log log = method.getAnnotation(Log.class);
        if(log != null){
            logInfo.setModel(log.model());
            logInfo.setLogType(log.logType().getValue());
        }
        Object[] args = joinPoint.getArgs();
        try{
            String params = JSONObject.toJSONString(args);
            logInfo.setParams(params);
        }catch (Exception e){

        }
        ServletRequestAttributes servletRequestAttributes =   (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        logInfo.setIp(IpUtils.getIpAddr(request));
        logInfo.setUrl(request.getServletPath());
        logInfo.setMethod(request.getMethod());
        logInfo.setUserId(123);
        logInfo.setUserName("admin");
        logInfo.setCreateTime(new Date());
        logInfo.setDataState(1);
        //Save operation log
        logInfoMapper.insert(logInfo);
    }
}
Copy code

Test log

  this example will be tested based on common interfaces. In the Controller method, we call the user-defined annotation and specify the model information and operation type information of the method according to the actual use meaning of the method.

@RequestMapping("user")
@Controller
public class UserController {

    @Resource
    private UserService userService;

    @RequestMapping("getAllUser")
    @ResponseBody
    @Log(model = "Query user list",logType = LogTypeEnum.QUERY)
    public List<User> getAllUser(){
        return userService.getAllUser();
    }


    @RequestMapping("getUserById")
    @ResponseBody
    @Log(model = "Gets the specified user",logType = LogTypeEnum.QUERY)
    public User getUserById(Integer id ){
        return userService.getById(id);
    }
}
Copy code

Calling interface: http://127.0.0.1:8888/user/getAllUser   The returned data information is as follows.

In the log table, you can see that a new log information has been added to query the user list.

Access other interfaces below: http://127.0.0.1:8888/user/getUserById?id=1   The returned data information is as follows.

In the log table, you can see that a new log has been added to obtain the log information of the specified user.

Posted by alsal on Sat, 27 Nov 2021 22:28:09 -0800