You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hibernate Attribute Converter<Integer,String>使用及BeanUtils自动加解密实现问询

用AttributeConverter + 自定义Bean拷贝逻辑实现自动加密/解密

先澄清一个关键点:AttributeConverter<Integer, String>本质是JPA用来处理实体属性和数据库列之间类型转换的工具,但你需要的是实体与DTO拷贝时自动完成id的加密/解密。不过我们可以复用加密解密的核心逻辑,结合BeanUtils的扩展来实现你要的效果,彻底省去手动处理的麻烦。

步骤1:实现通用加密解密工具类

先写一个通用工具类,把加密解密逻辑抽出来,方便后续所有转换器复用:

public class EncryptUtils {
    // 替换成你实际用的加密逻辑,比如AES、RSA或者自定义规则,这里用Base64做示例
    public static String encrypt(int id) {
        return Base64.getEncoder().encodeToString(String.valueOf(id).getBytes());
    }

    // 对应的解密逻辑,注意处理异常场景
    public static int decrypt(String encId) throws IllegalArgumentException {
        try {
            String idStr = new String(Base64.getDecoder().decode(encId));
            return Integer.parseInt(idStr);
        } catch (Exception e) {
            throw new IllegalArgumentException("无效的加密ID,请检查格式", e);
        }
    }
}

步骤2:实现JPA AttributeConverter(按需选择)

如果你的数据库主键存储的是加密后的字符串,而实体层用int id来操作,那需要这个转换器让Hibernate自动在实体和数据库之间做转换:

@Converter(autoApply = true) // autoApply=true会自动应用到所有Integer类型的主键字段
public class IdEncryptConverter implements AttributeConverter<Integer, String> {

    @Override
    public String convertToDatabaseColumn(Integer attribute) {
        if (attribute == null) {
            return null;
        }
        return EncryptUtils.encrypt(attribute);
    }

    @Override
    public Integer convertToEntityAttribute(String dbData) {
        if (dbData == null) {
            return null;
        }
        return EncryptUtils.decrypt(dbData);
    }
}

然后在实体的id字段上标记(如果开了autoApply=true可以省略这一步):

@Entity
public class User {
    @Id
    @Convert(converter = IdEncryptConverter.class)
    private int id;
    // 其他业务属性...
}

这一步完成后,Hibernate读写数据库时会自动处理加密解密,完全不用你手动干预。

步骤3:扩展BeanUtils实现实体-DTO自动映射

现在解决实体和DTO之间的拷贝问题:DTO里有int id和String encId,我们需要在拷贝时自动完成:

  • 实体→DTO:把实体的id加密后赋值给DTO的encId
  • DTO→实体:把DTO的encId解密后赋值给实体的id

我们可以自定义BeanUtilsBean来覆盖默认的属性拷贝逻辑:

public class EncryptAwareBeanUtilsBean extends BeanUtilsBean {

    @Override
    public void copyProperty(Object dest, String name, Object value) throws IllegalAccessException, InvocationTargetException {
        // 处理实体→DTO:目标是DTO且要赋值encId时,加密源对象的id
        if (dest instanceof BaseDto && "encId".equals(name) && value instanceof Integer) {
            String encryptedId = EncryptUtils.encrypt((Integer) value);
            super.copyProperty(dest, name, encryptedId);
            return;
        }
        // 处理DTO→实体:源是DTO且要赋值id时,解密DTO的encId
        if (value instanceof BaseDto && "id".equals(name)) {
            BaseDto dto = (BaseDto) value;
            if (dto.getEncId() != null) {
                int decryptedId = EncryptUtils.decrypt(dto.getEncId());
                super.copyProperty(dest, name, decryptedId);
                return;
            }
        }
        // 其他属性按默认逻辑拷贝
        super.copyProperty(dest, name, value);
    }
}

这里假设你所有的DTO都继承自BaseDto,统一包含encId的getter方法:

public abstract class BaseDto {
    private int id;
    private String encId;
    // 标准的getter、setter...
}

最后封装一个工具类来方便调用:

public class EncryptBeanUtils {
    private static final BeanUtilsBean beanUtilsBean = new EncryptAwareBeanUtilsBean();

    public static void copyProperties(Object dest, Object orig) {
        try {
            beanUtilsBean.copyProperties(dest, orig);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException("属性拷贝失败", e);
        }
    }
}

步骤4:实际使用

现在你只需要调用自定义的拷贝工具,就能自动完成所有加密解密操作:

// 实体→DTO:自动把实体id加密成DTO的encId
User user = userRepository.findById(1).orElseThrow();
UserDto userDto = new UserDto();
EncryptBeanUtils.copyProperties(userDto, user);

// DTO→实体:自动把DTO的encId解密成实体的id
UserDto userDto = new UserDto();
userDto.setEncId("加密后的ID字符串");
User user = new User();
EncryptBeanUtils.copyProperties(user, userDto);
// 直接把user存入数据库即可,无需额外处理

补充说明

  • 如果你的数据库存储的是原始int类型主键,步骤2的AttributeConverter可以直接省略,只需要步骤3的自定义BeanUtils就能满足需求。
  • 加密逻辑要根据业务安全性要求选择,Base64只是示例,生产环境建议用AES这类对称加密算法,并妥善保管密钥。
  • 如果你不想自定义BeanUtils,也可以用ModelMapper这类更灵活的映射工具,通过添加自定义转换器实现同样效果,但考虑到你提到了BeanUtils,优先给出了适配BeanUtils的方案。

内容的提问来源于stack exchange,提问作者Shakthi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:03:19