在使用mysql5.7或更高版本时,json类型字段应用场景越来越多,对于普通的对象或者List<Integer>、List<String>这些基础类型,jacksonTypeHandler都能很好的处理,如下:
1、定义一个person对象
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;@Data
public class Person {@JsonProperty("id")private Long id;@JsonProperty("name")private String name;@JsonProperty("age")private Integer age;
}
2、定义映射关系
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.Data;@Data
@TableName(value = "your_table", autoResultMap = true)
public class YourEntity {private Long id;// JSON 字段映射为 Person 对象@TableField(typeHandler = JacksonTypeHandler.class)private Person person;// JSON 字段映射为 List<String>@TableField(typeHandler = JacksonTypeHandler.class)private List<String> stringList;
}
通过上述两步,基本就可以解决json字段的处理,但json字段是一个列表,如List<Person>对象,上面的代码是有问题的,因为Jackson 在反序列化时,需要明确的目标类型信息来正确地将 JSON 数据映射到 Java 对象。如果没有明确的类型信息,Jackson 默认会将 JSON 数组解析为 List<LinkedHashMap>
,因为 LinkedHashMap
是 Jackson 默认的 Map 类型。下面就是我们给出的解决方案:
1、创建一个自定义类的注解JsonType
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface JsonType {Class<?> value();
}
2、创建一个通过的ListTypeHandler的实现类
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.ibatis.type.BaseTypeHandler;
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 JsonListTypeHandler extends BaseTypeHandler<Object> {private final ObjectMapper objectMapper = new ObjectMapper();@Overridepublic void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {try {ps.setString(i, objectMapper.writeValueAsString(parameter));} catch (Exception e) {throw new RuntimeException("Failed to serialize JSON", e);}}@Overridepublic Object getNullableResult(ResultSet rs, String columnName) throws SQLException {String json = rs.getString(columnName);return parseJson(json);}@Overridepublic Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException {String json = rs.getString(columnIndex);return parseJson(json);}@Overridepublic Object getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {String json = cs.getString(columnIndex);return parseJson(json);}private Object parseJson(String json) {if (json == null || json.trim().isEmpty()) {return null;}try {// 获取字段的类型信息JsonType jsonType = field.getAnnotation(JsonType.class);if (jsonType != null) {return objectMapper.readValue(json, objectMapper.getTypeFactory().constructCollectionType(List.class, jsonType.value()));}return objectMapper.readValue(json, Object.class);} catch (Exception e) {throw new RuntimeException("Failed to parse JSON", e);}}
}
3,接下来,你就可以使用它了
@TableName(autoResultMap = true)
public class YourEntity {private Long id;@TableField(typeHandler = JsonListTypeHandler.class)@JsonType(Person.class)private List<Person> personList;// Getters and Setters
}
这样,会不会很优雅,希望对后面的同学有帮助,有问题,请随时留言!