美文网首页
Hibernate 中自定义UserType映射枚举类型

Hibernate 中自定义UserType映射枚举类型

作者: Bertram_Wang | 来源:发表于2019-08-17 12:49 被阅读0次

    在开发中经常遇到一些枚举类型的字段;例如:

    @Entity
    @Data
    @Table(name = "sys_user")
    @NoArgsConstructor
    @AllArgsConstructor
    @Builder
    @EqualsAndHashCode(callSuper = true)
    public class User extends AbstractBean {
        private static final long serialVersionUID = 7814370326796291722L;
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        @Column(name = "create_time")
        @CreationTimestamp
        private Date createTime;
    
        @Column(name = "modify_time")
        @UpdateTimestamp
        private Date modifyTime;
    
        @Column(name = "phone")
        private String phone;
    
        @Column(name = "email")
        private String email;
    
        @Column(name = "password")
        private String password;
    
        @Column(name = "status")
        private UserStatus status;
    
        @Column(name = "name")
        private String name;
    }
    

    UserStatus status; 用户状态

    public class UserStatus extends StringEnum {
        private static final long serialVersionUID = 1220048355057672045L;
        public static final UserStatus CREATED = newInstance(UserStatus.class,"created", "创建");
        public static final UserStatus USE = newInstance(UserStatus.class, "use", "使用");
    }
    

    数据库存储编码 “created”,Java 映射对象 CREATED;
    这种场景是非常常见的,类型,状态,,,,等字段都可以这样搞。

    实现方案: 实现UserType接口

    @Data
    public class StringEnum extends AbstractSimpleField implements UserType {
        private static final long serialVersionUID = 1732002864737498898L;
        private static final Logger LOGGER = LoggerFactory.getLogger(StringEnum.class);
        String code;
        String value;
        /**
         * 因为我只存入code 所以这里只要一个值就行。  不同的类型可以查看Types对应的类型
         */
        private static final int[] SQL_TYPES = { Types.VARCHAR };
        @Override
        public int[] sqlTypes() {
            return SQL_TYPES;
        }
    
        /**
         * 返回的类型
         * @return class
         */
        @Override
        public Class returnedClass() {
            return StringEnum.class;
        }
    
        /**
         * 重写 equals
         * @param x 对象x
         * @param y 对象y
         * @return boolean
         * @throws HibernateException 异常
         */
        @Override
        public boolean equals(Object x, Object y) throws HibernateException {
            boolean result = false;
            if (x == y) result = true;
            if (x == null || y == null) result = false;
            if (x instanceof StringEnum && y instanceof StringEnum) {
                result = ((StringEnum) x).getCode().equals(((StringEnum) y).getCode());
            }
            return result;
        }
    
        /**
         * 重写 hashCode
         * @param o 对象o
         * @return int
         * @throws HibernateException 异常
         */
        @Override
        public int hashCode(Object o) throws HibernateException {
            StringEnum stringEnum = (StringEnum) o;
            return stringEnum.hashCode();
        }
    
        /**
         * 查询出来的code 生成对应的 StringEnum
         * @param resultSet 结果集
         * @param strings 字段集合--只有code
         * @param sharedSessionContractImplementor session
         * @param o 查询的对象
         * @return StringEnum
         * @throws HibernateException 异常
         * @throws SQLException 异常
         */
        @Override
        public Object nullSafeGet(ResultSet resultSet, String[] strings, SharedSessionContractImplementor sharedSessionContractImplementor, Object o) throws HibernateException, SQLException {
            // 结果集为 null 直接返回
            if (resultSet == null || resultSet.wasNull()) return null;
            // 获取code编码
            String code = resultSet.getString(strings[0]);
            // 获取 枚举属性类型
            Class clazz = this.getClass();
            // 返回对应的枚举
            return allSimpleFields.get(getKey(clazz, code));
        }
    
        /**
         * 新增和修改时,设置保存的code
         * @param preparedStatement 预编译SQL语句的对象
         * @param o 插入的数据
         * @param i 占位符
         * @param sharedSessionContractImplementor session
         * @throws HibernateException 异常
         * @throws SQLException 异常
         */
        @Override
        public void nullSafeSet(PreparedStatement preparedStatement, Object o, int i, SharedSessionContractImplementor sharedSessionContractImplementor) throws HibernateException, SQLException {
            if (o == null){
                preparedStatement.setNull(i, Types.VARCHAR);
            }else{
                StringEnum stringEnum = (StringEnum) o;
                preparedStatement.setString(i, stringEnum.getCode());
            }
        }
    
        @Override
        public Object deepCopy(Object o) throws HibernateException {
            return o;
        }
    
        @Override
        @Transient
        public boolean isMutable() {
            return false;
        }
    
        @Override
        public Serializable disassemble(Object o) throws HibernateException {
            return (Serializable) deepCopy(o);
        }
    
        @Override
        public Object assemble(Serializable serializable, Object o) throws HibernateException {
            return deepCopy(serializable);
        }
    
        @Override
        public Object replace(Object o, Object o1, Object o2) throws HibernateException {
            return o;
        }
    
    }
    

    AbstractSimpleField保存所有的枚举对象

    public abstract class AbstractSimpleField implements Serializable {
        private static final Logger LOGGER = LoggerFactory.getLogger(AbstractSimpleField.class);
        private static final long serialVersionUID = 5964652520313221077L;
        /**
         * 全部枚举类型
         */
        static Map<String, StringEnum> allSimpleFields = new ConcurrentHashMap<>();
    
        protected static <T extends StringEnum> T newInstance(Class<T> clazz, String code, String value){
            try {
                T t = clazz.newInstance();
                t.setCode(code);
                t.setValue(value);
                allSimpleFields.put(getKey(clazz,code), t);
                return t;
            } catch (Exception e) {
                LOGGER.error(e.getMessage());
                return null;
            }
        }
        static String getKey(Class clazz, String code){
            if (clazz == null) return code;
            return clazz.getName() + ":" +code;
        }
    } 
    

    测试

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration({ "classpath:config/spring-*.xml"})
    @Transactional
    // 测试结束后事物是否回滚;默认true;
    @Rollback(value = false)
    public class UserDaoImplTest {
    
        @Autowired
        private UserDao userDao;
    
        @Test
        public void findById() {
            User user = userDao.findById(1L);
            if (user == null){
                System.out.println("================");
            }
            System.out.println(user);
            UserStatus userStatus = user.getStatus();
            if (UserStatus.USE.equals(userStatus)){
                user.setStatus(UserStatus.CREATED);
            }else {
                user.setStatus(UserStatus.USE);
            }
            userDao.save(user);
            System.out.println(user);
        }
    }
    
    执行日志
    数据库成功修改

    相关文章

      网友评论

          本文标题:Hibernate 中自定义UserType映射枚举类型

          本文链接:https://www.haomeiwen.com/subject/kbshsctx.html