在開發(fā)中經(jīng)常遇到一些枚舉類型的字段地回;例如:
@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; 用戶狀態(tài)
public class UserStatus extends StringEnum {
private static final long serialVersionUID = 1220048355057672045L;
public static final UserStatus CREATED = newInstance(UserStatus.class,"created", "創(chuàng)建");
public static final UserStatus USE = newInstance(UserStatus.class, "use", "使用");
}
數(shù)據(jù)庫存儲編碼 “created”竞帽,Java 映射對象 CREATED杨帽;
這種場景是非常常見的法希,類型歹袁,狀態(tài)坷衍,,条舔,枫耳,等字段都可以這樣搞。
實現(xiàn)方案: 實現(xiàn)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 結(jié)果集
* @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 {
// 結(jié)果集為 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 插入的數(shù)據(jù)
* @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
// 測試結(jié)束后事物是否回滾;默認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);
}
}
執(zhí)行日志
數(shù)據(jù)庫成功修改