SpringBoot-Web开发之请求映射
请求路径匹配
- Spring5.3 之后加⼊PathPatternParser 策略;以前只⽀持 AntPathMatcher 策略
Ant风格路径用法
- *:表示任意数量的字符
- ?:表示任意⼀个字符
- **:表示任意数量的⽬录
- {}:表示⼀个命名的模式占位符
- []:表示字符集合,例如[a-z]表示小写字⺟
- 要匹配⽂件路径中的星号,则需要转义为\\*
- 要匹配⽂件路径中的问号,则需要转义为\\?

PathPatternParser
- 兼容 AntPathMatcher语法,并⽀持更多类型的路径模式
- "**" 多段匹配的⽀持仅允许在模式末尾使⽤,如果路径中间需要有 **,替换成ant⻛格路径
# 改变路径匹配策略:
# ant_path_matcher ⽼版策略;
# path_pattern_parser 新版策略;
spring.mvc.pathmatch.matching-strategy=ant_path_matcher
RestFul的使用
1. rest请求注解
- @GetMapping()
- @PostMapping()
- @PutMapping()
- @DeleteMapping()
- @PatchMapping:对Put的补充,区别是Patch是部分更新,Put是全部更新
2. 开启rest风格
- HiddenHttpMethodFilter,springboot自动配置
- 表单method=post,隐藏域 _method=put/delete/patch
- 配置文件开启,新版本将自动开启(待具体测试)

spring:mvc:hiddenmethod:filter:enabled: true #开启页面表单的Rest功能
<form action="/user" method="post"><input name="_method" type="hidden" value="PUT"/><input value="REST-PUT 提交" type="submit"/>
</form>
3. 修改默认隐藏域_method
- 自定义配置类
//自定义filter
@Bean
public HiddenHttpMethodFilter hiddenHttpMethodFilter(){HiddenHttpMethodFilter methodFilter = new HiddenHttpMethodFilter();//自定义隐藏域_mmethodFilter.setMethodParam("_m");return methodFilter;
}
4. rest请求原理
- filter原理,仅针对web端的网页表单提交,因为表单只能GET提交或POST提交。而其他的客户端工具,可以直接发送各种请求方式,因此无需filter做转换。
- 所以这个filter功能是选择性开启,而不是一定要开启的。比如如果只是当做提供接口,此时只传输json数据,无需配置这一项
//web的restful请求被HiddenHttpMethodFilter拦截
public class HiddenHttpMethodFilter extends OncePerRequestFilter {private static final List<String> ALLOWED_METHODS;public static final String DEFAULT_METHOD_PARAM = "_method";private String methodParam = "_method";public HiddenHttpMethodFilter() {}//此方法可以修改form表单默认隐藏域public void setMethodParam(String methodParam) {Assert.hasText(methodParam, "'methodParam' must not be empty");this.methodParam = methodParam;}protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {HttpServletRequest requestToUse = request;//表单请求是post且请求无异常if ("POST".equals(request.getMethod()) && request.getAttribute("javax.servlet.error.exception") == null) {//获取隐藏域中的值String paramValue = request.getParameter(this.methodParam);if (StringUtils.hasLength(paramValue)) {//转大写String method = paramValue.toUpperCase(Locale.ENGLISH);//PUT、DELETE、PATCHif (ALLOWED_METHODS.contains(method)) {requestToUse = new HiddenHttpMethodFilter.HttpMethodRequestWrapper(request, method);}}}//过滤器链放行的时候用wrapper//以后的方法调用getMethod是调用requesWrapper的filterChain.doFilter((ServletRequest)requestToUse, response);}}//包装模式requesWrapper重写了getMethod方法,返回的是传入的隐藏域中的值
private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {private final String method;public HttpMethodRequestWrapper(HttpServletRequest request, String method) {super(request);this.method = method;}public String getMethod() {return this.method;}
}
请求映射原理
1. 主要调用顺序:
- 从 org.springframework.web.servlet.DispatcherServlet开始
- 找到FrameworkServlet类里的doGet()/doPost()/doXxx()
- 都是执行this.processRequest(request, response)
- 调用this.doService(request, response)
- 找到主要实现逻辑this.doDispatch(request, response);

2. mappedHandler = this.getHandler(processedRequest)
- 找到当前请求使用哪个Handler(Controller的方法)处理
- 同样的请求方式,不能有相同的方法处理
- 也可以自己给容器中放HandlerMapping,自定义 HandlerMapping
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {if (this.handlerMappings != null) {Iterator var2 = this.handlerMappings.iterator();//循环尝试所有的HandlerMapping看是否有匹配请求信息while(var2.hasNext()) {HandlerMapping mapping = (HandlerMapping)var2.next();HandlerExecutionChain handler = mapping.getHandler(request);if (handler != null) {return handler;}}}return null;
}


