• 全栈之路-小程序API-Json数据类型的序列化与反序列化


      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}]"

    虽然前端也是可以处理的,但是后台我们进行序列化之后,再返回给前端不是更加友好吗?哈哈,真是贴心的后端开发者!!!
    2、最完美的返回形式
    "specs": [{"key_id": 1,"key": "颜色","value_id": 45, "value": "金属灰" },{"key_id": 3, "key": "图案","value_id": 9,"value": "七龙珠"},{"key_id": 4, "key": "尺码","value_id": 14,"value": "小号 S"}],
    这样的话,前端开发人员可以直接读取遍历出想要的数据

     二、单体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后端到全栈》视频课程

    七月老师课程链接:https://class.imooc.com/sale/javafullstack

  • 相关阅读:
    hiho#1445 重复旋律5 求子串数量 后缀自动机
    SPOJ LCS2 后缀自动机
    SPOJ-LCS 后缀自动机
    bzoj 3261 最大异或和 可持久化字典树(01树)
    【洛谷1297】单选错位
    【HAOI2008】木棍分割
    【SDOI2016】排列计数
    【HAOI2008】下落的圆盘
    【HAOI2008】硬币购物
    【洛谷5520】青原樱
  • 原文地址:https://www.cnblogs.com/ssh-html/p/12688172.html
Copyright © 2020-2023  润新知