学习Spring Boot:(十二)Mybatis 中自定义枚举转换器

前言

在 Spring Boot 中使用 Mybatis 中遇到了字段为枚举类型,数据库存储的是枚举的值,发现它不能自动装载。

解决

内置枚举转换器

MyBatis内置了两个枚举转换器分别是:org.apache.ibatis.type.EnumTypeHandlerorg.apache.ibatis.type.EnumOrdinalTypeHandler

EnumTypeHandler

mybatis 中默认的枚举转换器,是获取枚举中的 name 属性。

EnumOrdinalTypeHandler

获取枚举中 ordinal 属性,就是例如索引一样的东西,不过是从 1 开始递增的。

因此上面提供的两种的转换器都不能满足我们的需求,我们需要自定义一个转换器。

自定义枚举转换器

MyBatis提供了 org.apache.ibatis.type.BaseTypeHandler 类用于我们自己扩展类型转换器,上面的EnumTypeHandler和EnumOrdinalTypeHandler 也都实现了这个接口。

继承 BaseTypeHandler 一共需要实现4个方法:

  1. void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType)
    用于定义设置参数时,该如何把Java类型的参数转换为对应的数据库类型;
  2. T getNullableResult(ResultSet rs, String columnName)
    用于定义通过字段名称获取字段数据时,如何把数据库类型转换为对应的Java类型;
  3. T getNullableResult(ResultSet rs, int columnIndex)
    用于定义通过字段索引获取字段数据时,如何把数据库类型转换为对应的Java类型;
  4. T getNullableResult(CallableStatement cs, int columnIndex)
    用定义调用存储过程后,如何把数据库类型转换为对应的Java类型。
定义一个枚举通用行为

定义一个枚举通用行为,规范枚举的实现。

public interface BaseEnum<E extends Enum<?>, T> {/*** 获取枚举的值* @return 枚举的值*/T getValue();
}

定义自己需要的枚举:

public class SysConstant {/*** 人员状态*/public enum SysUserStatus implements BaseEnum<SysUserStatus, String> {/*** 账户已经激活(默认)*/ACTIVE("1"),/*** 账户锁定*/LOCK("0");private String value;private SysUserStatus(String value) {this.value = value;}@Overridepublic String getValue() {return value;}}/*** 人员类型*/public enum SysUserType implements BaseEnum<SysUserType, String> {/*** 普通用户*/USER("1"),/*** 系统管理员*/ADMIN("0");private String value;private SysUserType(String value) {this.value = value;}@Overridepublic String getValue() {return value;}}
}
实现自定义转换器

自定义一个基本的枚举转换器工具,如果有其他需求可以在这个基类上自定义。

package com.wuwii.common.util;import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Objects;/*** 参考 http://blog.csdn.net/fighterandknight/article/details/51520595 * 进行对本地项目的优化* <p>* 解决 Mybatis 中枚举的问题,* 获取 ResultSet 的值都是获取字符串的,然后比较字符串,以便通用。** @author Zhang Kai* @version 1.0* @since <pre>2018/2/9 17:26</pre>*/
public abstract class BaseEnumTypeHandler<E extends Enum<E> & BaseEnum> extends BaseTypeHandler<E> {/*** 枚举的class*/private Class<E> type;/*** 枚举的每个子类枚*/private E[] enums;/*** 一定要有默认的构造函数,不然抛出 not found method 异常*/public BaseEnumTypeHandler() {}/*** 设置配置文件设置的转换类以及枚举类内容,供其他方法更便捷高效的实现** @param type 配置文件中设置的转换类*/public BaseEnumTypeHandler(Class<E> type) {if (type == null) {throw new IllegalArgumentException("Type argument cannot be null");}this.type = type;this.enums = type.getEnumConstants();if (this.enums == null) {throw new IllegalArgumentException(type.getSimpleName()+ " does not represent an enum type.");}}@Overridepublic void setNonNullParameter(PreparedStatement ps, int i, E parameter,JdbcType jdbcType) throws SQLException {/** BaseTypeHandler已经帮我们做了parameter的null判断* 数据库存储的是枚举的值,所以我们这里使用 value , 如果需要存储 name,可以自定义修改*/if (jdbcType == null) {ps.setString(i, Objects.toString(parameter.getValue()));} else {ps.setObject(i, parameter.getValue(), jdbcType.TYPE_CODE);}}@Overridepublic E getNullableResult(ResultSet rs, String columnName)throws SQLException {String i = rs.getString(columnName);if (rs.wasNull()) {return null;} else {return locateEnumStatus(i);}}@Overridepublic E getNullableResult(ResultSet rs, int columnIndex)throws SQLException {String i = rs.getString(columnIndex);if (rs.wasNull()) {return null;} else {return locateEnumStatus(i);}}@Overridepublic E getNullableResult(CallableStatement cs, int columnIndex)throws SQLException {String i = cs.getString(columnIndex);if (cs.wasNull()) {return null;} else {return locateEnumStatus(i);}}/*** 枚举类型转换,由于构造函数获取了枚举的子类 enums,让遍历更加高效快捷,* <p>* 我将取出来的值 全部转换成字符串 进行比较,** @param value 数据库中存储的自定义value属性* @return value 对应的枚举类*/private E locateEnumStatus(String value) {for (E e : enums) {if (Objects.toString(e.getValue()).equals(value)) {return e;}}throw new IllegalArgumentException("未知的枚举类型:" + value + ",请核对"+ type.getSimpleName());}
}
配置转换器

将枚举转换器编写完成后,我们需要定义它对哪些枚举进行转换。
可以在Mybatis 配置文件配置

<typeHandlers><typeHandler handler="com.example.typeHandler.CodeEnumTypeHandler" javaType="com.example.entity.enums.ComputerState"/>
</typeHandlers>
优化

在MyBatis中添加typeHandler用于指定哪些类使用我们自定义的转换器,一旦系统中的枚举类多了起来,MyBatis的配置文件维护起来会变得非常麻烦,也容易出错

方法一
定义一个 EnumTypeHandler 去继承我们的 BaseEnumTypeHandler。然后使用注解 @MappedTypes 类型转换。

package com.wuwii.module.sys.common.handle;import com.wuwii.common.handle.BaseEnumTypeHandler;
import com.wuwii.common.util.BaseEnum;
import com.wuwii.module.sys.common.util.SysConstant;
import org.apache.ibatis.type.MappedTypes;/*** 枚举转换的公共模块** @author Zhang Kai* @version 1.0* @since <pre>2018/2/9 18:12</pre>*/
@MappedTypes(value = {SysConstant.SysUserStatus.class, SysConstant.SysUserType.class})
public class SysEnumTypeHandler<E extends Enum<E> & BaseEnum> extends BaseEnumTypeHandler<E> {/*** 设置配置文件设置的转换类以及枚举类内容,供其他方法更便捷高效的实现** @param type 配置文件中设置的转换类*/public SysEnumTypeHandler(Class<E> type) {super(type);}
}

需要在系统配置文件中配置

# 多个模块的的多个 包配置可以使用逗号分开。
mybatis:typeHandlersPackage: com.wuwii.module.sys.common.handle,com.wuwii.module.task.common.handle

方法二
如果你的项目中自定义了 SqlSessionFactory,推荐使用下面这种方式,一次使用无需多次配置。

如何在MyBatis中优雅的使用枚举

在 =》 方案 6. 优化

方法三
还有个人修改源码实现的,有兴趣的可以看看:

修改MyBatis源码实现扫描注册枚举-具体实现

参考文章

  • 如何在MyBatis中优雅的使用枚举
  • SpringBoot Mybatis EnumTypeHandler自定义统一处理器

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/556833.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

php旅行社网站源码在线支付,PHP各大支付平台在线支付集成源码

演示查看&#xff1a;http://www.erdangjiade.com/ph...php给客户开发网站的时候需要用到各大平台付款功能&#xff0c;下面就免费分享给大家&#xff0c;此类是个成熟类&#xff0c;网上down下来的&#xff0c;经过修改测试了(可以直接拿来使用&#xff0c;附带使用方法&#…

学习Spring Boot:(十三)配置 Shiro 权限认证

经过前面学习 Apache Shiro &#xff0c;现在结合 Spring Boot 使用在项目里&#xff0c;进行相关配置。 正文 添加依赖 在 pom.xml 文件中添加 shiro-spring 的依赖&#xff1a; <dependency><groupId>org.apache.shiro</groupId><artifactId>shir…

php设计之初用于什么,PHP设计模式(七)之门面模式

一、什么是外观模式(Facade Pattern)定义&#xff1a;外观模式又称门面模式&#xff0c;提供一个统一的接口&#xff0c;用来访问子系统中的一群接口。外部与子系统之间的通信采用门面(Facade)对象来完成。【举例】比如麦当劳套餐&#xff0c;套餐包含鸡肉卷、汉堡包、可乐等N个…

学习Spring Boot:(十四)spring-shiro的密码加密

前言 前面配置了怎么使用 shiro &#xff0c;这次研究下怎么使用spring shiro的密码加密&#xff0c;并且需要在新增、更新用户的时候&#xff0c;实现生成盐&#xff0c;加密后的密码进行入库操作。 正文 配置凭证匹配器 Beanpublic HashedCredentialsMatcher hashedCreden…

php 仿高德,仿高德路线规划滑动效果

因为项目有个界面要模仿高德地图路径规划滑动效果&#xff0c;因此写了demo&#xff0c;并简单说下分析过程。高德地图效果演示:仿高德路线规划滑动.gifdemo效果演示:高德地图规划滑动.gif一. 分析首先&#xff0c;我们可以看出这个滚动的视图应该是UIScrollView或者UIScrollVi…

php验证码完整功能,PHP验证码功能的实现

/***产生验证码图片*/public function actionVerfiycode() {Header ( "Content-type: image/gif" );$border 0; //是否要边框 1要:0不要$how 4; //验证码位数$w $how * 15; //图片宽度$h 20; //图片高度$fontsize 5; //字体大小$alpha "abcdefghijkmnopqr…

学习Spring Boot:(十五)使用Lombok来优雅的编码

前言 Lombok 是一种 Java? 实用工具&#xff0c;可用来帮助开发人员消除 Java 的冗长&#xff0c;尤其是对于简单的 Java 对象&#xff08;POJO&#xff09;。它通过注解实现这一目的。 正文 添加依赖 在 pom.xml 文件中添加相关依赖&#xff1a; <lombok.version>1.…

java 品尝饮料,java细节经典题型

28. 选项中哪一行代码可以替换题目中//add code here 而不产生编译错误?() [java] view plaincopy 1. public abstract class MyClass { 2. 3. 4. 5.......Java 基础试题 一:选择题(1*3030) (题目写在答题纸上面) 1:Java 提供哪几种运算符多选 ( abcd )。 A)算术运算符 B)位运…

学习Spring Boot:(十六)使用Shiro与JWT 实现认证服务

前言 代码可以参考 需要把Web应用做成无状态的&#xff0c;即服务器端无状态&#xff0c;就是说服务器端不会存储像会话这种东西&#xff0c;而是每次请求时access_token进行资源访问。这里我们将使用 JWT 1&#xff0c;基于散列的消息认证码&#xff0c;使用一个密钥和一个消…

java泛型和注解,泛型 · 注解和泛型 · 看云

[TOC]# 泛型## 为什么要使用泛型在之前学过的集合框架中&#xff0c;List和Map都使用了泛型技术来确认其内容的数据类型。如果不使用泛型&#xff0c;在程序运行阶段&#xff0c;会带来数据类型转型的错误风险。~~~List list new ArrayList();list.add("tom");for (…

java程序单引号报错,javapoigetInpuStream报错br/是这样的, 爱问知识人

是这样的&#xff0c;我写了重载了两个getInputStream方法&#xff0c;当调用不带参数的方法时&#xff0c;运行正常&#xff0c;当调用带参的方法则报 Can not find a java.io.InputStream with the name [inputStream] in是这样的&#xff0c;我写了重载了两个getInputStream…

学习Spring Boot:(十七)Spring Boot 中使用 Redis

前言 Redis是一个由Salvatore Sanfilippo写的key-value存储系统。 edis是一个开源的使用ANSI C语言编写、遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库&#xff0c;并提供多种语言的API。 通常被称为数据结构服务器&#xff0c;因为值&#xff08;va…

jqueryd登录异步请求 java,ajaxd的js和jquery实现

先来看一下javascript的。var httpxml;httpxml new XMLHttpRequest();httpxml.onreadystatechangefunction(){ //当服务器响应就绪时执行函数(就是说服务器准备好了你可以发请求了)if(httpxml.status 200 && httpxml.readyState 4){//这里200和4代表响应的状态&…

学习Spring Boot:(十八)Spring Boot 中session共享

前言 前面我们将 Redis 集成到工程中来了&#xff0c;现在需要用它来做点实事了。这次为了解决分布式系统中的 session 共享的问题&#xff0c;将 session 托管到 Redis。 正文 引入依赖 除了上篇文章中引入 spring-boot-starter-data-redis&#xff0c;还需要 spring-sess…

matlab 码元扩展,扩频通信及matlab仿真

扩展频谱通信以及直接扩频的matlab仿真号无关)扩展频谱后成为宽频带信号&#xff0c;然后再进行传输的一种系统。待传输的基带信号就是信源发出的数字信号。特定的扩频函数通常选用各种伪随机序列(扩频码)&#xff0c;其码元传输速率远大于基带信号速率&#xff0c;因而和基带信…

学习Spring Boot:(十九)Shiro 中使用缓存

前言 在 shiro 中每次去拦截请求进行权限认证的时候&#xff0c;都会去数据库查询该用户的所有权限信息&#xff0c; 这个时候就是有一个问题了&#xff0c;因为用户的权限信息在短时间内是不可变的&#xff0c;每次查询出来的数据其实都是重复数据&#xff0c;没必要每次都去…

matlab安装无效距离过远,求助matlab的远程序

求助matlab的远程序function varargout a1(varargin)% A1 M-file for a1.fig% A1, by itself, creates a new A1 or raises the existing% singleton*.%% H A1 returns the handle to a new A1 or the handle to% the existing singleton*.%% A1(CALLBACK,hObject,eventData,…

学习Spring Boot:(二十)使用 MongoDB

前言 MongoDB&#xff08;来自于英文单词“Humongous”&#xff0c;中文含义为“庞大” &#xff09;是可以应用于各种规模的企业、各个行业以及各类应用程序的开源数据库。基于分布式文件存储的数据库。由C语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。MongoD…

php 事件调度,PHP单元测试调度事件

如何在函数调用期间测试事件是否被调度&#xff1f;public function updateUser() {//Do some update stuff$event new UserUpdated($user);$event->attach([new SendEmailAddressChangeEmail($emailAddress),new SendEmailAddressChangeEmail($oldEmailAddress),]);$event…

学习Spring Boot:(二十一)使用 EhCache 实现数据缓存

前言 当多次查询数据库影响到系统性能的时候&#xff0c;可以考虑使用缓存&#xff0c;来解决数据访问新能的问题。 SpringBoot 已经为我们提供了自动配置多个 CacheManager 的实现&#xff0c;只要去实现使用它就可以了。 一般的系统都是优先使用 EhCache&#xff0c;它工作…