# 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