java保存实现变更记录

java保存实现变更记录

前言

  最近遇到一个需求,要求编写保存变更记录的功能,记录下哪些字段由什么值变为了什么值,经过参考网上的解决方案,将部分核心代码记录下来。

实现方案

  1. 自定义注解@LogCompar:配置了要比较的字段名称,日期格式,码值转换,默认值等;
  2. 编写工具类:通过java反射机制,获取要比较对象中所有添加了@LogCompar的属性,并进行比较记录;
  3. 单元测试:要比较的实体类添加@LogCompar注解,测试。

代码实现

  1. 创建自定义注解:
/**
 * @Describe 变更记录注解:用于注释在要比较变更的对象的属性上
 * @Author xlma
 * @Date 2023/02/06 21:45
 * @Version 1.0
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogCompar {
    /**
     * 属性名称
     */
    String value();

    /**
     * 日期格式, 如: yyyy-MM-dd
     */
    String dateFormat() default "";

    /**
     * 读取内容转表达式 (如: 0=男,1=女,2=未知)
     */
    String readConverterExp() default "";

    /**
     * 分隔符,readConverterExp表达式的分隔符
     */
    String separator() default ",";

    /**
     * 当值为空时的默认值
     */
    String defaultValue() default "null";
}
  1. 编写工具类
/**
 * @Describe 添加变更记录工具类
 * @Author xlma
 * @Date 2023/2/6 21:32
 * @Version 1.0
 */
@Slf4j
public class RecordUtils {

    /**
     * 注解列表(添加了@LogCompar的属性集合,数组的第一位是属性Field,第二位是注解LogCompar)
     */
    private static List<Object[]> fields;

    /**
     * 比较变更前后的数据,记录下添加了@LogCompar注解的属性,由原来的什么值变为了现在的什么值
     *
     * @param oldObj 原数据对象
     * @param newObj 新数据对象
     */
    public static String addChangeRecord(Object oldObj, Object newObj) {
        try {
            // 获取Class对象
            Class<?> oldClazz = oldObj.getClass();
            Class<?> newClazz = newObj.getClass();
            if (!oldClazz.equals(newClazz)) {
                throw new RuntimeException("请传入两个相同的实体类对象!");
            }
            // 获取加了注解的属性集合
            fields = getFields(oldClazz);
            if (fields.size() == 0) {
                throw new RuntimeException("没有找到要对比的属性!");
            }
            // 定义变量:变更描述信息
            StringBuilder info = new StringBuilder();
            // 根据注解列表,循环比较属性是否变化
            for (Object[] os : fields) {
                Field field = (Field) os[0];
                LogCompar logCompar = (LogCompar) os[1];
                // 获取新旧的属性值
                Object oldValue = field.get(oldObj);
                Object newValue = field.get(newObj);
                if (oldValue == null) {
                    oldValue = logCompar.defaultValue();
                }
                if (newValue == null) {
                    newValue = logCompar.defaultValue();
                }
                // 若新值和旧值相等,则跳过
                if (oldValue == newValue || newValue.equals(oldValue)) {
                    continue;
                }
                // 若是BigDecimal类型,需要compareTo方法判断是否相等,相等则跳过
                if (field.getType() == BigDecimal.class && ((BigDecimal) newValue).compareTo((BigDecimal) oldValue) == 0) {
                    continue;
                }
                // 若属性值有变化,则判断是否有码值,
                if (StringUtils.isNotBlank(logCompar.readConverterExp())) {
                    oldValue = convertByExp(oldValue.toString(), logCompar.readConverterExp(), logCompar.separator());
                    newValue = convertByExp(newValue.toString(), logCompar.readConverterExp(), logCompar.separator());
                } else if (StringUtils.isNotBlank(logCompar.dateFormat())) {
                    oldValue = DateHelper.format(oldValue, logCompar.dateFormat());
                    newValue = DateHelper.format(newValue, logCompar.dateFormat());
                }
                info.append(String.format("%s:由%s 变为了 %s;", logCompar.value(), oldValue, newValue));
            }
            // 此处可以返回info或直接保存日志表处理
            return info.toString();
        } catch (IllegalAccessException e) {
            log.error(e.getMessage());
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 获取注解属性信息
     */
    private static List<Object[]> getFields(Class<?> clazz) {
        // 定义加了@LogCompar注解的属性集合
        List<Object[]> fields = new ArrayList<Object[]>();
        // 定义临时的属性集合,包含了当前类及其父类的所有属性
        List<Field> tempFields = new ArrayList<>();
        tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));
        tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));
        // 遍历临时属性集合,判断遍历出的属性上是否有@LogCompar注解,若有,则将当前属性及注解添加到fields中
        for (Field field : tempFields) {
            // 若当前属性field上添加了@LogCompar注解,则isAnnotationPresent()方法返回true
            if (field.isAnnotationPresent(LogCompar.class)) {
                LogCompar logCompar = field.getAnnotation(LogCompar.class);
                if (logCompar != null) {
                    // 设置可以访问私有private的属性
                    field.setAccessible(true);
                    fields.add(new Object[]{field, logCompar});
                }
            }
        }
        return fields;
    }

    /**
     * 解析导出值 0=男,1=女,2=未知
     *
     * @param propertyValue 参数值
     * @param converterExp  翻译注解
     * @param separator     分隔符
     * @return 解析后值
     */
    private static String convertByExp(String propertyValue, String converterExp, String separator) {
        StringBuilder stringBuilder = new StringBuilder();
        String[] convertSource = converterExp.split(",");
        for (String item : convertSource) {
            String[] itemArray = item.split("=");
            if (StringUtils.containsAny(separator, propertyValue)) {
                for (String value : propertyValue.split(separator)) {
                    if (itemArray[0].equals(value)) {
                        stringBuilder.append(itemArray[1] + separator);
                        break;
                    }
                }
            } else if (itemArray[0].equals(propertyValue)) {
                return itemArray[1];
            }
        }
        return StringUtils.stripEnd(stringBuilder.toString(), separator);
    }
}
  1. 创建实体类,以用户表为例
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {

    private Long id;

    private String username;

    @LogCompar("真实姓名")
    private String realName;

    @LogCompar(value = "性别", readConverterExp = "0=男,1=女,2=未知")
    private Integer sex;

    @LogCompar("邮箱")
    private String email;

    @LogCompar(value = "薪水")
    private BigDecimal salary;

    @LogCompar(value = "创建时间", dateFormat = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;
}
  1. 单元测试
@Test
void recordEncrypt() {
    User oldUser = new User(1L, "admin", "张三", 1, "123@qq.com", BigDecimal.valueOf(12), LocalDateTime.now());
    User newUser = new User(2L, "admin", "李四", 2, null, BigDecimal.valueOf(12.00), LocalDateTime.of(2022, 2, 12, 5, 12, 5));
    System.out.println(RecordUtils.addChangeRecord(oldUser, newUser));
}
  1. 结果
真实姓名:由张三 变为了 李四;性别:由女 变为了 未知;邮箱:由123@qq.com 变为了 null;创建时间:由2023-03-12 13:53:03 变为了 2022-02-12 05:12:05;
  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
保存实时聊天记录到 MySQL 数据库,你需要实现以下步骤: 1. 创建一个 MySQL 数据库,并创建一个表来存储聊天记录。 2. 在 Java 应用程序连接到 MySQL 数据库。 3. 在应用程序编写代码以便将聊天记录插入到 MySQL 数据库。 4. 在应用程序编写代码以便从 MySQL 数据库读取聊天记录。 下面是一些示例代码,可以帮助你实现这些步骤: 1. 创建一个 MySQL 数据库,并创建一个表来存储聊天记录。 ```sql CREATE DATABASE chat_db; USE chat_db; CREATE TABLE chat_logs ( id INT AUTO_INCREMENT PRIMARY KEY, user_id INT NOT NULL, message TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); ``` 2. 在 Java 应用程序连接到 MySQL 数据库。 ```java import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class DatabaseConnection { private final String url = "jdbc:mysql://localhost:3306/chat_db"; private final String user = "root"; private final String password = "password"; public Connection getConnection() throws SQLException { return DriverManager.getConnection(url, user, password); } } ``` 3. 在应用程序编写代码以便将聊天记录插入到 MySQL 数据库。 ```java import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; public class ChatLogger { private final Connection connection; public ChatLogger(Connection connection) { this.connection = connection; } public void log(int userId, String message) throws SQLException { String query = "INSERT INTO chat_logs (user_id, message) VALUES (?, ?)"; try (PreparedStatement statement = connection.prepareStatement(query)) { statement.setInt(1, userId); statement.setString(2, message); statement.executeUpdate(); } } } ``` 4. 在应用程序编写代码以便从 MySQL 数据库读取聊天记录。 ```java import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; public class ChatReader { private final Connection connection; public ChatReader(Connection connection) { this.connection = connection; } public List<String> read(int userId) throws SQLException { List<String> messages = new ArrayList<>(); String query = "SELECT message FROM chat_logs WHERE user_id = ?"; try (PreparedStatement statement = connection.prepareStatement(query)) { statement.setInt(1, userId); ResultSet resultSet = statement.executeQuery(); while (resultSet.next()) { messages.add(resultSet.getString("message")); } } return messages; } } ``` 这些代码可以帮助你实现将聊天记录保存到 MySQL 数据库,以及从数据库读取聊天记录。请注意,这些代码可能需要根据你的具体需求进行修改。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值