SpringMVC-服務端校驗

在web的開發中,我們經常需要對參數進行校驗,使用最多的即爲在前端頁面通過js進行校驗,但是對於安全性要求較高的我們通常會在服務端進行校驗。

在服務端進行校驗主要包括如下內容:

控制層-Controller:主要校驗頁面請求參數的合法性(比如長度、是否爲空等),在Controller進行校驗,是不區分客戶端類型的(瀏覽器、手機客戶端等)。

業務層-Service:在業務層主要校驗的是關鍵業務的參數,僅限於Service層中使用的參數校驗。

持久層-Dao層:在這一層一般是不進行校驗的(使用Mybatis時可在mapper.xml中通過Sql片段以及sql的if判斷進行一些校驗)。


在SpringMVC中,我們使用Hibernate的validation框架進行校驗,這裏需要注意,Validation與Hibernate並沒有半毛錢的關係。

接下來說一下校驗思路:

首先頁面提交請求的參數,請求發送到Controller後,Controller使用Validation進行相關的校驗,如果校驗出錯,則將錯誤信息展現到頁面,反之系統正常運行。


在本次講解中,同樣的通過一個用戶登錄案例進行講解(用戶名長度必須爲1-3,密碼不能爲空),當校驗出錯後,顯示出錯信息。


開發如下:

1、加入相關jar包

百度雲下載:點擊下載


2、編寫出錯的資源文件LoginValidationMessages.properties

#添加校驗錯誤提交信息
user.username.length.error=請輸入1-3長度的用戶名...
user.password.isNULL=您輸入的密碼爲空...

3、接下來我們需要在pojo文件內對變量進行校驗

package com.sw.po;

import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotEmpty;

/*
 *@Author swxctx
 *@time 2017年5月15日
 *@Explain:用戶表po對象
 *id:編號
 *username:用戶名
 *password:密碼
 */
public class User {
	private int id;
	//長度在1-3之間
	@Length(min=1,max=3,message="{user.username.length.error}")
	private String username;
	//非空校驗
	@NotEmpty(message="{user.password.isNULL}")
	private String password;
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
}

如上代碼所示,將username的長度限定爲1-3,同時密碼不能爲空,如果出錯,則在登錄界面顯示出錯信息,若正常則進行正常的登錄校驗。

在hibernate的校驗框架中,常用的註解如下:

@Email 被註釋的元素必須是電子郵箱地址

@Length 被註釋的字符串的大小必須在指定的範圍內

@NotEmpty被註釋的字符串的必須非空

@Range 被註釋的元素必須在合適的範圍內


4、接下來我們需要在springmvc.xml文件中進行相關的配置,首先需要配置校驗信息的錯誤配置文件:

<!-- 校驗錯誤信息配置文件 -->
	<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
		<!-- 資源文件名 -->
		<property name="basenames">
			<list>
				<value>classpath:LoginValidationMessages</value>
			</list>
		</property>
		<!-- 資源文件編碼格式 -->
		<property name="fileEncodings" value="utf-8"></property>
		<!-- 資源文件內容緩存時間 -->
		<property name="cacheSeconds" value="120"></property>
	</bean>	


接下來需要配置校驗器:

<!-- 數據校驗-對用戶輸入的用戶名進行長度驗證,對密碼進行非空校驗 -->
	<bean id="validator" 
	class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
		<!-- 使用Hibernate校驗器 -->
		<property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>
		<!-- 指定使用的資源文件 -->
		<property name="validationMessageSource" ref="messageSource"></property>
	</bean>

配置好以後需要將其引用到適配器與映射器中:

<!-- 配置適配器與映射器-通過drivern進行綜合 -->
	<mvc:annotation-driven validator="validator"></mvc:annotation-driven>

5、校驗器相關的配置都已經做好,接下來我們需要在Controller文件中進行使用校驗:

package com.sw.controller;

import java.util.List;

import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import com.sw.container.SwServiceProvider;
import com.sw.po.User;
import com.sw.service.UserService;

/*
 *@Author swxctx
 *@time 2017年5月16日
 *@Explain:完成登錄相關工作
 */
@Controller
public class LoginController{
	//vo對象
	//UserForm userForm = new UserForm();
	
	//service
	UserService userService = (UserService) SwServiceProvider.getService(UserService.SERVICE_NAME);
	
	//登錄驗證
	@RequestMapping("/logincheck")
	public ModelAndView loginCheck(@Validated User user,BindingResult bindingResult)throws Exception{
		String pass = userService.findLoginCheck(user.getUsername());
		ModelAndView modelAndView = new ModelAndView();
		
		//獲取校驗信息
		if(bindingResult.hasErrors()){
			//輸出
			List<ObjectError> errors = bindingResult.getAllErrors();
			for(ObjectError objectError:errors){
				//輸出錯誤信息
				System.out.println(objectError.getDefaultMessage());
				//將錯誤信息傳到頁面
			}
			modelAndView.addObject("allErrors", errors);
			modelAndView.setViewName("forward:/login.jsp");
		}else{
			//判斷
			if(user.getPassword().equals(pass)){
				//modelAndView.setViewName("dataAll.action");
				//modelAndView.setView(new RedirectView("dataAll.action",false));
				modelAndView.setViewName("redirect:/data/dataAll.action");
			}else{
				modelAndView.setViewName("/login/err");
			}
		}
		return modelAndView;
	}
}

如上代碼所示,通過對用戶輸入的用戶名與密碼進行校驗,當校驗出錯後在登錄界面顯示錯誤信息,反之進一步的進行登錄驗證。

注意:

在Controller的開發中,我們在需要校驗的參數前面加入@Validated,在之後加入BindingResult用於獲取錯誤信息,註解與BindResult是配套使用的,並且我們需要注意其順序也是固定的。

6、最後我們需要在jsp登錄界面將錯誤信息展示出來,通過jsp標籤<c:if>判斷是否存在錯誤信息,若存在錯誤則通過<c:forech>將錯誤信息輸出顯示到頁面,如下所示:

<%@ 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>
</head>
<body>
	<!-- 顯示錯誤信息 -->
	<div style="width:100%;text-align:center">
		<div style="width:100%;text-align:center">
		<c:if test="${allErrors!=null}">
			<c:forEach items="${allErrors}" var="error">
				${error.defaultMessage}<br/>
			</c:forEach>
		</c:if>
		</div>
		<br/>
		<div style="width:100%;text-align:center">
			<form action="${pageContext.request.contextPath }/logincheck.action" method="post">
				<input type="text" name="username" value="${user.username}" placeholder="用戶名"/><br/>
				<input type="password" name="password" value="${user.password}" placeholder="密碼"/><br/>
				<input type="submit" value="登陸"/>
			</form>
		</div>
	</div>
</body>
</html>

至此,關於校驗器的開發已經完成了,我們測試一下:


如上圖所示,輸入的用戶名已經遠遠超出了3位,同時密碼爲空,點擊登錄,若頁面顯示錯誤信息則表示我們開發的校驗器校驗成功:


如上,在頁面輸出了我們配置的錯誤信息,則表示校驗器配置成功。


到這裏我們的基本校驗器已經完成,但是這在開發中是並不完美的,我們在pojo中已經完全限定了校驗(即對用戶名與密碼都進行校驗),但是在開發時,我們的很多Controller在使用pojo時,有的Controller並不需要對其進行校驗。

面對上面的問題,我們可以使用分組校驗的方法,即對pojo的成員進行分組,在Controller中校驗時使用分組,則可以對指定的成員進行校驗,而不是全部進行校驗。

下面我們通過上述案例進行改進。

1、首先我們需要定義一個接口,此接口用於分組,但是此接口不需要實現任何東西,如下:

package com.sw.validator.group;
/*
 *@Author swxctx
 *@time 2017年5月24日
 *@Explain:分組校驗
 */
public interface ValidGroupOne {
	/*注意:此接口並不需要編寫任何代碼
	 	此分組用於校驗用戶名的長度
	 */
}

2、下一步進行pojo的開發,引入分組的概念:

//長度在1-3之間
	@Length(min=1,max=3,message="{user.username.length.error}",groups={ValidGroupOne.class})
	private String username;
	//非空校驗
	@NotEmpty(message="{user.password.isNULL}")
	private String password;

如上代碼所示,將username放到了ValidGroupOne的分組中,密碼沒有放置到分組中,Controller在使用是若沒有指定分組只會對密碼進行校驗,若指定了分組,則只會對用戶名進行校驗。

3、Controller中,只需要在@Validated中加入分組屬性:

//登錄驗證
@RequestMapping("/logincheck")
public ModelAndView loginCheck(@Validated(value={ValidGroupOne.class}) User user,BindingResult bindingResult)throws Exception{}

如上,分組校驗已經完成,接下來進行測試:


如上所示,用戶名的長度已經超過了3位,密碼依然爲空,如果校驗成功,則只會顯示用戶名長度錯誤,並不會顯示密碼爲空的錯誤,在分組內並沒有對密碼進行校驗,點擊登錄,結果如下:


如上所示,登錄後提示用戶名長度錯誤,密碼並沒有校驗,則說明分組校驗已經成功。


結語:在SpringMVC的開發中,很多時候是需要用到校驗的,我們也經常在服務端進行校驗,除了我們本章講解的hibernate的校驗框架外,我們還可以使用JSR框架進行校驗,原理都是差不多的。


發佈了436 篇原創文章 · 獲贊 106 · 訪問量 57萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章