Spring-mvc - Filter - HiddenHttpMethodFilter - 支持Rest

🌳 支持Rest - 配置HiddenHttpMethodFilter

spring-mvc默认不支持rest(只能处理get、post请求)。配置HiddenHttpMethodFilter以支持Rest,HiddenHttpMethodFilter原理是把HttpServletRequest包装成HttpServletRequestWrapper,重写(override)其getMethod()方法。

步骤如下

  1. 配置HiddenHttpMethodFilter过滤器。
  2. 在表单中添加name是_method的字段。

1️⃣ 配置HiddenHttpMethodFilter

 <!-- hiddenHttpFilter - 支持PUT、DELETE请求 -->
<filter>
    <filter-name>hiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>hiddenHttpMethodFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

2️⃣ 表单中添加_method字段

<form id="mainForm" method="post" action="${basePath}/ad/edit" enctype="multipart/form-data">
    <input type="hidden" name="_method" value="put" />
</form>

🌲 Rest文件上传 - PUT请求上传文件问题 - 无法解析multipart

出现原因

  • form表单的enctype是multipart/form-data,浏览器发请求报文到服务器
  • 服务器(tomcat)解析http请求报文成HttpServletRequest,默认不解析multipart段
  • 请求到HiddenHttpMethodFilter,因为mulpart中的_method没解析,获取不到_method。

解决方法有两种

  • 配置multipart-config,支持解析multipart/form-data - StandardMultiPartResolver方式
  • 配置MultiPartFilter - CommonsMultiPartResolver方式

🅰️ 配置multipart-config

<!-- DispatcherServlet -->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring/spring-web.xml</param-value>
        </init-param>
        <init-param>
            <param-name>readonly</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
        <!--- ❤️ 这里的内容 - 解析后 - 解析成Part --->
        <multipart-config>
            <!-- 最大上传大小(-1表示不限制) - 10M -->
            <max-file-size>10485760</max-file-size>
            <!-- 请求报文最大大小(-1不限制) - 不限制 -->
            <max-request-size>-1</max-request-size>
            <!-- 文件超过多大,就会被临时存储在磁盘,而不是内存 -  10M  -->
            <file-size-threshold>10485760</file-size-threshold>
            <!-- location - part.write()如果写的不是绝对路径,相对于location-->
        </multipart-config>
    </servlet>

🅱️ 配值MultipartFilter

<!-- multiPartFilter - 用于解析 MultiPart请求 -->
<filter>
    <filter-name>multipartFilter</filter-name>
    <filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
    <!-- 指定multipartResolver的beanName - 默认是fileMultipartResolver -->
    <init-param>
        <param-name>multipartResolverBeanName</param-name>
        <param-value>filterMultipartResolver</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>multipartFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

你还需要把你的multipartResolver提取到RootApplicationContext

<!-- MultipartResolver -->
<bean id="filterMultipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="defaultEncoding" value="utf-8" />
    <property name="maxUploadSize" value="#{5*1024*1024}" />
    <property name="maxInMemorySize" value="#{5*1024*1024}" />
</bean>

🌾 JSP支持Rest - tomcat问题

在tomcat8之后,jsp不支持Rest,有如下解决方案

  1. 自定义Filter,把HttpServletRequest封装成HttpServletRequestWrapper,重写getMethod方法,配置Filter的dispatcher为DORWARD
  2. 在jsp页面中Page指令(三大指令之一)的isErrorPage属性

🅰️ 自定义Filter封装Request为RequestWrapper

1️⃣ 自定义Filter封装HttpServletRequest为HttpServletRequestWrapper,重写getMethod()方法

public class JspSpringFilter extends HiddenHttpMethodFilter {

    // ❤️ 实现HttpServvletRequestWrapper
    private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {
        private final String method;

        public HttpMethodRequestWrapper(HttpServletRequest request, String method) {
            super(request);
            this.method = method;
        }
        // ❤️ 重写getMethod()
        public String getMethod() {
            return this.method;
        }
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        HttpServletRequest requestToUse = request;

        // 1. init method - 匹配delete和put
        String method = requestToUse.getMethod();
        if (method.equalsIgnoreCase("delete") || method.equalsIgnoreCase("put")) {
            method = "POST";
        }

        // 2. init wrapper - 封装成HttpServletRequestWrapper
        requestToUse = new HttpMethodRequestWrapper(request, method);

        // 3. doFilter
        filterChain.doFilter(requestToUse, response);
    }
}

2️⃣ 配置Filter为FORWARD - 只在请求forwrad时候匹配

<!-- JspRestSupportFilter - JSP支持rest方式-->
<filter>
    <filter-name>jspSpringFilter</filter-name>
    <filter-class>com.yuki.dianping.filter.JspSpringFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>jspSpringFilter</filter-name>
    <url-pattern>*.jsp</url-pattern>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>

🅱️在Page指令中指定isErrorPage属性

<!-- 🟢 这里的isErrorPage设置成 true-->
<%@ page pageEncoding="UTF-8" contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" %>
<!-- taglib -->
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
posted @ 2021-03-09 22:17  全力一拼  阅读(194)  评论(0)    收藏  举报