1 包裝類型pojo參數綁定
ps:即參數對象的屬性也是對象,將所有參數封裝到一個對象中(對象的屬性由多個對象屬性組成)
使用場景:
1,當映射的方法需要多個參數對象的時候,
2,參數對象具有相同的屬性,需要對相同屬性賦值
不如將所有對象參數組合成一個類,統一進行處理
1.1 需求
商品查詢controller方法中實現商品查詢條件傳入。
1.2 實現方法
第一種方法:
在形參中 添加HttpServletRequest request參數,通過request接收查詢條件參數。
第二種方法:
在形參中讓包裝類型的pojo接收查詢條件參數。
分析:
頁面傳參數的特點:復雜,多樣性。條件包括 :用戶賬號、商品編號、訂單信息。。。
如果將用戶賬號、商品編號、訂單信息等放在簡單pojo(屬性是簡單類型)中,pojo類屬性比較多,比較亂。
建議使用包裝類型的pojo,pojo中屬性是pojo。
1.3 頁面參數和controller方法形參定義
頁面參數:
商品名稱:<input name="itemsCustom.name" /> (ps:該名字對應是屬性對象的屬性) 注意:itemsCustom和包裝pojo中的屬性一致即可。
controller方法形參:
public ModelAndView queryItems(HttpServletRequest request,ItemsQueryVo itemsQueryVo) throws Exception

2 集合類型綁定
2.1 數組綁定
2.1.1 需求
商品批量刪除,用戶在頁面選擇多個商品,批量刪除。
2.1.2 表現層實現
關鍵:將頁面選擇(多選)的商品id,傳到controller方法的形參,方法形參使用數組接收頁面請求的多個商品id。
controller方法定義:

@Controller // 為了對url進行分類管理 ,可以在這里定義根路徑,最終訪問url是根路徑+子路徑 // 比如:商品列表:/items/queryItems.action @RequestMapping("/items") public class ItemsController { @Autowired private ItemsService itemsService; // 商品分類 //itemtypes表示最終將方法返回值放在request中的key @ModelAttribute("itemtypes") public Map<String, String> getItemTypes() { Map<String, String> itemTypes = new HashMap<String, String>(); itemTypes.put("101", "數碼"); itemTypes.put("102", "母嬰"); return itemTypes; } // 商品查詢 @RequestMapping("/queryItems") public ModelAndView queryItems(HttpServletRequest request, ItemsQueryVo itemsQueryVo) throws Exception { // 測試forward后request是否可以共享 System.out.println(request.getParameter("id")); // 調用service查找 數據庫,查詢商品列表 List<ItemsCustom> itemsList = itemsService.findItemsList(itemsQueryVo); // 返回ModelAndView ModelAndView modelAndView = new ModelAndView(); // 相當 於request的setAttribut,在jsp頁面中通過itemsList取數據 modelAndView.addObject("itemsList", itemsList); // 指定視圖 // 下邊的路徑,如果在視圖解析器中配置jsp路徑的前綴和jsp路徑的后綴,修改為 // modelAndView.setViewName("/WEB-INF/jsp/items/itemsList.jsp"); // 上邊的路徑配置可以不在程序中指定jsp路徑的前綴和jsp路徑的后綴 modelAndView.setViewName("items/itemsList"); return modelAndView; } // 商品信息修改頁面顯示 // @RequestMapping("/editItems") // 限制http請求方法,可以post和get // @RequestMapping(value="/editItems",method={RequestMethod.POST,RequestMethod.GET}) // public ModelAndView editItems()throws Exception { // // //調用service根據商品id查詢商品信息 // ItemsCustom itemsCustom = itemsService.findItemsById(1); // // // 返回ModelAndView // ModelAndView modelAndView = new ModelAndView(); // // //將商品信息放到model // modelAndView.addObject("itemsCustom", itemsCustom); // // //商品修改頁面 // modelAndView.setViewName("items/editItems"); // // return modelAndView; // } @RequestMapping(value = "/editItems", method = { RequestMethod.POST, RequestMethod.GET }) // @RequestParam里邊指定request傳入參數名稱和形參進行綁定。 // 通過required屬性指定參數是否必須要傳入 // 通過defaultValue可以設置默認值,如果id參數沒有傳入,將默認值和形參綁定。 public String editItems(Model model, @RequestParam(value = "id", required = true) Integer items_id) throws Exception { // 調用service根據商品id查詢商品信息 ItemsCustom itemsCustom = itemsService.findItemsById(items_id); //判斷商品是否為空,根據id沒有查詢到商品,拋出異常,提示用戶商品信息不存 在 // if(itemsCustom == null){ // throw new CustomException("修改的商品信息不存在!"); // } // 通過形參中的model將model數據傳到頁面 // 相當於modelAndView.addObject方法 model.addAttribute("items", itemsCustom); return "items/editItems"; } //查詢商品信息,輸出json ///itemsView/{id}里邊的{id}表示占位符,通過@PathVariable獲取占位符中的參數, //如果占位符中的名稱和形參名一致,在@PathVariable可以不指定名稱 @RequestMapping("/itemsView/{id}") public @ResponseBody ItemsCustom itemsView(@PathVariable("id") Integer id)throws Exception{ //調用service查詢商品信息 ItemsCustom itemsCustom = itemsService.findItemsById(id); return itemsCustom; } // 商品信息修改提交 // 在需要校驗的pojo前邊添加@Validated,在需要校驗的pojo后邊添加BindingResult // bindingResult接收校驗出錯信息 // 注意:@Validated和BindingResult bindingResult是配對出現,並且形參順序是固定的(一前一后)。 // value={ValidGroup1.class}指定使用ValidGroup1分組的 校驗 // @ModelAttribute可以指定pojo回顯到頁面在request中的key @RequestMapping("/editItemsSubmit") public String editItemsSubmit( Model model, HttpServletRequest request, Integer id, @ModelAttribute("items") @Validated(value = { ValidGroup1.class }) ItemsCustom itemsCustom, BindingResult bindingResult, MultipartFile items_pic//接收商品圖片 ) throws Exception { // 獲取校驗錯誤信息 if (bindingResult.hasErrors()) { // 輸出錯誤信息 List<ObjectError> allErrors = bindingResult.getAllErrors(); for (ObjectError objectError : allErrors) { // 輸出錯誤信息 System.out.println(objectError.getDefaultMessage()); } // 將錯誤信息傳到頁面 model.addAttribute("allErrors", allErrors); //可以直接使用model將提交pojo回顯到頁面 model.addAttribute("items", itemsCustom); // 出錯重新到商品修改頁面 return "items/editItems"; } //原始名稱 String originalFilename = items_pic.getOriginalFilename(); //上傳圖片 if(items_pic!=null && originalFilename!=null && originalFilename.length()>0){ //存儲圖片的物理路徑 String pic_path = "F:\\develop\\upload\\temp\\"; //新的圖片名稱 String newFileName = UUID.randomUUID() + originalFilename.substring(originalFilename.lastIndexOf(".")); //新圖片 File newFile = new File(pic_path+newFileName); //將內存中的數據寫入磁盤 items_pic.transferTo(newFile); //將新圖片名稱寫到itemsCustom中 itemsCustom.setPic(newFileName); } // 調用service更新商品信息,頁面需要將商品信息傳到此方法 itemsService.updateItems(id, itemsCustom); // 重定向到商品查詢列表 // return "redirect:queryItems.action"; // 頁面轉發 // return "forward:queryItems.action"; return "success"; } // 批量刪除 商品信息 @RequestMapping("/deleteItems") public String deleteItems(Integer[] items_id) throws Exception { // 調用service批量刪除商品 // ... return "success"; } // 批量修改商品頁面,將商品信息查詢出來,在頁面中可以編輯商品信息 @RequestMapping("/editItemsQuery") public ModelAndView editItemsQuery(HttpServletRequest request, ItemsQueryVo itemsQueryVo) throws Exception { // 調用service查找 數據庫,查詢商品列表 List<ItemsCustom> itemsList = itemsService.findItemsList(itemsQueryVo); // 返回ModelAndView ModelAndView modelAndView = new ModelAndView(); // 相當 於request的setAttribut,在jsp頁面中通過itemsList取數據 modelAndView.addObject("itemsList", itemsList); modelAndView.setViewName("items/editItemsQuery"); return modelAndView; } // 批量修改商品提交 // 通過ItemsQueryVo接收批量提交的商品信息,將商品信息存儲到itemsQueryVo中itemsList屬性中。 @RequestMapping("/editItemsAllSubmit") public String editItemsAllSubmit(ItemsQueryVo itemsQueryVo) throws Exception { return "success"; } }
頁面定義:
ps:下面省略了表單的提交的標簽內容

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>查詢商品列表</title> <script type="text/javascript"> function deleteItems(){ //提交form document.itemsForm.action="${pageContext.request.contextPath }/items/deleteItems.action"; document.itemsForm.submit(); } function queryItems(){ //提交form document.itemsForm.action="${pageContext.request.contextPath }/items/queryItems.action"; document.itemsForm.submit(); } </script> </head> <body> 當前用戶:${username }, <c:if test="${username!=null }"> <a href="${pageContext.request.contextPath }/logout.action">退出</a> </c:if> <form name="itemsForm" action="${pageContext.request.contextPath }/items/queryItems.action" method="post"> 查詢條件: <table width="100%" border=1> <tr> <td> 商品名稱:<input name="itemsCustom.name" /> 商品類型: <select name="itemtype"> <c:forEach items="${itemtypes }" var="itemtype"> <option value="${itemtype.key }">${itemtype.value }</option> </c:forEach> </select> </td> <td><input type="button" value="查詢" onclick="queryItems()"/> <input type="button" value="批量刪除" onclick="deleteItems()"/> </td> </tr> </table> 商品列表: <table width="100%" border=1> <tr> <td>選擇</td> <td>商品名稱</td> <td>商品價格</td> <td>生產日期</td> <td>商品描述</td> <td>操作</td> </tr> <c:forEach items="${itemsList }" var="item"> <tr> <td><input type="checkbox" name="items_id" value="${item.id}"/></td> <td>${item.name }</td> <td>${item.price }</td> <td><fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/></td> <td>${item.detail }</td> <td><a href="${pageContext.request.contextPath }/items/editItems.action?id=${item.id}">修改</a></td> </tr> </c:forEach> </table> </form> </body> </html>
2.2 list綁定
2.2.1 需求
通常在需要批量提交數據時,將提交的數據綁定到list<pojo>中,比如:成績錄入(錄入多門課成績,批量提交),
本例子需求:批量商品修改,在頁面輸入多個商品信息,將多個商品信息提交到controller方法中。
2.2.2 表現層實現
controller方法定義:
1、進入批量商品修改頁面(頁面樣式參考商品列表實現)
2、批量修改商品提交 使用List接收頁面提交的批量數據,通過包裝pojo接收,在包裝pojo中定義list<pojo>屬性

頁面定義:

(ps: 以上作為多條文本框,表單提交)
1.1 map綁定
也通過在包裝pojo中定義map類型屬性。
在包裝類中定義Map對象,並添加get/set方法,action使用包裝對象接收。
包裝類中定義Map對象如下:
Public class QueryVo { private Map<String, Object> itemInfo = new HashMap<String, Object>(); //get/set方法.. }
頁面定義如下:
<tr> <td>學生信息:</td> <td> 姓名:<inputtype="text"name="itemInfo['name']"/> 年齡:<inputtype="text"name="itemInfo['price']"/> .. .. .. </td> </tr>
Contrller方法定義如下:
public String useraddsubmit(Model model,QueryVo queryVo)throws Exception{
System.out.println(queryVo.getStudentinfo());
}
3 springmvc校驗
3.1 校驗理解
項目中,通常使用較多是前端的校驗,比如頁面中js校驗。對於安全要求較高點建議在服務端進行校驗。
服務端校驗:
控制層conroller:校驗頁面請求的參數的合法性。在服務端控制層conroller校驗,不區分客戶端類型(瀏覽器、手機客戶端、遠程調用)
業務層service(使用較多):主要校驗關鍵業務參數,僅限於service接口中使用的參數。
持久層dao:一般是不校驗的。
3.2 springmvc校驗需求
springmvc使用hibernate的校驗框架validation(和hibernate沒有任何關系)。
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd "> <!-- 可以掃描controller、service、... 這里讓掃描controller,指定controller的包 --> <context:component-scan base-package="cn.itcast.ssm.controller"></context:component-scan> <!-- 靜態資源解析 包括 :js、css、img、.. --> <mvc:resources location="/js/" mapping="/js/**"/> <mvc:resources location="/img/" mapping="/img/**"/> <!--注解映射器 --> <!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> --> <!--注解適配器 --> <!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/> --> <!-- 使用 mvc:annotation-driven代替上邊注解映射器和注解適配器配置 mvc:annotation-driven默認加載很多的參數綁定方法, 比如json轉換解析器就默認加載了,如果使用mvc:annotation-driven不用配置上邊的RequestMappingHandlerMapping和RequestMappingHandlerAdapter 實際開發時使用mvc:annotation-driven --> <mvc:annotation-driven conversion-service="conversionService" validator="validator"></mvc:annotation-driven> <!-- 視圖解析器 解析jsp解析,默認使用jstl標簽,classpath下的得有jstl的包 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 配置jsp路徑的前綴 --> <property name="prefix" value="/WEB-INF/jsp/"/> <!-- 配置jsp路徑的后綴 --> <property name="suffix" value=".jsp"/> </bean> <!-- 自定義參數綁定 --> <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <!-- 轉換器 --> <property name="converters"> <list> <!-- 日期類型轉換 --> <bean class="cn.itcast.ssm.controller.converter.CustomDateConverter"/> </list> </property> </bean> <!-- 校驗器 --> <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"> <!-- hibernate校驗器--> <property name="providerClass" value="org.hibernate.validator.HibernateValidator" /> <!-- 指定校驗使用的資源文件,在文件中配置校驗錯誤信息,如果不指定則默認使用classpath下的ValidationMessages.properties --> <property name="validationMessageSource" ref="messageSource" /> </bean> <!-- 校驗錯誤信息配置文件 --> <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <!-- 資源文件名--> <property name="basenames"> <list> <value>classpath:CustomValidationMessages</value> </list> </property> <!-- 資源文件編碼格式 --> <property name="fileEncodings" value="utf-8" /> <!-- 對資源文件內容緩存時間,單位秒 --> <property name="cacheSeconds" value="120" /> </bean> <!-- 全局異常處理器 只要實現HandlerExceptionResolver接口就是全局異常處理器 --> <bean class="cn.itcast.ssm.exception.CustomExceptionResolver"></bean> <!-- 文件上傳 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 設置上傳文件的最大尺寸為5MB --> <property name="maxUploadSize"> <value>5242880</value> </property> </bean> <!--攔截器 --> <mvc:interceptors> <!--多個攔截器,順序執行 --> <!-- 登陸認證攔截器 --> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="cn.itcast.ssm.interceptor.LoginInterceptor"></bean> </mvc:interceptor> <mvc:interceptor> <!-- /**表示所有url包括子url路徑 --> <mvc:mapping path="/**"/> <bean class="cn.itcast.ssm.interceptor.HandlerInterceptor1"></bean> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="cn.itcast.ssm.interceptor.HandlerInterceptor2"></bean> </mvc:interceptor> </mvc:interceptors> </beans>
校驗思路:
頁面提交請求的參數,請求到controller方法中,使用validation進行校驗。如果校驗出錯,將錯誤信息展示到頁面。
具體需求:
商品修改,添加校驗(校驗商品名稱長度,生產日期的非空校驗),如果校驗出錯,在商品修改頁面顯示錯誤信息。
3.3 環境准備
hibernate的校驗框架validation所需要jar包:

3.4 配置校驗器(springmvc.xml)
<!-- 校驗器 --> <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"> <!-- hibernate校驗器--> <property name="providerClass" value="org.hibernate.validator.HibernateValidator" /> <!-- 指定校驗使用的資源文件,在文件中配置校驗錯誤信息,如果不指定則默認使用classpath下的ValidationMessages.properties --> <property name="validationMessageSource" ref="messageSource" /> </bean> <!-- 校驗錯誤信息配置文件 --> <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <!-- 資源文件名--> <property name="basenames"> <list> <value>classpath:CustomValidationMessages</value> </list> </property> <!-- 資源文件編碼格式 --> <property name="fileEncodings" value="utf-8" /> <!-- 對資源文件內容緩存時間,單位秒 --> <property name="cacheSeconds" value="120" /> </bean>
3.5 校驗器注入到處理器適配器中
<mvc:annotation-driven conversion-service="conversionService" validator="validator"></mvc:annotation-driven>
3.6 在pojo中添加校驗規則
在ItemsCustom.java中添加校驗規則:

3.7 CustomValidationMessages.properties
在CustomValidationMessages.properties配置校驗錯誤信息:

3.8 捕獲校驗錯誤信息
//在需要校驗的pojo前邊添加@Validated,在需要校驗的pojo后邊添加BindingResult bindingResult接收校驗出錯信息 //注意:@Validated和BindingResult bindingResult是配對出現,並且形參順序是固定的(一前一后)。 @RequestMapping("/editItemsSubmit") public String editItemsSubmit( HttpServletRequest request,Integer id,@Validated ItemsCustom itemsCustom,BindingResult bindingResult) throws Exception {
3.9 在頁面顯示校驗錯誤信息
在controller中將錯誤信息傳到頁面即可。

頁面顯示錯誤信息:

3.10 分組校驗
ps:任意將幾條校驗規則可以分為不同組(不同組規則可以重復),組名為自定義定義不同接口的名字
3.10.1 需求
在pojo中定義校驗規則,而pojo是被多個 controller所共用,當不同的controller方法對同一個pojo進行校驗,但是每個controller方法需要不同的校驗。
解決方法:
定義多個校驗分組(其實是一個java接口),分組中定義有哪些規則
每個controller方法使用不同的校驗分組
3.10.2 校驗分組

3.10.3 在校驗規則中添加分組

ps:驗證規則上可以同時定義多個組
3.10.4 在controller方法使用指定分組的校驗

4 數據回顯
4.1 什么數據回顯
提交后,如果出現錯誤,將剛才提交的數據回顯到剛才的提交頁面。
ps:即表單的數據,提交后還在頁面上(一般用於提交失敗,方便重新修改)
4.2 pojo數據回顯方法
1、springmvc默認對pojo數據進行回顯。
1,pojo數據傳入controller方法后,springmvc自動將pojo數據放到request域,key等於pojo類型(首字母小寫)
(ps:也就是說,跳轉的頁面自動從傳入的數據中取值,但是頁面的屬性名稱和傳入的對象名稱必須對應,也可以通過注解自定義名稱)

2,使用@ModelAttribute指定pojo回顯到頁面在request中的key(方法中添加注解,自定義前端屬性的名稱)

前端頁面:

2、@ModelAttribute還可以將方法的返回值傳到頁面
在商品查詢列表頁面,通過商品類型查詢商品信息。
在controller中定義商品類型查詢方法,最終將商品類型傳到頁面。

頁面上可以得到itemTypes數據。

3、使用最簡單方法,直接使用model存入,可以不用@ModelAttribute

4.3 簡單類型數據回顯
使用最簡單方法使用model。
model.addAttribute("id", id);
ps:默認對象參數會被自動存入request域中,簡單類型需要手動存入,model對象的數據會自動存入request域中。
