当前位置:网站首页>數據驗證框架 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 的功能還遠不止這些,可以參考老外的文章學習更多高級用法。
边栏推荐
猜你喜欢
RISCV64
[unity shader] insert pass to realize the X-ray perspective effect of model occlusion
我感觉被骗了,微信内测 “大小号” 功能,同一手机号可注册两个微信
清华、剑桥、UIC联合推出首个中文事实核查数据集:基于证据、涵盖医疗社会等多个领域
上市十天就下线过万台,欧尚Z6产品实力备受点赞
How to clean when win11 C disk is full? Win11 method of cleaning C disk
标准ACL与扩展ACL
AI defeated mankind and designed a better economic mechanism
socket编程之常用api介绍与socket、select、poll、epoll高并发服务器模型代码实现
如何选择合适的自动化测试工具?
随机推荐
[sword finger offer] 59 - I. maximum value of sliding window
gsap动画库
Usage of PHP interview questions foreach ($arr as $value) and foreach ($arr as $value)
直播预约通道开启!解锁音视频应用快速上线的秘诀
[paper sharing] where's crypto?
将模型的记忆保存下来!Meta&UC Berkeley提出MeMViT,建模时间支持比现有模型长30倍,计算量仅增加4.5%...
【demo】循环队列及条件锁实现goroutine间的通信
Calculation of torque target value (ftorque) in servo torque control mode
Using stored procedures, timers, triggers to solve data analysis problems
[principle and technology of network attack and Defense] Chapter 1: Introduction
线程池和单例模式以及文件操作
Rules for filling in volunteers for college entrance examination
“解密”华为机器视觉军团:华为向上,产业向前
标准ACL与扩展ACL
行业案例|数字化经营底座助力寿险行业转型
RIP和OSPF的区别和配置命令
Idea completely uninstalls installation and configuration notes
Five network IO models
通过 Play Integrity API 的 nonce 字段提高应用安全性
go语言的字符串类型、常量类型和容器类型