Mybatis基于enum的开发

起因:最近一次开会的时候,一位老司机说了下项目中应该使用常量还是枚举来设置参数,然后提到了mybatis中enum需要特殊处理。当时不知道mybatis强大的类型处理器,所以不知道还能用enum来定义对象属性,完成映射就自己研究了一下。

1.ENUM

首先,假设我们有一些特定用户的用户名和密码用枚举来存放(只是假设,真实场景肯定不是这样)

public enum UserEnum {
    ZHANGSAN("zhangsan","1235456"),
    LISI("lisi","zouni"),
    ADMIN("root","root")
    ;

    private String name;
    private String password;

    private UserEnum(String name, String password) {
        this.name = name;
        this.password = password;
    }
    // getter and setter 
}

2.POJO

我们需要修改数据库映射的pojo中的属性,将需要设置为枚举的改成对应的枚举类型。提供一个toString方法,方便我们查看返回结果

public class TestEnum {
    private Integer id;

    private UserEnum name;

    private UserEnum password;

    // getter and setter

    @Override
    public String toString() {
        return "Testnote [id=" + id + ", name=" + name.getName() + ", password=" + password.getPassword() + "]";
    }
}

3.UserEnum的处理器

要使用enum对应的转换器是十分重要的。在mybatis中,有两种对于枚举对象的处理器:

  • EnumTypeHandler(通过枚举对象处理)
  • EnumOrdinalTypeHandler(通过枚举中常量序号处理)。

这里参考EnumTypeHandler源码,因为测试的时候EnumOrdinalTypeHandler老是失败(希望有成功的伙伴可以指点下)。

public class UserEnumHandler extends BaseTypeHandler<UserEnum> {

    private Class<UserEnum> type;

    public UserEnumHandler(Class<UserEnum> type) {
        if (type == null)
            throw new IllegalArgumentException("Type argument cannot be null");
        this.type = type;
    }

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, UserEnum parameter, JdbcType jdbcType)
            throws SQLException {
        switch (i) { // i 表示第几个参数
        case 1:
            if (jdbcType == null) {
                ps.setString(i, parameter.getName()); // NameEnum的Name为需要存储的数据
            } else {
                ps.setObject(i, parameter.getName(), jdbcType.TYPE_CODE);
            }
            break;
        case 2:
            if (jdbcType == null) {
                ps.setString(i, parameter.getPassword()); // NameEnum的Name为需要存储的数据
            } else {
                ps.setObject(i, parameter.getPassword(), jdbcType.TYPE_CODE);
            }
        default:
            break;
        }

    }

    @Override
    public UserEnum getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String s = rs.getString(columnName);
        switch (columnName) {
        case "name":
            return s == null ? null : findName(s);
        case "password":
            return s == null ? null : findPassword(s);
        default:
            return null;
        }
    }

    @Override
    public UserEnum getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        String s = rs.getString(columnIndex);
        return s == null ? null : findName(s);
    }

    @Override
    public UserEnum getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        String s = cs.getString(columnIndex);
        return s == null ? null : findName(s);
    }
    // 遍历UserEnum查找对应name的枚举
    private UserEnum findName(String name) {
        for (UserEnum tenum : UserEnum.class.getEnumConstants()) {
            if (tenum.getName().equals(name)) {
                return tenum;
            }
        }
        return null;
    }
    // 遍历UserEnum查找对应password的枚举
    private UserEnum findPassword(String password) {
        for (UserEnum tenum : UserEnum.class.getEnumConstants()) {
            if (tenum.getPassword().equals(password)) {
                return tenum;
            }
        }
        return null;
    }
}

4.mapper.java

mapper.java中没有什么特别改动,只是参数应该为枚举类型

public interface TestEnumMapper {

    // 根据Enum来更新数据
    TestEnum selectByEnum(Integer id);

    int updateByEnum(@Param("id") Integer id, @Param("user") UserEnum user);
}

5.重点配置mapper.xml

首先,对于查询返回的resultMap映射,需要配置处理器

<resultMap id="BaseResultMap" type="com.ys.model.TestEnum">
    <id column="id" property="id" jdbcType="INTEGER" />
    <result column="name" property="name" jdbcType="VARCHAR" typeHandler="com.ys.constant.UserEnumHandler" />
    <result column="password" property="password" jdbcType="VARCHAR" typeHandler="com.ys.constant.UserEnumHandler"/>
</resultMap>

通过ID查询,并完成枚举的装配

<select id="selectByEnum" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
    select id,name,password
    from testnote
    where id = #{id,jdbcType=INTEGER}
</select>

通过枚举来更新数据

<update id="updateByEnum" parameterType="com.ys.model.TestEnum">
    update testnote
    <set>
        <if test="user != null">
            name = #{user,jdbcType=VARCHAR,typeHandler=com.ys.constant.UserEnumHandler},
            password = #{user,jdbcType=VARCHAR,typeHandler=com.ys.constant.UserEnumHandler},
        </if>
    </set>
    where id = #{id,jdbcType=INTEGER}
</update>

注意:需要使用枚举的地方,用typeHandler来配置即可

6.测试用例

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:/spring/applicationContext.xml",
        "classpath:/spring/applicationContext-mybatis.xml" })
public class MyBatisTest {

    @Autowired
    private TestEnumMapper testEnumMapper;

    @Test
    public void testEnum() {
        testEnumMapper.updateByEnum(1, UserEnum.ZHANGSAN);
        TestEnum note = testEnumMapper.selectByEnum(1);
        System.out.println(note.toString());
    }
}

输出结果

Preparing: update testnote SET name = ?, password = ? where id = ? 
Parameters: zhangsan(String), 1235456(String), 1(Integer)
Updates: 1
Preparing: select id,name,password from testnote where id = ? 
Parameters: 1(Integer)
Total: 1
Testnote [id=1, name=zhangsan, password=1235456]

更多源码: https://github.com/oDevilo/OWOWL

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值