1.引子
如果你经常从事后端开发,那么一定会遇到各种各样的json数据,并非所有的数据都可以直接按照springboot的映射的默认规则进行映射。
以我的需求为例接受的一个参数可以是
{
"event":"SendLinkMsg",
"to_wxid": "wxid_rxhdmvaefp1922",
"msg": {"xml" : "dwadadwadadwa","id" : "wxid_rxhdmvaefp1922"}
}
也可能是
{
"event":"SendTextMsg",
"to_wxid": "wxid_rxhdmvaefp1922",
"msg": "草神真可爱,软软的,嘿嘿嘿"
}
毫无疑问这是两种完全不同的结构,如果直接进行映射的话势必存在一个数据无法映射的情况。
这里我们就会经常使用@JsonDeserializer
手动处理参数,而其中的JsonParser
则是我们不能不了解的。
那这里我就简单说一下JsonParser的使用方法和简单的运行原理!
2.JsonParser的简单使用和理解
1.使用JsonFactory创建JsonParser
故名思意,jsonFactory就是用于处理json的工厂,它可以把你所指定的json处理成标记的字段,它提供了解析器,让操作者高效率手动处理json成为可能。
String a = "{\n" +
" \"event\":\"SendLinkMsg\",\n" +
" \"to_wxid\": \"wxid_rxhdmvaefp1922\",\n" +
" \"msg\": {\"xml\" : \"dwadadwadadwa\",\"id\" : \"22131\"}";
JsonFactory jsonFactory = new JsonFactory();
JsonParser parser = jsonFactory.createParser(a)
当然也可以通过 createParser()方法传入 Reader, InputStream, URL, byte[] 或 char[] 来解析不同来源的json
这里我们就成功拿到了jsonfactory生成的json解析器。
2.JsonParser的使用:
解析器根据json规则把传入的json切分成带有标记的字段。
字段类型包括
NOT_AVAILABLE((String)null, -1),
START_OBJECT("{", 1), //公共属性开始
END_OBJECT("}", 2), //公共属性结束
START_ARRAY("[", 3), //数组开始
END_ARRAY("]", 4), //数组结束
FIELD_NAME((String)null, 5), //字段名
VALUE_EMBEDDED_OBJECT((String)null, 12),
VALUE_STRING((String)null, 6), //字符串值
VALUE_NUMBER_INT((String)null, 7), //整数值
VALUE_NUMBER_FLOAT((String)null, 8),//浮点值
VALUE_TRUE("true", 9), //布尔值 正确
VALUE_FALSE("false", 10), //布尔值 错误
VALUE_NULL("null", 11); //空值
当我们处理json的时候,根据token标记,当token指针指到结尾的时候,JsonParser就会关闭,我们可以通过parser.isClosed()判断json是否解析到末尾。
parser给了我们很多操作读取字段的方法
currentToken(),nextToken()
用于返回当前token指针对应字段的类型;向右移动指针并且返回移动后的值
getCurrentName,getValueAsString()
获取当前指针对应字段的名字和值的类型。还有其他方法我就不一一阐述了
需要注意的是,当指针指向字段名的时候使用getValueAsString()
并不能返回字段名对应的字段值
而指针指向值的时候使用getCurrentName
却能获取对应的字段名
当然,我们也可以根据json规则,在字段名类型后面的字段必定是值类型正确示例
:
public static void main(String[] args) {
String a = "{\n" +
" \"event\":\"SendLinkMsg\",\n" +
" \"to_wxid\": \"wxid_rxhdmvaefp1922\",\n" +
" \"msg\": {\"xml\" : \"dwadadwadadwa\",\"id\" : \"22131\"}\n" +
"}";
JsonFactory jsonFactory = new JsonFactory();
try (JsonParser parser = jsonFactory.createParser(a)) {
System.out.println(parser.currentToken());
while(!parser.isClosed()){
JsonToken jsonToken = parser.nextToken();
if(JsonToken.FIELD_NAME.equals(jsonToken)){
String fieldName = parser.getCurrentName();
parser.nextToken();
System.out.println(fieldName+","+parser.getValueAsString());
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
3:多结构json映射解决思路:
回到最开始的问题,java是不能返回多种参数的,但是我们可以稍微变通下
我们可以把参数封装到一个实体类里,在实体类里多加一个字符串的属性
如果不是字符串的话就正常映射,如果是字符串的话把他打包,装到实体类的一个str
属性里
那么字符串json和对象json区别很简单:
正常json是有字段名和json值的
把对应的json值封装即可
而单单读取字符串其实不是json数据的,仅仅会读取到一个value值,把值封装返回即可
public Msg deserialize(JsonParser parser, DeserializationContext deserializationContext) throws IOException {
StringBuilder str = new StringBuilder();
String xml = null;
String name = null;
String path = null;
Integer type = null;
while(!parser.isClosed()){
if (parser.getValueAsString()!=null){
System.out.println(parser.getValueAsString());
str.append(parser.getValueAsString());
}
JsonToken jsonToken = parser.nextToken();
if(JsonToken.FIELD_NAME.equals(jsonToken)){
String fieldName = parser.getCurrentName();
parser.nextToken();
if ("xml".equals(fieldName)){
xml = parser.getValueAsString();
} else if("name".equals(fieldName)){
name = parser.getValueAsString();
} else if ("path".equals(fieldName)){
path = parser.getValueAsString();
} else if ("type".equals(fieldName)){
type = parser.getIntValue();
}else {
str.append(parser.getValueAsString());
}
}
}
Msg msg = new Msg(str.toString(),path,name,xml,type);
return msg;
}
1.处理字符串
2.处理对象
至此需求解决,当然代码不够凝练,如果各位大佬有什么更好的思路可以一起分享交流。