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:
重定向是客戶端
的操作,伺服器告訴瀏覽器要去哪個網址,然後瀏覽器進行跳轉,然後瀏覽器的位址列就是跳轉的網址。
【不能共享資料
】
重定向
-
不帶引數的重定向
/** * 不帶重定向到請求網址 * @param model * @return 重定向的網址: /bye */ @RequestMapping("redirect0") public String redirect1(Model model){ return "redirect:/bye"; }
-
帶引數的重定向
(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來接受資料【適合大量資料的情況】
建立一個UserBeanpublic 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); }
天地有正氣,雜然賦流形。下則為河嶽,上則為日星。於人曰浩然,沛乎塞蒼冥。