SpringBoot之自定义注解及Java反射机制实现对实体类某些字段记录日志的功能

SpringBoot之自定义注解及Java反射机制实现对实体类某些字段记录日志的功能

文章目录

  • SpringBoot之自定义注解及Java反射机制实现对实体类某些字段记录日志的功能
  • 1. 使用场景
  • 2. 实现思路
  • 3. 具体实现
    • 1. 定义注解类
    • 2. 日志实体类
    • 3. 反射操作工具类
    • 4. 定义记录日志的工具类
    • 5. 业务实体中标注自定义注解
    • 6. 业务Controller中使用

1. 使用场景

在有些项目中,对某些操作的功能需要记录日志的详细信息,如:

  1. 操作属于哪个模块?
  2. 属于模块下的哪个菜单?
  3. 属于菜单下的哪个功能?
  4. 属功能下的哪个操作?
  5. 给操作中的哪些字段记录日志?

2. 实现思路

  1. 自定义一个注解,可设置模块、菜单、功能、操作等属性;
  2. 写一个通用的记录日志的方法,并通过反射机制读取自定义注解中设置的值;
  3. 将自定义注解标注在业务实体类上并设置对应属性;
  4. 在需要记录日志的地方调用通用的日志记录方法即可

3. 具体实现

1. 定义注解类

定义一个名称为LogModel的注解

package com.yuan.annotation;import java.lang.annotation.*;/*** <p>** @Description: 日志记录模型注解 <br>* <p>* @Author: Yuan · JinSheng <br>* @Datetime: 2022-04-07 14:27* </p>*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface LogModel {/*** 模块名称*/String moduleName() default "系统管理";/*** 菜单名称*/String menuName() default "";/*** 功能描述* 不设置default默认值,则使用时必须为此属性赋值*/String functionDesc();/*** 操作* 不设置default默认值,则使用时必须为此属性赋值*/String operation();/**** 操作内容*/String operationContent() default "";
}

2. 日志实体类

package com.yuan.entity;import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;/*** <p>* Description: 系统日志* </p>** @author* @datetime*/
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("SYS_LOG")
public class Syslog implements Serializable {private static final long serialVersionUID = 1L;private String id;//....private String moduleName;private String menuName;private String functionDesc;private String operation;private String operationContent;// ...}

3. 反射操作工具类

package com.yuan.util;import com.yuan.annotation.LogModel;import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** <p>** @Description: 反射工具类 <br>* <p>* @Author: Yuan · JinSheng <br>* @Datetime: 2022-04-07 15:27* </p>*/
public class ReflectionUtil<T> {/*** @param entity           实体对象* @param contentSeparator 操作内容分割符* @return Map对象* @throws IllegalAccessException* @Description: 根据自定义@LogName注解设置记录日志的相关属性*/public Map<String, String> setLogModel(T entity, String contentSeparator) throws IllegalAccessException {Map<String, String> objectMap = new HashMap<>();List<String> operationContentList = new ArrayList<>();//操作内容集合//获取所有的属性Field[] fields = entity.getClass().getDeclaredFields();for (Field field : fields) {//是否存在LogName注解boolean annotationPresent = field.isAnnotationPresent(LogModel.class);//存在LogName注解if (annotationPresent) {LogModel annotation = field.getAnnotation(LogModel.class);field.setAccessible(true);//设置可访问私有属性objectMap.put("moduleName", annotation.moduleName());//模块名objectMap.put("menuName", annotation.menuName());//菜单名objectMap.put("function", annotation.function());//操作objectMap.put("functionDesc", annotation.functionDesc());//操作描述operationContentList.add(annotation.operationContent() + ":" + field.get(entity));//拼接操作操作内容以:分割}}objectMap.put("operationContent", String.join(contentSeparator, operationContentList));//操作内容return objectMap;}
}

4. 定义记录日志的工具类

package com.yuan.util;import com.yuan.util.UUIDGenerator;
import com.yuan.service.SyslogService;
import org.springframework.stereotype.Component;import java.util.ArrayList;
import java.util.List;
import java.util.Map;/*** <p>** @Description: 日志记录工具类 <br>* <p>* @Author: Yuan · JinSheng <br>* @Datetime: 2022-04-07 15:27* </p>*/
@Component
public class LogModelUtil<T> {//操作成功public static final String OPERATION_SUCCESS = "操作成功";//操作失败public static final String OPERATION_ERROR = "操作失败";//新增public static final String ADD = "新增";//删除public static final String DELETE = "删除";//查询public static final String QUERY = "查询";//修改public static final String UPDATE = "修改";//导入public static final String IMPORT = "导入";//导出public static final String EXPORT = "导出";//上传public static final String UPLOAD = "上传";//下载public static final String DOWNLOAD = "下载";//出现异常public static final String EXCEPTION = "出现异常";//一般操作public static final String GENERAL_OPERATION = "一般操作";@Autowiredprivate SyslogService syslogService;/*** <p>* Description: 记录日志新方法<br/>* Author: jinshengyuan <br/>* DateTime: 2020-04-08 16:11* </p>** @param entityList      实体对象集合* @param operationType   操作类型* @param operationResult 操作结果*/public void insertLog(List<T> entityList, String operationType, String operationResult) {Syslog syslog = new Syslog();//方法操作类ReflectionUtil reflectionUtil = new ReflectionUtil();//操作内容List<String> contentList = new ArrayList<>();//取每一个对象中加了@LogName注解的属性值for (T entity : entityList) {try {Map<String, String> map = reflectionUtil.setLogName(entity, ",");syslog.setModuleName(map.get("moduleName"));syslog.setMenuName(map.get("menuName"));syslog.setFunctionDesc(map.get("functionDesc"));syslog.setOperation(map.get("operation"));contentList.add(map.get("operationContent"));} catch (IllegalAccessException e) {//e.printStackTrace();continue;}}//有操作内容if (contentList.size() > 0) {String content = String.join(";", contentList);//1.如果操作内容长度大于2000则拆分成多条存储if (content.length() > 2000) {List<String> strList = new ArrayList<>();strList = substringStrListByLength(content, strList, 2000);strList.forEach(str -> {syslog.setId(UUIDGenerator.getUUID());//主键syslog.setOperationContent(str);//操作内容syslogService.save(syslog);});} else {//2.操作内容长度小于2000直接存成一条syslog.setId(UUIDGenerator.getUUID());//主键syslog.setOperationContent(String.join(";", contentList));//操作内容syslogService.save(syslog);}} else {//操作内容为空字符串,就存空字符syslog.setId(UUIDGenerator.getUUID());//主键syslog.setOperationContent("");//操作内容syslogService.save(syslog);}}private List<String> substringStrListByLength(String str, List<String> cacheList, int strLength) {if (str.length() > strLength) {cacheList.add(str.substring(0, strLength));substringStrListByLength(str.substring(strLength), cacheList, strLength);} else {cacheList.add(str);}return cacheList;}
}

5. 业务实体中标注自定义注解

如在角色操作中,对roleNameroleCode记录日志

package com.yuan.entity;import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;import java.io.Serializable;
import java.util.Date;/*** <p>** @Description: 角色实体 <br>* <p>* @Author: Yuan · JinSheng <br>* @Datetime: 2022-04-07 15:27* </p>*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("SYS_ROLE")
public class SysRole implements Serializable {private static final long serialVersionUID = 1L;/*** 主键id*/@TableId("ID")private String id;/*** 角色名称*/@TableField("ROLE_NAME")@LogModel(moduleName = "系统管理测试",menuName = "角色",function = "记录角色名称",functionDesc = "新增操作")private String roleName;/*** 角色编码*/@TableField("ROLE_CODE")@LogModel(moduleName = "系统管理测试",menuName = "角色",function = "记录角色编码",functionDesc = "新增操作")private String roleCode;/*** 创建人*/@TableField("CREATE_BY")private String createBy;/*** 创建时间*/@TableField("CREATE_TIME")private Date createTime;//...}

6. 业务Controller中使用

package com.yuan.sys.controller;import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yuan.sys.service.SysroleService;
import com.yuan.entity.Sysrole;
import com.yuan.util.MsgUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import java.util.List;/*** <p>** @Description: 角色控制器 <br>* <p>* @Author: Yuan · JinSheng <br>* @Datetime: 2022-04-07 15:27* </p>*/
@RestController
@RequestMapping("/sys/sysRole")
public class SysRoleController {@Autowiredprivate SysroleService service;@RequestMapping("/saveBatch")public MsgUtil saveBatch(@RequestParam("entityJsonList") String entityJsonList){List<Sysrole> list = JSON.parseObject(entityJsonList, List.class);if (service.saveBatch(list)) {//记录日志LogUtil.insertLog(list, LogUtil.ADD, LogUtil.OPERATION_SUCCESS);return MsgUtil.success();} else {return MsgUtil.fail();}}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/709989.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

江科大stm32学习笔记——【5-2】对射式红外传感器计次旋转编码计次

一.对射式红外传感器计次 1.原理 2.硬件连接 3.程序 CountSensor.c: #include "stm32f10x.h" // Device header #include "Delay.h"uint16_t CountSensor_Count;void CountSensor_Init(void) {//配置RCC时钟&#xff1a;RCC_APB2Perip…

前端架构: 脚手架之包管理工具的案例对比及workspaces特性的使用与发布过程

npm的workspaces 特性 1 &#xff09;使用或不使用包管理工具的对比 vue-cli 这个脚手架使用 Lerna 管理&#xff0c;它的项目显得非常清晰在 vue-cli 中包含很多 package 点开进去&#xff0c;每一个包都有package.json它里面有很多项目&#xff0c;再没有 Lerna 之前去维护和…

【大数据】Flink SQL 语法篇(七):Lookup Join、Array Expansion、Table Function

《Flink SQL 语法篇》系列&#xff0c;共包含以下 10 篇文章&#xff1a; Flink SQL 语法篇&#xff08;一&#xff09;&#xff1a;CREATEFlink SQL 语法篇&#xff08;二&#xff09;&#xff1a;WITH、SELECT & WHERE、SELECT DISTINCTFlink SQL 语法篇&#xff08;三&…

SpringCloudNacos注册中心服务分级存储模型

文章目录 服务分级存储模型概述配置集群同集群优先的负载均衡 权重配置总结 之前对 Nacos注册中心入门 已经做了演示. 这篇文章对 Nacos 的服务分级存储模型做理论与实践. 服务分级存储模型概述 一个服务可以有多个实例&#xff0c;例如我们的 user-server&#xff0c;可以有:…

C#使用iText7给PDF文档添加书签

上一篇文章将SqlSugar官网文档中每个链接对应的网页生成独立PDF文档再合并为单个PDF文档&#xff0c;但是没有书签&#xff0c;八百多页的内容查找和跳转都不方便&#xff0c;本文学习和使用iText7给PDF文档添加多级书签。   添加多级书签分为两大步骤&#xff1a;1&#xff…

老卫带你学---leetcode刷题(202. 快乐数)

202. 快乐数 问题 「快乐数」 定义为&#xff1a; 对于一个正整数&#xff0c;每一次将该数替换为它每个位置上的数字的平方和。 然后重复这个过程直到这个数变为 1&#xff0c;也可能是 无限循环 但始终变不到 1。 如果这个过程 结果为 1&#xff0c;那么这个数就是快乐数。…

VR全景HDR拍摄教程

什么是HDR&#xff1f; HDR可以用在哪里&#xff1f; 书面解释&#xff1a;HDR&#xff08;高动态范围 High Dynamic Range&#xff09;摄影&#xff0c;是摄影领域广泛使用的一种技术。 是不是有点懵&#xff1f; 我们来看一个实际的拍摄现场环境&#xff0c;你就懂了 我们…

使用 Gradle 版本目录进行依赖管理 - Android

/ 前言 / 在软件开发中&#xff0c;依赖管理是一个至关重要的方面。合理的依赖版本控制有助于确保项目的稳定性、安全性和可维护性。 Gradle版本目录&#xff08;Version Catalogs&#xff09;是 Gradle 构建工具的一个强大功能&#xff0c;它为项目提供了一种集中管理依赖…

定时任务框架

定时任务的框架有哪些 ● Timer&#xff0c;JDK自带的&#xff0c;比较简单&#xff0c;使用的时候&#xff0c;定义一个TimerTask&#xff0c;实现run方法&#xff0c;然后定义一个Timer类&#xff0c;调用timer.schedule(timerTask,1000,3000); ○ 缺点&#xff1a;单线程、…

附加Numpy数组

参考&#xff1a;Append Numpy Array 引言 在数据科学和机器学习领域&#xff0c;处理大规模数据集是一项重要且常见的任务。为了高效地处理数据&#xff0c;numpy是一个非常强大的Python库。本文将详细介绍numpy中的一个重要操作&#xff0c;即如何附加&#xff08;append&a…

LeetCode:2867. 统计树中的合法路径数目(筛质数+ DFS Java)

目录 2867. 统计树中的合法路径数目 题目描述&#xff1a; 实现代码与思路&#xff1a; 筛质数 DFS 原理思路&#xff1a; 2867. 统计树中的合法路径数目 题目描述&#xff1a; 给你一棵 n 个节点的无向树&#xff0c;节点编号为 1 到 n 。给你一个整数 n 和一个长度为 …

西软云XMS operate XXE漏洞

免责声明&#xff1a;文章来源互联网收集整理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该…

linux使用scp命令来在两台Linux设备之间传输文件

1、linux怎么将一个文件发送到另一个linux设备特定目录下 可以使用scp命令&#xff08;secure copy&#xff09;来将文件从一个Linux设备复制到另一个Linux设备的特定目录下。假设你要将本地文件localfile.txt发送到远程设备的/remote/directory目录下&#xff0c;你可以使用以…

Oracle修改用户密码之后连接特别慢的问题

一、问题现象 oracle数据库密码修改后连接速度特别慢&#xff0c;甚至出现超时的问题&#xff0c;查询表也特别慢 更改密码后&#xff0c;每次连接异常慢&#xff0c;就算用正确的密码连接&#xff0c;验证延时也非常大&#xff0c;导致应用程序连接反复出现超时现象&#xf…

Jquery操作DOM对象

文章目录 目录 文章目录 本章目标 一.DOM操作分类 二.JQuery中的DOM操作 内容操作 属性值操作 节点操作 节点属性操作 节点遍历 总结 本章目标 使用Jquery操作网页元素使用JQuery操作文本与属性值内容使用JQuery操作DOM节点使用Jquery遍历DOM节点使用JQuery操作CSS-DOM 一…

Groovy(第八节) Groovy 之类

目录 Song 类 Groovy 类就是 Java 类 类的关系 类初始化 核心的灵活性

WebServer -- 日志系统(下)

目录 &#x1f33c;整体思路 &#x1f382;基础API fputs 可变参数宏 __VA_ARGS__ fflush &#x1f6a9;流程图与日志类定义 流程图 日志类定义 &#x1f33c;功能实现 生成日志文件 && 判断写入方式 日志分级与分文件 &#x1f33c;整体思路 日志系统分两部…

常见概率分布介绍

介绍 概率分布是统计学中用于描述随机变量的概率特征的函数。以下是几种常用的概率分布&#xff1a; 均匀分布&#xff08;Uniform Distribution&#xff09;: 离散均匀分布: 每个结果发生的概率相等。连续均匀分布: 任意两个相同长度的区间内取值的概率相同。 二项分布&am…

无法调试MFC源码

VS无法调试MFC源码 起初 有时候就是这么无奈&#xff0c;MFC源码各种问题没有办法调试&#xff0c;可是又想看下代码如何调用&#xff0c;里面做了些什么&#xff0c;从哪儿调出&#xff0c;学习一下大神的思路什么的。整理一下有可能的原因。 检查生成代码设置 需要设置正…

[Java 基础] Java修饰符

Java修饰符详解 Java修饰符用于定义类、方法或者变量&#xff0c;修改其行为的关键字。Java语言主要提供了两类修饰符&#xff1a; 访问权限修饰符: default, public , protected, private非访问权限修饰符: final, abstract, static, synchronized&#xff0c; volatile等 …