java 入参校验
Posted itdeveloper
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java 入参校验相关的知识,希望对你有一定的参考价值。
项目中经常会涉及到入参校验,下面举个示例做法:
1、入参示例(JSON类型):
{
"sequenceNo":"11111",
"timestamp":"2020-06-05 13:53:02",
"channelId":"1003",
"requestData":{"productCode": "1002","supplierId":"002233"}
}
2、入参接收Vo:
import com.ocft.gamma.spds.trade.common.dto.BaseDto; import lombok.Getter; import lombok.Setter; import javax.validation.constraints.NotNull; @Getter @Setter public class ProductDetailsVo extends BaseDto { @NotNull(message ="产品代码不能为空") private String productCode; private String supplierId; }
3、controller中的方法:
@RequestMapping(value = "/getProductDetails.do", method = RequestMethod.POST) public BaseBodyResponse getProductDetails(@RequestBody BaseBodyRequest request) { ProductDetailsVo productDetailsVo = DealValidationJSRUtil.jsonParseAndJSR(request.getRequestData(),ProductDetailsVo.class); ProductDetailsDto productDetailsDto = productServiceImpl.getProductDetails(productDetailsVo); BaseBodyResponse baseBodyResponse = BaseBodyResponse.success(productDetailsDto); return baseBodyResponse; }
4、校验工具类DealValidationJSRUtil:
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONException; import com.demo.common.enums.MessageEnum; import com.demo.common.exception.JSRValidationException; import java.text.MessageFormat; import java.util.Map; public class DealValidationJSRUtil { private static final int msgLength = 250; // 报文标准长度 private static final int msgLengthMax = 300; // 最大报文长度 public static <T> T jsonParseAndJSR(String jsonStr, Class<T> clazz) throws JSONException, JSRValidationException { // 1、转换为JSON对象 T obj = JSON.parseObject(jsonStr, clazz); // 2、JSR参数验证 String code = MessageEnum.ParamsUnValidDetailsAndExplains.getCode(); // 错误码 DealValidationJSRUtil.validJsrByObj(obj, code); return obj; } public static <T> T jsonParseAndJSR(T obj) throws JSONException, JSRValidationException { // 1、JSR参数验证 String code = MessageEnum.ParamsUnValidDetailsAndExplains.getCode(); // 错误码 DealValidationJSRUtil.validJsrByObj(obj, code); return obj; } public static <T> T jsonParseAndJsrByTemplate(String jsonStr, Class<T> clazz, String templateCode) throws JSONException, JSRValidationException { // 1、转换为JSON对象 T obj = JSON.parseObject(jsonStr, clazz); // 2、JSR参数验证 String code = templateCode; // 错误码 if (MessageEnum.getErrorMessage(code) == null) { code = MessageEnum.ParamsUnValidDetailsAndExplains.getCode(); } DealValidationJSRUtil.validJsrByObj(obj, code); return obj; } /** * Description: JSR参数验证 * @param obj * @throws JSRValidationException */ private static void validJsrByObj(Object obj, String templateCode) throws JSRValidationException { if (obj == null) { throw new JSRValidationException(MessageEnum.ParamsDataNotFound); } // 2-1、参数校验 Map<String, Object> map = ViolationParamUtils .violationParamToJkkitJa(obj); Boolean isValid = (Boolean) map .get(ViolationParamUtils.JKKIT_LA_JSR_CODE); // 2-2、如果参数校验不通过,拼装响应报文消息 if (!isValid) { String msgTemplate = MessageEnum.getErrorMessage(templateCode); // 错误信息模板 String msg = MessageFormat.format( msgTemplate, map.get(ViolationParamUtils.JKKIT_LA_JSR_PROP), map.get(ViolationParamUtils.JKKIT_LA_JSR_MSG)); // 如果错误报文长度超过,获取精简模板 if (msg.length() > DealValidationJSRUtil.msgLength) { if (msg.length() > DealValidationJSRUtil.msgLengthMax) { // 超精简版 templateCode = MessageEnum.ParamsUnValid.getCode(); msg = MessageEnum.ParamsUnValid.getMessage(); } else { // 精简版 templateCode = MessageEnum.ParamsUnValidDetails.getCode(); msg = MessageFormat.format( MessageEnum.ParamsUnValidDetails.getMessage(), map.get(ViolationParamUtils.JKKIT_LA_JSR_PROP), map.get(ViolationParamUtils.JKKIT_LA_JSR_MSG)); } } throw new JSRValidationException(templateCode, msg); } } }
5、工具类ViolationParamUtils:
import com.demo.common.utils.StringUtil; import lombok.extern.slf4j.Slf4j; import javax.validation.*; import java.util.*; @Slf4j public class ViolationParamUtils { private static final Validator validator; private static final String PLACEHOLDER = "####"; public static final String JKKIT_LA_JSR_CODE = "JKKIT_LA_JSR_CODE"; public static final String JKKIT_LA_JSR_PROP = "JKKIT_LA_JSR_PROP"; public static final String JKKIT_LA_JSR_MSG = "JKKIT_LA_JSR_MSG"; static { ValidatorFactory vf = Validation.buildDefaultValidatorFactory(); validator = vf.getValidator(); } /** * Title [原生]通用的参数校验方法 Description 返回注解的message * @param object * @return List<String> String:错误信息 * @author MOSHIHONG930 */ public static List<String> violationParam(Object object) { List<String> validateMessage = new ArrayList<String>(); Set<ConstraintViolation<Object>> set = validator.validate(object); if (set != null && !set.isEmpty()) { for (ConstraintViolation<Object> constraintViolation : set) { validateMessage.add(constraintViolation.getMessage()); } } return validateMessage; } /** * Title [扩展]返回信息带属性名称的参数校验方法 Map Description * * @param object * @return Map<String, String> KEY 属性名称, Value 错误信息*/ public static Map<String, String> violationParam2(Object object) { Map<String, String> rmap = new HashMap<String, String>(); Set<ConstraintViolation<Object>> set = validator.validate(object); if (set != null && !set.isEmpty()) { for (ConstraintViolation<Object> constraintViolation : set) { Path prop = constraintViolation.getPropertyPath(); if (prop == null) { log.info("属性为空!{},msg:{})", object, constraintViolation.getMessage()); continue; } String key = prop.toString(); // 被校验的属性名称 String val = constraintViolation.getMessage(); // 错误信息 rmap.put(key, val); } } return rmap; } /** * Title [扩展]返回信息带属性名称的参数校验方法 List Description 1、返回信息格式: 属性名称 + 错误信息。 * 2、根据“####”占位符来自定义输出错误信息。 (占位符使用方法: 属性: * @Min(value=2, message="####不能小于1") private int id; 输出: * 当校验不通过时,将输出“id不能小于1” ) * @param object * @return List<String> String:错误信息 */ public static List<String> violationParamPro(Object object) { List<String> rlist = new ArrayList<String>(); Set<ConstraintViolation<Object>> set = validator.validate(object); if (set != null && !set.isEmpty()) { for (ConstraintViolation<Object> constraintViolation : set) { Path prop = constraintViolation.getPropertyPath(); if (prop == null) { // 基本不会出现的场景 log.info("属性为空!{},msg:{})", object, constraintViolation.getMessage()); continue; } String key = prop.toString(); // 被校验的属性名称 String val = constraintViolation.getMessage(); // 错误信息 // 判断是否存在占位符。存在 则替换。 boolean flag1 = ViolationParamUtils.existStrByK(val, PLACEHOLDER); boolean flag2 = ViolationParamUtils.existStrByK(val, key); String msg = ""; if (flag1 && !flag2) { // 如果占位符存在,属性不存在。 则替换占位符为属性名称 msg = val.replaceFirst(PLACEHOLDER, key); } else if (!flag1 && !flag2) { // 如果占位符不存在,属性也不存在。 则拼接属性名称在message前 msg = key + val; } else { // 其他情况。 返回错误信息原文 msg = val; } rlist.add(msg); } } return rlist; } /** * Description 验证k在str是否存在 */ private static boolean existStrByK(String str, String k) { if (StringUtil.isEmpty(str)|| StringUtil.isEmpty(k)) { return false; } int num = str.indexOf(k); if (num >= 0) { return true; } return false; } /** * Title [原生]通用的参数校验方法 Description 返回注解的message * @param object * @return List<String> String:错误信息 */ public static Map<String, Object> violationParamToJkkitJa(Object object) { Map<String, Object> msgMap = new HashMap<String, Object>(); msgMap.put(JKKIT_LA_JSR_CODE, true); // 验证结果 msgMap.put(JKKIT_LA_JSR_PROP, ""); // 被校验属性[prop1,prop2...] msgMap.put(JKKIT_LA_JSR_MSG, ""); // 校验结果[msg1,msg2...] Set<ConstraintViolation<Object>> set = validator.validate(object); // 验证通过 if (set == null || set.isEmpty()) { return msgMap; } // 否则,不通过 msgMap.put(JKKIT_LA_JSR_CODE, false); List<String> plist = new ArrayList<String>(); String props = ""; String msgs = ""; for (ConstraintViolation<Object> constraintViolation : set) { String prop = StringUtil.toString(constraintViolation.getPropertyPath()); if (!plist.contains(prop)) { plist.add(prop); props = props + constraintViolation.getPropertyPath() + ","; msgs = msgs + constraintViolation.getMessage() + ","; } } plist = null; // 封装被校验属性 if (StringUtil.isNotBlank(props)) { props = props.substring(0, props.length() - 1); msgMap.put(JKKIT_LA_JSR_PROP, props); } // 封装被校验属性结果 if (StringUtil.isNotBlank(msgs)) { msgs = msgs.substring(0, msgs.length() - 1); msgMap.put(JKKIT_LA_JSR_MSG, msgs); } return msgMap; } }
6、异常类JSRValidationException:
import com.demo.common.enums.MessageEnum; public class JSRValidationException extends RuntimeException { private static final long serialVersionUID = 8830274988553371796L; private String responseCode; private String responseMsg; public JSRValidationException(String code, String message) { super(message); this.responseCode = code; this.responseMsg = message; } public JSRValidationException(MessageEnum messageEnum) { this.responseCode = messageEnum.getCode(); this.responseMsg = messageEnum.getMessage(); } public JSRValidationException(String responseMsg) { super(responseMsg); this.responseMsg = responseMsg; } public String getResponseMsg() { return responseMsg; } public void setResponseMsg(String responseMsg) { this.responseMsg = responseMsg; } public String getResponseCode() { return responseCode; } public void setResponseCode(String responseCode) { this.responseCode = responseCode; } }
7、下面是校验注解包里面的相关类(放到同一个文件夹):
7.1
import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.RUNTIME; @Target({ METHOD, FIELD, ANNOTATION_TYPE }) @Retention(RUNTIME) @Constraint(validatedBy = BigDecimalMinValidator.class) @Documented public @interface BigDecimalMin { public String message() default "{java.math.BigDecimal.min.error}"; public Class<?>[] groups() default {}; public Class<? extends Payload>[] payload() default {}; public String value(); // 是否含自身, 默认否. 即false (0, 0), true [0, 0] public boolean containSelf() default false; }
7.2
import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; import java.math.BigDecimal; public final class BigDecimalMinValidator implements ConstraintValidator<BigDecimalMin, Object> { private BigDecimal value; private String message; public void initialize(BigDecimalMin bigDecimalMin) { try { value = new BigDecimal(bigDecimalMin.value()); } catch (NumberFormatException nfe) { throw new IllegalArgumentException( bigDecimalMin.value() + " 不是 BigDecimal 格式", nfe); } message = bigDecimalMin.message(); } public boolean isValid(final Object object, final ConstraintValidatorContext cvc) { if (object == null) { return true; } else if (object instanceof BigDecimal) { BigDecimal bigDecimal = new BigDecimal(object.toString()); if (value != null && bigDecimal.compareTo(value) < 0) { if (BigDecimal.ONE.compareTo(bigDecimal) != 0) { cvc.disableDefaultConstraintViolation(); cvc.buildConstraintViolationWithTemplate(message) .addConstraintViolation(); return false; } } return true; } return false; } }
7.3
import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.RUNTIME; @Target({ METHOD, FIELD, ANNOTATION_TYPE }) @Retention(RUNTIME) @Constraint(validatedBy = BigDecimalValidator.class) @Documented public @interface BigDecimalRange { public String message() default "{java.math.BigDecimal.range.error}"; public Class<?>[] groups() default {}; public Class<? extends Payload>[] payload() default {}; long minPrecision() default Long.MIN_VALUE; long maxPrecision() default Long.MAX_VALUE; int scale() default 0; }
7.4
import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; import java.math.BigDecimal; public final class BigDecimalValidator implements ConstraintValidator<BigDecimalRange, Object> { private long maxPrecision; private long minPrecision; private int scale; private String message; public void initialize(final BigDecimalRange bigDecimalRange) { maxPrecision = bigDecimalRange.maxPrecision(); minPrecision = bigDecimalRange.minPrecision(); scale = bigDecimalRange.scale(); message = bigDecimalRange.message(); } public boolean isValid(final Object object, final ConstraintValidatorContext cvc) { boolean isValid = false; if (object == null) { // This should be validated by the not null validator. isValid = true; } else if (object instanceof BigDecimal) { BigDecimal bigDecimal = new BigDecimal(object.toString()); int actualPrecision = bigDecimal.precision(); int actualScale = bigDecimal.scale(); isValid = actualPrecision >= minPrecision && actualPrecision <= maxPrecision && actualScale <= scale; if (!isValid) { cvc.disableDefaultConstraintViolation(); cvc.buildConstraintViolationWithTemplate(message) .addConstraintViolation(); } } return isValid; } }
7.5
import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.RUNTIME; @Target({ METHOD, FIELD, ANNOTATION_TYPE }) @Retention(RUNTIME) @Constraint(validatedBy = BigRangeValidator.class) @Documented public @interface BigRange { public String message() default "{this field describes bigger}"; public Class<?>[] groups() default {}; public Class<? extends Payload>[] payload() default {}; int value() default 0; }
7.6
import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; import java.math.BigDecimal; public final class BigRangeValidator implements ConstraintValidator<BigRange, Object> { @SuppressWarnings("unused") private int value; private String message; public void initialize(final BigRange big) { value = big.value(); message = big.message(); } public boolean isValid(final Object object, final ConstraintValidatorContext cvc) { if (object instanceof BigDecimal) { BigDecimal bd = new BigDecimal(object.toString()); if (bd.compareTo(BigDecimal.ZERO) == -1 || bd.compareTo(BigDecimal.ZERO) == 0) { cvc.disableDefaultConstraintViolation(); cvc.buildConstraintViolationWithTemplate(message) .addConstraintViolation(); return false; } } return true; } }
7.7
import java.lang.annotation.Retention; import java.lang.annotation.Target; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.RetentionPolicy.RUNTIME; /** * Description data部分可以为空 * */ @Target({ METHOD }) @Retention(RUNTIME) public @interface DataIsNullValidator { }
7.8
import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.RUNTIME; @Target({ METHOD, FIELD, ANNOTATION_TYPE }) @Retention(RUNTIME) @Constraint(validatedBy = DateTypeFormatValidator.class) @Documented public @interface DateTypeFormat { public String message() default "{this dateType format is error}"; public Class<?>[] groups() default {}; public Class<? extends Payload>[] payload() default {}; String dateRegex() default "^\d{4}(0[1-9]|1[0-2])$"; }
7.9
import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; import java.util.regex.Pattern; public class DateTypeFormatValidator implements ConstraintValidator<DateTypeFormat, Object> { private String dateRegex; private String message; public void initialize(final DateTypeFormat dateTypeFormat) { dateRegex = dateTypeFormat.dateRegex(); message = dateTypeFormat.message(); } public boolean isValid(final Object value, final ConstraintValidatorContext context) { boolean isValid = false; if (value == null) { // This should be validated by the not null // validator. isValid = false; } // 解决findbugs的问题 if (Pattern.compile(dateRegex) != null && Pattern.compile(dateRegex).matcher(value.toString()).matches()) { isValid = true; } if (!isValid) { context.disableDefaultConstraintViolation(); context.buildConstraintViolationWithTemplate(message).addConstraintViolation(); } return isValid; } }
7.10
import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.RUNTIME; /** * Description 字符串必须是纯数字 * */ @Target({ METHOD, FIELD, ANNOTATION_TYPE }) @Retention(RUNTIME) @Constraint(validatedBy = IsNumberStrValidator.class) @Documented public @interface IsNumberStr { String message() default "字符串必须是纯数字!"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
7.11
import com.ocft.gamma.spds.trade.common.utils.StringUtil; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Description 字符串必须是纯数字 * */ public class IsNumberStrValidator implements ConstraintValidator<IsNumberStr, Object> { private static final String regEx = "[0-9]*"; public void initialize(IsNumberStr constraintAnnotation) { } public boolean isValid(Object value, ConstraintValidatorContext context) { // 为空时,不验证是否为数字 if (value == null) { return true; } String str = StringUtil.valueOf(value); Pattern pattern = Pattern.compile(regEx); Matcher matcher = pattern.matcher(str); return matcher.matches(); } }
7.12
import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.RUNTIME; /** * Description 字符串不能包含特殊字符 */ @Target({ METHOD, FIELD, ANNOTATION_TYPE }) @Retention(RUNTIME) @Constraint(validatedBy = NotSpecialStrValidator.class) @Documented public @interface NotSpecialStr { String message() default "字符串不能包含特殊字符!"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
7.13
import com.ocft.gamma.spds.trade.common.utils.StringUtil; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Description 字符串不能包含特殊字符实现 */ public class NotSpecialStrValidator implements ConstraintValidator<NotSpecialStr, Object> { private static final String regEx = "[^`~!@#$%^&*()+=|{}‘:;‘,\[\].<>/?~!@#¥%……&*()——+|{}【】‘;:”“’。,、?]{1,}"; public void initialize(NotSpecialStr constraintAnnotation) { } public boolean isValid(Object value, ConstraintValidatorContext context) { // 为空时,不验证 if (value == null) { return true; } String str = StringUtil.valueOf(value); Pattern pattern = Pattern.compile(regEx); Matcher matcher = pattern.matcher(str); return matcher.matches(); } }
8、请求封装父类BaseBodyRequest:
import lombok.Getter; import lombok.Setter; @Getter @Setter public class BaseBodyRequest extends BaseDto { private static final long serialVersionUID = 941107305584836986L; private String sequenceNo; private String timestamp; private String channelId; private String requestData; }
9、请求封装父类BaseBodyResponse:
import com.ocft.gamma.spds.trade.common.enums.MessageEnum; import lombok.Getter; import lombok.Setter; @Getter @Setter public class BaseBodyResponse extends BaseDto{ private String responseCode; private String responseMessage; private Object responseData; public BaseBodyResponse(String code, String message) { super(); this.responseCode = code; responseMessage = message; } public BaseBodyResponse(String code, String message, Object data) { super(); this.responseCode = code; responseMessage = message; responseData = data; } public BaseBodyResponse(Object data) { super(); this.responseCode = MessageEnum.Success.getCode(); responseMessage = MessageEnum.Success.getMessage(); responseData = data; } public BaseBodyResponse(MessageEnum menum) { this.responseCode = MessageEnum.Success.getCode(); responseMessage = MessageEnum.Success.getMessage(); } /**成功直接返回数据和状态*/ public static BaseBodyResponse success(Object data){ return new BaseBodyResponse(data); } /**成功直接返回数据和状态*/ public static BaseBodyResponse success(){ return new BaseBodyResponse(MessageEnum.Success); } /**失败的时候调用*/ public static BaseBodyResponse failure(String code, String message){ return new BaseBodyResponse(code,message); } /**失败的时候调用*/ public static BaseBodyResponse failure(MessageEnum messageEnum){ return new BaseBodyResponse(messageEnum.getCode(),messageEnum.getMessage()); } }
以上是关于java 入参校验的主要内容,如果未能解决你的问题,请参考以下文章