SpringMVC入門學習(二)


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);
    }
    

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM