码迷,mamicode.com
首页 > 编程语言 > 详细

spring 19-Spring框架使用拦截器进行服务器验证

时间:2018-12-13 15:01:03      阅读:300      评论:0      收藏:0      [点我收藏+]

标签:输入   log   数据   bean   extends   prope   url   编辑器   cts   

  • 服务器端的数据接收必须要保证整个数据的合法性,该接收什么类型的数据就应该接收什么类型的
  • 常用的验证规则基本上有四种:
    • 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 ;
    }
}

spring 19-Spring框架使用拦截器进行服务器验证

标签:输入   log   数据   bean   extends   prope   url   编辑器   cts   

原文地址:https://www.cnblogs.com/liangjingfu/p/10113904.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!