springmvc使用JSR-303进行校验

下面提供一种springmvc的校验方案,一般没有校验或者手动写validator的话都要写好多代码好多if判断,使用JSR-303规范校验只需要在Pojo字段上加上相应的注解就可以实现校验了

1.依赖的jar包,我直接贴pom了

	
		UTF-8
		4.1.1.RELEASE
	
	
	
		
			com.fasterxml.jackson.core
			jackson-core
			2.4.0
		
		
			com.fasterxml.jackson.core
			jackson-databind
			2.4.0
		
		
			commons-fileupload
			commons-fileupload
			1.3.1
		
		
			javax.servlet
			javax.servlet-api
			3.1.0
		
		
			javax.validation
			validation-api
			1.1.0.Final
		
		
			org.hibernate
			hibernate-validator
			5.1.3.Final
		
		
			org.springframework
			spring-orm
			${spring.version}
		
		
			org.springframework
			spring-context
			${spring.version}
		
		
			org.springframework
			spring-web
			${spring.version}
		
		
			org.springframework
			spring-webmvc
			${spring.version}
		
		
			org.springframework
			spring-test
			${spring.version}
		
		
			org.slf4j
			slf4j-log4j12
			1.7.7
		
		
			junit
			junit
			4.11
			test
		
		
			org.aspectj
			aspectjweaver
			1.8.4
		
		
			javax.el
			javax.el-api
			3.0.0
		
	
2.springmvc配置




	
	
	
	

	
	
	
	
	

3.写java代码了

先建一个User类

public class User {
	@NotNull
	private String username;
	
	@NotNull(message = "密码不能为空")
	private String password;
	
	public String getUsername() {
		return username;
	}
	
	public void setUsername(String username) {
		this.username = username;
	}
	
	public String getPassword() {
		return password;
	}
	
	public void setPassword(String password) {
		this.password = password;
	}
	
}
然后建一个controller试试
@ResponseBody
@RequestMapping("/test1")
public AjaxResponse validateTest1(@Valid User user, BindingResult result){
	AjaxResponse ajaxResponse = new AjaxResponse();
	Map map = new HashMap<>();
	if(result.hasErrors()){
		ajaxResponse.setSuccess(false);
		ajaxResponse.setHasErrors(true);
		map.put("errors", result.getAllErrors());
	}
	else {
		map.put("now", new Date());
		map.put("user", user);
	}
	ajaxResponse.setData(map);
	return ajaxResponse;
}

这个方法第一个参数上加了@Valid标注,第二个参数是必须的而且必须紧跟着@Valid参数之后,校验结果都在这个result里面

方法逻辑比较简单,调用result.hasErrors()看校验有没有错误,有错误的话就把所有的错误放进结果返回给客户端,如果没有错误就返回当前时间跟user对象

然后写个测试方法试试

@Test
public void test1() throws Exception{
	this.mockMvc.perform(post("/validator/test1")).andDo(print());
	this.mockMvc.perform(post("/validator/test1").param("username", "testusername").param("password", "testpassword")).andDo(print());
}

第一个请求的结果是

{"success":false,"message":null,"hasErrors":true,"data":[{"name":"user","message":"may not be null"},{"name":"user","message":"密码不能为空"}]}

第二个请求结果是

{"success":true,"message":null,"hasErrors":false,"data":{"now":1420788232169,"user":{"username":"testusername","password":"testpassword"}}}

很明显第一次请求没有用户名和密码两个字段校验都没有通过,第二次是成功的

用起来还是很简单的,但是如果我不想每次都在controller方法里写if(result.hasErrors())怎么办呢,写个切面,把if写在切面里,如果有errors直接就返回了,不用再执行controller方法了

@Aspect
public class ValidAspect {
	
	@Autowired private Validator validator;
	
	@Around("@annotation(org.springframework.web.bind.annotation.ResponseBody)")
	public Object doTest(ProceedingJoinPoint pjp) throws Throwable{
		MethodSignature signature = (MethodSignature) pjp.getSignature();
		Method method = signature.getMethod();
		if(!AjaxResponse.class.equals(method.getReturnType())){
			pjp.proceed();
		}
		Object[] args = pjp.getArgs();
		Annotation[][] annotations = method.getParameterAnnotations();
		for(int i = 0; i < annotations.length; i++){
			if(!hasValidAnnotation(annotations[i])){
				continue;
			}
			if(!(i < annotations.length-1 && args[i+1] instanceof BindingResult)){
				//验证对象后面没有跟bindingResult,事实上如果没有应该到不了这一步
				continue;
			}
			BindingResult result = (BindingResult) args[i+1];
			if(result.hasErrors()){
				AjaxResponse ajaxResponse = new AjaxResponse();
				ajaxResponse.setSuccess(false);
				ajaxResponse.setHasErrors(true);
				ajaxResponse.setData(processErrors(result));
				return ajaxResponse;
			}
		}
		return pjp.proceed();
	}

	private boolean hasValidAnnotation(Annotation[] annotations){
		if(annotations == null){
			return false;
		}
		for(Annotation annotation : annotations){
			if(annotation instanceof Valid){
				return true;
			}
		}
		return false;
	}
	
	private List processErrors(BindingResult result){
		if(result != null && result.hasErrors()){
			List list = new ArrayList();
			for(ObjectError error : result.getAllErrors()){
				BindingError be = new BindingError();
				be.setMessage(error.getDefaultMessage());
				be.setName(error.getObjectName());
				list.add(be);
			}
			return list;
		}
		return null;
	}
}

注意要在springmvc配置文件加一行

然后再写个方法逻辑跟上面的类似

@ResponseBody
@RequestMapping("/test2")
public AjaxResponse validateTest2(@Valid User user, BindingResult result){
	AjaxResponse ajaxResponse = new AjaxResponse();
	Map map = new HashMap<>();
	map.put("now", new Date());
	map.put("user", user);
	ajaxResponse.setData(map);
	return ajaxResponse;
}

这里没有再去判断hasErrors()了,然后测试一下

写测试方式试一下

@Test
public void test2() throws Exception{
	this.mockMvc.perform(post("/validator/test2")).andDo(print());
	this.mockMvc.perform(post("/validator/test2").param("username", "testusername").param("password", "testpassword")).andDo(print());
}

第一个请求结果是

{"success":false,"message":null,"hasErrors":true,"data":[{"name":"user","message":"密码不能为空"},{"name":"user","message":"may not be null"}]}
第二个请求结果是

{"success":true,"message":null,"hasErrors":false,"data":{"now":1420788479105,"user":{"username":"testusername","password":"testpassword"}}}
效果跟上面是一样的

当然我这个切面仅仅是个示范,我拦截的是带有ResponseBody注解的方法,我这些方法会返回一个统一的格式,如果是要返回别的视图就要自己定义注解加其他参数了

JSR-303原生支持的校验注解也是有限的,如果要实现其他的验证,可以自己拓展,拓展方法就下次再说了,我也才刚接触。


你可能感兴趣的:(springframework,web,java)