文檔版本 | 開發工具 | 測試平臺 | 工程名字 | 日期 | 作者 | 備註 |
---|---|---|---|---|---|---|
V1.0 | 2016.07.01 | lutianfei | none |
商品修改功能開發
一、需求
- 操作流程:
- 1、進入商品查詢列表頁面
- 2、點擊修改,進入商品修改頁面,頁面中顯示了要修改的商品(從數據庫查詢)
- 要修改的商品從數據庫查詢,根據商品id(主鍵)查詢商品信息
- 3、在商品修改頁面,修改商品信息,修改後,點擊提交
二、開發mapper
- mapper:
- 根據id查詢商品信息
- 根據id更新Items表的數據
- 不用開發了,使用逆向工程生成的代碼。
- mapper:
三、開發service
- 接口功能:
- 根據id查詢商品信息
- 修改商品信息
- 接口功能:
// ItemsServiceImpl
@Override
public ItemsCustom findItemsById(Integer id) throws Exception{
Items items= itemsMappper.selectByPrimaryKey(id);
//中間對信息進行了業務處理
//。。。
//返回ItemsCustom
ItemsCustom itemsCustom = new ItemsCustom();
//將items的屬性拷貝到itemsCustom中
BeanUtils.copyProperties(items,itemsCustom);
return itemsCustoom;
}
@Override
public void updateItems(Integer id, ItemsCustom itemsCustom) throws Execption{
//添加業務校驗,通常在service接口對關鍵參數進行校驗
//校驗id是否爲空,如果爲空,拋出異常
// 更新商品信息
//因爲有大文本類型屬性所以要使用updateByPrimaryKeyWithBLOBs函數
itmesCustom.setId(id); //updateByPrimaryKeyWithBLOBs要求必須傳人id。
itemsMapper.updateByPrimaryKeyWithBLOBs(itemsCustom);
}
- 四、開發controller
- 方法:
- 商品信息修改頁面顯示
- 方法:
@RequestMapping("/editItems")
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("/editItemsSubmit")
public ModelAndView editItemsSubmit() throws Exception{
//調用service更新商品信息,頁面需要將商品信息傳到此方法
//。。。。。
//返回ModelAndView
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("success");
return modelAndView;
}
- 添加success.jsp 和 editItems.jsp
springmvc註解開發
@RequestMapping
註解
- 通過RequestMapping註解可以定義不同的處理器映射規則。
URL路徑映射
- @RequestMapping(value=”/item”)或@RequestMapping(“/item)
- value的值是數組,可以將多個url映射到同一個方法
窄化請求映射
- 在class上添加
@RequestMapping(url)
指定通用請求前綴, 限制此類下的所有方法請求url必須以請求前綴開頭,通過此方法對url進行分類管理。 - 如下:
- @RequestMapping放在類名上邊,設置請求前綴
- @Controller
- @RequestMapping(“/item”)
- 方法名上邊設置請求映射url:@RequestMapping放在方法名上邊,如下:
- @RequestMapping(“/queryItem “)
- 訪問地址爲:/item/queryItem
- @RequestMapping放在類名上邊,設置請求前綴
請求方法限定
- 限定GET方法
- @RequestMapping(method = RequestMethod.GET)
- 如果通過Post訪問則報錯:
- HTTP Status 405 - Request method** ‘POST’** not supported
例如:
- @RequestMapping(value=”/editItem”,method=RequestMethod.GET)
限定POST方法
- @RequestMapping(method = RequestMethod.POST)
- 如果通過Post訪問則報錯:
- HTTP Status 405 - Request method ‘GET’ not supported
- GET和POST都可以
- @RequestMapping(method={RequestMethod.GET,RequestMethod.POST})
controller方法返回值
- 返回ModelAndView
- controller方法中定義ModelAndView對象並返回,對象中可添加model數據、指定view。
- 需要方法結束時,定義ModelAndView,將model和view分別進行設置。
//指定邏輯視圖名,經過視圖解析器解析爲jsp物理路徑:/WEB-INF/jsp/item/editItem.jsp
return "item/editItem";
- 返回string
- 當controller方法返回string時,會有如下3種情況:
1、表示返回邏輯視圖名。真正視圖(jsp路徑)=前綴+邏輯視圖名+後綴
2、redirect重定向
- 商品修改提交後,重定向到商品查詢列表。
- redirect重定向特點:瀏覽器地址欄中的url會變化。修改提交的request數據無法傳到重定向的地址。因爲重定向後重新進行request(request無法共享)
- 注: 這裏因爲在同一個類下,不需要將窄化映射的路徑加入其中
- redirect方式相當於“response.sendRedirect()”,轉發後瀏覽器的地址欄變爲轉發後的地址,因爲轉發即執行了一個新的request和response。
- 由於新發起一個request原來的參數在轉發時就不能傳遞到下一個url,如果要傳參數可以/item/queryItem.action後邊加參數,如下:
- /item/
queryItem?...&…
3、forward頁面轉發
- 通過forward進行頁面轉發,瀏覽器地址欄url不變,request可以共享。
- forward方式相當於
request.getRequestDispatcher().forward(request,response)
,轉發後瀏覽器地址欄還是原來的地址。轉發並沒有執行新的request和response,而是和轉發前的請求共用一個request和response。所以轉發前請求的參數在轉發後仍然可以讀取到。
//結果轉發到editItem.action,request可以帶過去
return "forward:editItem.action";
- 返回void
- 在controller方法形參上可以定義request和response,使用request或response指定響應結果:
- 1、使用request轉向頁面,如下:
- request.getRequestDispatcher(“頁面路徑”).forward(request, response);
- 2、也可以通過response頁面重定向:
- response.sendRedirect(“url”)
- 3、也可以通過response指定響應結果,例如響應json數據如下:
- response.setCharacterEncoding(“utf-8”);
- response.setContentType(“application/json;charset=utf-8”);
- response.getWriter().write(“json串”);
spring參數綁定過程
- 從客戶端請求key/value數據,經過參數綁定,將key/value數據綁定到controller方法的形參上。
- springmvc中,接收頁面提交的數據是通過方法形參來接收。而不是在controller類定義成員變量接收。
參數綁定默認支持的類型
直接在controller方法形參上定義下邊類型的對象,就可以使用這些對象。在參數綁定過程中,如果遇到下邊類型直接進行綁定。
HttpServletRequest
通過request對象獲取請求信息- HttpServletResponse
- 通過response處理響應信息
- HttpSession
- 通過session對象得到session中存放的對象
- Model/ModelMap
- model是一個接口,modelMap是一個接口實現 。
- 作用:將model數據填充到request域。
參數綁定簡單類型
- 通過
@RequestParam
對簡單類型的參數進行綁定。
- 如果不使用@RequestParam,要求request傳入參數名稱和controller方法的形參名稱一致,方可綁定成功。
- 如果使用@RequestParam,不用限制request傳入參數名稱和controller方法的形參名稱一致。
- 通過
required屬性
指定參數是否必須要傳入,如果設置爲true,沒有傳入參數,報下邊錯誤:
使用@RequestParam常用於處理簡單類型的綁定。
value
:參數名字,即入參的請求參數名字,如value=“item_id”表示請求的參數區中的名字 爲item_id的參數的值將傳入;- required:是否必須,默認是true,表示請求中一定要有相應的參數,否則將報;
- TTP Status 400 - Required Integer parameter ‘XXXX’ is not present
- defaultValue:默認值,表示如果請求中沒有同名參數時的默認值
例子如下:
public String editItem(@RequestParam(value="item_id",required=true) String id) {
}
- 形參名稱爲id,但是這裏使用value=”item_id”限定請求的參數名爲item_id,所以頁面傳遞參數的名必須爲item_id。
- 注意:如果請求參數中沒有item_id將跑出異常:
- HTTP Status 500 - Required Integer parameter ‘item_id’ is not present
- 這裏通過required=true限定item_id參數爲必需傳遞,如果不傳遞則報400錯誤,可以使用defaultvalue設置默認值,即使required=true也可以不傳item_id參數值
pojo參數綁定
頁面中input的name和controller的pojo形參中的屬性名稱一致,將頁面中數據綁定到pojo。
頁面定義:
controller的pojo形參的定義:
測試:
post亂碼
- 在web.xml添加post亂碼filter
<!-- post亂碼過慮器 -->
<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>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
- 對於get請求中文參數出現亂碼解決方法有兩個:
- 修改tomcat配置文件添加編碼與工程編碼一致,如下:
<Connector URIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
- 另外一種方法對參數進行重新編碼:
String userName new String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8")
- ISO8859-1是tomcat默認編碼,需要將tomcat編碼後的內容按utf-8編碼
自定義參數綁定實現日期類型綁定
- 對於controller形參中pojo對象,如果屬性中有日期類型,需要自定義參數綁定。
- 將請求日期數據串轉成* 日期類型,要轉換的*日期類型和pojo中日期屬性的類型保持一致。
所以自定義參數綁定將日期字符串轉成java.util.Date類型。
需要向處理器適配器中注入自定義的參數綁定組件
自定義日期類型綁定
配置方式:springmvc.xml
包裝類型pojo參數綁定
- 需求: 商品查詢controller方法中實現商品查詢條件傳入。
實現方法
第一種方法:在形參中 添加HttpServletRequest request參數,通過request接收查詢條件參數。
第二種方法:在形參中讓包裝類型的pojo接收查詢條件參數。
- 頁面傳參數的特點:複雜,多樣性。
- 例如條件包括 :用戶賬號、商品編號、訂單信息。。。
- 如果將用戶賬號、商品編號、訂單信息等放在簡單pojo(屬性是簡單類型)中,pojo類屬性比較多,比較亂。
- 建議使用包裝類型的pojo,pojo中屬性是pojo。
- 頁面傳參數的特點:複雜,多樣性。
頁面參數和controller方法形參定義
- 頁面參數:
- 商品名稱:
<input name="itemsCustom.name" />
- 注意:itemsCustom和包裝pojo中的屬性一致即可。
- 商品名稱:
- 頁面參數:
包裝對象定義:
- controller方法 測試
@RequestMapping("/queryItems")
public ModelAndView queryItems(HttpServletRequest request, ItemsQueryVo itemsQueryVo) throws Exception{
System.out.println(request.getParameter("id"));
List<ItemsCustom> itemsList= itemsService.findItemsList(itemsQueryVo);
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("itemsList", itemsList);
modelAndView.setViewName("items/itemsList");
return modelAndView;
}
集合類型綁定
數組綁定
需求 : 商品批量刪除,用戶在頁面選擇多個商品,批量刪除。
表現層實現(controller層)
- 關鍵:將頁面選擇(多選)的商品id,傳到controller方法的形參,方法形參使用數組接收頁面請求的多個商品id。
controller方法定義:
頁面定義:
<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>
list綁定
- 需求 : 通常在需要批量提交數據時,將提交的數據綁定到
list<pojo>
中。
- 比如:成績錄入(錄入多門課成績,批量提交)。
本例子需求:批量商品修改,在頁面輸入多個商品信息,將多個商品信息提交到controller方法中。
表現層實現
- controller方法定義:
- 1、進入批量商品修改頁面(頁面樣式參考商品列表實現)
- 2、批量修改商品提交
- 使用List接收頁面提交的批量數據,通過包裝pojo接收: 在包裝pojo中定義
list<pojo>
屬性
- 頁面定義:(editItemsQuery.jsp)
- controller方法定義:
<title>查詢商品列表</title>
<script type="text/javascript">
function editItemsAllSubmit(){
//提交form
document.itemsForm.action="${pageContext.request.contextPath }/items/editItemsAllSubmit.action";
document.itemsForm.submit();
}
function queryItems(){
//提交form
document.itemsForm.action="${pageContext.request.contextPath }/items/queryItems.action";
document.itemsForm.submit();
}
</script>
</head>
<body>
<form name="itemsForm" action="${pageContext.request.contextPath }/items/queryItems.action" method="post">
查詢條件:
<table width="100%" border=1>
<tr>
<td>
商品名稱:<input name="itemsCustom.name" />
</td>
<td><input type="button" value="查詢" onclick="queryItems()"/>
<input type="button" value="批量修改提交" onclick="editItemsAllSubmit()"/>
</td>
</tr>
</table>
商品列表:
<table width="100%" border=1>
<tr>
<td>商品名稱</td>
<td>商品價格</td>
<td>生產日期</td>
<td>商品描述</td>
<td>操作</td>
</tr>
<c:forEach items="${itemsList }" var="item" varStatus="status">
<tr>
<td><input name="itemsList[${status.index }].name" value="${item.name }"/></td>
<td><input name="itemsList[${status.index }].price" value="${item.price }"/></td>
<td><input name="itemsList[${status.index }].createtime" value="<fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/>"/></td>
<td><input name="itemsList[${status.index }].detail" value="${item.detail }"/></td>
</tr>
</c:forEach>
</table>
</form>
</body>
</html>
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());
}
springmvc校驗
在項目中通常使用較多是前端的校驗,比如頁面中js校驗。對於安全要求較高點建議在服務端進行校驗。
服務端校驗:
- 控制層conroller:校驗頁面請求的參數的合法性。在服務端控制層conroller校驗,不區分客戶端類型(瀏覽器、手機客戶端、遠程調用)
- 業務層service(使用較多):主要校驗關鍵業務參數,僅限於service接口中使用的參數。
- 持久層dao:一般是不校驗的。
springmvc使用hibernate的校驗框架validation(和hibernate沒有任何關係)。
校驗思路:
- 頁面提交請求的參數,請求到controller方法中,使用validation進行校驗。如果校驗出錯,將錯誤信息展示到頁面。
- 具體需求:
- 商品修改,添加校驗(校驗商品名稱長度,生產日期的非空校驗),如果校驗出錯,在商品修改頁面顯示錯誤信息。
具體實現流程
- 環境準備
- hibernate的校驗框架validation所需要jar包:
- hibernate的校驗框架validation所需要jar包:
- 1、配置校驗器並添加校驗錯誤信息配置文件
<!-- 校驗器 -->
<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>
2、校驗器注入到處理器適配器中
3、在pojo中添加校驗規則
- 在Items.java中添加校驗規則:
- 在Items.java中添加校驗規則:
4、添加校驗錯誤配置信息
- 在CustomValidationMessages.properties配置校驗錯誤信息:
- 在CustomValidationMessages.properties配置校驗錯誤信息:
5、捕獲校驗錯誤信息
- 在需要校驗的pojo前邊添加
@Validated
, - 在需要校驗的pojo後邊添加
BindingResult bindingResult
接收校驗出錯信息 - 注意:
@Validated
和BindingResult bindingResult
是配對出現,並且形參順序是固定的(一前一後)。
- 在需要校驗的pojo前邊添加
- 6、在頁面顯示校驗錯誤信息
- 在controller中將錯誤信息傳到頁面即可。
- 在controller中將錯誤信息傳到頁面即可。
- 7、頁面顯示錯誤信息:
分組校驗
需求 : 在pojo中定義校驗規則,而pojo是被多個 controller所共用,當不同的controller方法對同一個pojo進行校驗,但是每個controller方法需要不同的校驗。
解決方法:
- 定義多個校驗分組(其實是一個java接口),分組中定義有哪些規則
- 每個controller方法使用不同的校驗分組
流程如下:
1、校驗分組
2、在校驗規則中添加分組(Items.java)
3、在controller方法使用指定分組的校驗
數據回顯
- 提交後,如果出現錯誤,將剛纔提交的數據回顯到剛纔的提交頁面。
pojo數據回顯方法
springmvc默認支持pojo數據回顯,springmvc自動將形參中的pojo重新放回request域中,request的key爲pojo的類名(首字母小寫),如下:
controller方法:
@RequestMapping("/editItemSubmit")
public String editItemSubmit(Integer id,ItemsCustom itemsCustom)throws Exception{
springmvc自動將itemsCustom放回request,相當於調用下邊的代碼:
model.addAttribute("itemsCustom", itemsCustom);
jsp頁面:
使用@ModelAttribute完成數據回顯
- 1、使用
@ModelAttribute
指定pojo回顯到頁面在request中的key
// 商品修改提交
@RequestMapping("/editItemSubmit")
public String editItemSubmit(Model model,@ModelAttribute("item") ItemsCustom itemsCustom)
頁面:
<tr>
<td>商品名稱</td>
<td><input type="text" name="name" value="${item.name }"/></td>
</tr>
<tr>
<td>商品價格</td>
<td><input type="text" name="price" value="${item.price }"/></td>
</tr>
如果不用@ModelAttribute也可以使用model.addAttribute(“item”, itemsCustom)完成數據回顯。
2、@ModelAttribute還可以將方法的返回值傳到頁面
- 在商品查詢列表頁面,通過商品類型查詢商品信息。
- 在controller中定義商品類型查詢方法,最終將商品類型傳到頁面。
//商品分類
@ModelAttribute("itemtypes")
public Map<String, String> getItemTypes(){
Map<String, String> itemTypes = new HashMap<String,String>();
itemTypes.put("101", "數碼");
itemTypes.put("102", "母嬰");
return itemTypes;
}
頁面:
商品類型:
<select name="itemtype">
<c:forEach items="${itemtypes }" var="itemtype">
<option value="${itemtype.key }">${itemtype.value }</option>
</c:forEach>
</select>
簡單類型數據回顯
- 對於簡單數據類型,如:Integer、String、Float等使用Model將傳入的參數再放到request域實現顯示。
@RequestMapping(value="/editItems",method={RequestMethod.GET})
public String editItems(Model model,Integer id)throws Exception{
//傳入的id重新放到request域
model.addAttribute("id", id);
springmvc和struts2的區別
- 1、springmvc基於方法開發的,struts2基於類開發的。
- springmvc將url和controller方法映射。映射成功後springmvc生成一個Handler對象,對象中只包括了一個method。
- 方法執行結束,形參數據銷燬。
- springmvc的controller開發類似service開發。
- 2、springmvc可以進行單例開發,並且建議使用單例開發,struts2通過類的成員變量接收參數,無法使用單例,只能使用多例。
- 3、經過實際測試,struts2速度慢,在於使用struts標籤,如果使用struts建議使用jstl。