胖哥學SpringMVC:請求方式轉換過濾器配置

胖先森發表於2018-03-18

@RequestMapping

個人建議重新練習一遍搭建的過程,如果感覺麻煩你可以直接複製上一個工程,但是需要修改pom.xml中的一點資訊

<groupId>com.hanpang.springmvc</groupId>
<artifactId>springmvc-demo02</artifactId>
<version>0.0.1-SNAPSHOT</version>
複製程式碼

1.請求路徑相同問題

看下面的程式碼,我設定了相同的路徑,那麼會有說明錯誤呢?請自己檢視控制檯資訊

package com.hanpang.web;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller//告知其是一個控制器
@RequestMapping("/cms")
public class Demo05Controller {
	@RequestMapping(value="/user")
	public ModelAndView test01() {
		System.out.println("用於獲取使用者資訊");
		return null;
	}
	@RequestMapping(value="/user")
	public ModelAndView test02() {
		System.out.println("用於修改使用者資訊");
		return null;
	}
}
複製程式碼

錯誤資訊如下:

Caused by: java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'demo05Controller' method 
public org.springframework.web.servlet.ModelAndView com.hanpang.web.Demo05Controller.test02()
to {[/cms/user]}: There is already 'demo05Controller' bean method
public org.springframework.web.servlet.ModelAndView com.hanpang.web.Demo05Controller.test01() mapped.
複製程式碼

在一個控制器名字叫demo05Controller的中有一個對映路徑"/cms/user"對應了兩個方法,屬於模糊對映

如果出現了這樣的情況或者需求,如何處理呢? 我們可以設定requestMethod來區別相同路徑的不同處理方式

2.method屬性的設定

可以通過設定method設定可以處理,個人推薦這種方式.

package com.hanpang.web;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller//告知其是一個控制器
@RequestMapping("/cms")
public class Demo05Controller {
	@RequestMapping(value="/user",method=RequestMethod.GET)
	public ModelAndView test01() {
		System.out.println("用於獲取使用者資訊");
		return null;
	}
	@RequestMapping(value="/user",method=RequestMethod.POST)
	public ModelAndView test02() {
		System.out.println("用於修改使用者資訊");
		return null;
	}
}
複製程式碼

啟動正常,區分你的請求方式執行相應的方法

問題:我們知道的是HTML傳送的請求方式有且僅有GET和POST?

HTTP Method Conversion
A key principle of REST is the use of the Uniform Interface. This means that all resources (URLs) can be manipulated using the same four HTTP methods: GET, PUT, POST, and DELETE. For each method, the HTTP specification defines the exact semantics. For instance, a GET should always be a safe operation, meaning that is has no side effects, and a PUT or DELETE should be idempotent, meaning that you can repeat these operations over and over again, but the end result should be the same. While HTTP defines these four methods, HTML only supports two: GET and POST. Fortunately, there are two possible workarounds: you can either use JavaScript to do your PUT or DELETE, or simply do a POST with the 'real' method as an additional parameter (modeled as a hidden input field in an HTML form). This latter trick is what Spring’s HiddenHttpMethodFilter does. This filter is a plain Servlet Filter and therefore it can be used in combination with any web framework (not just Spring MVC). Simply add this filter to your web.xml, and a POST with a hidden _method parameter will be converted into the corresponding HTTP method request.
複製程式碼

來自官網的處理方案

REST的一個關鍵原則是使用統一介面。這意味著所有資源(url)都可以使用相同的4個HTTP方法進行操作:GET、PUT、POST和DELETE。對於每個方法,HTTP規範定義了精確的語義。例如,GET應該始終是一個安全的操作,這意味著沒有副作用,PUT或DELETE應該是冪等的,這意味著您可以一次又一次地重複這些操作,但是最終結果應該是相同的。雖然HTTP定義了這四種方法,但是HTML只支援兩種方法:GET和POST。幸運的是,有兩種可能的解決方案:要麼使用JavaScript進行PUT或DELETE,要麼使用“real”方法作為附加引數(將其建模為HTML表單中的隱藏輸入欄位)。後一種技巧是Spring的HiddenHttpMethodFilter所做的。這個過濾器是一個普通的Servlet過濾器,因此它可以與任何web框架(不僅僅是Spring MVC)結合使用。只需將這個過濾器新增到您的web中。xml,以及帶有隱藏方法引數的POST將被轉換成相應的HTTP方法請求。
複製程式碼

Spiring Web MVC 中提供了八種請求方式,但是常用的是官方推薦的四種,分別是

  • GET 查詢操作
  • POST 新增操作
  • PUT 修改操作
  • DELETE 刪除操作

3.配置測試過程

  • (1) 測試程式碼如下

    package com.hanpang.web;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.servlet.ModelAndView;
    
    @Controller//告知其是一個控制器
    @RequestMapping("/cms")
    public class Demo05Controller {
    	@RequestMapping(value="/user",method=RequestMethod.GET)
    	public ModelAndView test01() {
    		System.out.println("用於獲取使用者資訊");
    		return null;
    	}
    	@RequestMapping(value="/user",method=RequestMethod.POST)
    	public ModelAndView test02() {
    		System.out.println("用於新增使用者資訊");
    		return null;
    	}
    	@RequestMapping(value="/user",method=RequestMethod.PUT)
    	public ModelAndView test03() {
    		System.out.println("用於修改使用者資訊");
    		return null;
    	}
    	@RequestMapping(value="/user",method=RequestMethod.DELETE)
    	public ModelAndView test04() {
    		System.out.println("用於刪除使用者資訊");
    		return null;
    	}
    }
    複製程式碼
  • (2) 配置HiddenHttpMethodFilter過濾器

    註解配置:

    package com.hanpang.config;
    
    import javax.servlet.Filter;
    import org.springframework.web.filter.HiddenHttpMethodFilter;
    import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
    
    public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    
    	@Override
    	protected Class<?>[] getRootConfigClasses() {
    		return new Class[] {WebConfig.class};
    	}
    
    	@Override
    	protected Class<?>[] getServletConfigClasses() {
    		return null;
    	}
    
    	@Override
    	protected String[] getServletMappings() {
    		return new String[] {"/"};
    	}
    	//看這裡重寫方法,新增過濾器
    	@Override
    	protected Filter[] getServletFilters() {
    		HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
    		return new Filter[] {hiddenHttpMethodFilter};
    	}
    }
    複製程式碼

    XML配置:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app id="WebApp_ID" version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    >
        <filter>
            <filter-name>httpMethodFilter</filter-name>
            <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
        </filter>
    
        <filter-mapping>
            <filter-name>httpMethodFilter</filter-name>
            <!-- 請注意這裡Servlet過濾器 -->
            <servlet-name>mvc</servlet-name>
        </filter-mapping>
    
        <servlet>
            <servlet-name>mvc</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <load-on-startup>2</load-on-startup>
        </servlet>
    
        <servlet-mapping>
            <servlet-name>mvc</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    
        <welcome-file-list>
            <welcome-file>default.jsp</welcome-file>
        </welcome-file-list>
    </web-app>
    複製程式碼
  • (3)使用Postman測試

    胖哥學SpringMVC:請求方式轉換過濾器配置

    POST是真正的請求方式,傳遞一個"_method"名的引數,賦值為PUT或者DELETE(不區分大小寫),看控制檯執行的方法

相關文章