ssm之路(19)服務端validation校驗
校驗通常是前端校驗,比如js校驗,但對於安全要求較高的建議在服務端進行校驗
controller層:校驗檢驗頁面請求的引數型別的合法性(頁面提交的東西)
service層:(使用較多)檢驗關鍵業務引數
dao層:一般不校驗:
springmvc使用了hibernate的validation校驗框架
引入依賴:
<dependency> <groupId>javax.el</groupId> <artifactId>javax.el-api</artifactId> <version>2.2.4</version> <scope>provided</scope> </dependency> <!-- Hibernate Validator新增依賴,使springmvc支援Hibernate的 Validator校驗--> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>1.1.0.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.4.0.Final</version> </dependency> <!-- Hibernate Validator新增依賴,使springmvc支援Hibernate的 Validator校驗-->
spring-mvc新增相關配置,使其支援validation校驗:
<?xml version="1.0" encoding="UTF-8"?> <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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <context:component-scan base-package="cn.itcast.ssm.controller"/> <mvc:annotation-driven></mvc:annotation-driven> <!--對於註解的handler可以單個配置,可以每次手動的在配置檔案中新增bean註冊,但建議使用元件掃描方式註冊bean--> <!--HttpRequestHandlerAdapter介面卡,要求編寫handler實現HttpRequestHandler--> <!-- <bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"/>--> <!-- 檢視解析器--> <!-- 解析jsp,預設使用jstl,classpath下的有jstl的包,檢視解析器的有程式碼://classname javax.servlet.jsp.jstl.core.Config--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp"/> <property name="suffix" value=".jsp"/> </bean> <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <property name="converters"> <list> <!--日期型別轉換--> <!-- <bean class="cn.meko.controller.converter.CustomDateConverter"/>--> </list> </property> </bean> <!-- 指定自己定義的validator --> <mvc:annotation-driven validator="validator"/> <!-- 以下 validator ConversionService 在使用 mvc:annotation-driven 會 自動註冊--> <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"> <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> <!-- 在web環境中一定要定位到classpath 否則預設到當前web應用下找 --> <value>classpath:validat</value> </list> </property> <property name="useCodeAsDefaultMessage" value="false"/> <property name="defaultEncoding" value="utf-8" /> <property name="cacheSeconds" value="60"/> </bean> <!--配置校驗器結束--> </beans>
實體類Items上添加註釋:校驗規則
public class Items { private Integer id; @Size(min=1,max=30,message = "{items.name.length.error}") private String name; private Float price; private String pic; @NotNull(message = "時間不允許為空") @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") private Date createtime; }
itemsController測試程式碼:
//@Validated 必須在之前,BindingResult必須在之後
@RequestMapping("/editItemsSubmit")
public String editItemsSubmit(Model model,HttpServletRequest request, Integer id, @Validated ItemsCustom itemsCustom,BindingResult bindingResult
)throws Exception {
List<ObjectError> allErrors = null;
if (bindingResult.hasErrors()) {
allErrors = bindingResult.getAllErrors();
for (ObjectError objectError : allErrors) {
System.out.println(objectError.getDefaultMessage());
}
}
model.addAttribute("allErrors", allErrors);
return "/items/editItems";
}
商品編輯頁面editItem.jsp程式碼:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>修改商品</title>
</head>
<body>
<c:if test="${allErrors!=null}">
<c:forEach items="${allErrors}" var="error">
${error.defaultMessage}
</c:forEach>
</c:if>
<form action="${pageContext.request.contextPath}/editItemsSubmit.action" method="post" id="itemForm">
<input type="hidden" name="id" value="${itemsCustom.id}"/>
修改商品資訊:
<table width="100%" border="1">
<tr>
<td>商品名稱</td>
<td><input type="text" name="name" value="${itemsCustom.name}"></td>
</tr>
<tr>
<td>商品價格</td>
<td><input type="text" name="price" value="${itemsCustom.price}"></td>
<%-- <td>生產日期</td>
<td>商品描述</td>
<td>操作</td>--%>
</tr>
<tr>
<td>商品簡介</td>
<td><textarea rows="3" cols="30" name="detail">${itemsCustom.detail}</textarea></td>
</tr>
<tr>
<td>商品時間</td>
<td><input type="text" name="createtime" value="<fmt:formatDate value='${itemsCustom.createtime}' type='date' pattern='yyyy-MM-dd HH:mm:ss'/>"></td></td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="提交"/></td>
</tr>
</table>
</form>
</body>
</html>
分組校驗:(當不同的controller方法對同一個pojo進行校驗,但每個controller有不同校驗規則)分組校驗(是一個java介面)
新建一個介面:ValidGroup1
public interface ValidGroup1 {
//此分組之校驗商品名稱
}
更改實體類Items中的validation如下:
public class Items {
private Integer id;
@Size(min=1,max=30,message = "長度錯誤",groups = {ValidGroup1.class})
private String name;
private Float price;
private String pic;
@NotNull(message = "時間不允許為空")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
private Date createtime;
private String detail;
}
更改ItemsController的程式碼如下:
//@Validated 必須在之前,BindingResult必須在之後,@Validated(value = {ValidGroup1.class}指定使用組一校驗
@RequestMapping("/editItemsSubmit")
public String editItemsSubmit(Model model, HttpServletRequest request, Integer id, @Validated(value = {ValidGroup1.class}) ItemsCustom itemsCustom, BindingResult bindingResult
)throws Exception {
List<ObjectError> allErrors = null;
if (bindingResult.hasErrors()) {
allErrors = bindingResult.getAllErrors();
for (ObjectError objectError : allErrors) {
System.out.println(objectError.getDefaultMessage());
}
}
model.addAttribute("allErrors", allErrors);
return "/items/editItems";
}
測試會發現:如果時間,姓名的長度都為空,validation只檢驗姓名,因為我們分組檢驗的就只是validation
資料回顯:
提交錯誤,將剛才提交的資料回顯到剛才的提交頁面
springmvc預設對pojo資料進行回顯
pojo資料傳入controller方法後,springmvc自動將pojo資料放到request域,而key就等於pojo的類名的首字母小寫itemscustom
資料 回顯驗證:通過ModelAttribute實現,
//@Validated 必須在之前,BindingResult必須在之後,@Validated(value = {ValidGroup1.class}指定使用組一校驗
// @ModelAttribute("items")指定pojo回顯到頁面在request中的key,還可以將方法的返回值傳到頁面
@RequestMapping("/editItemsSubmit")
public String editItemsSubmit(Model model, HttpServletRequest request, Integer id,
@ModelAttribute("items") @Validated(value = {ValidGroup1.class}) ItemsCustom itemsCustom, BindingResult bindingResult
)throws Exception {
List<ObjectError> allErrors = null;
if (bindingResult.hasErrors()) {
allErrors = bindingResult.getAllErrors();
for (ObjectError objectError : allErrors) {
System.out.println(objectError.getDefaultMessage());
}
}
model.addAttribute("allErrors", allErrors);
return "/items/editItems";
}
ModelAttribute("items")指定pojo回顯到頁面在request中的key,還可以將方法的返回值傳到頁面
//itemtypes表示最終將方法返回值放在requestType中的key,頁面上可以得到itemtypes的資料
@ModelAttribute("itemtypes")
public Map<String,String>getItemTypes(){
Map<String,String>itemTypes=new HashMap<String,String>();
itemTypes.put("101","數碼");
itemTypes.put("102","派克");
return itemsTypes;
}
jsp的測試程式碼:
<select name="itemtype">
<c:forEach items="${itemtypes}" var="itemtype">
<option value="${itemtype.key}">${itemtype.value}</option>
</c:forEach>
</select>
</form>
簡單資料型別的回顯用model就可以了,也可以用註解實現回顯:
最後在放一下綜合的:Controller層:ItemsController.java
@Controller
@RequestMapping("/items")
public class ItemsController {
@Autowired
private ItemsService itemsService;
//itemtypes表示最終將方法返回值放在requestType中的key,頁面上可以得到itemtypes的資料
@ModelAttribute("itemtypes")
public Map<String,String> getItemType(){
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 {
List<ItemsCustom> itemsList = itemsService.finditemsList(itemsQueryVo);
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("itemsList", itemsList);
modelAndView.setViewName("/items/itemsList");
return modelAndView;
}
//@Validated 必須在之前,BindingResult必須在之後,@Validated(value = {ValidGroup1.class}指定使用組一校驗
// @ModelAttribute("items")指定pojo回顯到頁面在request中的key,還可以將方法的返回值傳到頁面
@RequestMapping("/editItemsSubmit")
public String editItemsSubmit(Model model, HttpServletRequest request, Integer id,
@ModelAttribute("itemsCustom") @Validated(value = {ValidGroup1.class}) ItemsCustom itemsCustom, BindingResult bindingResult
)throws Exception {
List<ObjectError> allErrors = null;
if (bindingResult.hasErrors()) {
allErrors = bindingResult.getAllErrors();
for (ObjectError objectError : allErrors) {
System.out.println(objectError.getDefaultMessage());
}
}
model.addAttribute("allErrors", allErrors);
model.addAttribute("items",itemsCustom);
return "/items/editItems";
}
}
檢視層editItem.jsp:測試資料回顯頁面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>修改商品</title>
</head>
<body>
<c:if test="${allErrors!=null}">
<c:forEach items="${allErrors}" var="error">
${error.defaultMessage}
</c:forEach>
</c:if>
<form action="${pageContext.request.contextPath}/editItemsSubmit.action" method="post" id="itemForm">
<input type="hidden" name="id" value="${itemsCustom.id}"/>
修改商品資訊:
<table width="100%" border="1">
<tr>
<td>商品名稱</td>
<td><input type="text" name="name" value="${itemsCustom.name}"></td>
</tr>
<tr>
<td>商品價格</td>
<td><input type="text" name="price" value="${itemsCustom.price}"></td>
<%-- <td>生產日期</td>
<td>商品描述</td>
<td>操作</td>--%>
</tr>
<tr>
<td>商品簡介</td>
<td><textarea rows="3" cols="30" name="detail">${itemsCustom.detail}</textarea></td>
</tr>
<tr>
<td>商品時間</td>
<td><input type="text" name="createtime" value="<fmt:formatDate value='${itemsCustom.createtime}' type='date' pattern='yyyy-MM-dd HH:mm:ss'/>"></td></td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="提交"/></td>
</tr>
</table>
</body>
</html>
獲取modelAttribute標註方法的返回值的測試頁面:ItemsList.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>
<html>
<head>
<%-- <base href="<%=basePath%>">--%>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>查詢商品列表</title>
</head>
<body>
<form action="#" method="post" id="itemsForm">
查詢條件:
<table width="100%" border="1">
<tr>
<td>商品名稱    <input name="itemsCustom.name">
商品型別 <select name="itemtypes">
<c:forEach items="${itemtypes}" var="i">
<option value="${i.key}">${i.value}</option>
</c:forEach>
</select>
</td>
<td><button onclick="queryItems()">查詢</button> </td>
<td><button onclick="deleteItems()">刪除</button> </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="ids" 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}/selectAllItem.action">修改</a></td>
</tr>
</c:forEach>
</table>
</form>
<script type="text/javascript">
function queryItems() {
document.getElementById("itemsForm").action ="${pageContext.request.contextPath}/queryItems.action";
document.getElementById("itemsForm").submit();
}
function deleteItems() {
document.getElementById("itemsForm").action="${pageContext.request.contextPath}/deleteItems.action";
document.getElementById("itemsForm").submit;
}
</script>
</body>
</html>
測試結果如下: