天天看點

java:自定義注解,校驗枚舉類

作用:校驗請求參數中,有對應枚舉類類型的字段,判斷取值是否為枚舉類内的值,以及是否可以為空。

借鑒其他大神部落格,原文在枚舉類中定義校驗方法,本文利用反射去除了枚舉類中校驗方法,實作注解與枚舉類解耦。原文部落格位址找不到了實在抱歉。如有錯誤歡迎指正聯系。

僅作自己記錄

一:定義注解

package com.example.demo.anno;

import lombok.SneakyThrows;

import java.lang.annotation.*;
import java.lang.reflect.Method;
import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.Payload;


@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = ValidEnum.Validator.class)
public @interface ValidEnum {
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};


    Class<? extends Enum<?>> enumClass(); // 枚舉類
    boolean allowNull() default false; // 是否允許為空
    String message() default "{enum.value.invalid}"; // 錯誤資訊


    class Validator implements ConstraintValidator<ValidEnum, Object> {
        private Class<? extends Enum<?>> enumClass;
        private boolean allowNull;
        @Override
        public void initialize(ValidEnum enumValue) {
            enumClass = enumValue.enumClass();
            allowNull = enumValue.allowNull();
        }

        @SneakyThrows
        @Override
        public boolean isValid(Object value, ConstraintValidatorContext constraintValidatorContext) {
            // 是否允許為null 或者 “”
            if (value == null || value.equals("")) {
                return allowNull;
            }
            // 參照枚舉類為空說明不校驗直接傳回true
            if (enumClass == null ) {
                return Boolean.TRUE;
            }

            //校驗是否為枚舉類中的值
            Boolean flag = false;
            Enum<?>[] enumConstants = enumClass.getEnumConstants();
            for (Enum<?> enumConstant : enumConstants) {
                Method method = enumConstant.getClass().getMethod("status");
                Class<?> returnType = method.getReturnType();
                String s = value.getClass().toString();
                // 如果方法傳回值不同,立即傳回錯誤
                if (!returnType.toString().equals(s)){
                    return false;
                }
                // 如果有值相等則傳回true
                Object status = method.invoke(enumConstant, null);
                if (status.equals(value)){
                    flag = true;
                    return flag;
                }
            }
            return flag;
        }

    }

}

           

二:枚舉類

package com.example.demo.anno;

public enum FundStatusEnum {


    SUBMITTED("Submitted", "已送出"),
    SETTLED("Settled", "已結算"),
    PENDING_SETTLEMENT("PS", "待結算"),
    PENDING_TOPUP("PT", "待充值"),
    CANCELLED("Cancelled", "已取消");

    private final String status;

    private final String description;

    FundStatusEnum(String status, String description) {
        this.status = status;
        this.description = description;
    }

    public String status() {
        return status;
    }

    public String description() {
        return description;
    }
    
}

           

三:請求體使用注解

@ValidEnum(enumClass = FundStatusEnum.class,allowNull = true,message = "不在枚舉類範圍内")
    private String fundStatus;
           

四:controller層接口

package com.example.demo.anno;

import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;

@RestController
public class TestController {

    @RequestMapping(value = "/record")
    public String update(@Valid @RequestBody UpdateTxnReqVO updateTxnReqVO, BindingResult bindingResult) {
        // 參數不符合校驗規則,則傳回定義錯誤資訊
        if (bindingResult.hasErrors()) {
            return bindingResult.getAllErrors().get(0).getDefaultMessage();
        }
        return "OK";
    }

}