在使用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
}
這樣,會不會很優雅,希望對后面的同學有幫助,有問題,請隨時留言!