1. 程式人生 > >通過自定義spring invalidator註解校驗資料合法性

通過自定義spring invalidator註解校驗資料合法性

在專案中經常會對使用者輸入的資料,或者外部匯入到系統的資料做合法性檢查。在spring boot框架的微服務中可以使用invalidator註解對資料做合法性,安全性校驗。下面給一個樣例說明如何自定義註解實現校驗邏輯。

一、定義校驗屬性字串長度的註解

package com.elon.springbootdemo.manager.invalidator;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;

/**
 * 屬性欄位長度校驗註解定義。
 * 
 * @author elon
 * @version 2018年9月19日
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = FieldLengthInvalidatorImpl.class)
@Documented
public @interface FieldLengthInvalidator {

    // 欄位支援的最大長度(字元數)
    int maxLength() default 50;

    // 校驗失敗後返回的錯誤資訊
    String message() default "";

    // 分組
    Class<?>[] groups() default {};

    // 負載
    Class<? extends Payload>[] payload() default {};
}

在定義註解時可宣告變數用於輔助校驗。上面的註解中定義了maxLength變數用於指定最大長度限制。變數可以設定預設值,使用註解時不傳引數,變數就使用預設值。

二、實現校驗邏輯,校驗失敗後返回錯誤提示

package com.elon.springbootdemo.manager.invalidator;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

/**
 * 欄位長度校驗實現類。
 * 
 * @author elon
 * @version 2018年9月19日
 */
public class FieldLengthInvalidatorImpl implements ConstraintValidator<FieldLengthInvalidator, String> {

    private int maxLength = 0;

    @Override
    public void initialize(FieldLengthInvalidator invalidator) {
        maxLength = invalidator.maxLength();
    }

    @Override
    public boolean isValid(String fieldValue, ConstraintValidatorContext context) {

        if (fieldValue.length() > maxLength) {
            context.disableDefaultConstraintViolation();
            context.buildConstraintViolationWithTemplate("物件屬性長度超過限制。").addConstraintViolation();

            // 校驗失敗返回false。返回true上游收集不到錯誤資訊。
            return false;
        }

        return true;
    }
}

三、在模型欄位屬性上增加校驗的註解

public class User
{
	private int userId = -1;

	@FieldLengthInvalidator(maxLength=10)
	private String name = "";

}

四、提供統一的校驗方法

package com.elon.springbootdemo.manager;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

/**
 * 有效性校驗管理類。對外提供統一的校驗呼叫介面。
 * @author elon
 * @version 2018年9月19日
 */
public class InvalidatorMgr {
    private InvalidatorMgr() {
        
    }
    
    /**
     * 獲取單例物件。
     * 
     * @return 單例物件
     */
    public static InvalidatorMgr instance() {
        return InvalidatorMgrBuilder.instance;
    }
    
    /**
     * 校驗模型所有屬性的有效性。
     * 
     * @param model 待校驗模型
     * @return 錯誤資訊列表
     */
    public <T> List<String> validate(T model) {
        
        ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
        Validator validator = validatorFactory.getValidator();
        Set<ConstraintViolation<T>> resultSet = validator.validate(model);
        
        List<String> messageList = new ArrayList<>();
        resultSet.forEach((r)->messageList.add(r.getMessage()));
        
        return messageList;
    }
    
    /**
     * 單例構建器。
     * @author elon
     * @version 2018年9月19日
     */
    private static class InvalidatorMgrBuilder{
        private static InvalidatorMgr instance = new InvalidatorMgr();
    }
}

五、業務層呼叫校驗方法

        User user = new User();
        user.setName("ahskahskhqlwjqlwqlwhqlhwlqjwlqhwlhqwhqlwjjqlwl");
        List<String> messageList = InvalidatorMgr.instance().validate(user);
        System.out.println(messageList);

invalidator註解主要用於實現長度,範圍,非法字元等通用的規則校驗。不適合用於做業務邏輯的校驗,特定的業務校驗寫在業務層。