mybatis TypeHandler处理自定义枚举类型

迈不过友情╰ 2022-06-08 11:38 324阅读 0赞

之前做一个项目一个表字段中有很多状态,通过状态码来实现各个状态,但是在java 实体类中用int类型表示状态码,就出现一堆魔鬼数字。如果这样,那么后期代码维护和可读性比较困难,如果没有完整注释。
后来在官方参考 中发现mybatis提供两种枚举类型转换器:EnumTypeHandler(默认),EnumOrdinalTypeHandler.

EnumTypeHandler主要将字段值转换成对应枚举对象。通过Enum.valueOf(class,string) 方法实现。部分源码如下

  1. @Override
  2. public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
  3. String s = rs.getString(columnName);
  4. return s == null ? null : Enum.valueOf(type, s);
  5. }

EnumOrdinalTypeHandler 是将字段值(必须数字类型)作为枚举下标搜索对应枚举对象.部分源码如下

  1. @Override
  2. public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
  3. int i = rs.getInt(columnName);
  4. if (rs.wasNull()) {
  5. return null;
  6. } else {
  7. try {
  8. return enums[i];
  9. } catch (Exception ex) {
  10. throw new IllegalArgumentException("Cannot convert " + i + " to " + type.getSimpleName() + " by ordinal value.", ex);
  11. }
  12. }
  13. }

int i = rs.getInt(columnName); i是返回字段值,然后通过return enums[i];返回对应下标枚举对象。

但是很多时候码是根据业务确定的不一定是按照枚举下标来表示的。没办法这个时候只能自己动手,但是可以参考EnumOrdinalTypeHandler 做法,替换return enums[i];代码
自定义枚举类型转换器MyEnumTypeHandler完整代码如下:

  1. public class MyEnumTypeHandler<E extends Enum<E>&BaseEnum<E>> extends BaseTypeHandler<E> {
  2. private Class<E> type;
  3. private E[] enums;
  4. public MyEnumTypeHandler(Class<E> type) throws InstantiationException, IllegalAccessException{
  5. if (type == null) {
  6. throw new IllegalArgumentException("Type argument cannot be null");
  7. }
  8. this.type=type;
  9. this.enums=this.type.getEnumConstants();
  10. if(this.enums==null){
  11. throw new IllegalArgumentException(type.getSimpleName() + " does not represent an enum type.");
  12. }
  13. }
  14. @Override
  15. public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {
  16. ps.setInt(i, parameter.getCode());
  17. }
  18. @Override
  19. public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
  20. int i = rs.getInt(columnName);
  21. if (rs.wasNull()) {
  22. return null;
  23. } else {
  24. try {
  25. return getEnum(i);
  26. } catch (Exception ex) {
  27. throw new IllegalArgumentException("Cannot convert " + i + " to " + type.getSimpleName() + " by ordinal value.", ex);
  28. }
  29. }
  30. }
  31. @Override
  32. public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
  33. int i = rs.getInt(columnIndex);
  34. if (rs.wasNull()) {
  35. return null;
  36. } else {
  37. try {
  38. return getEnum(i);
  39. } catch (Exception ex) {
  40. throw new IllegalArgumentException("Cannot convert " + i + " to " + type.getSimpleName() + " by ordinal value.", ex);
  41. }
  42. }
  43. }
  44. @Override
  45. public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
  46. int i = cs.getInt(columnIndex);
  47. if (cs.wasNull()) {
  48. return null;
  49. } else {
  50. try {
  51. return getEnum(i);
  52. } catch (Exception ex) {
  53. throw new IllegalArgumentException("Cannot convert " + i + " to " + type.getSimpleName() + " by ordinal value.", ex);
  54. }
  55. }
  56. }
  57. private E getEnum(int code){
  58. for(E tmpE:this.enums){
  59. if(tmpE.getCode()==code){
  60. return tmpE;
  61. }
  62. }
  63. return null;
  64. }
  65. }

BaseEnum 代码:

  1. public interface BaseEnum<T> {
  2. int getCode();
  3. String getName();
  4. T getEnumByCode(int code);
  5. }

BaseEnum 接口是所有枚举必须继承,主要为了统一性。这样一个TypeHandler可以实现很多自定义enum.
在完成typeHandler之后需要将其加入到mybatis 配置文件中。

  1. <typeHandlers>
  2. <typeHandler handler="com.test.mybatis.typeHandler.MyEnumTypeHandler" javaType="XXEnum" />
  3. </typeHandlers>

考虑到如果很多枚举出现,不能都要修改一次配置文件,而且变化仅仅是javaType。后来发现mybatis提供一个MappedTypes 注解。只要在自定义typeHandler上实现即可。

  1. @Documented
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Target(ElementType.TYPE)
  4. public @interface MappedTypes {
  5. Class<?>[] value();
  6. }

这个注解value是数组类型,所以可以更方便添加。这样mybatis配置文件中只要将javaType属性去掉即可,后期再多枚举也不用改动mybatis配置文件,只要在MappedTypes注解里加新枚举即可。

发表评论

表情:
评论列表 (有 0 条评论,324人围观)

还没有评论,来说两句吧...

相关阅读