SpringBoot踩坑日記-一個非空校驗引起的bug

首先先給出mini版項目

@Data
public class User {
    @NotNull
    @Size(min = 1)
    private List<String> strings;
}

    @RequestMapping("")
    public User hello(@Validated @RequestBody User user) {
        user.setStrings(user.getStrings()
                            .stream()
                            .map(String::toUpperCase)
                            .collect(Collectors.toList()));
        return user;
    }
複製代碼

User類爲數據類,裏面有一個list存放String,業務邏輯就是將User類中的String由小寫轉爲大寫,返回給前臺,很簡單吧。spring

以前的業務代碼裏只有strings不爲空,且長度大於1就能夠經過校驗了。json

可是這樣是不是萬無一失呢?一開始我也是這麼認爲的,直到有一天前臺發來了這麼一個對象springboot

"strings":["abc",null,"def"]
複製代碼

而後我這兒報了個NullPoint異常。因此這個地方還漏了一個校驗,就是集合裏的對象,也都不能爲空!bash

集合裏的對象不能爲空該怎麼辦呢?若是不想把這部分校驗放在業務代碼裏的話,解決思路有兩個:app

1.在轉換的時候,過濾掉null。
2.在校驗的時候,校驗集合裏的對象爲非空。
複製代碼

1.在轉換時候過濾

首先看看若是轉換的時候須要過濾該怎麼辦?直接上代碼:框架

@Configuration
public class GlobalConfiguration {

    @Bean
    //向spring容器中注入fastjson消息轉換器(我比較喜歡用這個,大家隨意)
    public HttpMessageConverters message(){
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
        FastJsonHttpMessageConverter fastJson = new FastJsonHttpMessageConverter();
        fastJson.setFastJsonConfig(fastJsonConfig);
        return new HttpMessageConverters(fastJson);
    }

}

//自定義fastjson反序列化組件
public class ListNotNullDeserializer implements ObjectDeserializer {

    @Override
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
        if (parser.lexer.token() == JSONToken.NULL) {
            parser.lexer.nextToken(JSONToken.COMMA);
            return null;
        }

        Collection list = TypeUtils.createCollection(type);

        Type itemType = TypeUtils.getCollectionItemType(type);
        parser.parseArray(itemType, list, fieldName);
        //在返回的時候,過濾掉集合裏的null對象
        return (T) list.stream().filter(Objects::nonNull).collect(Collectors.toList());
    }

    @Override
    public int getFastMatchToken() {
        return 0;
    }
}

    //在須要過濾的集合上面添加相應的轉換器標誌
    @JSONField(deserializeUsing = ListNotNullDeserializer.class)
    private List<String> strings;
複製代碼

這樣的話,咱們拿到的list就是已通過濾掉null對象的list了。這個時候在對整個集合進行非空校驗和長度校驗,就能夠確保沒問題。ide

可是講道理的話,前臺傳這種數據過來,多半是他們本身的邏輯出現了問題,咱們就這樣把問題吃了也不是特別合適。因此得經過校驗告訴他們哪裏有問題。post

自定義校驗器

在springboot中,我並無找到能夠校驗集合裏全部對象爲非空的註解。因此看來得本身實現一個。ui

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
@Inherited
@Documented
@Constraint(validatedBy = NotNullEleValidator.class)
public @interface NotNullElement {
    String message() default " 集合中有元素爲null !";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

public class NotNullEleValidator implements ConstraintValidator<NotNullElement, List<?>> {
    @Override
    public boolean isValid(List<?> value, ConstraintValidatorContext context) {
        if (value == null) {
            return true;
        }

        for (Object o : value) {
            if (o == null) {
                return false;
            }
        }

        return true;
    }
}
複製代碼

自定義校驗器規則也很簡單校驗經過返回true,不經過返回false,這樣的話springboot就能夠獲取到校驗信息,來決定是否拋出異常。spa

須要注意的是,校驗器的加載由spring框架完成,也就是校驗器能夠使用spring容器中的類。這個功能也頗有用。


返回目錄

相關文章
相關標籤/搜索