十SpringBoot2核心技术——web开发(请求参数处理)

Posted 上善若水

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了十SpringBoot2核心技术——web开发(请求参数处理)相关的知识,希望对你有一定的参考价值。

一、请求参数处理

1.1、请求映射

1.1.1、rest使用与原理

  • @xxxMapping;
  • Rest风格支持(使用HTTP请求方式,动词来表示对资源的操作)
    1.以前:/getUser 获取用户 ,/deleteUser 删除用户,/editUser 编辑用户,/saveUser 保存用户;
    2.现在:/user    GET-获取用户,DELETE-删除用户,PUT-修改用户,POST-保存用户;
    3.核心Filter;HiddenHttpMethodFilter
          3.1 :用法:表单method=post,隐藏域 _method=put
          3.2 :SpringBoot中手动开启
    4.扩展:如何把_method这个名字换成我们自己喜欢的。
package com.xbmu.controller;

import org.springframework.web.bind.annotation.*;

@RestController
public class UserController {
   // @RequestMapping(value = "/user",method = RequestMethod.GET)
   @GetMapping(value = "/user")
   public String getUser(){
       return "GET-张三";
   }

   // @RequestMapping(value = "/user",method = RequestMethod.POST)
   @PostMapping(value = "/user")
   public String saveUser(){
       return "POST-张三";
   }

   // @RequestMapping(value = "/user",method = RequestMethod.PUT)
   @PutMapping(value = "/user")
   public String putUser(){
       return "PUT-张三";
   }

   // @RequestMapping(value = "/user",method = RequestMethod.DELETE)
   @DeleteMapping(value = "/user")
   public String deleteUser(){
       return "DELETE-张三";
   }
}

src/main/resources/static/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Spring Boot2</title>
</head>
<body>
    <h1>Spring Boot2,欢迎您</h1>
    测试REST风格;
    <form action="/user" method="get">
        <input value="REST-GET 提交" type="submit"/>
    </form>
    <form action="/user" method="post">
        <input value="REST-POST 提交" type="submit"/>
    </form>
    <form action="/user" method="delete">
        <input value="REST-DELETE 提交" type="submit"/>
    </form>
    <form action="/user" method="put">
        <input value="REST-PUT 提交" type="submit"/>
    </form>
    <hr/>
</body>
</html>

在这里插入图片描述
源码分析:
在浏览器中,通过表单提交数据的方式只支持两种:GET、POST;想要实现DELETE和PUT的方式,需要使用spring提供的过滤器HiddenHttpMethodFilter。

  1. 进入webmvc的自动配置类:
    org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.
    hiddenHttpMethodFilter()方法。
    从该方法的@ConditionalOnProperty注解中,可以看出SpringBoot需求手动开启,默认关闭了这个过滤器。
@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
@ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled")
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
	return new OrderedHiddenHttpMethodFilter();
}
  1. org.springframework.web.filter.HiddenHttpMethodFilter
    从源码中可以看出:只对表单提交的POST请求做处理,才会把你提交的真正请求参数获取到request.getParameter(this.methodParam),然后才会处理你真正提交的PUT、DELETE、PATCH方式的请求。
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
		throws ServletException, IOException {

	HttpServletRequest requestToUse = request;

	if ("POST".equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) {
		// this.methodParam 的值为: "_method"
		String paramValue = request.getParameter(this.methodParam);
		if (StringUtils.hasLength(paramValue)) {
			String method = paramValue.toUpperCase(Locale.ENGLISH);
			// ALLOWED_METHODS 集合中包含:[PUT、DELETE、PATCH]
			if (ALLOWED_METHODS.contains(method)) {
				requestToUse = new HttpMethodRequestWrapper(request, method);
			}
		}
	}

	filterChain.doFilter(requestToUse, response);
}

给表单新增隐藏表单域,传递真正的请求方式

    <form action="/user" method="post">
        <input name="_method" type="hidden" value="delete"/>
        <input value="REST-DELETE 提交" type="submit"/>
    </form>
    <form action="/user" method="post">
        <input name="_method" type="hidden" value="PUT"/>
        <input value="REST-PUT 提交" type="submit"/>
    </form>

SpringBoot中开启hiddenmethod 过滤器

server:
  port: 8888
spring:
  mvc:
    hiddenmethod:
      filter:
        enabled: true # 开启页面表单的Rest功能。默认false,不开启

1.1.2、总结

Rest原理(表单提交要使用REST的时候)

  • 表单提交会带上 _mothod=PUT_mothod=DELETE_mothod=PATCH
  • 请求过来被HiddenHttpMethodFilter拦截
    1.请求是否正常,并且是POST
          1.1 获取到 _mothod的值
          1.2 兼容以下请求:PUT、DELETE、PATCH
          1.3 原生request(post),包装模式requesWrapper重写了getMethod方法,返回的是传入的值。
          1.4 过滤器链放行的时候用wrapper。以后的方法调用getMethod是调用requesWrapper的。

Rest使用客户端工具

  • 如PostMan直接发送PUT、DELETE等方式请求,无需Filter。

1.2、请求映射原理

在这里插入图片描述SpringMVC功能分析都是从org.springframework.web.servlet.DispatcherServletorg.springframework.web.servlet.DispatcherServlet---->doDispatch(request, response);

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);

			// Determine handler for the current request.
			// 找到当前请求使用哪个Handler(Controller的方法)处理
			mappedHandler = getHandler(processedRequest);
			if (mappedHandler == null) {
				noHandlerFound(processedRequest, response);
				return;
			}

			// Determine handler adapter for the current request.
			HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

			...
		}
		...
	}
	...
}

在这里插入图片描述RequestMappingHandlerMapping:保存了所有@RequestMapping 和handler的映射规则。
在这里插入图片描述所有的请求映射都在HandlerMapping中。

  • SpringBoot自动配置欢迎页WelcomePageHandleMapping。访问 / 能访问到index.html
  • SpringBoot自动配置了默认的RequestMappingHandlerMapping
  • 请求进来,挨个尝试所有的HandlerMapping,看是否有请求信息。如果有就找到这个请求对应的handler,如果没有就是下一个HandlerMapping
  • 我们需要一些自定义的映射处理,我们也可以自己给容器中放HandlerMapping,自定义HandlerMapping。

以上是关于十SpringBoot2核心技术——web开发(请求参数处理)的主要内容,如果未能解决你的问题,请参考以下文章

八SpringBoot2核心技术——web开发(静态资源访问)

八SpringBoot2核心技术——web开发(静态资源访问)

九SpringBoot2核心技术——web开发(静态资源配置原理)

九SpringBoot2核心技术——web开发(静态资源配置原理)

十四SpringBoot2核心技术——web开发(模块引擎Thymeleaf)_上

十四SpringBoot2核心技术——web开发(模块引擎Thymeleaf)_上