1. 程式人生 > >ssm之路(19)服務端validation校驗

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>商品名稱&nbsp&nbsp&nbsp&nbsp<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>

測試結果如下: