1. 程式人生 > >SpringMVC入門學習(二)

SpringMVC入門學習(二)

SpringMVC入門學習(二)

ssm框架  springMVC 

在上一篇部落格中,我簡單介紹了一下SpringMVC的環境配置,和簡單的使用,今天我們將進一步的學習下Springmvc的操作。

model.addAttribute()的使用

model介面的原始碼:

由圖可知,在addAttribute()中有兩種入參方式,一種是指明名字var1,一種是不指明名字var1。在不指明名字中,會通過相近的去尋找。

在addAttribute()中,我們可以放任何物件:

首先先匯入jsp標籤maven相關的庫

<!--servlet匯入-->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
    <scope>provided</scope>
</dependency>
<!--標籤庫的匯入-->
<dependency>
    <groupId
>
javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency>

controller裡面的程式碼

@RequestMapping("bye")
public String bye(Model model){
    // 放list
    List<String> byeList = new ArrayList<>();
    byeList.add("小明"
); byeList.add("小紅"); byeList.add("小方"); model.addAttribute("byeList",byeList); // 放Map Map<String,String> map= new HashMap<>(); map.put("one","第一個"); map.put("two","第二個"); map.put("three","第三個"); map.put("four","第四個"); model.addAttribute("map",map); // 放物件bean User user = new User(); user.setAge("18"); user.setName("帥哥"); model.addAttribute("user",user); return "bye"; }

jsp裡面的使用

放List <br>
<c:forEach  items="${byeList}" var="bye">
    ${bye}<br>
</c:forEach>

放map <br>
${map.one}<br>
${map.two}<br>
${map.three}<br>
${map.four}<br>

放物件bean <br>
${user.age} <br>
${user.name} <br>

轉發與重定向

這位博主的例子寫的挺好的部落格地址

假設你去辦理某個執照,

重定向:你先去了A局,A局的人說:“這個事情不歸我們管,去B局”,然後,你就從A退了出來,自己乘車去了B局。

轉發:你先去了A局,A局看了以後,知道這個事情其實應該B局來管,但是他沒有把你退回來,而是讓你坐一會兒,自己到後面辦公室聯絡了B的人,讓他們辦好後,送了過來。

  • 轉發forward:
    伺服器內部的操作,伺服器去請求目標地址的URL【同一個WEB下面的元件】,然後讀取返回結果,並將其傳送給瀏覽器。所以在客戶端看來,位址列是沒有變化的。
    【轉發頁面和轉發到的頁面能夠共享資料
  • 重定向redirect:
    重定向是客戶端的操作,伺服器告訴瀏覽器要去哪個網址,然後瀏覽器進行跳轉,然後瀏覽器的位址列就是跳轉的網址。
    不能共享資料

重定向

  1. 不帶引數的重定向

    /**
    * 不帶重定向到請求網址
    * @param model
    * @return 重定向的網址: /bye
    */
    @RequestMapping("redirect0")
    public String redirect1(Model model){
        return "redirect:/bye";
    }
    
  2. 帶引數的重定向
    (1)使用addAttribute進行字串拼接

    /**
    *  帶引數
    * @param attributes
    * @return 請求的網址是: /mian1?name=bird
    */
    @RequestMapping("redirect1")
    public String redirect1(RedirectAttributes attributes){
        attributes.addAttribute("name","bird");
        return "redirect:main1";
    }
    

    controller寫法:

    @RequestMapping("main1")
    public String main1(@RequestParam("name") String name, Model model){
        //通@RequestParam過獲得name資料
    
        model.addAttribute("name",name);
        return "redirect";
    }
    

    (2)使用addFlashAttribute

    /***
    *  
    *
    */
    @RequestMapping("redirect2")
    public String redirect2(RedirectAttributes attributes){
        /*
        * 此時請求的網址是:/mian2
        * addFlashAttribute()是將資料放在session裡面,但是session在頁面跳轉時,會馬上移除。
        */
        attributes.addFlashAttribute("name","xiaohuiFlash");
        return "redirect:main2";
    }
    

    controller的寫法:

    /* 與addAttribute不同的是,他是通過@ModelAttribute獲得資料
    *  
    */
    @RequestMapping("main2")
    public String main2(@ModelAttribute("name") String name, Model model){
        model.addAttribute("name",name);
        return "redirect";
    }
    

轉發

在Springmvc中請求是預設轉發到jsp中的【可以省略forward】,例如:

@RequestMapping("hello")
public String hello(Model model){
    model.addAttribute("hello","世界");
    return "hello";
}

此時是自動轉發到:/WEB-INF/jsp/hello.jsp【路徑設定問題在上一篇提到過】,當然如果檔案不在jsp資料夾中,則可以指令路徑,如:return "forward:WEB-INF/index/index.jsp"

如果要轉發到controller上,則必須加上forward:

@RequestMapping("hello")
public String hello(Model model){
    model.addAttribute("hello","世界");
    // 轉發到:/bye 的controller上面
    return "forward:bye";
}

關於請求路徑的問題

在Springmvc中支援ant風格的路徑,其中ANT萬用字元有三種:

萬用字元 說明
? 匹配任意一個字元【不能為空,不能為/】
* 匹配0個或則任意個字元
** 匹配0或則多個目錄

例子:

URL路徑 說明
/index?/get 可以為/index1/get,/index2/get,但是不能為/index/get
/index*/get 可以為/index1/get,/indexa1/get,也可以為/index/get
/index/**/get 可以為/index/one/get,/index/one/two/get,也可以為/index/get

其中,會根據最長匹配原則(has more characters)來進行匹配,例如:

/jsp/index/.jsp和/jsp/**/.jsp會優先匹配第一個

Springmvc設定字元編碼過濾器

在web.xml的配置檔案中:

<!-- characterEncodingFilter字元編碼過濾器 -->
<filter>
    <filter-name>characterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <!-- 需要使用的字符集 -->
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
        <!--是否強制設定request的編碼為encoding,即UTF-8,預設為false -->
        <param-name>forceRequestEncoding</param-name>
        <param-value>false</param-value>
    </init-param>
    <init-param>
        <!--是否強制設定response的編碼為encoding,即UTF-8 -->
        <param-name>forceResponseEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <!-- 這裡必須寫 /* -->
    <url-pattern>/*</url-pattern>
</filter-mapping>

注意:此時是設定預設的編碼方式,也即是說,可以在自己寫的程式碼中重新指令編碼方式。

關於靜態資源放行的問題

由於我們經Servlet設定的URI匹配模式是:/,所以,它將靜態資源js,css等等也當成了一個後臺請求從而導致404錯誤。

最簡單的解決方法,在Spring配置檔案中

<!-- 他將在Spring上下文中定義一個DefaultServletHttpRequestHandler來處理靜態資源,實際上就是將轉發給預設的servlet -->
<mvc:default-servlet-handler/>

但是此時會發現又會出現一個問題,那就是@RequestMapping("/path")不能訪問,這時候再配置檔案中再新增一句程式碼

<!-- 原因是因為當沒有mvc:default-servlet-handler時,框架預設註冊AnnotationMethodHandlerAdapter可以處理@RequestMapping,而當加入時,就沒有了,這時候加入mvc:annotation-driven就會註冊一個AnnotationMethodHandlerAdapter -->
<mvc:annotation-driven/>

關於form表單提交資料的方式

  • 方式一:直接將表單引數解除安裝Controller相應的方法的形參中。
    前端表單

    <form action="/form" method="post">
        <input type="text" name="name"><br>
        <input type="password" name="pwd"><br>
        <input type="submit" value="提交">
    </form>
    
    @RequestMapping("/form")
    後端接受資料
    public String getForm(String name,String pwd){
        /**
        * 在形參中,name和pwd要一一對應
        * @param name
        * @param pwd
        * @return
        */
        System.out.println("名字:"+name);
        System.out.println("密碼:"+pwd);
        return "";
    }
    
  • 方式二:使用HttpServletRequest接受資料

    @RequestMapping("/form")
    public String getForm(HttpServletRequest request){
        System.out.println("名字是"+request.getParameter("name"));
        System.out.println("密碼是"+request.getParameter("pwd"));
        return "";
    }
    
  • 通過一個Bean來接受資料【適合大量資料的情況】
    建立一個UserBean

    public class User {
        private String name;
        private String pwd;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getPwd() {
            return pwd;
        }
    
        public void setPwd(String pwd) {
            this.pwd = pwd;
        }
    }
    

    這時候就可將形參改為User了,注意User必須保留預設的構造方法

    @RequestMapping("/form")
    public String getForm(User user){
        System.out.println("名字是"+user.getName());
        System.out.println("密碼是"+user.getPwd());
        return "";
    }
    
  • 使用註解@RequestParam繫結請求引數到方法入參

    @RequestMapping("/form")
    public String getForm(@RequestParam("name")String name,@RequestParam(value = "pwd")String pwd){
        System.out.println("名字是"+name);
        System.out.println("密碼是"+pwd);
        return "";
    }
    

    當然這時候,如果請求的資料沒有pwd,比如說請求的資料是:/form?name=one,那麼程式便會報錯

    13-Nov-2018 02:00:11.459 警告 [http-nio-8080-exec-9] org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver.resolveException Resolved [org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'pwd' is not present]
    

    這時候可以設定@RequestParam的屬性required為false

    //此時要將value補上,同時可以設定defaultValue 也就是預設值
    @RequestParam(value = "name",required=false)   
    
    @RequestParam(value = "name",required=false,defaultValue="0")String name   
    
  • 使用@PathVariable獲得路徑的引數

    @RequestMapping("/form1/{name}/{pwd}")
    public String form1(@PathVariable String name,@PathVariable String pwd){
        System.out.println("使用@");
        System.out.println("名字是"+name);
        System.out.println("密碼是"+pwd);
        return "";
    }
    

    這時候如果訪問http://localhost:8080/form1/one/two使,那麼one將繫結在name上,two將繫結在pwd上面。

    輸出結果:

    名字是one
    密碼是two
    

關於時間日期提交的問題

當我們的資料庫中含有Data型別的資料時,因為form表單提交的是String型別,而在SpringMVC中無法自動的將String型別的轉為Data型別,從而無法將資料寫入實體類和資料庫。解決方法如下:

  • 使用@DateTimeFormat註解

    // 實體類UserDate,在Date上面加上註解
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date date;
    

    Controller類不需要有任何變化

    @RequestMapping("/formData")
    public String formData(UserDate userData) {
        return "";
    }
    
  • 使用@InitBinder註解
    @InitBinder用於在@Controller中標註於方法,表示為當前控制器註冊一個屬性編輯器或者其他,只對當前的Controller有效。

    // 這個方法會在控制器中其他方法之前呼叫,這樣就可以預先處理資料
    @InitBinder
    public void InitBinder(WebDataBinder binder){
        DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        // 第二個引數表示是否允許為空
        CustomDateEditor dateEditor = new CustomDateEditor(format,true);
        //註冊自定義的日期轉換格式
        binder.registerCustomEditor(Date.class,dateEditor);
    }
    

天地有正氣,雜然賦流形。下則為河嶽,上則為日星。於人曰浩然,沛乎塞蒼冥。