SpringBoot学习笔记【part09】Web开发——rest使用与原理

SpringBoot 学习笔记 Part09

1. 请求映射

从@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吗,前往底层源码可以发现,并没有。因此,必须手动配置。

在这里插入图片描述

使用方法总结

  1. 将表单的 method 设置为 post ,并将隐藏域 _method 设置为 put/delete/get (即 _method 里设置真正的请求方式)

    <form action="user" method="post">
      <input type="hidden" name="_method" value="put">
      <input type="submit" value="REST-PUT提交">
    </form>
    
    <form action="user" method="post">
      <input type="hidden" name="_method" value="delete">
      <input type="submit" value="REST-DELETE提交">
    </form>
    
  2. 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 请求方式为例)

  1. 表单提交时会带上隐藏域 _method=DELETE
  2. 请求过来时会被 HiddenHttpMethodFilter拦截
  3. 判断请求是否有异常,并且要求请求方式是 POST
  4. 获取 _method 的值并转成大写(这一步说明我们在编写html时,请求方式大小写可以随意)
  5. 判断允许的请求方式中包不包含 _method的值(这里可以发现除了HTTP传统的 GET、POST外,还兼容PUT、DELETE、PATCH)
  6. 调用HttpMethodRequestWrapper方法。(原生request的请求是post,包装模式requestWrapper重写了原生request的getMethod方法,返回的就变成了_method的值)
  7. 过滤器链放行时放行的是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( ) 可以更改隐藏域属性。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Parker7

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值