Базовое руководство по Spring Boot 2.x: JSR-303 реализует проверку параметров запроса

Spring Boot

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

  • Для решения проверки параметров полагайтесь только на интерфейсную структуру, а проверка на стороне сервера отсутствует. Такая ситуация распространена, когда фронт и бэкенд нужно разрабатывать одновременно, хотя нормальное использование программы не будет проблемой, но аномальную работу разработчик игнорирует. Например, обход клиентской программы и прямая имитация клиентского запроса внезапно установит различные ограничения на интерфейс и напрямую затронет различные интерфейсы доступа к данным, что создаст угрозу безопасности нашей системы.
  • Интенсивное использованиеif/elseОператор вложен, а логика проверки неясна и сложна для понимания, что не способствует долгосрочному обслуживанию.

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

Далее в этом руководстве мы подробно обсудим, как элегантно реализовать проверку параметров запроса на сервере Spring Boot.

JSR-303

Прежде чем мы приступим к практической работе, давайте взглянем на стандартную спецификацию, которую мы будем использовать дальше: JSR-303.

Что такое ЖСР?

JSR — это аббревиатура от Java Specification Requests, что означает предложение спецификации Java. Это официальный запрос в JCP (Java Community Process) о добавлении стандартизированной технической спецификации. Любой может отправить JSR для добавления новых API и сервисов на платформу Java. JSR стал важным стандартом в мире Java.

Какой стандарт определен JSR-303?

JSR-303 — это подспецификация в JAVA EE 6, называемая «Проверка компонентов», а Hibernate Validator — эталонная реализация проверки компонентов.Hibernate Validator обеспечивает реализацию всех встроенных ограничений спецификации JSR 303 в дополнение к некоторым дополнительным ограничение.

Ограничения, встроенные в проверку компонентов

Дополнительные ограничения Hibernate Validator

В соответствии со стандартом JSR-303 мы можем элегантно определить проверку каждого параметра запроса с помощью приведенных выше аннотаций. Подробнее о JSR можно узнать в официальной документации или ссылках [1].

Руки

После понимания JSR-303 давайте попробуем реализовать проверку параметров на основе этой спецификации!

Готов к работе

Читатели могут взять за основу любой проект, созданный с помощью Spring Boot 2.x, который предоставляет RESTful API. также можно использоватьБазовое руководство по Spring Boot 2.x: создание надежной документации API с помощью Swagger2Экспериментальный проект, построенный вchapter2-2Каталог для получения:

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

Быстрый старт

Сначала рассмотрим простой пример, например: поле определения не может бытьNull. Всего два шага

первый шаг: Добавить Для проверки на поле@NotNullПримечания, как показано ниже:

@Data
@ApiModel(description="用户实体")
public class User {

    @ApiModelProperty("用户编号")
    private Long id;

    @NotNull
    @ApiModelProperty("用户姓名")
    private String name;

    @NotNull
    @ApiModelProperty("用户年龄")
    private Integer age;

}

второй шаг: добавить перед объектом параметра, который необходимо проверить.@ValidПримечания, как показано ниже:

@PostMapping("/")
@ApiOperation(value = "创建用户", notes = "根据User对象创建用户")
public String postUser(@Valid @RequestBody User user) {
    users.put(user.getId(), user);
    return "success";
}

После завершения вышеуказанной настройки запустите приложение и получите к нему доступ с помощью POST-запроса.localhost:8080/users/Интерфейс, корпус использует пустой объект,{}. Вы можете инициировать инструменты тестирования, такие как Postman, или запускать их с помощью CURL, например:

curl -X POST \
  http://localhost:8080/users/ \
  -H 'Content-Type: application/json' \
  -H 'Postman-Token: 72745d04-caa5-44a1-be84-ba9c115f4dfb' \
  -H 'cache-control: no-cache' \
  -d '{
    
}'

Неудивительно, что вы можете получить следующие результаты:

{
    "timestamp": "2019-10-05T05:45:19.221+0000",
    "status": 400,
    "error": "Bad Request",
    "errors": [
        {
            "codes": [
                "NotNull.user.age",
                "NotNull.age",
                "NotNull.java.lang.Integer",
                "NotNull"
            ],
            "arguments": [
                {
                    "codes": [
                        "user.age",
                        "age"
                    ],
                    "arguments": null,
                    "defaultMessage": "age",
                    "code": "age"
                }
            ],
            "defaultMessage": "不能为null",
            "objectName": "user",
            "field": "age",
            "rejectedValue": null,
            "bindingFailure": false,
            "code": "NotNull"
        },
        {
            "codes": [
                "NotNull.user.name",
                "NotNull.name",
                "NotNull.java.lang.String",
                "NotNull"
            ],
            "arguments": [
                {
                    "codes": [
                        "user.name",
                        "name"
                    ],
                    "arguments": null,
                    "defaultMessage": "name",
                    "code": "name"
                }
            ],
            "defaultMessage": "不能为null",
            "objectName": "user",
            "field": "name",
            "rejectedValue": null,
            "bindingFailure": false,
            "code": "NotNull"
        }
    ],
    "message": "Validation failed for object='user'. Error count: 2",
    "path": "/users/"
}

Значение каждого параметра возвращаемого содержимого следующее:

  • timestamp: время запроса
  • status: Код состояния, возвращаемый HTTP, здесь возвращает 400, то есть: неверный запрос, неправильный запрос, обычно 400, если проверка параметра не удалась.
  • error: Описание ошибки, возвращенное HTTP, которое соответствует описанию ошибки статуса 400: Неверный запрос.
  • errors: Конкретной причиной ошибки является тип массива; проверка ошибок, поскольку могут быть ошибки множества полей, таких как определенные здесь, поскольку два параметра не могутNull, поэтому есть две записи об ошибках
  • message: сводное сообщение об ошибке. Это легко понять из возвращенного содержимого. Причина ошибки здесь в том, что проверка объекта пользователя не удалась, а количество ошибок равно2, а конкретное сообщение об ошибке определено вышеerrorsв массиве
  • path: путь запроса

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

попробуйте другие проверки

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

@Data
@ApiModel(description="用户实体")
public class User {

    @ApiModelProperty("用户编号")
    private Long id;

    @NotNull
    @Size(min = 2, max = 5)
    @ApiModelProperty("用户姓名")
    private String name;

    @NotNull
    @Max(100)
    @Min(10)
    @ApiModelProperty("用户年龄")
    private Integer age;

    @NotNull
    @Email
    @ApiModelProperty("用户邮箱")
    private String email;

}

Инициировать может пойтиname,age,emailЗапросы, не прошедшие проверку, например:

curl -X POST \
  http://localhost:8080/users/ \
  -H 'Content-Type: application/json' \
  -H 'Postman-Token: 114db0f0-bdce-4ba5-baf6-01e5104a68a3' \
  -H 'cache-control: no-cache' \
  -d '{
    "name": "abcdefg",
    "age": 8,
    "email": "aaaa"
}'

Мы получим следующий возврат ошибки:

{
    "timestamp": "2019-10-05T06:24:30.518+0000",
    "status": 400,
    "error": "Bad Request",
    "errors": [
        {
            "codes": [
                "Size.user.name",
                "Size.name",
                "Size.java.lang.String",
                "Size"
            ],
            "arguments": [
                {
                    "codes": [
                        "user.name",
                        "name"
                    ],
                    "arguments": null,
                    "defaultMessage": "name",
                    "code": "name"
                },
                5,
                2
            ],
            "defaultMessage": "个数必须在2和5之间",
            "objectName": "user",
            "field": "name",
            "rejectedValue": "abcdefg",
            "bindingFailure": false,
            "code": "Size"
        },
        {
            "codes": [
                "Min.user.age",
                "Min.age",
                "Min.java.lang.Integer",
                "Min"
            ],
            "arguments": [
                {
                    "codes": [
                        "user.age",
                        "age"
                    ],
                    "arguments": null,
                    "defaultMessage": "age",
                    "code": "age"
                },
                10
            ],
            "defaultMessage": "最小不能小于10",
            "objectName": "user",
            "field": "age",
            "rejectedValue": 8,
            "bindingFailure": false,
            "code": "Min"
        },
        {
            "codes": [
                "Email.user.email",
                "Email.email",
                "Email.java.lang.String",
                "Email"
            ],
            "arguments": [
                {
                    "codes": [
                        "user.email",
                        "email"
                    ],
                    "arguments": null,
                    "defaultMessage": "email",
                    "code": "email"
                },
                [],
                {
                    "defaultMessage": ".*",
                    "codes": [
                        ".*"
                    ],
                    "arguments": null
                }
            ],
            "defaultMessage": "不是一个合法的电子邮件地址",
            "objectName": "user",
            "field": "email",
            "rejectedValue": "aaaa",
            "bindingFailure": false,
            "code": "Email"
        }
    ],
    "message": "Validation failed for object='user'. Error count: 3",
    "path": "/users/"
}

отerrorsВ различных ошибках в массиве вы знаете каждое полеdefaultMessageВы можете увидеть очень четкое описание ошибки.

Воплощено в документации Swagger

Некоторые читатели могут спросить, так много всего настроено в моем интерфейсе. В предыдущем туториале разве не учили автоматически генерировать документы, так как описать логику проверки параметров?

Здесь есть два случая: сам Swagger имеет некоторую поддержку JSR-303, но поддержка не такая полная, и она не распространяется на все аннотации.

Например, аннотации, которые мы использовали выше, могут быть сгенерированы автоматически, запустить наш экспериментальный проект выше, а затем посетитьhttp://localhost:8080/swagger-ui.html,существуетModelsНет, мы можем видеть что-то вроде изображения ниже:

в:nameиageПо сравнению с описанием документа в предыдущем руководстве, в этом поле содержится больше пояснений по поводу проверки; иemailПоле не отражает соответствующие инструкции по проверке. В настоящее время Swagger поддерживает следующие аннотации:@NotNull,@Max,@Min,@Size,@Pattern. В реальном процессе разработки нам нужно иметь дело с ситуацией.Для ветки Swagger, созданной автоматически, ее можно сгенерировать с помощью встроенной поддержки.Если некоторые поля не могут быть сгенерированы, вы можете@ApiModelPropertyВ описании аннотации он добавляет соответствующие инструкции по проверке для удобства просмотра пользователем.

Дополнительно: Возможно, у вас есть эти вопросы

Когда появляется сообщение об ошибке при проверке параметра запроса, можно ли изменить формат ошибки?

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

spring-boot-starter-validationЭто необходимо?

Некоторые читатели спрашивали раньше и видели, что было написано и представлено много руководств.spring-boot-starter-validationЗависит от этого зависимого? (В этой статье не представлено в этой статье)

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

На самом деле, просто присмотритесьspring-boot-starter-validationЗависимость в основном заключается в том, чтобы представить что, а затем судить в соответствии с версией Spring Boot, которую вы используете в настоящее время. По факту,spring-boot-starter-validationЗависимость в основном состоит в том, чтобы ввести следующие зависимости:

<dependency>
   <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.0.14.Final</version>
    <scope>compile</scope>
</dependency>

Мы можем увидеть, существует ли он в зависимостях текущего проекта, и можем судить, нужно ли дополнительное введение. В Spring Boot версии 2.1 это все еще было включено вspring-boot-starter-webВ зависимостях дополнительное введение не требуется, поэтому в этой статье вы не найдете этого шага.

пример кода

Полный проект этой статьи можно посмотреть на следующем складеchapter2-3содержание:

Если вы считаете, что эта статья хороша, добро пожаловатьStarПоддержите, ваше внимание - движущая сила моего упорства!

использованная литература

  • [1] https://www.jianshu.com/p/554533f88370
  • [2] http://blog.didispace.com/spring-boot-starter-swagger-1.3.0/

Эта статья была впервые опубликована на:блог Brother space.com/spring-boot…

Добро пожаловать, чтобы обратить внимание на мой общедоступный номер: Programmer DD, получить эксклюзивные учебные ресурсы и ежедневный толчок галантерейных товаров. Если вам интересен мой рекомендуемый контент, вы также можете подписаться на мой блог:didispace.com