# json_operator **Repository Path**: nonoy/json_operator ## Basic Information - **Project Name**: json_operator - **Description**: 在springboot中使用了gson来完成json的dao与vo对象间的序列化操作 - **Primary Language**: Java - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-06-03 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README - [ json_operator](#head1) - [ 一、环境准备](#head2) - [ 二、项目结构](#head3) - [ 三、模型结构说明](#head4) - [ 四、测试样例](#head5) - [测试一 :使用org.springframework.beans.BeanUtils ](#head6) - [ 测试二:使用Gson注解,排除不需要序列化的属性](#head7) - [测试三:在springboot 服务中使用 Gson](#head8) - [ 测试四:Gson序列化复杂嵌套对象](#head9) - [ 测试五:Gson自定义排除策略](#head10) - [ 五、引用参考](#head11) # json_operator 使用gson和beanutils工具进行了对象转换以及序列化为json时字段的切割。 #### 一、环境准备 | 框架 | 版本 | | ---------- | ----------------------- | | springboot | 2.x | | junit | 4.x | | gson | 2.8(springboot自动配置) | pom.xml 中依赖: ```xml org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-json org.springframework.boot spring-boot-devtools runtime true org.springframework.boot spring-boot-starter-test test org.junit.vintage junit-vintage-engine com.google.code.gson gson ``` ------ #### 二、项目结构 ```xml com.example.demo:. │ DemoApplication.java //web程序运行入口 │ ├─config │ GsonConfig.java //gson框架与springboot 整合配置 │ ├─controller │ TestController.java //web请求处理方法 │ └─model // 模型文件 │ AbstractBaseModel.java //公共父类,提供测试使用的公共方法 │ BaseModel.java //所有模型的标记接口 │ ├─dao │ PersonDao.java //持久层模型 │ └─vo PersonVo.java //显示层模型 ``` ------ #### 三、模型结构说明 Person模型中的属性: | 属性名 | 类型 | 视图层是否显示 | | --------------- | ------------- | -------------- | | num | long | True | | name | String | True | | age | int | True | | data | List | True | | invisibleString | String | **False** | | invisiableMap | Map | **False** | ------ #### 四、测试样例 ###### 测试一 :使用org.springframework.beans.BeanUtils ```java @Test void test1(){ //设置dao对象 PersonDao dao = new PersonDao(); dao.setNum(1000); dao.setName("厚盾"); dao.setAge(25); dao.setData(new ArrayList<>(Arrays.asList(1,2,3))); dao.setInvisibleString("不可见"); dao.setInvisiableMap(new HashMap<>()); System.out.println("dao所有属性:"+dao.toString()); //dao --> vo PersonVo vo = new PersonVo(); BeanUtils.copyProperties(dao,vo); System.out.println("dao 转化为 vo 后:"+vo.getJson()); } ``` *运行结果*: > dao所有属性:PersonDao{num=1000, name='厚盾', age=25, invisibleString='不可见', invisiableMap={}} > dao 转化为 vo 后:{"num":1000,"name":"厚盾","age":25} ###### 测试二:使用Gson注解,排除不需要序列化的属性 ​ 1. ***`@Expose`*** 注解使用说明: ```java @Expose 注解用来标记属性是否需要序列化,相关参数: serialize 默认为true 表示需要序列化 deserialize 默认为true 表示需要反序列化 ----------------------------------------------------------------------------------------- //使用 @Expose注解时需要通过 Gson 工厂类来创建对象 GsonBuilder builder = new GsonBuilder(); //开启使用@Expose注解 builder.excludeFieldsWithoutExposeAnnotation(); Gson gson = builder.create(); ``` ​ 2.personDao代码(get/set等省略): ```java public class PersonDao extends AbstractBaseModel implements Serializable { /** * 编号 */ @Expose(serialize = true,deserialize = true) private long num; /** * 姓名 */ @Expose(serialize = true,deserialize = true) private String name; /** * 年龄 */ @Expose(serialize = true,deserialize = true) private int age; /** *测试集合类的显示 */ @Expose(serialize = true,deserialize = true) private List data; /** * 不需要展示给前台的数据1 */ @Expose(serialize = false) private String invisibleString; /** * 不需要给前台展示的数据2 */ @Expose(serialize = false) private Map invisiableMap; } ``` 3. 测试代码: ```java @Test @Test void test2() { //生成dao PersonDao dao = new PersonDao(); dao.setNum(1000); dao.setName("厚盾"); dao.setAge(25); dao.setData(new ArrayList<>(Arrays.asList(1,2,3))); dao.setInvisibleString("不可见"); dao.setInvisiableMap(new HashMap<>()); //使用gson 序列化为json GsonBuilder builder = new GsonBuilder(); builder.excludeFieldsWithoutExposeAnnotation(); Gson gson = builder.create(); System.out.println("dao属性:"+dao.toString()); String json = gson.toJson(dao); System.out.println("序列化后属性: "+json); } ``` 测试结果: > ​ dao属性:PersonDao{num=1000, name='厚盾', age=25, invisibleString='不可见', invisiableMap={}} > > ​ 序列化后属性: {"num":1000,"name":"厚盾","age":25,"data":[1,2,3]} ###### 测试三:在springboot 服务中使用 Gson - 配置 springboot 配置: ``` #server的配置 server.context-path=/ server.port=8080 ``` ​ 为了使用gson进行json消息的处理 ,需要做到以下工作: 1. 排除springboot-web自带的jackson框架 ```xml org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-json ``` 2. 将Gson注册为消息处理器(HttpMessageConverter) 在springboot2.x中,官方已经为我们准备好了GsonHttpMessageConverter,我们只需要重新配置HttpMessageConverters即可实现。这里采用springboot 推荐的java代码配置方式: ```java @Configuration public class GsonConfig { @Bean public Gson getgson(){ return new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); } @Bean public HttpMessageConverters gsonConverter(Gson gson){ Collection> messageConverters = new ArrayList<>(); GsonHttpMessageConverter gsonHttpMessageConverter = new GsonHttpMessageConverter(gson); messageConverters.add(gsonHttpMessageConverter); //将Gson作为消息处理器放置于默认处理器链之后 return new HttpMessageConverters(true, messageConverters); } } ``` 到这里 ,Gson就已经配置好了 - 编写controller ```java @RestController @RequestMapping("test") public class TestController { @GetMapping("/info") public BaseModel input(HttpServletRequest req){ PersonDao dao = new PersonDao(); dao.setNum(1000); dao.setName("厚盾"); dao.setAge(25); dao.setData(new ArrayList<>(Arrays.asList(1,2,3))); dao.setInvisibleString("不可见"); dao.setInvisiableMap(new HashMap<>()); System.out.println(dao.toString()); return dao; }; } ``` 最后开启服务器,访问:http://localhost:8080/test/info 测试结果: web端: ``` {"num":1000,"name":"厚盾","age":25,"data":[1,2,3]} ``` dao对象: ``` PersonDao{num=1000, name='厚盾', age=25, invisibleString='不可见', invisiableMap={}} ``` ###### 测试四:Gson序列化复杂嵌套对象 新增一个Father类,并将PersonDao作为成员变量,放入List中 ```java public class Father { @Expose private int id; @Expose private String address; @Expose private double count; @Expose private List daoList; } ``` controller新增一个映射方法: ```java @GetMapping("/contain") public BaseModel input2(HttpServletRequest req){ //生成元素 PersonDao dao1 = new PersonDao(); dao1.setNum(1000); dao1.setName("厚盾"); dao1.setAge(25); dao1.setData(new ArrayList<>(Arrays.asList(1,2,3))); dao1.setInvisibleString("不可见"); dao1.setInvisiableMap(new HashMap<>()); PersonDao dao2 = new PersonDao(); dao2.setNum(1000); dao2.setName("厚盾2"); dao2.setAge(252); dao2.setData(new ArrayList<>(Arrays.asList(4,5,6))); dao2.setInvisibleString("不可见"); dao2.setInvisiableMap(new HashMap<>()); System.out.println(dao1.toString()); Father f = new Father(); f.setId(1); f.setAddress("杭州"); f.setCount(10.001); f.setDaoList(new ArrayList<>(Arrays.asList(dao1,dao2))); return f; }; ``` 测试结果: ​ web端: ```json { "id": 1, "address": "杭州", "count": 10.001, "daoList": [ { "num": 1000, "name": "厚盾", "age": 25, "data": [ 1, 2, 3 ] }, { "num": 1000, "name": "厚盾2", "age": 252, "data": [ 4, 5, 6 ] } ] } ``` ​ father属性打印: ``` Father{id=1, address='杭州', count=10.001, daoList=[PersonDao{num=1000, name='厚盾', age=25, invisibleString='不可见', invisiableMap={}}, PersonDao{num=1000, name='厚盾2', age=252, invisibleString='不可见', invisiableMap={}}]} ``` ###### 测试五:Gson自定义排除策略 ​ 当 ***`@Expose`*** 不能满足需求时我们可以通过实现 *ExclusionStrategy* 接口,并通过工厂类注册,来自定义排除策略。 *ExclusionStrategy* 接口: ```java public interface ExclusionStrategy { /** * @param f the field object that is under test * @return true if the field should be ignored; otherwise false */ public boolean shouldSkipField(FieldAttributes f); /** * @param clazz the class object that is under test * @return true if the class should be ignored; otherwise false */ public boolean shouldSkipClass(Class clazz); } ``` 接下来进行测试: 1. 新建注解类 Invisible 用来标记需排除的属性: ```java /** * 标记注解,作用于属性上则本属性在序列化为json时被排除 */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD}) public @interface Invisible { } ``` 2. 在PersonDao类中添加 注解 ***`@invisible`*** ,这里我们将 num 属性标记为排除 : ```java public class PersonDao extends AbstractBaseModel implements Serializable { /** * 编号 */ @Invisible @Expose(serialize = true,deserialize = true) private long num; /** * 姓名 */ @Expose(serialize = true,deserialize = true) private String name; /** * 年龄 */ @Expose(serialize = true,deserialize = true) private int age; /** *测试集合类的显示 */ @Expose(serialize = true,deserialize = true) private List data; /** * 不需要展示给前台的数据1 */ @Expose(serialize = false) private String invisibleString; /** * 不需要给前台展示的数据2 */ @Expose(serialize = false) private Map invisiableMap; ``` ​ 3.构建Gson对象并测试 ```java @Test void test5(){ //设置dao对象 PersonDao dao = new PersonDao(); dao.setNum(1000); dao.setName("厚盾"); dao.setAge(25); dao.setData(new ArrayList<>(Arrays.asList(1,2,3))); dao.setInvisibleString("不可见"); dao.setInvisiableMap(new HashMap<>()); System.out.println("dao所有属性:"+dao.toString()); //注册自定义排除策略 并构建Gson对象 ,这里我们的排除策略为:num属性 和 String类型 GsonBuilder builder = new GsonBuilder(); builder.addSerializationExclusionStrategy(new MyExclusionStrategy(String.class)); Gson gson = builder.create(); System.out.println(gson.toJson(dao)); } ``` 测试结果: ```json {"age":25,"data":[1,2,3],"invisiableMap":{}} ``` 证明在我们的配置下,自定义策略MyExclusionStrategy生效 , ***`@expose`***注解失效。 #### 五、引用参考 1. Gson用户手册: https://github.com/google/gson/blob/master/UserGuide.md 2. Spring用户手册:https://spring.io/guides#topical-guides