在JPA注解中,有个@Convert注解,其中需要传入一个Class作为convert参数,该class需要实现AttributeConverter<X,Y>接口。下面来看看AttributeConverter接口的作用。

AttributeConverter<X,Y>
实体属性类型转换器。主要使用场景:

持久化enum
加解密数据
持久化日期
简单化操作,用持久化enum枚举来进行一个操作。AttributeConverter<X,Y>该接口中需要实现两个方法:

y convertToDatabaseColumn(x) 作用:将实体属性x转化为y存储到数据库中,即插入和更新操作时执行;
x convertToEntityAttribute(y) 作用:将数据库中的字段y转化为实体属性x,即查询操作时执行。
场景:用户登录时,记录用户的动作:登录,登出,注册,重置密码。

创建一个枚举类UserAction

* 用户操作枚举. * @author Wang.ch public enum UserAction { REG ( 0 , "注册" ) , RESET ( 1 , "重置密码" ) , LOGIN ( 2 , "用户登录" ) , LOGOUT ( 3 , "用户登出" ) ; private int value ; private String desc ; UserAction ( int value , String desc ) { this . value = value ; this . desc = desc ; public int getValue ( ) { return value ; public void setValue ( int value ) { this . value = value ; public String getDesc ( ) { return desc ; public void setDesc ( String desc ) { this . desc = desc ; public static class Convert implements AttributeConverter < UserAction , Integer > { @Override public Integer convertToDatabaseColumn ( UserAction attribute ) { return attribute == null ? null : attribute . getValue ( ) ; @Override public UserAction convertToEntityAttribute ( Integer dbData ) { for ( UserAction type : UserAction . values ( ) ) { //将数字转换为描述 if ( dbData . equals ( type . getValue ( ) ) ) { return type ; throw new RuntimeException ( "Unknown database value: " + dbData ) ; //另一种写法 //public UserAction convertToEntityAttribute(Integer dbData) { // return Stream.of(values()) // .filter(userAction -> //userAction.value.equalsIgnoreCase(dbData)) // .findFirst() // .orElse(UNKNOWN);

其中,在已经把转换类Convert写入到了枚举当中。

在实体内中添加注解

@Convert(converter = UserAction.Convert.class)
private UserAction action;

从转换类中的方法可以看出,在写入数据库时,jpa会调用convert的convertToDatabaseColumn方法,把UserAction枚举的value写入到库中,在反向查询时,通过数据库的值和遍历的枚举的value进行比较,然后返回UserAction实体。

数据的加密和日期的转换也就类似的操作了。

但是这样的每个枚举可能都要去写这样的转换类,可能会存在重复的操作。可以尝试写个通用的枚举转换类。

所有的枚举都实现一个接口:BaseEnum.java
写一个抽象类去实现AttributeConverter<X,Y>:BaseEnumConverter<X,Y>
所有的枚举中定义一个public静态类继承抽象类
BaseEnum.java

* 枚举基类. * @author Wang.ch * @param <T> 数据库存储的java类型 public interface BaseEnum<Y> { * 存取到数据库中的值. * @return public Y getValue();

BaseEnumConverter.java

public abstract class BaseEnumConverter<X extends BaseEnum<Y>, Y> implements AttributeConverter<BaseEnum<Y>, Y> {
    private Class<X> xclazz;
    private Method valuesMethod;
    @SuppressWarnings("unchecked")
    public BaseEnumConverter() {
        this.xclazz = (Class<X>) (((ParameterizedType) this.getClass().getGenericSuperclass())
                .getActualTypeArguments())[0];
        try {
            valuesMethod = xclazz.getMethod("values");
        } catch (Exception e) {
            throw new RuntimeException("can't get values method from " + xclazz);
    @Override
    public Y convertToDatabaseColumn(BaseEnum<Y> attribute) {
        return attribute == null ? null : attribute.getValue();
    @SuppressWarnings("unchecked")
    @Override
    public X convertToEntityAttribute(Y dbData) {
        try {
            X[] values = (X[]) valuesMethod.invoke(null);
            for (X x : values) {
                if (x.getValue().equals(dbData)) {
                    return x;
        } catch (Exception e) {
            throw new RuntimeException("can't convertToEntityAttribute" + e.getMessage());
        throw new RuntimeException("unknown dbData " + dbData);

修改后的枚举:UserAction.java

* 用户操作枚举. * @author Wang.ch public enum UserAction implements BaseEnum<Integer> { REG(0, "注册"), RESET(1, "重置密码"), LOGIN(2, "用户登录"), LOGOUT(3, "用户登出"); private Integer value; private String desc; UserAction(Integer value, String desc) { this.value = value; this.desc = desc; public Integer getValue() { return value; public void setValue(Integer value) { this.value = value; public String getDesc() { return desc; public void setDesc(String desc) { this.desc = desc; public static class Convert2 extends BaseEnumConverter<UserAction, Integer>{

需要注意的是,在上面的代码中,BaseEnumConverter使用了BaseEnum作为X的限定类型,但是实际上并未能真正限定传入的数据类型是一个枚举类型,显然BaseEnumConverter只适用于枚举类型,因为在类初始化时,使用了values这个Method反射,只有枚举类型才有。在其他的值类型转换时,可以参照枚举自定义其他的X限定类型。

小技巧,如果枚举没有这么复杂,则完全可以用@Enumerated(EnumType.ORDINAL)和@Enumerated(EnumType.STRING)让数据库自动进行转换。

参考链接:https://www.jianshu.com/p/15f5b7062eac

可以使用JPA 2.0保留枚举,但是没有很好的方法来实现。 使用@Enumerated批注,可以使用EnumType.ORDINAL或EnumType.STRING将枚举值映射到其数据库表示形式。 但是这两种选择都有一些缺点,我们将在本文的第一部分中进行讨论。 在第二部分中,我将向您展示通过使用JPA 2.1类型转换来避免这些缺点。 使用JPA 2.0持久枚举 EnumType.ORD...
目录前言具体实现Map与JSON的属性转换List与JSON属性转换实体应用效果图 @Convert属性转换用于数据库属性类型与java存储的类型做转换,其方便之处在于存储与读取的时候能自动转换,如下业务场景: 业务对象存在一个Map或List属性,存入数据库时需保存为json字符串,返回前端时以对象来返回。 @Convert属性转换需实现AttributeConverter<X, Y>接口,第一个泛型类型为Entity字段类型,第二个泛型类型为数据库字段类型。
JPA踩坑记:Spring Data Jpa 原生SQL联表查询返回自定义DTO 关键字: JPA复杂查询,JPA返回自定义实体,JPA返回自定义DTO,JPA联表查询,JPA原生SQL查询,JPA踩坑 新冠疫情之下,闲来无事研究了一下JPA,发现坑还是不少的,特地记录一下,有兴趣的道友可以看看。 在灵活性上JPA比不上MyBatis,比如想联表查询返回一个自定义实体Dto,结果发现不能直...
3.8 类型转换原理与设置 Spring为我们提供了ConversionService接口用来做类型转换,它是Spring类型转换系统的入口。像我们注册的Formatter的FormattingConversionService类就是它的实现类。 FormattingConversionService支持注册Formatter、Converter和AnnotationFormatterFactory,它属于配置初始化数据绑定的一部分。 3.8.1 Formatter Formatter用于格式化(id|na
开发过程中我们可能会遇到这样的问题。如何将一个Map<String,String>(一个Object)保存到数据库中,很多人的第一想法是这个简单。只要我们持久化的时候将这个Map转换成一个JSON以String的形式保存即可。 今天我们换一个新的方式去实现这个功能: 首先我们要了解一个东西AttributeConverters属性转换 第一步:实现一个AttributeConve...
public class BooleanConverter implements AttributeConverter<Boolean, Integer> { 2. 属性注解 @Column(name = "VALID")@Convert(converter = BooleanConverter.class) 转载于:https://www.cnblogs.c...
AttributeConverter javax.persistence.AttributeConverter 开发中有一个问题,有一个业务对象,它的属性是一个JSONObject对象,但是我们希望存入数据库时,存为json字符串。前端在插入和查询时,都是以对象来处理,所以希望能自动转换,即在插入数据库时,转为字符串,查询出来后转为对象。这就用到了今天要说的属性转换。 第一步:定义一个属性转换...
在真实的生产环境中,我们可能会把某些对象转换成json数据存到数据库,等到需要的时候再把这些数据取出来。 1、我们可以在数据库中添加一个class字段,存放该类的全路径,取出来的时候把json数据和class字段取出来,然后可以使用 fastjson等三方工具转成对象。 2、上面这种方式是通用的,不过在jpa中可以简化这个操作 。使用到的对象就是AttributeConve...
最近将项目由mybatis 修改为 jpa,遇到一个问题. 描述: 实体中的成员属性的类型是数组,在mybatis的xml中对该数组类型的属性进行了处理,而在jpa中,认为数组是(一对一或者一对多或者多对多)的关系映射 提示如下错误: 意思是无法进行序列化,在网上查找n多资料都说要加 关系注解,ranbinluan org.springframework.orm.jpa.JpaSystemExc...
用于数据库属性类型与java存储的类型做转换,例如枚举类型,在存储到数据库时或者在数据库取出来时,不用手动转换。 必须实现接口AttributeConverter&lt;X,Y&gt;,源码如下: package javax.persistence; * A class that implements this interface can be used to conver...