• springboot项目使用切面记录用户操作日志


    https://blog.csdn.net/qq_36752632/article/details/79444257

    https://blog.csdn.net/WoddenFish/article/details/82593850?utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control&dist_request_id=1328761.1432.16171810920315613&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control

    1、引入springboot-aop集成jar

              Spring-boot-start-aop

    2、application.yml中启用声明

    #spring配置
    spring:
    #切面启用
    aop:
    proxy-target-class: true
    auto: true
    3、自定义一个拦截controller的注解

    package cn.annotation;

    import java.lang.annotation.*;

    /**
    * Title: SystemControllerLog
    * @date 2018年8月31日
    * @version V1.0
    * Description: 自定义注解,拦截controller
    */

    @Target({ElementType.PARAMETER, ElementType.METHOD})//作用在参数和方法上
    @Retention(RetentionPolicy.RUNTIME)//运行时注解
    @Documented//表明这个注解应该被 javadoc工具记录
    public @interface SystemControllerLog {
    String description() default "";
    }
    4、自定义一个拦截service的注解
    package cn.annotation;

    import java.lang.annotation.*;

    /**
    * Title: SystemControllerLog
    * @date 2018年8月31日
    * @version V1.0
    * Description: 自定义注解,拦截service
    */
    @Target({ElementType.PARAMETER, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface SystemServiceLog {
    String description() default "";
    }
     

    5、定义日志记录切面

    package cn.annotation;

    import cn.pojo.Action;
    import cn.pojo.User;
    import cn.service.ActionService;
    import cn.utils.IpUtils;
    import cn.utils.JsonUtils;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.AfterThrowing;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;

    import javax.annotation.Resource;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpSession;
    import java.lang.reflect.Method;
    import java.util.Date;

    /**
    * Title: SystemControllerLog
    * @date 2018年8月31日
    * @version V1.0
    * Description: 切点类
    */
    @Aspect
    @Component
    @SuppressWarnings("all")
    public class SystemLogAspect {
    //注入Service用于把日志保存数据库,实际项目入库采用队列做异步
    @Resource
    private ActionService actionService;
    //本地异常日志记录对象
    private static final Logger logger = LoggerFactory.getLogger(SystemLogAspect.class);
    //Service层切点
    @Pointcut("@annotation(cn.annotation.SystemServiceLog)")
    public void serviceAspect(){
    }

    //Controller层切点
    @Pointcut("@annotation(cn.oa.annotation.SystemControllerLog)")
    public void controllerAspect(){
    }

    /**
    * @Description 前置通知 用于拦截Controller层记录用户的操作
    * @date 2018年9月3日 10:38
    */

    @Before("controllerAspect()")
    public void doBefore(JoinPoint joinPoint){
    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    HttpSession session = request.getSession();
    //读取session中的用户
    User user = (User) session.getAttribute("user");

    String ip = IpUtils.getIpAddr(request);

    try {
    //*========控制台输出=========*//
    System.out.println("==============前置通知开始==============");
    System.out.println("请求方法" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName()));
    System.out.println("方法描述:" + getControllerMethodDescription(joinPoint));
    System.out.println("请求人:"+user.getUsername());
    System.out.println("请求ip:"+ip);

    //*========数据库日志=========*//
    Action action = new Action();
    action.setActionDes(getControllerMethodDescription(joinPoint));
    action.setActionType("0");
    action.setActionIp(ip);
    action.setUserId(user.getId());
    action.setActionTime(new Date());
    //保存数据库
    actionService.add(action);

    }catch (Exception e){
    //记录本地异常日志
    logger.error("==前置通知异常==");
    logger.error("异常信息:{}",e.getMessage());
    }
    }

    /**
    * @Description 异常通知 用于拦截service层记录异常日志
    * @date 2018年9月3日 下午5:43
    */
    @AfterThrowing(pointcut = "serviceAspect()",throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint,Throwable e){
    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    HttpSession session = request.getSession();
    //读取session中的用户
    User user = (User) session.getAttribute("user");
    //获取请求ip
    String ip = IpUtils.getIpAddr(request);
    //获取用户请求方法的参数并序列化为JSON格式字符串
    String params = "";
    if (joinPoint.getArgs()!=null&&joinPoint.getArgs().length>0){
    for (int i = 0; i < joinPoint.getArgs().length; i++) {
    params+= JsonUtils.objectToJson(joinPoint.getArgs()[i])+";";
    }
    }
    try{
    /*========控制台输出=========*/
    System.out.println("=====异常通知开始=====");
    System.out.println("异常代码:" + e.getClass().getName());
    System.out.println("异常信息:" + e.getMessage());
    System.out.println("异常方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
    System.out.println("方法描述:" + getServiceMethodDescription(joinPoint));
    System.out.println("请求人:" + user.getUsername());
    System.out.println("请求IP:" + ip);
    System.out.println("请求参数:" + params);
    /*==========数据库日志=========*/
    Action action = new Action();
    action.setActionDes(getServiceMethodDescription(joinPoint));
    action.setActionType("1");
    action.setUserId(user.getId());
    action.setActionIp(ip);
    action.setActionTime(new Date());
    //保存到数据库
    actionService.add(action);
    }catch (Exception ex){
    //记录本地异常日志
    logger.error("==异常通知异常==");
    logger.error("异常信息:{}", ex.getMessage());
    }
    }


    /**
    * @Description 获取注解中对方法的描述信息 用于service层注解
    * @date 2018年9月3日 下午5:05
    */
    public static String getServiceMethodDescription(JoinPoint joinPoint)throws Exception{
    String targetName = joinPoint.getTarget().getClass().getName();
    String methodName = joinPoint.getSignature().getName();
    Object[] arguments = joinPoint.getArgs();
    Class targetClass = Class.forName(targetName);
    Method[] methods = targetClass.getMethods();
    String description = "";
    for (Method method:methods) {
    if (method.getName().equals(methodName)){
    Class[] clazzs = method.getParameterTypes();
    if (clazzs.length==arguments.length){
    description = method.getAnnotation(SystemServiceLog.class).description();
    break;
    }
    }
    }
    return description;
    }



    /**
    * @Description 获取注解中对方法的描述信息 用于Controller层注解
    * @date 2018年9月3日 上午12:01
    */
    public static String getControllerMethodDescription(JoinPoint joinPoint) throws Exception {
    String targetName = joinPoint.getTarget().getClass().getName();
    String methodName = joinPoint.getSignature().getName();//目标方法名
    Object[] arguments = joinPoint.getArgs();
    Class targetClass = Class.forName(targetName);
    Method[] methods = targetClass.getMethods();
    String description = "";
    for (Method method:methods) {
    if (method.getName().equals(methodName)){
    Class[] clazzs = method.getParameterTypes();
    if (clazzs.length==arguments.length){
    description = method.getAnnotation(SystemControllerLog.class).description();
    break;
    }
    }
    }
    return description;
    }
    }
    6、开始使用

        1)@SystemControllerLog(description = "")

              注解加在控制器中方法上面,括号里写上操作描述

        2)用于监控service异常,可以不使用

            @SystemServiceLog(description = "")

            注解加在service层方法上面,括号里写上操作描述

    (此处为AOP拦截Service记录异常信息。方法不需要加try-catch)

    ------------------------------------------------------------------------------------------------------

    项目地址:https://gitee.com/lwydyby/wwmxd-log/
    1. 在需要记录的方法上使用注解EnableGameleyLog
    参数如下:

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD})
    public @interface EnableGameleyLog {
    /**
    * 操作的中文说明 可以直接调用ModifyName
    * @return
    */
    String name() default "";

    /**
    * 获取编辑信息的解析类,目前为使用id获取,复杂的解析需要自己实现,默认不填写
    * 则使用默认解析类
    * @return
    */
    Class parseclass() default DefaultContentParse.class;

    /**
    * 查询数据库所调用的class文件
    * @return
    */
    Class serviceclass() default IService.class;

    /**
    * 前台字段名称
    */
    String[] feildName() default {"id"};

    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    简单例子:
    “`
    @EnableGameleyLog(name = ModifyName.SAVE,serviceclass = DemoService.class)
    public BaseResponse addDemo(@RequestBody Demo demo){

    }

    2.编写解析类,默认的解析类为使用id查询,自定义的解析类请继承ContentParser接口,并在注解中赋值
    1
    /**
    * 基础解析类
    * 单表编辑时可以直接使用id来查询
    * 如果为多表复杂逻辑,请自行编写具体实现类
    * @author lw
    * @date 2018-03-02
    */
    public class DefaultContentParse implements ContentParser {
    @Override
    public Object getResult(Map

    3.默认的操作方式有:
    ```
    public class ModifyName {
    public final static String SAVE="新建";
    public final static String UPDATE="编辑";
    public final static String DELETE="删除";
    }
    1
    2
    3
    4
    5
    6
    7
    4.如需记录操作字段中文请在entity中使用DataName注解
    如:

    @DataName(name="操作日期")
    private String modifydate;

  • 相关阅读:
    P2048 [NOI2010]超级钢琴
    [LOJ#6468.] 魔法
    [牛客小白月赛18] Forsaken的数列
    [JSOI2011]柠檬
    [TJOI2015]组合数学
    【单调队列优化】[CF372C] Watching Fireworks is Fun
    【线段树】[Luogu P4198]楼房修建
    Python资源
    人生的几个阶段
    两种解读,生活的意义和方法
  • 原文地址:https://www.cnblogs.com/zhoading/p/14602404.html
Copyright © 2020-2023  润新知