把 mysql 总 string 转换成 list
一、需求描述
首先说明需求,有三张表:
学生
学生表、角色表、以及一张关联的中间表。
角色
学生可以有多个角色,但是这多个角色我是作为多条记录存储在另外一张表中的,现在想将这多条记录查询出来,注入到Student
对象中的一个List
属性中去。
即最后的Student
对象结果应该长这样:
1
|
;[{ id: 1, name: '硕子鸽', roles: ['物理课代表', '数学课代表'] }]
|
总之就是要将 1,2,3
或者 1 2 3
转换为 Java 中的 List = [1,2,3]。
我可以在Service
层中做两次查询然后分别注入,但是为了优雅一点,我想只使用持久层框架就解决这个问题。
二、实现方案
这边了解到Mybatis
框架中提供了一个类型转换器,我可以实现该接口来完成自定义类型转换。这个抽象类为BaseTypeHandler
。
首先我需要写个SQL
将想要的数据查询出来,然后再考虑类型转换。
查询的语句为:
1
|
SELECT stu.*, (SELECT group_concat(r.role_name) AS roles FROM stud_role sr left join role r on sr.role_id = r.role_id WHERE sr.stu_id = stu.id) AS roles FROM student stu;
|
这段SQL
的查询结果如下,含义是把该学生信息、以及该学生所属的角色拼接成字符串作为一个字段查出来。
其中group_concat
是Mysql
中的函数,在Oracle
中请使用wmsys.wm_concat
以达到同样的效果。
查询结果
然后就是类型转换了。
实现BaseTypeHandler
抽象类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
package com.shuo.mpth.handler;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import org.springframework.util.StringUtils;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
/**
* @author : wshuo
* @date : 2023/1/11 15:59
*/
@MappedJdbcTypes(JdbcType.VARCHAR)
@MappedTypes({List.class})
public class ListTypeHandler extends BaseTypeHandler<List<String>> {
private static final String DELIM = ",";
@Override
public void setNonNullParameter(PreparedStatement preparedStatement, int i, List<String> strings, JdbcType jdbcType) throws SQLException {
String value = StringUtils.collectionToDelimitedString(strings, DELIM);
preparedStatement.setString(i, value);
}
@Override
public List<String> getNullableResult(ResultSet resultSet, String s) throws SQLException {
String value = resultSet.getString(s);
return Arrays.asList(StringUtils.tokenizeToStringArray(value, DELIM));
}
@Override
public List<String> getNullableResult(ResultSet resultSet, int i) throws SQLException {
String value = resultSet.getString(i);
return Arrays.asList(StringUtils.tokenizeToStringArray(value, DELIM));
}
@Override
public List<String> getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
String value = callableStatement.getString(i);
return Arrays.asList(StringUtils.tokenizeToStringArray(value, DELIM));
}
}
|
- @MappedJdbcTypes:表示
SQL
语句中查出来的类型;
- @MappedTypes:表示要转成 Java 对象的类型;
- DELIM:表示字符串的分隔符,如果你是用空格分开的就赋值为空格。
这知识第一步,下面我们需要在指定的地方使用它,这里我直接使用 @TableField
注解指定待转换字段。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
@Data
public class Student {
/**
* 学生ID
*/
private Integer id;
/**
* 学生姓名
*/
private String name;
/**
* 该学生所具备的角色
*/
@TableField(typeHandler = ListTypeHandler.class)
private List<String> roles;
}
|
如果没有使用 mybatis-plus ,使用的是 mybatis 的 xml 配置,则在 property 标签里增加typeHandler
属性是一样的效果。
最后我们还需要在 yml
配置文件中增加一段配置:
1
2
3
4
5
6
|
mybatis-plus:
mapper-locations: classpath*:mapper/*.xml
type-aliases-package: com.shuo.mpth.**.entity
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
type-handlers-package: com.shuo.mpth.handler
|
- type-handlers-package:指定
handler
的包名。
随即启动项目,请求接口,发现已经完成类型的转换: