type
status
date
slug
summary
tags
category
icon
password
标签
需求场景
很多时候我们需要在项目中对用户的操作记录进行日志持久化操作,在SpringBoot中采用自定义注解方式采用Spring Aop拦截器实现对用户请求的操作日记持久化。
引入依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
自定义注解类
创建自定义系统日志注解类,记录操作模块、方法名、描述信息。
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 自定义系统日志注解 * Created by admin on 2017/7/24. */ @Target({ElementType.PARAMETER, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface SysLog { String module() default ""; //模块名称 系统管理-用户管理 String methods() default ""; //方法名称 String description() default ""; //描述 }
拦截器类
创建拦截器类,在该类中,定义了拦截规则:拦截所有有@SysLog注解的方法。
package com.iws.aspect; import com.iws.model.SysLog; import com.iws.service.SysLogService; import com.iws.util.IpUtils; import com.iws.util.T; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; 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.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.lang.reflect.Method; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; /** * 系统日志拦截器 * * @author calf * @create 2017-07-25 11:01 */ @Aspect @Component public class SysLogAspect { private static Logger logger = LoggerFactory.getLogger(SysLogAspect.class); @Autowired private SysLogService sysLogService; /** * 定义拦截规则:拦截所有有SysLog注解的方法 */ @Pointcut("@annotation(com.iws.annotation.SysLog)") public void sysLogPointcut(){} @Around("sysLogPointcut()") public Object Interceptor(ProceedingJoinPoint joinPoint) throws Throwable { Object result = null; long beginTime = System.currentTimeMillis(); MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); //获取被拦截的方法 //日志持久化对象 SysLog log = new SysLog(); log.setStartTime(beginTime); com.iws.annotation.SysLog sysLog= method.getAnnotation(com.iws.annotation.SysLog.class); //获取注解类 String module = sysLog.module(); //获取注解的模块名 if (StringUtils.isEmpty(module)) { //获取被拦截方法的类名 module = signature.getDeclaringTypeName(); } String methods = sysLog.methods(); //获取注解的方法名 if (StringUtils.isEmpty(methods)) { //获取被拦截的方法名 methods = method.getName(); } String description = sysLog.description(); //获取注解的描述 //log.setBenaName(module); log.setMethod(methods); //log.setDescription(description); //保存所有请求参数,用于输出日志 Set<Object> paramSet = new LinkedHashSet<>(); logger.debug("拦截请求开始,类:{},方法:{}", module, methods); Object[] args = joinPoint.getArgs(); for (Object arg : args) { logger.debug("arg: {}", arg); if (arg instanceof Map<?,?>) { //提取方法中的MAP参数,用于记录进日志中 Map<String, Object> map = (Map<String, Object>) arg; paramSet.add(map); } else if (arg instanceof HttpServletRequest) { //提取request的请求参数 HttpServletRequest request = (HttpServletRequest) arg; Map<String, String[]> paramMap = request.getParameterMap(); if (!paramMap.isEmpty()) { paramSet.add(paramMap); } log.setIp(IpUtils.getIp(request)); //ip地址 log.setUri(request.getRequestURI()); //请求uri } else if (arg instanceof HttpServletResponse) { //do nothing... } } //执行被拦截的方法 result = joinPoint.proceed(); log.setParams(T.getJsonString(paramSet)); //参数 log.setResult(T.getJsonString(result)); //结果 long reqTime = System.currentTimeMillis() - beginTime; log.setReqTime(T.integerValue(String.valueOf(reqTime))); //耗时 sysLogService.save(log); //insert db logger.debug("拦截请求结束,类:{}, 方法:{}, 耗时:{}ms", module, methods, reqTime); return result; } }
测试代码
package com.iws.web; import com.iws.annotation.SysLog; import com.iws.util.T; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; /** * @author calf * @create 2017-07-25 13:43 */ @Controller public class TestController { @SysLog @ResponseBody @RequestMapping("/test") public String test() { return "test"; } @SysLog(module = "测试模块", methods = "返回JSON详情") @ResponseBody @RequestMapping("/test/detail") public String detail(@RequestParam(name = "arg") String arg) { return T.getJson(200, "success", "navTabId", null); } }
运行结果
[nio-9091-exec-9] com.iws.aspect.SysLogAspect : 拦截请求开始,类:com.iws.web.TestController,方法:test [nio-9091-exec-9] com.iws.aspect.SysLogAspect : 拦截请求结束,类:com.iws.web.TestController, 方法:test, 耗时:69ms [nio-9091-exec-8] com.iws.aspect.SysLogAspect : 拦截请求开始,类:测试模块,方法:返回JSON详情 [nio-9091-exec-8] com.iws.aspect.SysLogAspect : arg: ddd [nio-9091-exec-8] com.iws.aspect.SysLogAspect : 拦截请求结束,类:测试模块, 方法:返回JSON详情, 耗时:25ms