[JAVA] Kollektive Behandlung von Spring-Validierungsfehlern mit @ControllerAdvice

Fazit

Wenn Sie eine Handlerklasse mit [@ControllerAdvice] vorbereiten (https://spring.pleiades.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/ControllerAdvice.html) Die Behandlung von Validierungsfehlern jedes Controllers kann sofort behandelt werden.

Umgebung

Java 11 SpringBoot 2.3.3

Kommentar

Im Folgenden wird der REST-Controller erläutert, der eine Liste von Benutzern durch Angabe von Suchparametern erfasst. Die Eingabevalidierung der Anforderung wird bereitgestellt, und wenn ein Validierungsfehler erkannt wird, wird ein 400-Fehler zusammen mit einem vorbestimmten Antworttext zurückgegeben.

Controller-Klasse

Fügen Sie dem Argument "@ Validated" hinzu, damit die Validierung durchgeführt wird. Die Behandlung zum Zeitpunkt des Fehlers wird hier nicht besonders durchgeführt.


@RestController
@RequiredArgsConstructor
public class UserController {

    @NonNull
    private final UserService userService;

    @NonNull
    private final GetUsersQueryValidator getUsersQueryValidator;

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.addValidators(getUsersQueryValidator);
    }

    /**
     *Erhalten Sie Benutzerinformationen, indem Sie Suchbedingungen angeben
     *
     * @param getUsersQuery Suchkriterien Abfrageparameter
     * @zurückgegeben Gesuchte Benutzerinformationen
     */
    @GetMapping(value = "/users")
    ResponseEntity<List<UserDto>> getUsers(@Validated GetUsersQuery getUsersQuery) {

        SearchUsersCondition searchUsersCondition = new SearchUsersCondition();
        searchUsersCondition.setName(getUsersQuery.getName());
        searchUsersCondition.setLowerLimitAge(getUsersQuery.getLowerLimitAge());
        searchUsersCondition.setUpperLimitAge(getUsersQuery.getUpperLimitAge());

        return ResponseEntity.ok(userService.searchUsers(searchUsersCondition));
    }
}

Parameterklasse abfragen

Die Klasse, an die die Abfrageparameter der Anforderung gebunden sind. "@ NotBlank" und "@ NotNull" werden zu jedem Feld hinzugefügt, so dass eine Einzeltermvalidierung durchgeführt wird.

/**
 *Abfrageparameter, die Benutzersuchbedingungen angeben
 */
@Data
public class GetUsersQuery {

    /**
     *Nutzername
     */
    @NotBlank
    private String name;

    /**
     *Mindestalter
     */
    @NotNull
    private Integer lowerLimitAge;

    /**
     *Maximales Alter
     */
    @NotNull
    private Integer upperLimitAge;

}

Korrelations-Varidata-Klasse

Ein Fehler tritt auf, wenn das untere Grenzalter des Abfrageparameters das obere Grenzalter überschreitet.

/**
 * {@link GetUsersQuery}Korrelationsvaridaten
 */
@Component
public class GetUsersQueryValidator implements Validator {

    @Override
    public boolean supports(Class<?> clazz) {
        return GetUsersQuery.class.isAssignableFrom(clazz);
    }

    /**
     *Validierungsimplementierung
     *
     * @param target Validierungsziel
     * @Parameterfehler Erkannte Fehler
     */
    @Override
    public void validate(Object target, Errors errors) {

        //Eine Korrelationsvalidierung wird nicht durchgeführt, wenn ein einzelner Termfehler entweder im oberen Grenzalter oder im unteren Grenzalter auftritt.
        if (errors.hasFieldErrors("lowerLimitAge") || errors.hasFieldErrors("upperLimitAge")) {
            return;
        }

        GetUsersQuery getUsersQuery = GetUsersQuery.class.cast(target);

        int lowerLimitAge = getUsersQuery.getLowerLimitAge();
        int upperLimitAge = getUsersQuery.getUpperLimitAge();

        //Wenn das Alter der Obergrenze das Alter der Untergrenze nicht überschreitet, tritt ein Fehler auf.
        if (lowerLimitAge >= upperLimitAge) {
            errors.reject("reverseLimitAge");
        }
    }
}

Fehlerklasse für Antworttext

Wenn ein Fehler auftritt, wird ein Objekt dieses Typs im Antworttext gespeichert.

/**
 *Fehlerinformationen, die im Anforderungshauptteil festgelegt werden sollen
 */
@Data
public class ApiError implements Serializable {

    private static final long serialVersionUID = 1L;

    private String message;
}

Ausnahmebehandlungsklasse

Bereiten Sie eine Ausnahmebehandlungsklasse mit @ ControllerAdvice vor, wie unten gezeigt.


/**
 *Handler für Ausnahmen, die auf dem Controller ausgelöst wurden
 */
@ControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

    @Autowired
    MessageSource messageSource;

    /**
     * {@link BindException}Handhabung
     *
     * @param bindException {@link BindException}
     * @param httpHeaders   {@link HttpHeaders}
     * @param httpStatus    {@link HttpStatus}
     * @param webRequest    {@link WebRequest}
     * @Antwort an Client zurückgeben
     */
    @Override
    protected ResponseEntity<Object> handleBindException(
            BindException bindException,
            HttpHeaders httpHeaders,
            HttpStatus httpStatus,
            WebRequest webRequest
    ) {
        //Fehlerliste im Antworttext gespeichert
        List<ApiError> apiErrorList = new ArrayList<>();

        List<ObjectError> objectErrorList = bindException.getAllErrors();

        for (ObjectError objectError : objectErrorList) {

            //Nachricht vom Fehlercode abrufen
            String message = messageSource.getMessage(objectError, webRequest.getLocale());

            //Erstellen Sie ein Fehlerobjekt für den Antworttext und speichern Sie es in der Liste
            ApiError apiError = new ApiError();
            apiError.setMessage(message);
            apiErrorList.add(apiError);
        }

        return new ResponseEntity<>(apiErrorList, httpHeaders, httpStatus);
    }
}

Wenn ein Validierungsfehler auftritt, löst der Controller eine "BindException" aus, in der die Fehlerinformationen gespeichert werden. Implementieren Sie in der Klasse mit "@ ControllerAdvice" den Prozess, den Sie auf jeden Controller anwenden möchten. Durch Erben von "ResponseEntityExceptionHandler" und Überschreiben der "handleBindException" -Methode können Sie die Antwort zum Zeitpunkt des Validierungsfehlers frei anpassen.

Hier wird es wie folgt angepasst.

Der Fehlercode wird in objectError im folgenden Format gespeichert.

Einzeltermvalidierung: "Annotationsname + Klassenname (Kamelfall) + Feldname" Korrelationsvalidierung: "Fehlercode in Korrelationsvalidierung + Klassenname (Kamelfall) festgelegt"

Wenn Sie messages.properties wie folgt vorbereiten, wird es in eine Nachricht konvertiert.

messages.properties

NotBlank.getUsersQuery.name=Die Eingabe eines Namens ist obligatorisch.
NotNull.getUsersQuery.lowerLimitAge=Die Eingabe des Mindestalters ist obligatorisch.
NotNull.getUsersQuery.upperLimitAge=Die Eingabe des Höchstalters ist obligatorisch.
reverseLimitAge.getUsersQuery=Geben Sie einen Wert an, der größer als das untere Grenzalter für das obere Grenzalter ist.

Recommended Posts

Kollektive Behandlung von Spring-Validierungsfehlern mit @ControllerAdvice
Selbstgemachte Validierung mit Spring
Erhalten Sie Validierungsergebnisse mit Spring Boot
Formularklassenvalidierungstest mit Spring Boot
Holen Sie sich den Body-Teil von HttpResponse mit Spring Filter
[Java] Artikel zum Hinzufügen einer Validierung mit Spring Boot 2.3.1.
Ich benötige eine Validierung der Federdaten für Pageable ~
Anpassung der Validierung
Kompatibilität von Spring JDBC und My Batis mit Spring Data JDBC (vorläufig)
Greifen Sie mit jdbcTemplate auf das integrierte h2db des Spring Boot zu
Erstellen Sie Restapi mit Spring Boot (bis zum Ausführen der App)
Booten nach Umgebung mit Spring Boot of Maven
Steuern Sie den Spring Batch-Verarbeitungsablauf mit JavaConfig.