- 服务器端的数据接收必须要保证整个数据的合法性,该接收什么类型的数据就应该接收什么类型的
- 常用的验证规则基本上有四种:
- int数据类型:\d+
- double数据类型:\d+(.\d+)?
- string数据类型:验证该数据是否为空
- date数据:验证是否为一个日期,\d{4}-\d{2}-\d
经典案例:使用拦截器进行服务器数据类型验证
1、编写/pages/emp_add.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!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>Insert title here</title>
</head>
<body>
<%
String addUrl = request.getContextPath() + "/pages/emp/addall.action" ;
%>
<form action="<%=addUrl%>" method="post" enctype="multipart/form-data">
雇员编号:<input type="text" name="empno" id="empno" value="7369"><br>
雇员姓名:<input type="text" name="ename" id="ename" value="liang"><br>
雇员工资:<input type="text" name="sal" id="sal" value="1.1"><br>
雇佣日期:<input type="text" name="hiredate" id="hiredate" value="1911-11-11"><br>
雇员照片:<input type="file" name="photo" id="photo"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
2、编写/pages/emp/show.jsp
<h1>${empno}</h1>
<h1>${ename}</h1>
<h1>${sal}</h1>
<h1>${hiredate}</h1>
<h1>${photo}</h1>
3、编写/pages/errors.jsp
<%@ page pageEncoding="UTF-8"%>
<h1>对不起,出现了错误!</h1>
<h1>${errors}</h1>
4、编写properties文件
error.page=/pages/errors.jsp
EmpTAction.addall.error.page=/pages/errors.jsp
validation.string.msg=该数据不允许为空!
validation.int.msg=该数据不允许为空!
validation.double.msg=该数据必须是数字!
validation.rand.msg=验证码输入错误!
validation.date.msg=该数据必须是日期(yyyy-mm-dd)!
validation.datetime.msg=该数据必须是日期时间(yyyy-mm-dd hh:mm:ss)!
validation.mime.msg=上传了非法文件,请确认后重新上传!
mime.rules=image/bmp|image/jpg|image/jpeg|image/png|image/gif
EmpTAction.addall.mime.rules=image/bmp|image/jpg|image/jpeg|image/png|image/gif
EmpTAction.addall.rules=empno:int|ename:string|sal:double|hiredate:date
5、编写AbstractAction.java
package cn.liang.util.action;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Locale;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.context.MessageSource;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.multipart.MultipartFile;
import cn.liang.util.UploadFileUtil;
public abstract class AbstractAction {
@Resource
private MessageSource msgSource ; // 表示此对象直接引用配置好的类对象(根据类型匹配)
/**
* 根据指定的key的信息进行资源数据的读取控制
* @param msgKey 表示要读取的资源文件的key的内容
* @return 表示资源对应的内容
*/
public String getValue(String msgKey,Object ...args) {
return this.msgSource.getMessage(msgKey, args, Locale.getDefault()) ;
}
@InitBinder
public void initBinder(WebDataBinder binder) { // 方法名称自己随便写
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") ;
// 本方法的处理指的是追加有一个自定义的转换编辑器,如果遇见的操作目标类型为java.util.Date类
// 则使用定义好的SimpleDateFormat类来进行格式化处理,并且允许此参数的内容为空
binder.registerCustomEditor(java.util.Date.class, new CustomDateEditor(sdf, true));
}
/**
* 生成图片名称
* @param photoFile 上传上来的图片文件对象
* @return
*/
public String createFileName(MultipartFile photoFile){
if (photoFile.isEmpty()) {
return "nophoto.png";
}else {
return UUID.randomUUID() + "." + photoFile.getContentType().split("/")[1];
}
}
public abstract String getFileUploadDir();
}
6、编写EmpTAction.java
package cn.liang.action;
import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import cn.liang.util.action.AbstractAction;
@Controller
@RequestMapping("/pages/emp/*")
public class EmpTAction extends AbstractAction{
private Logger log = Logger.getLogger(EmpTAction.class) ;
@RequestMapping("addall")
public ModelAndView addall(int empno,String ename , Double sal, String hiredate,MultipartFile photo) {
log.info("*** empno = " + empno);
log.info("*** ename = " + ename);
log.info("*** sal = " + sal);
log.info("*** hiredate = " + hiredate);
log.info("*** photo = " + super.createFileName(photo));
Map<String,Object> map = new HashMap<String,Object>() ;
map.put("empno", empno);
map.put("ename", ename);
map.put("sal", sal);
map.put("hiredate", hiredate);
map.put("photo", super.createFileName(photo));
ModelAndView mav = new ModelAndView("show.jsp") ;
mav.addAllObjects(map) ;
return mav ;
}
@Override
public String getFileUploadDir() {
return "/upload/images/";
}
}
7、编写ResourceReadUtil.java
package cn.liang.util;
import java.lang.reflect.Method;
import org.springframework.web.method.HandlerMethod;
public class ResourceReadUtil {
/**
* 读取错误页的配置消息
* @param handlerMethod
* @return
*/
public static String getErrorPageValue(HandlerMethod handlerMethod) {
String pageKey = handlerMethod.getBean().getClass().getSimpleName() + "."
+ handlerMethod.getMethod().getName() + ".error.page";
String pageUrl = getValue(handlerMethod,pageKey) ;
if (pageUrl == null) {
pageUrl = getValue(handlerMethod,"error.page") ;
}
return pageUrl ;
}
/**
* 实现消息的手工配置读取
* @param handlerMethod
* @param msgKey
* @return
*/
public static String getValue(HandlerMethod handlerMethod, String msgKey) {
try {
Method getValueMethod = handlerMethod.getBean().getClass().getMethod("getValue", String.class,
Object[].class);
return getValueMethod.invoke(handlerMethod.getBean(), msgKey, null).toString();
} catch (Exception e) {
return null ;
}
}
}
8、编写拦截器ValidationInterveptor.java
package cn.liang.util.validate;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import cn.liang.util.ResourceReadUtil;
public class ValidationInterveptor implements HandlerInterceptor {
Logger log = Logger.getLogger(ValidationInterveptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
log.info("**** ValidationInterveptor--preHandle ****");
boolean flag = true ; // 默认放行
// 需要取得HandlerMethod对象,这样可以取得相关的Action信息
HandlerMethod handlerMethod = (HandlerMethod) handler ;
System.out.println(handlerMethod.getBean().getClass().getSimpleName() + "."
+ handlerMethod.getMethod().getName() + ".rules");
System.out.println(handlerMethod.getBean().getClass().getMethod("getValue", String.class,
Object[].class).invoke(handlerMethod.getBean(), handlerMethod.getBean().getClass().getSimpleName() + "."
+ handlerMethod.getMethod().getName() + ".rules", null));
// 表示具体的验证处理操作,所有的错误信息通过Map返回
Map<String,String> errors = ValidatorUtils.validate(request, handlerMethod) ;
log.info(errors.toString());
if (errors.size() > 0) { // 有错
request.setAttribute("errors", errors); // 保存在Request属性范围之中
flag = false ; // 表示现在有错误,无法向下执行
request.getRequestDispatcher(ResourceReadUtil.getErrorPageValue(handlerMethod)).forward(request, response);
log.info(ResourceReadUtil.getErrorPageValue(handlerMethod));
} else { // 没有错
return true ;
}
return flag;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
log.info("**** ValidationInterveptor--postHandle ****");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
log.info("**** ValidationInterveptor--afterCompletion ****");
}
}
9、编写验证类ValidatorUtils.java
package cn.liang.util.validate;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.log4j.Logger;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartRequest;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import cn.liang.util.ResourceReadUtil;
public class ValidatorUtils {
private static Logger log = Logger.getLogger(ValidatorUtils.class);
/**
* 实现提交参数的验证,使用指定Action的指定验证规则处理
* @param request
* @param handlerMethod
* @return 所有的验证错误信息保存在Map集合中返回,如果没有错误,则Map集合的长度为0
*/
public static Map<String, String> validate(HttpServletRequest request, HandlerMethod handlerMethod) {
// 通过给定的Action名称以及要调用的业务方法“rules”一起拼凑出要取出的验证规则,在Validations.properties中定义
String validationKey = handlerMethod.getBean().getClass().getSimpleName() + "."
+ handlerMethod.getMethod().getName() + ".rules";
Map<String,String> errors = new HashMap<String,String>() ; // 保存所有的验证信息
// log.info("【*** preHandle ***】validationValue = " + validationKey);
try {
// 现在取得了验证规则的key的信息之后实际上并无法知道该key对应的具体的内容是什么,而内容需要依靠AbstractAction.getValue()取得
Method getValueMethod = handlerMethod.getBean().getClass().getMethod("getValue", String.class,
Object[].class);
try { // 如果现在没有指定的key有可能产生异常,就认为现在没有具体的验证规则出现
// 通过getValue()方法的Method对象取得对应的验证信息
String validationValue = (String) getValueMethod.invoke(handlerMethod.getBean(), validationKey, null);
if (validationValue != null) { // 表示规则现在存在
// log.info("【*** preHandle ***】validationValue = " + validationValue);
// 取得全部的提交参数, 需要针对于给定的规则进行拆分控制
String result[] = validationValue.split("\\|"); // 按照竖线拆分
for (int x = 0; x < result.length; x++) { // 每一个规则的组成“参数名称:规则类型”
String temp[] = result[x].split(":");
String paramName = temp [0];
String paramRule = temp [1] ; // 验证规则
String paramValue = request.getParameter(paramName) ;
log.info("【提交参数】paramName = " + paramName + "、paramValue = " + request.getParameter(paramName));
switch (paramRule) {
case "string" : {
if (!ValidateRuleUtil.isString(paramValue)) { // 该验证没有通过
String msg = (String) getValueMethod.invoke(handlerMethod.getBean(), "validation.string.msg", null) ;
errors.put(paramName, msg) ;
}
break ;
}
case "int" : {
if (!ValidateRuleUtil.isInt(paramValue)) { // 该验证没有通过
String msg = (String) getValueMethod.invoke(handlerMethod.getBean(), "validation.int.msg", null) ;
errors.put(paramName, msg) ;
}
break ;
}
case "double" : {
if (!ValidateRuleUtil.isDouble(paramValue)) { // 该验证没有通过
String msg = (String) getValueMethod.invoke(handlerMethod.getBean(), "validation.double.msg", null) ;
errors.put(paramName, msg) ;
}
break ;
}
case "date" : {
if (!ValidateRuleUtil.isDate(paramValue)) { // 该验证没有通过
String msg = (String) getValueMethod.invoke(handlerMethod.getBean(), "validation.date.msg", null) ;
errors.put(paramName, msg) ;
}
break ;
}
case "datetime" : {
if (!ValidateRuleUtil.isDatetime(paramValue)) { // 该验证没有通过
String msg = (String) getValueMethod.invoke(handlerMethod.getBean(), "validation.datetime.msg", null) ;
errors.put(paramName, msg) ;
}
break ;
}
case "rand" : {
if (!ValidateRuleUtil.isRand(request,paramValue)) { // 该验证没有通过
String msg = (String) getValueMethod.invoke(handlerMethod.getBean(), "validation.rand.msg", null) ;
errors.put(paramName, msg) ;
}
break ;
}
}
}
}
} catch (Exception e) {
}
} catch (Exception e) {
}
if (errors.size() == 0) { // 之前没有错误信息,现在表示我可以对上传文件类型进行验证
// 需要判断是否当前有上传文件
MultipartResolver mr = new CommonsMultipartResolver() ; // 通过它来判断对于上传文件的接收操作
if (mr.isMultipart(request)) { // 表示的是当前有上传文件
// 需要拼凑验证规则使用的key的信息
String mimeKey = handlerMethod.getBean().getClass().getSimpleName() + "."
+ handlerMethod.getMethod().getName() + ".mime.rules" ;
// 取得具体的验证规则的消息
String mimeValue = ResourceReadUtil.getValue(handlerMethod, mimeKey) ;
if (mimeValue == null) { // 没有消息读到,没有设置单独的验证规则
mimeValue = ResourceReadUtil.getValue(handlerMethod, "mime.rules") ;
}
// 进行每一个上传文件的具体验证操作
String mimeResult [] = mimeValue.split("\\|") ; // 因为是一组规则,所以需要拆分
MultipartRequest mreq = (MultipartRequest) request ; // 处理上传时的request
Map<String,MultipartFile> fileMap = mreq.getFileMap() ; // 取得全部的上传文件
if (fileMap.size() > 0) { // 现在有上传文件
// 需要判断每一个文件的类型
Iterator<Map.Entry<String,MultipartFile>> iter = fileMap.entrySet().iterator() ;
while (iter.hasNext()) { // 判断每一个文件的类型
Map.Entry<String,MultipartFile> me = iter.next() ;
if (me.getValue().getSize() > 0) { // 当前的这个上传文件的长度大于0,有上传
if (!ValidateRuleUtil.isMime(mimeResult, me.getValue().getContentType())) { // 没有验证通过
errors.put("file", ResourceReadUtil.getValue(handlerMethod, "validation.mime.msg")) ;
}
}
}
}
}
}
return errors ;
}
}
10、编写数据类型验证类ValidateRuleUtil.java
package cn.liang.util.validate;
import javax.servlet.http.HttpServletRequest;
/**
* 完成的是一个个具体的验证规则的判断操作
* @author
*/
public class ValidateRuleUtil {
/**
* 验证传入的mime类型是否复合于当前的开发要求
* @param mimeRules 整体的验证规则
* @param mime 每一个上传文件的类型
* @return
*/
public static boolean isMime(String mimeRules[], String mime) {
if (isString(mime)) {
for (int x = 0; x < mimeRules.length; x++) {
if (mime.equals(mimeRules[x])) {
return true;
}
}
}
return false;
}
/**
* 进行验证码的检测,验证码的属性名称固定为rand
* @param request
* @param param
* @return
*/
public static boolean isRand(HttpServletRequest request,String str) {
if (isString(str)) {
String rand = (String) request.getSession().getAttribute("rand") ;
if (isString(rand)) {
return rand.equalsIgnoreCase(str) ;
}
}
return false ;
}
/**
* 判断是否是整数
* @param str
* @return
*/
public static boolean isInt(String str) {
if (isString(str)) { // 验证数据是否为空
return str.matches("\\d+") ;
}
return false ; // 数据为空返回false
}
/**
* 验证是否是日期,格式为“yyyy-MM-dd HH:mm:ss”
* @return
*/
public static boolean isDatetime(String str) {
if (isString(str)) {
return str.matches("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}") ;
}
return false ;
}
/**
* 验证是否是日期,格式为“yyyy-MM-dd”
* @return
*/
public static boolean isDate(String str) {
if (isString(str)) {
return str.matches("\\d{4}-\\d{2}-\\d{2}") ;
}
return false ;
}
/**
* 验证该数据是否是小数
* @param str
* @return
*/
public static boolean isDouble(String str) {
if (isString(str)) {
return str.matches("\\d+(\\.\\d+)?") ;
}
return false ;
}
/**
* 如果传入的内容为null或者是空字符串,则表示错误,返回false
* @param str
* @return
*/
public static boolean isString(String str) {
if (str == null || "".equals(str)) {
return false ;
}
return true ;
}
}