1.背景
在我们平时开发中需要向数据库存储 list 这种类型的数据,这种可以用关联表来做,也可以直接用json 类型的字段来存储,在这里我选择用json类型的字段来存储。因为关联数据太多会增加我们系统的复杂度,也会影响我们数据库的查询效率。
2. 如何用 mybaits plus 来实现
2.1 定义权限类
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.util.CollectionUtils;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/***
* className Permission
* date: 2021-08-18 12:19
* author: 杨兴
**/
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class Permission implements Serializable {
private static final long serialVersionUID = 7450078753438003785L;
private String code;
private String name;
private Set<Permission> children;
public Permission(String name, String code) {
this.name = name;
this.code = code;
}
public void addItem(Permission dto) {
if (children == null) {
children = new HashSet<>();
}
children.add(dto);
}
@JsonIgnore
public List<String> getPermissionStrings() {
List<String> permissions = new ArrayList<>();
permissions.add(code);
if (!CollectionUtils.isEmpty(getChildren())) {
permissions.addAll(getChildren().stream().map(Permission::getCode).collect(Collectors.toList()));
}
return permissions;
}
}
我设计的权限由权限码和权限标题组成,并且还有上下级关系,因此不能使用 mybatis plus 默认提供的转换器,因为它提供的转换器只支持 object的序列化
2.2 封装 Jackson工具类
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
public class JsonUtils {
private static ObjectMapper objectMapper = new ObjectMapper();
//初始化相关的配置
static {
//只引用不为空的值
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
//取消默认转换timestemp
objectMapper.configure(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS, false);
//忽略空bean转换错误
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
//忽略在json中存在,在java对象不存在的错误
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 解决jackson2无法反序列化LocalDateTime的问题
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
objectMapper.registerModule(new JavaTimeModule());
}
/**
* 将java对象转换成json字符串
*
* @param obj
* java 对象
* @param <T>
* @return
*/
public static <T> String objectToString(T obj) {
if (obj == null) {
return null;
}
try {
return obj instanceof String ? (String) obj : objectMapper.writeValueAsString(obj);
} catch (JsonProcessingException e) {
e.printStackTrace();
return null;
}
}
/**
* 将json字符串转换成java对象
*
* @param json
* 字符串
* @param tClass
* 要转换的对象
* @param <T>
* @return
*/
public static <T> T getObjetFormString(String json, Class<T> tClass) {
if (StringUtils.isBlank(json) || tClass == null) {
return null;
}
try {
return tClass.equals(String.class) ? (T) json : objectMapper.readValue(json, tClass);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
/**
* 将字符串转换成java对象
* @param json
* 字符串
* @param tTypeReference
* 对象
*
* @param <T>
* @return
*/
public static <T> T fromString(String json, TypeReference<T> tTypeReference){
if (StringUtils.isBlank(json) || tTypeReference == null) {
return null;
}
try {
return tTypeReference.getType().equals(String.class) ? (T) json : objectMapper.readValue(json, tTypeReference);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
/**
* 将json字符串转换成java集合对象
* @param json
* 字符串
* @param collectionClass
* 集合类型
* @param elementClazzes
* 成员类型
* @param <T>
* @return
*/
public static <T> T fromString(String json, Class<?> collectionClass, Class<?> ... elementClazzes){
JavaType javaType = objectMapper.getTypeFactory().constructParametricType(collectionClass, elementClazzes);
try {
return objectMapper.readValue(json, javaType);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
我的json序列化工具用的是jackson
2.3 定义 转换器
import com.baomidou.mybatisplus.extension.handlers.AbstractJsonTypeHandler;
import com.communal.common.utils.JsonUtils;
import com.comptroller.entities.Permission;
import org.apache.ibatis.type.MappedTypes;
import java.util.List;
@MappedTypes({List.class, Permission.class})
public class PermissionTypeHandler extends AbstractJsonTypeHandler<List<Permission>> {
@Override
protected List<Permission> parse(String json) {
return JsonUtils.fromString(json, List.class, Permission.class);
}
@Override
protected String toJson(List<Permission> obj) {
return JsonUtils.objectToString(obj);
}
}
2.4 使用转换器
@TableField(typeHandler = PermissionTypeHandler.class)
private List<Permission> permissions = new ArrayList<>();
注意: 在引用实体类上一定要加 @TableName(autoResultMap = true) 注解, 否则查询出来的结果会为 null