一、REST
1、什么是REST
(1)概念
- 即 Representational State Transfer。(资源)表现层状态转化。是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。
- 资源: 网络上的一个实体,或者说是网络上的一个具体信息。
它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的存在。可以用一个 URI(统一资源定位符)指向它,每种资源对应一个特定的 URI 。获取这个资源,访问它的 URI 就可以,因此 URI 即为每一个资源的独一无二的识别符 - 表现出(Representation):吧资源具体呈现出来的形式,叫做它的表现层。比如,文本可以用text格式表现,也可以用html格式,可以xml,JSON,等格式。
- 状态转化(state Transfer):每发出一个请求,就代表客户端和服务器的异常交换过程,http协议,是一个无状态的协议,即所有的状态都保存在服务器,因此,如果客户端向要操作服务器,必须通过某种手段,让服务器端发生状态转化,而这种转是建立在表现层之上的,所以称为表现层状态层转化。
- 具体说,就是HTTP协议里面,四个表示操作方式的动词,get,post,put,delete。他们分别是对应的四种基本操作,get用来或者资源,post新建资源,put用来跟心资源,delete用来删除资源
- 资源: 网络上的一个实体,或者说是网络上的一个具体信息。
(2)URL风格
- /order/1 HTTP GET :得到 id = 1 的 order
- /order/1 HTTP DELETE:删除 id = 1 的 order
- /order HTTP PUT:更新 order
- /order HTTP POST:新增 order
2、RestFul实现
(1)具体概念
- 原始的
- restful风格
(2)RestFul操作用户资源
(3)HiddenHTTPMethodFilter过滤器处理put和delete
- 首先不配置的情况下,我们采用put方式提交是报错:405错误,但是我们启动了后端项目是不会报错的,原因在于我们的SpringMVC会自动处理,默认按着get方式请求。
- 浏览器 form 表单只支持 GET 与 POST 请求,而 DELETE、PUT 等 method 并不支持,Spring3.0 添加了一个过滤器,可以将这些请求转换为标准的 http 方法,使得支持 GET、POST、PUT
-
配置PUT方式步骤【同样要采用post方式提交】
-
配置delete步骤【但是它不能是post,这个后续补充】
(4)两过滤器
如果按着这样的顺序,你启动项目访问是会报编码错误的,所以你这里不能能这样写的。在我们编码之前不可以有任何的配置访问。
- 所以要把两个过滤器的位置调换一下。
3、RestFul代码实现
- 这个后续补充
二、HttpMessageConverter
- HttpMessageConverter报文信息转换器,将请求报文转换为Java对象,或将Java对象转换为报文。
- HttpMessageConverter提供了两个注解和两个类型:@RequestBody,@ResponseBody,RequestEntity,ResponseEntity
1、@RequestBody
- @RequestBody可以获取请求体,需要再控制器方法设置一个型参,使用@RequestBody进行识别,当前请求的请求头就会为当前注解所表示的型参赋值。
2、RequestEntity
- RequestEntity封装请求报文的一种类型,需要控制器方法的形参设置该类型的形参,当前请求的请求报文就会赋值给该形参,可以通过getHeaders()获取请求头信息,通过getBody()获取请求信息。
差不多也回到了我们的request里面了。
3、@ResponseBody
- @ResponseBody是:用来给浏览器响应数据的,【和Response是一样的概念】
- 当加上ResponseBody注解后,就不会返回的时候跳转到success路径了,而是返回的响应体了。【返回的是给页面的数据了,而不是返回的时候一个路径了】
4、@ResponseBody响应JSON
- 响应一个对象试一试【你浏览器根本就不知User是什么语言写的,这样肯定是不行的】
- 所以要封装为一个JSON格式【JSON是一种数据交换格式,在AJAX里面什么的都是可以使用的】,所以要引入依赖
此时再去点击就会直接返回给你浏览器JSON一个格式了。内容执行了四个步骤
- 回顾一下JSON
JSON是JavaScript里面一种数据格式,是我们数据交互格式,它应用很广泛,原因在于它使用{}和方括号[]扩起来的,数据量比较少,之前也有使用xml,但是它是我们自定义的数据格式,应用比较少,数据量是比较多的。
<person>
<username> xxx</username>
.
.
.
.
.
</person>
{ "username": xxx,"password":xxxx}
方括号[]放对象,{}方对象
5、SpringMVC处理AJAX
6、@RestController
@RestController注解是SpringMVC提供的复合注解,表示在控制器的类上,就相当于为类添加了@Controller注解,并且为其中的每个方法添加了@ResponseBody注解
7、ResponseEntity
ResponseEntity是用于控制器方法的返回值类型,该控制器返回值就是响应到浏览器的响应报文上。【就是些在方法上,自定义的响应报文】
(1)ResponseEntity实现文件下载
@Controller
public class JPGController {
@RequestMapping("/testDown")
public ResponseEntity<byte[]> testJPG(HttpSession session) throws IOException {
//获取ServletContext对象
ServletContext servletContext = session.getServletContext();
//获取服务器中文件的真实路径【部署路径】
String path = servletContext.getRealPath("/static/1.jpg");
//创建输入流
InputStream is = new FilterInputStream(path);
//创建字节数组【is.available()获取所有的输入字节流】
byte[] bytes = new byte[is.available()];
//将流读到字节数组中
is.read(bytes);
//创建httpHeaders对象设置响应头
MultiValueMap<String,String> headers = new HttpHeaders();
//设置要下载方式和下载文件的名字
headers.add("content-Disposition","attachment;filename=1.jpg");
//设置响应状态码
HttpStatus status = HttpStatus.OK;
//创建ResponseEntity对象
ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes,headers,status);
is.close();
return responseEntity;
}
}
- ResponseEntity自定义响应报文格式。
(2)SpringMVC配置文件上传解析器
首先上传的要求,不可以是get请求,一定是post,而且要修改如下的一个属性
正式的来练习
- 添加依赖
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
- MultipartFile就是文件上传的信息,操作也是封装在里面的,但是我们上传的文件不能直接转换为multipartFile对象,所以要去添加文件上传解析器【配置在我们的配置文件里面】
- 文件服务器地址配置
@RequestMapping("/up")
public String testUP(MultipartFile multipartFile,HttpSession session) throws IOException {
//MultipartFile就是文件上传的信息,操作也是封装在里面的,但是我们上传的文件不能直接转换为multipartFile对象,所以要去添加文件上传解析器
String fileName = multipartFile.getOriginalFilename();//获取文件名字
ServletContext servletContext = session.getServletContext();
String photoPath = servletContext.getRealPath("photo");
//动态的创建目录
File file = new File(photoPath);
if (!file.exists()) { //判断路径是否存再
//若不存则创建
file.mkdir();
}
//最终上传的路径
String finalPaht = photoPath + File.separator + fileName;
//指定上传到哪个位置
multipartFile.transferTo(new File(finalPaht));
//返回值
return "success";
}
(3)文件上传的特殊情况
上面的文件上传中,如果用户1上传了1.jpg,然后接着第二个用户上传1.jpg后,之前的就会被覆盖调,这种情况很严重。【不是文件覆盖,而是文件中的内容覆盖】
- 此时就可以用UUID来进行文件名的配置了
@RequestMapping("/up")
public String testUP(MultipartFile multipartFile,HttpSession session) throws IOException {
//MultipartFile就是文件上传的信息,操作也是封装在里面的,但是我们上传的文件不能直接转换为multipartFile对象,所以要去添加文件上传解析器
String fileName = multipartFile.getOriginalFilename();//获取文件名字
//获取上传文件的文件名,通过servlet获取服务器中photoPath目录的路径
//获取后缀名
String suffixName = fileName.substring(fileName.lastIndexOf("."));//suffixName = .xxxx
//通过UUID设置文件名
String uuid = UUID.randomUUID().toString();
//将uuid进行拼接作为最后的文件名
fileName = uuid + suffixName;
ServletContext servletContext = session.getServletContext();
String photoPath = servletContext.getRealPath("photo");
//动态的创建目录
File file = new File(photoPath);
if (!file.exists()) { //判断路径是否存再
//若不存则创建
file.mkdir();
}
//最终上传的路径
String finalPaht = photoPath + File.separator + fileName;
//指定上传到哪个位置
multipartFile.transferTo(new File(finalPaht));
//返回值
return "success";
}
}
三、拦截器
1、介绍
- SpringMVC中的拦截器用于拦截控制器方法的执行【它和过滤器的区别是:过滤器那个/*拦截浏览器和服务器的的所有的请求过滤的,而拦截器是作用于控制器】
拦截器拦截时候有三个方法调用控制器方法执行之前,另外一个拦截执行之后,另外一个在渲染视图完成之后。
2、创建拦截器
- implements HandlerInterceptor
- extends HandlerInterceptorAdapter
本次选择上一个
- 快捷键Ctrl + O即可查看可以继承的方法
3、配置拦截器
(1)bean方式
不管你现在是访问哪个链路都是不可行的。【preHandler就是我们的拦截的方法,返回true是拦截,返回false为放行】
- 此时采用bean的方式配置拦截,它会拦截所有的请求
(2)ref方式
也是对所有的请求进行拦截
(3)path类型(指定页面拦截)
这里的“/*" 表示上下文的一层目录,如果是拦截所有的用“/**”
4、prehandler方法,各个方法的执行顺序
(1)返回true多个拦截器的执行顺序
当有两个拦截器的时候,拦截的顺序是什么样子的呢?
- 原因是呢?【其实就是我们的配置文件里面的书写顺序】
- 首先你访问就会进入到这一点
- 然后会进入到这,遍历你的拦截器,第0个它自己创建的,第二第三就是我们创建的顺序了
此时执行后,我们的两句话就要输出了
- 接下来就要返回了
- 其他的为什么反着来输出
这里就要输出如下了
- 同样的渲染之后执行也是这样执行的
- 首先你访问就会进入到这一点
(2)返回false多个拦截器的执行顺序
- 首先修改这里
- 同样的也是执行处理前方法()
又会返过去执行之前的方法。
比如我现在有1,2,3,4,5拦截器:如果3拦截器返回false的话,那就会只有1和2和2会执行,后面的两就不会执行了,postHandler是任何一个都不会执行的,还有后面的after都不会执行了
(3)总结
四、SpringMVC之异常处理
1、异常处理器
自动的异常处理的话,我们就可以指定异常跳转到指定页面的配置。
- 当你自己写的有问题的时候,它就会给你返回一个新的modelAndview
如果你的请求出了如下的一些错误就会到这里进行处理
- 自定义异常处理时候【我们可以通过配置文件和注解处理方式】
2、基于配置的异常处理
- 配置异常信息
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
错误页面
<p th:text="@{ex}">
</p>
</body>
</html>