Springboot使用AOP记录用户操作日志

- 日理万妓 2021-12-10 18:34 442阅读 0赞

Aop类 LogAop

  1. package com.qishimai.travelplan.controller;
  2. import com.qishimai.travelplan.pojo.Sys_log;
  3. import com.qishimai.travelplan.pojo.Sys_user;
  4. import com.qishimai.travelplan.pojo.common.Constant;
  5. import com.qishimai.travelplan.service.Sys_logService;
  6. import com.qishimai.travelplan.service.Sys_userService;
  7. import com.qishimai.travelplan.utils.JwtUtil;
  8. import org.aspectj.lang.JoinPoint;
  9. import org.aspectj.lang.annotation.After;
  10. import org.aspectj.lang.annotation.Aspect;
  11. import org.aspectj.lang.annotation.Before;
  12. import org.springframework.beans.factory.annotation.Autowired;
  13. import org.springframework.stereotype.Component;
  14. import org.springframework.web.bind.annotation.RequestMapping;
  15. import org.springframework.web.context.request.RequestContextHolder;
  16. import org.springframework.web.context.request.ServletRequestAttributes;
  17. import javax.servlet.http.HttpServletRequest;
  18. import java.lang.reflect.Method;
  19. import java.text.SimpleDateFormat;
  20. import java.util.Arrays;
  21. import java.util.Date;
  22. @Component
  23. @Aspect
  24. public class LogAop {
  25. @Autowired
  26. private HttpServletRequest request;
  27. @Autowired
  28. private Sys_logService sysLogService;
  29. @Autowired
  30. private Sys_userService sys_userService;
  31. private Class clazz;//访问的类,对象
  32. private Method method;//访问的方法,对象
  33. Object[] args = null;
  34. //前置通知 只要是获取开始的时间,执行的类是哪一个,执行的是哪一个方法
  35. @Before("execution(public * com.qishimai.travelplan.controller..*.*(..))")
  36. public void doBefore(JoinPoint joinPoint) {
  37. try {
  38. clazz = joinPoint.getTarget().getClass();//具体要访问的类
  39. String requestMethod = joinPoint.getSignature().getName();//获取访问的方法名==method.getName()
  40. args = joinPoint.getArgs();//获取访问的方法的参数
  41. //获取具体执行的方法的Method对象
  42. if (args == null || args.length == 0) {
  43. method = clazz.getMethod(requestMethod);//只能获取无参的方法名
  44. } else {
  45. Class[] classArgs = new Class[args.length];
  46. for (int i = 0; i < args.length; i++) {
  47. classArgs[i] = args[i].getClass();//此处难理解
  48. }
  49. method = clazz.getMethod(requestMethod, classArgs);//获取有参方法名
  50. }
  51. } catch (Exception e) {
  52. System.out.println("***********" + e.getMessage());//打印输出异常信息
  53. }
  54. }
  55. //后置通知
  56. @After("execution(public * com.qishimai.travelplan.controller..*.*(..))")
  57. public void doAfter(JoinPoint joinPoint) {
  58. try {
  59. String url = "";
  60. //获取url
  61. if (clazz != null && method != null & clazz != LogAop.class) {
  62. //1获取类上的@RequestMapping("/..)
  63. RequestMapping classAnnotation = (RequestMapping) clazz.getAnnotation(RequestMapping.class);
  64. if (classAnnotation != null) {
  65. String[] classValue = classAnnotation.value();
  66. //2获取方法上的@RequestMapping("/xxx)
  67. RequestMapping methodAnnotation = method.getAnnotation(RequestMapping.class);
  68. if (methodAnnotation != null) {
  69. String[] methodValue = methodAnnotation.value();
  70. url = classValue[0] + methodValue[0];
  71. HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
  72. String token = request.getHeader("Authorization");
  73. System.err.println("token : " + token);
  74. Sys_log sys_log = new Sys_log();
  75. if (!"".equals(token)) {
  76. String username = JwtUtil.getClaim(token, Constant.ACCOUNT);
  77. Sys_user sys_user = sys_userService.findUserByPhone(username);
  78. sys_log.setUser_id(sys_user.getUser_id());//获取用户id
  79. sys_log.setUser_name(sys_user.getUser_name());
  80. } else {
  81. sys_log.setUser_id(0);
  82. sys_log.setUser_name("匿名用户");
  83. }
  84. //类名太长,直接截取最后一段controller名称
  85. String className = clazz.getName().substring(clazz.getName().lastIndexOf(".")+1);
  86. sys_log.setLog_content("[类名]" + className + "[方法名]" + method.getName() + "[参数]" + Arrays.toString(args));
  87. if (methodValue[0].contains("find") || methodValue[0].contains("select")) {
  88. sys_log.setLog_type(0);//查询
  89. } else if (methodValue[0].contains("save") || methodValue[0].contains("insert")) {
  90. sys_log.setLog_type(1);//插入
  91. } else if (methodValue[0].contains("update")) {
  92. sys_log.setLog_type(3);//更新
  93. } else if (methodValue[0].contains("delete")) {
  94. sys_log.setLog_type(2);//删除
  95. } else {
  96. sys_log.setLog_type(4);//其他操作
  97. }
  98. SimpleDateFormat dateFormat = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
  99. String format = dateFormat.format(new Date());
  100. sys_log.setLog_time(format);
  101. //调用service层完成存储日志的操作
  102. sysLogService.saveLog(sys_log);
  103. }
  104. }
  105. }
  106. } catch (Exception e) {
  107. System.out.println("************" + e.getMessage());
  108. }
  109. }
  110. }

日志实体类

  1. @Data
  2. @ToString
  3. public class Sys_log implements Serializable {
  4. private int log_id;//日志ID
  5. private int user_id;//用户ID
  6. private String user_name;//用户名称
  7. private int log_type;//日志操作类型 增删改查:查:0,增:1,删:2,改:3
  8. private String log_content;//操作内容 操作接口
  9. private String log_time;//记录时间
  10. }

承接LogAop的方法String username = JwtUtil.getClaim(token, Constant.ACCOUNT);

Constant类

  1. package com.qishimai.travelplan.pojo.common;
  2. /**
  3. * 常量
  4. * @author WangWenlong
  5. * @date 2019/4/3 16:03
  6. */
  7. public class Constant {
  8. /**
  9. * redis-OK
  10. */
  11. public final static String OK = "OK";
  12. /**
  13. * redis过期时间,以秒为单位,一分钟
  14. */
  15. public final static int EXRP_MINUTE = 60;
  16. /**
  17. * redis过期时间,以秒为单位,一小时
  18. */
  19. public final static int EXRP_HOUR = 60 * 60;
  20. /**
  21. * redis过期时间,以秒为单位,一天
  22. */
  23. public final static int EXRP_DAY = 60 * 60 * 24;
  24. /**
  25. * redis-key-前缀-shiro:cache:
  26. */
  27. public final static String PREFIX_SHIRO_CACHE = "shiro:cache:";
  28. /**
  29. * redis-key-前缀-shiro:access_token:
  30. */
  31. public final static String PREFIX_SHIRO_ACCESS_TOKEN = "shiro:access_token:";
  32. /**
  33. * redis-key-前缀-shiro:refresh_token:
  34. */
  35. public final static String PREFIX_SHIRO_REFRESH_TOKEN = "shiro:refresh_token:";
  36. /**
  37. * JWT-account:
  38. */
  39. public final static String ACCOUNT = "account";
  40. /**
  41. * JWT-currentTimeMillis:
  42. */
  43. public final static String CURRENT_TIME_MILLIS = "currentTimeMillis";
  44. /**
  45. * PASSWORD_MAX_LEN
  46. */
  47. public static final Integer PASSWORD_MAX_LEN = 8;
  48. }

JwtUtil工具类

  1. package com.qishimai.travelplan.utils;
  2. import com.auth0.jwt.JWT;
  3. import com.auth0.jwt.JWTVerifier;
  4. import com.auth0.jwt.algorithms.Algorithm;
  5. import com.auth0.jwt.exceptions.JWTDecodeException;
  6. import com.auth0.jwt.interfaces.DecodedJWT;
  7. import com.qishimai.travelplan.exception.CustomException;
  8. import com.qishimai.travelplan.pojo.common.Constant;
  9. import com.qishimai.travelplan.utils.common.Base64ConvertUtil;
  10. import org.slf4j.Logger;
  11. import org.slf4j.LoggerFactory;
  12. import org.springframework.beans.factory.annotation.Value;
  13. import org.springframework.stereotype.Component;
  14. import java.io.UnsupportedEncodingException;
  15. import java.util.Date;
  16. /**
  17. * JAVA-JWT工具类
  18. * @author WangWenlong
  19. */
  20. @Component
  21. public class JwtUtil {
  22. /**
  23. * LOGGER
  24. */
  25. private static final Logger LOGGER = LoggerFactory.getLogger(JwtUtil.class);
  26. /**
  27. * 过期时间改为从配置文件获取
  28. */
  29. private static String accessTokenExpireTime;
  30. /**
  31. * JWT认证加密私钥(Base64加密)
  32. */
  33. private static String encryptJWTKey;
  34. @Value("${accessTokenExpireTime}")
  35. public void setAccessTokenExpireTime(String accessTokenExpireTime) {
  36. JwtUtil.accessTokenExpireTime = accessTokenExpireTime;
  37. }
  38. @Value("${encryptJWTKey}")
  39. public void setEncryptJWTKey(String encryptJWTKey) {
  40. JwtUtil.encryptJWTKey = encryptJWTKey;
  41. }
  42. /**
  43. * 校验token是否正确
  44. * @param token Token
  45. * @return boolean 是否正确
  46. * @author WangWenlong
  47. * @date 2019/4/3 9:05
  48. */
  49. public static boolean verify(String token) {
  50. try {
  51. // 帐号加JWT私钥解密
  52. String secret = getClaim(token, Constant.ACCOUNT) + Base64ConvertUtil.decode(encryptJWTKey);
  53. Algorithm algorithm = Algorithm.HMAC256(secret);
  54. JWTVerifier verifier = JWT.require(algorithm)
  55. .build();
  56. DecodedJWT jwt = verifier.verify(token);
  57. return true;
  58. } catch (UnsupportedEncodingException e) {
  59. LOGGER.error("JWTToken认证解密出现UnsupportedEncodingException异常:" + e.getMessage());
  60. throw new CustomException("JWTToken认证解密出现UnsupportedEncodingException异常:" + e.getMessage());
  61. }
  62. }
  63. /**
  64. * 获得Token中的信息无需secret解密也能获得
  65. * @param token
  66. * @param claim
  67. * @return java.lang.String
  68. * @author WangWenlong
  69. * @date 2019/4/7 16:54
  70. */
  71. public static String getClaim(String token, String claim) {
  72. try {
  73. DecodedJWT jwt = JWT.decode(token);
  74. // 只能输出String类型,如果是其他类型返回null
  75. return jwt.getClaim(claim).asString();
  76. } catch (JWTDecodeException e) {
  77. LOGGER.error("解密Token中的公共信息出现JWTDecodeException异常:" + e.getMessage());
  78. throw new CustomException("解密Token中的公共信息出现JWTDecodeException异常:" + e.getMessage());
  79. }
  80. }
  81. /**
  82. * 生成签名
  83. * @param account 帐号
  84. * @return java.lang.String 返回加密的Token
  85. * @author WangWenlong
  86. * @date 2019/4/3 9:07
  87. */
  88. public static String sign(String account, String currentTimeMillis) {
  89. try {
  90. // 帐号加JWT私钥加密
  91. String secret = account + Base64ConvertUtil.decode(encryptJWTKey);
  92. // 此处过期时间是以毫秒为单位,所以乘以1000
  93. Date date = new Date(System.currentTimeMillis() + Long.parseLong(accessTokenExpireTime) * 1000);
  94. Algorithm algorithm = Algorithm.HMAC256(secret);
  95. // 附带account帐号信息
  96. return JWT.create()
  97. .withClaim("account", account)
  98. .withClaim("currentTimeMillis", currentTimeMillis)
  99. .withExpiresAt(date)
  100. .sign(algorithm);
  101. } catch (UnsupportedEncodingException e) {
  102. LOGGER.error("JWTToken加密出现UnsupportedEncodingException异常:" + e.getMessage());
  103. throw new CustomException("JWTToken加密出现UnsupportedEncodingException异常:" + e.getMessage());
  104. }
  105. }
  106. }

最后调用添加方法,将日志插入到日志表(普通的增删改查,所以省略不写了)

发表评论

表情:
评论列表 (有 0 条评论,442人围观)

还没有评论,来说两句吧...

相关阅读

    相关 SpringBoot+AOP实现用户操作记录

    前言: 任何一个项目都会有一个用户操作日志(也叫行为日志)的模块,它主要用来记录某个用户做了某个操作,当出现操作失败时,通过日志就可以快速的查找是哪个用户在哪个模块出现了错