从@RequestMapping标注处理什么请求,到控制器方法的方法体返回值,这个过程就叫做请求映射,如下:
@RequestMapping("hello") public String hello(){ return "Hello SpringBoot 2 !"; }
2. Rest映射
Rest风格支持,即使用HTTP请求方式动词来表示对资源的 *** 作。
以前:/getUser 获取用户 /deleteUser 删除用户 /editUser 修改用户 /saveUser 保存用户现在: /user GET-获取用户 DELETE-删除用户 PUT-修改用户 POST-保存用户
Rest风格的请求映射,它们映射到的地址都是同一个,再根据请求方式的不同来区分不同的处理。代码如下:
@RequestMapping(value = "user",method = RequestMethod.GET) public String getUser(){ return "GET-张三"; } @RequestMapping(value = "user",method = RequestMethod.POST) public String saveUser(){ return "POST-张三"; } @RequestMapping(value = "user",method = RequestMethod.PUT) public String putUser(){ return "PUT-张三"; } @RequestMapping(value = "user",method = RequestMethod.DELETE) public String deleteUser(){ return "DELETE-张三"; }
使用Rest风格进行映射,我们需要使用到一个核心Filter:HiddenHttpMethodFilter,我们进入这个Filter的底层可以发现,这个过滤器对于请求方式的处理过程。
那么SpringMVC有为我们自动配置这个Filter吗,前往底层源码可以发现,并没有。因此,必须手动配置。
使用方法总结:
将表单的 method 设置为 post ,并将隐藏域 _method 设置为 put/delete/get (即 _method 里设置真正的请求方式)
SpringBoot中 手动开启
spring: mvc: hiddenmethod: filter: enabled: true
3. Rest的派生注解
@GetMapping、@PostMapping、@PutMapping、@DeleteMapping、@PatchMapping:它们就是@RequestMapping派生出来的注解,默认携带某个提交方式属性,源码如下:
@RequestMapping(method = {RequestMethod.GET}) public @interface GetMapping{}
将上面的示例全都改写为用派生注解,代码如下:
@GetMapping("user") public String getUser(){ return "GET-张三"; } @PostMapping("user") public String saveUser(){ return "POST-张三"; } @PutMapping("user") public String putUser(){ return "PUT-张三"; } @DeleteMapping("user") public String deleteUser(){ return "DELETE-张三"; }
4. Rest映射的原理
springmvc底层源码:
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { HttpServletRequest requestToUse = request; 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); }
分析基于表单提交时使用的Rest映射过程:(下面以 DELETE 请求方式为例)
- 表单提交时会带上隐藏域 _method=DELETE请求过来时会被 HiddenHttpMethodFilter拦截判断请求是否有异常,并且要求请求方式是 POST获取 _method 的值并转成大写(这一步说明我们在编写html时,请求方式大小写可以随意)判断允许的请求方式中包不包含 _method的值(这里可以发现除了HTTP传统的 GET、POST外,还兼容PUT、DELETE、PATCH)调用HttpMethodRequestWrapper方法。(原生request的请求是post,包装模式requestWrapper重写了原生request的getMethod方法,返回的就变成了_method的值)过滤器链放行时放行的是Wrapper,以后的方法调用getMethod都会调用到包装模式requestWrapper重写过的,所以以后获取到的都是_method的值了。
注意:Http只兼容两种原生请求方式,才需要过滤器的支持。Rest使用客户端工具时,如安卓或Postman模拟,就可以直接发送PUT、DELETE请求,无需Filter。
在此我们也能够意识到为什么springboot默认没有把HiddenHttpMethodFilter开启。因为如果不做页面开发,springboot就是用于微服务的开发,微服务开发简单来说就是给别人提供接口,别人发给我们请求,我们提供JSON数据。不会经常交互页面,且前后端分离,页面也可能是别人写的。
5. 更换隐藏域的属性名
由于 SpringMVC 的自动配置时加载 HiddenHttpMethodFilter 组件是根据 @ConditionalOnMissingBean 按需加载的,因此我们可以自己给容器中放一个 HiddenHttpMethodFilter,并且隐藏域的属性名自己喜欢取什么就取什么。
@Configuration(proxyBeanMethods = false) //没有什么依赖,所以弄成多例可以减少开销 public class WebConfig { @Bean public HiddenHttpMethodFilter hiddenHttpMethodFilter(){ HiddenHttpMethodFilter methodFilter = new HiddenHttpMethodFilter(); methodFilter.setMethodParam("_m"); // HiddenHttpMethodFilter有一个set方法可以更改隐藏域属性 return methodFilter; } }
用 HiddenHttpMethodFilter 里的一个set方法 setMethodParam( ) 可以更改隐藏域属性。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)