5、SpringBoot2 Web开发之Rest接口映射原理以及表单访问Rest接口

1、Rest风格接口形式

//@RequestMapping(value = "/user",method = RequestMethod.GET) 等同于
@GetMapping("/user")
public String getUser(){
    return "GET-张三";
}
//@RequestMapping(value = "/user",method = RequestMethod.POST) 等同于
@PostMapping("/user")
public String saveUser(){
    return "POST-张三";
}
//@RequestMapping(value = "/user",method = RequestMethod.PUT)  等同于
@PutMapping("/user")
public String putUser(){
    return "PUT-张三";
}
//@RequestMapping(value = "/user",method = RequestMethod.DELETE)  等同于
@DeleteMapping("/user")
public String deleteUser(){
    return "DELETE-张三";
}

2、请求映射原理

(1)springMvc请求开始

所有接口请求都是从org.springframework.web.servlet.DispatcherServlet中doDispatch方法进行处理执行

在这里插入图片描述

//FrameworkServlet 重写doXXX方法
protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    this.processRequest(request, response);
}
protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
   .......
   this.doService(request, response);
   .......
}
//DispatcherServlet 实现了 doService
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    .........
    //核心处理方法
    this.doDispatch(request, response);
    ........
}

(2)doDispatch映射处理分析

获取容器中所有的handlerMappings,然后循环遍历查找能处理请求的handlerMappings,所有的controller中的请求都会在项目启动时封装到RequestMappingHandlerMapping中

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    .........
    //获取处理请求的Handler 根据获取到hanlder进行请求处理
    mappedHandler = this.getHandler(processedRequest);
    .........
}
//循环遍历获取处理请求的handlerMappings
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
        Iterator var2 = this.handlerMappings.iterator();
        while(var2.hasNext()) {
            HandlerMapping mapping = (HandlerMapping)var2.next();
            HandlerExecutionChain handler = mapping.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
    }
    return null;
}

在这里插入图片描述

(3)匹配原理

根据url匹配所有能处理请求的方法,然后根据RequestMethod值确定唯一方法进行处理

//AbstractHandlerMapping
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    Object handler = this.getHandlerInternal(request);
    .......
}
//RequestMappingInfoHandlerMapping
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    ..........
    var2 = super.getHandlerInternal(request);
    .........
}
//AbstractHandlerMethodMapping
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    //获取请求url
    String lookupPath = this.getUrlPathHelper().getLookupPathForRequest(request);
    ..........
    //进行匹配
    HandlerMethod handlerMethod = this.lookupHandlerMethod(lookupPath, request);
    .........
}
//AbstractHandlerMethodMapping.class
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
    ......
    //获取所有匹配的请求
    List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
    if (directPathMatches != null) {
        //根据请求行为(method)进行筛选
        this.addMatchingMappings(directPathMatches, matches, request);
    }
    //路径变量处理会在此处进行匹配
    if (matches.isEmpty()) {
        this.addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
    }
    .......
}

(4)自定义HandlerMapping

我们需要一些自定义的映射处理,我们也可以自己给容器中放HandlerMapping,实现自定义处理

3、表单请求Rest接口

(1)表单支持put、delete请求

表单只支持get与post请求,可通过OrderedHiddenHttpMethodFilter实现put与delete请求

spring:
  mvc:
    hiddenmethod:
      filter:
        enabled: true # 默认不开启
<!-- 表单post请求提交带上参数_method=PUT -->
<form action="/user" method="post">
    <input name="_method" type="hidden" value="PUT"/>
    <input value="REST-PUT 提交" type="submit"/>
</form>

(2)实现原理

SpringBoot web环境下,会根据spring.mvc.hiddenmethod.filter值是否注入OrderedHiddenHttpMethodFilter,OrderedHiddenHttpMethodFilter根据_method的值包装request请求

//1、springboot启动会自动加载webmvc自动配置
@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration

//2、按需注入OrderedHiddenHttpMethodFilter
@Bean
@ConditionalOnMissingBean({HiddenHttpMethodFilter.class})
@ConditionalOnProperty(
    prefix = "spring.mvc.hiddenmethod.filter",
    name = {"enabled"},
    matchIfMissing = false
)//默认不开启
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
    return new OrderedHiddenHttpMethodFilter();
}

//3、OrderedHiddenHttpMethodFilter判断绑定method
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
    HttpServletRequest requestToUse = request;
    //判断是否是post请求,切请求参数中有_method
    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);
            if (ALLOWED_METHODS.contains(method)) {
                requestToUse = new HiddenHttpMethodFilter.HttpMethodRequestWrapper(request, method);
            }
        }
    }
    filterChain.doFilter((ServletRequest)requestToUse, response);
}

(3)自定义参数(修改_method)

打破@ConditionalOnMissingBean({HiddenHttpMethodFilter.class}),启动就不会将OrderedHiddenHttpMethodFilter注入到容器中

//容器中注入HiddenHttpMethodFilter,打破自动注入@ConditionalOnMissingBean({HiddenHttpMethodFilter.class})条件
@Bean
public HiddenHttpMethodFilter hiddenHttpMethodFilter(){
    HiddenHttpMethodFilter methodFilter = new HiddenHttpMethodFilter();
    methodFilter.setMethodParam("_m");
    return methodFilter;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值