一、Restful请求格式
Restful的出现同时也解决了客户端的种类多种多样造成请求的格式比较混乱的问题,Restful提供了一种统一的前后端交互的接口规范,可以更好的实现数据的交互。
正常使用
以前我们来实现对用户的增删该查的时候是以操作为基础来声明URL地址的:
如:新增用户: http://localhost:8080/userAdd?uid=1&uname=zhangsan&age=12
而按照Restful的格式对用户的操作应当只有一个url地址:
操作用户: http://localhost:8080/user
Restful要求在当前的url地址中直接嵌套请求数据。
HTTP协议中支持很多种请求方式,除了GET和POST还有PUT和DELETE等,restful中要求使用不同的请求方式来标记对资源的操作方式,达到调用不同的后台功能方法来处理请求的目的。
请求数据的获取不能在像以前直接在单元方法上声明形参来接收了,需要结合@PathVariable注解来获取。
@RequestMapping注解可以接收任意请求方式的请求
@GetMapping("地址"):接收GET请求,一般用在查询方法上
@DeleteMapping("地址"):接收DELETE请求,一般用在删除方法上
@PostMapping("地址"):接收POST请求,一般用户在新增上
@PutMapping("地址"):接收PUT请求,一般用在修改上
使用Restful可以只写一个控制器。
其中映射路径前面的/page/不是强制要求,随意在前面添加的内容。也可以不写/page/,也可以多加几级路径。
@RequestMapping("/page/{yemian}")
public String showPage(@PathVariable String yemian){
return "/WEB-INF/page/"+yemian+".jsp";
}
二、@ResponseBody注解
@ResponseBody注解是类或方法级注解。
当方法上添加@ResponseBody注解后,控制单元方法返回值将不再被视图解析器进行解析|不会使用转发。而是把返回值放入到响应流中进行响应。
在使用@ResponseBody注解时,只要返回值类型不是类或Map或List等满足键值对类型。Spring MVC 都会设置响应内容类型为text/html;charset=ISO-8859-1。
想要改变@ResonseBody注解的响应内容类型(Content-Type)只能通过@RequestMapping的produces属性进行设置。
@RequestMapping(value="/demo1",produces = "text/html;charset=utf-8")
@ResponseBody
public String demo1() {
return "你好";
}
1.自动转换为JSON字符串
@ResponseBody注解可以把控制单元返回值自动转换为JSON字符串。主要完成下面几个事情:
1)判断返回值是否为JavaBean、JavaBean数组、List<JavaBean类型>、Map等满足键值对的类型。
(2)如果满足键值对类型,会使用Jackson把对象转换为JSON字符串,设置到响应流中。 同时会设置响应内容类型(Content-Type)为application/json;charset=utf-8
因为Spring MVC默认使用Jackson作为JSON转换工具,所以必须保证项目中存在Jackson的依赖。
除了Map以外,也可以使用实体类或List<实体类>或List<Map>等类型,这些类型都可以被转换为JSON字符串
2.转换为XML文件
XML格式在一些开放平台上用的比较多。例如:微信里面很多接口都是XML格式。
在Spring MVC中支持把返回值转换为XML文件。如果还是使用jackson-databind依赖,默认只能转换返回值为类类型的控制单元,返回值为List是无法转换为XML的,同时还要求实体类上必须有@XmlRootElement,才能转换。
执行步骤
导入依赖
导入依赖时注意:
(1)不要导入jackson-databind,只导入jackson-dataformat-xml。
(2)jackson-dataformat-xml版本不要太高,和Tomcat8插件不兼容。2.9.9和Spring 5.3.x可以正确兼容。
编写控制单元
控制单元方法和转换为JSON时写法完全相同。
测试结果
3.@RestController注解
对于页面中使用前端框架时的项目。例如页面时通过:EasyUI、BootStrap、Vue等前端框架进行编写时,客户端向服务端发送的请求都是异步Ajax(或类似Ajax的异步请求)。对于这样的项目,控制器中所有的方法都包含@ResponseBody注解。
像这种类中所有的控制单元方法都有@ResponseBody,可以使用@RestController进行简化。当类上使用的是@RestController而不是@Controller时,控制单元方法不再需要写@ResponseBody(也不能写@ResponseBody),Spring MVC在解析控制单元方法时会自动带有@ResponseBody注解。(全局的)
只要类中有一个方法是希望实现页面跳转功能,类上就不能使用@RestController。只有类中所有的方法都是返回JSON或XML的情况才能使用@RestController注解。
三、@RequestBody注解
@RequestBody注解底层依赖的依然是Jackson工具包,其作用是把客户端传递过来的请求体中JSON或XML数据转换为Map、类、List<类>、List<Map>等类型。
既然是转换为请求体数据,所以不能是GET类型请求(GET没有请求体),多用在POST类型的请求中。
@RequestBody注解在单体架构项目使用的不是特别多。主要用在分布式项目中多个项目之间传递数据或一些开发平台中(例如微信开发平台接口返回XML数据)
如果希望在单体架构项目中使用@RequestBody注解,需要在客户端中使用Ajax请求,刻意设置请求的内容类型(Content-Type)为JSON或XML。
请求内容类型详解
在客户端中无论使用的是<form>
表单,还是Ajax请求,post请求内容类型都是application/x-www-form-urlencoded,表示普通表单参数。普通表单参数接收方式和上次课讲解的参数接收方式是相同的。因为是默认请求内容类型,所以在谷歌浏览器开发者工具中有时不会特意的显示,有时会显示。
@Controller
public class Demo2Controller {
// 使用多个简单数据类型接收请求参数
@RequestMapping("/testContentType")
public String testContentType(int id, String name) {
System.out.println(id + "," + name);
return "/index.jsp";
}
// 使用JavaBean接收请求参数
// @RequestMapping("/testContentType")
// public String testContentType2(People peo){
// System.out.println(peo);
// return "/index.jsp";
// }
}
使用Ajax请求时,默认的参数类型也是普通表单参数(Form Data)。
$.ajax({
url:"/testContentTypeAjax",
data:{"id":1,"name":"张三"},
type:"post",
success:function (data) {
console.log(data);
},
dataType:"json"
});
服务端控制器中接收参数还是和正常参数接收相同。但是客户端希望服务端返回JSON数据,所以一定要在类上添加@ResponseBody注解。
如果希望修改请求内容类型,可以使用HTML的<form>
中enctype属性或使用Ajax中contentType属性进行设置。
注意:<form>
的enctype属性一般只有在文件上传时才会修改,所以希望传递特定类型请求参数内容时,都是通过Ajax进行请求。
在下面代码中有三次需要重点注意的地方:
(1)contentType:必须设置。常见取值“application/json”或"application/xml"。如果没有设置这个属性,取值默认是application/x-www-form-urlencoded,表示普通表单参数。当设置为"application/json"时,会把data取值设置到请求体中,所以服务端接收参数时就不能按照普通表单参数进行接收。
(2)data:请求参数。必须是JSON字符串类型,不能是JSON格式的对象。因为在JSON中key两次必须有双引号,所以data取值两侧用单引号包含。因为在JavaScript中字符串string类型可以使用单引号包含,也可以使用双引号包含。
(3)type:请求类型不能是get类型,因为get类型没有请求体。常用就是post类型。
$.ajax({
url:"testContentType",
contentType:"application/json",// 修改请求内容类型为JSON
data:'{"id":1,"name":"张三"}',// 取值两次必须有单引号,没有单引号无效
type:"post",// 不能是GET类型请求
success:function (data) {
console.log(data);
},
dataType:"json"
});
服务端接收请求体中包含JSON字符串的请求时,需要在参数前面添加@RequestBody。表示使用Jackson把请求体中JSON/XML格式数据转换为JavaBean或Map。
-
因为一个请求只有一个请求体。控制单元参数中绝对不允许出现两个@RequestBody注解。
-
因为@RequestBody底层使用Jackson,所以只适用于把请求体数据转换为JavaBean或Map。绝对不能在@RequestBody后面使用String等类型接收请求体内容。也就是说,客户端把JSON或XML设置到请求体,服务端使用JavaBean或Map接收请求体数据时,才能在控制单元参数前面添加@RequestBody注解。
四、Spring MVC文件上传
文件上传就是把客户端的文件上传到服务端进行保存。在文件上传时文件和其他请求参数是在请求体中进行传递。所以不支持GET类型请求。
默认的表单内容类型application/x-www-form-urlencoded不支持传递文件流。所以需要在<form>
的enctype中设置enctype="multipart/form-data"才表示把文件和其他表单参数设置到请求体中。
Spring MVC的文件上传是通过MultipartResovler组件实现的。提供了两个具体的实现类
其中CommonsMultipartResovler是我们需要使用的实现类。底层是对Apache的Commons-Fileupload的封装,让文件上传代码实现起来更加简单。所以在文件上传时必须在Spring MVC的配置文件中配置CommonsMultipartResovler组件的Bean,同时也得在项目中导入Commons-Fileupload的依赖。
谨记:没有MultipartResovler是无法获取到Content-Type="multipart/form-data"类型的数据,无论是表单域数据还是文件域数据。
总结出来,Spring MVC 文件上传有如下几点要求:
(1)客户端:
(1.1) 请求方式必须是POST
(1.2)enctype必须为multipart/form-data
(2)服务端:
(2.1)必须配置MultipartResovler。否则无法解析上传文件的流数据。(<bean>
的id值必须叫做multipartResovler)如果没有配置MultipartResovler不仅仅是文件流数据无法解析,连带着其他表单域数据也无法解析。因为文件流数据和表单数据都在请求体中,不解析的话,文件流数据和表单数据都接收不到。
(2.2)注意文件域的name取值,文件域必须MultipartFile类型接收。且name的取值必须和MultipartFile对象名相同。
如果客户端就一个文件域使用一个MultipartFile对象接收就可以了。
如果客户端是多个同名的文件域使用MultipartFile 数组接收。
如果客户端是多个不同名的文件域使用多个MultipartFile对象接收就可以了。
文件上传控制单元方法实现
*
* @param name 也可以使用JavaBean接收name的值
* @param address 也可以使用JavaBean接收address的值
* @param photo 名字必须和表单中文件域的name属性值相同
* @return
* @throws IOException transferTo抛出的异常,可以使用try...catch处理异常。示例中为了让代码看起来简洁直接抛出了。
限制上传文件大小
在很多项目中是对上传文件做严格大小限制的。当文件太大会占用服务器存储空间。当文件太小(尤其是图片)可能显示不清晰。
在CommonsMultipartResolver中提供了setmaxUploadSize(long)方法,表示设置上传文件的大小。单位是字节byte。默认值为-1,表示无限制。
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="1024"></property>
</bean>
再次上传文件,当文件大小超出限制,会报FileUploadBase$SizeLimitExceededException异常,其中SizeLimitExceededException是FileUploadBase的内部类。
异常信息中会明确告诉我们实际大小和限制大小
五、文件下载
文件下载就是把服务器中的资源下载到本地。
但是需要注意的是浏览器本身作为一款软件,能够打开的文件格式比较多。
例如:.html文件、图片文件、.txt文件、.xml文件、.json文件等。当超链接访问的是浏览器本身能打开的资源。浏览器直接打开。这个特点就是响应头参数Content-Disposition控制的,其默认值为inline,表示能打开就打开,不能打开就下载。
Content-Disposition可取值有两个:
(1)inline。直接在浏览器中打开(能打开就打开,不能打开就下载)。
(2)attachment。以附件形式下载。