主要学习和了解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)的格式

  1. 如何让他不返回时间戳的问题
    我们需要关闭ObjectMapper的时间戳功能。
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
  1. 时间格式化问题
    自定义日期格式对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
  1. 让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来测试这一块。这两个注解一般都会在异步获取数据中使用到。