MySQL中有一種新的數據結構,就是json格式,在使用springboot中進行數據的讀取的時候往往會將json類型的數據直接轉換成字符串類型的數據,對於頁面的數據的處理很不友好,如何來將json類型的數據序列化成List或者Map類型的,七月老師提供了一整套的代碼完成以及思考過程,記錄一下整個代碼的優化過程
一、為什么要對這個進行優化?
1、這塊主要涉及的是sku表中的specs字段,這個字段的意義在於可以准確的確定是哪一件商品,比如:我需要的是(顏色:暗夜綠色,版本:256G全網通)的iPhone 11 Pro手機,其中暗夜綠色,全網通的iPhone 11 Pro手機就是一條sku數據,暗夜綠色,全網通版本就是specs字段所存儲的內容,我們在數據庫中是以json字段進行存儲的,我們不做處理的話,返回給前端的就是json字符串,
例如:"specs": "[{\"key\": \"顏色\", \"value\": \"橘黃色\", \"key_id\": 1, \"value_id\": 44}, {\"key\": \"圖案\", \"value\": \"七龍珠\", \"key_id\": 3, \"value_id\": 9}, {\"key\": \"尺碼\", \"value\": \"小號 S\", \"key_id\": 4, \"value_id\": 14}]"
二、單體Json對象的映射處理
1、首先做一個單體Json對象與Map的轉換的工具類
注意:
(1)json序列化工具用的是jackson
(2)異常處理是拋出500錯誤,也就是服務器異常,做了一下異常處理的封裝(這里是把必須要處理的IO異常。轉換成RuntimeException)
(3)一定要加上@Converter注解
1 @Converter 2 public class MapAndJson implements AttributeConverter<Map<String, Object>, String> { 3 4 @Autowired 5 private ObjectMapper mapper; 6 7 @Override 8 public String convertToDatabaseColumn(Map<String, Object> stringObjectMap) { 9 try { 10 return mapper.writeValueAsString(stringObjectMap); 11 } catch (JsonProcessingException e) { 12 e.printStackTrace(); 13 throw new ServerErrorException(9999); 14 } 15 } 16 17 @Override 18 public Map<String, Object> convertToEntityAttribute(String s) { 19 try { 20 if (s == null) { 21 return null; 22 } 23 return mapper.readValue(s, HashMap.class); 24 } catch (JsonProcessingException e) { 25 e.printStackTrace(); 26 throw new ServerErrorException(9999); 27 } 28 } 29 }
2、轉換字段中使用
1 @Convert(converter = MapAndJson.class) 2 private Map<String, Object> test;
三、數組類型json與List的映射
1、首先做一個數組類型Json與List轉換的工具類
注意:這個工具類基本上和單體Json與Map映射很類似
1 @Converter 2 public class ListAndJson implements AttributeConverter<List<Object>, String> { 3 4 @Autowired 5 private ObjectMapper mapper; 6 7 @Override 8 public String convertToDatabaseColumn(List<Object> objects) { 9 try { 10 return mapper.writeValueAsString(objects); 11 } catch (JsonProcessingException e) { 12 e.printStackTrace(); 13 throw new ServerErrorException(9999); 14 } 15 } 16 17 @Override 18 public List<Object> convertToEntityAttribute(String s) { 19 try { 20 if (s == null) { 21 return null; 22 } 23 return mapper.readValue(s, List.class); 24 } catch (JsonProcessingException e) { 25 e.printStackTrace(); 26 throw new ServerErrorException(9999); 27 } 28 } 29 30 }
2、字段中使用
1 @Convert(converter = ListAndJson.class) 2 private List<Object> specs;
四、更優的解決方案
以上兩個方法存在的問題是:沒有辦法確定具體的業務對象,就是一個Map,或者是List<Object>,沒有辦法確定到底是哪種業務對象,就像我們這里所要的,我們想要的是List<Spec>這種具體的Spec的對象的集合,這樣的話,更加符合面向對象的思想,而且即使后面我們調用Spec具體對象中的業務方法的時候會更加方便,所以有必要做一個更加的優化方案!
1、創建一個通用的序列化反序列化工具類
注意:這里很不好理解的,只有對泛型比較熟悉,才能很容易理解,至於寫出這種代碼,我覺得目前還是寫不出來的
1 @Component 2 public class GenericAndJson { 3 4 private static ObjectMapper mapper; 5 6 // 這里用到的set方法的自動注入,實例化static變量 7 @Autowired 8 public void setMapper(ObjectMapper mapper) { 9 GenericAndJson.mapper = mapper; 10 } 11 12 public static <T> String objectToJson(T o) { 13 try { 14 return GenericAndJson.mapper.writeValueAsString(o); 15 } catch (JsonProcessingException e) { 16 e.printStackTrace(); 17 throw new ServerErrorException(9999); 18 } 19 } 20 21 public static <T> T jsonToObject(String s, TypeReference<T> tr) { 22 try { 23 if (s == null) { 24 return null; 25 } 26 return GenericAndJson.mapper.readValue(s, tr); 27 } catch (JsonProcessingException e) { 28 e.printStackTrace(); 29 throw new ServerErrorException(9999); 30 } 31 } 32 33 }
2、實際中使用
注意:需要重寫變量的set與get方法,來進行序列化與反序列化操作
1 private String specs; 2 3 public List<Spec> getSpecs() { 4 if(this.specs == null){ 5 return Collections.emptyList(); 6 } 7 return GenericAndJson.jsonToObject(this.specs, new TypeReference<List<Spec>>() { 8 }); 9 } 10 11 public void setSpecs(List<Spec> specs) { 12 if(specs.isEmpty()){ 13 return; 14 } 15 this.specs = GenericAndJson.objectToJson(specs); 16 }
內容出處:七月老師《從Java后端到全棧》視頻課程