Spring Boot核心技术之Rest映射以及源码的分析

controller

package com.xbhong.Controller;

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

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

// @PostMapping("/user")
@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-张三";
}

}
测试功能是否可用:
观察效果:

可以看到最后两个请求都变成Get的请求了。由此我们可以引出来如下问题:

为什么不同的请求会出现相同的结果
怎么实现的才能完成我们的功能
后面的文章就是围绕上述的问题进行展开的。

解决问题:
像之前的SpringMVC中的表单请求通过HiddenHttpMethodFilter实现的,这样我们查一下在SpringBoot中是怎么样的。

默认双击Shift键,输入WebMvcAutoConfiguration这个类

找到默认配置的过滤器:

@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
@ConditionalOnProperty(prefix = “spring.mvc.hiddenmethod.filter”, name = “enabled”, matchIfMissing = false)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter();
}
通过OrderedHiddenHttpMethodFilter进入父类HiddenHttpMethodFilter:

在使用之前,我们需要将后两个的请求方式改写成post方式,并且需要在请求的时候传入一个_method方法(设置隐藏域);

流程:

第一步保存了传入的请求
当该请求时post,并且请求没有异常,才能进入下面方法,不是Post请求将直接通过过滤器链放行。
获取请求中的参数(this.methodParam)
DEFAULT_METHOD_PARAM = _method获得(作为真正的请求方式)
然后再测试,发现还是没有实现。

我再回到WebMvcConfiguration中:

@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
@ConditionalOnProperty(prefix = “spring.mvc.hiddenmethod.filter”, name = “enabled”, matchIfMissing = false)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter();
}
首先该类存在于容器中。

@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
当容器中不存在HiddenHttpMethodFilter这个类的时候,下面内容开启(条件装配);

@ConditionalOnProperty(prefix = “spring.mvc.hiddenmethod.filter”, name = “enabled”, matchIfMissing = false)
表示:绑定的配置文件中:spring.mvc.hiddenmethod.filter名字为enable是默认不开启的(后续版本可能开启)。这样我们就找到了问题的所在。

所以我们需要在配置文件中配置(两种方法都可以)。

yaml:

spring:
mvc:
hiddenmethod:
filter:
enabled: true
properties:

spring.mvc.hiddenmethod.filter.enabled=true
重启项目:成功解决。

源码分析:
主要是分析doFilterInternal:

@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) {
    String paramValue = request.getParameter(this.methodParam);
    if (StringUtils.hasLength(paramValue)) {
        String method = paramValue.toUpperCase(Locale.ENGLISH);
        if (ALLOWED_METHODS.contains(method)) {
            requestToUse = new HttpMethodRequestWrapper(request, method);
        }
    }
}

filterChain.doFilter(requestToUse, response);

}
表单提交会带上_method=PUT

请求过来被HiddenHttpMethodFilter拦截

请求是否正常,并且是POST

获取到_method的值。

兼容以下请求;PUT.DELETE.PATCH

当方法走到上述代码11行时,进入ALLOWED_METHODS:

private static final List ALLOWED_METHODS =
Collections.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(),
HttpMethod.DELETE.name(), HttpMethod.PATCH.name()));
如果请求里的参数在ALLOWED_METHODS存在,则执行下面代码。

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

进入HttpMethodRequestWrapper对象中,向上找父类。本质还是HttpServletRequest

由下面代码:

private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {

private final String method;

public HttpMethodRequestWrapper(HttpServletRequest request, String method) {
    super(request);
    this.method = method;
}

@Override
public String getMethod() {
    return this.method;
}

}
可知,接收到前面的请求封装为HttpMethodRequestWrapper返回。

过滤器链放行的时候用wrapper。以后的方法调用getMethod是调用requesWrapper的。
mosfet驱动芯片 https://www.zg886.cn

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值