第十五章:mybatis-plus 字段和类转换(TypeHandler)

本文介绍如何在MyBatis Plus中实现自定义类型转换,通过定义WorkInfoTypeHandler处理类,完成User表中work_info字段的序列化与反序列化过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在实际的业务开发过程中,部分类会有类对像成员,但是在DB保存时只是一个段,以一定的字符串形保存,比如以下USER表中work_info以以下形式保存

而实际的User类如下

public class User extends Model<User> {

private Long id;

@TableId(type = IdType.ASSIGN_UUID)

private String specid;

private String name;

private Integer age;

private String email;

private WorkInfo workInfo;

private int deleted;

@TableField(fill = FieldFill.INSERT_UPDATE)

private LocalDateTime createtime;

@Version

private long version;

private String fab;

}

其中workInfo类如下

@Data

public class WorkInfo {

private String title;

private String Company;

private String adrees;

}

这时从DB取数据时就会涉及如何转换成WorkInfo类。

以Mybatis中提供了BaseTypeHandler这个类形式类型自动转换,下面我们看看在mybatis-plus中如何进行?

1.在User类增加相关注解

@Data

@TableName(autoResultMap = true)

public class User extends Model<User> {

private Long id;

@TableId(type = IdType.ASSIGN_UUID)

private String specid;

private String name;

private Integer age;

private String email;

@TableField(value = "work_info",typeHandler = WorkInfoTypeHandler.class)

private WorkInfo workInfo;

private int deleted;

@TableField(fill = FieldFill.INSERT_UPDATE)

private LocalDateTime createtime;

@Version

private long version;

private String fab;

}

2.准备类WorkInfoTypeHandler继承BaseTypeHandler

public class WorkInfoTypeHandler extends BaseTypeHandler<WorkInfo> {

private String ObjectToString(WorkInfo workInfo) throws Exception

{

System.out.println("String ObjectToString");

String s="";

Field[] fields=workInfo.getClass().getDeclaredFields();

System.out.println(fields.length);

for(Field field:fields){

field.setAccessible(true);

if(s.length()>0)

s=s+",";

s+=field.getName()+"="+field.get(workInfo).toString();

}

return s;

}

private WorkInfo StringToObject(String workInfo) {

System.out.println("WorkInfo StringToObject");

String[] objectValues=workInfo.split(",");

WorkInfo workInfo1=new WorkInfo();

Field[] fields=workInfo1.getClass().getDeclaredFields();

for(String objectValue :objectValues) {

String[] filedValue = objectValue.split("=");

for (Field field : fields) {

if (field.getName().equals(filedValue[0])) {

field.setAccessible(true);

try {

field.set(workInfo1, filedValue[1]);

} catch (IllegalAccessException e) {

e.printStackTrace();

try {

field.set(workInfo1, null);

} catch (Exception ex) {

ex.printStackTrace();

}

}

}

}

}

return workInfo1;

}

@Override

public void setNonNullParameter(PreparedStatement preparedStatement, int i, WorkInfo workInfo, JdbcType jdbcType) throws SQLException {

System.out.println("setNonNullParameter");

try {

preparedStatement.setString(i, this.ObjectToString(workInfo));

} catch (Exception exception){

exception.printStackTrace();

}

}

@Override

public WorkInfo getNullableResult(ResultSet resultSet, String s) throws SQLException {

System.out.println("getNullableResult String s ");

WorkInfo workInfo=this.StringToObject(resultSet.getString(s));

return workInfo;

}

@Override

public WorkInfo getNullableResult(ResultSet resultSet, int i) throws SQLException {

System.out.println("getNullableResult int i ");

WorkInfo workInfo=this.StringToObject(resultSet.getString(i));

return workInfo;

}

@Override

public WorkInfo getNullableResult(CallableStatement callableStatement, int i) throws SQLException {

System.out.println("getNullableResult CallableStatement ");

WorkInfo workInfo=this.StringToObject(callableStatement.getString(i));

return workInfo;

}

}

3.插入数据测试方法

@Test

public void testSave(){

for(long i=34;i<35;i++) {

User user = new User();

user.setId(400+i);

user.setAge((int)i+30);

user.setEmail("zoulinlin"+i+"@163.com");

user.setName("zouli"+i);

WorkInfo workInfo=new WorkInfo();

workInfo.setAdrees("suzhou");

workInfo.setCompany("build fuck");

workInfo.setTitle("ceo");

user.setWorkInfo(workInfo);

int row = userMapper.insert(user);

System.out.println(row);

}

}

运行log(可以看出在向数据库保存进行了转换):

2022-10-12 18:33:00.034 DEBUG 12076 --- [ main] c.m.service.mapper.UserMapper.insert : ==> Preparing: INSERT INTO user (specid, id, name, age, email, work_info, deleted, createtime, version, FAB) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 'FAB1')

setNonNullParameter

String ObjectToString

3

2022-10-12 18:33:00.088 DEBUG 12076 --- [ main] c.m.service.mapper.UserMapper.insert : ==> Parameters: lot-20221012183257(String), 434(Long), zouli34(String), 64(Integer), zoulinlin34@163.com(String), title=ceo,Company=build fuck,adrees=suzhou(String), 0(Integer), 2022-10-12T18:32:57.180(LocalDateTime), 0(Long)

Consume Time:151 ms 2022-10-12 18:33:00

Execute SQL:INSERT INTO user (specid, id, name, age, email, work_info, deleted, createtime, version, FAB) VALUES ('lot-20221012183257', 434, 'zouli34', 64, 'zoulinlin34@163.com', 'title=ceo,Company=build fuck,adrees=suzhou', 0, '2022-10-12T18:32:57.180', 0, 'FAB1')

4.数据查询测试方法

@Test

public void testQuery(){

HashMap<String,Object> hashMap=new HashMap<String,Object>();

//hashMap.put("name","jack");

hashMap.put("id",434);

List<User> users= userMapper.selectByMap(hashMap);

users.forEach(System.out::println);

}

运行log(可以看出从数据库取数据时进行了转换):

2022-10-12 18:35:50.920 DEBUG 18236 --- [ main] c.m.s.mapper.UserMapper.selectByMap : ==> Preparing: SELECT specid, id, name, age, email, work_info, deleted, createtime, version, fab FROM user WHERE id = ? AND deleted = 0 AND user.FAB = 'FAB1'

2022-10-12 18:35:50.956 DEBUG 18236 --- [ main] c.m.s.mapper.UserMapper.selectByMap : ==> Parameters: 434(Integer)

Consume Time:13 ms 2022-10-12 18:35:50

Execute SQL:SELECT specid, id, name, age, email, work_info, deleted, createtime, version, fab FROM user WHERE id = 434 AND deleted = 0 AND user.FAB = 'FAB1'

getNullableResult String s

WorkInfo StringToObject

2022-10-12 18:35:50.994 DEBUG 18236 --- [ main] c.m.s.mapper.UserMapper.selectByMap : <== Total: 1

User(id=434, specid=lot-20221012183257, name=zouli34, age=64, email=zoulinlin34@163.com, workInfo=WorkInfo(title=ceo, Company=build fuck, adrees=suzhou), deleted=0, createtime=2022-10-12T18:32:57, version=0, fab=FAB1)

以上实例是告知怎么来实现,其实mybatis-plus提供了转jason格式的typehandler,如果想按照自已格式来进行需要按照以上方法来自行定义新类

public class FastjsonTypeHandler extends AbstractJsonTypeHandler<Object>

public class GsonTypeHandler extends AbstractJsonTypeHandler<Object>

public class JacksonTypeHandler extends AbstractJsonTypeHandler<Object>

<think>我们正在讨论MyBatis-Plus中配置TypeHandler时使用别名的问题。根据用户的问题,我们需要指导如何在MyBatis-Plus中为TypeHandler配置别名。在MyBatis中,TypeHandler用于处理Java类型JDBC类型之间的转换。有时,我们可能希望为自定义的TypeHandler设置一个别名,以便在映射文件中方便地引用。在MyBatis-Plus中,我们可以通过多种方式配置TypeHandler,其中使用别名的方式与Mybatis类似。步骤:1.自定义TypeHandler:首先需要编写自己的TypeHandler,实现MybatisTypeHandler接口或继承BaseTypeHandler。2.为TypeHandler设置别名:在Mybatis的配置中,我们可以通过类型别名(typeAliases)来为TypeHandler设置别名。3.在映射文件中使用别名:在定义ResultMap或参数映射时,使用别名来引用TypeHandler。但是,在MyBatis-Plus中,我们通常使用注解配置,也可以使用XML配置。参考引用[1]中提到了配置mybatis-config.xml,因此我们可以考虑在mybatis-config.xml中配置别名。示例:步骤1:自定义TypeHandler例如,我们有一个自定义的TypeHandler用于处理List类型:```javapublic classListTypeHandler extendsBaseTypeHandler<List<String>>{//实现方法}```步骤2:在mybatis-config.xml中配置别名在<typeAliases>标签下,为TypeHandler设置别名: ```xml<typeAliases><!--其他别名配置--><typeAliastype="com.example.handler.ListTypeHandler"alias="ListTypeHandler"/></typeAliases> ```步骤3:在映射文件中使用在ResultMap中指定某个列使用这个TypeHandler:```xml<result column="tags" property="tags" typeHandler="ListTypeHandler"/>```另外,MyBatis-Plus也支持通过注解来配置TypeHandler。在实体类的字段上使用@TableField注解指定typeHandler: ```java@TableField(typeHandler =ListTypeHandler.class) privateList<String> tags; ```但是,这里直接使用了类名,并没有使用别名。那么,如果我们想用别名怎么办?实际上,在注解中不能直接使用别名,而是必须使用Class对象。因此,在注解方式下,我们无法使用别名。所以,使用别名主要是在XML映射文件中使用。另外,我们还可以在MyBatis-Plus的全局配置中通过配置typeHandler来注册,但这并不是别名的方式。注意:在MyBatis中,我们还可以通过扫描包的方式来注册TypeHandler,这样就不需要为每个TypeHandler单独配置别名。但是,如果我们需要在XML中引用,那么别名可以简化配置。总结:1.在XML配置中使用别名:在mybatis-config.xml中配置别名,然后在XML映射文件中使用别名引用TypeHandler。2.在注解方式下,无法使用别名,只能直接指定TypeHandler的类。因此,如果用户需要在XML映射文件中使用简短的别名来引用TypeHandler,可以按照上述步骤配置。参考引用[4]中提到了数据库连接的配置,虽然不直接相关,但提醒我们在配置数据库连接时要注意细节。生成相关问题:1.如何在MyBatis-Plus中自定义TypeHandler?2. MyBatis-Plus中如何配置全局的TypeHandler?3.在MyBatis-Plus中,如何通过注解方式指定TypeHandler?4.使用TypeHandler时,如何解决数据库时区问题(如引用[4]中提到的时区问题)?注意:用户的问题集中在“别名”的使用上,因此我们主要解答别名配置的方法。</think>### MyBatis-Plus 中配置 TypeHandler 使用别名的方法 在 MyBatis-Plus 中,通过别名配置 TypeHandler 需要以下步骤: #### 1. **自定义 TypeHandler** 首先创建自定义 TypeHandler 类(以处理 List<String> 类型为例): ```java public class ListTypeHandler extends BaseTypeHandler<List<String>> { @Override public void setNonNullParameter(...) { // 实现JDBC参数设置逻辑 } @Override public List<String> getNullableResult(...) { // 实现结果集转换逻辑 } } ``` #### 2. **配置别名(关键步骤)** 在 `mybatis-config.xml` 中注册别名: ```xml <typeAliases> <!--TypeHandler设置别名 --> <typeAlias type="com.example.handler.ListTypeHandler" alias="ListHandler"/> </typeAliases> ``` #### 3. **在映射中使用别名** ##### 方式1:XML 映射文件 ```xml <resultMap id="userMap" type="User"> <result column="tags" property="tags" typeHandler="ListHandler"/> </resultMap> ``` ##### 方式2:注解方式(需结合 XML 别名) ```java public class User { @TableField(typeHandler = ListHandler.class) // 使用别名 private List<String> tags; } ``` #### 4. **全局配置(可选)** 在 MyBatis-Plus 配置类中全局注册: ```java @Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 添加其他拦截器... return interceptor; } // 注册TypeHandler @Bean public ConfigurationCustomizer configurationCustomizer() { return configuration -> { configuration.getTypeHandlerRegistry().register(ListHandler.class); // 使用别名 }; } } ``` #### 注意事项: 1. **别名作用域** 别名仅在 MyBatis 配置文件作用域内有效,需确保别名在 `mybatis-config.xml` 中正确定义[^1]。 2. **依赖冲突** 如遇 `ClassNotFoundException`,检查是否缺少 `mybatis-typehandlers-jsr310` 等依赖(类似引用[3]中的依赖问题)。 3. **JDBC 参数** 数据库连接需正确配置参数,如 MySQL 时区设置(参考引用[4]): ```properties spring.datasource.url=jdbc:mysql:///db?serverTimezone=Asia/Shanghai ``` 4. **优先级规则** - 字段注解 > XML 映射 > 全局注册 - 自定义 TypeHandler 优先于内置处理器 > **最佳实践**:对于复杂类型处理,建议结合 `@MappedTypes` `@MappedJdbcTypes` 注解声明处理器作用范围,减少显式配置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值