0
点赞
收藏
分享

微信扫一扫

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

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

文章目录

1. 使用场景

2. 实现思路

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 = "一般操作";


    @Autowired
    private 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. 业务实体中标注自定义注解

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 {
    @Autowired
    private 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();
        }
    }

}

举报

相关推荐

0 条评论