java字段修改记录保存实现

需求说明

工作中,经常会有业务会要求展示某个业务字段的变更信息或变更流水线,为方便,对不同业务表也能使用同样的数据结构,因此需要构建一个公共日志记录类型来处理。

思路

通过java自带反射、注解简单记录。
1.创建公共日志记录表
2.通过反射、注解获取新旧记录自定义字段名称和字段值等
3.比较新旧记录,拼接日志

代码实现

1.表及数据结构设计

字段名称备注
logNo日志编号日志主键
businessType业务类型自定义业务类型
businessNo业务编号具体关联的业务编号
changeDate修改时间YYYY-MM-DD
changeContent修改内容每个字段变更都是一个JONS格式。
remark备注
createTime创建时间YYYY-MM-DD hh:mm:sss
creatorId创建人Id
creatorName创建人名称

注:changeContent修改内容数据格式如下:

[
	{
		"field": "字段英文名",
		"fieldName": "字段名称",
		"oldValue": "变更前的值",
		"newValue": "变更后的值",
		"content": "变更内容拼接(自定义拼接,比如:成立日期-20220101 --> 调整为 --> 成立日期-20220106"
	}
]

2.核心代码

(1)自定义注解

/**
 * 自定义属性名称
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldName {
    /**
     * 字段名称
     * @return
     */
    String value();
    /**
     * 解析时是否忽略空值
     * @return
     */
    boolean isIgnoreNull() default false;
}

(2)字段使用注解示例

    /**
     * 成立日期
     */
    @FieldName("成立日期")
    private String startDate;
    /**
     * 费率
     */
    @FieldName("费率")
    private String rate;
	
	@FieldName(value = "ID",isIgnoreNull = true)
	private String id;

(3)日志保存

/**
 * 保存修改日志
 * @param newObj 更新后数据
 * @param oldObj 更新前数据
 * @param businessType 业务类型
 * @param businessNo 业务主键
 * @param clazz
 * @return
 */
public int saveLog(Object newObj, Object oldObj, String businessType, String businessNo, Class clazz) {

        if (newObj == null || oldObj == null) {
            return 0;
        }
        //这里对应上面日志表实体类
        BusinessChangeLog log = new BusinessChangeLog();

        //通过hutool BeanUtil工具将实体类转换为Map
        Map newMap = BeanUtil.beanToMap(newObj);
        Map oldMap = BeanUtil.beanToMap(oldObj);
        
        //通过类对象获取类字段
        Field[] fields = clazz.getDeclaredFields();
        Map<String, Map> changeMap = new HashMap<>();
        for (Field field : fields) {
            //判断是否有FieldName注解
            if (field.isAnnotationPresent(FieldName.class)) {
                FieldName fieldName = field.getAnnotation(FieldName.class);
                //空的和忽略的字段不进行处理
				if (fieldName.isIgnoreNull() &&  ObjectUtil.isEmpty(newMap.get(field.getName()))) {
                    continue;
                }
                String newValue =  newMap.get(field.getName()) == null ? "" : newMap.get(field.getName()).toString();
                String oldValue =  oldMap.get(field.getName()) == null ? "" : oldMap.get(field.getName()).toString();
                String changeField;
                Map<String, String> conMap = new HashMap<>();
                //新旧记录内容不同,说明是修改过,因此记录起来
                if (!StringUtils.equals(newValue, oldValue)) {
                    //CHANGE_TEXT 自定义拼接内容
                    //CHANGE_TEXT = "fieldName-oldValue --> 调整为 --> fieldName-newValue"
                    changeField = CHANGE_TEXT.replaceAll("fieldName", fieldName.value())
                            .replaceAll("oldValue", oldValue)
                            .replaceAll("newValue", newValue);
                    conMap.put("field", field.getName());
                    conMap.put("fieldName",fieldName.value());
                    conMap.put("newValue", newValue);
                    conMap.put("oldValue", oldValue);
                    conMap.put("content", changeField);
                    changeMap.put(field.getName(), conMap);
                }
            }
        }
        log.setBusinessType(businessType);
        log.setBusinessNo(businessNo);
        if (!changeMap.isEmpty()) {
            log.setChangeContent(JSON.toJSONString(changeMap.values()).replaceAll("\\\\",""));
        }
        log.setCreatorId(SessionUtil.getUser().getEmpId());
        log.setCreatorName(SessionUtil.getUserName());
        //入库(需要自己实现入库代码编写)
        return logMapper.insertLog(log);
    }

  • 11
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Java EE常用框架 WebService 介绍 基于Web的服务。它使用Web(HTTP)方式,接收和响应外部系统的某种请求。从而实现远程调用 术语 XML. Extensible Markup Language -扩展性标记语言 WSDL – WebService Description Language – Web服务描述语言。 SOAP-Simple Object Access Protocol(简单对象访问协议) SOA(Service-Oriented Architecture) :面向服务的架构 它是一种思想,IBM大力倡导是即插即用的,IBM大力提倡,希望以组装电脑的方式来开发应用 它是目录服务,通过该服务可以注册和发布webservcie,以便第三方的调用者统一调用 使用: 二、我们可以使用Java自带的WsImport来实现本地代理。这种方法会将WebService翻译成Java类,我们使用类一样去访问WebService就行了。非常好用。 三、除了调用别人发布的webService,也可以自己发布WebService服务 四、CXF框架可以与spring无缝连接,就不用我们自己Endpoint了。它还能记录日志之类的 五、我们还可以使用Idea下的webservice,能够使用图形画面的方式获取本地代理和生成WSDL文件。 Activiti 介绍 Activiti5是一个业务流程管理(BPM)框架 如果我们的业务是比较复杂的话,我们才会用到工作流! 使用Activiti的步骤 定义工作流 画一个BPMN图就可以了 部署工作流 执行工作流-->按照我们定义的工作流来执行 工作流在执行的过程中肯定会涉及到很多数据,Activiti是默认提供数据库表给我们使用的 Activiti工作流框架快速入门: 定义工作流,使用插件来把我们的流程图画出来。这个流程图就是我们定义的工作流。 工作流引擎是工作流的核心,能够让我们定义出来的工作流部署起来。 由于我们使用工作流的时候是有很多数据产生的,因此Activiti是将数据保存到数据库表中的。这些数据库表由Actitviti创建,由Activiti维护。 部署完的工作流是需要手动去执行该工作流的。 根据由谁处理当前任务,我们就可以查询出具体的任务信息。 根据任务的id,我们就可以执行任务了。 细节 流程定义:涉及到了四张数据库表 我们可以通过API把我们的流程定义图读取出来 可以根据查询最新版本的流程定义 删除流程定义 部署流程定义的时候也可以是ZIP文件 流程运行:涉及到两个对象,四张数据库表: 流程实例 获取流程实例和任务的历史信息 判断流程实例是否为空来判断流程是否结束了 查看正在运行服务的详细信息 通过流程实例来开启流程 流程变量:它涉及到了两张表。 流 程变量实际上就是我们的条件。 作用 我们可以在流程开始的时候设置流程变量,在任务完成的时候设置流程变量。 运行时服务和流程任务都可以设置流程变量。 连线 通过连线我们可以在其中设置条件,根据不同的条件流程走不同的分支 排他网关 SpringData JPA 简介 API Repository接口 PagingAndSortingRepository JpaRepository JpaSpecificationExecutor 过滤条件查询接口 注解 nameQuery注解 SQL命名,调用的时候根据名称调用 查询注解 1,targetEntity 属性表示默认关联的实体类型,默认为当前标注的实体类。 2,cascade属性表示与此实体一对一关联的实体的级联样式类型。 3,fetch属性是该实体的加载方式,默认为即时加载EAGER 4,optional属性表示关联的该实体是否能够存在null值,默认为ture,如果设置为false,则该实体不能为null, 5, mapperBy属性:指关系被维护端 1,@JoinColumn注释是保存表与表之间关系的字段 2,如果不设置name,默认name = 关联表的名称+”-“+关联表
为了实现Java中的历史修改记录,可以使用Memento设计模式。该模式允许记录对象的内部状态,并在需要时恢复该状态。在实现历史修改记录时,我们可以将对象的每个状态保存在一个备忘录对象中,并将备忘录对象存储在一个列表中。每当对象的状态发生更改时,我们都会创建一个新的备忘录对象并将其添加到列表中。 下面是Java实现历史修改记录的示例代码: ```java import java.util.ArrayList; import java.util.List; public class Document { private String content; private List<Memento> history = new ArrayList<>(); private int currentState = 0; public Document(String content) { this.content = content; history.add(new Memento(content)); } public void setContent(String content) { this.content = content; history.add(new Memento(content)); currentState = history.size() - 1; } public void undo() { if (currentState > 0) { currentState--; content = history.get(currentState).getContent(); } } public void redo() { if (currentState < history.size() - 1) { currentState++; content = history.get(currentState).getContent(); } } @Override public String toString() { return content; } private class Memento { private String content; public Memento(String content) { this.content = content; } public String getContent() { return content; } } } ``` 在这个例子中,我们创建了一个名为“Document”的类,它表示一个文档对象。该类有一个名为“content”的字符串属性,它保存了文档的内容。类中还有一个名为“history”的列表,它保存了文档的历史修改记录。每当文档的内容更改时,我们都会创建一个新的备忘录对象,并将其添加到历史记录列表中。类还有名为“undo”和“redo”的方法,它们允许用户撤消和恢复文档中的更改。 在这个例子中,我们使用了内部类来实现备忘录对象。备忘录对象只有一个名为“content”的属性,它保存了文档的内容。我们在Memento类中提供了一个名为“getContent”的方法,它允许我们从备忘录对象中恢复文档的旧状态。 使用上述代码,我们可以轻松地实现Java中的历史修改记录

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值