1.引入依赖

<!--spring切面aop依赖-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>在application.properties文件里加这样一条配置
spring.aop.auto=true //这个配置我的例子中没有加 也正常运行

2.yml配置

spring:aop:auto: true    #这个配置我的例子中没有加 也正常运行

3.创建实体类

import lombok.Data;
import java.io.Serializable;
import java.util.Date;/*** @author Mr.Wang* @create 2020/10/26*/
@Data
public class SysLog implements Serializable {private Long id;private String username; //用户名private String operation; //操作private String method; //方法名private String params; //参数private String ip; //ip地址private Date createDate; //操作时间private String account;  //账户唯一标识
}

4.使用spring 的 aop 技术切到自定义注解上,创建一个自定义注解类

/*** @author Mr.Wang* @create 2020/10/26*/import java.lang.annotation.*;/*** 自定义注解类*/
@Target(ElementType.METHOD) //注解放置的目标位置,METHOD是可注解在方法级别上
@Retention(RetentionPolicy.RUNTIME) //注解在哪个阶段执行
@Documented //生成文档
public @interface MyLog {String value() default "";
}

5.创建aop切面实现类

package team.ggbond.hotel.component;import com.alibaba.fastjson.JSON;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import team.ggbond.hotel.entity.log.SysLog;
import team.ggbond.hotel.service.MyLog;
import team.ggbond.hotel.service.impl.SysLogService;
import team.ggbond.hotel.util.HttpContextUtils;
import team.ggbond.hotel.util.IPUtils;
import team.ggbond.hotel.util.JwtTokenUtil;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.util.Date;/*** @author Mr.Wang* @create 2020/10/26*/@Aspect
@Component
public class SysLogAspect {@Autowiredprivate SysLogService sysLogService;//定义切点 @Pointcut//在注解的位置切入代码@Pointcut("@annotation(team.ggbond.hotel.service.MyLog)")public void logPoinCut() {}//切面 配置通知@AfterReturning("logPoinCut()")public void saveSysLog(JoinPoint joinPoint) {//保存日志SysLog sysLog = new SysLog();//从切面织入点处通过反射机制获取织入点处的方法MethodSignature signature = (MethodSignature) joinPoint.getSignature();//获取切入点所在的方法Method method = signature.getMethod();//获取操作MyLog myLog = method.getAnnotation(MyLog.class);if (myLog != null) {String value = myLog.value();sysLog.setOperation(value);//保存获取的操作}//获取请求的类名String className = joinPoint.getTarget().getClass().getName();//获取请求的方法名String methodName = method.getName();sysLog.setMethod(className + "." + methodName);//请求的参数Object[] args = joinPoint.getArgs();//将参数所在的数组转换成jsonString params = JSON.toJSONString(args);sysLog.setParams(params);sysLog.setCreateDate(new Date());//获取用户名//此例子用到了ShiroUtils框架来实现获取用户名,此处还可以用session来获取登录操作名//例:HttpSession session=((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest().getSession();HttpSession session=((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getSession();
//        session.get//获取用户ip地址HttpServletRequest request = HttpContextUtils.getHttpServletRequest();sysLog.setIp(IPUtils.getIpAddr(request));//调用service保存SysLog实体类到数据库//sysLogService.save(sysLog);String token = request.getHeader(JwtTokenUtil.TOKEN_HEADER).replace(JwtTokenUtil.TOKEN_PREFIX, "");String userRole = JwtTokenUtil.getUserRole(token);String count = JwtTokenUtil.getUsername(token);String username=null;    if(userRole.equals("ROLE_USER")){username =  sysLogService.findUsernameByOpenId(count);}else if(userRole.equals("ROLE_MERCHANT")){username =  sysLogService.findUsernameByTelephone(count);}sysLog.setUsername(username);sysLog.setAccount(count);sysLogService.insertSysLog(sysLog);}}

注意:此处因为之前数据库设计不合理,在JWT中获取出来的用户名不正常,所以这里写多了写判断查询

6.接下来就可以在需要监控的方法上添加 aop的自定义注解

格式为 @+自定义注解的类名 @MyLog

eg:

//例如在contoller类的方法上加注解@MyLog(value = "修改客户头像") @PostMapping("customeravatar")public Result updateCustomerAvatar(@RequestBody  Customer customer) {Integer integer = customerService.updateCustomerAvatar(customer.getAvatar(),customer.getOpenId());if (integer != 0) {return new Result(200, null, "修改客户头像成功");} else {return new Result(400, null, "修改客户头像失败");}}

8.Mapper

package team.ggbond.hotel.mapper;import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import team.ggbond.hotel.entity.log.SysLog;/*** @author Mr.Wang* @create 2020/10/26*/
public interface SysLogMapper {/*** 插入日志* @param sysLog* @return*/@Insert("INSERT INTO syslog (username,operation,method,params,ip,create_date,account)\n" +"VALUES(#{username},#{operation},#{method},#{params},#{ip},#{createDate},#{account})")Integer insertSysLog(SysLog sysLog);/*** 通过openId查询用户名字* @param openId* @return*/@Select("SELECT c_name  from customer WHERE open_id=#{openId}")String  findUsernameByOpenId(String openId);/*** 通过telephone查询商家名字* @param telephone* @return*/@Select("SELECT m_name  from merchant WHERE telephone=#{openId}")String  findUsernameByTelephone(String telephone);
}

serviceImpl只是普通调用,此处省略

9.附带工具类

  1. HttpContextUtils

import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Objects;/*** @author Mr.Wang* @create 2020/10/26*/
public class HttpContextUtils {public static HttpServletRequest getHttpServletRequest() {return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();}
}
  1. IPUtils
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.net.InetAddress;
import java.net.UnknownHostException;public class IPUtils {private IPUtils() {}/*** 获取当前网络ip* @param request* @return*/public static String getIpAddr(HttpServletRequest request){String ipAddress = request.getHeader("x-forwarded-for");if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getHeader("Proxy-Client-IP");}if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getHeader("WL-Proxy-Client-IP");}if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getRemoteAddr();if(ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")){//根据网卡取本机配置的IPInetAddress inet=null;try {inet = InetAddress.getLocalHost();} catch (UnknownHostException e) {e.printStackTrace();}ipAddress= inet.getHostAddress();}}//对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割if(ipAddress!=null && ipAddress.length()>15){ //"***.***.***.***".length() = 15if(ipAddress.indexOf(",")>0){ipAddress = ipAddress.substring(0,ipAddress.indexOf(","));}}return ipAddress;}/*** 获得MAC地址* @param ip* @return*/public static String getMACAddress(String ip){String str = "";String macAddress = "";try {Process p = Runtime.getRuntime().exec("nbtstat -A " + ip);InputStreamReader ir = new InputStreamReader(p.getInputStream());LineNumberReader input = new LineNumberReader(ir);for (int i = 1; i < 100; i++) {str = input.readLine();if (str != null) {if (str.indexOf("MAC Address") > 1) {macAddress = str.substring(str.indexOf("MAC Address") + 14, str.length());break;}}}} catch (IOException e) {e.printStackTrace(System.out);}return macAddress;}}
  1. JwtTokenUtil
package team.ggbond.hotel.util;import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtParser;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;
import team.ggbond.hotel.entity.Users;import java.util.Date;
import java.util.HashMap;
import java.util.Map;/*** JwtToken生成的工具类* JWT token的格式:header.payload.signature* header的格式(算法、token的类型):* {"alg": "HS512","type": "JWT"}* payload的格式(用户名、创建时间、生成时间):* {"sub":"wang","created":1489079981393,"exp":1489684781}* signature的生成算法:* HMACSHA512(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)*/
@Component
public class JwtTokenUtil {//header和prefixpublic static final String TOKEN_HEADER = "Authorization";public static final String TOKEN_PREFIX = "Bearer ";//主题public static final String SUBJECT = "congge";//时间(一天)public static final long EXPIRATION = 1000 * 24 * 60 * 60;//密钥(signature=HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), APPSECRET_KEY))public static final String APPSECRET_KEY = "zhe_shi_wo_de_mi_yao";//权限private static final String ROLE_CLAIMS = "rol";/*** 生成token* @param username* @param role* @return*/public static String createToken(String username,String role) {//指定签名的时候使用的签名算法,也就是header那部分,jjwt已经将这部分内容封装好了。SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;//过期时间(一天后)Date expireDate=new Date(System.currentTimeMillis()+EXPIRATION);//创建payload的私有声明()Map<String,Object> map = new HashMap<>();map.put(ROLE_CLAIMS, role);//        System.out.println("当前时间:"+new Date());String token = Jwts.builder()//这里其实就是new一个JwtBuilder,设置jwt的body.setClaims(map)
//                .claim("username",username).setAudience(username)//aud.setIssuedAt(new Date())//.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION)).signWith(signatureAlgorithm, APPSECRET_KEY).compact();System.out.println("token:"+token);return token;}/*** 解密Token** @param token* @return* @throws Exception*/public static Claims checkJWT(String token) {try {final Claims claims = Jwts.parser()//得到DefaultJwtParser.setSigningKey(APPSECRET_KEY)//设置签名的秘钥.parseClaimsJws(token).getBody();//设置需要解析的jwtreturn claims;} catch (Exception e) {e.printStackTrace();//token 校验失败, 抛出Token验证非法异常return null;}}/*** 获取用户名* @param token* @return*/public static String getUsername(String token){Claims claims = Jwts.parser().setSigningKey(APPSECRET_KEY).parseClaimsJws(token).getBody();return claims.get("aud").toString();}/*** 获取用户角色* @param token* @return*/public static String getUserRole(String token){Claims claims = Jwts.parser().setSigningKey(APPSECRET_KEY).parseClaimsJws(token).getBody();return claims.get("rol").toString();}/*** 是否过期* @param token* @return*/public static boolean isExpiration(String token){Claims claims = Jwts.parser().setSigningKey(APPSECRET_KEY).parseClaimsJws(token).getBody();return claims.getExpiration().before(new Date());}/*** 获取到期时间* @param token* @return*/public static String getExpTime(String token){Claims claims = Jwts.parser().setSigningKey(APPSECRET_KEY).parseClaimsJws(token).getBody();return claims.getExpiration().toString();}//    public static void main(String[] args) {//        String username = "wzj";
//        String rol = "admin";
//        String token = createToken(username,rol);
//        System.out.println(token);
//
        System.out.println(JWT.require(Algorithm.HMAC256(APPSECRET_KEY)).build().verify(token).getClaims());
//
        Claims claimss = Jwts.parser()//得到DefaultJwtParser
                .setSigningKey(APPSECRET_KEY)//设置签名的秘钥
                .parseClaimsJws(token)
                .getBody()
                ;
        System.out.println(claimss);
//
        Claims claims = checkJWT(token);
        System.out.println(claims);
        System.out.println(claims.get("aud"));

        System.out.println(getUsername(token));
        System.out.println(getUserRole(token));
        System.out.println(isExpiration(token));
//
//    }//    public static String generateJsonWebToken(Users user) {//
        if (user.getId() == null || user.getUserName() == null || user.getFaceImage() == null) {//        if (user.getUsername() == null) {//            return null;
//        }
//
//        Map<String,Object> map = new HashMap<>();
//        map.put(ROLE_CLAIMS, "rol");
//
//        String token = Jwts
//                .builder()
//                .setSubject(SUBJECT)
//                .setClaims(map)
                .claim("id", user.getId())
//                .claim("name", user.getUsername())
                .claim("img", user.getFaceImage())
//                .setIssuedAt(new Date())
//                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION))
//                .signWith(SignatureAlgorithm.HS256, APPSECRET_KEY).compact();
//        return token;
//    }
}

10.运行效果

spring aop 实现系统操作日志记录存储到数据库相关推荐

  1. Spring AOP 切面记录操作日志

    前言 实际业务,有时候需要记录服务的操作日志,我们可以利用SpringAOP 切面来拦截记录用户操作:用户使用session或者前端传值都可以. 1.创建日志记录接口 首先我们得有一个接口,这个接口可 ...

  2. 系统操作日志实现_JAVA

    最近需求需要记录系统日志,在网上查询发现目前有两种主流方式.一种是利用AOP注解实现,一种是利用拦截器实现. AOP实现的方式更为灵活,但需要为每一个需要记录的方法上加上注解(类似于白名单). 我这个 ...

  3. Spring Boot——基于AOP的HTTP操作日志解决方案

    解决方案 package com.hailiu.web.aop;import com.fasterxml.jackson.databind.ObjectMapper; import com.haili ...

  4. spring aop 自定义注解配合swagger注解保存操作日志到mysql数据库含(源码)

    spring aop 自定义注解保存操作日志到mysql数据库 一.思路 二.自定义注解 三.编写操作日志 四.编写操作日志切面\增强 五.使用 六.`注意` 一.思路 利用spring aop 对方 ...

  5. Spring Boot + Aop 记录用户操作日志

    目录 一.前言 二.实战 1.设计用户操作日志表: sys_oper_log 2.引入依赖 3.自定义用户操作日志注解 4.自定义用户操作日志切面 5.MyLog注解的使用 6.最终效果 三.总结 一 ...

  6. 中操作日志文件记录的是什么_SpringBoot+AOP实现用户操作日志的记录

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

  7. 系统操作日志设计(二)

    上一篇<系统操作日志设计>,已基本介绍了为什么要系统操作日志和设计系统操作日志部分内容,如不清楚系统操作日志的请点这里. :) 通了解<系统操作日志设计>,已基本明确我们不能通 ...

  8. 如何在springboot项目中使用自定义注解实现系统操作日志的功能

    通常我们的项目中都需要记录操作日志,方便回溯问题,找到根源. 因为给项目添加日志记录功能是属于系统级别的功能,所以这个问题我们马上会想到spring的AOP,可以通过切面的形式.那么怎么来实现呢? 先 ...

  9. Java之——Spring AOP自定义注解实现日志管理

    转载请注明出处:https://blog.csdn.net/l1028386804/article/details/80295737 1.定义日志类SystemLog package io.mykit ...

最新文章

  1. 漫画 | 辞职前与老板的最后一次谈话有哪些禁忌?
  2. Razor @Html.Raw()的作用
  3. LA3971组装电脑
  4. g标签 怎么设置svg_SVG(可缩放矢量图形)图片添加、高斯模糊、渐变与g标签
  5. java 静态方法的使用_java的静态方法的使用
  6. linux standby模式,搭建11g 单机 linux standby 操作文档
  7. Windows XP增强dos命令
  8. PyQt+QtDesigner及相关插件的安装和设置
  9. LaTeX常用的符号
  10. 电子科技大学《图论及其应用》复习总结--第五章 匹配与因子分解
  11. 远程计算机上不接受445端口,服务器禁止远程445端口
  12. 行业步入快速发展期,万亿级“虚拟蛋糕“将被如何瓜分?
  13. 数论(继续补充)(gcd + lcm + qpow + prime+qmul)
  14. 【Python】大数据挖掘课程作业3——使用朴素贝叶斯分类对B站评论进行分析
  15. 数据结构C语言版(答案)
  16. 五大方面多管齐下,用友助力企业建设世界一流司库体系
  17. CodeForces - 711A 找座位 难度:C++入门 复杂度:简单 翻译难度:难
  18. linux 第七天 linuxprobe
  19. 由JVM深入了解Java的线程安全与锁优化
  20. CSDN大神多,在这里驻扎一下,沾沾神气

热门文章

  1. 面向对象基础 python
  2. 物联网时代的35款开源工具
  3. 自己写的iOS BLE SDK
  4. 靶机渗透测试(Tre: 1)
  5. Python numpy.testing.assert_approx_equal函数方法的使用
  6. OA办公系统选型必读:深度解析移动OA
  7. 微信打开链接提示“该网页包含不安全内容,已停止访问”的解决方案
  8. SQL练习:查询近30天活跃用户数
  9. (13)主流以太网类型及各层的主要功能
  10. 5 mysql 凤舞天骄_凤舞天骄私服服务端菜鸟架设步步走