想必大家在做参数验证的时候,都会遇到一个问题,就是如何验证枚举? 自定义annotation 自定义Validator

想必大家在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);    } }

来自为知笔记(Wiz)

时间: 2024-08-27 11:11:34

想必大家在做参数验证的时候,都会遇到一个问题,就是如何验证枚举? 自定义annotation 自定义Validator的相关文章

以函数返回值做参数时,函数调用的顺序

环境:vs2013 在下面的代码中 1 //类似于下面的代码 2 3 foo(char*,char*,char*); 4 5 char* str ="A#B#C"; 6 7 foo(strtok(str,"#"),strtok(NULL,"#"),strtok(NULL,"#")); 预计让函数foo得到("A","B","C")的参数,程序编译的时候没问题,但是运行

C++ 中数组做参数的分析

C++ 中数组做参数的分析 1.数组降价问题? "数组引用"以避免"数组降阶",数组降阶是个讨厌的事,这在C语言中是个无法解决的问题,先看一段代码,了解什么是"数组降阶" 1 #include <IOSTREAM> 2 using namespace std; 3 4 void Test( char array[20] ) 5 { 6 cout << sizeof(array) << endl; // 输出 4

Java基础-继承 利用接口做参数,写个计算器,能完成+-*/运算

38.利用接口做参数,写个计算器,能完成+-*/运算 (1)定义一个接口Compute含有一个方法int computer(int n,int m); (2)设计四个类分别实现此接口,完成+-*/运算 (3)设计一个类UseCompute,含有方法: public void useCom(Compute com, int one, int two) 此方法要求能够:1.用传递过来的对象调用computer方法完成运算 2.输出运算的结果 (4)设计一个测试类,调用UseCompute中的方法us

C++二维数组(指针)做参数

一.问题描述 使用C++编程过程中经常需要使用到二维数组,然而初级程序员在使用过程中经常会出错使程序崩溃.下面就二维指针的定义,初始化,以及二维指针做参数给出简单介绍. 1.二维数组的定义与初始化 在实际使用数组的时候往往开始不知道二维数组的行数和列数,因此程序需要根据用户输入动态定义二维数组的行和列.这里通过C++二级指针来实现,引入变量 int rowNum 行 数, int coluNum 列数, char **p 二维字符数组,这里假定二维字符数组中的字符只能为'0'和'1'. int

Linq中Lanbda表达式做参数

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Lanbda表达式做参数 { class Program { static void Main(string[] args) { int[] Array = new int[] { 3, 2, 4, 56, 6, 14, 53 }; Func<int, bool> mtDelB = delegate(in

句柄线程做参数和PostMessage的用法

当我们启动一个线程,并且要给线程函数传递的参数是窗口句柄时,我们应该这样做: HWND hHwnd = GetSafeHwnd(); HANDLE hThread; DWORd dwThreadId; hThread = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)DeviceOnLine, (LPVOID)hHwnd, 0, &dwThreadId); // DeviceOnLine是线程函数,原型static UINT DeviceOnLi

python 将中文转拼音后填充到url做参数并写入excel

闲着没事写了个小工具,将中文转拼音后填充到url做参数并写如excel 一.先看下演示,是个什么东西 二.代码 代码用到一个中文转拼音的库,库是网上下的,稍微做了下修改,已经找不原来下载的地址了,然后需要装个pywin32库,用来写excel表格的,下面看代码. #!/usr/bin/env python # coding=utf-8# Author: ca0gu0 from lib.chinese2pinyin import search from time import sleep impo

C++数组做参数

首先,看一下下面这段代码: void changearr(int a[],int n){    cout<<sizeof(a)<<endl;         // 输出4}int main(){    int a[10] = {2,78,100,88,12,55,45,0,1,2}; cout<<sizeof(a)<<endl;         // 输出40    changearr(a,10);    return 0;} 在C++中,数组名就是指向数组

0709 C语言常见误区----------二维数组做参数

总结: 1.二维数组名是指向一位数组的指针,本例中,其类型为 int (*)[4],在传递的过程中丢失了第一维的信息,因此需要将第一维的信息传递给调用函数. 关于二维数组名代表的类型,可通过下面的例子看出. 1 /************************************************************************* 2 > File Name: test_2arr.c 3 > Author:Monica 4 > Mail:[email prot