假设一个场景:一个用户可以有多个角色,用户列表需要显示用户所有的角色名称,如下表
ID | 名称 | 角色 |
1 | 张三 | 管理员、审核员 |
2 | 李四 | 普通员工 |
那么我们可以设计三个表:user(用户表) role(角色表) user_role(用户角色表)
第一种方法就是使用mybatis的association标签关联,但这个方法,有多少条用户记录,就要多少次的子查询来关联角色信息,所以不推荐使用
第二种方法,使用GROUP_CONTACT和JSON_OBJECT把角色列表的数据封装成一个json数组,再使用TypeHandler解析成一个List
Mapper.xml如下:
其中,关键的语句是:
CASE WHEN max(r.id) is not null THEN CONCAT('[',GROUP_CONCAT(JSON_OBJECT('id',r.id,'roleName',r.role_name)),']') END roles
result中的javaType也不能少
TypeHandler如下:
package com.exapmle.common.mybatis.handler;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class JsonTypeHandler implements TypeHandler {
private Class type;
public JsonTypeHandler(Class type) {
if (type == null) {
throw new IllegalArgumentException("Type argument cannot be null");
}
// 拿到xml中配置的javaType
this.type = type;
}
@Override
public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, parseJsonString(parameter));
}
@Override
public T getResult(ResultSet rs, String columnName) throws SQLException {
return parseJavaObject(rs.getString(columnName));
}
@Override
public T getResult(ResultSet rs, int columnIndex) throws SQLException {
return parseJavaObject(rs.getString(columnIndex));
}
@Override
public T getResult(CallableStatement cs, int columnIndex) throws SQLException {
return parseJavaObject(cs.getString(columnIndex));
}
private String parseJsonString(T parameter) {
if (parameter == null) {
return null;
}
return JSON.toJSONString(parameter, SerializerFeature.WriteClassName,SerializerFeature.NotWriteRootClassName);
}
@SuppressWarnings("unchecked")
private T parseJavaObject(String parameter) {
if (parameter == null) {
return null;
}
if (parameter.startsWith("[")) {
return (T) JSON.parseArray(parameter, this.type);
}
return JSON.parseObject(parameter, this.type);
}
}