Spring实现日志注解

1、目的

写项目的时候经常会通过日志来排查原因,一种是通过log4j将日志收集出来,然后使用elk进行数据的分类与统计,这种是针对大量的请求日志进行记录。另一种就是通过自定义注解的方式写入数据库,这种是针对特定接口来处理,将重要的操作信息记录到数据库中。这篇博客就是说的第二种方式。

2、思路

首先,应该使用自定义注解来标记哪些接口需要记录操作日志。

然后, 使用切面来统一拦截参数和返回的结果,并将信息返回到数据库。

3、实现过程

 1、Log 自定义注解

package com.example.demo.common.annotation;

import com.example.demo.enums.BusinessType;
import com.example.demo.enums.OperatorType;

import java.lang.annotation.*;

/**
 * @author zhangyang
 * @version 1.0
 * @Date 2022/5/14 13:54
 * @Description 自定义注解
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {

    /**
     * 模块
     * @return
     */
    String title() default  "";

    /**
     * 功能
     * @return
     */
    BusinessType businessType() default BusinessType.INSERT;

    /**
     * 操作人类别
     * @return
     */
    OperatorType operatorType()  default  OperatorType.OTHER;

    /**
     * 是否保存请求的参数
     * @return
     */
     boolean isSaveRequestData()  default  true;


}

2、 进行跨域配置

package com.example.demo.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @ClassName SysConfig
 * @Description 跨域配置类
 * @Author zhangyang
 * @Date 2022/3/2 17:41
 * @Version 1.0
 */
@Configuration
public class CorsConfiguration implements WebMvcConfigurer {


    @Override
    public void addCorsMappings(CorsRegistry registry) {
        //本应用的所有方法都会去处理跨域请求
        registry.addMapping("/**")
                .allowCredentials(true)
                //允许远端访问的域名
                .allowedOrigins("*")
                //允许请求的方法("POST", "GET", "PUT", "OPTIONS", "DELETE")
                .allowedMethods("*")
                //允许请求头
                .allowedHeaders("*")
                .maxAge(3600);
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry){
        registry.addResourceHandler("/uploads/**")
                .addResourceLocations("classpath:/static/");
    }
}

3、定义用于测试的controller

package com.example.demo.controller;

import com.example.demo.common.annotation.Log;
import com.example.demo.entity.User;
import com.example.demo.enums.BusinessType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

/**
 * @author zhangyang
 * @version 1.0
 * @Date 2022/5/14 13:53
 * @Description 用于测试的Controller
 */
@RequestMapping("/user")
@RestController
public class UserController {


    @GetMapping("/selectAll")
    @Log(title = "用户查询",businessType = BusinessType.SELECT)
    public List<User> selectAllUser() {
          return new ArrayList<>();
    }
}

4、定义切面实现请求拦截

package com.example.demo.aspectj;

import com.alibaba.fastjson.JSON;
import com.example.demo.common.annotation.Log;
import com.example.demo.entity.SysLog;
import com.example.demo.enums.BusinessStatus;
import com.example.demo.service.ISysLogService;
import com.example.demo.util.IpUtils;
import com.example.demo.util.SpringUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.HandlerMapping;

import java.lang.reflect.Method;
import java.util.Map;


/**
 * @author zhangyang
 * @version 1.0
 * @Date 2022/5/14 14:09
 * @Description 操作日志切面
 */
@Aspect
@Component
public class LogAspect {

    private static final Logger log = LoggerFactory.getLogger(LogAspect.class);

    //配置织入点
    @Pointcut("@annotation(com.example.demo.common.annotation.Log)")
    public void logPointCut() {

    }


    /**
     * 处理完请求后执行
     *
     * @param joinPoint  切点
     * @param jsonResult 返回的信息
     */
    @AfterReturning(pointcut = "logPointCut()", returning = "jsonResult")
    public void doAfterRetuning(JoinPoint joinPoint, Object jsonResult) {
        handleLog(joinPoint, null, jsonResult);
    }

    /**
     * 拦截异常操作
     *
     * @param joinPoint 切点
     * @param ex        异常
     */
    @AfterThrowing(value = "logPointCut()", throwing = "ex")
    public void doAfterThrowing(JoinPoint joinPoint, Exception ex) {
        handleLog(joinPoint, ex, null);
    }

    /**
     * 处理完请求之后执行
     *
     * @param joinPoint  切点
     * @param e          异常信息
     * @param jsonResult 返回结果
     */
    protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult) {

        Log controllerLog = getAnnotationLog(joinPoint);
        if (controllerLog == null) {
            return;
        }

        SysLog sysLog = new SysLog();
        sysLog.setStatus(BusinessStatus.SUCCESS.ordinal());
        // 请求的地址
        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) attributes;
        String ip = IpUtils.getIpAddr(requestAttributes.getRequest());
        sysLog.setOperIp(ip);

        // 返回参数
        sysLog.setOperUrl(requestAttributes.getRequest().getRequestURI());
        sysLog.setOperName("zhangyang");
        if (e != null) {
            sysLog.setStatus(BusinessStatus.FAIL.ordinal());
            sysLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));
        }
        // 设置方法名称
        String className = joinPoint.getTarget().getClass().getName();

        String methodName = joinPoint.getSignature().getName();
        sysLog.setMethod(className + "." + methodName + "()");
        sysLog.setOperLocation(sysLog.getOperIp());
        // 设置请求方式
        sysLog.setRequestMethod(requestAttributes.getRequest().getMethod());
        getControllerMethodDescription(joinPoint, controllerLog, sysLog);
        // 保存到数据库
        SpringUtils.getBean(ISysLogService.class).insertLog(sysLog);
    }


    /**
     * 获取注解中对方法的描述信息,用于controller层注解
     *
     * @param joinPoint 切点
     * @param log       日志
     * @param sysLog    数据库操作日志对象
     */
    public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysLog sysLog) {
        // 设置action动作
        sysLog.setBusinessType(log.businessType().ordinal());
        // 设置标题
        sysLog.setTitle(log.title());
        // 设置操作人的类别
        sysLog.setOperatorType(log.operatorType().ordinal());
        // 是否需要保存request 参数和 值
        if (log.isSaveRequestData()) {
            setRequestValue(joinPoint, sysLog);
        }

    }

    /**
     * 获取的请求参数,放到log中
     * @param joinPoint 切点
     * @param sysLog 操作日志
     */
    private void setRequestValue(JoinPoint joinPoint,SysLog sysLog) {
        String requestMethod = sysLog.getRequestMethod();
        if(HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) {

            String params = argsArrayString(joinPoint.getArgs());
            sysLog.setOperParam(StringUtils.substring(params,0,2000));
        } else {
            // 请求的地址
            RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes) attributes;
            Map<?,?> paramsMap = (Map<?,?>) requestAttributes.getRequest().getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
            sysLog.setOperParam(StringUtils.substring(paramsMap.toString(),0,2000));

        }
    }

    /**
     * 参数转化成Json字符串
     * @param paramsArray 参数对象
     * @return
     */
    private String argsArrayString(Object[] paramsArray) {
        String param = "";
        if(paramsArray != null && paramsArray.length > 0) {
            for(int i=0; i<paramsArray.length; i++) {
                if(StringUtils.isNotEmpty(paramsArray[i].toString())) {
                    Object object = JSON.toJSON(paramsArray[i]);
                    param += object.toString() + "";
                }
            }
        }
        return param;
    }




    /**
     * 是否存在注解,如果存在就获取
     *
     * @param joinPoint 切点
     * @return 注解对象
     */
    private Log getAnnotationLog(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        if (method != null) {
            return method.getAnnotation(Log.class);
        }
        return null;
    }


}

5、相关实体类

        1、操作日志实体类SysLog

package com.example.demo.entity;

import lombok.Data;

/**
 * @author zhangyang
 * @version 1.0
 * @Date 2022/5/14 15:28
 * @Description
 */
@Data
public class SysLog {

    /**
     * 主键
     */
    private Long id;


    /**
     * 操作模块
     */
    private String title;

    /**
     * 业务类型(0 其他 1 新增 2 修改 3删除)
     */
    private Integer businessType;



    /**
     * 请求方法
     */
    private String method;

    /**
     *  请求方式
     */
    private String requestMethod;

    /**
     * 操作类别 (0 其他 1 后台用户 2 手机端用户)
     */
    private Integer operatorType;

    /**
     * 操作人员
     */
    private String operName;

    /**
     * 部门名称
     */
    private String deptName;

    /**
     * 请求URl
     */
    private String operUrl;

    /**
     *  操作地址
     */
    private String operIp;

    /**
     * 操作地点
     */
    private String operLocation;

    /**
     * 请求参数
     */
    private String operParam;

    /**
     * 返回参数
     */
    private String jsonResult;

    /**
     * 状态
     */
    private Integer status;

    /**
     * 异常信息
     */
    private String errorMsg;
}

        2、User

package com.example.demo.entity;

import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;

/**
 * @author zhangyang
 * @version 1.0
 * @Date 2022/5/14 14:03
 * @Description
 */
@Data
public class User {

    /**
     * 主键
     */
    @TableId
    Integer id;

    /**
     * 用户姓名
     */
    String name;


    /**
     * 用户地址
     */

    String address;

}

6、枚举类

package com.example.demo.enums;

/**
 * @author lenovo
 * @version 1.0
 * @Date 2022/5/14 15:43
 * @Description 操作状态
 */

public enum BusinessStatus {

    /**
     * 成功
     */
    SUCCESS,

    /**
     * 失败
     */
    FAIL,
}
package com.example.demo.enums;

/**
 * @author lenovo
 * @version 1.0
 * @Date 2022/5/14 13:56
 * @Description
 */
public enum BusinessType {

    /**
     * 新增
     */
    INSERT,

    /**
     * 修改
     */
    UPDATE,

    /**
     * 删除
     */
    DELETE,
    /**
     * 清空
     */
    CLEAN,

    /**
     * 查询
     */
    SELECT,

}
package com.example.demo.enums;

/**
 * @author lenovo
 * @version 1.0
 * @Date 2022/5/14 13:59
 * @Description
 */
public enum OperatorType {

    /**
     * 其他
     */
    OTHER,

    /**
     * 后台用户
     */
    MANAGE,

    /**
     * 手机端用户
     */
    MOBILE
}

 7、Mapper

package com.example.demo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.entity.SysLog;
import org.apache.ibatis.annotations.Mapper;

/**
 * @author zhangyang
 * @version 1.0
 * @Date 2022/5/14 16:40
 * @Description
 */
@Mapper
public interface  SysLogMapper extends BaseMapper<SysLog> {



}

8、service以及Impl

package com.example.demo.service;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.demo.entity.SysLog;
import com.example.demo.vo.SysLogBasePageVo;

/**
 * @author lenovo
 * @version 1.0
 * @Date 2022/5/14 16:38
 * @Description 日志服务层
 */
public interface ISysLogService {

    /**
     * 新增数据库日志记录
     * @param sysLog
     */
    void insertLog(SysLog sysLog);

    /**
     * 分页查询对象
     * @param sysLogBasePageVo 分页查询对象
     * @return Page
     */
    Page<SysLog> selectSysLogPage(SysLogBasePageVo sysLogBasePageVo);
}
package com.example.demo.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.demo.entity.SysLog;
import com.example.demo.mapper.SysLogMapper;
import com.example.demo.service.ISysLogService;
import com.example.demo.vo.SysLogBasePageVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * @author lenovo
 * @version 1.0
 * @Date 2022/5/14 16:39
 * @Description
 */
@Service
public class SysLogServiceImpl implements ISysLogService {

    @Resource
    private SysLogMapper sysLogMapper;

    @Override
    public void insertLog(SysLog sysLog) {
        sysLogMapper.insert(sysLog);
    }

    @Override
    public Page<SysLog> selectSysLogPage(SysLogBasePageVo sysLogBasePageVo) {
        QueryWrapper<SysLog> sysLogQueryWrapper = new QueryWrapper<>();
        if(StringUtils.isNotEmpty(sysLogBasePageVo.getSearchKey())) {
            sysLogQueryWrapper.eq("title",sysLogBasePageVo.getSearchKey());
        }
        return sysLogMapper.selectPage(new Page<>(sysLogBasePageVo.getCurrentPage(),sysLogBasePageVo.getPageSize()),sysLogQueryWrapper);
    }
}

9、Util工具类

package com.example.demo.util;

import javax.servlet.http.HttpServletRequest;

/**
 * 获取IP地址
 */
public class IpUtils
{
    public static String getIpAddr(HttpServletRequest request)
    {
        if (request == null)
        {
            return "unknown";
        }
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
        {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
        {
            ip = request.getHeader("X-Forwarded-For");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
        {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
        {
            ip = request.getHeader("X-Real-IP");
        }

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
        {
            ip = request.getRemoteAddr();
        }
        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : "";
    }
}
package com.example.demo.util;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * @author lenovo
 * @version 1.0
 * @Date 2022/5/14 16:31
 * @Description
 */
@Component
public class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware {

    /**
     * Spring 应用上下文
     */
    private static ConfigurableListableBeanFactory beanFactory;

    private static ApplicationContext applicationContext;

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        SpringUtils.beanFactory = configurableListableBeanFactory;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringUtils.applicationContext = applicationContext;
    }

    /**
     * 获取对象
     *
     * @param name 名称
     * @param <T>  定义的泛型类型
     * @return
     */
    public static <T> T getBean(String name) {
        return (T) beanFactory.getBean(name);
    }

    /**
     * 根据类获取到bean对象
     * @param clz 类对象
     * @param <T> 定义泛型类型
     * @return
     */
    public static <T> T getBean(Class<T> clz) {
        T result = (T) beanFactory.getBean(clz);
        return  result;
    }
}

10、vo 对象

package com.example.demo.vo;

import lombok.Data;

/**
 * @author zhangyang
 * @version 1.0
 * @Date 2022/5/14 17:09
 * @Description 基础分页查询vo对象
 */
@Data
public class BasePageVo {

    /**
     * 页面大小
     */
    Integer pageSize;

    /**
     * 页码
     */
    Integer currentPage;

    /**
     * 总页数
     */
    Integer pages;


}
package com.example.demo.vo;

import lombok.Data;

/**
 * @author zhangyang
 * @version 1.0
 * @Date 2022/5/14 17:08
 * @Description
 */
@Data
public class SysLogBasePageVo extends BasePageVo {

    /**
     * 查询关键字
     */
    String searchKey;
}

11、application.yml工具类

# 应用名称
spring.application.name=demo
# 应用服务 WEB 访问端口
server.port=8080
# 数据库驱动:
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# 数据源名称
spring.datasource.name=defaultDataSource
# 数据库连接地址
spring.datasource.url=jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
# 数据库用户名&密码:
spring.datasource.username=root
spring.datasource.password=root


SysLog 表结构

User 表结构

 

 

4、代码分析

   首先,定义了一个自定义注解Log,其目标范围为Method,只有在运行的时候才会保留,同时可以被javadoc工具类文档化。其代码中定义了 属性类型为String的属性名称为title ,

属性类型为BusinessType 属性名称为busniessType 默认值为INSERT , 属性类型为OperatorType 属性名称operatorTpye 默认值为 OperatorType.OTHER, 属性类型为boolean

 属性方法为isSaveRequestData  默认值为true。

 然后controller 使用了这个注解

 @GetMapping("/selectAll")

 @Log(title = "用户查询",busninessType = BusinessType.SELECT)

最后,定义了LogAspect 切面类,

/**
	*  配置了织入点,即要拦截使用了Log注解的方法
	*/
	@Pointcut("@annotation(com.example.demo.common.annnotaion.Log)")
	public void logPointCut() {
	
	
	
	}

  拦截方法处理完后的请求

	/**
	*
	*  处理完请求后执行
	*  @param joinPoint 切点
	*  @param jsonResult  返回的信息
	*/
     @AfterReturning(poincut = "logPointCut()", returning="jsonResult")
	 public void doAfterReturning(JoinPoint joinPoint, Object jsonResult) {
		handleLog(joinPoint, null, jsonResult);
	 }
	

拦截方法被抛出异常的请求 

	/*
	*
	* @param joinPoint 切点
	* @param e  异常信息
	* @param jsonResult 返回结果
	*/
	public void doAfterThrowing(JoinPoint joinPoint,Exception ex) {
		handleLog(joinPoint,ex,null);
	}

 封装方法并保存到数据库中

  /**
     * 处理完请求之后执行
     *
     * @param joinPoint  切点
     * @param e          异常信息
     * @param jsonResult 返回结果
     */
    protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult) {

        Log controllerLog = getAnnotationLog(joinPoint);
        if (controllerLog == null) {
            return;
        }

        SysLog sysLog = new SysLog();
        sysLog.setStatus(BusinessStatus.SUCCESS.ordinal());
        // 请求的地址
        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) attributes;
        String ip = IpUtils.getIpAddr(requestAttributes.getRequest());
        sysLog.setOperIp(ip);

        // 返回参数
        sysLog.setOperUrl(requestAttributes.getRequest().getRequestURI());
        sysLog.setOperName("zhangyang");
        if (e != null) {
            sysLog.setStatus(BusinessStatus.FAIL.ordinal());
            sysLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));
        }
        // 设置方法名称
        String className = joinPoint.getTarget().getClass().getName();

        String methodName = joinPoint.getSignature().getName();
        sysLog.setMethod(className + "." + methodName + "()");
        sysLog.setOperLocation(sysLog.getOperIp());
        // 设置请求方式
        sysLog.setRequestMethod(requestAttributes.getRequest().getMethod());
        getControllerMethodDescription(joinPoint, controllerLog, sysLog);
        // 保存到数据库
        SpringUtils.getBean(ISysLogService.class).insertLog(sysLog);
    }
    /**
     * 获取注解中对方法的描述信息,用于controller层注解
     *
     * @param joinPoint 切点
     * @param log       日志
     * @param sysLog    数据库操作日志对象
     */
    public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysLog sysLog) {
        // 设置action动作
        sysLog.setBusinessType(log.businessType().ordinal());
        // 设置标题
        sysLog.setTitle(log.title());
        // 设置操作人的类别
        sysLog.setOperatorType(log.operatorType().ordinal());
        // 是否需要保存request 参数和 值
        if (log.isSaveRequestData()) {
            setRequestValue(joinPoint, sysLog);
        }

    }

读取请求中的参数并放到log中 

   /**
     * 获取的请求参数,放到log中
     * @param joinPoint 切点
     * @param sysLog 操作日志
     */
    private void setRequestValue(JoinPoint joinPoint,SysLog sysLog) {
        String requestMethod = sysLog.getRequestMethod();
        if(HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) {

            String params = argsArrayString(joinPoint.getArgs());
            sysLog.setOperParam(StringUtils.substring(params,0,2000));
        } else {
            // 请求的地址
            RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes) attributes;
            Map<?,?> paramsMap = (Map<?,?>) requestAttributes.getRequest().getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
            sysLog.setOperParam(StringUtils.substring(paramsMap.toString(),0,2000));

        }
    }

将参数转化为json 

    /**
     * 参数转化成Json字符串
     * @param paramsArray 参数对象
     * @return
     */
    private String argsArrayString(Object[] paramsArray) {
        String param = "";
        if(paramsArray != null && paramsArray.length > 0) {
            for(int i=0; i<paramsArray.length; i++) {
                if(StringUtils.isNotEmpty(paramsArray[i].toString())) {
                    Object object = JSON.toJSON(paramsArray[i]);
                    param += object.toString() + "";
                }
            }
        }
        return param;
    }

 /**
     * 是否存在注解,如果存在就获取
     *
     * @param joinPoint 切点
     * @return 注解对象
     */
    private Log getAnnotationLog(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        if (method != null) {
            return method.getAnnotation(Log.class);
        }
        return null;
    }

5、实现结果

  运行起项目,地址栏访问 http://localhost:8080/user/selectAll

  这时候就会发现数据库表sys_log 就会新增一条记录

6、总结

  记录请求日志功能主要是用切面知识,

 切面主要支持5种类型的通知注解:

        @Before 前置通知,在方法执行之前执行

         @After 后置通知,在方法执行之后执行

        @AfterRunning 返回通知,在方法返回结果之后执行

        @AfterThrowing 异常通知,在方法抛出异常之后

         @Around: 环绕通知

也就是,需要在核心业务前执行该辅助业务、在核心业务执行之后执行该辅助业务、在报错时候执行该辅助业务、在方法执行之前之后异常时执行该辅助业务

 @PointCut(value ="execution(* com.cn.spring.aspectj.NotVeryUsefulAspectService.*(...))")

其中表达式标签

 execution 用于匹配方法执行的连接点

args(): 用于匹配当前执行的方法传入的参数为指定类型的执行方法

this(): 用于匹配当前AOP代理对象类型的执行方法,注意是AOP代理对象类型的配置,这样就可能包括引入接口也类型匹配;

target(): 用于匹配当前目标对象类型的执行方法,注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配;

within(): 用于匹配指定类型内的方法执行;

@args(): 用于匹配当前执行的参数

如 this(com.test.spring.aop.pointcutexp.Intf) 实现Intf 接口的所有类,如果Intf不是接口,限定Intf单个类

@target(org.springframework.transaction.annotation.Transactional) 带有@Transactional 标注的所有类的任意方法

@args(org.springframework.transation.annotation.Transational) 参数带有@Transational 标注的方法

args(String) 参数为String 类型的方法,

args(java,io.serializable,...)  任何一个以接受“传入参数类型为java.io.serializable”开头,且其后可跟任意个任意类型的参数的方法执行,args 指定的参数类型是在运行时动态匹配的

第二个就是使用手动获取Spring的bean对象

package com.example.demo.util;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * @author lenovo
 * @version 1.0
 * @Date 2022/5/14 16:31
 * @Description
 */
@Component
public class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware {

    /**
     * Spring 应用上下文
     */
    private static ConfigurableListableBeanFactory beanFactory;

    private static ApplicationContext applicationContext;

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        SpringUtils.beanFactory = configurableListableBeanFactory;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringUtils.applicationContext = applicationContext;
    }

    /**
     * 获取对象
     *
     * @param name 名称
     * @param <T>  定义的泛型类型
     * @return
     */
    public static <T> T getBean(String name) {
        return (T) beanFactory.getBean(name);
    }

    /**
     * 根据类获取到bean对象
     * @param clz 类对象
     * @param <T> 定义泛型类型
     * @return
     */
    public static <T> T getBean(Class<T> clz) {
        T result = (T) beanFactory.getBean(clz);
        return  result;
    }
}

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值