JAVA中的字段校驗(yàn)(validation)
在開(kāi)發(fā)業(yè)務(wù)時(shí),不可避免的需要處理一些校驗(yàn), 如果是寫(xiě)if-else這種代碼去校驗(yàn), 那會(huì)有一大段這樣的代碼。
不過(guò)還好有個(gè)校驗(yàn)插件:javax.validation.validation-api,不過(guò)一般會(huì)引用hibernate的校驗(yàn)組件:org.hibernate.hibernate-validator, 它已經(jīng)引用了validation-api組件。
基礎(chǔ)校驗(yàn)類(lèi)型
JSR303 是一套JavaBean參數(shù)校驗(yàn)的標(biāo)準(zhǔn),它定義了很多常用的校驗(yàn)注解,我們可以直接將這些注解加在我們JavaBean的屬性上面,就可以在需要校驗(yàn)的時(shí)候進(jìn)行校驗(yàn)了。
注解如下:
Hibernate validator 在JSR303的基礎(chǔ)上對(duì)校驗(yàn)注解進(jìn)行了擴(kuò)展,擴(kuò)展注解如下:
寫(xiě)個(gè)DEMO看看
校驗(yàn)工具類(lèi):ValidatorUtils
import javax.validation.ConstraintViolation; import javax.validation.Validation; import javax.validation.Validator; import javax.validation.groups.Default; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; /** * Created by saleson on 2017/10/13. */ public class ValidatorUtils { private static Validator validator = Validation.buildDefaultValidatorFactory() .getValidator(); public static <T> Map<String, String> validate(T obj) { Map<String, StringBuilder> errorMap = new HashMap<>(); Set<ConstraintViolation<T>> set = validator.validate(obj, Default.class); if (set != null && set.size() > 0) { String property = null; for (ConstraintViolation<T> cv : set) { //這里循環(huán)獲取錯(cuò)誤信息,可以自定義格式 property = cv.getPropertyPath().toString(); if (errorMap.get(property) != null) { errorMap.get(property).append("," + cv.getMessage()); } else { StringBuilder sb = new StringBuilder(); sb.append(cv.getMessage()); errorMap.put(property, sb); } } } return errorMap.entrySet().stream().collect(Collectors.toMap(k -> k.getKey(), v -> v.getValue().toString())); } }
DemoBean:
import com.fm.core.exceptions.ApiException; import org.hibernate.validator.constraints.NotEmpty; import com.fm.framework.api.ApiResultHelper; import com.fm.framework.json.Json; import com.fm.framework.utils.StringUtils; import com.fm.grantauth.domain.ValidateResult; import com.fm.grantauth.domain.dto.AuthorizationApplyDTO; import com.fm.grantauth.utils.ValidatorUtils; import org.junit.Test; import javax.validation.Valid; import java.util.Map; /** * Created by saleson on 2017/10/12. */ public class DataAuthValidator { private static final Logger log = LoggerFactory.getLogger(DataAuthValidator.class); @Override public ValidateResult validate(AuthorizationApplyDTO applyDTO) { String json = applyDTO.getContractParams(); if (StringUtils.isEmpty(json)) { throw new ApiException(ApiResultHelper.newParameterEmpty("contractParams字段不能為空")); } DataAuthContractParams params = Json.parseObject(json, DataAuthContractParams.class); Map<String, String> validMap = ValidatorUtils.validate(params); if (!validMap.isEmpty()) { log.warn(validMap.toString()); throw new ApiException(ApiResultHelper.newBusinessError(lackFieldMessage(validMap.keySet().toArray(new String[0])))); } return new ValidateResult(true); } public static class DataAuthContractParams { @NotEmpty private String businessName; @NotEmpty private String dataProvider; @NotEmpty private String personalDataName; @NotEmpty private String dataDemander; public String getBusinessName() { return businessName; } public void setBusinessName(String businessName) { this.businessName = businessName; } public String getDataProvider() { return dataProvider; } public void setDataProvider(String dataProvider) { this.dataProvider = dataProvider; } public String getPersonalDataName() { return personalDataName; } public void setPersonalDataName(String personalDataName) { this.personalDataName = personalDataName; } public String getDataDemander() { return dataDemander; } public void setDataDemander(String dataDemander) { this.dataDemander = dataDemander; } } @Test public void test() { AuthorizationApplyDTO applyDTO = new AuthorizationApplyDTO(); DataAuthContractParams params = new DataAuthContractParams(); params.setBusinessName("f"); params.setDataDemander("f"); params.setDataProvider(""); params.setPersonalDataName(""); applyDTO.setContractParams(Json.toJSONString(params)); ValidateResult result = new DataAuthValidator().validate(applyDTO); System.out.println(Json.toJSONString(result)); assert result.isSeccess(); } }
運(yùn)行結(jié)果:
[main] WARN com.fm.grantauth.module.authorization.contact.DataAuthValidator - {dataProvider=不能為空, personalDataName=不能為空}
com.fm.core.exceptions.ApiException: 參數(shù)contractParams中缺少字段:dataProvider, personalDataName
自定義校驗(yàn)規(guī)則(Validator)
自定義注解:
package com.fm.core.validation; import com.fm.core.validation.validator.NotEmptyValidator; import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import static java.lang.annotation.ElementType.ANNOTATION_TYPE; import static java.lang.annotation.ElementType.CONSTRUCTOR; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.PARAMETER; /** * Created by saleson on 2017/5/31. */ @Retention(RetentionPolicy.RUNTIME) @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER}) @Documented @Constraint(validatedBy = {NotEmptyValidator.class}) public @interface NotEmpty { String message() default "參數(shù)不能為null或空字符串"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
校驗(yàn)器(validator):
package com.fm.core.validation.validator; import com.fm.core.validation.NotEmpty; import com.fm.framework.utils.StringUtils; import org.apache.commons.collections.MapUtils; import javax.validation.ConstraintValidatorContext; import java.lang.reflect.Array; import java.util.Collection; import java.util.Map; /** * Created by saleson on 2017/5/27. */ public class NotEmptyValidator extends AbstractValidator<NotEmpty, Object> { @Override protected boolean validNull(ConstraintValidatorContext context) { return false; } @Override protected boolean valid(Object value, ConstraintValidatorContext context) { if (value instanceof String) { return StringUtils.isNotEmpty(value.toString()); } else if (value instanceof Collection) { return !org.springframework.util.CollectionUtils.isEmpty((Collection) value); } else if (value instanceof Map) { return MapUtils.isNotEmpty((Map) value); } else if (value.getClass().isArray()) { return Array.getLength(value) > 0; } return true; } }
將上個(gè)demo中引用的org.hibernate.validator.constraints.NotEmpty改為com.fm.core.validation.NotEmpty即可。
運(yùn)行結(jié)果:
WARN com.fm.grantauth.module.authorization.contact.DataAuthValidator - {dataProvider=參數(shù)不能為null或空字符串, personalDataName=參數(shù)不能為null或空字符串}
com.fm.core.exceptions.ApiException: 參數(shù)contractParams中缺少字段:dataProvider, personalDataName
級(jí)聯(lián)校驗(yàn)
校驗(yàn)的對(duì)象中包含另一個(gè)需要校驗(yàn)的對(duì)象時(shí),則可以使用@javax.validation.Valid
import com.fm.core.exceptions.ApiException; import com.fm.core.validation.NotEmpty; import com.fm.framework.api.ApiResultHelper; import com.fm.framework.json.Json; import com.fm.framework.utils.StringUtils; import com.fm.grantauth.domain.ValidateResult; import com.fm.grantauth.domain.dto.AuthorizationApplyDTO; import com.fm.grantauth.utils.ValidatorUtils; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.validation.Valid; import java.util.Map; /** * Created by saleson on 2017/10/12. */ public class DataAuthValidator implements ContractParamsValidator { private static final Logger log = LoggerFactory.getLogger(DataAuthValidator.class); @Override public ValidateResult validate(AuthorizationApplyDTO applyDTO) { String json = applyDTO.getContractParams(); if (StringUtils.isEmpty(json)) { throw new ApiException(ApiResultHelper.newParameterEmpty("contractParams字段不能為空")); } DataAuthContractParams params = Json.parseObject(json, DataAuthContractParams.class); Map<String, String> validMap = ValidatorUtils.validate(params); if (!validMap.isEmpty()) { log.warn(validMap.toString()); throw new ApiException(ApiResultHelper.newBusinessError(lackFieldMessage(validMap.keySet().toArray(new String[0])))); } return new ValidateResult(true); } public static class DataAuthContractParams { @NotEmpty private String businessName; @NotEmpty private String dataProvider; @NotEmpty private String personalDataName; @NotEmpty private String dataDemander; // @NotEmpty @Valid private Re r; public String getBusinessName() { return businessName; } public void setBusinessName(String businessName) { this.businessName = businessName; } public String getDataProvider() { return dataProvider; } public void setDataProvider(String dataProvider) { this.dataProvider = dataProvider; } public String getPersonalDataName() { return personalDataName; } public void setPersonalDataName(String personalDataName) { this.personalDataName = personalDataName; } public String getDataDemander() { return dataDemander; } public void setDataDemander(String dataDemander) { this.dataDemander = dataDemander; } public Re getR() { return r; } public void setR(Re r) { this.r = r; } } public static class Re { @NotEmpty private String d; public String getD() { return d; } public void setD(String d) { this.d = d; } } @Test public void test() { AuthorizationApplyDTO applyDTO = new AuthorizationApplyDTO(); DataAuthContractParams params = new DataAuthContractParams(); params.setBusinessName("f"); params.setDataDemander("f"); params.setDataProvider(""); params.setPersonalDataName(""); Re r = new Re(); params.setR(r); applyDTO.setContractParams(Json.toJSONString(params)); ValidateResult result = new DataAuthValidator().validate(applyDTO); System.out.println(Json.toJSONString(result)); assert result.isSeccess(); } }
運(yùn)行結(jié)果:
WARN com.fm.grantauth.module.authorization.contact.DataAuthValidator - {r.d=參數(shù)不能為null或空字符串, dataProvider=參數(shù)不能為null或空字符串, personalDataName=參數(shù)不能為null或空字符串}
com.fm.core.exceptions.ApiException: 參數(shù)contractParams中缺少字段:r.d, dataProvider, personalDataName
分組校驗(yàn)
對(duì)同一個(gè)Model,我們?cè)谠黾雍托薷臅r(shí)對(duì)參數(shù)的校驗(yàn)也是不一樣的,這個(gè)時(shí)候我們就需要定義分組驗(yàn)證。
com.fm.core.validation.NotEmpty#groups()就是用于分組校驗(yàn)的
添加兩個(gè)用于分組校驗(yàn)的接口:
public static interface GroupFirst { } public static interface GroupSecond { }
校驗(yàn)改成:
public static class DataAuthContractParams { @NotEmpty private String businessName; @NotEmpty private String dataProvider; @NotEmpty(groups = GroupFirst.class) private String personalDataName; @NotEmpty(groups = {GroupFirst.class, GroupSecond.class}) private String dataDemander; // @NotEmpty @Valid private Re r; public String getBusinessName() { return businessName; } public void setBusinessName(String businessName) { this.businessName = businessName; } public String getDataProvider() { return dataProvider; } public void setDataProvider(String dataProvider) { this.dataProvider = dataProvider; } public String getPersonalDataName() { return personalDataName; } public void setPersonalDataName(String personalDataName) { this.personalDataName = personalDataName; } public String getDataDemander() { return dataDemander; } public void setDataDemander(String dataDemander) { this.dataDemander = dataDemander; } public Re getR() { return r; } public void setR(Re r) { this.r = r; } } public static class Re { @NotEmpty(groups = GroupSecond.class) private String d; public String getD() { return d; } public void setD(String d) { this.d = d; } }
修改ValidatorUtils
package com.fm.grantauth.utils; import javax.validation.ConstraintViolation; import javax.validation.Validation; import javax.validation.Validator; import javax.validation.groups.Default; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; /** * Created by saleson on 2017/10/13. */ public class ValidatorUtils { private static Validator validator = Validation.buildDefaultValidatorFactory() .getValidator(); public static <T> Map<String, String> validate(T obj) { Set<ConstraintViolation<T>> set = validator.validate(obj, Default.class); return convertErrorMap(set); } public static <T> Map<String, String> validate(T obj, Class<?>... groups) { Set<ConstraintViolation<T>> set = validator.validate(obj, groups); return convertErrorMap(set); } private static <T> Map<String, String> convertErrorMap(Set<ConstraintViolation<T>> set) { Map<String, StringBuilder> errorMap = new HashMap<>(); if (set != null && set.size() > 0) { String property = null; for (ConstraintViolation<T> cv : set) { //這里循環(huán)獲取錯(cuò)誤信息,可以自定義格式 property = cv.getPropertyPath().toString(); if (errorMap.get(property) != null) { errorMap.get(property).append("," + cv.getMessage()); } else { StringBuilder sb = new StringBuilder(); sb.append(cv.getMessage()); errorMap.put(property, sb); } } } return errorMap.entrySet().stream().collect(Collectors.toMap(k -> k.getKey(), v -> v.getValue().toString())); } }
測(cè)試GroupFirst.class:
@Test public void test() { DataAuthContractParams params = new DataAuthContractParams(); params.setBusinessName("f"); params.setDataDemander(""); params.setDataProvider("f"); params.setPersonalDataName(""); Re r = new Re(); params.setR(r); Map<String, String> validMap = ValidatorUtils.validate(params, GroupFirst.class); System.out.println("error is: " + validMap); }
運(yùn)行結(jié)果:
error is: {dataDemander=參數(shù)不能為null或空字符串, personalDataName=參數(shù)不能為null或空字符串}
測(cè)試GroupSecond.class:
@Test public void test() { DataAuthContractParams params = new DataAuthContractParams(); params.setBusinessName("f"); params.setDataDemander(""); params.setDataProvider("f"); params.setPersonalDataName(""); Re r = new Re(); params.setR(r); Map<String, String> validMap = ValidatorUtils.validate(params, GroupSecond.class); System.out.println("error is: " + validMap); }
運(yùn)行結(jié)果:
error is: {dataDemander=參數(shù)不能為null或空字符串, r.d=參數(shù)不能為null或空字符串}
測(cè)試GroupFirst.class+GroupSecond.class:
@Test public void test() { DataAuthContractParams params = new DataAuthContractParams(); params.setBusinessName("f"); params.setDataDemander(""); params.setDataProvider("f"); params.setPersonalDataName(""); Re r = new Re(); params.setR(r); Map<String, String> validMap = ValidatorUtils.validate(params, GroupFirst.class, GroupSecond.class); System.out.println("error is: " + validMap); }
運(yùn)行結(jié)果:
error is: {dataDemander=參數(shù)不能為null或空字符串, r.d=參數(shù)不能為null或空字符串, personalDataName=參數(shù)不能為null或空字符串}
spring mvc上使用分組校驗(yàn):
@org.springframework.validation.annotation.Validated({GroupFirst.class, GroupSecond.class})
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
在Java中以及Spring環(huán)境下操作Redis的過(guò)程
文章介紹了在Java和Spring環(huán)境下操作Redis的基本方法,在Java環(huán)境下,使用Maven創(chuàng)建項(xiàng)目并導(dǎo)入Jedis依賴(lài),通過(guò)配置端口轉(zhuǎn)發(fā)訪(fǎng)問(wèn)Redis,文章總結(jié)了Redis的基本命令和類(lèi)別,如String、list、hash、set和zset,感興趣的朋友跟隨小編一起看看吧2025-03-03Java使用Scala實(shí)現(xiàn)尾遞歸優(yōu)化來(lái)解決爆棧問(wèn)題
Scala?作為一種多范式的編程語(yǔ)言,結(jié)合了面向?qū)ο蠛秃瘮?shù)式編程的特性,在?Scala?中,尾遞歸?是通過(guò)編譯器優(yōu)化來(lái)防止棧溢出問(wèn)題的,尾遞歸優(yōu)化是一種特殊的優(yōu)化方式,可以讓遞歸調(diào)用不使用新的棧幀,所以本文介紹了在Java項(xiàng)目中如何使用Scala實(shí)現(xiàn)尾遞歸優(yōu)化來(lái)解決爆棧問(wèn)題2024-10-10動(dòng)態(tài)配置Spring Boot日志級(jí)別的全步驟
這篇文章主要給大家介紹了關(guān)于動(dòng)態(tài)配置Spring Boot日志級(jí)別的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Spring Boot具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04Java調(diào)用SQL腳本執(zhí)行常用的方法示例
這篇文章主要給大家介紹了關(guān)于Java調(diào)用SQL腳本執(zhí)行常用的方法的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2018-04-04SpringBoot四大神器之Actuator的使用小結(jié)
這篇文章主要介紹了SpringBoot四大神器之Actuator的使用小結(jié),詳細(xì)的介紹了Actuator的使用和端點(diǎn)的使用,有興趣的可以了解一下2017-11-11JAVALambda表達(dá)式與函數(shù)式接口詳解
大家好,本篇文章主要講的是JAVALambda表達(dá)式與函數(shù)式接口詳解,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話(huà)記得收藏一下2022-02-02java?Object轉(zhuǎn)Integer實(shí)現(xiàn)方式
這篇文章主要介紹了java?Object轉(zhuǎn)Integer實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07Java設(shè)計(jì)模式初識(shí)之備忘錄模式詳解
備忘錄設(shè)計(jì)模式(Memento Design Pattern)也叫作快照(Snapshot)模式,主要用于實(shí)現(xiàn)防丟失、撤銷(xiāo)、恢復(fù)等功能。本文將通過(guò)示例為大家介紹一些備忘錄模式的定義與使用,需要的可以參考一下2022-11-11