主要学习和了解Json,在springmvc中用Controller将后端的对象数据通过Json的数据格式传递给前端的界面,以及最后对Json的简单封装,常用于前后端分离的项目。
预备知识
- SpringMVC
- Controller
- springmvc配置文件
- web.xml
- JavaScript
- 引入javaScript ,(script)
- 函数
Web1.0时代
- 早期登陆一个网页的时候,如果失败需要刷新界面,才能重新登陆,不点击提交的按钮,就不知道自己密码输错了。
- 现在大多数的网站都是局部刷新,不刷新整个界面的情况下,实现页面更新。(像注册的时候,发现手机已经注册过了,但是你只是输入了,没有提交,然后他就提示了。
- 这就是Ajax,这是时我们就要先了解json格式。
- Web2.0时代最重要的一个因素就是Ajax
Json
JSON (JavaScript Object Notation,JS对象标记)是一种轻量级的数据交换格式,目前使用特别广泛。
采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得JSON成为理想的数据交换语言。易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
在JS语言中,一切都是对象。因此,任何JS支持的类型都可以通过JSON来表示,例如字符串、数字、对象、数组等。详情见JSON
看看他的要求和语法格式 :
- 对象表示为键值对
- 数据由逗号分隔
- 花括号保存对象
- 方括号保存数组
JSON键值对是用来保存JS对象的一种方式,和JS对象的写法也大同小异,键/值对组合中的键名写在前面并用双引号""包裹,使用冒号∶分隔,然后紧接着值:
{"name":"zhengzheng"} {"age":"20"} {"sex":"男"}
很多人搞不清楚JSON和Js对象的关系,甚至连谁是谁都不清楚。其实,可以这么理解: JSON是JS对象的字符串表示法,它使用文本表示一个JS对象的信息,本质是一个字符串。
var obj = {a: 'Hello', b: 'world '};//这是一个对象,注意键名也是可以使用引号包裹的 var json = '[" a":"Hello", "b":"World"} ';//这是一个JSON字符串,本质是一个字符串
Json与JS对象的互转
要实现从JSON字符串转换为JS对象,使用JSON.parse()方法:
var obj = JSON.parse('{"a":"Hello","b":"World"}';//结果是{a: 'Hello',b: 'World'}
要实现从JS对象转换为JSON字符串,使用JSON.stringify()方法:
var json = JSON.stringify({a:'Hello',b: 'World'});//结果是 '{"a":"Hello","b":"World"}'
现在大部分都是前后端分离,数据交互变得异常重要
JSON就是王者!
现在我们就是想用Java把这种字符串转化出来,并且使得前端能获取到。
使用Controller实现返回Json数据
创建一个普通的maven工程,配置相关的pom.xml和其他配置文件。
创建实体包pojo和控制器包controller,其中创建一个用户实体类User,增加其部分属性,无参和全参构造方法以及相应的get和set方法。创建UserController,增加注释@Controller。
我们创建一个方法
@RequestMapping("/json1") public String json1() { return null; }
我们正常返回,走的是视图解析器,而json需要返回的是一个字符串。市面上有很多的第三方jar包可以实现这个功能,比如jackson,fastjson。这里我们使用jackson,它只要一个简单的注解就可以。我们需要去到maven仓库中找到他,将其加到我们的maven依赖库中。
Jackson
选择其中使用人数最多的一个,将其加到我们的pom.xml中
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.8</version> </dependency>
我们就可以用@ResponseBody注解将服务器端返回的对象转成JSON对象响应回去。
首先它需要一个jackson对象映射器,就是一个类,使用它可以直接将对象转成json字符串。
ObjectMapper mapper = new ObjectMapper();
然后创建用户一个对象。之后就可以用mapper中的writeValueAsString()方法将其转成字符串str。
我们最后返回的内容在之前是直接跳视图解析器,而在我们加上@ResponseBody注解后他就不会返回到视图解析器了。
由于@ResponseBody注解,这里会将字符串str以json格式的字符串返回,十分方便,这也是我们以后工作中使用较多的。
@RequestMapping("/json1") @ResponseBody public String json1() throws JsonProcessingException { ObjectMapper mapper = new ObjectMapper(); User user = new User("zhengzheng",20,"男"); String str = mapper.writeValueAsString(user); return str; }
//精简版 @RequestMapping("/json1") @ResponseBody public String json1() throws JsonProcessingException { User user = new User("zhengzheng",20,"男"); return new ObjectMapper().writeValueAsString(user); }
我们可以运行Tomcat后访问这个地址 http://localhost:8080/jsonTester/json1
其中jsonTester是我的工程名。
我们就可以在界面上看到服务器给我们返回的json字符。
{"name":"zhengzheng","age":20,"sex":"?"}
但是可以看到其中的中文字符解析不出来,我们需要解决这个乱码问题,这其实是@RequestMapping的问题,要给@RequestMapping加一个属性。我们需要设置一下他的编码格式为utf-8,以及它返回的类型,通过@RequestMapping的produces属性来实现,produces它就是用来指定响应体返回类型和编码。修改下代码
@RequestMapping(value="/json1",produces="application/json;charset=utf-8")
这样我们的返回到界面的就不是乱码了,我们还可以用一个一劳永逸的方法,更改配置文件,在其中加上
<mvc:annotation-driven> <!--JSON格式乱码处理方式--> <mvc:message-converters register-defaults="true"> <bean class="org.springframework.http.converter.StringHttpMessageConverter"> <constructor-arg value="UTF-8"/> </bean> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="objectMapper"> <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"> <property name="failOnEmptyBeans" value="false" /> </bean> </property> </bean> </mvc:message-converters> </mvc:annotation-driven>
像这样的我们根本不用去记它,只要在需要的时候拿来用就行。
我们这次用List来实验一下
@RequestMapping("/json3") @ResponseBody public String json3() throws JsonProcessingException { List<User> list = new ArrayList<User>(); list.add(new User("张三",20,"男")); list.add(new User("李四",20,"女")); list.add(new User("赵五",18,"男")); return new ObjectMapper().writeValueAsString(list); }
我们去到:http://localhost:8080/jsonTester/json3
可以看到我们解决了乱码问题,并且可以看到我们数组在json中的样式
[{"name":"张三","age":20,"sex":"男"},{"name":"李四","age":20,"sex":"女"},{"name":"赵五","age":18,"sex":"男"}]
将其格式化就是这样:
[ { "name": "张三", "age": 20, "sex": "男" }, { "name": "李四", "age": 20, "sex": "女" }, { "name": "赵五", "age": 18, "sex": "男" } ]
我们再了解下有时候会用到关于日期Date的处理
@RequestMapping("/time1") @ResponseBody public String json4() throws JsonProcessingException { Date date = new Date(); return new ObjectMapper().writeValueAsString(date); }
我们来到相应的地址:http://localhost:8080/jsonTester/time1
可以看到一个时间串,我们当前的时间,各不相同
1611574850169
此时如果我们加个System.out,我们可以看到我们的控制台也会相应的输出格林威治时间格式
Mon Jan 25 19:40:50 CST 2021
我们的时间默认返回的json格式变成了时间戳(Timestamp)的格式
- 如何让他不返回时间戳的问题
我们需要关闭ObjectMapper的时间戳功能。
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
- 时间格式化问题
自定义日期格式对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
- 让mapper指定时间日期格式为SimpleDateFormat
mapper.setDateFormat(sdf);
我们写好一个例子测试一下
@RequestMapping("/time2") @ResponseBody public String json5() throws JsonProcessingException { Date date = new Date(); ObjectMapper mapper = new ObjectMapper(); mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); mapper.setDateFormat(sdf); return mapper.writeValueAsString(date); }
运行后来到 http://localhost:8080/jsonTester/time2
这时他就是我们所定义的样式了。
"2021-01-25 20:19:24"
封装与总结
我们可以发现整个过程中有很多的重复的代码,我们可以将其封装成一个工具类。
新建一个utils的包其中新建一个JsonUtils类,在这里面将我们想封装的东西做成一个个的方法。
public class JsonUtils { public static String getJson(Object object) { return getJson(object,"yyyy-MM-dd HH:mm: ss");} public static String getJson(Object object,String dateFormat){ ObjectMapper mapper = new ObjectMapper(); mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); SimpleDateFormat sdf = new SimpleDateFormat(dateFormat); mapper.setDateFormat(sdf); try { return mapper.writeValueAsString (object); }catch (JsonProcessingException e) { e.printStackTrace(); } return null; } }
我们在需要的时候直接调用即可,比如
@RequestMapping("/time3") @ResponseBody public String json6() throws JsonProcessingException { return JsonUtils.getJson(new Date()); }
上面都是用的是@ResponseBody注解,它就是把后台的对象转换成json对象,返回到页面,和它对应的当然就是@RequestBody,一般用来负责接收前台的json数据,把json数据自动封装到pojo中。我们之后Ajax来测试这一块。这两个注解一般都会在异步获取数据中使用到。