JSON简介
JSON 是一种与开发语言无关的、轻量级的数据格式 – JavaScript Object Notation
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。 易于人阅读和编写。同时也易于机器解析和生成。 它基于JavaScript Programming Language, Standard ECMA-262 3rd Edition – December 1999的一个子集。 JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)。 这些特性使JSON成为理想的数据交换语言。
优点:易于人的阅读和编写,易于程序的解析和生产
基本格式:{key:value}
标准的json数据表示
数据结构:Object、Array
基本类型:String、number、true、false、null
1 2 |
因此如果需要表示时间类型的时候需要使用约定格式的字符串如"YYYY-MM-DD" 然后在后台对数据进行解析 |
数据结构——object
使用花括号{}包含的键值对结构,key必须是String类型,value为任何基本类型或数据结构
数据结构——Array
使用中括号[]来起始,并用逗号来分割元素
下面这个网站可以帮助你解析json字符串,并生成文件:
JSON Editor Online
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
{ "array": [ 1, 2, 3 ], "boolean": true, "null": null, "number": 123, "object": { "a": "b", "c": "d", "e": "f" }, "string": "Hello World" } |
1 |
注意,JSON文件里不允许注释 |
具体资料可以查阅–>JSON中文官方网站
这里还有所有语言的示例代码以及相关工具等等内容,十分详尽,如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
Java: JSON-java. JSONUtil. jsonp. Json-lib. Stringtree. SOJO. json-taglib. Flexjson. JON tools. Argo. jsonij. fastjson. mjson. jjson. json-simple. json-io. JsonMarshaller. google-gson. Json-smart. FOSS Nova JSON. Corn CONVERTER. Apache johnzon. Genson. JSONUtil. cookjson. JavaScript: JSON. json2.js. clarinet. Oboe.js. |
利用org.Json构建json数据
利用org.Json在Java中使用JSONObject对象
Json是Android SDK的官方库
适合移动端开发
例子 JSON和对象的转换,在pom.xml中添加依赖包
1 2 3 4 5 |
<!--JAVA ASON--> <dependency> <groupId>org.json</groupId> <artifactId>json</artifactId> <version>20090211</version> </dependency> |
测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
@Test public void testJSONObject(){ BasicConfigurator.configure(); JSONObject jsonObject = new JSONObject(); Object nullObject= null;//使编译器跳过对null类型对检查 try { jsonObject.put("name","张全蛋"); jsonObject.put("age","25.2"); jsonObject.put("birthday","1990-01-01"); jsonObject.put("school","富土康"); jsonObject.put("major", new String[]{"理发", "挖掘机"}); jsonObject.put("hasGirlFriend",false); jsonObject.put("hascar",nullObject); jsonObject.put("comment","这是一个注释,因为json格式里是不能使用常规注释手段的"); System.out.println(jsonObject.toString()); } catch (JSONException e) { e.printStackTrace(); } //output //{"birthday":"1990-01-01","major":["理发","挖掘机"],"school":"富土康","name":"张全蛋","comment":"这是一个注释,因为json格式里是不能使用常规注释手段的","hasGirlFriend":false,"age":"25.2"} } } |
输出
1 2 3 4 5 6 7 8 9 10 11 12 |
{ "birthday": "1990-01-01", "major": [ "理发", "挖掘机" ], "school": "富土康", "name": "张全蛋", "comment": "这是一个注释,因为json格式里是不能使用常规注释手段的", "hasGirlFriend": false, "age": "25.2" } |
Json在Java中使用字符串生成JSONObject对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
@Test public void createJSONObjectByString(){ JSONObject jsonObject = null; String jsonStr ="{\"errno\":0,\"data\":true,\"errmsg\":\"success\"}"; try { jsonObject = new JSONObject(jsonStr); } catch (JSONException e) { e.printStackTrace(); } if(jsonObject != null){ System.out.println(jsonObject.toString()); //out: // {"errno":0,"data":true,"errmsg":"success"} } } |
Json在Java中使用MAP生成JSONObject对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
@Test public void createJSONObjectByMap() { Object nullObject = null;//使编译器跳过对null类型对检查 Map<String, Object> jsonObject = new HashMap<String, Object>(); jsonObject.put("name", "张全蛋"); jsonObject.put("age", "25.2"); jsonObject.put("birthday", "1990-01-01"); jsonObject.put("school", "富土康"); jsonObject.put("major", new String[]{"理发", "挖掘机"}); jsonObject.put("hasGirlFriend", false); jsonObject.put("hascar", nullObject); jsonObject.put("comment", "这是一个注释,因为json格式里是不能使用常规注释手段的"); System.out.println(new JSONObject(jsonObject).toString()); //out:{"birthday":"1990-01-01","major":["理发","挖掘机"],"school":"富土康","name":"张全蛋","comment":"这是一个注释,因为json格式里是不能使用常规注释手段的","hasGirlFriend":false,"age":"25.2","hascar":null} } |
Json在Java中使用JavaBean对象来生成JSONObject对象
1 2 3 4 5 6 7 8 9 10 11 12 |
@Test public void createJSONObjectbyJavaBean() { //常用 Message msg = new Message(); msg.errno = 0; msg.errmsg = "success"; msg.data = true; System.out.println(new JSONObject(msg).toString()); //out: //{"errno":0,"data":true,"errmsg":"success"} } |
从文件读取JSON数据
依赖
1 2 3 4 5 6 |
<!--org.apache.commons.io.FileUtils--> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency> |
测试文件的内容 与测试类文件同级 名为success_message.json
1 2 3 4 5 |
{ "errno": 0, "errmsg":["智商余额不足","需发红包给刘老师@95820608进行充值!"], "data":true } |
测试类中的测试方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
@Test public void readJSONFile() throws IOException, JSONException { //从当前类的同源文件中查找特定路径的文件 File file = new File(ReadJSONFileSample.class.getResource("/success_message.json").getFile()); String content = FileUtils.readFileToString(file); JSONObject jsonObject = new JSONObject(content); if(!jsonObject.isNull("errno")){ System.out.println("错误代码 --> " + jsonObject.getInt("errno")); } if(!jsonObject.isNull("errmsg")){ System.out.println("错误信息 --> " + jsonObject.getString("errmsg").toString()); } if(!jsonObject.isNull("data")){ System.out.println("错误内容 --> " + jsonObject.getBoolean("data")); } //out //错误代码 --> 0 //错误信息 --> ["智商余额不足","需发红包给刘老师@95820608进行充值!"] //错误内容 --> true //将JSONObject中的属性值为数组的值读取出来遍历 //如果值不是数组则会导致报错! if(!jsonObject.isNull("errmsg")){ JSONArray jsonArray = jsonObject.getJSONArray("errmsg"); for (int i = 0; i < jsonArray.length(); i++) { String m = (String)jsonArray.get(i); System.out.println(m); } } //out //智商余额不足 //需发红包给刘老师@95820608进行充值! } } |
使用Gson 来更加灵活的构建json数据
gson是google提供的开源api
Gson功能更强大可以在json格式和javaObject之间通过反射灵活转换
更适合服务端后台的开发
- 优点:
- 1.轻量, 支持将json字符串反向生成指定类的对象
- 2.支持日期格式
使用Gson生成json
pom.xml 添加依赖
123456 <!--GOOGLE GSON--><dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.4</version></dependency>测试类和测试方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
//使用GSON注解更改序列化后JSON的属性名称 protected class Message{ @SerializedName("ERRNO") int errno; String errmsg; boolean data; } @Test public void gsonCreate(){ Message msg = new Message(); msg.errno = 0; msg.errmsg = "success";msg.data = true; Gson gson = new Gson(); String jsonStr = gson.toJson(msg); System.out.println(jsonStr); //out:{"ERRNO":0,"errmsg":"success","data":true} } |
使用gsonBuilder定制json的转换规则
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
protected class FailMessage{ private int errno; private String errmsg; private boolean data; private transient String ignor;//transient 声明的属性不会被序列化 } @Test public void gsonCreateByGsonBuilder(){ FailMessage msg = new FailMessage(); msg.errno = -1; msg.errmsg = "fail";msg.data = false; GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.setPrettyPrinting();//美化格式后输出!方便调试 gsonBuilder.setFieldNamingStrategy(new FieldNamingStrategy() { //通过回调函数修改反射得到的属性值 @Override public String translateName(Field field) { if(field.getName().equals("errno")){ return ("error-code"); }else{ return field.getName(); } } }); Gson gsonNew = gsonBuilder.create(); System.out.println(gsonNew.toJson(msg));////美化格式后输出!方便调试 //out: // { // "error-code": -1, //errno被修改为error-code // "errmsg": "fail", // "data": false // } } |
使用gson反向将json字串转换成指定类
message.json文件内容如下:
1 2 3 4 5 6 |
{ "errno": 0, "errmsg":"智商余额不足,需发红包给刘老师@95820608进行充值!", "data":true } |
测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
public class Message { public int errno; public String errmsg; public boolean data; public int getErrno() { return errno; } public void setErrno(int errno) { this.errno = errno; } public String getErrmsg() { return errmsg; } public void setErrmsg(String errmsg) { this.errmsg = errmsg; } public boolean getData() { return data; } public void setData(boolean data) { this.data = data; } @Override public String toString() { return "Message{" + "errno=" + errno + ", errmsg='" + errmsg + '\'' + ", data=" + data + '}'; } } |
测试方法
1 2 3 4 5 6 7 8 9 10 11 12 |
@Test public void GsonReadTest() throws IOException { File file = new File(GsonSample.class.getResource("/message.json").getFile()); String content = FileUtils.readFileToString(file); Gson gson = new Gson(); //将json文件转换成指定类 Message msg = gson.fromJson(content, com.niit.mvcdemo.model.Message.class); System.out.println(msg.toString()); //out: //Message{errno=0, errmsg='智商余额不足,需发红包给刘老师@95820608进行充值!', data=true} } |
反向将json字串转换成指定带有时间属性的类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
class Logger{ private String content; private Date createtime; @Override public String toString() { return "Logger{content='" + content + '\'' + ", createtime=" + createtime.toString() +'}'; } } @Test public void GsonFromJsonToObject() throws IOException { Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create(); //使用gsonBuilder指定时间类型格式将json文件转换成指定类 Logger logger = gson.fromJson("{\"content\":\"Application started...\",\"createtime\":\"1970-01-01 00:00:00\"}", json.GsonSample.Logger.class); System.out.println(logger.toLocalString()); //out:Logger{content='Application started...', createtime=1970-1-1 0:00:00} } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
小知识 yyyy-MM-dd HH:mm:ss 年-月-日 时:分:秒 大写是为了区分“月”与“分” 顺便说下HH为什么大写,是为了区分12小时制与24小时制。 小写的h是12小时制,大写的H是24小时制。 书写格式和语言规定有关,上述写法是Windows系统中的我们常见的写法,包括日期设置于办公软件在内。在其他语言中有类似的但使用符号或格式不同的写法。 有的时候我们会看到这样的格式:yyyy-M-d H:m:s mm与m等,它们的区别为是否有前导零:H,m,s表示非零开始,HH,mm,ss表示从零开始。 比如凌晨1点2分,HH:mm显示为01:02,H:m显示为1:2。 以2014年1月1日凌晨1点1分1秒(当天是星期三)为例子介绍一下其他的: yyyy/yyy/yy/y 显示为 2014/2014/14/4 (3个y与4个y是一样的,为了便于理解多写成4个y) MMMM/MMM/MM/M 显示为 一月/一月/01/1 (4个M显示全称,3个M显示缩写,不过中文显示是一样的,英文就是January和J) dddd/ddd/dd/d 显示为 星期三/周三(有的语言显示为“三”)/01/1 (在英文中同M一样,4个d是全称,3个是简称; dddd/ddd表示星期几,dd/d表示几号) HH/H/hh/h 显示为 01/1/01 AM/1 AM 剩下的mm/m/ss/s只是前导零的问题了。 yyyy/M/d/dddd H:mm:ss 就是 2014年1月1日星期三 1:01:01 |
gson转换会自动将数组值映射成实体类对应的集合属性
注意Map会被映射成google自定义的Map类型..
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
class Product{ private String title; private String[] array; private List list; private Set set; private Map map; } @Test public void GsonMappingForCollection(){ String jsonStr= "" + "{\n" + " \"title\": \"product_id_1\",\n" + " \"array\": [\n" + " \"array1\",\n" + " \"array2\"\n" + " ],\n" + " \"list\": [\n" + " \"list1\",\n" + " \"list2\"\n" + " ],\n" + " \"set\": [\n" + " \"set2\",\n" + " \"set1\"\n" + " ],\n" + " \"map\": {\n" + " \"1\": \"map1\",\n" + " \"2\": \"map2\"\n" + " }\n" + "}" ; //通过gson将制定类的实例转化成json字符串 Product product = new Gson().fromJson(jsonStr,GsonSample.Product.class); System.out.println(product.title.toString() + "\t\t" + product.title.getClass()); //out: product_id_1 class java.lang.String System.out.println(Arrays.toString(product.array) + "\t\t" + product.array.getClass()); //out: [array1, array2] class [Ljava.lang.String; System.out.println(product.set.toString() + "\t\t" + product.set.getClass()); //out: [set2, set1] class java.util.LinkedHashSet System.out.println(product.list.toString() + "\t\t" + product.list.getClass()); //out: [list1, list2] class java.util.ArrayList System.out.println(product.map.toString() + "\t\t" + product.map.getClass()); //out: {1=map1, 2=map2} class com.google.gson.internal.LinkedTreeMap } |
jackson实现Json序列化和反序列化
利用fasterxml.jackson实现JSON序列化和反序列化
Gradle依赖
fasterxml.jackson依赖jackson-core, jackson-databind和jackson-annotations.
示例如下:
1 2 3 |
compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.5' compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.9.5' compile group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: '2.9.5' |
序列化和反序列化实现
JSON工具类
我们构造一个JSON工具类,实现JSON序列化和反序列化, 主要用到的类为com.fasterxml.jackson.databind.ObjectMapper, 代码示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
package com.notepad.util; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.HashMap; import java.util.Map; public class JsonSerializer { /** * JSON序列化 * * @param object 对象 * @return JSON字符串 */ public static String serialize(Object object) { ObjectMapper mapper = new ObjectMapper(); try { return mapper.writeValueAsString(object); } catch (JsonProcessingException e) { e.printStackTrace(); return ""; } } /** * JSON字符串反序列化 * * @param jsonStr JSON字符串 * @return a Map */ public static Map deserialize(String jsonStr) { try { return deserialize(jsonStr, Map.class); } catch (Exception e) { e.printStackTrace(); return new HashMap(); } } public static <T> T deserialize(String jsonStr, Class<T> classType) throws Exception { return new ObjectMapper().readValue(jsonStr, classType); } } |
Entity
为测试我们编写的JSON工具类, 定义一个Entity对象。
为了构建的Entity对象被JSON工具类操作, 关于Entity有几点说明:
- Entity对象必须有默认构造函数
- 成员变量必须有对应的Setter方法
- 可选: 可通过@JsonProperty自定义序列化和反序列化对应的字符的名称,如@JsonProperty(“UID”),则序列化时uid字段显示为UID,同理反序列化时找到字符串中UID对应的值,复制给uid。
- 可选:可通过@JsonIgnore注解,过滤掉不需要进行序列化的成员变量。
示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
package com.notepad.thinkingnote.domain; import com.fasterxml.jackson.annotation.JsonProperty; public class Entity { public Entity() {} public Entity(String uid, String name) { this.uid = uid; this.name = name; } /** 实体标识符 */ @JsonProperty("UID") private String uid; @JsonProperty("name") private String name; public void setUid(String uid) { this.uid = uid; } public String getUid() { return uid; } public void setName(String name) { this.name = name; } public String getName() { return name; } } |
单元测试
编写单元测试,测试Entity的序列化和反序列化, 示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
package com.notepad.thinkingnote.domain; import com.notepad.util.JsonSerializer; import org.junit.Test; import static org.junit.Assert.*; public class EntityTest { @Test public void testSerialize() throws Exception { Entity entity = new Entity("James", "James"); System.out.println(JsonSerializer.serialize(entity)); } @Test public void testDeserialize() throws Exception { String test = "{\"UID\":\"James\",\"name\":\"James\"}"; Entity entity = JsonSerializer.deserialize(test, Entity.class); System.out.println(entity.getUid() + ":" + entity.getName()); } } |
输出结果如下:
entity的序列化结果, 显示字段UID
{"UID":"James","name":"James"}
entity的序列化结果
James:James
UnrecognizedPropertyException异常解决
通过上面的介绍, 我们基本了解了JSON的序列化和反序列化,不过有时我们会遇到一种问题。
考虑这样一种情况,我们针对Http接口返回的JSON字符串,构建了一个具体的Entity对象,但是当Http接口中突然增加了一个字段type,如果还是按照原来方式解析会如何呢?
1 2 3 4 5 6 |
@Test public void testDeserialize() throws Exception { String test = "{\"UID\":\"James\",\"name\":\"James\", \"type\":\"entity\"}"; Entity entity = JsonSerializer.deserialize(test, Entity.class); System.out.println(entity.getUid() + ":" + entity.getName()); } |
出现UnrecognizedPropertyException
异常:
1 |
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "type" .... |
即对于新添加的type字符无法识别。如何解决这个问题呢?我们这里提供2种方法。
- 方法1 JsonIgnoreProperties注解
利用fasterxml.jackson提供的@JsonIgnoreProperties注解,针对无法识别的属性进行过滤。这里主要是修改需要进行反序列化的对象Entity,示例如下:
针对无法识别的属性进行过滤
12@JsonIgnoreProperties(ignoreUnknown = true)public class Entity {...} - 方法2 DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
方法1的修改需要对每一个需要进行反序列化的类进行修改, 不太方便。
方法2通过修改JSON工具类的反序列化方法,设置DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES的值为false, 可以仅一次修改就适用全部对象。
示例如下:
1234567public static <T> T deserialize(String jsonStr, Class<T> classType) throws Exception {// 添加configure, 设置DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES为false// 则对于无法识别的属性直接过滤return new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).readValue(jsonStr, classType);}
Views: 18