Если вы напишете валидатор параметров таким образом, вас не заставят выйти~

Java

Очень больно сталкиваться с большим количеством параметров для проверки и выбрасывать исключения или Информация о проверке, когда исключение постоянно возвращается, довольно многословна в коде, полном кода проверки if-else, сегодня мы изучим проверку параметра аннотации Spring javax.validation.


Зачем использовать валидатор

  1. javax.validationРяд аннотаций может помочь нам завершить проверку параметров, избавляя от утомительной последовательной проверки.

    В противном случае наш код выглядел бы так:

 //  http://localhost:8080/api/user/save/serial

    /**
     * 走串行校验
     *
     * @param userVO
     * @return
     */
    @PostMapping("/save/serial")
    public Object save(@RequestBody UserVO userVO) {
        String mobile = userVO.getMobile();

        //手动逐个 参数校验~ 写法
        if (StringUtils.isBlank(mobile)) {
            return RspDTO.paramFail("mobile:手机号码不能为空");
        } else if (!Pattern.matches("^[1][3,4,5,6,7,8,9][0-9]{9}$", mobile)) {
            return RspDTO.paramFail("mobile:手机号码格式不对");
        }

        //抛出自定义异常等~写法
        if (StringUtils.isBlank(userVO.getUsername())) {
            throw new BizException(Constant.PARAM_FAIL_CODE, "用户名不能为空");
        }

        // 比如写一个map返回
        if (StringUtils.isBlank(userVO.getSex())) {
            Map<String, Object> result = new HashMap<>(5);
            result.put("code", Constant.PARAM_FAIL_CODE);
            result.put("msg", "性别不能为空");
            return result;
        }
        //.........各种写法 ...
        userService.save(userVO);
        return RspDTO.success();
    }

Когда начальник увидел это, он, должно быть, сказал, что написал это после 9102, а потом его уговорили уволиться...

  1. чтоjavax.validation

JSR303 — это набор стандартов для проверки параметров JavaBean. Он определяет многие часто используемые аннотации проверки. Мы можем напрямую добавлять эти аннотации к свойствам наших JavaBeans (в эпоху программирования аннотаций), а затем при необходимости проверять их. проверки, он был включен в starter-web в SpringBoot, и вы можете ссылаться на зависимости в других проектах и ​​самостоятельно настраивать версию:

        <!--jsr 303-->
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>1.1.0.Final</version>
        </dependency>
        <!-- hibernate validator-->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.2.0.Final</version>
        </dependency>

  1. Аннотация

       1.@NotNull:不能为null,但可以为empty(""," ","   ")      
       2.@NotEmpty:不能为null,而且长度必须大于0 (" ","  ")
       3.@NotBlank:只能作用在String上,不能为null,而且调用trim()后,长度必须大于0("test")    即:必须有实际字符
    
Проверить аннотации Проверенный тип данных инструкция
@AssertFalse Boolean,boolean Подтвердите, что значение элемента аннотации является ложным
@AssertTrue Boolean,boolean Убедитесь, что значение элемента аннотации истинно.
@NotNull любой тип Убедитесь, что значение элемента аннотации не равно нулю
@Null любой тип Убедитесь, что значение элемента аннотации равно null
@Мин(значение=значение) BigDecimal, BigInteger, byte, short, int, long и т. д. любой подтип числа или CharSequence (в котором хранятся числа) Убедитесь, что значение элемента аннотации больше или равно значению, заданному параметром @Min.
@Макс (значение = значение) То же, что спросил @Min Убедитесь, что значение элемента аннотации меньше или равно значению, указанному @Max.
@DecimalMin (значение = значение) То же, что спросил @Min Убедитесь, что значение элемента аннотации больше или равно значению, указанному @DecimalMin
@DecimalMax (значение = значение) То же, что спросил @Min Убедитесь, что значение элемента аннотации меньше или равно значению, указанному @DecimalMax.
@Digits(целое=целые цифры, дробь=десятичные цифры) То же, что спросил @Min Подтвердите максимальное количество целых и десятичных знаков для значения элемента аннотации.
@Size (мин. = нижний предел, макс. = верхний предел) Строка, коллекция, карта, массив и т. д. Убедитесь, что значение элемента аннотации находится в пределах указанного интервала минимума и максимума (включительно), например длина символа, установленный размер
@Past java.util.Date, java.util.Calendar — тип даты библиотеки классов Joda Time. Убедитесь, что значение элемента аннотации (тип даты) предшествует текущему времени.
@Future То же, что и @Past запрос Убедитесь, что значение элемента аннотации (тип даты) позже текущего времени.
@NotBlank Подтип CharSequence Убедитесь, что значение элемента аннотации не пустое (не пустое, длина равна 0 после удаления первого пробела), в отличие от @NotEmpty, @NotBlank применяется только к строкам и удалит первый пробел строки при сравнении
@Length(min=нижний предел, max=верхний предел) Подтип CharSequence Убедитесь, что длина значения элемента аннотации находится в пределах минимального и максимального интервалов.
@NotEmpty Подтип CharSequence, Коллекция, Карта, Массив Убедитесь, что значение элемента аннотации не равно нулю и не пусто (длина строки не равна 0, размер коллекции не равен 0).
@Range(мин=минимум, максимум=максимум) Атомарные типы и типы-оболочки, такие как BigDecimal, BigInteger, CharSequence, byte, short, int, long Убедитесь, что значение элемента аннотации находится между минимальным и максимальным значениями.
@Email(regexp=регулярное выражение, flag=шаблон флага) Подтип CharSequence (например, String) Убедитесь, что значением элемента аннотации является электронная почта, или вы можете указать собственный формат электронной почты с помощью регулярного выражения и флага.
@Pattern(regexp=регулярное выражение, flag=шаблон флага) Строка, любой подтип CharSequence Убедитесь, что значение элемента аннотации соответствует указанному регулярному выражению.
@Valid любой неатомарный тип Укажите объект, связанный с рекурсивной проверкой. Например, в объекте пользователя есть свойство объекта адреса. Если вы хотите вместе проверять объект адреса при проверке объекта пользователя, добавьте аннотацию @Valid к объекту адреса для каскадной проверки.

Здесь перечислены только большинство аннотаций ограничений проверки, предоставляемых Hibernate Validator. Пожалуйста, обратитесь к официальной документации валидатора hibernate для других аннотаций ограничений проверки и пользовательских определений аннотаций ограничений проверки.

Практическая тренировка

Говорить особо нечего, переходим сразу к практическому пути, а также используем быструю среду SpringBoot Подробный код см.GitHub.com/AJ один/каждый шаг…

1. @Validated объявляет параметр для проверки

Здесь мы делаем объявления аннотаций на уровне контроллера.

 /**
     * 走参数校验注解
     *
     * @param userDTO
     * @return
     */
    @PostMapping("/save/valid")
    public RspDTO save(@RequestBody @Validated UserDTO userDTO) {
        userService.save(userDTO);
        return RspDTO.success();
    }

2. Аннотировать поля параметров


import lombok.Data;
import org.hibernate.validator.constraints.Length;

import javax.validation.constraints.*;
import java.io.Serializable;
import java.util.Date;

/**
 * @author LiJing
 * @ClassName: UserDTO
 * @Description: 用户传输对象
 * @date 2019/7/30 13:55
 */
@Data
public class UserDTO implements Serializable {

    private static final long serialVersionUID = 1L;

    /*** 用户ID*/
    @NotNull(message = "用户id不能为空")
    private Long userId;
    
    /** 用户名*/
    @NotBlank(message = "用户名不能为空")
    @Length(max = 20, message = "用户名不能超过20个字符")
    @Pattern(regexp = "^[\\u4E00-\\u9FA5A-Za-z0-9\\*]*$", message = "用户昵称限制:最多20字符,包含文字、字母和数字")
    private String username;
    
    /** 手机号*/
    @NotBlank(message = "手机号不能为空")
    @Pattern(regexp = "^[1][3,4,5,6,7,8,9][0-9]{9}$", message = "手机号格式有误")
    private String mobile;

    /**性别*/
    private String sex;

    /** 邮箱*/
    @NotBlank(message = "联系邮箱不能为空")
    @Email(message = "邮箱格式不对")
    private String email;

    /** 密码*/
    private String password;

    /*** 创建时间 */
    @Future(message = "时间必须是将来时间")
    private Date createTime;

}

3. Добавить исключение проверки в глобальную проверку

MethodArgumentNotValidExceptionЭто исключение в проверке параметров привязки в SpringBoot, которое необходимо обрабатывать в SpringBoot и других потребностях. Обработайте исключение ConstraintViolationException для обработки.

  • Чтобы быть более элегантным, мы объединили исключение параметра и бизнес-исключение в глобальное исключение и обернули исключение уровня управления в наше пользовательское исключение.
  • Чтобы быть более элегантным, мы также сделали унифицированную структуру для инкапсуляции запрошенного кода вместе с msg и данными в структуру, что повышает возможность повторного использования кода.

import com.boot.lea.mybot.dto.RspDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;


/**
 * @author LiJing
 * @ClassName: GlobalExceptionHandler
 * @Description: 全局异常处理器
 * @date 2019/7/30 13:57
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    private Logger logger = LoggerFactory.getLogger(getClass());

    private static int DUPLICATE_KEY_CODE = 1001;
    private static int PARAM_FAIL_CODE = 1002;
    private static int VALIDATION_CODE = 1003;

    /**
     * 处理自定义异常
     */
    @ExceptionHandler(BizException.class)
    public RspDTO handleRRException(BizException e) {
        logger.error(e.getMessage(), e);
        return new RspDTO(e.getCode(), e.getMessage());
    }

    /**
     * 方法参数校验
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public RspDTO handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        logger.error(e.getMessage(), e);
        return new RspDTO(PARAM_FAIL_CODE, e.getBindingResult().getFieldError().getDefaultMessage());
    }

    /**
     * ValidationException
     */
    @ExceptionHandler(ValidationException.class)
    public RspDTO handleValidationException(ValidationException e) {
        logger.error(e.getMessage(), e);
        return new RspDTO(VALIDATION_CODE, e.getCause().getMessage());
    }

    /**
     * ConstraintViolationException
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public RspDTO handleConstraintViolationException(ConstraintViolationException e) {
        logger.error(e.getMessage(), e);
        return new RspDTO(PARAM_FAIL_CODE, e.getMessage());
    }

    @ExceptionHandler(NoHandlerFoundException.class)
    public RspDTO handlerNoFoundException(Exception e) {
        logger.error(e.getMessage(), e);
        return new RspDTO(404, "路径不存在,请检查路径是否正确");
    }

    @ExceptionHandler(DuplicateKeyException.class)
    public RspDTO handleDuplicateKeyException(DuplicateKeyException e) {
        logger.error(e.getMessage(), e);
        return new RspDTO(DUPLICATE_KEY_CODE, "数据重复,请检查后提交");
    }


    @ExceptionHandler(Exception.class)
    public RspDTO handleException(Exception e) {
        logger.error(e.getMessage(), e);
        return new RspDTO(500, "系统繁忙,请稍后再试");
    }
}

4. Тест

А именно: это правда, что аномальная информация и соответствующий код возвращаются, когда параметр проверяется, что нам удобно больше не обрабатывать проверку параметра.

В ValidationMessages.properties находится проверочное сообщение, которое имеет написанное сообщение по умолчанию и поддерживает i18n. Вы можете прочитать исходный код для оценки

Аннотации пользовательских параметров

1. Например, возьмем пользовательскую аннотацию для проверки идентификатора.

@Documented
@Target({ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = IdentityCardNumberValidator.class)
public @interface IdentityCardNumber {

    String message() default "身份证号码不合法";

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

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

Эта аннотация воздействует на поле Field, вступает в силу во время выполнения и запускает класс аутентификации IdentityCardNumber.

  • Сообщение Индивидуальные подсказки в основном извлекаются из файла validationMessages.properties или настраиваются в соответствии с фактическими условиями.
  • группы Основная цель здесь — классифицировать валидаторы, и разные операции валидаторов будут выполняться в разных группах классов.
  • полезная нагрузка В основном для фасоли, мало используется.

2. Затем настройте валидатор

Это логический код, который фактически выполняет проверку:

public class IdentityCardNumberValidator implements ConstraintValidator<IdentityCardNumber, Object> {

    @Override
    public void initialize(IdentityCardNumber identityCardNumber) {
    }

    @Override
    public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {
        return IdCardValidatorUtils.isValidate18Idcard(o.toString());
    }
}

IdCardValidatorUtils находится в исходном коде проекта и может быть просмотрен самостоятельно

3. Используйте пользовательские аннотации

    @NotBlank(message = "身份证号不能为空")
    @IdentityCardNumber(message = "身份证信息有误,请核对后提交")
    private String clientCardNo;

4. Используйте группы для проверки

Некоторые дети говорят, что один и тот же объект следует использовать повторно. Например, UserDTO должен проверять userId при обновлении, но не требует проверки userId при сохранении. В обоих случаях необходимо проверить имя пользователя, а затем использоватьgroupsв настоящее время:

Сначала определите интерфейс группировки группCreateиUpdate

import javax.validation.groups.Default;

public interface Create extends Default {
}

import javax.validation.groups.Default;

public interface Update extends Default{
}

Затем в том месте, которое необходимо проверить@ValidatedОбъявить группу проверки

 /**
     * 走参数校验注解的 groups 组合校验
     *
     * @param userDTO
     * @return
     */
    @PostMapping("/update/groups")
    public RspDTO update(@RequestBody @Validated(Update.class) UserDTO userDTO) {
        userService.updateById(userDTO);
        return RspDTO.success();
    }

Определяется в поле в DTOgroups = {}тип группировки

@Data
public class UserDTO implements Serializable {

    private static final long serialVersionUID = 1L;

    /*** 用户ID*/
    @NotNull(message = "用户id不能为空", groups = Update.class)
    private Long userId;

    /**
     * 用户名
     */
    @NotBlank(message = "用户名不能为空")
    @Length(max = 20, message = "用户名不能超过20个字符", groups = {Create.class, Update.class})
    @Pattern(regexp = "^[\\u4E00-\\u9FA5A-Za-z0-9\\*]*$", message = "用户昵称限制:最多20字符,包含文字、字母和数字")
    private String username;

    /**
     * 手机号
     */
    @NotBlank(message = "手机号不能为空")
    @Pattern(regexp = "^[1][3,4,5,6,7,8,9][0-9]{9}$", message = "手机号格式有误", groups = {Create.class, Update.class})
    private String mobile;

    /**
     * 性别
     */
    private String sex;

    /**
     * 邮箱
     */
    @NotBlank(message = "联系邮箱不能为空")
    @Email(message = "邮箱格式不对")
    private String email;

    /**
     * 密码
     */
    private String password;

    /*** 创建时间 */
    @Future(message = "时间必须是将来时间", groups = {Create.class})
    private Date createTime;

}

Уведомление: попробуйте добавить его при объявлении группировкиextend javax.validation.groups.DefaultВ противном случае, после объявления@Validated(Update.class), будет казаться, что вы не добавилиgroups = {}Когда группа проверки @Email (сообщение = «формат почтового ящика неверен»), она не будет проверена, потому что группа проверки по умолчаниюgroups = {Default.class}.

5. Использование спокойного стиля

Когда проверяются несколько параметров или в форме @RequestParam, @Validated необходимо добавить в контроллер.

 @GetMapping("/get")
    public RspDTO getUser(@RequestParam("userId") @NotNull(message = "用户id不能为空") Long userId) {
        User user = userService.selectById(userId);
        if (user == null) {
            return new RspDTO<User>().nonAbsent("用户不存在");
        }
        return new RspDTO<User>().success(user);
    }

@RestController
@RequestMapping("user/")
@Validated
public class UserController extends AbstractController {

....圣洛代码...

Суммировать

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

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