响应 AJAX 的 Json 类型

设置响应内容

只需要在请求处理方法前面加上 @ResponseBody 表示将方法返回值添加到响应体中。

1
2
3
4
5
@ResponseBody
@RequestMapping("ajax")
public String getAjax() {
return "<script>alert('AJAX!')</script>";
}

然后就会在响应体里面看到一串 JS 代码了。

Json 处理

SpringMVC 支持自动将对象转化为 Json 格式的字符串,需要导入三个包:jackson-corejackson-annotationsjackson-databind。然后对于将自定义对象返回的方法,会自动转化为 Json 字符串:

1
2
3
4
5
@ResponseBody
@RequestMapping("ajax/get")
public Collection<Employee> returnAjax() {
return employeeDao.getAll();
}

方法返回的值是一个 Collection<Employee> 对象,但是标注了 @ResponseBody 之后,这个对象会经过转换器转化为 Json 格式(因为我们引入的 jackson-core 里面的 Json 转化器被添加到了转化器列表里面)

还可以使用一些其他关于 Json 的注解来控制转化的过程,如 @JsonIgnore 用于标注被省略转化的字段,使用 JsonFormat(pattern="XXXX") 来规定向 Date Time 这样的字段的转化格式等等:

1
2
3
4
@JsonFormat(pattern = "yyyy-MM-dd")
private Date date;
@JsonIgnore
private String password;

然后响应体里面返回的转化 Json 就是按照我们的要求的了,没有 password,时间按照 yyyy-MM-dd 格式: {"userName":"Tempest","email":"cloudloverain@Foxmail.com","date":"2021-06-16"}

获取请求内容

只需要在请求处理方法的参数前面加上 @RequestBody 表示将请求中的请求体放入参数中,比如我们设置一个 userName 的 Post 提交,按照 SpringMVC 参数填充规则,是无法填充到 String body 上面的,没有设置注解,参数名也不匹配,但是我们标注 @RequestBody 之后,整个 Post 的请求体会作为一个 String 字符串填充到 body 中:

1
2
3
4
@RequestMapping("ajax/post")
public void getAjax(@RequestBody String body) {
System.out.println(body);
}

输出结果,为 Post 所有内容:

1
Tempest=Xorex&Submit=Submit

@RequestBody 也支持自动转化格式的功能,比如将请求体中的 Json 数据转化为对象:

请求体:

1
{"userName":"Tempest","password":"Xorex","email":"cloudloverain@Foxmail.com","date":"2021-06-16"}

接收请求的处理方法,将 Json 自动转化为 User 对象并传入参数:

1
2
3
4
@RequestMapping("ajax/post")
public void getAjax(@RequestBody User user) {
System.out.println(user);
}

Body 数据转化原理

HttpMessageConverter<T>

对于请求 Body 和响应 Body 和 Java 对象的数据转化流程如下:

302.jpg

对于任意一个涉及到 Body 数据转换的请求或者响应,SpringMVC 会遍历自己拥有的所有 HttpMessageConverter<T>,去一一确认是否能处理此转换,默认实现了的转换器如下:

303.jpg

使用 HttpEntity<T> 代替 @RequestBody

将这个类作为请求参数,泛型 T 写为 RequestBody 需要被转化的类型(会依次寻找能处理 T 的Converter)。然后调用 getBody()getHeaders() 等来获取更加完整的请求信息(请求头);

使用 ResponseEntity<T> 代替 @ResponseBody

只需要将这个这个类作为请求处理方法的返回类型,泛型 T 为向响应体写入的数据类型,也就是 Object->String 转化的 Object 类型。

比如下面设置请求头(setcookie),设置请求体(User 用 Json 格式转 String),设置响应码(200 OK)。

1
2
3
4
5
6
7
8
@RequestMapping("/Entity")
public ResponseEntity<User> getEntity() {
User user = new User("Tempest", "Xorex", "cloudloverain@foxmail.com", new Date());
MultiValueMap<String,String> headers=new HttpHeaders();
headers.set(HttpHeaders.SET_COOKIE, "Temespt=Xorex");
HttpStatus status=HttpStatus.OK;
return new ResponseEntity<>(user, headers, status);
}

文件上传

对于多媒体文件的处理在 SpringMVC 中使用的是 MultipartResolver 这个组件来解决的,当我们需要处理文件上传的时候,就需要给这个组件设置一个实现类去处理。

从 MultipartResolver 的创建过程可以看到:

1
this.multipartResolver = (MultipartResolver)context.getBean("multipartResolver", MultipartResolver.class);

我们只需要在 ioc 容器中注册一个 id 为 multipartResolver 的 Bean 即可,这里使用的是:CommonsMultipartResolver 这个实现类:

1
2
3
4
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="#{1024*1024*100}" />
<!--设置最大上传文件大小为100MB-->
</bean>

单文件接收

然后使用 MultipartFile 类作为参数来接受请求发过来的文件,需要注意的是 getName() 指的是文件上传的 key 值 file,而 getOriginalFileName() 指的是文件本身的名字 XXX.jpg,使用它自带的 transferTo(File) 方法将上传来的文件转移到指定的位置。

1
2
3
4
@RequestMapping("/upload")
public void getEntity(@RequestParam("file") MultipartFile file) throws IOException {
file.transferTo(new File("D:\\Pictures\\Saved Pictures\\Tempest.jpg"));
}

注意需要将文件上传的表单里面添加一项 enctype="multipart/form-data",其不对字符编码。当使用有文件上传控件的表单时,该值是必需的。

如果不加编码规则,那么上传的就是 file=fileName,并不包含多媒体数据(上传文件本身),惨痛结果:

304.jpg

加了之后(没找到请求体 QAQ):

305.jpg

多文件接收

这里的多文件指的是一个 name 对应多个文件的情景,这个时候只需要使用 MultipartFile[] 来接收文件即可。

1
2
3
4
5
6
7
@RequestMapping("/upload")
public void getEntity(@RequestParam("file") MultipartFile file,@RequestParam("files") MultipartFile[] files) throws IOException {
System.out.println(file.getOriginalFilename());
for (MultipartFile multipartFile : files) {
System.out.println(multipartFile.getOriginalFilename());
}
}