日期:2014-05-16  浏览次数:20291 次

jquery<--json-->spring(3.0)之后台校验

前一段试了一下前台用jquery(1.3.2),后台用spring(3.0),之间用json交换数据,
然后写了篇总结jquery(1.3.2)<--json-->spring(3.0),有几位大侠提出了后台校验
的问题,我也觉得这是很普遍的问题,就参考一些资料做了个小demo,现在总结一下,
欢迎各位拍砖。

我是这样考虑的,在后台接收数据时,首先使用一个所有属性均为String的对象,在
这个对象上,使用Bean Validation(JSR-303)进行数据校验,校验通过后,再将该对象
转换为一个VO然后进行后续处理,在校验充分的情况下,转换步骤是不会出现例外的。
在校验失败的时候,返回由属性名(也即页面元素名)、错误信息对组成的数组,前端
根据元素名自动突出显示对应元素、并在其旁边显示错误信息,下面详细说明。

1. 前端提交
这和前文一样,没什么可说的。

2. 后台校验

2.1 属性全为String的对象,及其校验
spring 3开始全面支持JSR-303,并以hibernate validator作为默认实现,该技术可以
用声明(Annotaion)的方式定义校验,而且标记可以自由扩充,我觉得这很方便,所以
用的这一技术做的校验。
后台所有接收的对象都为全String类型属性对象,因为对于json数据传输我们无法在接收
数据之前进行校验,属性全用String可以避免在Controller获取数据前发生数据转换错误。
JSR-303内建了一些校验规则,例如Min,Max,Pattern(正则表达式,有了这个就可以
处理绝大部分校验了),hibernate validtor还扩充了NotEmpty,Email等,一下是我的
例子中客户信息的对象:
package json;

import javax.validation.constraints.Digits;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.Pattern;

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

import constraints.IsDate;

public class JSONCustomer {
	@NotEmpty
	private String name;

	@NotEmpty
	private String addr;

	@NotEmpty
	@IsDate(format="yyyy-MM-dd")
	private String birthday;

	@NotEmpty
	private String hukou;

	@Email
	private String email;

	@Pattern(regexp="(((\\w+)\\.)+(\\w+))?")
	private String url;

	@Digits(integer = 3, fraction = 0)
	@Min(value = 100)
	@Max(value = 230)
	private String height;

	//setter, getter略
}


其中IsDate是我自己扩充的校验Annotation,这个后面再说。
这样,校验就定义好了,简单吧。

2.2 校验
下面来看看Controller中的校验。首先要在Controller的构造函数中传入validator,
spring有默认的validator,就是hibennate validator 4(所以需要这个jar包)。
然后在处理函数中使用validator.validate()就可以了,代码如下:
package controller;

import java.lang.reflect.InvocationTargetException;
import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Validator;

import org.apache.commons.beanutils.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import json.JSONCustomer;
import json.JSONResponse;
import vo.Customer;

@Controller
@RequestMapping("/customerInfo")
public class CustomerInfoController extends JSONController {

	@Autowired
	public CustomerInfoController(Validator validator) {
		super(validator);
	}
	
	@RequestMapping(value = "/new", method = RequestMethod.POST)
	@ResponseBody
	public JSONResponse newCustomer(@RequestBody JSONCustomer jsoncustomer) throws IllegalAccessException, InvocationTargetException {
		Set<ConstraintViolation<JSONCustomer>> failures = validator.validate(jsoncustomer);
		
		if (failures.isEmpty()) {
			//校验通过
			Customer customer = new Customer();
			//将接收的全String属性对象转成vo
			BeanUtils.copyProperties(jsoncustomer, customer);
			
			return successed(jsoncustomer);
		} else {
			//校验失败
			return failed(failures);
		}
	}
}


其中JSONController是我自己的Controller基类,后面再说。根据validate()的返回值failures
可以知道是否通过了校验,successed()和failed()是JSONController的方法,为了统一成功与
失败时的返回数据格式,这个在后面说明。

2.3 自定义校验Annotation
这部分请参阅相关的文档,我就不多说了,这里只贴出代码:
package constraints;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;

@Target( { METHO