Cara menggunakan SpringBoot+Aop untuk merekod log operasi pengguna
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) @Documented public @interface MyLog { // 自定义模块名,eg:登录 String title() default ""; // 方法传入的参数 String optParam() default ""; // 操作类型,eg:INSERT, UPDATE... BusinessType businessType() default BusinessType.OTHER; }
BusinessType.java — 操作类型枚举类
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 @Slf4j public 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、最终效果
Atas ialah kandungan terperinci Cara menggunakan SpringBoot+Aop untuk merekod log operasi pengguna. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

AI Hentai Generator
Menjana ai hentai secara percuma.

Artikel Panas

Alat panas

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

MinGW - GNU Minimalis untuk Windows
Projek ini dalam proses untuk dipindahkan ke osdn.net/projects/mingw, anda boleh terus mengikuti kami di sana. MinGW: Port Windows asli bagi GNU Compiler Collection (GCC), perpustakaan import yang boleh diedarkan secara bebas dan fail pengepala untuk membina aplikasi Windows asli termasuk sambungan kepada masa jalan MSVC untuk menyokong fungsi C99. Semua perisian MinGW boleh dijalankan pada platform Windows 64-bit.

Dreamweaver CS6
Alat pembangunan web visual

mPDF
mPDF ialah perpustakaan PHP yang boleh menjana fail PDF daripada HTML yang dikodkan UTF-8. Pengarang asal, Ian Back, menulis mPDF untuk mengeluarkan fail PDF "dengan cepat" dari tapak webnya dan mengendalikan bahasa yang berbeza. Ia lebih perlahan dan menghasilkan fail yang lebih besar apabila menggunakan fon Unicode daripada skrip asal seperti HTML2FPDF, tetapi menyokong gaya CSS dsb. dan mempunyai banyak peningkatan. Menyokong hampir semua bahasa, termasuk RTL (Arab dan Ibrani) dan CJK (Cina, Jepun dan Korea). Menyokong elemen peringkat blok bersarang (seperti P, DIV),

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa