springMVC学习笔记-请求映射,参数绑定,响应,restful,响应状态码,springMVC拦截器

目录

概述

springMVC做了什么

springMVC与struts2区别

springMVC整个流程是一个单向闭环

springMVC具体的处理流程

springMVC的组成部分

请求映射

@RequestMapping

用法

属性

1.value

2.method

GET方式和POST方式

概述

HTTP给GET和POST做了哪些规定

GET方式,url参数中有+、空格、=、%、&、#等特殊符号的问题解决

参数绑定

1.默认支持的参数类型

2.绑定简单类型自动绑定

3.@RequestParam手动绑定

属性

4.实体类属性自动绑定

5.Map绑定

6.绑定数组类型

7.绑定List类型

8.绑定日期类型

9.@RequestBody

绑定String,直接接收到请求体JSON串

绑定Map

绑定实体类

绑定数组/集合

@RequestBody与@RequestParam()同时使用

实际上,@RequestBody之外的参数可以是2-8上提到的任意方式,相当于请求体和url上的参数是隔离的

总结

JSON

1.什么是JSON

2.结构

响应(接口返回值)

转发和重定向

void

@ResponseBody

restful风格

特点

URI等价于资源

统一HTTP方法分类

统一返回数据格式

从URL上获取参数

POJO

响应状态码

1xx

2xx

3xx

4xx

5xx

springMVC拦截器

创建和配置

配置多个拦截器时的执行顺序


概述

springMVC是spring框架体系的一部分,功能和struts2类似,可以完美替代struts2,可以认为struts2已经被淘汰

随着前后端分离和springboot的普及,我们不再需要关注xml配置,也不关注Model,View相关的接口返回值,此处只关注springMVC本身

springMVC做了什么

简化了请求的接收和处理,不再需要开发者针对每个请求编写Servlet,重写方法接收请求,也不再需要关注参数转换,大量减少了代码量

springMVC与struts2区别

1.springmvc入口是一个servlet,即前端控制器;struts2入口是filter过滤器(配置很多拦截器)

2.springmvc基于方法开发,请求参数传递到方法,可以为单例或者多例;struts2是基于类开发,方法只能通过类的参数接收,只能为多例

3.springmvc解析request请求内容,把请求参数和映射方法的形参绑定,将数据封装成ModelAndView返回给前端解析;struts2是通过值栈方式存储请求和响应数据,通过OGNL存取数据

springMVC整个流程是一个单向闭环

用户(输入)--->控制器controller,将用户输入分发给业务模型--->模型model,进行业务逻辑判断,数据库存取--->视图view,根据需要渲染不同的视图--->用户(获得反馈)

springMVC具体的处理流程

1.用户请求-被前端控制器拦截DispatcherServlet

2.DispatcherServlet接收到请求以后调用HandlerMapping处理器映射器

3.HandlerMapping根据请求的url找到对应的Handler处理器,生成处理器对象和拦截器返回给dispatcher

4.DispatcherServlet通过HandlerAdapter处理器适配器调用Handler处理器

5.执行处理器(即Controller)

6.执行结果ModelAndView通过HandlerAdapter返回给DispatcherServlet

7.DispatcherServlet将ModelAndView传给ViewReslover视图解析器

8.ViewReslover解析后返回具体的View给DispatcherServlet

9.DispatcherServlet对View进行渲染(填充数据)

10.DispatcherServlet将最终的结果返回给客户

springMVC的组成部分

部分组件会默认加载,程序员需要开发的是Handler和View,也就是接收请求后的业务处理和前端页面

DispatcherServlet 前端控制器:这是mvc流程的核心,通过DispatcherServlet调用其他组件处理请求,降低了组件间的耦合

HandlerMapping 处理器映射器:根据请求的url找到对应的Handler

Handler 处理器:在DispatcherServlet控制下进行请求的业务操作,这是程序员开发的主要内容

HandlAdapter 处理器适配器:DispatcherServlet通过HandlerAdapter处理器适配器调用Handler处理器

ViewResolver 视图解析器:ViewResolver负责将处理结果生成View视图,ViewResolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,DispatcherServlet对View进行渲染将处理结果通过页面展示给用户

View 视图:springmvc框架提供了很多的View视图类型的支持,包括:jstlView、freemarkerView、pdfView等

请求映射

@RequestMapping

定义请求映射规则,接收并处理请求

用法

1.注解在类上:访问该类所有方法都要加上该前置路径

2.注解在方法上:访问该方法的映射路径

属性

1.value

映射路径,如果只有value属性,则value="/xxxx"的value=可以省略

@RequestMapping(value="/xx/xx"),@RequestMapping("/xx/xx")

value的值是数组,可以将多个url映射到同一个方法

@RequestMapping(value={"/xx/xx","xx/xxx"})

2.method

限制请求方法类型

RequestMethod.GET,RequestMethod.POST

@RequestMapping(value = "/xxx/person/get/{id}", method = RequestMethod.GET)
public ApiResult getPersonById(@PathVariable Integer id) {...Person person = ...return ApiResult.success(person);
}

GET方式和POST方式

概述

GET方式和POST方式是HTTP协议中两种发送请求的方式

HTTP是基于TCP/IP的,关于数据如何在网络中传递的协议

因此,GET和POST本质上都是基于TCP/IP的发送请求的方式,在底层上说,并没有本质的区别

GET和POST的区别是由HTTP协议规定的,HTTP这么规定是为了给各式各样的请求分类

换句话说,并不是GET请求和POST有什么区别,你如果想要GET请求使用RequestBody传参,并不是不行,所谓的区别只是HTTP协议做出的规定

HTTP给GET和POST做了哪些规定

参数传递渠道:

GET:拼接到url上

POST:放在请求体中(RequestBody)

长度限制:

GET:由浏览器决定,通常为2k,最多64k

POST:理论上无限制

TCP数据包:

GET:发送一次请求,产生一个TCP数据包

POST:发送两次请求,先发送请求头Header,获取到响应后再发送RequestBody,产生两个TCP数据包,但要注意并不是所有浏览器都严格遵循这样的规定,即有的浏览器POST也只发送一次

GET方式,url参数中有+、空格、=、%、&、#等特殊符号的问题解决

问题:Url出现了有+,空格,/,?,%,#,&,=等特殊符号的时候,可能在服务器端无法获得正确的参数值

问题原因:为何Url中有这些字符就会出现问题,这涉及到URL编码与解码

URL编码与解码,网络标准RFC 1738做了硬性规定:

只有字母和数字[0-9a-zA-Z]、一些特殊符号”$-_.+!*’(),”[不包括双引号]、以及某些保留字,才可以不经过编码直接用于URL

这意味着,如果URL中有汉字,等特殊字符的时候,就必须编码后使用。而+,空格,/,?,%,#,&,=,这些字符(不安全),当把他们直接放在Url中的时候,可能会引起解析程序的歧义,因此也必须经过编码才能使用

解决办法:将这些字符转化成服务器可以识别的字符,对应关系如下:

+ URL中+号表示空格 %2B

空格 URL中的空格可以用+号或者编码 %20

/ 分隔目录和子目录 %2F

? 分隔实际的URL和参数 %3F

% 指定特殊字符 %25

# 表示书签 %23

& URL 中指定的参数间的分隔符 %26

= URL 中指定参数的值 %3D

参数绑定

1.默认支持的参数类型

处理器形参中添加如下类型的参数处理适配器会默认识别并进行赋值

HttpServletRequest 通过域对象传递参数,包含请求的详细信息,不仅仅是参数

HttpServletResponse 处理响应信息

HttpSession 获取session中存放的对象

2.绑定简单类型自动绑定

整形:Integer、int

字符串:String

单精度:Float、float

双精度:Double、double

布尔型:Boolean、boolean

只要Controller形参和请求参数名称能匹配上就可以接收值

通常使用包装类,因为基本数据类型不能为null值

通常有多个参数,会封装成POJO,可以方便数据的进一步使用

@RequestMapping(value = "/xxx/person/getById", method = RequestMethod.GET)
public ApiResult getPersonById(Integer id) {...Person person = ...return ApiResult.success(person);
}

3.@RequestParam手动绑定

将Controller形参和请求参数名称手动绑定,字段名称不一致时可以这样,但通常不这样

@RequestMapping(value = "/xxx/person/getByName", method = RequestMethod.GET)
public ApiResult getPersonById(@RequestParam(value="paramName")String name) {    //这样就将Controller的形参name和请求传递的参数paramName绑定了...Person person = ...return ApiResult.success(person);
}

属性

value 指定绑定的请求参数名称

required 是否必须有值,false/true,默认是true,此时入参为空会报错TTP Status 400 - Required parameter 'XXXX' is not present

defaultValue 默认值,没有值的时候赋默认值

4.实体类属性自动绑定

请求参数名称和实体类属性名一致,会自动将请求参数赋值给实体类的属性

@RequestMapping("/updateCustomer")
public String update(Customer customer) {...
}

5.Map绑定

@RequestMapping(value = "/getCustomerListPage")
@ResponseBody
public ApiResult getCustomerListPage(@RequestParam(required = false) Map<Object, Object> customerParams) {List<Customer> customerList = customerService.getCustomerListPage(customerParams);return ApiResult.success();
}

6.绑定数组类型

页面选中多个checkbox向controller方法传递,本身属于一个form表单,此时需要用数组参数接收该请求参数,参数名是checkbox的name

@RequestMapping(value = "/xxx/person/getByIds")
public ApiResult getPersonById(Integer[] ids) {...List<Person> personList = ...return ApiResult.success(personList);
}

7.绑定List类型

List是一个接口,不能直接实例化,因此无法直接绑定,要使用实现类来绑定,比如ArrayList,如果直接绑定ArrayList,还需要加上@RequestParam,这是由参数解析器决定的;

通常我们不这么做,而是通过将List放入实体类中进行绑定

//通过@RequestParam绑定
@RequestMapping(value = "/getCustomerListPage")
@ResponseBody
public ApiResult getCustomerListPage(@RequestParam(required = false) ArrayList<Integer> idList) {List<Customer> customerList = customerService.getCustomerListPage(idList);return ApiResult.success();
}//通过实体类绑定
@RequestMapping(value = "/xxx/person/getByIds")
public ApiResult getPersonById(PersonParams personParams) {...List<Person> personList = ...return ApiResult.success(personList);
}pulic class PersonParams {private List<Integer> idList;public List<Integer> getIdList() {...    }...
}

8.绑定日期类型

日期比较特殊,因为前台控件在提交的时候都是String,所以接收的时候不能直接用日期类型

当然可以自定义转换类来实现自定义参数绑定,但通常不这么做,而是使用实体类接收,在对应的成员上通过注解实现自动转换

@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")

@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")

9.@RequestBody

上面的2到8种参数绑定,都需要我们把参数放到请求上,如果我们的参数是放在请求体RequestBody中,会发现接收到的都是null,那么怎么获取RequestBody中的参数呢

通过@RequestBody注解

注意:

请求体RequestBody是以JSON字符串的方式传递

一个接口只能定义一个@RequestBody,因为浏览器只会发送一个RequestBody

@RequestBody虽然不可以定义两个,但除了@RequestBody之外,还可以定义别的参数来接收url上的参数

绑定String,直接接收到请求体JSON串

不可以直接绑定单个Integer之类的参数,只能以String传递

@RequestMapping(value = "/getCustomerListPage")
@ResponseBody
public ApiResult getCustomerListPage(@RequestBody String i) {//这里的i是请求体的整个JSON串,比如{
"i": "1"
}return ApiResult.success();
}

绑定Map

@RequestMapping(value = "/getCustomerListPage")
@ResponseBody
public ApiResult getCustomerListPage(@RequestBody Map map) {return ApiResult.success();
}

绑定实体类

入参key要和实体类中属性名一致

@RequestMapping(value = "/getCustomerListPage")
@ResponseBody
public ApiResult getCustomerListPage(@RequestBody CustomerParams customerParams) {return ApiResult.success();
}

绑定数组/集合

元素可以是基本类型包装类,实体类,Map

@RequestMapping(value = "/getCustomerListPage")
@ResponseBody
public ApiResult getCustomerListPage(@RequestBody List<Integer> idList) {return ApiResult.success();
}
@RequestMapping(value = "/getCustomerListPage")
@ResponseBody
public ApiResult getCustomerListPage(@RequestBody CustomerParams[] customerParamsArr) {return ApiResult.success();
}
@RequestMapping(value = "/getCustomerListPage")
@ResponseBody
public ApiResult getCustomerListPage(@RequestBody List<CustomerParams> customerParamsList) {return ApiResult.success();
}

@RequestBody与@RequestParam()同时使用

即请求体和url上都有入参

@RequestMapping(value = "/getCustomerListPage")
@ResponseBody
public ApiResult getCustomerListPage(@RequestBody CustomerParams customerParams, @RequestParam String token) {return ApiResult.success();
}//@RequestParam可以省略
@RequestMapping(value = "/getCustomerListPage")
@ResponseBody
public ApiResult getCustomerListPage(@RequestBody CustomerParams customerParams, String token) {return ApiResult.success();
}

实际上,@RequestBody之外的参数可以是2-8上提到的任意方式,相当于请求体和url上的参数是隔离的

@RequestMapping(value = "/getCustomerListPage")
@ResponseBody
public ApiResult getCustomerListPage(@RequestBody CustomerParams customerParams, CustomerParams customerParams2) {return ApiResult.success();
}

总结

url传参,使用参数直接绑定,可以使用多种方式绑定

请求体传参,使用@RequestBody方式绑定,@RequestBody可以直接绑定多种形式

换句话说,实际上数据绑定方式与请求方式没有必然关系,直接绑定参数是接收url参数,@RequestBody是接收请求体参数

而因为浏览器对GET,POST的规定,显然,POST请求需要用@RequestBody接收,GET请求需要直接绑定的方式接收

JSON

1.什么是JSON

JSON(JavaScript Object Notation),是一种轻量级的数据交换格式,是一个字符串

简单的说就是javascript中的对象和数组

2.结构

1.对象:{}括起来的内容,结构为键值对,可以嵌套,通过对象名.key取值

2.数组:[]括起来的内容,结构为["xxx","xxxx",...],通过索引取值

{"animals": {"dog": [{"name": "wangcai","age":15},{"name": "Marty","age": null}]}
}
animals.dog[0].name为wangcai

响应(接口返回值)

再次强调,在前后端分离的背景下,此处不过多关注Model,View,static页面

@RequestMapping("/index")
public String toIndex() {return "/index";                //返回static/index页面
}
@RequestMapping("/index")
public String toIndex() {return "redirect:/index";       //重定向到static/index页面
}
@RequestMapping("/index")
public String toIndex(Model model) {model.addAttribute("message", "这是index页面");    //可以通过Model传递数据return "/index";                //返回static/index页面
}
@RequestMapping(value = "/index", method = RequestMethod.GET)
public ModelAndView toIndex() {ModelAndView mv = new ModelAndView();mv.addObject("message", "这是index页面");mv.setViewName("/index");return mv;                      //通过ModelAndView返回
}

转发和重定向

重定向,重定向到别的url,通常是个页面,操作完这一步打开一个新的页面

重定向会使用新的request和response

return "redirect:/newPage?userId=" + vo.getId();

转发,执行后继续执行另一个url,通常为Controller

request和response仍然为最初的,所以数据还在,不需要像重定向那样跟参数

return "forward:/edit";

void

接口可以没有返回值

@RequestMapping("/save")
public void save() {sout("save");
}

@ResponseBody

在前后端分离的背景下,我们通常编写的都是直接返回数据的接口,如果我们要直接返回数据,而不是页面,也不通过Model去渲染,要怎么做

通过@ResponseBody注解

这个注解会通过springmvc提供的HttpMessageConverter接口转换为指定格式的数据,默认是String,然后通过Response响应给客户端

通过这个注解,我们可以实现将返回值转化为JSON字符串响应给浏览器,这个过程可以理解为数据序列化和反序列化的过程,通常我们还会定义一个类作为所有接口的统一返回格式

实际上,使用这个注解需要导入spring-web这个依赖,而如果我们需要返回JSON而不是String,还需要导入JSON相关依赖,但springboot的背景下,我们只需要导入一个spring-boot-starter-web启动器就已经包含了所需要的所有依赖和配置

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>import java.io.Serializable;
public class ApiResult implements Serializable {// 返回编码private String code;// 返回信息private String msg;// 返回数据封装private Object data = null;public static ApiResult failure(String msg) {ApiResult apiResult = new ApiResult();apiResult.setCode(ResultCodeEnum.SYS_ERROR.k());apiResult.setMsg(msg);return apiResult;}...
}@RequestMapping("/save")
@ResponseBody
public ApiResult save() {return ApiResult.failure("保存失败!");
}

restful风格

restful是一种软件开发风格,并不是什么开发规范,或者什么语法规则,只是一种约定,如果你写成这个样子,那么我们就叫你这种代码是restful

特点

URI等价于资源

每个资源对应一个URI,要获取这个资源那么访问它的URI即可,因此URI只能包含名词,URL是最典型的URI

要求资源是无状态的,对某个资源的请求不依赖其他资源/请求

即访问URI就可以获得资源,比如在OA上查看某个员工的信息,需要输入账号密码登陆系统再查看就是有状态的,而输入URI直接就可以获取就是无状态的

统一HTTP方法分类

GET        查询SELECT: 从服务器获取资源

POST        新增CREATE: 在服务器新建资源

PUT        更新UPDATE: 在服务器更新资源(客户端提供改变后的完整资源)

PATCH         更新UPDATE: 在服务器更新资源(客户端提供改变的属性)

DELETE        删除DELETE: 从服务器删除资源

统一返回数据格式

使用JSON串返回

针对不同操作,服务器向用户返回的结果应该符合以下规范

GET        返回单个资源对象/资源对象的列表(数组)

POST        返回新生成的资源对象

PUT        返回完整的资源对象

PATCH        返回完整的资源对象

DELETE        返回空

从URL上获取参数

restful风格要求资源通过URI直接定位,所以参数会拼写在URL中

使用占位符{}进行这样的拼接,使用@PathVariable()获取url路径上的参数

@Pathvariable()常用属性

name/value 绑定占位符名称

required 早期不支持这个属性

        如果配置fasle,意味着url中的路径那个占位符就为空了,将不会拼接到url

        那么@RequestMapping就需要映射多个url,变为@RequestMapping(value = "xxx/people/age/{age}", "xxx/people/age")

@RequestMapping("xxx/people/age/{age}")
public List<people> getPeopleByAge(@PathVariable() Integer age) {
...
}

POJO

POJO(plain ordinary java object) 简单无规则java对象

最基本的对象,没有实现任何接口,继承任何类,只包含属性,getter,setter,可以迁移和复用,比如生成PO,DTO,VO都可以直接继承POJO

PO(persistant object) 持久对象

数据库映射对象,属性与数据库对应表的字段对应

DAO(data access object 数据访问对象)

提供数据库的CRUD操作

DTO (Data Transfer Object)数据传输对象

输入:接口接收传入对象

输出:接口返回数据,此时会被改写为VO

VO( View Object 显示层对象)

页面需要很多DTO之外的信息,比如code,message等等,VO=DTO+其它信息

响应状态码

1xx

信息,1XX类型的状态码是临时响应,代表着请求已经被接受,但需要继续处理

100 Continue 服务器仅接收到部分请求,但是一旦服务器并没有拒绝该请求,客户端应该继续发送其余的请求

101 Switching Protocols 服务器转换协议:服务器将遵从客户的请求转换到另外一种协议。

102 Processing 由WebDAV(RFC 2518)扩展的状态码,代表处理将被继续执行

2xx

成功,2XX类型的状态码代表着请求已经被服务器接收、理解、并接受

200 OK 请求成功(其后是对GET和POST请求的响应文档)

201 Created 请求被创建完成,同时新的资源被创建

202 Accepted 请求已被接受,但是处理未完成

203 Non-authoritative Information 文档已经正常地返回,但一些响应头可能不正确,因为使用的是文档的拷贝

204 No Content 没有新文档,浏览器应该继续显示原来的文档,如果用户定期地刷新页面,而Servlet可以确定用户文档足够新,这个状态代码是很有用的

205 Reset Content 没有新文档,但浏览器应该重置它所显示的内容,用来强制浏览器清除表单输入内容

206 Partial Content 客户发送了一个带有Range头的GET请求,服务器完成了它

207 Multi-Status 由WebDAV(RFC 2518)扩展的状态码,代表之后的消息体将是一个XML消息,并且可能依照之前子请求数量的不同,包含一系列独立的响应代码

3xx

重定向,3XX这类状态码代表着客户端需要采取进一步的操作才能完成请求,通常这些状态码是用来重定向的

300 Multiple Choices 多重选择,链接列表,用户可以选择某链接到达目的地,最多允许五个地址

301 Moved Permanently 所请求的页面已经转移至新的url

302 Found 所请求的页面已经临时转移至新的url

303 See Other 所请求的页面可在别的url下被找到

304 Not Modified 未按预期修改文档,客户端有缓冲的文档并发出了一个条件性的请求(一般是提供If-Modified-Since头表示客户只想比指定日期更新的文档)。服务器告诉客户,原来缓冲的文档还可以继续使用

305 Use Proxy 客户请求的文档应该通过Location头所指明的代理服务器提取

306 Unused 此代码被用于前一版本,表示当前功能目前已不再使用,但是代码依然被保留

307 Temporary Redirect 被请求的页面已经临时移至新的url

4xx

客户端错误,4XX类型的状态码代表着客户端可能发生了错误,阻碍了服务器的处理

400 Bad Request 服务器未能理解请求或是请求参数有误

401 Unauthorized 被请求的页面需要用户名和密码

402 Payment Required 此代码尚无法使用(为了将来可能的需求而预留的)

403 Forbidden 对被请求页面的访问被禁止

404 Not Found 服务器无法找到被请求的页面,url有误

405 Method Not Allowed 请求中指定的方法不被允许

406 Not Acceptable 服务器生成的响应无法被客户端所接受

407 Proxy Authentication Required 用户必须首先使用代理服务器进行验证,这样请求才会被处理

408 Request Timeout 请求超出了服务器的等待时间

409 Conflict 由于冲突,请求无法被完成

410 Gone 被请求的页面不可用

411 Length Required "Content-Length" 未被定义,如果无此内容,服务器不会接受请求

412 Precondition Failed 请求中的前提条件被服务器评估为失败

413 Request Entity Too Large 由于所请求的实体的太大,服务器不会接受请求

414 Request-url Too Long 由于url太长,服务器不会接受请求。当post请求被转换为带有很长的查询信息的get请求时,就会发生这种情况

415 Unsupported Media Type — 由于媒介类型不被支持,服务器不会接受请求

416 服务器不能满足客户在请求中指定的Range头

417 Expectation Failed

5xx

服务器错误

500 Internal Server Error 请求未完成。服务器遇到不可预知的情况

501 Not Implemented 请求未完成。服务器不支持所请求的功能

502 Bad Gateway 请求未完成。服务器从上游服务器收到一个无效的响应

503 Service Unavailable 请求未完成。服务器临时过载或当机

504 Gateway Timeout 网关超时

505 HTTP Version Not Supported 服务器不支持请求中指明的HTTP协议版本

springMVC拦截器

springmvc的拦截器可以对处理器进行预处理和后处理

创建和配置

implements HandlerInterceptor,重写方法

public class HandlerInterceptor1 implements HandlerInterceptor {/*** Controller方法执行前调用此方法* 返回true表示继续执行,返回false中止执行*/@Overridepublic boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {System.out.println("HandlerInterceptor1....preHandle");// 设置为true,测试使用,设置为false请求就被拦截了return true;}/*** controller方法执行后但未返回视图前调用此方法* 这里可以对返回数据进行统一的二次处理,比如多个页面都需要某些同样的处理*/@Overridepublic void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception {System.out.println("HandlerInterceptor1....postHandle");}/*** controller方法执行后且视图返回后调用此方法(页面渲染后)* 这里可得到执行controller时的异常信息,可以记录请求日志*/@Overridepublic void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception {System.out.println("HandlerInterceptor1....afterCompletion");}
}@Configuration
public class mvcConfig implements WebMvcConfigurer {@Autowiredprivate HandlerInterceptor1 handlerInterceptor1;@Overridepublic void add Interceptors(InterceptorRegistry registry) {// 注册拦截器,并指定要拦截的URL模式registry.addInterceptor(handlerInterceptor1).addPathPatterns("/");}
}

配置多个拦截器时的执行顺序

preHandle按拦截器定义顺序调用

postHandler按拦截器定义逆序调用

afterCompletion按拦截器定义逆序调用

postHandler在拦截器链内所有拦截器preHandle返回true才会调用

afterCompletion只要对应的preHandle返回true就调用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/197405.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HTML5学习系列之实用性标记

HTML5学习系列之实用性标记 前言实用性标记高亮显示进度刻度时间联系信息显示方向换行断点标注 总结 前言 学习记录 实用性标记 高亮显示 mark元素可以进行高亮显示。 <p><mark>我感冒了</mark></p>进度 progress指示某项任务的完成进度。 <p…

vscode编写verilog的插件【对齐、自动生成testbench文件】

vscode编写verilog的插件&#xff1a; 插件名称&#xff1a;verilog_testbench,用于自动生成激励文件 安装教程&#xff1a;基于VS Code的Testbench文件自动生成方法——基于VS Code的Verilog编写环境搭建SP_哔哩哔哩_bilibili 优化的方法&#xff1a;https://blog.csdn.net…

无需添加udid,ios企业证书的自助生成方法

我们开发uniapp的app的时候&#xff0c;需要苹果证书去打包。 假如申请的是个人或company类型的苹果开发者账号&#xff0c;必须上架才能安装&#xff0c;异常的麻烦&#xff0c;但是有一些app&#xff0c;比如企业内部使用的app&#xff0c;是不需要上架苹果应用市场的。 假…

庖丁解牛:NIO核心概念与机制详解 02 _ 缓冲区的细节实现

文章目录 PreOverview状态变量概述Position 访问方法 Pre 庖丁解牛&#xff1a;NIO核心概念与机制详解 01 接下来我们来看下缓冲区内部细节 Overview 接下来将介绍 NIO 中两个重要的缓冲区组件&#xff1a;状态变量和访问方法 (accessor) 状态变量是"内部统计机制&quo…

vmware workstation pro 17.5 安装 macos 13.5.2 虚拟机超详细图文教程

前言 本文很细&#xff0c;甚至有点墨迹&#xff0c;主要为了方便从来没用过 vmware 的新人&#xff0c;其实大部分步骤和正常安装虚拟机没有区别&#xff0c;详细贴图以方便大家对比细节 参考文章 感谢大佬们的无私分享 https://blog.csdn.net/qq_19731521/article/details…

记录将excel表无变形的弄进word里面来

之前关于这个问题记录过一篇文章&#xff1a; 将excel中的表快速复制粘贴进word中且不变形-CSDN博客 今天记录另外一种方法&#xff1a;举例表述&#xff0c;excel表如图&#xff1a; 按F12&#xff0c;出现“另存为...”对话框&#xff0c;选择“单个文件网页”&#xff0c;…

String字符串性能优化的几种方案

原创/朱季谦 String字符串是系统里最常用的类型之一&#xff0c;在系统中占据了很大的内存&#xff0c;因此&#xff0c;高效地使用字符串&#xff0c;对系统的性能有较好的提升。 针对字符串的优化&#xff0c;我在工作与学习过程总结了以下三种方案作分享&#xff1a; 一.优…

BUG:编写springboot单元测试,自动注入实体类报空指针异常

原因:修饰测试方法的Test注解导入错误 造成错误的原因是 import org.junit.Test;正确的应该是 import org.junit.jupiter.api.Test前者是Junit4,后者是Junit5 junit4的使用似乎要在测试类除了添加SpringbootTest还要添加RunWith(SpringRunner.class) 同时要注意spring-boot-s…

智能驾驶汽车虚拟仿真视频数据理解(一)

赛题官网 datawhale 赛题介绍 跑通demo paddle 跑通demo torch 提交的障碍物取最主要的那个&#xff1f;不考虑多物体提交。障碍物&#xff0c;尽可能选择状态发生变化的物体。如果没有明显变化的&#xff0c;则考虑周边的物体。车的状态最后趋于减速、停止&#xff0c;时序…

搭建网关服务器实现DHCP自动分配、HTTP服务和免密登录

目录 一. 实验要求 二. 实验准备 三. 实验过程 1. 网关服务器新建网卡并改为仅主机模式 2. 修改新建网卡IP配置文件并重启服务 3. 搭建网关服务器的dhcp服务 4. 修改server2网卡配置文件重启服务并效验 5. 设置主机1的网络连接为仅主机模式 6. 给server2和网关服务器之…

公共字段自动填充-@TableField的fill实现(2)

TheadLocal 客户端发送的每次http请求&#xff0c;在服务端都会分配新的线程。因此登录检查过滤器、controller、元数据对象处理器属于一个线程。 TheadLocal是线程的局部变量&#xff1a; TheadLocal常用方法&#xff1a; 如何在元数据对象处理器中获取当前登录用户的id&…

qt-C++笔记之两个窗口ui的交互

qt-C笔记之两个窗口ui的交互 code review! 文章目录 qt-C笔记之两个窗口ui的交互0.运行1.文件结构2.先创建widget项目&#xff0c;搞一个窗口ui出来3.项目添加第二个widget窗口出来4.补充代码4.1.qt_widget_interaction.pro4.2.main.cpp4.3.widget.h4.4.widget.cpp4.5.second…

高防IP是什么?如何隐藏源站IP?如何进行防护?

高防IP是针对互联网服务器遭受大流量的DDoS攻击后导致服务不可用的情况下,推出的付费增值服务。用户在数据不转移的情况下,就可以通过配置高防IP , 将攻击流量引流到高防|P,确保源站的稳定可靠。高防IP采用的技术手段包括DDoS防护、WAF ( Web应用程序防火墙)等,它能够有效抵御来…

C#,数值计算——插值和外推,BaryRat_interp的计算方法与源程序

1 文本格式 using System; namespace Legalsoft.Truffer { /// <summary> /// 重心有理插值对象 /// Barycentric rational interpolation object. /// After constructing the object, /// call interp for interpolated values. /// Note t…

论文阅读:JINA EMBEDDINGS: A Novel Set of High-Performance Sentence Embedding Models

Abstract JINA EMBEDINGS构成了一组高性能的句子嵌入模型&#xff0c;擅长将文本输入转换为数字表示&#xff0c;捕捉文本的语义。这些模型在密集检索和语义文本相似性等应用中表现出色。文章详细介绍了JINA EMBEDINGS的开发&#xff0c;从创建高质量的成对&#xff08;pairwi…

037、目标检测-SSD实现

之——简单实现 目录 之——简单实现 杂谈 正文 1.类别预测层 2.边界框预测 3.多尺度输出联结做预测&#xff08;提高预测效率&#xff09; 4.多尺度实现 5.基本网络块 6.完整模型 杂谈 原理查看&#xff1a;037、目标检测-算法速览-CSDN博客 正文 1.类别预测层 类别…

Newman

近期在复习Postman的基础知识&#xff0c;在小破站上跟着百里老师系统复习了一遍&#xff0c;也做了一些笔记&#xff0c;希望可以给大家一点点启发。 一&#xff09;如何安装Newman 1、下载并安装NodeJs 在官网下载NodeJs&#xff1a; Download | Node.js&#xff08;官网的…

具有mDNS功能的串口服务器

1.概述: 通过mDNS协议可以获得设备的ID、mac、IP、port等信息&#xff0c;方便计算机在同一个局域网内连接到具有该服务的模块。支持产品有串口服务器、串口转以太网模块、RS485串口转网口芯片等。 图 1 mDNS网络结构图 当具有mDNS的服务的设备接入网络的时候&#xff0c;首先…

五、Linux目录结构

1.基本介绍 1.Linux的文件系统是采用级层式的树状目录结构&#xff0c;在此结构中的最上层是根目录"r/"&#xff0c;然后在此目录下再创建其他的目录。 2.深刻理解linux树状文件目录是非常重要的 3.记住一句经典的话&#xff1a;在Linux世界里&#xff0c;一切皆文件…

酷柚易汛ERP - 序列号盘点操作指南

1、应用场景 将系统中开启序列号的商品数量与与实际存放的数量进行对比。 2、主要操作 2.1 录入序列号 打开【盘点】-【序列号盘点】&#xff0c;新增序列号盘点单&#xff0c;点击【SN】按钮&#xff0c;在弹框中输入序列号。 支持扫描枪录入序列号支持复制粘贴序列号录入…