• Mybatis实战之自定义TypeHandler处理枚举


                    <input type="hidden" class="isFancy">
                    
                        
                            <header class="article-header">
                                
    
    <h1 class="article-title" itemprop="name">
      Mybatis实战之自定义TypeHandler处理枚举
    </h1>
    
    
    
                            </header>
                            
                                <div class="article-info article-info-post">
                                    
    <div class="article-tag tagcloud">
    	<ul class="article-tag-list"><li class="article-tag-list-item"><a class="color5" href="/tags/java/" style="font-size: 12px;">java</a></li><li class="article-tag-list-item"><a class="color3" href="/tags/mybatis/" style="font-size: 12px;">mybatis</a></li></ul>
    </div>
    
    
                                        
    <div class="article-category tagcloud">
    <a class="color5" href="/categories/后端技术/" style="font-size: 12px;">后端技术</a>
    </div>
    
    
                                            <div class="clearfix"></div>
                                </div>
                                
                                    
    
                                        <div class="article-entry" itemprop="articleBody">
                                           <!--
                                            
    
                                                    <p class="toc-button">目录</p>
    
                                            -->
                                            
                                                     <p>在Mybatis中,处理枚举类的TypeHandler有两个:</p>
    
    1. EnumTypeHandler: 用于保存枚举名
    2. EnumOrdinalTypeHandler: 用于保存枚举的序号。

    在实际项目中,以上往往不能满足我们的需求。

    需求分析

    枚举需要包含两个属性,label(用于显示), value(实际的枚举值)。数据库保存枚举值(value)。

    这很明显Mybatis提供的两个枚举TypeHandler不能满足我们的需求。此时,我们可以自定义一个通用的枚举TypeHandler来满足我们的需求。

    自定义枚举TypeHandler

    通用枚举DisplayedEnum

    public interface DisplayedEnum {
    
    String DEFAULT_VALUE_NAME = "value";
    
    String DEFAULT_LABEL_NAME = "label";
    
    default Integer getValue() {
        Field field = ReflectionUtils.findField(this.getClass(), DEFAULT_VALUE_NAME);
        if (field == null)
            return null;
        try {
            field.setAccessible(true);
            return Integer.parseInt(field.get(this).toString());
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
    
    @JsonValue
    default String getLabel() {
        Field field = ReflectionUtils.findField(this.getClass(), DEFAULT_LABEL_NAME);
        if (field == null)
            return null;
        try {
            field.setAccessible(true);
            return field.get(this).toString();
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
    
    static &lt;T extends Enum&lt;T&gt;&gt; T valueOfEnum(Class&lt;T&gt; enumClass, Integer value) {
        if (value == null)
            throw  new IllegalArgumentException("DisplayedEnum value should not be null");
        if (enumClass.isAssignableFrom(DisplayedEnum.class))
            throw new IllegalArgumentException("illegal DisplayedEnum type");
        T[] enums = enumClass.getEnumConstants();
        for (T t: enums) {
            DisplayedEnum displayedEnum = (DisplayedEnum)t;
            if (displayedEnum.getValue().equals(value))
                return (T) displayedEnum;
        }
        throw new IllegalArgumentException("cannot parse integer: " + value + " to " + enumClass.getName());
    }
    

    }

    说明:
    普通枚举类通过实现DisplayedEnum接口,就可以:

    1. 通过getValue()获取枚举值。
    2. 通过getLabel()获取枚举的label属性。
    3. 通过valueOfEnum()将Integer值转换为指定的枚举类型。

    普通枚举类

    public enum CommonsType implements DisplayedEnum {
    
    NORMAL("正常", 0), INVALID("无效", 1);
    
    String label;
    
    Integer value;
    
    private CommonsType(String label, Integer value) {
        this.label = label;
        this.value = value;
    }
    

    }

    以上就是一个普通枚举类的示例。

    自定义枚举TypeHandler

    @MappedJdbcTypes(value = JdbcType.TINYINT, includeNullJdbcType = true)
    public class DefaultEnumTypeHandler extends BaseTypeHandler<DisplayedEnum> {
    
    private Class&lt;DisplayedEnum&gt; type;
    
    public EnumTypeHandler(){};
    
    public EnumTypeHandler(Class&lt;DisplayedEnum&gt; type) {
        if (type == null) throw new IllegalArgumentException("Type argument cannot be null");
        this.type = type;
    }
    
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, DisplayedEnum parameter, JdbcType jdbcType)
            throws SQLException {
        ps.setInt(i, parameter.getValue());
    }
    
    @Override
    public DisplayedEnum getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return convert(rs.getInt(columnName));
    }
    
    @Override
    public DisplayedEnum getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return convert(rs.getInt(columnIndex));
    }
    
    @Override
    public DisplayedEnum getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return convert(cs.getInt(columnIndex));
    }
    
    private DisplayedEnum convert(int status){
        DisplayedEnum[] objs = type.getEnumConstants();
        for(DisplayedEnum em: objs){
            if(em.getValue() == status){
                return  em;
            }
        }
        return null;
    }
    

    }

    使用我们自定义的DefaultEnumTypeHandler

    由于Mybatis默认在处理枚举类型的时候会使用EnumTypeHandler(只保存及转换枚举类型的名字), 因此,我们需要手动指定使用DefaultEnumTypeHandler。示例如下:

    <resultMap id="xxx" type="xxx">
        ...
        <result column="type" jdbcType="TINYINT" property="type" typeHandler="xxx.xxx.xxx.DefaultEnumTypeHandler" />
        ...
    </resultMap>    
    

    即我们需要通过使用typeHandler来指定。

    小结

    以上是我们应用在实际项目中的一个对于Mybatis处理枚举类的方案。我看大多数人也都是这样在用。然而,在实际项目中,我们会发现随着枚举类的增多,这样写起来会很繁琐。我看了一下网络上似乎也没人处理这种情况。那么,下一篇文章将针对这种情况进行处理。

                                        </div>
    
                                        
            </div>
  • 相关阅读:
    游标cursor
    SQL: EXISTS
    LeetCode Reverse Integer
    LeetCode Same Tree
    LeetCode Maximum Depth of Binary Tree
    LeetCode 3Sum Closest
    LeetCode Linked List Cycle
    LeetCode Best Time to Buy and Sell Stock II
    LeetCode Balanced Binary Tree
    LeetCode Validate Binary Search Tree
  • 原文地址:https://www.cnblogs.com/zhuhui-site/p/10090844.html
Copyright © 2020-2023  润新知