java 自定义注解校验实体类属性
直接上代码
1.是否启用参数校验注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EnableArgumentsCheck {/*** 是否启用*/boolean enable() default true;}
2.参数校验自定义注解
/*** 参数校验自定义注解* 属性定义:* name 必填,字段名称,用于参数校验失败消息提示* range 非必填,范围校验,Long,int,Double属性校验生效,{0,500000000}* decimal 非必填,Double类型校验,decimal = {5,2},校验参数为5位数保留2位小数* contain 非必填,参数int,String校验,{"10","20","30"}* isNotNull 非必填,参数是否不能为空,默认值:false,使用所有类型* type 非必传,,适用String类型校验,字段类型(EMAIL,MOBILE,IDENTITY_CARD,NUMBER,DATE)* min 非必传,Long,int,Double属性校验最小值限制,校验当前类型值不能小于min的值,默认值:Integer.MIN_VALUE* max 非必传,Long,int,Double属性校验最大值限制,校验当前类型值不能大于max的值,默认值:Integer.MAX_VALUE* pattern 非必传,参数int,String正则表达式校验* enumClass 非必传,枚举值校验,判断当前值是否在枚举中,enumClass和enumAttr一起使用,适用String,int* message 非必填,错误消息提示,默认:字段:xxx参数检验不合法* maxLength 非必传,最大长度限制校验,适用:Long,int,Double,string,list,arrays* minLength 非必传,最小长度限制校验,,适用:Long,int,Double,string,list,arrays* like 非必传,参数模糊匹配* groups 非必传,分组匹配,使用所有类型* formatDate 非必传,时间格式参数验证,适用string校验* division,非必传,校验时间是否将来时间还是过去时间,,future将来时间,past过去时间,适用date校验* @author 106979*/
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PropertiesVerify {/*** 字段名称* @return*/String name();/*** 范围range* @return*/int[] range() default {};/*** 小数类型长度和小数位数* @return*/int[] decimal() default {};/*** 包含字符串* @return*/String[] contain() default {};/*** 是否为空*/boolean isNotNull() default false;/*** 字段类型* @return*/FieldType type() default FieldType.NULL;/*** Int最小值*/int minInt() default Integer.MIN_VALUE;/*** Int最大值*/int maxInt() default Integer.MAX_VALUE;/*** Long最小值*/long minLong() default Long.MIN_VALUE;/*** Long最大值*/long maxLong() default Long.MAX_VALUE;/*** 正则表达式*/String pattern() default "";/*** 枚举* @return*/Class<?> enumClass() default Void.class;/*** 分组* @return*/Class<? extends Default>[] groups() default {};/*** 枚举方法* @return*/String enumAttr() default "";/*** 模糊匹配* @return*/String like() default "";/*** 时间格式* @return*/String formatDate() default "";/*** 最大长度* @return*/int maxLength() default -1;/*** 最小长度* @return*/int minLength() default -1;/*** 时间分割线* @return*/DateDivisionEnum division() default DateDivisionEnum.NONE;/*** 错误消息提示* @return*/String message() default "%s校验不通过,%s";enum FieldType {NULL("", ""),EMAIL("邮箱", "^[A-Za-z\\d]+([-_.][A-Za-z\\d]+)*@([A-Za-z\\d]+[-.])+[A-Za-z\\d]{2,4}$"),MOBILE("手机号码", "^((13[0-9])|(14[5,7,9])|(15([0-3]|[5-9]))|(16[5,6])|(17[0-8])|(18[0-9])|(19[1、5、8、9]))\\\\d{8}$"),IDENTITY_CARD("身份证", "^[1-9]\\\\d{5}[1-9]\\\\d{3}((0\\\\d)|(1[0-2]))(([0|1|2]\\\\d)|3[0-1])\\\\d{3}([\\\\d|x|X]{1})$"),NUMBER("正整数", "^[0-9]*[1-9][0-9]*$"),DATE("日期", "((^((1[8-9]\\d{2})|([2-9]\\d{3}))([-\\/\\._])(10|12|0?[13578])([-\\/\\._])(3[01]|[12][0-9]|0?[1-9])$)|(^((1[8-9]\\d{2})|([2-9]\\d{3}))([-\\/\\._])(11|0?[469])([-\\/\\._])(30|[12][0-9]|0?[1-9])$)|(^((1[8-9]\\d{2})|([2-9]\\d{3}))([-\\/\\._])(0?2)([-\\/\\._])(2[0-8]|1[0-9]|0?[1-9])$)|(^([2468][048]00)([-\\/\\._])(0?2)([-\\/\\._])(29)$)|(^([3579][26]00)([-\\/\\._])(0?2)([-\\/\\._])(29)$)|(^([1][89][0][48])([-\\/\\._])(0?2)([-\\/\\._])(29)$)|(^([2-9][0-9][0][48])([-\\/\\._])(0?2)([-\\/\\._])(29)$)|(^([1][89][2468][048])([-\\/\\._])(0?2)([-\\/\\._])(29)$)|(^([2-9][0-9][2468][048])([-\\/\\._])(0?2)([-\\/\\._])(29)$)|(^([1][89][13579][26])([-\\/\\._])(0?2)([-\\/\\._])(29)$)|(^([2-9][0-9][13579][26])([-\\/\\._])(0?2)([-\\/\\._])(29)$))");public String name;public String regular;FieldType(String name, String regular) {this.name = name;this.regular = regular;}}}
3.参数校验接口
/*** 参数校验接口* @author zcs*/
public interface ArgumentsVerify {/*** 默认参数校验* @return*/String check();
}
4.参数校验抽象类,提供基础校验方法,以及继承抽象类的子类.
public abstract class AbstractArgumentsVerify implements ArgumentsVerify {private static final String DECIMAL_POINT = "\\.";private static final int ARRAY_LENGTH = 2;protected Object inputData;protected PropertiesVerify propertiesVerify;protected Class<? extends Default> groups;AbstractArgumentsVerify(Object inputData, PropertiesVerify propertiesVerify, Class<? extends Default> groups) {this.inputData = inputData;this.propertiesVerify = propertiesVerify;this.groups = groups;}/*** 包含校验* @return*/public String isContain() {if (inputData != null&& propertiesVerify != null&& propertiesVerify.contain() != null&& propertiesVerify.contain().length > 0&& !Arrays.asList(propertiesVerify.contain()).contains(inputData.toString())) {return getMsg("不存在指定值范围内");}return StringUtils.EMPTY;}/*** 时间类型校验* @return*/public String isFormatDate() {if (inputData == null) {return StringUtils.EMPTY;}if (StringUtils.isNotBlank(propertiesVerify.formatDate())) {Date d = null;try {SimpleDateFormat sdf = new SimpleDateFormat(propertiesVerify.formatDate(), Locale.CHINA);d = sdf.parse(inputData.toString());} catch (ParseException e) {throw new RuntimeException("参数校验时间格式错误");}if (d == null) {return getMsg("时间格式错误");}}return StringUtils.EMPTY;}/*** 时间分界校验* @return*/public String division() {if (inputData == null) {return StringUtils.EMPTY;}if (propertiesVerify.division() != null && !DateDivisionEnum.NONE.equals(propertiesVerify.division())) {Date d = (Date) inputData;Date currentDate = new Date();switch (propertiesVerify.division()) {case FUTURE:if (!d.after(currentDate)) {return getMsg("必须大于当前时间");}break;case PAST:if (!d.before(currentDate)) {return getMsg("必须小于当前时间");}break;}}return StringUtils.EMPTY;}/*** 最小值参数校验* @return*/public String isMinInt() {if (inputData == null) {return StringUtils.EMPTY;}int intVal = 0;try {intVal = (int) inputData;} catch (Exception e) {//非数字类型不校验}if (propertiesVerify.minInt() > intVal) {return getMsg("输入值小于指定最小值");}return StringUtils.EMPTY;}/*** 最大值* @return*/public String isMaxInt() {if (inputData == null) {return StringUtils.EMPTY;}int intVal = 0;try {intVal = (int) inputData;} catch (Exception e) {//非数字类型不校验}if (propertiesVerify.maxInt() < intVal) {return getMsg("输入值大于指定最大值");}return StringUtils.EMPTY;}/*** 最小值参数校验* @return*/public String isMinLong() {if (inputData == null) {return StringUtils.EMPTY;}long longVal = 0;try {longVal = (long) inputData;} catch (Exception e) {//非数字类型不校验}if (propertiesVerify.minLong() > longVal) {return getMsg("输入值小于指定最小值");}return StringUtils.EMPTY;}/*** 最大值* @return*/public String isMaxLong() {if (inputData == null) {return StringUtils.EMPTY;}long longVal = 0;try {longVal = (long) inputData;} catch (Exception e) {//非数字类型不校验}if (propertiesVerify.maxLong() < longVal) {return getMsg("输入值大于指定最大值");}return StringUtils.EMPTY;}/*** 最小长度* @return*/public String minLength() {if (inputData == null) {return StringUtils.EMPTY;}if (propertiesVerify.minLength() > 0) {int length;length = getLength();if (length < propertiesVerify.minLength()) {return getMsg("输入值长度小于最小值");}}return StringUtils.EMPTY;}/*** 最大长度* @return*/public String maxLength() {if (inputData == null) {return StringUtils.EMPTY;}if (propertiesVerify.maxLength() > 0) {int length;length = getLength();if (length > propertiesVerify.maxLength()) {return getMsg("输入值长度大于最大值");}}return StringUtils.EMPTY;}private int getLength() {int length;if (inputData instanceof Map) {Map mapData = (Map) inputData;length = mapData.size();} else if (inputData instanceof List) {List listData = (List) inputData;length = listData.size();} else if (inputData instanceof Collection) {Collection collectionData = (Collection) inputData;length = collectionData.size();} else if (inputData.getClass().isArray()) {length = Arrays.asList(inputData).size();} else {length = inputData.toString().length();}return length;}/*** 取值范围* @return*/public String range() {if (inputData == null) {return StringUtils.EMPTY;}BigDecimal b = null;try {b = new BigDecimal(inputData.toString());} catch (Exception e) {//非数字类型不校验}if (b != null&& propertiesVerify.range() != null&& propertiesVerify.range().length >= ARRAY_LENGTH&& (b.doubleValue() > propertiesVerify.range()[1] || b.doubleValue() < propertiesVerify.range()[0])) {return getMsg(String.format("输入值必须在%s-%s范围内", propertiesVerify.range()[0], propertiesVerify.range()[1]));}return StringUtils.EMPTY;}/*** 模糊匹配* @return*/public String isLike() {if (inputData == null) {return StringUtils.EMPTY;}if (StringUtils.isNotBlank(propertiesVerify.like())&& !inputData.toString().contains(propertiesVerify.like())) {return getMsg(String.format("参数必须包含[%s]", propertiesVerify.like()));}return StringUtils.EMPTY;}/*** 字段类型枚举* @return*/public String type() {if (inputData == null) {return StringUtils.EMPTY;}if (propertiesVerify.type() != null && StringUtils.isNotBlank(propertiesVerify.type().regular)) {Pattern pat = Pattern.compile(propertiesVerify.type().regular);Matcher mat = pat.matcher(inputData.toString());boolean isMatch = mat.matches();if (!isMatch) {return getMsg(String.format("参数不匹配类型:", propertiesVerify.type().name));}}return StringUtils.EMPTY;}/*** 小数范围* @return*/public String decimal() {if (inputData == null) {return StringUtils.EMPTY;}if (propertiesVerify.decimal() != null && propertiesVerify.decimal().length >= ARRAY_LENGTH) {//全部位数int digitsNumber = propertiesVerify.decimal()[0];//小数位数int decimalNumber = propertiesVerify.decimal()[1];String strVal = inputData.toString().replace("-", "");if (StringUtils.contains(strVal, ".")) {int intLength = strVal.split(DECIMAL_POINT)[0].length();int decimalLength = strVal.split(DECIMAL_POINT)[1].length();if (intLength + decimalLength > digitsNumber) {return getMsg(String.format("参数不能超过%s位", digitsNumber));}if (decimalLength > decimalNumber) {return getMsg(String.format("小数不能超过%s位", decimalNumber));}} else {int intLength = strVal.length();if (intLength > digitsNumber) {return getMsg(String.format("参数不能超过%s位", digitsNumber));}}}return StringUtils.EMPTY;}/*** 自定义正则表达式* @return*/public String pattern() {if (inputData == null) {return StringUtils.EMPTY;}if (StringUtils.isNotBlank(propertiesVerify.pattern())) {Pattern pat = Pattern.compile(propertiesVerify.pattern());Matcher mat = pat.matcher(inputData.toString());boolean isMatch = mat.matches();if (!isMatch) {return getMsg("参数不满足正则表达式");}}return StringUtils.EMPTY;}/*** 枚举值* @return*/public String enumVal() {if (inputData == null) {return StringUtils.EMPTY;}if (propertiesVerify.enumClass() != null&& propertiesVerify.enumClass() != Void.class&& StringUtils.isNotBlank(propertiesVerify.enumAttr())) {try {// 2.得到所有枚举常量Object[] objects = propertiesVerify.enumClass().getEnumConstants();String methodName = "get" + propertiesVerify.enumAttr().substring(0, 1).toUpperCase() + propertiesVerify.enumAttr().substring(1);Method method = propertiesVerify.enumClass().getMethod(methodName);boolean isInclude = false;for (Object obj : objects) {// 3.调用对应方法,得到枚举常量中字段的值Object val = method.invoke(obj);if (val != null && inputData.toString().equals(val + "")) {isInclude = true;break;}}if (!isInclude) {return getMsg("参数不在指定枚举值中");}} catch (Exception e) {//todo 异常处理System.out.println(e.getMessage());}}return StringUtils.EMPTY;}private String getMsg(String desc) {return String.format(propertiesVerify.message(), propertiesVerify.name(), desc);}
}
实现类型 :
public class DateArgumentsVerify extends AbstractArgumentsVerify {public DateArgumentsVerify(Date val, PropertiesVerify propertiesVerify, Class<? extends Default> groups) {super(val, propertiesVerify, groups);}@Overridepublic String check() {String res = super.division();if (StringUtils.isNotBlank(res)) {return res;}return StringUtils.EMPTY;}
}
public class DoubleArgumentsVerify extends AbstractArgumentsVerify {public DoubleArgumentsVerify(String val, PropertiesVerify propertiesVerify, Class<? extends Default> groups) {super(val, propertiesVerify, groups);}@Overridepublic String check() {//包含校验String res = super.maxLength();if (StringUtils.isNotBlank(res)) {return res;}res = super.minLength();if (StringUtils.isNotBlank(res)) {return res;}res = super.decimal();if (StringUtils.isNotBlank(res)) {return res;}res = super.isLike();if (StringUtils.isNotBlank(res)) {return res;}res = super.range();return res;}
}
public class IntegerArgumentsVerify extends AbstractArgumentsVerify {public IntegerArgumentsVerify(Integer val, PropertiesVerify propertiesVerify, Class<? extends Default> groups) {super(val, propertiesVerify, groups);}@Overridepublic String check() {//包含校验String res = super.isContain();if (StringUtils.isNotBlank(res)) {return res;}res = super.maxLength();if (StringUtils.isNotBlank(res)) {return res;}res = super.minLength();if (StringUtils.isNotBlank(res)) {return res;}//最小值校验res = super.isMinInt();if (StringUtils.isNotBlank(res)) {return res;}res = super.pattern();if (StringUtils.isNotBlank(res)) {return res;}res = super.isLike();if (StringUtils.isNotBlank(res)) {return res;}res = super.enumVal();if (StringUtils.isNotBlank(res)) {return res;}//最大值校验res = super.isMaxInt();if (StringUtils.isNotBlank(res)) {return res;}res = super.range();return res;}
}
public class ListArgumentsVerify extends AbstractArgumentsVerify {public ListArgumentsVerify(List<Object> val, PropertiesVerify propertiesVerify, Class<? extends Default> groups) {super(val, propertiesVerify, groups);}@Overridepublic String check() {//校验List类型参数String res = super.minLength();if (StringUtils.isNotBlank(res)) {return res;}res = super.maxLength();if (StringUtils.isNotBlank(res)) {return res;}if (CollectionUtils.isNotEmpty((Collection) super.inputData)) {for (Object obj : (Collection) super.inputData) {res = ArgumentsCheckUtil.check(obj, super.groups);if (StringUtils.isNotBlank(res)) {break;}}}return res;}
}
public class LongArgumentsVerify extends AbstractArgumentsVerify {public LongArgumentsVerify(Long val, PropertiesVerify propertiesVerify, Class<? extends Default> groups) {super(val, propertiesVerify, groups);}@Overridepublic String check() {String res = super.maxLength();if (StringUtils.isNotBlank(res)) {return res;}res = super.minLength();if (StringUtils.isNotBlank(res)) {return res;}res = super.isLike();if (StringUtils.isNotBlank(res)) {return res;}//最小值校验res = super.isMinLong();if (StringUtils.isNotBlank(res)) {return res;}//最大值校验res = super.isMaxLong();if (StringUtils.isNotBlank(res)) {return res;}res = super.range();return res;}
}
public class StringArgumentsVerify extends AbstractArgumentsVerify {public StringArgumentsVerify(String val, PropertiesVerify propertiesVerify, Class<? extends Default> groups) {super(val, propertiesVerify, groups);}@Overridepublic String check() {//包含校验if(StringUtils.isBlank((String)inputData)){return "";}String res = super.isContain();if (StringUtils.isNotBlank(res)) {return res;}res = super.isLike();if (StringUtils.isNotBlank(res)) {return res;}res = super.type();if (StringUtils.isNotBlank(res)) {return res;}res = super.pattern();if (StringUtils.isNotBlank(res)) {return res;}res = super.enumVal();if (StringUtils.isNotBlank(res)) {return res;}res = super.maxLength();if (StringUtils.isNotBlank(res)) {return res;}res = super.isFormatDate();if (StringUtils.isNotBlank(res)) {return res;}res = super.minLength();return res;}
}
5.使用到的枚举
/*** 时间检验分割线* @author 106979*/
public enum DateDivisionEnum {NONE("无"),FUTURE("将来时间"),PAST("过去时间");public String name;DateDivisionEnum(String name) {this.name = name;}
}
6.工具类:
public class ArgumentsCheckUtil {/*** 参数验证* @param cla 需要校验的对象* @return 校验异常消息*/public static String check(Object cla) {return check(cla, null);}/*** 参数验证* @param cla 需要校验的对象* @param groups 分组* @return 校验异常消息*/public static String check(Object cla, Class<? extends Default> groups) {if (cla != null) {EnableArgumentsCheck enableArgumentsCheck = cla.getClass().getAnnotation(EnableArgumentsCheck.class);if (enableArgumentsCheck == null || !enableArgumentsCheck.enable()) {return StringUtils.EMPTY;}Field[] fields = cla.getClass().getDeclaredFields();for (Field f : fields) {PropertiesVerify propertiesVerify = f.getAnnotation(PropertiesVerify.class);if (propertiesVerify == null) {continue;}f.setAccessible(true);Object value = null;try {value = getFieldValue(f.getName(), cla);} catch (Exception e) {throw new RuntimeException(String.format("获取字段:%s值异常", f.getName()));}//分组判断if (isMatchGroups(groups, propertiesVerify)) {continue;}//判断是否为空if (value == null && propertiesVerify.isNotNull()) {return String.format("参数:%s不能为空", propertiesVerify.name());}if(Objects.isNull(value)){continue;}String res;if (value instanceof String) {//校验字符串参数res = new StringArgumentsVerify((String) value, propertiesVerify, groups).check();} else if (value instanceof Long) {//检验Long类型参数res = new LongArgumentsVerify(Long.parseLong(value.toString()), propertiesVerify, groups).check();} else if (value instanceof Integer) {//校验Integer类型参数res = new IntegerArgumentsVerify(Integer.parseInt(value.toString()), propertiesVerify, groups).check();} else if (value instanceof Double) {//校验Double类型参数res = new DoubleArgumentsVerify(formatDouble((Double) value), propertiesVerify, groups).check();} else if (value instanceof Date) {//校验Date类型参数res = new DateArgumentsVerify((Date) value, propertiesVerify, groups).check();} else if (value instanceof List) {//list判断res = new ListArgumentsVerify((List<Object>) value, propertiesVerify, groups).check();} else if (value.getClass().isArray()) {//校验数组类型参数res = new ListArgumentsVerify(Arrays.asList((Object[]) value), propertiesVerify, groups).check();} else {return check(value);}if (StringUtils.isNotBlank(res)) {return res;}}}return StringUtils.EMPTY;}private static String formatDouble(Double d) {NumberFormat nf = NumberFormat.getInstance();//设置保留多少位小数nf.setMaximumFractionDigits(20);// 取消科学计数法nf.setGroupingUsed(false);//返回结果return nf.format(d);}private static boolean isMatchGroups(Class<? extends Default> groups, PropertiesVerify propertiesVerify) {if (groups != null) {Class<? extends Default>[] fieldGroups = propertiesVerify.groups();if (fieldGroups != null) {boolean isMatchGroup = false;for (Class c : fieldGroups) {if (c == groups) {isMatchGroup = true;break;}}if(!isMatchGroup){return true;}}}return false;}/*** @param fieldName 属性名称* @param o 属性对象* @return Object* @throws IllegalAccessException* @throws IllegalArgumentException* @throws InvocationTargetException* @throws NoSuchMethodException* @throws SecurityException* @Title: getFieldValue* @Description: 获取对象属性的值* @author ZENGCHONG*/public static Object getFieldValue(String fieldName, Object o) throws Exception {String firstLetter = fieldName.substring(0, 1).toUpperCase();String getter = "get" + firstLetter + fieldName.substring(1);Method method = o.getClass().getMethod(getter);Object value = method.invoke(o);return value;}
}
7.实体类(用于测试)
@Data
@EnableArgumentsCheck()
public class PrepareOrderRouteReq {/*** */@PropertiesVerify(name = "下单编码", isNotNull = true, minLength = 1, maxLength = 200)private String orderNumber;private String plateNumber;}
8.测试类
public class processTest {public static void main(String[] args) {PrepareOrderRouteReq req = new PrepareOrderRouteReq();req.setOrderNumber("{\n" +"\t\"actualWeight\": 88.0,\n" +"\t\"addWorkday\": 1.0,\n" +"\t\"autoDistributionFlag\": 10,\n" +"\t\"billFlag\": \"20\",\n" +"\t\"contraband\": 20,\n" +"\t\"createTime\": 1725865110020,\n" +"\t\"customerServiceId\": \"12163\",\n" +"\t\"customerServiceName\": \"客服中台中心\",\n" +"\t\"deliveryAddWorkday\": 0.0,\n" +"\t\"deliveryAging\": 1726037880000,\n" +"\t\"freightAmount\": 0.0,\n" +"\t\"goodsCategory\": \"\",\n" +"\t\"goodsLabel\": \"40\",\n" +"\t\"goodsSize\": \"\",\n" +"\t\"goodsType\": \"托寄物青0瓜\",\n" +"\t\"id\": \"155872956798825217\",\n" +"\t\"invalidFlag\": 20,\n" +"\t\"linePlusAddDay\": 0.0,\n" +"\t\"newCustomerFlag\": 20,\n" +"\t\"nightOvertime\": \"10\",\n" +"\t\"orderTime\": 1725865100000,\n" +"\t\"orderUploadMode\": \"20\",\n" +"\t\"pickupAddWorkday\": 1.0,\n" +"\t\"pickupTime\": \"2024-09-09 14:58:00\",\n" +"\t\"predictWeight\": 50.0,\n" +"\t\"receiveAddress\": \"上海市闵行区江川路690号上海电机学院(闵行校区)\",\n" +"\t\"receiveAreaCode\": \"10\",\n" +"\t\"receiveCustomerCode\": \"02106680981\",\n" +"\t\"receiveCustomerId\": \"8898771\",\n" +"\t\"receiveCustomerName\": \"上海每林\",\n" +"\t\"receiveMobile\": \"B2F64BDFB2A77B477C35867C00B7FDC5\",\n" +"\t\"receiveNodeId\": \"3997\",\n" +"\t\"receiveNodeName\": \"闵行点部\",\n" +"\t\"receivePhone\": \"0A967228DE1933E879C7F46FF845C8E8\",\n" +"\t\"receiveRegionCode\": \"021\",\n" +"\t\"reportNodeId\": \"5141\",\n" +"\t\"reportNodeName\": \"松岗新桥点部\",\n" +"\t\"requestFromAirport\": \"温州\",\n" +"\t\"requestToAirport\": \"上海虹桥\",\n" +"\t\"safetyCheck\": \"20\",\n" +"\t\"saleProjectCode\": \"XM-202204-0049\",\n" +"\t\"sendAddress\": \"广东省深圳市宝安区松岗街道松岗中心幼儿园2号1\",\n" +"\t\"sendAreaCode\": \"20\",\n" +"\t\"sendCustomerCode\": \"075508105755\",\n" +"\t\"sendCustomerId\": \"2207729\",\n" +"\t\"sendCustomerName\": \"深圳三四川科技\",\n" +"\t\"sendMobile\": \"C19C06D177CF75380C3754D5FABC24E8\",\n" +"\t\"sendNodeId\": \"5141\",\n" +"\t\"sendNodeName\": \"松岗新桥点部\",\n" +"\t\"sendRegionCode\": \"0755\",\n" +"\t\"serviceMode\": \"20\",\n" +"\t\"specialCode\": \"\",\n" +"\t\"transferFlag\": \"20\",\n" +"\t\"updateTime\": 1725865112166,\n" +"\t\"volumeWeight\": 0.0,\n" +"\t\"waybillCount\": 10,\n" +"\t\"waybillNo\": \"KY5000249115370\",\n" +"\t\"waybillRemark\": \"运单备注米123兰含电池\",\n" +"\t\"waybillSource\": \"240\",\n" +"\t\"waybillStatus\": \"70\",\n" +"\t\"waybillType\": \"2010\",\n" +"\t\"woodenFrameFlag\": \"\"\n" +"}");String check = ArgumentsCheckUtil.check(req);System.out.println(check);}
}
结果:
使用到的jar包
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.16.18</version></dependency><dependency><groupId>javax.validation</groupId><artifactId>validation-api</artifactId><version>2.0.1.Final</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.12.0</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-collections4</artifactId><version>4.4</version></dependency>
相关文章:

java 自定义注解校验实体类属性
直接上代码 1.是否启用参数校验注解 Target({ElementType.TYPE}) Retention(RetentionPolicy.RUNTIME) Documented public interface EnableArgumentsCheck {/*** 是否启用*/boolean enable() default true;} 2.参数校验自定义注解 /*** 参数校验自定义注解* 属性定义&#…...

光伏并网发电系统中电能质量监测与优化技术探讨
0引言 随着清洁能源技术的持续进步与广泛应用,光伏并网发电系统亦逐步崭露头角。作为一种关键的电力供应方式,其受到了广泛的关注。然而,由于天气等外部条件的影响,光伏发电系统面临若干挑战。电能质量问题,诸如电压波…...

网页解析的那些事
Vue 方面 模板语法理解 熟悉 Vue 的模板语法,包括插值表达式(如{{ message }})、指令(如v-if、v-for、v-bind等)。理解这些语法元素如何将数据与 DOM 元素进行绑定和交互。例如,v-for指令用于循环渲染列表数…...

从文字到世界:2024外语阅读大赛报名开启,赛氪网全程护航
中国外文局CATTI项目管理中心与中国外文界联合宣布,将举办2024年外语阅读大赛,旨在激发外语学习兴趣,选拔并培养优秀的语言应用人才,同时向世界展示和传播具有中国特色的优秀文化。此次大赛旨在激发外语学习兴趣,选拔优…...

微信小程序知识点(二)
1.下拉刷新事件 如果页面需要下拉刷新功能,则在页面对应的json配置文件中,将enablePullDownRefresh配置设置为true,如下 {"usingComponents": {},"enablePullDownRefresh": true } 2.上拉触底事件 在很多时候&#x…...

Springcould -第一个Eureka应用 --- day02
标题 Eureka工作原理Spring Cloud框架下的服务发现Eureka包含两个组件,分别是:Eureka Server与Eureka Client。Eureka Server:Eureka Client: 搭建Eureka Server步骤:步骤1:创建项目,引入依赖步…...

RedissonClient 分布式队列工具类
注意:轻量级队列可以使用工具类,重量级数据量 请使用 MQ 本文章基于redis使用redisson客户端实现轻量级队列,以及代码、执行结果演示 一、常见队列了解 普通队列:先进先出(FIFO),只能在一端添…...

protobuf使用
我下载的是 protobuf-27.4 以下使用vs2022 根据readme,执行如下命令 "C:\Program Files\CMake\bin\cmake.exe" -G "Visual Studio 17 2022" -DCMAKE_INSTALL_PREFIXC:\Users\x\Downloads\install C:\Users\x\Downloads\protobuf-27.4 -D…...

【微处理器系统原理与应用设计第十二讲】通用定时器设计二之PWM波实现呼吸灯的功能
一、基础知识 1、寄存器的配置 (1)GPIOX_AFRL:GPIO复用功能低位寄存器 GPIOX_AFRH:GPIO复用功能高位寄存器 (2)配置PA5 GPIOA->MODER(端口模式寄存器),10为复用功…...

2025秋招NLP算法面试真题(十九)-大模型分布式训练题目
目录: 理论篇 1.1 训练大语言模型存在问题? 1.2 什么是点对点通信? 1.3 什么是集体通信? 1.4 什么是数据并行? 1.5 数据并行如何提升效率? 1.6 什么是流水线并行? 1.7 什么是张量并行 (intra-layer)? 1.8 数据并行 vs 张量并行 vs 流水线并行? 1.9 什么是3D并行? 1.1…...

线程池的应用
1.线程的执行机制 线程分为用户线程 和 内核线程 内核线程就是系统级别的线程,与cpu逻辑处理器数量对应的 用户线程就是使用java代码创建的Thread对象 用户线程必须与内核线程关联(映射),才能执行任务 当用户线程多于内核线程时…...

OPenCV结构分析与形状描述符(5)查找图像中的连通组件的函数connectedComponents()的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 connectedComponents 函数计算布尔图像的连通组件标签图像。 该函数接受一个具有4或8连通性的二值图像,并返回 N,即标签…...

HCIA--实验十三:VLAN间通信子接口实验/双单臂路由实验
一、实验内容 1.需求/要求: 将两个单臂路由通过两台交换机连接起来,成为双臂路由,并探讨这么做的原因。实现全网通,让任何一台主机之间都可以通信。 二、实验过程 1.拓扑图: 2.步骤: 1.给PC配置ip地址…...

AIStarter市场指南:项目分享与框架优化【AI绘画、写作、对话、办公、设计】
随着人工智能技术的飞速发展,越来越多的开发者和爱好者希望能够将自己的创意和项目分享给更多人。AIStarter作为一个专注于AI领域的平台,正致力于打造一个开放的应用市场,让创作者能够轻松分享他们的项目,同时也方便其他用户下载和…...

机器学习第8章 集成学习
目录 个体与集成BoostingBagging与随机森林Bagging随机森林 结合策略平均法投票法学习法 个体与集成 定义:集成学习,也叫多分类器系统、基于委员会的学习等,它是一种通过结合多个学习器来构建一个更强大的学习器的技术。如下图所示 在这里&a…...

京东鸿蒙上线前瞻——使用 Taro 打造高性能原生应用
背景 2024 年 1 月,京东正式启动鸿蒙原生应用开发,基于 HarmonyOS NEXT 的全场景、原生智能、原生安全等优势特性,为消费者打造更流畅、更智能、更安全的购物体验。同年 6 月,京东鸿蒙原生应用尝鲜版上架华为应用市场,…...

day2 QT
作业 2> 在登录界面的登录取消按钮进行以下设置: 使用手动连接,将登录框中的取消按钮使用第2种方式的连接到自定义的槽函数中,在自定义的槽函数中调用关闭函数 将登录按钮使用qt4版本的连接到自定义的槽函数中,在槽函数中判断…...

JS_函数声明
JS中的方法,多称为函数,函数的声明语法和JAVA中有较大区别 函数说明 函数没有权限控制符不用声明函数的返回值类型,需要返回在函数体中直接return即可,也无需void关键字参数列表中,无需数据类型调用函数时,实参和形参的个数可以不一致声明函数时需要用function关键字函数没有…...

快速排序+归并排序代码回顾
快速排序与归并排序简介: quick_sort为快速排序,merge_sort为归并排序,两者基于分治的思想; 快速排序,简称快排,它以原来数组中的一个值(我们记为x)作为界限,将比它小…...

DBC中一种特殊的特殊的Signal—多路复用Signal
前言: DBC设计中一般设计Signal时其实存在三种类型,如下图所示: **1)步骤1,鼠标单击展开Message,选中底下的Signal **2)步骤2,弹出dialog中选择 map signal **3)得到…...

前端基础面试题·第三篇——JavaScript(其三)
1.字符串 (1) 常用方法 1.charAt(index) 返回指定位置的字符,若没找到,则返回空2.charCodeAt(index) 返回指定位置的unicode字符编码,若没找到,则返回空 3.String.concat(str1,str2) 连接多个字符串,并返回新字符串4.String.fromCharCode(co…...

MacBook真的不能打游戏吗?Mac打游戏会损坏电脑吗?苹果电脑怎么玩游戏
MacBook从来都是高端的代名词,超强的性能搭配顶尖的系统,不光处理大型文件时举重若轻,长期使用也不会有明显卡顿。但很多人在需要MacBook一流的生产力同时,也希望能在空闲时体验游戏的乐趣。在大多人的印象里,Mac电脑对…...

安卓逆向(之)真机root(红米手机)
概览: 1, 手机解锁 2, 下载官方系统包,推荐线刷包,取出镜像文件 3, magisk工具修补 官方系统包 4, adb:命令对手机刷 root 5, 完成 6, 小米手机解锁 点击 小米手机解锁OEM官方教程 记得数据线连接手机电脑 工具下载 点击 下载adb(电脑操作…...

关于转行网络安全的一些建议
在当前就业形势下,不少朋友面临转行的困境。网络安全作为一个热门领域,自然也吸引了许多人的目光。本文将就转行网络安全这一话题,提供一些切实可行的建议。 网络安全行业概况 网络安全涵盖了从基础的脚本编写到高级的漏洞研究等多个层面。该…...

(六十五)第 10 章 内部排序(希尔排序)
示例代码 shellSort.h // // 希尔排序实现头文件#ifndef SHELL_SORT_H #define SHELL_SORT_H#include "errorRecord.h"#define NUM 10 #define MAX_SIZE 20#define EQUAL(a, b) ((a) == (b)) #define LESS_THAN(a, b) ((a) < (b)) #define LESS_OR_EQUAL(a, b) ((…...

802.11 中 scrambler的matlab仿真
802.11a和802.11n中的scrambler仿真不可以直接用matlab中的comm.Scrambler函数。因为这个函数实现的是multiplicative scrambling,而802.11a和802.11n中的scrambler使用的是additive scrambling。additive scrambling使用异或操作进行扰码,multiplicativ…...

centos 服务器 多网卡 ip 地址 设置
centos 服务器 多网卡 ip 地址 设置 https://blog.csdn.net/xh_w20/article/details/141574357 cd /etc/sysconfig/network-scripts/ sudo systemctl status network ● network.service - LSB: Bring up/down networkingLoaded: loaded (/etc/rc.d/init.d/network; bad; v…...

什么是大数据、有什么用以及学习内容
目录 1.什么是大数据? 2.大数据有什么用? 2.1商业与营销: 2.2医疗与健康: 2.3金融服务: 2.4政府与公共服务: 2.5交通与物流: 2.6教育与个性化学习: 3.学习大数据需要学习哪…...

ZBrush与Blender雕刻功能哪个更好些?
选择正确的3D软件首先会让你的创作过程更加轻松,尤其是在动画或大片电影制作方面。不同的软件提供不同的功能,并倾向于专注于特定领域,如绘画、动画或雕刻。如果你选择了适合你风格和目标的软件,你可以创作出极具创意的作品。 在…...

软件工程技术专业软件开发综合实训室解决方案
一、行业背景与前景分析 1.1 软件工程技术专业就业前景 近年来,中国的软件行业取得了显著的成就,即便在全球经济受到新冠疫情冲击的情况下,仍保持了强劲的增长势头。据工业和信息化部发布的数据,2021年我国软件和信息技术服务业…...