springmvc概述(4)(不同對象[pojo/數組/list/map]參數綁定,校驗,數據回顯)


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

}
ItemsController.java

頁面定義:

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>
itemsList.jsp

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>
springmvc.xml

校驗思路:

頁面提交請求的參數,請求到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域中。

 


免責聲明!

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



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