1

form表单put、delete方式提交处理

form表单只支持get和post的方式提交,而我们使用restful风格必然要使用到@PUTmapping、@DELETEmapping等注解,那么在提交表单时的method=“put/delete”也要对应注解,下面来看看SpringMVC和SpringBoot的处理方式。

1、SpringMVC的处理

SpringMVC通过在web.xml中配置如下过滤器HiddenHttpMethodFilter处理;然后在页面上提交一个隐藏的input来实现;

1、配置HiddenHttpMethodFilter

<filter>
        <filter-name>HttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>HttpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

2、表单处理

<form th:action="" method="post">
    <!--
 发送put请求修改员工数据
 1、SpringMVC中配置HiddenHttpMethodFilter;
 2、页面创建一个Post表单;
 3、创建一个隐藏的input项,name=_method,value就是我们指定的请求方式; --> 
 <input type="hidden" name="_method" value="put" />
 </form>
注意这里的name属性只能为_method,value为我们想提交的方式;

2、SpringBoot的处理

SpringBoot已经为我们自动配置了HttpMethodFilter,SpringBoot2.2.0以上版本需要我们手动开启配置;

1、开启配置

#开启hiddenmethod 过滤器
spring.mvc.hiddenmethod.filter.enabled=true

2、表单处理
同上;

3、看看源码

Ctrl+N搜索-WebMvcAutoConfiguration类
然后Ctrl+F搜索-hiddenmethod
看看SpringBoot如何自动配置的
源码如下:
@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
//意为当我们配置文件中没找到这个前缀(prefix)为spring.mvc.hiddenmethod.filter的名为enabled的属性就不开启这项配置,即默认false;
@ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled", matchIfMissing = false)

public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
   return new OrderedHiddenHttpMethodFilter();
}
按住Ctrl并点击HiddenHttpMethodFilter.class,去看看过滤器的源码
public class HiddenHttpMethodFilter extends OncePerRequestFilter {
    private static final List<String> ALLOWED_METHODS;//允许的方法
    public static final String DEFAULT_METHOD_PARAM = "_method";
    private String methodParam = "_method";//这就是name="_method",也就是从页面拿到的参数
    public HiddenHttpMethodFilter() {
    }
    public void setMethodParam(String methodParam) {
        Assert.hasText(methodParam, "'methodParam' must not be empty");
        this.methodParam = methodParam;
    }
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        HttpServletRequest requestToUse = request;
        //这里if判断request是不是post,这也是为什么form必须为post的原因
        if ("POST".equals(request.getMethod()) && request.getAttribute("javax.servlet.error.exception") == null) {
        
            //利用request.getParameter取到hidden的input传来的value;
            String paramValue = request.getParameter(this.methodParam);
            
            //hasLength()判断paramValue不为空即将paramValue转为大写并赋值给method
            if (StringUtils.hasLength(paramValue)) {
            //这个method才是我们真正想要的请求方式
                String method = paramValue.toUpperCase(Locale.ENGLISH);
                
                //如果被允许的method中包含有我们真正想要的请求方式
                if (ALLOWED_METHODS.contains(method)) {
                //就使用我们希望的请求方式,把不是我们传的method过滤掉了
                    requestToUse = new HiddenHttpMethodFilter.HttpMethodRequestWrapper(request, method);
                }
            }
        }
        filterChain.doFilter((ServletRequest)requestToUse, response);
    }
    //这里定义了3种允许的方法DELETE、PUT、PATCH
    static {
        ALLOWED_METHODS = Collections.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(), HttpMethod.DELETE.name(), HttpMethod.PATCH.name()));
    }
    
    private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {
        private final String method;
        public HttpMethodRequestWrapper(HttpServletRequest request, String method) {
            super(request);
            this.method = method;
        }
        public String getMethod() {
            return this.method;
        }
    }
}

胖椿
13 声望2 粉丝