记录业务操作日志实现

前言

        今天跟大家分享的是业务日志记录的实现,主要是有些业务场景要记录变更前、变更后具体修改内容等信息,仅仅用aop已经不能满足了,其实也就是日志已经耦合业务了。


一、实现思路

思路描述
        自定义一个注解,用在具体方法上,实现主动记录基础日志(AOP)。在方法里面提供业务日志工具类,工具类可以根据业务个性化修改注解实现记录的基础日志(不在方法上加注解,工具类在ThreadLocal拿不到日志信息可以直接创建)。
实现流程图

在这里插入图片描述

二、实现步骤

1.建表与实体

日志记录建表语句

CREATE TABLE `base_business_log` (
  `id_` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键,自增',
  `request_code_` varchar(30) DEFAULT NULL COMMENT '请求id',
  `request_ip_` varchar(30) DEFAULT NULL COMMENT '请求ip',
  `operate_privilege_id_` bigint(20) DEFAULT NULL COMMENT '操作菜单id',
  `operate_privilege_name_` varchar(200) DEFAULT NULL COMMENT '操作菜单名称',
  `operate_privilege_code_` varchar(200) DEFAULT NULL COMMENT '菜单编码,来源权限码',
  `param_` longtext COMMENT '入参',
  `core_param_` text COMMENT '核心参数描述',
  `action_type_` int(11) DEFAULT NULL COMMENT '操作动作,1新增,2编辑,3删除,4关联设备。。。',
  `action_type_name_` varchar(100) DEFAULT NULL COMMENT '操作动作名称',
  `before_info_` longtext COMMENT '操作前信息',
  `after_info_` longtext COMMENT '操作后信息',
  `action_result_` varchar(50) DEFAULT NULL COMMENT '操作结果,成功success,失败fail',
  `result_` bit(1) DEFAULT NULL COMMENT '操作结果 false-失败 true-成功',
  `result_content_` text COMMENT '结果内容,或异常信息',
  `memo_` text COMMENT '备注',
  `application_id_` bigint(20) DEFAULT NULL COMMENT '应用id',
  `application_name_` varchar(300) DEFAULT NULL COMMENT '应用名称',
  `creator_id_` bigint(20) DEFAULT NULL COMMENT '创建人id',
  `create_time_` datetime DEFAULT NULL COMMENT '创建时间',
  `modify_id_` bigint(20) DEFAULT NULL COMMENT '修改人id',
  `modify_time_` datetime DEFAULT NULL COMMENT '修改时间',
  `deleted_` int(11) DEFAULT '0' COMMENT '是否删除,0否,1是',
  PRIMARY KEY (`id_`),
  KEY `base_business_log_operate_privilege_id__IDX` (`operate_privilege_id_`) USING BTREE,
  KEY `base_business_log_operate_privilege_name__IDX` (`operate_privilege_name_`) USING BTREE,
  KEY `base_business_log_creator_id__IDX` (`creator_id_`) USING BTREE,
  KEY `base_business_log_create_time__IDX` (`create_time_`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=59632 DEFAULT CHARSET=utf8 COMMENT='业务日志记录表';

实体


import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import com.smartPark.common.entity.BaseEntity;
import lombok.*;
import lombok.experimental.Accessors;

import java.io.Serializable;
import java.util.Date;

/**
 * 业务日志记录表
 *
 * @author zhengwen
 * @since 2023-04-13
 */
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@Builder
@AllArgsConstructor
@NoArgsConstructor
@TableName("base_business_log")
public class BusinessLog extends BaseEntity<BusinessLog> {

    private static final long serialVersionUID = 1L;

    /**
     * 主键,自增
     */
    @TableId(value = "id_", type = IdType.AUTO)
    private Long id;

    /**
     * 请求id
     */
    @TableField("request_code_")
    private String requestCode;

    /**
     * 请求ip
     */
    @TableField("request_ip_")
    private String requestIp;

    /**
     * 操作菜单id
     */
    @TableField("operate_privilege_id_")
    private Long operatePrivilegeId;

    /**
     * 操作菜单名称
     */
    @TableField("operate_privilege_name_")
    private String operatePrivilegeName;

    /**
     * 操作菜单编码,来源于权限编码
     */
    @TableField("operate_privilege_code_")
    private String operatePrivilegeCode;


    /**
     * 参数
     */
    @TableField("param_")
    private String param;

    /**
     * 核心参数描述
     */
    @TableField("core_param_")
    private String coreParam;

    /**
     * 操作动作,1新增,2编辑,3删除,4关联设备。。。
     */
    @TableField("action_type_")
    private Integer actionType;

    /**
     * 操作动作名称
     */
    @TableField("action_type_name_")
    private String actionTypeName;

    /**
     * 操作前信息
     */
    @TableField("before_info_")
    private String beforeInfo;

    /**
     * 操作后信息
     */
    @TableField("after_info_")
    private String afterInfo;

    /**
     * 操作结果,成功success,失败fail
     */
    @TableField("action_result_")
    private String actionResult;

    /**
     * 操作结果,成功success,失败fail
     */
    @TableField("result_")
    private Boolean result;

    /**
     * 结果内容,或异常信息
     */
    @TableField("result_content_")
    private String resultContent;


    /**
     * 备注
     */
    @TableField("memo_")
    private String memo;

    /**
     * 应用id
     */
    @TableField("application_id_")
    private Long applicationId;

    /**
     * 应用名称
     */
    @TableField("application_name_")
    private String applicationName;

    /**
     * 创建人id
     */
    @TableField("creator_id_")
    private Long creatorId;

    /**
     * 创建时间
     */
    @TableField("create_time_")
    private Date createTime;

    /**
     * 修改人id
     */
    @TableField("modify_id_")
    private Long modifyId;

    /**
     * 修改时间
     */
    @TableField("modify_time_")
    private Date modifyTime;

    /**
     * 是否删除,0否,1是
     */
    @TableLogic(value = "0", delval = "1")
    @TableField("deleted_")
    private Integer deleted;



}

2.核心代码

自定义注解




import com.xxx.LogConstant;

import java.lang.annotation.*;

/**
 * 操作日志注解
 *
 * @author zhengwen
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface BusinessLogAnnotate {

    /**
     * 是否记录参数 默认 true
     * @return
     */
    boolean recordParam() default true;

    /**
     * 操作动作
     * @return
     */
    LogConstant.LogOperateActionType actionType();

    /**
     * 描述
     * @return
     */
    String desc();

    /**
     * 操作菜单编码
     * @return
     */
    String menuCode();
}

业务操作常量类


/**
 * 日志管理常量
 *
 * @author zhengwen
 */
public interface LogConstant {

    /**
     * 日志操作动作
     */
    enum LogOperateActionType {


        /**
         * 操作动作
         */
        ADD(1, "新增"),
        EDIT(2, "修改"),
        DEL(3, "删除"),
        QUERY(4, "查询"),

        DEVICE_CONTROL(5,"设备控制" ),
        DEVICE_TACTIC(6,"设备操作策略" ),
        DEVICE_PLAN(7,"设备操作计划" ),

        ALARM_CONFIG(8,"配置" ),
        APPROVE(9,"审核" ),
        JOIN_DEVICE(10,"关联设备" ),

        ENABLE(11,"启用" ),
        DISABLE(12,"禁用" ),
        EXPORT(13,"导出" ),
        IMPORT(14,"导入" ),
        ;


        Integer actionType;

        /**
         * 名称
         */
        private String actionTypeName;

        public Integer getActionType() {
            return actionType;
        }

        public String getActionTypeName() {
            return actionTypeName;
        }

        LogOperateActionType(Integer actionType, String actionTypeName) {
            this.actionType = actionType;
            this.actionTypeName = actionTypeName;
        }
    }


}

日志工具类



import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.xx.BusinessLog;
import com.xx.LogConstant;
import com.xx.BaseApplication;
import com.xx.BaseappUser;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import site.morn.translate.Translator;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Date;


@Component
@Slf4j
public class LogHelper {

    private static Translator translator;

    private LogHelper() {
    }

    private static final ThreadLocal<String> logContentThreadLocal = new ThreadLocal<>();
    private static final ThreadLocal<BaseappUser> customerThreadLocal = new ThreadLocal<>();
    private static final ThreadLocal<BaseApplication> applicationThreadLocal = new ThreadLocal<>();

    private static final ThreadLocal<BusinessLog> businessLogThreadLocal = new ThreadLocal<>();

    public static BusinessLog getBusinessLog() {
        return businessLogThreadLocal.get();
    }

    public static void setBusinessLog(BusinessLog businessLog) {
        businessLogThreadLocal.set(businessLog);
    }


    public static BaseApplication getApplication() {
        return applicationThreadLocal.get();
    }

    public static void setApplication(BaseApplication application) {
        applicationThreadLocal.set(application);
    }

    public static String getContent() {
        return logContentThreadLocal.get();
    }

    public static void setContent(String content, Object... args) {
        if (null == translator) {
            translator = SpringUtil.getBean(Translator.class);
        }
        String message = translator.translate(content, args, content);
        logContentThreadLocal.set(message);
    }


    public static BaseappUser getCustomer() {
        return customerThreadLocal.get();
    }

    public static void setCustomer(BaseappUser customer) {
        customerThreadLocal.set(customer);
    }

    public static void clearContent() {
        logContentThreadLocal.remove();
        customerThreadLocal.remove();
        applicationThreadLocal.remove();
        businessLogThreadLocal.remove();
    }

    public static String beanToLog(Object obj) {
        return beanToLog(obj, true);
    }

    public static String beanToLog(Object obj, boolean ignoreNull) {
        StringBuilder sb = new StringBuilder();
        try {
            if (null != obj) {
                Field[] declaredFields = obj.getClass().getDeclaredFields();
                for (Field field : declaredFields) {
                    LogField f = field.getAnnotation(LogField.class);
                    if (f == null) {
                        continue;
                    }
                    String prefix = "get";
                    if (field.getType() == boolean.class) {
                        prefix = "is";
                    }
                    String methodName = prefix + StringUtils.capitalize(field.getName());
                    Method method = ReflectUtil.getMethod(obj.getClass(), methodName);
                    if (method == null) {
                        continue;
                    }
                    Object value = ReflectUtil.invoke(obj, method);
                    if (ignoreNull && value == null) {
                        continue;
                    }
                    if (value instanceof Date) {
                        value = DateUtil.formatDateTime((Date) value);
                    }
                    if (sb.length() > 0) {
                        sb.append(", ");
                    }
                    sb.append(f.name()).append(":").append(value);
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return sb.toString();
    }

    /**
     * 设置菜单编码
     *
     * @param privilegeCode 菜单编码
     */
    public static void setMenuCode(String privilegeCode) {
        BusinessLog businessLog = getBusinessLog();
        if (businessLog != null) {
            businessLog.setOperatePrivilegeCode(privilegeCode);
        }
    }

    /**
     * 设置核心参数
     *
     * @param coreParam 核心参数
     */
    public static void setCoreParam(String coreParam) {
        BusinessLog businessLog = getBusinessLog();
        if (businessLog != null) {
            businessLog.setCoreParam(coreParam);
        }
    }

    /**
     * 设置操作前信息
     *
     * @param beforeInfoJson 操作前信息json串
     */
    public static void setBeforeInfo(String beforeInfoJson) {
        BusinessLog businessLog = getBusinessLog();
        if (businessLog != null) {
            businessLog.setBeforeInfo(beforeInfoJson);
        }
    }

    /**
     * 设置操作后信息
     *
     * @param afterInfoJson 操作后信息json串
     */
    public static void setAfterInfo(String afterInfoJson) {
        BusinessLog businessLog = getBusinessLog();
        if (businessLog != null) {
            businessLog.setAfterInfo(afterInfoJson);
        }
    }

    /**
     * 设置描述
     *
     * @param desc 描述
     */
    public static void setDesc(String desc) {
        BusinessLog businessLog = getBusinessLog();
        if (businessLog != null) {
            businessLog.setMemo(desc);
        }
    }

    public static void setLogInfo(String menuCode, String coreParam) {
        setLogInfo(menuCode, coreParam, null);
    }

    public static void setLogInfo(String menuCode, String coreParam, String beforeInfoJsonStr) {
        setLogInfo(menuCode, coreParam, beforeInfoJsonStr, null);
    }

    public static void setLogInfo(String menuCode, String coreParam, String beforeInfoJsonStr, String afterInfoJsonStr) {
        setLogInfo(menuCode, coreParam, beforeInfoJsonStr, afterInfoJsonStr, null);
    }

    public static void setLogInfo(String menuCode, String coreParam, String beforeInfoJsonStr, String afterInfoJsonStr, String descStr) {
        BusinessLog businessLog = getBusinessLog();
        if (businessLog != null) {
            if (StringUtils.isNotBlank(menuCode)) {
                businessLog.setOperatePrivilegeCode(menuCode);
            }
            if (StringUtils.isNotBlank(coreParam)) {
                businessLog.setCoreParam(coreParam);
            }
            if (StringUtils.isNotBlank(beforeInfoJsonStr)) {
                businessLog.setBeforeInfo(beforeInfoJsonStr);
            }
            if (StringUtils.isNotBlank(afterInfoJsonStr)) {
                businessLog.setAfterInfo(afterInfoJsonStr);
            }
            if (StringUtils.isNotBlank(descStr)){
                if(descStr.length() >= 4000){
                    descStr = descStr.substring(0, 3500) + "...";
                }
                businessLog.setMemo(descStr);
            }
        }
    }

    /**
     * 记录日志
     * @param menuCode 菜单code
     * @param actionType 动作枚举
     * @param descStr 描述
     */
    public static void setLogInfo(String menuCode, LogConstant.LogOperateActionType actionType, String descStr) {
        BusinessLog businessLog = getBusinessLog();
        if (businessLog != null) {
            if (StringUtils.isNotBlank(menuCode)) {
                businessLog.setOperatePrivilegeCode(menuCode);
            }
            if (null != actionType){
                businessLog.setActionType(actionType.getActionType());
                businessLog.setActionTypeName(actionType.getActionTypeName());
            }
            if (StringUtils.isNotBlank(descStr)){
                businessLog.setMemo(descStr);
            }
        }
    }

    /**
     * 记录日志描述
     * @param memo 描述
     */
    public static void setLogMemo(String memo) {
        BusinessLog businessLog = getBusinessLog();
        if (businessLog != null) {
            if (StringUtils.isNotBlank(memo)){
                businessLog.setMemo(memo);
            }
        }
    }
}

AOP切面



import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.env.Environment;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author zhengwen
 */
@Component
@Aspect
@Slf4j
public class BusinessLogAspect {

    /**
     * 环境变量
     */
    private static Environment environment;

    private static BusinessLogService businessLogService;

    private static CommonService commonService;

    private static RedisUtil redisUtil;

    @PostConstruct
    private void init() {
        environment = SpringUtil.getBean(Environment.class);
        businessLogService = SpringUtil.getBean(BusinessLogService.class);
        commonService = SpringUtil.getBean(CommonService.class);
        redisUtil = SpringUtil.getBean(RedisUtil.class);
    }

    private static int charLength = 40000;

    @Pointcut("@annotation(com.smartPark.common.annotation.BusinessLogAnnotate)")
    private void pointcut() {
    }

    @Before(argNames = "joinPoint,businessLogAnnotate", value = "pointcut() && @annotation(businessLogAnnotate)")
    private void doBefore(JoinPoint joinPoint, BusinessLogAnnotate businessLogAnnotate) {
        String applicationName = environment.getProperty("sanzhi.application.name");
        if (StringUtils.isBlank(applicationName)) {
            log.warn("未配置应用信息");
            return;
        }
        Object[] args = joinPoint.getArgs();
        if (ArrayUtils.isNotEmpty(args)) {
            String paramStr = JSONUtil.toJsonStr(args);
            BaseApplication baseApplication = (BaseApplication) redisUtil.hget(RedisConstant.APPLICATION, applicationName);
            if (baseApplication == null) {
                log.warn("未找到应用信息");
                return;
            }
            if (businessLogAnnotate != null) {
                LogConstant.LogOperateActionType logActionType = businessLogAnnotate.actionType();
                BusinessLog businessLog = BusinessLog.builder()
                        .actionType(logActionType.getActionType())
                        .actionTypeName(logActionType.getActionTypeName())
                        .operatePrivilegeCode(businessLogAnnotate.menuCode())
                        .memo(businessLogAnnotate.desc())
                        .build();
                if (baseApplication != null) {
                    businessLog.setApplicationId(baseApplication.getId());
                    businessLog.setApplicationName(baseApplication.getName());
                }
                if (StringUtils.isNotBlank(paramStr) && paramStr.length() < charLength) {
                    businessLog.setParam(paramStr);
                }
                LogHelper.setBusinessLog(businessLog);
            }
        }
    }


    @AfterReturning(pointcut = "pointcut() && @annotation(businessLogAnnotate)", returning = "returnObj")
    public void doAfterReturning(JoinPoint joinPoint, BusinessLogAnnotate businessLogAnnotate, Object returnObj) {
        String desc = businessLogAnnotate.desc();
        String applicationName = environment.getProperty("sanzhi.application.name");
        if (StringUtils.isBlank(applicationName)) {
            log.warn("未配置应用信息");
            return;
        }
        BaseApplication baseApplication = (BaseApplication) redisUtil.hget(RedisConstant.APPLICATION, applicationName);
        if (baseApplication == null) {
            log.warn("未找到应用信息");
            return;
        }
        LogConstant.LogOperateActionType logActionType = businessLogAnnotate.actionType();
        BusinessLog businessLog = LogHelper.getBusinessLog();
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if(requestAttributes != null){
            // 获取request
            HttpServletRequest request =
                    ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            if (null == request) {
                return;
            }
            businessLog.setRequestIp(request.getRemoteAddr());
        }

        commonService.setCreateAndModifyInfo(businessLog);

        doAfterReturning(joinPoint, businessLogAnnotate, returnObj, businessLog);
        LogHelper.clearContent();
    }

    @Async
    public void doAfterReturning(JoinPoint joinPoint, BusinessLogAnnotate businessLogAnnotate, Object returnObj, BusinessLog businessLog) {
        if (returnObj != null) {
            String jsonStr = JSON.toJSONString(returnObj);
            businessLog.setResultContent(JSON.toJSONString(returnObj));
            JSONObject jsonObject = JSONObject.parseObject(jsonStr);
            Boolean isSuccess = jsonObject.getBoolean("success");
            businessLog.setResult(isSuccess);
            businessLog.setActionResult(jsonObject.getString("code"));
        } else {
            // 返回为空时默认为成功
            businessLog.setResult(true);
        }
        addBusinessLog(joinPoint, businessLogAnnotate, businessLog);
    }

    @AfterThrowing(pointcut = "pointcut() && @annotation(businessLogAnnotate)", throwing = "ex")
    public void doAfterThrowing(JoinPoint joinPoint, BusinessLogAnnotate businessLogAnnotate, Exception ex) {
        String desc = businessLogAnnotate.desc();
        String applicationName = environment.getProperty("sanzhi.application.name");
        if (StringUtils.isBlank(applicationName)) {
            log.warn("未配置应用信息");
            return;
        }
        BaseApplication baseApplication = (BaseApplication) redisUtil.hget(RedisConstant.APPLICATION, applicationName);
        if (baseApplication == null) {
            log.warn("未找到应用信息");
            return;
        }
        BusinessLog businessLog = LogHelper.getBusinessLog();
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if(requestAttributes != null){
            // 获取request
            HttpServletRequest request =
                    ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            if (null == request) {
                return;
            }
        }

        doAfterThrowing(joinPoint, businessLogAnnotate, ex, businessLog);
        LogHelper.clearContent();
    }

    @Async
    public void doAfterThrowing(JoinPoint joinPoint, BusinessLogAnnotate businessLogAnnotate, Exception ex, BusinessLog businessLog) {
        if (ex != null) {
            businessLog.setResultContent("异常信息:" + ex.toString());
        }
        businessLog.setResult(false);
        addBusinessLog(joinPoint, businessLogAnnotate, businessLog);
    }

    public void addBusinessLog(JoinPoint joinPoint, BusinessLogAnnotate businessLogAnnotate, BusinessLog businessLog) {
        // 参数
        if (businessLogAnnotate.recordParam() && joinPoint.getArgs() != null) {
            Object[] args = joinPoint.getArgs();
            Stream<?> stream = ArrayUtils.isEmpty(args) ? Stream.empty() : Arrays.asList(args).stream();
            List<Object> logArgs = stream
                    .filter(arg -> (!(arg instanceof HttpServletRequest) && !(arg instanceof HttpServletResponse) && !(arg instanceof MultipartFile)))
                    .collect(Collectors.toList());
            //过滤后序列化无异常
            String string = JSON.toJSONString(logArgs);
            if (StringUtils.isNotEmpty(string) && string.length() > charLength) {
                try {
                    string = CharCompressUtil.compressWrap(string);
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
            businessLog.setCoreParam(string);
        }
        businessLogService.saveOne(businessLog);

    }

}

3.使用方法

controller里

/**
     * 保存广告素材
     *
     * @param serveDeviceVo 智能服务vo
     * @return 统一出参
     */
    @PostMapping("/saveAdList")
    @ApiOperation("保存广告素材")
    @BusinessLogAnnotate(actionType = LogConstant.LogOperateActionType.ADD, menuCode = "smartPublicToilet:smartServe:toiletAd:save", desc = "保存广告素材")
    public RestMessage saveAdList(@RequestBody SmartServeDeviceVo serveDeviceVo) {
        Assert.notNull(serveDeviceVo, "参数不能为空");
        Assert.notNull(serveDeviceVo.getToiletDevice().getId(), "设备id不能为空");
        Assert.notNull(serveDeviceVo.getAdList(), "设备素材不能为空");
        return toiletDeviceAdService.saveAdList(serveDeviceVo);
    }

serviceImpl里

@Override
    public RestMessage saveAdList(SmartServeDeviceVo serveDeviceVo) {
        StringJoiner sj = new StringJoiner(",");
        ToiletDevice toiletDevice = serveDeviceVo.getToiletDevice();
        Long deviceId = toiletDevice.getId();
        ToiletDevice dbToiletDevice = toiletDeviceMapper.selectById(deviceId);
        sj.add("保存广告素材,设备编码:" + dbToiletDevice.getDeviceCode());
        sj.add("设备名称:" + toiletDevice.getDeviceName());
        //先删除广告素材
        QueryWrapper<ToiletDeviceAd> qw = new QueryWrapper<>();
        qw.eq("toilet_device_id_", deviceId);
        qw.eq("deleted_", CommonConstant.NOT_DELETE);
        baseMapper.delete(qw);

        //再新增新素材
        List<ToiletDeviceAd> adList = serveDeviceVo.getAdList();
        if (CollectionUtil.isNotEmpty(adList)) {
            sj.add("素材url地址:");
            adList.forEach(ad -> {
                ad.setToiletDeviceId(deviceId);
                commonService.setCreateAndModifyInfo(ad);
                sj.add(ad.getAdFileUrl());
                baseMapper.insert(ad);
            });
        }
        LogHelper.setLogInfo(null, null, null, null, sj.toString());
        //TODO 是否要处理素材下发?
        return RestBuilders.successBuilder().build();
    }

        LogHelper.setLogInfo方法有几个传参的方法。其实我觉得这个工具类提供的不是蛮好,还可以优化。


总结

  • 自定义操作业务日志就这么简单
  • 业务操作记录到变更字段避免不了跟业务耦合
  • 其实还有一种方法是跟每张表建一张影子表,带版本号,通过版本找历史
    好,就写到这里,希望可以帮到大家,uping!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

肥仔哥哥1930

来一波支持,吃不了亏上不了当

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值