您好,欢迎来到三六零分类信息网!老站,搜索引擎当天收录,欢迎发信息

怎么使用SpringBoot+Aop记录用户操作日志

2024/7/26 16:51:52发布32次查看
1、设计用户操作日志表: sys_oper_log
对应实体类为sysoperlog.java
import com.baomidou.mybatisplus.annotation.idtype;import com.baomidou.mybatisplus.annotation.tableid;import io.swagger.annotations.apimodelproperty;import lombok.data;import lombok.equalsandhashcode;import lombok.experimental.accessors;import java.io.serializable;import java.util.date;/** * <p> * 操作日志记录 * </p> */@data@equalsandhashcode(callsuper = false)@accessors(chain = true)public class sysoperlog implements serializable { private static final long serialversionuid = 1l; @tableid(value = "id", type = idtype.auto) @apimodelproperty("主键id") private integer id; @apimodelproperty("模块标题") private string title; @apimodelproperty("参数") private string optparam; @apimodelproperty("业务类型(0其它 1新增 2修改 3删除)") private integer businesstype; @apimodelproperty("路径名称") private string uri; @apimodelproperty("操作状态(0正常 1异常)") private integer status; @apimodelproperty("错误消息") private string errormsg; @apimodelproperty("操作时间") private date opertime;}
2、引入依赖<dependency> <groupid>com.alibaba</groupid> <artifactid>fastjson</artifactid> <version>2.0.9</version></dependency><dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-aop</artifactid></dependency>
3、自定义用户操作日志注解mylog.java
import java.lang.annotation.*;@target({elementtype.parameter, elementtype.method})@retention(retentionpolicy.runtime)@documentedpublic @interface mylog { // 自定义模块名,eg:登录 string title() default ""; // 方法传入的参数 string optparam() default ""; // 操作类型,eg:insert, update... businesstype businesstype() default businesstype.other; }
businesstype.java &mdash; 操作类型枚举类
public enum businesstype { // 其它 other, // 查找 select, // 新增 insert, // 修改 update, // 删除 delete,}
4、自定义用户操作日志切面logaspect.java
import com.alibaba.fastjson.jsonobject;import iot.sixiang.license.entity.sysoperlog;import iot.sixiang.license.handler.iotlicenseexception;import iot.sixiang.license.jwt.userutils;import iot.sixiang.license.service.sysoperlogservice;import lombok.extern.slf4j.slf4j;import org.apache.commons.lang3.stringutils;import org.aspectj.lang.joinpoint;import org.aspectj.lang.signature;import org.aspectj.lang.annotation.afterreturning;import org.aspectj.lang.annotation.afterthrowing;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 java.lang.reflect.method;import java.util.date;import java.util.hashmap;import java.util.map;@aspect@component@slf4jpublic class logaspect { /** * 该service及其实现类相关代码请自行实现,只是一个简单的插入数据库操作 */ @autowired private sysoperlogservice sysoperlogservice; /** * @annotation(mylog类的路径) 在idea中,右键自定义的mylog类-> 点击copy reference */ @pointcut("@annotation(xxx.xxx.xxx.mylog)") public void logpointcut() { log.info("------>配置织入点"); } /** * 处理完请求后执行 * * @param joinpoint 切点 */ @afterreturning(pointcut = "logpointcut()") public void doafterreturning(joinpoint joinpoint) { handlelog(joinpoint, null); } /** * 拦截异常操作 * * @param joinpoint 切点 * @param e 异常 */ @afterthrowing(value = "logpointcut()", throwing = "e") public void doafterthrowing(joinpoint joinpoint, exception e) { handlelog(joinpoint, e); } private void handlelog(final joinpoint joinpoint, final exception e) { // 获得mylog注解 mylog controllerlog = getannotationlog(joinpoint); if (controllerlog == null) { return; } sysoperlog operlog = new sysoperlog(); // 操作状态(0正常 1异常) operlog.setstatus(0); // 操作时间 operlog.setopertime(new date()); if (e != null) { operlog.setstatus(1); // iotlicenseexception为本系统自定义的异常类,读者若要获取异常信息,请根据自身情况变通 operlog.seterrormsg(stringutils.substring(((iotlicenseexception) e).getmsg(), 0, 2000)); } // userutils.geturi();获取方法上的路径 如:/login,本文实现方法如下: // 1、在拦截器中 string uri = request.getrequesturi(); // 2、用threadlocal存放uri,userutils.seturi(uri); // 3、userutils.geturi(); string uri = userutils.geturi(); operlog.seturi(uri); // 处理注解上的参数 getcontrollermethoddescription(joinpoint, controllerlog, operlog); // 保存数据库 sysoperlogservice.addoperlog(operlog.gettitle(), operlog.getbusinesstype(), operlog.geturi(), operlog.getstatus(), operlog.getoptparam(), operlog.geterrormsg(), operlog.getopertime()); } /** * 是否存在注解,如果存在就获取,不存在则返回null * @param joinpoint * @return */ private mylog getannotationlog(joinpoint joinpoint) { signature signature = joinpoint.getsignature(); methodsignature methodsignature = (methodsignature) signature; method method = methodsignature.getmethod(); if (method != null) { return method.getannotation(mylog.class); } return null; } /** * 获取controller层上mylog注解中对方法的描述信息 * @param joinpoint 切点 * @param mylog 自定义的注解 * @param operlog 操作日志实体类 */ private void getcontrollermethoddescription(joinpoint joinpoint, mylog mylog, sysoperlog operlog) { // 设置业务类型(0其它 1新增 2修改 3删除) operlog.setbusinesstype(mylog.businesstype().ordinal()); // 设置模块标题,eg:登录 operlog.settitle(mylog.title()); // 对方法上的参数进行处理,处理完:username=xxx,password=xxx string optparam = getannotationvalue(joinpoint, mylog.optparam()); operlog.setoptparam(optparam); } /** * 对方法上的参数进行处理 * @param joinpoint * @param name * @return */ private string getannotationvalue(joinpoint joinpoint, string name) { string paramname = name; // 获取方法中所有的参数 map<string, object> params = getparams(joinpoint); // 参数是否是动态的:#{paramname} if (paramname.matches("^#\\{\\d*\\}")) { // 获取参数名,去掉#{ } paramname = paramname.replace("#{", "").replace("}", ""); // 是否是复杂的参数类型:对象.参数名 if (paramname.contains(".")) { string[] split = paramname.split("\\."); // 获取方法中对象的内容 object object = getvalue(params, split[0]); // 转换为jsonobject jsonobject jsonobject = (jsonobject) jsonobject.tojson(object); // 获取值 object o = jsonobject.get(split[1]); return string.valueof(o); } else {// 简单的动态参数直接返回 stringbuilder str = new stringbuilder(); string[] paranames = paramname.split(","); for (string paraname : paranames) { string val = string.valueof(getvalue(params, paraname)); // 组装成 username=xxx,password=xxx, str.append(paraname).append("=").append(val).append(","); } // 去掉末尾的, if (str.tostring().endswith(",")) { string substring = str.substring(0, str.length() - 1); return substring; } else { return str.tostring(); } } } // 非动态参数直接返回 return name; } /** * 获取方法上的所有参数,返回map类型, eg: 键:"username",值:xxx 键:"password",值:xxx * @param joinpoint * @return */ public map<string, object> getparams(joinpoint joinpoint) { map<string, object> params = new hashmap<>(8); // 通过切点获取方法所有参数值["zhangsan", "123456"] object[] args = joinpoint.getargs(); // 通过切点获取方法所有参数名 eg:["username", "password"] methodsignature signature = (methodsignature) joinpoint.getsignature(); string[] names = signature.getparameternames(); for (int i = 0; i < args.length; i++) { params.put(names[i], args[i]); } return params; } /** * 从map中获取键为paramname的值,不存在放回null * @param map * @param paramname * @return */ private object getvalue(map<string, object> map, string paramname) { for (map.entry<string, object> entry : map.entryset()) { if (entry.getkey().equals(paramname)) { return entry.getvalue(); } } return null; }}
5、mylog注解的使用@getmapping("login")@mylog(title = "登录", optparam = "#{username},#{password}", businesstype = businesstype.other)public dataresult login(@requestparam("username") string username, @requestparam("password") string password) { ...}
6、最终效果
以上就是怎么使用springboot+aop记录用户操作日志的详细内容。
该用户其它信息

VIP推荐

免费发布信息,免费发布B2B信息网站平台 - 三六零分类信息网 沪ICP备09012988号-2
企业名录 Product