SpringMVC概念
MVC模式简介
MVC是一种软件架构的思想,将软件按照模型、视图、控制器来划分
- M:Model,模型层,指工程中的JavaBean,作用是处理数据
- 实体类Bean:专门存储业务数据的,如 Student、User 等
- 业务处理 Bean:指 Service 或 Dao 对象,专门用于处理业务逻辑和数据访问
- V:View,视图层,指工程中的html或jsp等页面,作用是与用户进行交互,展示数据
- C:Controller,控制层,指工程中的servlet,作用是接收请求和响应浏览器
SpringMVC工作流程
用户通过视图层发送请求到服务器,在服务器中请求被 Controller 接收,Controller 调用相应的 Model 层处理请求,处理完毕将结果返回到 Controller,Controller 再根据请求处理的结果找到相应的 View 视图,渲染数据后最终响应给浏览器

SpringMVC处理请求流程
- 用户发送请求至前端控制器 DispatcherServlet,其收到请求调用 HandlerMapping 处理器映射器
- HandlerMapping 处理器映射器根据请求 URL 找到处理器,生成处理器对象及拦截器返回给DispathcerServlet
- DispatcherServlet 通过 HandlerAdapter 处理器适配器调用处理器 Handler(Controller), Controller 执行完成返回 ModelAndView 给 HandlerAdapter
- HandlerAdapter 将处理器 Handler(Controller) 执行结果 ModelAndView 返回给 DispatcherServlet
- DispatcherServlet 将 ModelAndView 传给 ViewResolver 视图解析器
- ViewResolver 解析后返回具体 View 对象,DispatcherServlet 对 View 进行渲染视图
- DispathcerServlet 响应用户
SpringMVC相关组件
- DispatcherServlet:前端控制器(单例),统一处理请求和响应,整个流程控制中心,相当于 MVC 模式中的 Controller,调用其它组件处理用户请求
- HandlerMapping:处理器映射器,根据用户请求的URL、method等信息查找 Handler处理器,SpringMVC 提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等
- Handler:处理器,开发中要编写的具体业务控制器。在 DispatcherServlet 的控制下 Handler 对具体的用户请求进行处理
- HandlerAdapter:处理器适配器,通过 HandlerAdapter 对 Handler 处理器(控制器方法)进行执行
- ViewResolver:视图解析器,进行视图解析,得到相应的视图,例如:ThymeleafView。首先根据逻辑视图名解析成物理视图名,即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户
- View:视图,将模型数据通过页面展示给用户。SpringMVC 框架提供了很多的 View 视图类型的支持,包括:jstlView、freemarkerView、pdfView等。最常用的视图就是jsp。一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面
SpringMVC注解
-
@RestController
@Controller + @ResponseBody -
@RequestMapping
-
功能:将 SpringMVC 接收到指定的请求和处理请求的控制器(Controller)方法关联,建立映射关系
-
位置:
- 类:设置映射请求的请求路径的初始信息
- 方法:设置映射请求请求路径的具体信息
@Controller @RequestMapping("/test") public class RequestMappingController { // 此时请求映射所映射的请求的请求路径为:/test/testRequestMapping @RequestMapping("/testRequestMapping") public String testRequestMapping(){ return "success"; } }
-
属性:
-
value:字符串类型的数组,表示该请求映射能够匹配多个请求地址所对应的请求(通过请求的请求地址匹配请求映射)
@RequestMapping(value = {"/testRequestMapping", "/test"}) public String testRequestMapping(){ return "success"; }
-
method:RequestMethod类型的数组,表示该请求映射能够匹配多种请求方式的请求(通过请求的请求方式匹配请求映射)
若请求地址满足请求映射的value属性,但请求方式不满足method属性,则浏览器报错405:Request method 'POST' not supported@RequestMapping( value = {"/testRequestMapping", "/test"}, method = {RequestMethod.GET, RequestMethod.POST} ) public String testRequestMapping(){ return "success"; }
-
-
派生注解
@GetMapping:处理get请求的映射
@PostMapping:处理post请求的映射
@PutMapping:处理put请求的映射
@DeleteMapping:处理delete请求的映射
-
-
@RequestParam
- 功能:请求参数中的名称和属性名不同的处理
- 属性:
public String requestparam(@RequestParam(value="user_id",required=false) String userId)
- value:参数名字,即入参的请求参数名字
- required:是否必须,默认是true,表示请求中一定要有相应的参数,否则将报400
- defaultValue:默认值,如果请求中没有同名参数时,设置该参数,自动将required设为false
-
@ResponseBody:支持将返回值放到 response 内,而不是一个页面,通常用户返回 json 数据。将内容或对象作为 HTTP 响应正文返回,并调用适合HttpMessageConverter的Adapter转换对象,写入输出流
- 作用:读取 Request 请求的 body 部分数据,使用系统默认配置的 HttpMessageConverter 进行解析,然后把相应的数据绑定到要返回的对象上。再把 HttpMessageConverter 返回的对象数据绑定到 controller 中方法的参数上(该方法的返回结果直接写入HTTP Response Body)
- 使用场景:
- GET、POST方式提时, 根据 request header Content-Type的值来判断:
- application/x-www-form-urlencoded, 可选(即非必须,因为这种情况的数据@RequestParam, @ModelAttribute也可以处理,当然@RequestBody也能处理)
- multipart/form-data, 不能处理(即使用@RequestBody不能处理这种格式的数据)
- 其他格式, 必须(其他格式包括application/json, application/xml等。这些格式的数据,必须使用@RequestBody来处理)
- PUT方式提交时, 根据 request header Content-Type的值来判断:
- application/x-www-form-urlencoded, 必须
- multipart/form-data, 不能处理
- 其他格式, 必须
说明:request 的 body 部分的数据编码格式由 header 部分的 Content-Type 指定
- GET、POST方式提时, 根据 request header Content-Type的值来判断:
-
@RequestBody
- 作用:该注解用于将 Controller 的方法返回的对象,通过适当的 HttpMessageConverter 转换为指定格式后,写入到 Response 对象的 body 数据区
- 使用场景:返回的数据不是html标签的页面,而是其他某种格式的数据时(如json、xml等)使用@PostMapping方法参数传@RequestBody
-
@PathVariable
用于接收路径参数,比如@RequestMapping(“/hello/{name}”)声明的路径,将注解放在参数前,即可获取该值,通常作为Restful的接口实现方法@RequestMapping(value="/users/{userId}/topics/{topicId}") public String test( @PathVariable(value="userId") int userId, @PathVariable(value="topicId") int topicId) { }
- @RestControllerAdvice:对 Controller 进行增强的,可以全局捕获 SpringMVC 抛的异常
- @RequestHeader 注解
作用:绑定请求报头的属性值,将请求头中的属性值绑定到处理方法的入参中
public String testRequestHeader(@RequestHeader("Accept-Language") String accpetLanguage) {}
- @CookieValue
作用:让处理方法入参绑定某个 Cookie 值
public String testCookieValue(@CookieValue("JSESSIONID") String sessionId) {}
SpringMVC请求响应
SpringMVC处理请求
获取请求参数
通过Servlet API获取
将 HttpServletRequest 作为控制器方法的形参,此时 HttpServletRequest 类型的参数表示封装了当前请求的请求报文的对象
@RequestMapping("/testParam")
public String testParam(HttpServletRequest request){
String username = request.getParameter("username");
String password = request.getParameter("password");
System.out.println("username:"+username+",password:"+password);
return "success";
}
HttpServletRequest
继承自 ServletRequest 接口,其主要作用是封装 HTTP 请求消息(请求行 + 请求头 + 消息体)
获取请求行信息:
- String getMethod(): 获取HTTP请求消息中的请求方式(如GET、POST等)
- String getRequestURI():获取请求行中资源名称部分,位于URL的主机和端口之后、参数部分之前的部分
- String getQueryString():获取请求行中的参数部分,也就是URL中后面问号(?)以后的所有内容
- String getProtocol():获取请求行中的协议名和版本,例如,HTTP/1.0或HTTP/1.1
- String getContextPath():获取请求URL中属于WEB应用程序的路径,这个路径以“/”开头,表示相对于整个WEB站点的根目录,路径结尾不含“/”。如果请求URL属于WEB站点的根目录,那么返回结果为空字符串(")
- String getServletPath():获取Servlet的名称或Servlet所映射的路径
- String getRemoteAddr():获取请求客户端的IP地址,其格式类似于“192.168.0.3”
- String getRemoteHost():获取请求客户端的完整主机名,其格式类似于”localhost”。需要注意的是,如果无法解析出客户机的完整主机名,该方法将会返回客户端的IP地址
- int getRemotePort():获取请求客户端网络连接的端口号
- String getL.ocalAddr():获取Web服务器上接收当前请求网络连接的IP地址
- String getL.ocalName():获取Web服务器上接收当前网络连接IP所对应的主机名
- int getL.ocalPort():获取Web服务器上接收当前网络连接的端口号
- String getServerName():获取当前请求所指向的主机名,即HTTP请求消息中Host头对应的主机名部分
- int getserverfPort():获取当前请求所连接的服务器端口号,即如果HTTP请求消息中Host头字段所对应的端口号部分
- String getScheme():获取请求的协议名,例如HTTP、HTTPS或FTP
- StringBuffer getRequestURL():获取客户端发出请求时的完整URL,包括协议、服务器名、端口号、资源路径等信息,但不包括后面的查询参数部分。注意,getRequestURL0方法返回的结果是StringBuffer类型,而不是String类型,这样更便于对结果进行修改
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 设置返回客户端的contentType
// text/plain :纯文本格式 设置为text/html println的换行会失效,可以添加<br>换行标签
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
// 获取请求行的相关信息
out.println("HttpServletRequest对象获取请求行信息方法示例:<br>");
out.println("getMethod : " + request.getMethod() + "<br>");
out.println("getRequestURI : " + request.getRequestURI() + "<br>");
out.println("getQueryString:" + request.getQueryString() + "<br>");
out.println("getProtocol : " + request.getProtocol() + "<br>");
out.println("getContextPath:" + request.getContextPath() + "<br>");
out.println("getServletPath : " + request.getServletPath() + "<br>");
out.println("getRemoteAddr : " + request.getRemoteAddr() + "<br>");
out.println("getRemoteHost : " + request.getRemoteHost() + "<br>");
out.println("getRemotePort : " + request.getRemotePort() + "<br>");
out.println("getLocalAddr : " + request.getLocalAddr() + "<br>");
out.println("getLocalName : " + request.getLocalName() + "<br>");
out.println("getLocalPort : " + request.getLocalPort() + "<br>");
out.println("getServerName : " + request.getServerName() + "<br>");
out.println("getServerPort : " + request.getServerPort() + "<br>");
out.println("getScheme : " + request.getScheme() + "<br>");
out.println("getRequestURL : " + request.getRequestURL() + "<br>");
}
获取请求头信息:
- String getHeader(String name):获取一个指定头字段的值,如果请求消息中没有包含指定的头字段,getHeader0方法返回null;如果请求消息中包含有多个指定名称的头字段,getHeader0方法返回其中第一个头字段的值
- Enumeration getHeaders(String name):返回一个Enumeration集合对象,该集合对象由请求消息中出现的某个指定名称的所有头字段值组成。在多数情况下,一个头字段名在请求消息中只出现一次,但有时候可能会出现多次
- Enumeration getHeaderNames():获取一个包含所有请求头字段的Enumeration对象
- int getIntHeader(String name):获取指定名称的头字段,并且将其值转为int类型。需要注意的是,如果指定名称的头字段不存在,返回值为-1;如果获取到的头字段的值不能转为int类型,将发生NumberFormatException异常
- long getDateHeader(String name):获取指定头字段的值,并将其按GMT时间格式转换成一个代表日期/时间的长整数,这个长整数是自1970年1月1日0点0分0秒算起的以毫秒为单位的时间值
- String getContentType():该方法用于获取Content-Type头字段的值
- int getContentLength():获取Content-Length头字段的值
- String getCharacterEncoding():返回请求消息的实体部分的字符集编码,通常是从Content-Type头字段中进行提取
- Cookie] getCookies():该方法用与获取所有的客户端传来的cookie对象,如果客户端没有发送cookie,则返回null
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//获取请求行信息
//...
out.println("<hr/>");
out.println("HttpServletRequest对象获取请求头信息方法示例:<br>");
out.println("getHeaderNames,all headers info as follows:" + "<br>");
// 获取请求消息中所有头字段
Enumeration headerNames = request.getHeaderNames();
// 使用循环遍历所有请求头,并通过getHeader()方法获取一个指定名称的头字段
while (headerNames.hasMoreElements()) {
String headerName = (String) headerNames.nextElement();
out.print(headerName + " : " + request.getHeader(headerName) + "<br>");
}
out.println("getCookies,all cookies info as follows:" + "<br>");
Cookie []cookies = request.getCookies();
for(Cookie cookie: cookies) {
out.println(cookie.getName() + ":" + cookie.getValue() + "<br>");
}
}
获取请求参数:
- String getParameter(String name):获取某个指定名称的参数值,如果请求消息中没有包含指定名称的参数,getParameter()方法返回null;如果指定名称的参数存在但没有设置值,则返回一个空串;如果请求消息中包含有多个该指定名称的参数,getParameter()方法返回第一个出现的参数值
- String[] getParameter Values(String name):HTTP请求消息中可以有多个相同名称的参数(通常由一个包含有多个同名的字段元素的FORM表单生成),如果要获得HTTP请求消息中的同一个参数名所对应的所有参数值,那么就应该使用getParameterValues()方法,该方法用于返回一个String类型的数组
- Enumeration getParameterNames):返回一个包含请求消息中所有参数名的Enumeration对象,在此基础上,可以对请求消息中的所有参数进行遍历处理
- Map getParameterMap):将请求消息中的所有参数名和值装入进一个Map对象中返回
HttpServletResponse
设置响应状态码:
- void setStatus(int sc):设置此次给客户端响应的状态码
- void sendError(int sc):指定的状态码向客户端返回一个错误响应,并且清空缓冲区
- void sendError(int sc, String msg):指定状态码和状态描述向客户端返回一个错误响应,并清空缓冲区
//设置返回客户端的contentType
response.setContentType("text/html;charset=utf-8");
//设置状态码
response.setStatus(500);
//response.sendError(500);
//获取输出流
PrintWriter out = response.getWriter();
设置响应消息头:
- setContentTypeString type():设定Content-Type消息头
- setContentLength(int length):设定Content-Length消息头
- setCharacterEncoding(String charset):设定返回给客户端的内容的编码方式
- addHleader(Sting name, String value):新增String类型的值到名为name的header
- addlntHeader(Sting name, String value):新增int类型的值到名为name的header
- addDateHeader(Sting name, long date):以毫秒数新增类型为Date的header
- addCookie():为Set-Cookie消息头增加一个值
setContentType("text/html; charset=UTF-8")
==setContentType("text/html"); + setCharacterEncoding("charset=UTF-8")
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置返回客户端的contentType
response.setContentType("text/html;charset=utf-8");
//添加类型为String的header
response.addHeader("Location", "#");
//添加类型为long的header
response.addDateHeader("Date", new Date().getTime());
//创建一个Cookie
Cookie cookie = new Cookie("name", "hefery");
//添加一个cookie
response.addCookie(cookie);
}
发送响应消息体:
- ServletOutputStream getOutputStream():返回一个适合写入二进制数据 ServletOutputStream 对象,并通过调用 flush() 提交这次响应
- PrintWriter getWriter():返回一个 PrintWriter对 象,该对象可以将字符文本发送到客户端
这两个方法在一个response对象中不可以同时调用,否则会抛出一个IllegalStateException
直接接收请求参数
@RequestMapping("/hello")
public String test(String username, String password, int age, Model model) {
System.out.println(username+"--"+password+"--"+age);
model.addAttribute("msg", "hello springmvc ~~");
return "hello";
}
使用JavaBean接收
@RequestMapping("/hello")
public String test(User user, Model model){
System.out.println(user);
model.addAttribute("msg", "hello springmvc~~");
return "hello";
}
路径占位符
- ?:表示任意的单个字符
- *:表示任意的 0 个或多个字符
@RequestMapping("/testRest/{id}/{username}") public String testRest(@PathVariable("id") String id, @PathVariable("username") String username){ System.out.println("id:"+id+",username:"+username); return "success"; }
请求参数类型
-
获得基本类型参数:public void save(String username)
Controller中业务方法的参数名要与请求参数的name一致,参数值会自动映射匹配,并能自动做类型转换 -
获得 JavaBean 类型参数:public void save(User user)
Controller中业务方法的POJO的属性名与请求参数的name一致,参数值会自动映射匹配 -
获得数组类型参数:public void save(String[] strs)
Controller中业务方法数组名称与请求参数的name一致,参数值会自动映射匹配 -
获得集合类型参数:public void save(VO vo)
获得集合参数时,要将集合参数包装到一个 JavaBean 中才可以<form action="${pageContext.request.contextPath}/user/quick" method="post"> <%--表明是第一个User对象的username age--%> <input type="text" name="userList[0].username"><br/> <input type="text" name="userList[0].age"><br/> <input type="text" name="userList[1].username"><br/> <input type="text" name="userList[1].age"><br/> <input type="submit" value="提交"> </form> public class VO { private List<User> userList; } @RequestMapping(value="/quick") @ResponseBody public void save(VO vo) throws IOException { System.out.println(vo); } 当ajax提交时,指定contentType为json形式,在方法参数位置使用@RequestBody接收集合数据而无需使用POJO <script src="${pageContext.request.contextPath}/js/jquery-3.3.1.js"></script> <script> var userList = new Array(); userList.push({username:"zhangsan",age:18}); userList.push({username:"lisi",age:28}); $.ajax({ type:"POST", url:"${pageContext.request.contextPath}/user/quick", data:JSON.stringify(userList), contentType:"application/json;charset=utf-8" }); </script> @RequestMapping(value="/quick") @ResponseBody public void save(@RequestBody List<User> userList) throws IOException { System.out.println(userList); }
SpringMVC响应数据
响应数据类型
ModelAndView
ModelAndView 对象是指"模型(数据)与视图(界面)"对象,通过 ModelAndView 可将包含数据对象与模板引擎进行绑定
Model
ModelMap
返回字符串、对象或集合
域对象共享数据
域共享方式
- 使用 Servlet API 向 request 域对象共享数据
@RequestMapping("/testServletAPI") public String testServletAPI(HttpServletRequest request){ request.setAttribute("testScope", "hello,servletAPI"); return "success"; }
- 使用 ModelAndView 向 request 域对象共享数据
@RequestMapping("/testModelAndView") public ModelAndView testModelAndView(){ /** * ModelAndView有Model和View的功能 * Model主要用于向请求域共享数据 * View主要用于设置视图,实现页面跳转 */ ModelAndView mav = new ModelAndView(); // 向请求域共享数据 mav.addObject("testScope", "hello,ModelAndView"); // 设置视图,实现页面跳转 mav.setViewName("success"); return mav; }
- 使用 Model 向 request 域对象共享数据
@RequestMapping("/testModel") public String testModel(Model model){ model.addAttribute("testScope", "hello,Model"); return "success"; }
- 使用 Map 向 request 域对象共享数据
@RequestMapping("/testMap") public String testMap(Map<String, Object> map){ map.put("testScope", "hello,Map"); return "success"; }
- 使用 ModelMap 向 request 域对象共享数据
@RequestMapping("/testModelMap") public String testModelMap(ModelMap modelMap){ modelMap.addAttribute("testScope", "hello,ModelMap"); return "success"; }
域共享区域
- 向 session 域共享数据
@RequestMapping("/testSession") public String testSession(HttpSession session){ session.setAttribute("testSessionScope", "hello,session"); return "success"; }
- 向 application 域共享数据
@RequestMapping("/testApplication") public String testApplication(HttpSession session){ ServletContext application = session.getServletContext(); application.setAttribute("testApplicationScope", "hello,application"); return "success"; }
SpringMVC视图
作用:渲染数据,将模型Model中的数据展示给用户
种类
-
转发视图
SpringMVC中默认的转发视图是InternalResourceView
SpringMVC中创建转发视图的情况:当控制器方法中所设置的视图名称以"forward:"为前缀时,创建InternalResourceView视图,此时的视图名称不会被SpringMVC配置文件中所配置的视图解析器解析,而是会将前缀"forward:"去掉,剩余部分作为最终路径通过转发的方式实现跳转。例如"forward:/","forward:/employee"@RequestMapping("/testForward") public String testForward(){ // request.getRequestDispatcher("/WEB-INF/views/success.vue").forward(request, response); return "forward:/testHello"; }
-
重定向视图
SpringMVC中默认的重定向视图是RedirectView
当控制器方法中所设置的视图名称以"redirect:"为前缀时,创建RedirectView视图,此时的视图名称不会被SpringMVC配置文件中所配置的视图解析器解析,而是会将前缀"redirect:"去掉,剩余部分作为最终路径通过重定向的方式实现跳转。例如"redirect:/","redirect:/employee"@RequestMapping("/testRedirect") public String testRedirect(){ // response.sendRedirect("http://www.baidu.com"); return "redirect:/testHello"; }
RESTful
REST:Representational State Transfer,表现层资源状态转移
HTTP协议操作资源:GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删除资源
操作 | 传统方式 | REST风格 |
---|---|---|
查询操作 | getUserById?id=1 | user/1 |
保存操作 | saveUser | user |
删除操作 | deleteUser?id=1 | user/1 |
更新操作 | updateUser | user |
PS:浏览器只支持发送get和post方式的请求
- 注解
-
@RequestBody
功能:获取请求体,需要在控制器方法设置一个形参,使用@RequestBody进行标识,当前请求的请求体就会为当前注解所标识的形参赋值<form th:action="@{/testRequestBody}" method="post"> 用户名:<input type="text" name="username"><br> 密码:<input type="password" name="password"><br> <input type="submit"> </form>
@RequestMapping("/testRequestBody") public String testRequestBody(@RequestBody String requestBody){ System.out.println("requestBody:"+requestBody); return "success"; }
输出结果:requestBody:username=admin&password=123456
-
@ResponseBody
功能:标识一个控制器方法,可以将该方法的返回值直接作为响应报文的响应体响应到浏览器@RequestMapping("/testResponseBody") @ResponseBody public String testResponseBody(){ return "success"; }
结果:浏览器页面显示success
-
@RestController
-
SpringMVC相关
SpringMVC处理JSON
在处理器方法上使用 @ResponseBody 注解进行标识,将Java对象直接作为控制器方法的返回值返回,就会自动转换为 JSON 格式的字符串
@RequestMapping("/testResponseUser")
@ResponseBody
public User testResponseUser(){
return new User(1001,"admin","123456",23,"男");
}
浏览器的页面中展示的结果:{"id":1001,"username":"admin","password":"123456","age":23,"sex":"男"}
SpringMVC处理AJAX
请求超链接
<div id="app">
<a th:href="@{/testAjax}" @click="testAjax">testAjax</a><br>
</div>
vue和axios处理点击事件
<script type="text/javascript" th:src="@{/static/js/vue.js}"></script>
<script type="text/javascript" th:src="@{/static/js/axios.min.js}"></script>
<script type="text/javascript">
var vue = new Vue({
el:"#app",
methods:{
testAjax:function (event) {
axios({
method:"post",
url:event.target.href,
params:{
username:"admin",
password:"123456"
}
}).then(function (response) {
alert(response.data);
});
event.preventDefault();
}
}
});
</script>
@RequestMapping("/testAjax")
@ResponseBody
public String testAjax(String username, String password){
System.out.println("username:"+username+",password:"+password);
return "hello,ajax";
}
@ControllerAdvice 将当前类标识为异常处理的组件
Nacos = Eureka/Consule + Config + Admin
Sentinel = Hystrix + Dashboard + Turbine
Schedulerx = Quartz
基于Token的鉴权机制
基于token的鉴权机制类似于http协议也是无状态的,它不需要在服务端去保留用户的认证信息或者会话信息
这就意味着基于token认证机制的应用不需要去考虑用户在哪一台服务器登录了,这就为应用的扩展提供了便利
鉴权流程:
- 用户使用用户名+密码来请求服务器
- 服务器进行验证用户的信息
- 服务器通过验证发送给用户一个token
- 客户端存储token,并在每次请求时附送上这个token值
- 服务端验证token值,并返回数据
这个token必须要在每次请求时传递给服务端,它应该保存在请求头里,另外,服务端要支持CORS(跨来源资源共享)策略
JWT的构成
-
头部(header): 将头部进行base64加密
{ 'typ': 'JWT', # 类型 'alg': 'HS256' # 加密算法 }
-
载荷(payload): 存放有效信息
-
标准中注册的声明
iss: jwt签发者 sub: jwt所面向的用户 aud: 接收jwt的一方 exp: jwt的过期时间,这个过期时间必须要大于签发时间 nbf: 定义在什么时间之前,该jwt都是不可用的. iat: jwt的签发时间 jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击
-
公共的声明
添加用户的相关信息或其他业务需要的必要信息 不建议添加敏感信息
-
私有的声明
提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息 { "sub": "1234567890", "name": "John Doe", "admin": true }
-
-
签证(signature):header (base64后) . payload (base64后) . secret
-
需要base64加密后header和base64使用
.
连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密String encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload); String signature = HMACSHA256(encodedString, 'secret');
-
自定义拦截器
创建拦截器类实现HandlerInterceptor接口,重写preHandle、postHandle、afterCompletion