[8] springboot integrates AOP to realize log operation (super detailed)

Introduction: next, I will integrate the framework and other knowledge points learned in the learning stage. Each integration is based on the previous chapter, so the later integration will not repeat the previous code. I put each demo at the end. This time, I continue the content of the previous chapter, and only add new or modified code.

In the previous chapter, Redis was integrated to realize that a user corresponds to a token, and the number of user login failures is locked.

In this chapter, AOP will be integrated. After the request interface is implemented, the log will be processed and not directly written into the logic. Try to decouple and adopt the aspect method.  

First, show me my directory structure:  

 

The checked part is the code added after the integration of this chapter.

Step 1: add a log entity class

@Data
@TableName(value = "syslog")
@Accessors(chain = true)
public class SysLog {

    private static final long serialVersionUID = 1L;

    @TableId(type = IdType.UUID)
    private String id;//id

    @TableField("operationUser")
    private String operationUser;//Operator

    @TableField("path")
    private String path;//Request path

    @TableField("time")
    private String time;//Method execution time

    @TableField("parameter")
    private String parameter;//Method input parameter

    @TableField("title")
    private String title;//Operation method

    @TableField("action")
    private String action;//Method description

    @TableField("sysType")
    private Integer sysType;//System type

    @TableField("opType")
    private Integer opType;//Operation type

    public SysLog(String operationUser, String path, String time,
                      String parameter, String title, String action, Integer sysType, Integer opType) {
        super();
        this.operationUser = operationUser;
        this.path = path;
        this.time = time;
        this.parameter = parameter;
        this.title = title;
        this.action = action;
        this.sysType = sysType;
        this.opType = opType;
    }

}

ps: please do not omit the notes involved here. It is related to the use of mybatis plus. The automatic setting of id here is not necessarily used   IdType.UUID.

The code generator integrated above can be used for generation. I use the code generator here, but some improvements are needed, otherwise an error will be reported.

Step 2: add each layer code

 

Step 3: write the annotations that the aspect needs to rely on (secondary focus)

ps: for custom annotation, you need to add the annotation of the box selection part. For the selection of parameters, there are big guys and detailed articles on csdn.

Step 4: write section (key)

@Aspect
@Component
@EnableAsync
public class SystemLogAspect {
    @Resource
    private SyslogMapper logMapper;//Log mapper

    private String requestPath = null ; // Request address
    private long startTimeMillis = 0; // start time
    private long endTimeMillis = 0; // End time
    private String user = null; // Operator
    private HttpServletRequest request = null;//request

    /**
     * Location of annotation
     */
    @Pointcut("@annotation(com.swagger.demo.config.OperationAnnotation)")
    public void logPointCut() {}

    /**
     * @param joinPoint
     * @Description Before calling the pre notification method, trigger the record start time to obtain the operator from the session
     */
    @Before(value="logPointCut()")
    public void before(JoinPoint joinPoint){
        startTimeMillis = System.currentTimeMillis();
    }
    /**
     * @param joinPoint
     * @Description Get input method parameters
     * @return
     */
    public Map<String, Object> getNameAndValue(JoinPoint joinPoint) {
        Map<String, Object> param = new HashMap<>();
        Object[] paramValues = joinPoint.getArgs();
        String[] paramNames = ((CodeSignature)joinPoint.getSignature()).getParameterNames();
        for (int i = 0; i < paramNames.length; i++) {
            if(paramValues[i] instanceof Integer || paramValues[i] instanceof String) {
                param.put(paramNames[i], paramValues[i]);
            }
        }
        return param;
    }
    /**
     * @param joinPoint
     * @Description After calling the post notification method, trigger the record end time, operator, input parameter, etc
     */
    @After(value="logPointCut()")
    public void after(JoinPoint joinPoint) {
        request = getHttpServletRequest();
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] arguments = joinPoint.getArgs();
        Class<?> targetClass = null;
        try {
            targetClass = Class.forName(targetName);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        Method[] methods = targetClass.getMethods();
        String title;
        String action;
        Integer sysType;
        Integer opType;
        Class<?>[] clazzs;
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                clazzs = method.getParameterTypes();
                if (clazzs!=null&&clazzs.length == arguments.length
                        &&method.getAnnotation(OperationAnnotation.class)!=null) {
                    request = getHttpServletRequest();
                    requestPath=request.getServletPath();
                    HttpSession session = request.getSession();
                    user = session.getAttribute("userName").toString();
                    title = method.getAnnotation(OperationAnnotation.class).content();
                    action = method.getAnnotation(OperationAnnotation.class).action();
                    sysType = method.getAnnotation(OperationAnnotation.class).sysType();
                    opType = method.getAnnotation(OperationAnnotation.class).opType();
                    endTimeMillis = System.currentTimeMillis();

                    SysLog log=new SysLog(user, requestPath,
                            (endTimeMillis-startTimeMillis)+"ms",
                            getNameAndValue(joinPoint).toString(), title, action,sysType,opType);
                    System.out.println("Add parameters:"+log);
                    logMapper.insert(log);
//                    break;
                }
            }
        }
    }
    /**
     * @Description: Get request
     */
    public HttpServletRequest getHttpServletRequest(){
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes)ra;
        HttpServletRequest request = sra.getRequest();
        return request;
    }
    /**
     * @param joinPoint
     * @return Around Advice 
     * @throws Throwable
     */
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        return null;
    }
    /**
     * @param joinPoint
     * @Description Exception notification
     */
    public void throwing(JoinPoint joinPoint) {
        System.out.println("Exception notification");
    }
}

ps: this section is explained below.

 

The aspect annotation indicates that the class is defined as a facet.

The component annotation indicates that the class is registered with the spring container.

The pointcut annotation means to define the pointcut. Here, it means to cut into   The location of the OperationAnnotation annotation and the parameters defining the pointcut are particularly numerous. You can learn more about them.

  The before annotation represents the pre notification, which is equivalent to the function of BeforeAdvice. The value is the name of the pointcut.

  This method is to get the input parameters of the method.

The after annotation represents a post notification, even if the pointcut annotation executes this part of the code after the pointcut is executed. Here, the current user is obtained from the session and represents the Log Operator (save the user name into the session when logging in). Other methods can also be used in actual use.

You can use the insert method of mybatis plus to directly add new records, or you can write your own sql.  

Add: the login interface is modified. After successful login, the wrong user name is reported to the session, as follows:

ps: to use session, you need to add HttpServletRequest request at the input parameter.

This input parameter needs to be added from the logged in controller method to the implementation class.

Step 5: demonstration

Request login interface

result:

Successfully added.

The integration of this issue has been completed. Next, we will continue to update and strengthen the integration. Look forward to it.

Access address: http://localhost:8088/swagger-ui.html perhaps http://localhost:8088/doc.html

demo address: https://github.com/zrc11/studydemo/tree/main/%E6%95%B4%E5%90%88swagger

The code word is not easy. If you can help us, please help us for three times. Thank you

 

Tags: Java Spring Spring Boot

Posted on Tue, 07 Sep 2021 16:28:43 -0400 by daydie2008