zoukankan      html  css  js  c++  java
  • SpringMVC参数校验,包括JavaBean和基本类型的校验

    该示例项目使用SpringBoot,添加web和aop依赖。
    SpringMVC最常用的校验是对一个javaBean的校验,默认使用hibernate-validator校验框架。而网上对校验单个参数,譬如String,int之类的资料极少,这一篇就是讲这个的。

    校验JavaBean

    package com.example.bean;
    
    import org.hibernate.validator.constraints.Length;
    import org.hibernate.validator.constraints.NotEmpty;
    
    /**
     * Created by admin on 17/5/3.
     */
    public class User {
        private Long id;
    
        @NotEmpty(message = "姓名不能为空")
        private String name;
    
        @NotEmpty(message = "密码不能为空")
        @Length(min = 6, message = "密码长度不能小于6位")
        private String password;
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    }
    

    定义了@NotEmpty等标签后,结合在Controller里使用@Valid即可完成参数的校验。

    package com.example.controller;
    
    import com.example.bean.User;
    import org.hibernate.validator.constraints.Length;
    import org.hibernate.validator.constraints.Range;
    import org.springframework.validation.BindingResult;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.validation.Valid;
    
    /**
     * Created by wuwf on 17/4/27.
     *
     */
    @RestController
    public class FirstController {
    
        @RequestMapping("/first")
        public Object first(@Valid User user, BindingResult bindingResult) {
            return "first controller";
        }
    
        @RequestMapping("/second")
        public @Length Object second(@Length(min = 6, message = "密码长度不能小于6位") String password) {
            return "second controller";
        }
    
        @RequestMapping("/third")
        public @Length Object third(@Range(min = 6, max = 10, message = "数据需要大于6小于10") int num, @Length(min = 6, message = "密码长度不能小于6位") String password) {
            return "third controller";
        }
    
        @RequestMapping("/four")
        public @Length Object four(int page) {
            return "four controller";
        }
    }
    

    譬如first方法里,只需要加上@Valid标签即可完成校验。如果校验不通过,那么错误信息就会封装到BindingResult对象了,可以通过bindingResult的相关方法获取详细的错误信息并返回给用户。
    访问:http://localhost:8080/first?name=1&password=1 debug可看到
    这里写图片描述
    如果不加BindingResult则会抛出异常。
    此时即可完成表单类,或者用户注册之类的类似请求的参数校验了,可以选择获取bindingResult信息后直接return给用户。如果这样的需要校验的地方比较多,每个都单独处理比较麻烦,可以通过aop统一处理返回,后面会讲到。
    校验的标签可参考:http://blog.csdn.net/catoop/article/details/51278675
    相关文章:http://412887952-qq-com.iteye.com/blog/2312356

    校验基本类型

    在很多场景下,我们不需要校验一个javaBean,更多的是校验单个的int,String等。也就是controller里的second和third方法。像方法中写的那样,但是直接写上去,是不起作用的,校验框架并没有去校验,我们需要做的就是让它生效。
    参考如下:https://diamondfsd.com/article/78fa12cd-b530-4a90-b438-13d5a0c4e26c
    http://blog.csdn.net/catoop/article/details/51284638
    直接上代码吧

    package com.example.aop;
    
    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.PathImpl;
    import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
    import org.springframework.core.ParameterNameDiscoverer;
    import org.springframework.stereotype.Component;
    import org.springframework.validation.BeanPropertyBindingResult;
    import org.springframework.validation.ObjectError;
    
    import javax.validation.ConstraintViolation;
    import javax.validation.Validation;
    import javax.validation.ValidatorFactory;
    import javax.validation.executable.ExecutableValidator;
    import java.lang.reflect.Method;
    import java.util.List;
    import java.util.Set;
    
    /**
     * Created by wuwf on 17/4/27.
     * 参数校验切面
     */
    @Aspect
    @Component
    public class ValidAspect {
        private ObjectError error;
    
        @Pointcut("execution(public * com.example.controller.*.*(..))")
        public void valid() {
        }
    
        //环绕通知,环绕增强,相当于MethodInterceptor
        @Around("valid()")
        public Object arround(ProceedingJoinPoint pjp) {
            System.out.println("方法环绕start.....");
            try {
                //取参数,如果没参数,那肯定不校验了
                Object[] objects = pjp.getArgs();
                if (objects.length == 0) {
                    return pjp.proceed();
                }
                /**************************校验封装好的javabean**********************/
                //寻找带BindingResult参数的方法,然后判断是否有error,如果有则是校验不通过
                for (Object object : objects) {
                    if (object instanceof BeanPropertyBindingResult) {
                        //有校验
                        BeanPropertyBindingResult result = (BeanPropertyBindingResult) object;
                        if (result.hasErrors()) {
                            List<ObjectError> list = result.getAllErrors();
                            for (ObjectError error : list) {
                                System.out.println(error.getCode() + "---" + error.getArguments() + "--" + error.getDefaultMessage());
                                //返回第一条校验失败信息。也可以拼接起来返回所有的
                                return error.getDefaultMessage();
                            }
                        }
                    }
                }
    
                /**************************校验普通参数*************************/
                //  获得切入目标对象
                Object target = pjp.getThis();
                // 获得切入的方法
                Method method = ((MethodSignature) pjp.getSignature()).getMethod();
                // 执行校验,获得校验结果
                Set<ConstraintViolation<Object>> validResult = validMethodParams(target, method, objects);
                //如果有校验不通过的
                if (!validResult.isEmpty()) {
                    String[] parameterNames = parameterNameDiscoverer.getParameterNames(method); // 获得方法的参数名称
    
                    for(ConstraintViolation<Object> constraintViolation : validResult) {
                        PathImpl pathImpl = (PathImpl) constraintViolation.getPropertyPath();  // 获得校验的参数路径信息
                        int paramIndex = pathImpl.getLeafNode().getParameterIndex(); // 获得校验的参数位置
                        String paramName = parameterNames[paramIndex];  // 获得校验的参数名称
    
                        System.out.println(paramName);
                        //校验信息
                        System.out.println(constraintViolation.getMessage());
                    }
                    //返回第一条
                    return validResult.iterator().next().getMessage();
                }
    
                return pjp.proceed();
            } catch (Throwable e) {
                e.printStackTrace();
                return null;
            }
        }
    
        private ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
        private final ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        private final ExecutableValidator validator = factory.getValidator().forExecutables();
    
    
        private <T> Set<ConstraintViolation<T>> validMethodParams(T obj, Method method, Object[] params) {
            return validator.validateParameters(obj, method, params);
        }
    }
    

    注释写的比较清楚了,这是一个aop切面类,拦截请求,并获取方法里的所有参数。第65行到85行是对普通参数进行校验的。
    加上这几行代码后在controller里写的那些才会生效,并且把校验信息保存到了ConstraintViolation的Set集合里,判断Set是否有值,即可知道是否有校验不通过的信息,然后就可以取到校验信息并返回给用户,然后结束方法。
    而49到62行,主要是判断是否存在BindingResult参数,如果有,说明有校验javaBean的意图,如果BindingResult有值,说明存在校验不通过的信息,那么就可以做处理了。通过这样的aop切面,就可以不用在每个controller方法里去处理校验信息了。

    原文地址:https://blog.csdn.net/tianyaleixiaowu/article/details/71173059
  • 相关阅读:
    .NET 开源框架
    ORM 开发框架
    C# 文件下载四方法
    用ASP.net判断上传文件类型的三种方法
    站在十字路口的程序媛,该如何选择?
    突然的烦恼
    Request获取url信息的各种方法比较 及 Request.UrlReferrer详解
    JS 获得当前地址栏url
    MvcPager 概述
    Simditor使用方法
  • 原文地址:https://www.cnblogs.com/jpfss/p/11097631.html
Copyright © 2011-2022 走看看