SpringMVC参数校验,包括JavaBean和基本类型的校验(转载)

参考博客: SpringMVC参数校验,包括JavaBean和基本类型的校验


一、spingmvc引入Hibernate Validator校验框架,参考地址:http://blog.csdn.net/menghuanzhiming/article/details/78059876

二、校验JavaBean

1、javaben的实体类注解校验:

package edu.hrbeu.platform.modeling.pojo;

import java.io.Serializable;
import javax.validation.constraints.Pattern;

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

public class User implements Serializable{
    private Integer userId;
    @NotEmpty
    @Pattern(regexp="^[A-Za-z\u4e00-\u9fa5]{2,10}$", message="登录名:2-10位以内中文或英文或数字")
    private String username;

    @NotEmpty
    @Pattern(regexp="^[A-Za-z\u4e00-\u9fa5]{2,10}$", message="用户名:2-10位以内中文或英文或数字")
    private String alias;

    @NotEmpty
    @Pattern(regexp="^(?=.*[a-z])(?=.*[A-Z])[a-zA-Z\\d]{6,18}$", message="密码:6-18位以内数字和字母,至少各一个大小写字母")
    private String password;

    @NotEmpty
    @Email
    private String email;

    @NotEmpty
    @Pattern(regexp="^1[0-9]{10}$", message="手机号:11位以内中国大陆手机号")
    private String phone;   
}

2、javaben定义了注解校验等标签后,结合在Controller里使用@Valid和BindingResult即可完成参数的校验。
譬如registerUser方法里,只需要加上@Valid标签即可完成校验。如果校验不通过,那么错误信息就会封装到BindingResult对象了,可以通过bindingResult的相关方法获取详细的错误信息并返回给用户。
如果不加BindingResult则会抛出异常。
此时即可完成表单类,或者用户注册之类的类似请求的参数校验了,可以选择获取bindingResult信息后直接return给用户。如果这样的需要校验的地方比较多,每个都单独处理比较麻烦,可以通过aop统一处理返回,后面会讲到。
校验的标签可参考:http://blog.csdn.net/catoop/article/details/51278675
相关文章:http://412887952-qq-com.iteye.com/blog/2312356

/**
     * 
    * @Title: RegisterUser
    * @Description: TODO(用户注册)
    * @return Map    返回类型
    * @return
     */
    @RequestMapping("registerUser")
    @ResponseBody
    @Operationlog(desc="用户注册")
    public Map registerUser(
            @Valid 
            User user, 
            BindingResult bindingResult
            ) {
        while(bindingResult.hasErrors()) {
            System.out.println("没有通过校验");
            return null;
        }
        return null;
    }

二、校验基本类型

在很多场景下,我们不需要校验一个javaBean,更多的是校验单个的int,String等。但是直接写上去,是不起作用的,校验框架并没有去校验,我们需要做的就是让它生效。
参考如下:https://diamondfsd.com/article/78fa12cd-b530-4a90-b438-13d5a0c4e26c
这里写链接内容

1、controller层添加注解校验:
controller层方法代码如下,既有javabean的校验也有简单参数的校验:

/**
     * 
    * @Title: RegisterUser
    * @Description: TODO(用户注册)
    * @return Map    返回类型
    * @param user
    * @param confirmPassword
    * @param vercode
    * @param request
    * @return
     */
    @RequestMapping("registerUser")
    @ResponseBody
    @Operationlog(desc="用户注册")
    public Map registerUser(
            @Valid 
            User user, 
            BindingResult bindingResult,
            @NotEmpty
            String confirmPassword,
            @NotEmpty
            String vercode) {
        return null;
    }

2、配置aop统一管理javabean的校验信息BindingResult以及使简单参数的注解校验生效:
(1)springmvc的controller配置aop注意事项:
参考连接:http://blog.csdn.net/menghuanzhiming/article/details/78780612
如果仍然无法使用aop请检查jar包是否冲突;

(2)配置文件:spring-aspect.xml


<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans    
                            http://www.springframework.org/schema/beans/spring-beans-3.1.xsd    
                            http://www.springframework.org/schema/context    
                            http://www.springframework.org/schema/context/spring-context-3.1.xsd    
                            http://www.springframework.org/schema/mvc    
                            http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
                            http://www.springframework.org/schema/tx
                            http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
                            http://www.springframework.org/schema/aop 
                            http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">

    
    <aop:aspectj-autoproxy proxy-target-class="true"/>
    
    <bean id="requestParamValidAspect" class="edu.hrbeu.platform.modeling.common.aspect.RequestParamValidAspect"/>
beans>  

springmvc配置文件引入spring-aspect.xml文件:

"1.0" encoding="UTF-8"?>
"http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:task="http://www.springframework.org/schema/task"
    xsi:schemaLocation="http://www.springframework.org/schema/beans    
                            http://www.springframework.org/schema/beans/spring-beans-3.1.xsd    
                            http://www.springframework.org/schema/context    
                            http://www.springframework.org/schema/context/spring-context-3.1.xsd 
                            http://www.springframework.org/schema/task
                            http://www.springframework.org/schema/task/spring-task-3.1.xsd   
                            http://www.springframework.org/schema/mvc    
                            http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
    ...
    省略
    ...
    "spring-aspect.xml"/>

切面类RequestParamValidAspect :

package edu.hrbeu.platform.modeling.common.aspect;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.ElementKind;
import javax.validation.Validation;
import javax.validation.ValidatorFactory;
import javax.validation.executable.ExecutableValidator;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.hibernate.validator.internal.engine.path.NodeImpl;
import org.hibernate.validator.internal.engine.path.PathImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;

import edu.hrbeu.platform.modeling.exception.ParamValidException;
import edu.hrbeu.platform.modeling.pojo.SimpleFiledError;

/**
 * 
* @ClassName: RequestParamValidAspect 
* @Description: TODO(controller参数校验aspectj) 
* @author chenliming
* @date 2017年12月12日 上午10:27:36 
*
 */
@Aspect
public class RequestParamValidAspect {
    private final ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
    private final ExecutableValidator validator = factory.getValidator().forExecutables();
    Logger log = LoggerFactory.getLogger(getClass());

    @Pointcut("execution(public java.util.Map edu.hrbeu.platform.modeling.*.controller.*.*(..))")
    public void controllerAround() {
    }

    ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();

    /**
     * 
    * @Title: around
    * @Description: TODO(环绕增强,校验controller参数)
    * @return Object    返回类型
    * @param pjp
    * @return
    * @throws Throwable
     */
    @Around("controllerAround()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("aspect参数校验start.....");
        try {
            // 取参数,如果没参数,那肯定不校验了
            Object[] args = pjp.getArgs();
            if (args.length == 0) {
                return pjp.proceed();
            }

            List simpleFiledErrors = new ArrayList<>();
            /************************** 校验封装好的javabean **********************/
            // 寻找带BindingResult参数的方法,然后判断是否有error,如果有则是校验不通过
            for (Object arg : args) {
                if (arg instanceof BeanPropertyBindingResult) {
                    // 有校验
                    BeanPropertyBindingResult result = (BeanPropertyBindingResult) arg;
                    if (result.hasErrors()) {
                        List list = result.getAllErrors();
                        for (ObjectError error : list) {
//                          System.out.println(
//                                  error.getCode() + "---" + error.getArguments() + "--" + error.getDefaultMessage());
                            String name = null;
                            if(error instanceof FieldError) {
                                //字段名称
                                name = ((FieldError)error).getField();
                            } else {
                                //对象名称
                                name = error.getObjectName();
                            }

                            SimpleFiledError simpleFiledError = new SimpleFiledError();
                            simpleFiledError.setName(name);
                            simpleFiledError.setMessage(error.getDefaultMessage());
                            simpleFiledErrors.add(simpleFiledError);
                        }
                    }
                }
            }

            /************************** 校验普通参数 *************************/
            // 获得切入目标对象
            Object target = pjp.getThis();
            // 获得切入的方法
            Method method = ((MethodSignature) pjp.getSignature()).getMethod();
            // 执行校验,获得校验结果
            Set> validResult = validMethodParams(target, method, args);
            // 如果有校验不通过的
            if (!validResult.isEmpty()) {
                String[] parameterNames = parameterNameDiscoverer.getParameterNames(method); // 获得方法的参数名称

                for (ConstraintViolation constraintViolation : validResult) {
                    PathImpl pathImpl = (PathImpl) constraintViolation.getPropertyPath(); // 获得校验的参数路径信息
                    NodeImpl leafNode = pathImpl.getLeafNode();

                    //判断是否是参数类型(如果是bean的属性无法获取index,抛出异常)
                    if(leafNode.getKind() == ElementKind.PARAMETER) {
                        int paramIndex = leafNode.getParameterIndex(); // 获得校验的参数位置
                        String paramName = parameterNames[paramIndex]; // 获得校验的参数名称

//                      //参数名称
//                      System.out.println(paramName);
//                      // 校验信息
//                      System.out.println(constraintViolation.getMessage());

                        SimpleFiledError simpleFiledError = new SimpleFiledError();
                        simpleFiledError.setName(paramName);
                        simpleFiledError.setMessage(constraintViolation.getMessage());
                        simpleFiledErrors.add(simpleFiledError);
                    }

                }
            }

            if(!simpleFiledErrors.isEmpty()) {
                Map map = new HashMap();
                map.put("success", false);//是否成功
                map.put("message", "参数校验不成功");//文本消息
                map.put("filedErrors", simpleFiledErrors);
                return map;
            }

            return pjp.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
            throw e;
        }
    }

    public void before(JoinPoint point) throws ParamValidException {
        // 获得切入目标对象
        Object target = point.getThis();
        // 获得切入方法参数
        Object[] args = point.getArgs();
        // 获得切入的方法
        Method method = ((MethodSignature) point.getSignature()).getMethod();

        // 执行校验,获得校验结果
        Set> validResult = validMethodParams(target, method, args);

        if (!validResult.isEmpty()) {
            String[] parameterNames = parameterNameDiscoverer.getParameterNames(method); // 获得方法的参数名称

            List errors = new ArrayList<>();
            for (ConstraintViolation constraintViolation : validResult) {
                PathImpl pathImpl = (PathImpl) constraintViolation.getPropertyPath(); // 获得校验的参数路径信息
                int paramIndex = pathImpl.getLeafNode().getParameterIndex(); // 获得校验的参数位置
                String paramName = parameterNames[paramIndex]; // 获得校验的参数名称

                SimpleFiledError error = new SimpleFiledError(); // 将需要的信息包装成简单的对象,方便后面处理
                error.setName(paramName); // 参数名称(校验错误的参数名称)
                error.setMessage(constraintViolation.getMessage()); // 校验的错误信息
                errors.add(error);

                System.out.println(paramName);
                // 校验信息
                System.out.println(constraintViolation.getMessage());
            }

            throw new ParamValidException(errors); // 我个人的处理方式,抛出异常,交给上层处理

        }
    }

    private  Set> validMethodParams(T obj, Method method, Object[] params) {
        return validator.validateParameters(obj, method, params);
    }
} 
  

切面类中的环绕增强将校验错误汇总并返回;


参数异常处理类ParamValidException:

package edu.hrbeu.platform.modeling.exception;

import java.util.List;

import edu.hrbeu.platform.modeling.pojo.SimpleFiledError;

public class ParamValidException extends Exception{
    private static final long serialVersionUID = 1L;

    private List fieldErrors;
    public ParamValidException(List fieldErrors) {
        this.fieldErrors = fieldErrors;
    }
}

自定义校验错误实体类SimpleFiledError :

package edu.hrbeu.platform.modeling.pojo;

public class SimpleFiledError {
    private String name;
    private String message;

    public SimpleFiledError() {
        super();
        // TODO Auto-generated constructor stub
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }


}

你可能感兴趣的:(springmvc)