博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
基于Spring AOP实现可控的请求日志保存,自定义注解
阅读量:6837 次
发布时间:2019-06-26

本文共 6013 字,大约阅读时间需要 20 分钟。

  hot3.png

需求

  1. 对系统请求的敏感数据做记录
  2. 记录操作类型 如"更新","修改"
  3. 记录关键值
  4. 记录操作人

思路

基于AOP对controller方法进行操作,判断该controller方法是不是需要记录的操作类型;然后对方法参数进行筛选,记录参数中符合要求的关键值

实现

基于Spring boot aop做了实现

通过注解标注方法,参数,属性

自定义注解

import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * 用来判断该方法是否进行日志记录 * Created by xuchonggao on 2017/2/21. */@Target({ElementType.METHOD, ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})@Retention(RetentionPolicy.RUNTIME)public @interface LogAble {    String value();  //操作对象名称,操作类型 或者字段对应的名称}

定义AOP类,进行操作

import com.jockiller.logable.annotion.LogAble;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.Signature;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.reflect.MethodSignature;import org.springframework.stereotype.Component;import org.springframework.util.StringUtils;import javax.servlet.http.HttpServletRequest;import java.lang.annotation.Annotation;import java.lang.reflect.Field;import java.lang.reflect.Method;/** * Created by jockiller on 2017/2/25. */@Aspect@Componentpublic abstract class LogInterceptor {    @Around("@annotation(logAble)")    Object saveLog(ProceedingJoinPoint point, LogAble logAble) throws Throwable {        StringBuffer accessContent = new StringBuffer();        long userId = 0;        HttpServletRequest request = null;        Signature signature = point.getSignature();        try {            MethodSignature methodSignature = (MethodSignature) signature;            Method targetMethod = methodSignature.getMethod();            Annotation[][] paramAnnotions = targetMethod.getParameterAnnotations();            String paramAnno = null;            Class clazz;            Object requestArg;            LogAble classLog;            for (int i = 0; i < point.getArgs().length; i++) {                requestArg = point.getArgs()[i];                paramAnno = isLogAbleParam(paramAnnotions, i);                if (requestArg == null && paramAnno == null) {                    continue;                } else if (requestArg != null) {                    clazz = requestArg.getClass();                    if (requestArg instanceof HttpServletRequest) {                        request = (HttpServletRequest) requestArg;                        userId = getUserId(request);                    } else if (clazz.isAnnotationPresent(LogAble.class)) {                        classLog = (LogAble) clazz.getAnnotation(LogAble.class);                        accessContent.append("--").append(classLog.value()).append("[");                        for (Field field : clazz.getDeclaredFields()) {                            if (field.isAnnotationPresent(LogAble.class)) {                                LogAble fieldLog = (LogAble) field.getAnnotation(LogAble.class);                                if (fieldLog != null) {                                    field.setAccessible(true);                                    Object val = field.get(requestArg);                                    accessContent.append("--").append(fieldLog.value()).append(":").append(val == null ? null : val.toString());                                }                            }                        }                        accessContent.append("]");                    } else if (!StringUtils.isEmpty(paramAnno)) {                        accessContent.append("--").append(paramAnno).append('[').append(requestArg.toString()).append(']');                    }                } else {                    accessContent.append("--").append(paramAnno).append('[').append(']');                }            }            if (userId <= 0) {                throw new RuntimeException("没有获取到用户信息,请确保controller方法有HttpServletRequest参数,并且用户已经登录");            }        } catch (Exception e) {            //保证日志处理不影响正常业务            //TODO 需要自己对异常进行处理            if (e instanceof RuntimeException) {                throw e;            } else {                System.out.println("处理操作日志出错");            }        }        Object proceed = point.proceed();        if (doSave(proceed)) {            saveLog(accessContent, userId, getRequestIp(request));        }        return proceed;    }    /**     * 判断参数是否被@LogAble修饰     *     * @param annotations     * @param paramIndex     * @return 返回LogAble的value     */    String isLogAbleParam(Annotation[][] annotations, int paramIndex) {        assert annotations.length > paramIndex;        String res = null;        for (Annotation anno : annotations[paramIndex]) {            if (anno instanceof LogAble) {                res = ((LogAble) anno).value();                break;            }        }        return res;    }    /**     * 获取操作人Id的方法     *     * @param request     * @return     */    public abstract long getUserId(HttpServletRequest request);    /**     * 获取真实访问IP的方法     *     * @param request     * @return     */    public abstract String getRequestIp(HttpServletRequest request);    /**     * 进行保存日志的方法     *     * @param saveparam     */    public abstract void saveLog(Object... saveparam);    /**     * 根据执行结果或者参数准备情况判断是否保存日志     *     * @param logObj     * @return     */    public abstract boolean doSave(Object logObj);}

demo

@RequestMapping("/save")    @LogAble("保存")    public String saveTT(TestLog log, String abc, HttpServletRequest request,@LogAble("小白") String name) {        return "aaa";    }
package com.test.domain;import com.jockiller.logable.annotion.LogAble;/** * 用来测试的类 * Created by jockiller on 2017/2/25. */@LogAble("雷锋兔")public class TestLog {    @LogAble("名字")    private String name;    private String desc;    public TestLog() {    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getDesc() {        return desc;    }    public void setDesc(String desc) {        this.desc = desc;    }}

总结

代码略显简陋,仅提供了基本实现

AOP是个好东西

码云地址

转载于:https://my.oschina.net/razox/blog/846306

你可能感兴趣的文章
Xfire实现webservice时,对象传递规则及解析简析
查看>>
设计模式——备忘录模式
查看>>
Oracle 常用性能监控SQL语句
查看>>
CentOS 启动提示unexpected inconsistency;RUN fsck MANUALLY
查看>>
red5安装时候出现服务不能启动异常
查看>>
查找目录下的所有文件中是否含有某个字符串
查看>>
段错误以及调试方式
查看>>
javascript中的时间处理
查看>>
JS正则截取两个字符串之间的字符串
查看>>
从零开始学习OpenCL开发(三)深入API
查看>>
新时期读书的价值
查看>>
hdoj 1226 超级password 【隐图BFS】
查看>>
10年工作经验老程序员推荐的7个开发类工具
查看>>
C# sqlserver 2008 连接字符串
查看>>
相关列的基数计算
查看>>
Java阅读word程序说明文件
查看>>
JSpider是一个用Java实现的WebSpider
查看>>
cocos2dx-3.0(13)------SpriteBatchNode与SpriteFrameCache渲染速度
查看>>
oracle备份和升级数据库
查看>>
linux shell 正则表达式(BREs,EREs,PREs)差异比较
查看>>