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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM