mybatis更新时记录变更的字段日志&&java反射获取字段值转成string

 1.先写个注解,加在entity的字段上,标记要记录这个字段的更新记录,再加个变更记录表(你们可以用自己的日志表)

@Retention(RetentionPolicy.RUNTIME)
@Target({java.lang.annotation.ElementType.FIELD})
@Documented
public @interface ModifyAware {

    /**
     * 字段名称,这里直接写,不去找其他注解或者解析doc了,必填
     */
    public abstract String name();


}

@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("modifyrecord")
@ApiModel("变更记录表")
public class ModifyRecord extends CommonBaseEntity {
    private static final long serialVersionUID = 7314951651619250712L;
    /**
     * 变更表名
     */
    @TableField("tableName")
    @ApiModelProperty("变更表名/业务名称")
    private String tableName;

    /**
     * 变更记录Id
     */
    @TableField("recordKey")
    @ApiModelProperty("变更记录Id")
    private Integer recordKey;

    /**
     * 变更字段
     */
    @TableField("modifyColumn")
    @ApiModelProperty("变更字段")
    private String modifyColumn;

    /**
     * 变更前内容
     */
    @ApiModelProperty("变更前内容")
    @TableField("beforeContent")
    private String beforeContent;

    /**
     * 变更后内容
     */
    @TableField("afterContent")
    @ApiModelProperty("变更后内容")
    private String afterContent;

    /**
     * 变更时间
     */
    @TableField("modifyTime")
    @ApiModelProperty("变更时间")
    private Date modifyTime;

    /**
     * 变更原因
     */
    @TableField("modifyReason")
    @ApiModelProperty("变更原因")
    private String modifyReason;

    /**
     * 变更人
     */
    @TableField("modifier")
    @ApiModelProperty("变更人")
    private String modifier;

    /**
     * 变更人姓名
     */
    @TableField(exist = false)
    @ApiModelProperty("变更人姓名")
    private String modifierName;

    public ModifyRecord(String tableName, Integer recordKey, String modifyColumn, String beforeContent, String afterContent, Date modifyTime, String modifyReason, String modifier) {
        this.tableName = tableName;
        this.recordKey = recordKey;
        this.modifyColumn = modifyColumn;
        this.modifyTime = modifyTime;
        this.beforeContent = beforeContent;
        this.afterContent = afterContent;
        this.modifyReason = modifyReason;
        this.modifier = modifier;
    }
}

2.再在BaseService和impl实现中增加modify方法(如果没有就自己写,基本上用mybatis都会自己包一层service(继承IService)服务,多定义一些好用的增删改查的方法),等同update,实现变更记录的逻辑,最好前端增加一个变更原因字段,带到entity里面,做变更原因记录,我这里先写死;

PS:这里反射取值时,直接穷举了字段基本类型,常规开发就这些,暂不支持list,map等集合的变化,有需要自己多写个if分支拓展下。

public int modify(T entity) {
        Integer id = (Integer) EntityUtils.getFieldValueByFieldName("id", entity);
        //获取旧数据
        T old = this.getById(id);
        //执行更新,保证业务执行
        int num = getBaseMapper().updateById(entity);
        //获取加了注解的字段
        Field[] fields = entity.getClass().getDeclaredFields();
        String className = entity.getClass().getSimpleName();
        List modifyRecordList = Lists.newArrayList();
        for (Field field : fields) {
            field.setAccessible(true);
            if (!field.isAnnotationPresent(ModifyAware.class)) {
                continue;
            }
            ModifyAware attr = field.getAnnotation(ModifyAware.class);
            //获取实体旧值
            Object oldValue = EntityUtils.getFieldValueByFieldName(field.getName(), old);
            //获取新值
            Object newValue = EntityUtils.getFieldValueByFieldName(field.getName(), entity);
            //新旧比较
            String beforeContent = "";
            String afterContent = "";
            if (null == oldValue && null == newValue) {
                continue;
            } else if (null == oldValue) {
                afterContent = getFieldValue(field, newValue);
            } else if (null == newValue) {
                beforeContent = getFieldValue(field, oldValue);
            } else {
                beforeContent = getFieldValue(field, oldValue);
                afterContent = getFieldValue(field, newValue);
            }
            if (!beforeContent.equals(afterContent)) {//前后不一致
                //保存变更
                modifyRecordList.add(new ModifyRecord(className, id, attr.name(), beforeContent, afterContent, new Date(), "信息更新", LoginUtil.getLoginName()));
            }
        }
        //无则直接返回
        if (CollectionUtils.isEmpty(modifyRecordList)) {
            return num;
        }
        //有直接存储
        ModifyRecordMapper modifyRecordMapper = SpringContextUtil.getBean(ModifyRecordMapper.class);
        modifyRecordMapper.insertBatch(modifyRecordList);
        return num;
    }

    /**
     * 获取字段值,并转成string
     *
     * @param field 字段
     * @param value value
     * @return 字符串类型的值
     */
    private static String getFieldValue(Field field, Object value) {
        String typeName = field.getType().getSimpleName();
        if ("Integer".equalsIgnoreCase(typeName)) {//数字类型
            return String.valueOf(value);
        } else if ("BigInteger".equalsIgnoreCase(typeName)) {//数字类型
            return String.valueOf(value);
        } else if ("Short".equalsIgnoreCase(typeName)) {//数字类型
            return String.valueOf(value);
        } else if ("Float".equalsIgnoreCase(typeName)) {//数字类型
            return String.valueOf(value);
        } else if ("Double".equalsIgnoreCase(typeName)) {//数字类型
            return String.valueOf(value);
        } else if ("Long".equalsIgnoreCase(typeName)) {//数字类型
            return String.valueOf(value);
        } else if ("BigDecimal".equalsIgnoreCase(typeName)) {//数字类型
            return ((BigDecimal) value).toPlainString();
        } else if ("String".equalsIgnoreCase(typeName)) {//字符串
            return value.toString();
        } else if ("Date".equalsIgnoreCase(typeName)) {//日期
            SimpleDateFormat sdf = new SimpleDateFormat(DatePattern.YYYY_MM_DD_HH_MM_SS);
            return sdf.format(value);
        }
        return "";
    }

3.最后在业务数据中展示这些变更日志时,可能还要在查询时转换下,必须存储的项目Id,实际日志要展示项目中文,那就在日志列表的接口中自己识别转换下,最后效果如下:

 

你可能感兴趣的:(mybatis,java,反射,变更记录,Field)