当前位置:网站首页>数据验证框架 Apache BVal 再使用

数据验证框架 Apache BVal 再使用

2022-07-07 16:51:00 sp42a

关于 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<[email protected]> * */
@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 的功能还远不止这些,可以参考老外的文章学习更多高级用法。

原网站

版权声明
本文为[sp42a]所创,转载请带上原文链接,感谢
https://zhangxin.blog.csdn.net/article/details/125593783