之前做项目的时候,处理json报文,是通过JSONObject实例一个obj对象,通过fromObject方法来获取请求的json字符串,然后再通过obj.getString()方法来获取请求报文中的变量值,这种方法没什么好说的,比较无脑,然后项目过程中就产生了一些问题,让我事后想了一下要如何改进,结果如下。
先来看一下产生的问题:
1.我们做项目时,各对象之间的数据传递通常是使用model对象,所以在获取到json中的数据后,我们要把数据添加到model中,如果按照我之前用的方法,那么就要根据model的定义,每个field一个一个的get set 进去,model小还好,如果很大的话,代码量也是很可观。不想偷懒的程序猿不是好工程狮。
2.在项目联调阶段,client部门发来json报文,按理说我按照报文规范,一个字段一个字段的get set 是不会出现问题的。但是,一上来就obj.getString()就报了空指针,原因是client端的规范是非必输项如果是空值,则字段可以缺省。这一下把我干傻了,这还怎么解析,最后通过沟通,让client端修改的报文规范,所有字段必须传送,即使为空。
那么这件事就一直在我心里,不解决不快啊。
好了话不多说,看一下目前的解决方法。
承接上一篇文章,首先先建立报文接受的server端:
StringBuffer str = new StringBuffer();
try {
BufferedInputStream in = new BufferedInputStream(req.getInputStream());
int i;
char c;
while((i=in.read()) != -1) {
c = (char)i;
str.append(c);
}
} catch (Exception ex) {
// TODO: handle exception
ex.printStackTrace();
}
JSONObject obj = JSONObject.fromObject(str.toString());
这样我们就得到了一个json格式的object,顺便说一下JSONObject的maven以来
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
接下来我们建立一个名字叫做Person的Model
public class Person {
private String name = "";
private String age = "";
private String sex = "";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
下面一段就是我最新的json解析的关键了
在方法中加入如下处理代码
Person person = new Person();
Field[] fields = person.getClass().getDeclaredFields();
for(Field field:fields) {
int mod = field.getModifiers();
if(Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
continue;
}
field.setAccessible(true);
try {
field.set(person,obj.get(field.getName()));
} catch (IllegalArgumentException | IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
JSONObject resp = JSONObject.fromObject(person);
String respJson = resp.toString();
整个方法的代码如下:
@RequestMapping(value="/json",produces= {"application/json;charset=UTF-8"})
@ResponseBody
public String dealJson(HttpServletRequest req) {
StringBuffer str = new StringBuffer();
try {
BufferedInputStream in = new BufferedInputStream(req.getInputStream());
int i;
char c;
while((i=in.read()) != -1) {
c = (char)i;
str.append(c);
}
} catch (Exception ex) {
// TODO: handle exception
ex.printStackTrace();
}
JSONObject obj = JSONObject.fromObject(str.toString());
Person person = new Person();
Field[] fields = person.getClass().getDeclaredFields();
for(Field field:fields) {
int mod = field.getModifiers();
if(Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
continue;
}
field.setAccessible(true);
try {
field.set(person,obj.get(field.getName()));
} catch (IllegalArgumentException | IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
logger.info(person.getName());
JSONObject resp = JSONObject.fromObject(person);
String respJson = resp.toString();
return respJson;
}
我们来通过postman调用一下,看一下处理结果
得到如下返回结果
可以看到我并没有传送age字段,但是并不影响报文的处理,而且person实力可以通过get方法来直接使用请求报文中的数据了。问题解决了!!