spring aop 实现系统操作日志记录存储到数据库
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.附带工具类
- 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();}
}
- 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;}}
- 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 实现系统操作日志记录存储到数据库相关推荐
- Spring AOP 切面记录操作日志
前言 实际业务,有时候需要记录服务的操作日志,我们可以利用SpringAOP 切面来拦截记录用户操作:用户使用session或者前端传值都可以. 1.创建日志记录接口 首先我们得有一个接口,这个接口可 ...
- 系统操作日志实现_JAVA
最近需求需要记录系统日志,在网上查询发现目前有两种主流方式.一种是利用AOP注解实现,一种是利用拦截器实现. AOP实现的方式更为灵活,但需要为每一个需要记录的方法上加上注解(类似于白名单). 我这个 ...
- Spring Boot——基于AOP的HTTP操作日志解决方案
解决方案 package com.hailiu.web.aop;import com.fasterxml.jackson.databind.ObjectMapper; import com.haili ...
- spring aop 自定义注解配合swagger注解保存操作日志到mysql数据库含(源码)
spring aop 自定义注解保存操作日志到mysql数据库 一.思路 二.自定义注解 三.编写操作日志 四.编写操作日志切面\增强 五.使用 六.`注意` 一.思路 利用spring aop 对方 ...
- Spring Boot + Aop 记录用户操作日志
目录 一.前言 二.实战 1.设计用户操作日志表: sys_oper_log 2.引入依赖 3.自定义用户操作日志注解 4.自定义用户操作日志切面 5.MyLog注解的使用 6.最终效果 三.总结 一 ...
- 中操作日志文件记录的是什么_SpringBoot+AOP实现用户操作日志的记录
前言: 任何一个项目都会有一个用户操作日志(也叫行为日志)的模块,它主要用来记录某个用户做了某个操作,当出现操作失败时,通过日志就可以快速的查找是哪个用户在哪个模块出现了错误,以便于开发人员快速定位问 ...
- 系统操作日志设计(二)
上一篇<系统操作日志设计>,已基本介绍了为什么要系统操作日志和设计系统操作日志部分内容,如不清楚系统操作日志的请点这里. :) 通了解<系统操作日志设计>,已基本明确我们不能通 ...
- 如何在springboot项目中使用自定义注解实现系统操作日志的功能
通常我们的项目中都需要记录操作日志,方便回溯问题,找到根源. 因为给项目添加日志记录功能是属于系统级别的功能,所以这个问题我们马上会想到spring的AOP,可以通过切面的形式.那么怎么来实现呢? 先 ...
- Java之——Spring AOP自定义注解实现日志管理
转载请注明出处:https://blog.csdn.net/l1028386804/article/details/80295737 1.定义日志类SystemLog package io.mykit ...
最新文章
- 漫画 | 辞职前与老板的最后一次谈话有哪些禁忌?
- Razor @Html.Raw()的作用
- LA3971组装电脑
- g标签 怎么设置svg_SVG(可缩放矢量图形)图片添加、高斯模糊、渐变与g标签
- java 静态方法的使用_java的静态方法的使用
- linux standby模式,搭建11g 单机 linux standby 操作文档
- Windows XP增强dos命令
- PyQt+QtDesigner及相关插件的安装和设置
- LaTeX常用的符号
- 电子科技大学《图论及其应用》复习总结--第五章 匹配与因子分解
- 远程计算机上不接受445端口,服务器禁止远程445端口
- 行业步入快速发展期,万亿级“虚拟蛋糕“将被如何瓜分?
- 数论(继续补充)(gcd + lcm + qpow + prime+qmul)
- 【Python】大数据挖掘课程作业3——使用朴素贝叶斯分类对B站评论进行分析
- 数据结构C语言版(答案)
- 五大方面多管齐下,用友助力企业建设世界一流司库体系
- CodeForces - 711A 找座位 难度:C++入门 复杂度:简单 翻译难度:难
- linux 第七天 linuxprobe
- 由JVM深入了解Java的线程安全与锁优化
- CSDN大神多,在这里驻扎一下,沾沾神气