数据验证框架 Apache BVal 再使用

Posted sp42a

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据验证框架 Apache BVal 再使用相关的知识,希望对你有一定的参考价值。

关于 Apache BVal,我 N 久之前使用过,还写了甚至全网唯一的简中教程《数据验证框架 Apache BVal 简介》,我依然还是那个观点:

Apache BVal (源码)是实体数据验证 Java Bean Validation 的参考实现。Apache BVal 提供了 JSR 303 规范中所有内置 constraint 的实现,用于对 Bean 中的字段的值进行约束定义、描述和验证。若单单说 JSR 规范大渣可能还不清楚,但做过 POJO 的 Hibernate Validator 注解的朋友就知道是啥,——那为什么不使用主流的 Hibernate Validator 呢?因为这货净是个压缩包都已经 13mb 了(尽管可以有文档、源码其他在内),BVal 才只有 400 多 kb,而我只需要服务端验证而已,——天真的孩纸伤不起啊。俺的 ORM 也是 Mybatis 的,务求尽可能地轻量级。

用法

Maven 引用

添加以下两个 Maven 依赖:

<dependency>
	<groupId>org.apache.bval</groupId>
	<artifactId>bval-jsr</artifactId>
	<version>2.0.6</version>
</dependency>

<dependency>
	<groupId>javax.validation</groupId>
	<artifactId>validation-api</artifactId>
	<version>2.0.1.Final</version>
</dependency>

2.0 要求 Java 8,Apache CommonUtils 不是强依赖了,同时 JSR 验证规范也升级到 2.x。

整合 Spring

Spring 里面注入 Provider。

/**
 * 数据验证框架
 * 
 * @return
 */
@Bean
LocalValidatorFactoryBean localValidatorFactoryBean() 
	LocalValidatorFactoryBean v = new LocalValidatorFactoryBean();
	v.setProviderClass(ApacheValidationProvider.class);
	
	return v;

调用校验

手动校验方法,先试试

@Autowired
LocalValidatorFactoryBean v;

public List<DataDict> getDataDict(Long parentId) 
	List<DataDict> list = DataDictDao.DataDictDAO.setWhereQuery("parentId", parentId).findList();

	Validator validator = v.getValidator();
	Set<ConstraintViolation<DataDict>> violations = validator.validate(list.get(0));
	System.out.println(violations.size()); // 校验结果

	System.out.println(list.get(0).getParentId());
	if (CollectionUtils.isEmpty(list))
		list = new ArrayList<>();

	return list;

上述代码是对一个 Java Bean:DataDict 进行校验,Bean 的字段可配置如下的约束。

public class DataDict implements CommonEntity 
	/**
	 * 主键 id,自增
	 */
	private Long id;

	/**
	 * 父 id
	 */
	@NotNull
	private Long parentId;

	/**
	 * 类型 id
	 */
	@NotNull
	private Long type;
	……

更多校验注解参见旧文

Spring MVC 自动校验

很简单,添加注解 @Valid 在 Bean 参数上。

/**
 * 新建 
 * @return
 */
@RequestMapping(method = RequestMethod.POST)
public String create(@Valid T news, Model model) 
	System.out.println("新建");
	if (result.hasErrors()) 
		LOGGER.info("create error!");
	else
		LOGGER.info("create ok!");
	
	news.setService(getService());
	try 
		getService().create(news);
		model.addAttribute("newlyId", news.getId());
	 catch (ServiceException e) 
		model.addAttribute("errMsg", e.toString());
	
	
	return "common/entity/json_cud";

接着说说怎么处理错误,或者不处理默认交由 Servlet 处理也可以。下面是自定义异常的处理器,转化为 JSON 返回。

import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import com.ajaxjs.util.WebHelper;

/**
 * 后端表单、数据校验的异常捕获
 * 
 * @author Frank Cheung<sp42@qq.com>
 *
 */
@ControllerAdvice
public class RestResponseEntityExceptionHandler 
	static final String TPL = "输入字段 [%s] 未通过校验,原因 [%s],输入值为 [%s],请检查后再提交。";

	@ExceptionHandler(value = BindException.class)
	public void exceptionHandler(HttpServletRequest req, HttpServletResponse resp, BindException e) 
		String msg = "";
		List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();

		for (FieldError err : fieldErrors) 
			msg += String.format(TPL, err.getField(), err.getDefaultMessage(), err.getRejectedValue());
//			msg += "\\\\\\\\n";
		

		ResponseResult result = new ResponseResult();
		result.setErrorCode("400");
		result.setMessage(msg);

		WebHelper.outputJson(resp, result.toString());
	

这个 RestResponseEntityExceptionHandler 按照正常注入 Spring 组件方式即可,下面是一种方法:

@Bean
RestResponseEntityExceptionHandler initRestResponseEntityExceptionHandler() 
	return new RestResponseEntityExceptionHandler();

JSR 303 可以自定义约束的原因,这样就不会输出默认的英文,但要逐个说明也比较麻烦。

另外有个 getAllErrors,这个不是针对字段的,估计是 for 校验方法的。

List<ObjectError> allErrors = e.getAllErrors();
for (ObjectError err : allErrors) 
	msg += err.getDefaultMessage();
	msg += StringUtils.arrayToDelimitedString(err.getCodes(), ",");

高级用法

Apache BVal 的功能还远不止这些,可以参考老外的文章学习更多高级用法。还有这篇介绍如何对枚举校验,非常不错。

以上是关于数据验证框架 Apache BVal 再使用的主要内容,如果未能解决你的问题,请参考以下文章

数据验证框架 Apache BVal 再使用

数据验证框架 Apache BVal 简介

Java bean validation 规范与参考实现

thinkphp 注册验证

08.19安全帮®每日资讯:Apache Shiro身份验证绕过漏洞安全风险通告;美国再拉黑38家华为子公司

在 django rest 框架中使用令牌身份验证返回更多信息