This is the fourth day of my participation in the First Challenge 2022.

HTML forms only support GET and POST requests. Other request methods, such as PUT and DELETE, cannot be sent directly through HTML. The value of the method attribute can only be GET, POST, or Dialog (dialog is used to close the dialog when submitting if the form is in a


element). Other values are sent as GET requests by default.

To address this problem, Spring 3.0 added a filter, HiddenHttpMethodFilter. The filter overrides the original HTTP request method (that is, POST) using the _method value in the form, and then sends it to the HandlerMapping to find the corresponding Controller method.

<form action="..." method="post">
    <input type="hidden" name="_method" value="put" />.</form>
Copy the code

doFilterInternalmethods

HiddenHTTPMethodFilter inherits from OncePerRequestFilter and implements the abstract method doFilterInternal.

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);
}
Copy the code

From the above several ifs, we can clearly understand that only when…

  1. The request method isPOST;
  2. javax.servlet.error.exceptionProperties fornull(You can ignore it for the moment. It’s generally truenull);
  3. methodParamThe value of theALLOW_METHODSIn (i.ePUT,DELETEPATCH), case insensitive;
    private static finalList<String> ALLOWED_METHODS; .static {
        ALLOWED_METHODS = Collections.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(), HttpMethod.DELETE.name(), HttpMethod.PATCH.name()));
    }
    Copy the code

The request is wrapped in the HttpMethodRequestWrapper class.

Note: Stringutils. haslength is a Spring utility method used to ensure that paramValue is not null and contains at least one non-whitespace character.

HttpMethodRequestWrapperA wrapper class

HiddenHTTPMethodFilter within defined a private static class – HttpMethodRequestWrapper, rewrite the HttpServletRequestWrapper getMethod method of a class.

The original HttpMethodRequestWrapper returns the default getMethod method of the wrapped HttpServletRequest request object.

public class HttpServletRequestWrapper extends ServletRequestWrapper implements HttpServletRequest {...private HttpServletRequest _getHttpServletRequest(a) {
        return (HttpServletRequest)super.getRequest(); }...public String getMethod(a) {
        return this._getHttpServletRequest().getMethod(); }... }Copy the code

HttpMethodRequestWrapper source code:

private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {
    private final String method;

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

    public String getMethod(a) {
        return this.method; }}Copy the code

With the method constructor above, the return value of getMethod is fixed to the value given at initialization. Simply PUT, the wrapper “takes a different approach” by assigning the Method property to the doFilterInternal method above to a value (that is, PUT, PATCH, or DELETE). And that’s what we’re going to use when we look for controllers.

To change the_methodParameter names

Method parameter names can be set with setMethodParam.

public void setMethodParam(String methodParam) {
    Assert.hasText(methodParam, "'methodParam' must not be empty");
    this.methodParam = methodParam;
}
Copy the code

Note: Assert.hasText is also a Spring utility method that calls Stringutils. hasText (mentioned above) in the source code, but adds assertion functionality.

public static void hasText(@Nullable String text, String message) {
    if(! StringUtils.hasText(text)) {throw newIllegalArgumentException(message); }}Copy the code

The resources

  1. Docs. Spring. IO/spring – fram…
  2. Blog.csdn.net/geloin/arti…
  3. Developer.mozilla.org/zh-CN/docs/…