zoukankan      html  css  js  c++  java
  • spring 19-Spring框架使用拦截器进行服务器验证

    • 服务器端的数据接收必须要保证整个数据的合法性,该接收什么类型的数据就应该接收什么类型的
    • 常用的验证规则基本上有四种:
      • int数据类型:d+
      • double数据类型:d+(.d+)?
      • string数据类型:验证该数据是否为空
      • date数据:验证是否为一个日期,d{4}-d{2}-d{2}

    经典案例:使用拦截器进行服务器数据类型验证

    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 ;
    	}
    }
    
  • 相关阅读:
    vue动态组件
    服务端渲染和nuxt简单介绍
    nuxt Window 或 Document未定义解决方案
    知乎专栏开放性api
    小程序的一些坑
    搭建微服务器(续)
    调研pwa和sw
    mysql索引原理以及优化
    装饰器
    斐波那契数列和小青蛙跳跳跳问题
  • 原文地址:https://www.cnblogs.com/liangjingfu/p/10113904.html
Copyright © 2011-2022 走看看