SpringBoot Stepping Diary — ошибка, вызванная непустой проверкой

задняя часть

Сначала дайте мини версию проекта

@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 — это класс данных, и в нем есть список для хранения String. Бизнес-логика состоит в том, чтобы преобразовать String в классе User из нижнего регистра в верхний и вернуть его на стойку регистрации. Это очень просто.

В предыдущем бизнес-коде только непустые строки, длина которых больше 1, могут пройти проверку.

Но надежно ли это? Я тоже сначала так думал, пока однажды на стойке регистрации не прислали такой объект

"strings":["abc",null,"def"]

Затем я сообщил об исключении NullPoint здесь. Так вот это место тоже пропустило проверку, то есть объекты в коллекции не могут быть пустыми!

Что делать, если объекты в коллекции не могут быть пустыми? Если вы не хотите помещать эту часть проверки в бизнес-код, есть два решения:

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;

В этом случае список, который мы получаем, представляет собой список с отфильтрованными нулевыми объектами. В это время для всего набора выполняется непустая проверка и проверка длины, чтобы убедиться в отсутствии проблем.

Но если быть разумным, если на стойке регистрации передаются такие данные, у большинства из них проблемы с собственной логикой, и нам не особенно подходит такая проблема. Таким образом, они должны пройти проверку, чтобы сказать им, что не так.

пользовательский валидатор

В springboot я не нашел аннотации, которая может проверить, что все объекты в коллекции не пусты. Так что похоже, что я должен реализовать один сам.

@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 может получить информацию о проверке, чтобы решить, следует ли генерировать исключение.

Следует отметить, что загрузка валидатора завершается фреймворком spring, то есть валидатор может использовать классы в контейнере spring. Эта функция также полезна.


Назад к содержанию