這篇文章主要介紹Mybatis中怎么樣操作MySQL8的Json字段類型,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!
目前成都創(chuàng)新互聯(lián)公司已為上1000家的企業(yè)提供了網(wǎng)站建設(shè)、域名、虛擬空間、網(wǎng)站改版維護(hù)、企業(yè)網(wǎng)站設(shè)計(jì)、大足網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長(zhǎng),共同發(fā)展。
Json字段是從mysql 5.7起加進(jìn)來的全新的字段類型,現(xiàn)在我們看看在什么情況下使用該字段類型,以及用mybatis如何操作該字段類型
一般來說,在不知道字段的具體數(shù)量的時(shí)候,使用該字段是非常合適的,比如說——商品的無限屬性。
現(xiàn)在我們來假設(shè)這么一個(gè)場(chǎng)景,在商品的二級(jí)分類中給商品定義足夠多的屬性,我們先設(shè)計(jì)屬性的類
/** * 商品自定義屬性 */@NoArgsConstructor@AllArgsConstructorpublic class OtherProperty implements Serializable {@Getter @Setter private Long id; //屬性id @Getter @Setter private FormType formType; //前端使用的表單類型 @Getter @Setter private String name; //屬性名稱 @Getter @Setter private String unit; //單位 @Getter @Setter private String values; //可選值以@分隔,如配件@車品 @Getter private ListvalueList = new ArrayList<>(); //對(duì)可選值的取值列表 @Getter @Setter private String defaultValue; //可選值中的默認(rèn)值 @Getter @Setter private boolean search; //是否可搜索 @Getter @Setter private boolean mustWrite; //是否必錄 @Getter @Setter private Boolean used = false; //是否已經(jīng)在商品中使用,已使用該屬性則不允許修改 public OtherProperty changeValuesToList() { String[] split = this.values.split("@"); for (String value : split) {this.valueList.add(value); }this.values = null; return this; }@Override public boolean equals(Object o) {if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; OtherProperty that = (OtherProperty) o; if (!id.equals(that.id)) return false; if (search != that.search) return false; if (mustWrite != that.mustWrite) return false; if (formType != that.formType) return false; if (!name.equals(that.name)) return false; if (unit != null ? !unit.equals(that.unit) : that.unit != null) return false; if (values != null ? !values.equals(that.values) : that.values != null) return false; return defaultValue != null ? defaultValue.equals(that.defaultValue) : that.defaultValue == null; }@Override public int hashCode() {int result = id.hashCode() + formType.hashCode() + name.hashCode(); result = result + (unit != null ? unit.hashCode() : 0); result = result + (values != null ? values.hashCode() : 0); result = result + (defaultValue != null ? defaultValue.hashCode() : 0); result = result + (search ? 1 : 0); result = result + (mustWrite ? 1 : 0); return result; } }
其中formType為枚舉類型
public enum FormType implements Localisable {TYPE1("文本框"), TYPE2("下拉框"), TYPE3("單選框"), TYPE4("復(fù)選框"), TYPE5("多行文本框"); private String value; private FormType(String value) {this.value = value; }@Override public String getValue() {return this.value; } }
我們來看一下商品分類的部分代碼
@AllArgsConstructor@NoArgsConstructorpublic class ProviderProductLevel implements Provider,Serializable
其中包含一個(gè)商品屬性對(duì)象的列表
@Getter@Setterprivate ListotherProperties;
部分操作源碼如下
/** * 通過二級(jí)配件分類id查找其包含的所有其他屬性 * @param * @return */public ListfindOtherProperties() {if (this.level == 2) { LevelDao levelDao = SpringBootUtil.getBean(LevelDao.class); String ids = levelDao.findIdsByLevel2Id(this.id); return levelDao.findOtherProperties(ids); }return null;}/** * 在二級(jí)配件分類中刪除其他屬性的id * @param paramIds * @return */public boolean deletePropertyIdfromLevel(String paramIds) {if (this.level == 2) { LevelDao levelDao = SpringBootUtil.getBean(LevelDao.class); String ids = levelDao.findIdsByLevel2Id(this.id); String[] idsArray = ids.split(","); List idsList = Arrays.asList(idsArray); List contentIdsList = new ArrayList<>(); contentIdsList.addAll(idsList); String[] paramArray = paramIds.split(","); List paramList = Arrays.asList(paramArray); if (contentIdsList.containsAll(paramList)) { contentIdsList.removeAll(paramList); }if (contentIdsList.size() > 0) { StringBuilder builder = new StringBuilder(); contentIdsList.stream().forEach(eachId -> builder.append(eachId + ",")); String newIds = builder.toString().substring(0, builder.toString().length() - 1); levelDao.addOtherPropertiesToLevel(new ParamOtherPropertiesId(newIds, this.id)); }else { levelDao.addOtherPropertiesToLevel(new ParamOtherPropertiesId("",this.id)); }return true; }return false;}
/** * 展示某二級(jí)配件分類的所有其他屬性 * @param id * @return */@SuppressWarnings("unchecked")@Transactional@GetMapping("/productprovider-anon/showproperties")public Result> showOtherProperties(@RequestParam("id") Long id) { Provider level2 = levelDao.findLevel2(id); return Result.success(((ProviderProductLevel)level2).findOtherProperties());}/** * 修改某二級(jí)配件分類的其他屬性 * @param id * @param otherProperties * @return */@SuppressWarnings("unchecked")@Transactional@PostMapping("/productprovider-anon/changeother")public Result
changeOtherProperties(@RequestParam("id") Long id,@RequestBody List otherProperties) {//獲取配件二級(jí)分類對(duì)象 Provider level2 = levelDao.findLevel2(id); //獲取未使用的配件二級(jí)分類的其他屬性(沒有任何商品使用過該屬性) List unUsedList = Optional.ofNullable(((ProviderProductLevel) level2).getOtherProperties()).map(otherProperties1 -> otherProperties1.stream()) .orElse(new ArrayList ().stream()) .filter(otherProperty -> !otherProperty.getUsed()) .collect(Collectors.toList()); //獲取已使用的配件二級(jí)分類的其他屬性 List usedIdList = Optional.ofNullable(((ProviderProductLevel) level2).getOtherProperties()).map(otherProperties1 -> otherProperties1.stream()) .orElse(new ArrayList ().stream()) .filter(otherProperty -> otherProperty.getUsed()) .map(OtherProperty::getId) .collect(Collectors.toList()); //在傳遞回來的配件二級(jí)分類其他屬性中校對(duì)沒有修改過的,沒有使用過的其他屬性,只對(duì)修改過的,沒有使用過的其他屬性進(jìn)行 //存儲(chǔ),否則不處理 List changeList = otherProperties.stream().filter(otherProperty -> Optional.ofNullable(otherProperty.getId()).isPresent()) .filter(otherProperty -> !unUsedList.contains(otherProperty)) .filter(otherProperty -> !usedIdList.contains(otherProperty.getId())) .peek(otherProperty -> otherPropertyDao.deleteOtherPropertiesById(otherProperty.getId())) .collect(Collectors.toList()); if (changeList.size() > 0) { StringBuilder builder = new StringBuilder(); changeList.stream().map(OtherProperty::getId).forEach(eachId -> builder.append(eachId + ",")); String newIds = builder.toString().substring(0, builder.toString().length() - 1); ((ProviderProductLevel) level2).deletePropertyIdfromLevel(newIds); ((ProviderProductLevel) level2).addOtherProperties(changeList); }//獲取新增的其他屬性進(jìn)行追加到配件二級(jí)分類的其他屬性中 List newList = otherProperties.stream().filter(otherProperty -> !Optional.ofNullable(otherProperty.getId()).isPresent()) .peek(otherProperty -> otherProperty.setId(idService.genId())) .collect(Collectors.toList()); ((ProviderProductLevel) level2).addOtherProperties(newList); return Result.success("修改成功");}
在進(jìn)行一番增刪改查后,數(shù)據(jù)庫中的數(shù)據(jù)大致如下
我們查高級(jí)項(xiàng)鏈的所有屬性的結(jié)果如下
現(xiàn)在我們要在屬于該商品分類中添加商品,商品類定義大致如下
@Data@NoArgsConstructorpublic class ProviderProduct implements Provider { private Product product; //配件元信息對(duì)象 private String code; //配件編碼 private Brand brand; //品牌 private String details; //配件圖文說明 private String levelName; //二級(jí)配件分類名稱 private DefaultProvider provider; //配件商 private ExtBeanWrapper otherValues; //其他屬性集合 }
其中對(duì)應(yīng)于屬性列表的字段為otherValues,這個(gè)值正是我們要存入數(shù)據(jù)庫的Json字段類型映射。
商品的數(shù)據(jù)庫表結(jié)構(gòu)如下
要使用mybatis的數(shù)據(jù)對(duì)Json字段類型的轉(zhuǎn)換,可以先引用一個(gè)網(wǎng)上寫好的轉(zhuǎn)換器,當(dāng)然也可以自己寫
pom
com.github.jeffreyning extcol 0.0.1-RELEASE
配置文件中添加 type-handlers-package:com.nh.micro.ext.th
mybatis: type-aliases-package: com.cloud.model.productprovider type-handlers-package: com.nh.micro.ext.th mapper-locations: classpath:/mybatis-mappers/* configuration: mapUnderscoreToCamelCase: true
在mapper文件中寫入一段插入語句
insert into product (id,name,code,model,normal_price,price_begin,product_imgs,details,brand_id,other_property_value) values (#{product.id},#{product.name},#{code},#{product.model},#{product.price.normalPrice}, , #{product.productImgs}, #{details}, #{brand.id}, #{otherValues,jdbcType=VARCHAR} ) 1 0
對(duì)應(yīng)商品分類的每一個(gè)自定義屬性,我們可以先拿到該自定義屬性的id,然后以該id,取值為鍵值對(duì)進(jìn)行插入
{
"product":{
"name":"AAAA",
"model":"AAAAA",
"price":{
"normalPrice":199,
"begin":false
},
"productImgs":"http://123.433.567.988"
},
"code":"0001",
"details":"
執(zhí)行之后,數(shù)據(jù)庫的數(shù)據(jù)如下
該插件的數(shù)據(jù)類和轉(zhuǎn)換器的源碼如下,其實(shí)也是很簡(jiǎn)單的
public class ExtBeanWrapper { public ExtBeanWrapper() { }; public ExtBeanWrapper(Object entity) { this.setObj(entity); } private Map innerMap = new HashMap(); public Map getInnerMap() { return innerMap; } public void setInnerMap(Map innerMap) { this.innerMap = innerMap; } public void setObj(Object entity) { if (entity == null) { innerMap = null; } JSON jobj = (JSON) JSON.toJSON(entity); innerMap = JSON.toJavaObject(jobj, Map.class); } public Object getObj() { if (innerMap == null) { return null; } JSON jobj = (JSON) JSON.toJSON(innerMap); Map entity = JSON.toJavaObject(jobj, Map.class); return entity; } public Object getObj(Class targetClass) { if (innerMap == null) { return null; } JSON jobj = (JSON) JSON.toJSON(innerMap); Object entity = JSON.toJavaObject(jobj, targetClass); return entity; } }
MappedTypes(com.nh.micro.ext.ExtBeanWrapper.class)@MappedJdbcTypes(JdbcType.VARCHAR)public class TagToJsonTypeHandler extends BaseTypeHandler{ private Map jsonToMap(String value) { if (value == null || "".equals(value)) { return Collections.emptyMap(); } else { return JSON.parseObject(value, new TypeReference
現(xiàn)在我們來看一下如何將該Json字段從數(shù)據(jù)庫取出,還是以上面的案例為例,先在mapper文件中定義一組resultMap
這里稍微解釋一下,price里的begin是boolean類型,price_begin在數(shù)據(jù)庫中是整形,有一個(gè)轉(zhuǎn)換器,代碼如下
public class BoolIntTypeHandler extends BaseTypeHandler{@Override public void setNonNullParameter(PreparedStatement ps, int i, Boolean parameter, JdbcType jdbcType) throws SQLException { ps.setBoolean(i,parameter); }@Override public Boolean getNullableResult(ResultSet rs, String columnName) throws SQLException {int value = rs.getInt(columnName); if (rs.wasNull()) {return false; }else {if (value == 0) {return false; }else if (value == 1) {return true; } }return false; }@Override public Boolean getNullableResult(ResultSet rs, int columnIndex) throws SQLException {int value = rs.getInt(columnIndex); if (rs.wasNull()) {return false; }else {if (value == 0) {return false; }else if (value == 1) {return true; } }return false; }@Override public Boolean getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {int value = cs.getInt(columnIndex); if (cs.wasNull()) {return false; }else {if (value == 0) {return false; }else if (value == 1) {return true; } }return false; } }
品牌這里有一個(gè)查找
配件二級(jí)分類名稱
配件商信息
當(dāng)然我們的重點(diǎn)還是otherValues這里
獲取數(shù)據(jù)的全部select代碼如下
獲取出來的數(shù)據(jù)如下
{ "code": 200, "data": { "brand": { "code": "001", "id": 1, "logoUrl": "http://123.456.789", "name": "飛利浦", "sort": 1 }, "code": "0001", "levelName": "高級(jí)項(xiàng)鏈", "otherValues": { "innerMap": { "2459623566996411192": "國際", "2459623566996408120": "10", "2459623566996409144": "呼和浩特", "2459623566996410168": "飛利浦", "2459623566996412216": "包郵" }, "obj": { "2459623566996410168": "飛利浦", "2459623566996411192": "國際", "2459623566996408120": "10", "2459623566996409144": "呼和浩特", "2459623566996412216": "包郵" } }, "product": { "id": 2459722970793247544, "model": "AAAAA", "name": "AAAA", "onShelf": false, "price": { "begin": false, "normalPrice": 199 } }, "provider": { "code": "0001", "productProvider": { "id": 2459698718186668856, "name": "大眾4S店", "productList": [] }, "status": false } }, "msg": "操作成功" }
當(dāng)然我們這里要把其他屬性的id替換成用戶能看懂的其他屬性的名稱
@Overridepublic Provider findProduct(Long id) { ProductDao productDao = SpringBootUtil.getBean(ProductDao.class); OtherPropertyDao otherPropertyDao = SpringBootUtil.getBean(OtherPropertyDao.class); Provider product = productDao.findProductById(id); Map map = ((ProviderProduct) product).getOtherValues().getInnerMap(); MapinsteadMap = new HashMap<>(); for (Object key : map.keySet()) {log.info("鍵名為:" + String.valueOf(key)); String name = otherPropertyDao.findNameById(Long.parseLong(String.valueOf(key))); insteadMap.put(name,(String) map.get(key)); } ((ProviderProduct) product).getOtherValues().setObj(insteadMap); return product;}
最后我們獲取的結(jié)果為
{ "code": 200, "data": { "brand": { "code": "001", "id": 1, "logoUrl": "http://123.456.789", "name": "飛利浦", "sort": 1 }, "code": "0001", "levelName": "高級(jí)項(xiàng)鏈", "otherValues": { "innerMap": { "商品等級(jí)": "國際", "運(yùn)費(fèi)設(shè)置": "包郵", "生產(chǎn)廠家": "飛利浦", "包裝規(guī)格": "10", "商品產(chǎn)地": "呼和浩特" }, "obj": { "$ref": "$.data.otherValues.innerMap" } }, "product": { "id": 2459722970793247544, "model": "AAAAA", "name": "AAAA", "onShelf": false, "price": { "begin": false, "normalPrice": 199 } }, "provider": { "code": "0001", "productProvider": { "id": 2459698718186668856, "name": "大眾4S店", "productList": [] }, "status": false } }, "msg": "操作成功" }
以上是“Mybatis中怎么樣操作mysql8的Json字段類型”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!