使用拦截器(intercept)和AOP写操作日志-springboot

来源:互联网 发布:linux终端选项 编辑:程序博客网 时间:2024/05/17 23:39

写用户的操作日志,使用拦截器还是使用aop的方式呢?纠结了好久,
先是使用拦截器的方式,写了一半,发现好多参数没法获取,感觉比较麻烦。
后来又换做aop的方式。再后来,发现两种方式其实都可以。对于一些
自定义的参数,可以写一个注解来解决。
以下是两种方式的总结:

日志拦截器方法

1.创建拦截器类

public class LogInterceptor implements HandlerInterceptor {  private final Logger logger = LoggerFactory.getLogger(LogInterceptor.class);  @Override  public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {    //把整个log中的参数,交给logUtil来获取,并返回log对象    Log log = null;    try {      log = LoggerUtil.getLog(httpServletRequest);    }catch (GeneralException g){      logger.warn("logger",g.getMessage());    }catch (Exception e){      logger.error("logger",e.getMessage());    }    httpServletRequest.setAttribute(LoggerUtil.LOG_OPERATE,log);    return true;  }  @Override  public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {  }  @Override  public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {    //返回视图时,插入操作日志    LogMapper logMapper = getMapper(LogMapper.class,httpServletRequest);    Log log = (Log) httpServletRequest.getAttribute(LoggerUtil.LOG_OPERATE);    if(log == null){      logger.warn("日志信息为空",log);    }else{      logMapper.insert(log);    }  }  private <T> T getMapper(Class<T> clazz,HttpServletRequest request)  {    BeanFactory factory = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext());    return factory.getBean(clazz);  }}

拦截器的执行顺序,这里不解释了。这里注意mapper类是如何创建的。
2. 注册拦截器

@Configurationpublic class WebMvcConfig extends WebMvcConfigurerAdapter {    @Override    public void addInterceptors(InterceptorRegistry registry) {        registry.addInterceptor(new UserInterceptor()).addPathPatterns("/**").excludePathPatterns("/user/login");        registry.addInterceptor(new LogInterceptor()).addPathPatterns("/**");        super.addInterceptors(registry);    }}
  1. LoggerUtil类
public class LoggerUtil {    public static final String LOG_TARGET_TYPE="targetType";    public static final String LOG_ACTION="action";    public static final String LOG_REMARK="remark";    public LoggerUtil(){}    public static Log getLog(HttpServletRequest request){        //1.依次获取每个属性信息 userId,operator,action,remark,ip,targetType        Log log = new Log();        log.setIp(LoggerUtil.getCliectIp(request));        log.setOperator("operator");        log.setUserId(1);        log.setAction("create");        log.setCustomerId("0000-1111");        log.setTargetType("message");        log.setRemark("消息发布");        return log;    }    /**     * 获取客户端ip地址     * @param request     * @return     */    public static String getCliectIp(HttpServletRequest request){        String ip = request.getHeader("X-Real-IP");        if (!StringUtils.isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {            return ip;        }        ip = request.getHeader("X-Forwarded-For");        if (!StringUtils.isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {            // 多次反向代理后会有多个IP值,第一个为真实IP。            int index = ip.indexOf(',');            if (index != -1) {                return ip.substring(0, index);            } else {                return ip;            }        } else {            return request.getRemoteAddr();        }    }}
  • loggerUtil类主要返回一个Log对象的实体类。

AOP记录操作日志

  1. 引入springboot的aop的jar
<dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-aop</artifactId>        </dependency>
  1. LogAopAction类
@Aspect@Componentpublic class LogAopAction {    private final Logger logger = LoggerFactory.getLogger(LogAopAction.class);    @Autowired    private LogMapper logMapper;    @Pointcut("execution(public * cn.vobile.hss.controller..*(..))")    private void pointCutMethod(){}    /**     * 记录操作日志     */    @After("pointCutMethod()")  // 使用上面定义的切入点    public void recordLog(JoinPoint joinPoint){        Long start = System.currentTimeMillis();        Log log = new Log();        HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();        User user = (User) request.getSession().getAttribute("user");        if(user == null){            logger.warn("user 信息为空");        }else{            log.setUserId(user.getId());            log.setOperator(user.getUserName());            log.setCustomerId(user.getCustomerId());        }        //下面开始获取 ip,targetType,remark,action        try {            Map<String,String> map = getLogMark(joinPoint);            log.setAction(map.get(LoggerUtil.LOG_ACTION));            log.setTargetType(map.get(LoggerUtil.LOG_TARGET_TYPE));            log.setRemark(map.get(LoggerUtil.LOG_REMARK));            log.setIp(LoggerUtil.getCliectIp(request));            logMapper.insert(log);        }catch (ClassNotFoundException c){            logger.error(c.getMessage());        }catch (Exception e){            logger.error("插入日志异常",e.getMessage());        }        Long end = System.currentTimeMillis();        logger.info("记录日志消耗时间:"+ (end - start) / 1000);    }    private Map<String,String> getLogMark(JoinPoint joinPoint) throws ClassNotFoundException {        Map<String,String> map = new HashMap<>();        String methodName = joinPoint.getSignature().getName();        String targetName = joinPoint.getTarget().getClass().getName();        Class targetClass = Class.forName(targetName);        Method[] methods = targetClass.getMethods();        for (Method method : methods){            if(method.getName().equals(methodName)){                LogAnnotation logAnnotation = method.getAnnotation(LogAnnotation.class);                map.put(LoggerUtil.LOG_TARGET_TYPE,logAnnotation.targetType());                map.put(LoggerUtil.LOG_ACTION,logAnnotation.action());                map.put(LoggerUtil.LOG_REMARK,logAnnotation.remark());            }        }        return map;    }}

2.1 Pointcut优化部分

//切入点设置到自定义的log注解上    @Pointcut("@annotation(cn.vobile.hss.annotation.LogAnnotation)")    private void pointCutMethod(){}

我们可以将切入方法设置到自定义的log注解上,这样aop就会只在有log注解的方法进行拦截了。

  1. 特殊字段的注解
@Retention(RetentionPolicy.RUNTIME)//注解会在class中存在,运行时可通过反射获取@Target(ElementType.METHOD)//目标是方法@Documented//文档生成时,该注解将被包含在javadoc中,可去掉public @interface LogAnnotation {    String action() default "";    String targetType() default "";    String remark() default "";}
  1. 引用部分
@LogAnnotation(targetType = "user",action = "create",remark = "用户登录")    @RequestMapping(value = "/login",method = RequestMethod.POST)    public ModelMap login(HttpServletRequest request){        ModelMapHelper helper = new ModelMapHelper();        String userName = request.getParameter("userName");        String password = request.getParameter("password");        String imgCode = request.getParameter("imageCode");        String sessionCode = (String) request.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY);        logger.info("input code is "+imgCode+" session id is "+request.getSession().getId()+" session code is "+sessionCode);        if(StringUtils.isEmpty(imgCode)){            helper.setErrorMap("验证码不能为空");            return helper;        }        .....}
阅读全文
1 0