想必大家在SpringMVC项目做请求参数验证的时候,都会遇到一个问题,就是如何验证枚举?方法无外乎以下几种:
方法1:直接用枚举定义字段类型
方法2:用Integer类型定义字段类型,然后在代码里面验证(即:放弃使用javax.validation.validator去统一验证)
缺点:
方法1的缺点:当枚举的value值不是从0开始有序设置时,就会出现问题,因为虽然spring支持枚举类型字段的解析,但其实它是根据枚举的index,也就是索引来解析的。并且直接在请求字段上使用枚举,这个不太规范,并且在Mapping到po或者vo的时候会存在转值需要,即,得通过枚举成员去拿value值设置给PO。
方法2的缺点:得写多余的if...else来判断,远远没有validator的简洁。代码结构看上去就比较糟糕。
那么,难道就没有解决办法了吗?当然不是,在程序员的世界,没有不能解决的问题,只有等待解决的问题。解决方案如下:
目标:
即使用基础类型作为字段类型,又可以使用枚举来约束验证字段。
原料:
1.枚举一枚
2.自定义annotation一枚
3.自定义Validator一枚
步骤:
Step 1:自定义枚举
Step 2:首先需要自定义一个annotation来标记你的验证字段,因为Validator框架里面的基础annotation已经不够用。
Step 3:自定义一个Validator(继承ConstraintValidator),并将Step2中annotation类型给到ConstraintValidator的泛型列表,相当于做了一个绑定。然后implement ConstraintValidator的两个方法,在isValid方法里面用Step1的枚举验证参数。
Step 4:使用我们的老朋友Validator,尽情的验证吧!
不多说,直接上干货,JAVACODE:
/** * 请求参数model * Created by TonyZeng on 2017/3/25. */public class AddQuestionRqVo { /** * 性别 */ @CheckSex private Integer sex; }
/** * 性别 * Created by TonyZeng on 2017/3/29. */public enum SexType { Free(0, "不限"), Male(1, "男"), Female(2, "女"); private int id; private String chinese; // 构造方法 SexType(int id, String chinese) { this.id = id; this.chinese = chinese; } public static SexType valueOf(int value) { switch (value) { case 0: return SexType.Free; case 1: return SexType.Male; case 2: return SexType.Female; default: return null; } } public static SexType textOf(String text) { switch (text) { case "不限": return SexType.Free; case "男": return SexType.Male; case "女": return SexType.Female; default: return null; } } //此处省略get&set方法}
/** * 用枚举指定参数 * Created by TonyZeng on 2017/4/24. */@Target({ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})@Retention(RetentionPolicy.RUNTIME)@Constraint(validatedBy = CheckSexValidator.class)@Documentedpublic @interface CheckSex { /** * 用来定义默认得消息模版, 当这个约束条件被验证失败的时候,通过此属性来输出错误信息. * @return */ String message() default "请提供正确的性别(ID)"; /** * 用于指定这个约束条件属于哪(些)个校验组 * @return */ Class<?>[] groups() default {}; /** * Bean Validation API 的使用者可以通过此属性来给约束条件指定严重级别. 这个属性并不被API自身所使用. * @return */ Class<? extends Payload>[] payload() default {};}
/** * 自定义性别Validator * Created by TonyZeng on 2017/4/25. */public class CheckSexValidator implements ConstraintValidator<CheckSex, Integer> { @Override public void initialize(CheckSex constraintAnnotation) { } @Override public boolean isValid(Integer value, ConstraintValidatorContext context) { return SexType.valueOf(value) != null; }}
/** * Created by TonyZeng on 2016/9/6. */public class ValidateUtil<T> { private static ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory(); private static Validator validator = validatorFactory.getValidator(); /** * 验证请求参数 * * @param model * @return null 则说明验证成功,如果非null 则说明验证失败 */ public String validate(T model) { model.getClass().getAnnotatedInterfaces(); Set<ConstraintViolation<T>> violations = validator.validate(model); if (violations.size() > 0) { String msg = ""; for (ConstraintViolation<T> violation : violations) { msg += violation.getMessage() + "<br>"; } return msg; } return null; }}
@Overridepublic BaseDto addQuestion(AddQuestionRqVo requestVo) { String validateResult = new ValidateUtil<AddQuestionRqVo>().validate(requestVo); if (validateResult != null) { return new BaseDto(-1, validateResult); } }