当前位置:网站首页>數據驗證框架 Apache BVal 再使用

數據驗證框架 Apache BVal 再使用

2022-07-07 18:54: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://yzsam.com/2022/188/202207071651433707.html