天天看點

四、SpringMVC擷取請求參數的方式與設定編碼       四、SpringMVC擷取請求參數

       四、SpringMVC擷取請求參數

1、通過ServletAPI擷取

        首先,我們從浏覽器發送的請求首先會被@RequestMapping這個注解進行比對,如果比對成功,那麼就會由我們的控制器方法來處理請求,但是也說過,我們在之前web.xml中注冊前端控制器,我們浏覽器發出的請求先要被前端控制器處理,之後又執行了相對應的控制器方法,是以說将我們的請求與@RequestMapping進行比對,來找到我們的控制器方法這個過程,就是由DispatcherServlet所完成的,是以說當我們的DispatcherServlet間接調用控制器方法(中間還有其他元件),在我們的DispatcherServlet中封裝了許多資料,當我們調用目前的控制器方法的時候,就會根據我們目前的控制器方法的參數,然後來為目前的方法去注入這個參數(為參數指派)

@RequestMapping标注的方法就為控制器方法,由DispatcherServlet調用,根據你的形參如HttpServletRequest的對象,DispatcherServlet既可以将表示目前請求的Request對象指派給這個參數

@RequestMapping("/testServletAPI")
    //形參位置上的request表示目前請求
    public String testServletAPI(HttpServletRequest request){

    }
           

怎麼傳輸請求參數呢?要麼在後面寫問号,要麼寫小括号

<a th:href="@{/testServletAPI(username='admin',password=123456)}" target="_blank" rel="external nofollow" >測試使用servletAPI擷取請求參數</a>
           

此時方法裡有了request(目前請求),此時處理猶如的得心應手,直接request.getParameter()(這個方法是根據name擷取value)擷取請求參數就OK了

public String testServletAPI(HttpServletRequest request){
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        System.out.println("username"+username+",password:"+password);
        return "success";
    }
           

我們在使用SpringMVC的時候,能不用原生API就不用,因為我們要操作的這些資料,我們的SpringMVC已經幫我們擷取過了,并給我們提供了一些簡單的方式去擷取,我們根本沒有必要用原生的ServletAPI(侮辱了SpringMVC手動狗頭)

2、通過控制器方法的形參來擷取參數

        咱們隻要能保證方法的形參名與請求參數的名字保持一緻就可以自動的将我們的請求參數賦給它所對應的形參

@RequestMapping("/testParam")
    public String testParam(String username,String password){
        System.out.println("username="+username+",password="+password);
        return "success";
    }
           

這時候就來了,我們要是有多個重名的請求參數(如複選框)該怎麼辦呢,上面原生ServletAPI就得用request.getParameterValues方法(傳回的是一個String類型的數組),裡面就包含參數的值,而SpringMVC可以直接用字元串或者字元串數組都可以,用字元串為參數此重名參數傳回的所有值通過逗号來進行拼接,用字元串數組為參數輸出則為[a,b,c]

@RequestMapping("/testParam")
    public String testParam(String username,String password,String hobby){
        System.out.println("username="+username+",password="+password+",hobby:"+hobby);
        return "success";
    }
           
@RequestMapping("/testParam")
    public String testParam(String username,String password,String[] hobby){
        System.out.println("username="+username+",password="+password+",hobby:"+ Arrays.toString(hobby));
        return "success";
    }
           

問題:如果遇到請求參數的參數名與形參的參數名不一緻怎麼辦呢,例如請求參數中名為username改為user_name,這時候沒辦法擷取這個值,如果這樣的話就得在控制器中加上一個SpingMVC提供的@RequestParam注解,将我們的請求參數跟我們的形參來建立映射關系的,就是說你需要拿哪一個請求參數對應哪一個形參。

@RequestParam源碼中有value,required,defaultValue屬性,首先是xml檔案裝配Bean,能裝就裝,裝不了拉倒,而使用注解自動裝配如果裝配不了,就是說在目前IOC容器中沒有任何一個Bean為目前的屬性自動指派,會報no such bean 錯誤,是因為自動裝配的@autowierd注解裡面也有一個屬性,叫做required(),預設值也是true,就是說必須自動裝配,裝配不了就報錯,@RequestParam中required()中預設為true,就是必須要在浏覽器中傳輸參數數值,可以用defaultValue預設數值防止報錯(沒輸入值或者輸入空字元串時)。

@RequestParam(value = "user_name",required = false,defaultValue = "hehe") String username
           

@RequestHeader是将請求頭資訊和控制器方法的形參建立映射關系

@CookieValue是将cookie資料和控制器方法的形參建立映射關系

兩種會話技術的關系,Session依賴于Cookie,Cookie是用戶端的會話技術,Session是伺服器端的會話技術,當調用getSession方法的時候,本質上會建立一個鍵為JSESSIONID的Cookie

例子:如第一次進入,那麼就會第一次建立HttpSession對象,将Session放在伺服器所維護的Map集合中,并且去建立的Cookie,Cookie的鍵是固定的,是JSESSIONID,它的值是一個随機序列,在響應頭中,作為Map集合的鍵,然後把咱們的Session對象作為Map集合的值進行存儲,存儲在伺服器的内部,再把Cookie響應到浏覽器,此時是在響應(封包)頭中,從此之後JSESSIONID的Cookie從此之後就會在請求頭(封包)中,因為Cookie也是這樣的工作原理,伺服器建立響應到浏覽器之後,以後每一次浏覽器向伺服器發送請求都會攜帶Cookie。

3、通過POJO擷取請求參數

        在我們擷取請求參數的過程中,有的時候請求參數非常的多,比如添加修改的功能,使用mysql資料庫,我們所添加的這些資料就要所對應目前資料庫中的字段,我們資料庫同樣對應我們的實體類對象,我們也可以說在我們頁面中添加的這些資料跟咱們的實體類對象中的屬性也是一一對應的,SpringMVC給我們提供了一個非常簡單的方式,如果目前我從浏覽器發送的請求所送出的這些請求參數然後他跟我們目前實體類對象裡的屬性一一對應,那我們就可以直接在形參位置直接去寫一個實體類型的對象,隻需要保證我們請求參數的名字跟我們實體類對象中的屬性名保持一緻就可以自動通過實體類對象收集這些請求參數。省去了從rep中取值,再new對象,進行指派的過程。

tips:架構裡面用到的好多技術都是反射,通過反射建立類型對象的時候,預設的使用是無參構造

如果不學習通過實體類擷取請求參數的話,那就需要在控制器方法中寫好多好多的參數,就像第二個通過控制器方法的形參擷取參數一樣,是以可以直接通過我們的User對象進行擷取

@RequestMapping("/testBean")
    public String testBean(User user){
        System.out.println(user);
        return "success";
    }
           

4、亂碼問題(用過濾器處理)

        如果出現亂碼(字元串編碼不一緻),原來出現亂碼是使用request.setCharacterEncoding(針對post請求的亂碼問題),那我們現在想要處理亂碼問題,因為沒有用Request對象(有也沒用),因為在設定請求對象編碼的時候,有一個前提條件,如果說在這之前,你已經擷取了咱們的某一個請求參數,那麼之後設定編碼是沒有任何效果的,再上一個階段,如果在BaseServlet已經對我們request設定了編碼,然後在通過BaseServlet在通路我們具體處理方法的請求的時候,就不會出現亂碼問題,如果把編碼放在具體處理方法裡面,是沒有任何效果的。get請求的亂碼是由Tomcat造成的,我們要想解決get的亂碼需要改tomcat中的server.xml檔案中的端口号的地方加上屬性URLEncoding編碼改為UTF-8,八版本以後預設UTF-8。

        Dispatcher擷取請求參數在前擷取Request對象設定編碼在後,是以說就算有在SpringMVC中擷取Request對象也沒用,是以要想找到一種技術或者一種元件,在Dispathcer後去請求參數前就設定編碼,伺服器中三大元件(過濾器,監聽器,Servlet),ServletContextListener(監聽器)加載時間最早,之後是過濾器,在之後是Servlet,監聽器隻是監聽Servlet的建立和銷毀,隻要我們設定了過濾路徑(目前所通路的請求位址滿足過濾路徑),都會由過濾器進行過濾,SpringMVC已經為我們提供好了,是以說要想過濾器生效,隻需要在web.xml中進行注冊(配置)。

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

        此時仍不能設定編碼的成功,因為沒有設定編碼格式,是以翻到源碼CharacterEncodingFilter找到執行過濾的方法,可以找有沒有FilterChain,放行就是用的這個參數,沒這個參數放不了行。找到後發現

四、SpringMVC擷取請求參數的方式與設定編碼       四、SpringMVC擷取請求參數

需要設定裡面的encoding屬性的值并且裡面的if中forceRequestEncoding為true(預設為false)或request.getCharacterEncoding為null(沒設定預設為null)才可以設定請求編碼,是以我們用

四、SpringMVC擷取請求參數的方式與設定編碼       四、SpringMVC擷取請求參數

 是以說根據上面的源碼要想在設定響應編碼,還需要一個<init-param>中設定forceResponseEncoding(源碼裡的屬性)設定為true

四、SpringMVC擷取請求參數的方式與設定編碼       四、SpringMVC擷取請求參數

 小知識點:響應浏覽器的方式除了我們的轉發重定向,還有response.getwriter.writer(),響應浏覽器資料。