Spring Boot请求映射处理

1. 请求映射

  • @xxxMapping:

  • Rest风格支持(使用HTTP请求方式动词来表示对资源的操作)

    • 以前:/getUser 获取用户 /deleteUser 删除用户 /editUser 修改用户 /saveUser 保存用户

      • 现在:/user GET-获取用户 DELETE-删除用户 PUT-修改用户 POST-保存用户

      • 核心Filter:HiddenHttpMethodFilter

        • 用法:表单method=post,隐藏域_method=put

        • 需要在SpringBoot中手动开启

@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
@ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled")
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
   return new OrderedHiddenHttpMethodFilter();
}
spring:
  mvc:
    hiddenmethod:
      filter:
        enable: true #开启页面表单的Rest风格
Rest原理(表单提交使用Rest风格时)
  • 表单提交会带上_method=PUT

  • 请求过来被HiddenHttpMethodFilter拦截

    • 请求是否正常,并且是POST

      • 获取_method的值

      • 兼容以下请求:PUT、DELETE、PATCH

      • 原生request(post),包装模式requestWrapper重写了getMethod()方法,返回的是传入的值

      • 过滤器链放行的时候用wrapper作为request放行,以后的方法调用getMethod()是调用requestWrapper的

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) {
        // 获得_method请求参数
        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);
}

修改请求方式参数名

// 组件之间没有依赖
@Configuration(proxyBeanMethods = false)
public class WebConfig {
​
    @Bean
    public HiddenHttpMethodFilter hiddenHttpMethodFilter(){
        HiddenHttpMethodFilter methodFilter = new HiddenHttpMethodFilter();
        // 修改请求方式参数名
        methodFilter.setMethodParam("_m");
        return methodFilter;
    }
​
}
Rest使用客户端工具
  • 如axios、PostMan等直接发送put、delete等方式请求,无需filter开启

请求映射

继承关系

Spring Boot请求映射处理_第1张图片

请求进来,先调用HttpServlet的doGet()方法,在doGet方法中会调用FrameworkServlet的processRequest(HttpServletRequest request, HttpServletResponse response)方法,在processRequest中调用DispatcherServlet的doService()方法,再调用doDispatch(每个请求都会调用)

SpringMVC的功能分析都从org.springframework.web.servlet.DispatcherServlet-->doDispatch()方法开始

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
   HttpServletRequest processedRequest = request;
   HandlerExecutionChain mappedHandler = null;
   boolean multipartRequestParsed = false;
​
    // 请求是否使用异步,使用了,就使用异步管理器
   WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
​
   try {
      ModelAndView mv = null;
      Exception dispatchException = null;
​
      try {
          // 检查是否是文件上传请求
         processedRequest = checkMultipart(request);
         multipartRequestParsed = (processedRequest != request);
​
          // 找到当前请求使用哪个handler->controller处理当前请求
         // Determine handler for the current request.
         mappedHandler = getHandler(processedRequest);
         if (mappedHandler == null) {
            noHandlerFound(processedRequest, response);
            return;
         }
​
         
// HanlderMapping,处理器映射 /xxx->xxxController->method
// Request Mapping HandlerMapping:保存了所有@RequestMapping 和 handler的映射规则
@Nullable
    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        if (this.handlerMappings != null) {
            for (HandlerMapping mapping : this.handlerMappings) {
                HandlerExecutionChain handler = mapping.getHandler(request);
                if (handler != null) {
                    return handler;
                }
            }
        }
        return null;
    }

Spring Boot请求映射处理_第2张图片

所有的请求映射都保存在Handler Mapping中

  • SpringBoot自己注册了欢迎页的请求映射"/"可以访问index.html

  • SpringBoot自动配置了默认 的 RequestMappingHandlerMapping

  • 请求进来,尝试所有的HanlderMapping看是否有请求信息

    • 如果有就找到这个请求对应的handler

    • 如果没有就是下一个HandlerMapping

  • 我们需要一些自定义的映射处理,我们也可自己给容器中注册自定义的HandlerMapping

你可能感兴趣的:(Spring,spring,boot,后端,java)