如果一个对象太复杂了,那么在网络传输键的JSON格式数据转换容易出问题。
比如下面一个类Area.java
import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.data.mongodb.core.geo.GeoJsonPolygon; @Data @NoArgsConstructor @AllArgsConstructor public class Area { private String name; private GeoJsonPolygon geoJsonPolygon; }
在这个Area类中,有个属性GeoJsonPloygon有点复杂,这个类的源码我就不贴了,只给大家看一下Area对象中包含它的JSON格式数据表示:
{ "name": "AAAA", "geoJsonPolygon": { "points": [{ "x": 3.4, "y": 3.9 }, { "x": 6.2, "y": 8.1 }, { "x": 9.8, "y": 3.1 }, { "x": 3.4, "y": 3.9 }], "coordinates": [{ "type": "LineString", "coordinates": [{ "x": 3.4, "y": 3.9 }, { "x": 6.2, "y": 8.1 }, { "x": 9.8, "y": 3.1 }, { "x": 3.4, "y": 3.9 }] }], "type": "Polygon" } }
上面红色标识就是GeoJsonPolygon的JSON格式。
这里如果看不懂points和coordinates没关系。
下面模拟一个服务A向另一个服务B,传输泛型为Area的一个List,服务B解析该数据,并返回数据。
服务A的Controller,就是造一个泛型为Area的一个List,通过RestTemplate向B服务传数据。
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.data.geo.Point; import org.springframework.data.mongodb.core.geo.GeoJsonPolygon; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import java.util.ArrayList; import java.util.List; @RestController public class SendController { @Autowired private RestTemplate restTemplate; @GetMapping(value = "/send") @ResponseBody public List sendArea(){ Point point1 = new Point(3.4, 3.9); Point point2 = new Point(6.2, 8.1); Point point3 = new Point(9.8, 3.1); Point point4 = new Point(3.4, 3.9); List<Point> points = new ArrayList<>(); points.add(point1); points.add(point2); points.add(point3); points.add(point4); List<Area> areaList = new ArrayList<>(); areaList.add(new Area("AAAA",new GeoJsonPolygon(points))); areaList.add(new Area("BBBB",new GeoJsonPolygon(points))); areaList.add(new Area("CCCC",new GeoJsonPolygon(points))); String url = ReceiveController.BASE_URL+ReceiveController.POST_MAPPING; ResponseEntity entity = restTemplate.postForEntity(url, areaList,List.class); List body = (List) entity.getBody(); return body; } @Bean public RestTemplate restTemplate(){ return new RestTemplate(); } }
服务B的Controller
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.TypeReference; import org.springframework.data.geo.Point; import org.springframework.data.mongodb.core.geo.GeoJsonPolygon; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import java.util.ArrayList; import java.util.List; @RestController public class ReceiveController { public static final String BASE_URL = "http://localhost:8080"; public static final String POST_MAPPING = "/receive"; @PostMapping(value = POST_MAPPING) @ResponseBody public List areaList(@RequestBody String areaList){ List<Area> list = new ArrayList<>(); if(areaList == null ){ return list; } /** * List<Area> listString = JSON.parseObject(areaList, new TypeReference<List<Area>>(){}); * 注意这样写是错误的,Area包含属性GeoJsonPolygon,解析不了 * 只好吧List的泛型写成String */ List<String> listString = JSON.parseObject(areaList, new TypeReference<List<String>>(){}); JSONObject jsonObject = null; JSONObject polygonJsonObject = null; GeoJsonPolygon geoJsonPolygon = null; for (int i=0; i < listString.size(); i++){ String s = listString.get(i); jsonObject = JSONObject.parseObject(s); //通过JSONObject对象获取key对应的value String name = jsonObject.getString("name"); //解析复杂的GeoJsonPolygon属性 String geoJsonPolygonString = jsonObject.getString("geoJsonPolygon"); polygonJsonObject = JSONObject.parseObject(geoJsonPolygonString); String pointsString = polygonJsonObject.getString("points"); List<Point> points = JSON.parseObject(pointsString, new TypeReference<List<Point>>() {}); geoJsonPolygon = new GeoJsonPolygon(points); Area area = new Area(); area.setName(name); area.setGeoJsonPolygon(geoJsonPolygon); list.add(area); } return list; } }
注意:使用的是fastjson版本是1.2.47,如果是1.2.7版本在执行这条语句List<Point> points = JSON.parseObject(pointsString, new TypeReference<List<Point>>() {}) 会报错,因为1.2.7要求这里的泛型类Point必须有无参构造函数,而1.2.47版本没有无参构造函数也可以。
总结
a. 服务B首先使用了@RequestBody注解,然后解析该嵌套数据类型;
b. 如果是list利用List<String> listString = JSON.parseObject(areaList, new TypeReference<List<String>>(){}) 先解析成泛型为String的List。因为GeoJsonPolygon太复杂了,直接解析不了,如果是简单的如Point可以直接List<Point> points = JSON.parseObject(pointsString, new TypeReference<List<Point>>() {});
c. 如果不是list,并且该String对象还是嵌套JSON数据格式,就把String对象解析成JsonObject 对象;
d. 利用JsonObject 对象的getString方法获取对应属性key的字符串,如果该字符串还是复杂的JSON数据,进行b或c步骤,直到获取到想要的数据或解析完成。
在线JSON:http://www.bejson.com/