[JAVA] Implementieren Sie eine benutzerdefinierte Validierung mit Anmerkungen in Spring Framework und geben Sie eine Nachricht aus

Hallo, das ist Kurata, die zum ersten Mal seit langer Zeit wieder mit Spring rumgespielt hat. Ich habe es seit ungefähr einem halben Jahr bei der Arbeit nicht mehr benutzt.

Wie der Titel schon sagt, habe ich den folgenden Inhalt notiert.

  1. Erstellen einer Anmerkung
  2. Erstellen Sie eine Validatorklasse, an die die Validierungsverarbeitung aus der Annotation übertragen wird
  3. Zeigen Sie benutzerdefinierte Nachrichten an

Einführung

Hintergrund

Ich möchte die Konsistenz mit den in der Datenbank gespeicherten Stammdaten überprüfen.

Was Sie erreichen wollen

Implementieren Sie ein Reservierungsformular für Besprechungsräume. Wählen Sie im Reservierungsformular für Besprechungsräume den Besprechungsraum aus, der mit dem Optionsfeld verwendet werden soll, und geben Sie Datum und Uhrzeit der Nutzung sowie die Anzahl der Personen ein. Es gibt mehrere Tagungsräume mit jeweils fester Kapazität. Wenn mehr als die Kapazität eingegeben wird, tritt ein Eingabefehler auf.

Implementierung

Validierungsspezifikationen

Rufen Sie die Besprechungsrauminformationen basierend auf der eingegebenen Besprechungsraum-ID ab. Beziehen Sie die Kapazität aus den Informationen im Besprechungsraum und bestimmen Sie, ob die eingegebene Anzahl von Benutzern kleiner oder gleich der Kapazität ist. Wenn der Wert ungültig ist, wird eine Validierungsnachricht für die Kapazitätsformularsteuerung angezeigt.

1. Erstellen einer Anmerkung.

Wir haben es "SeatingCapacityValid" genannt, weil es eine Validierung der Kapazität ist. Gemäß den Validierungsspezifikationen müssen mindestens die Raum-ID und der Name des Kapazitätsfelds als Argument für die Anmerkung empfangen werden. Jeder muss als Methode deklariert werden.

SeatingCapacityValid.java


@Documented
@Constraint(validatedBy = {SeatingCapacityValidator.class}) //Geben Sie eine Klasse an, die die Validierungslogik implementiert.
@Target(ElementType.TYPE) //Weil es die Validierung für mehrere Attribute des Formulars ist,Bestimmt, um der Klasse gewährt zu werden.
@Retention(RetentionPolicy.RUNTIME)
public @interface SeatingCapacityValid{
    //Geben Sie den Schlüssel der Nachricht an, die standardmäßig angezeigt werden soll.
    String message() default "{com.example.demo.form.validator.SeatingCapacityValid.message}";
    String roomIdProperty(); //Receive gab den Namen der Unterkunft an, in der die eingegebene Raum-ID gespeichert ist.
    String numberOfUsersProperty(); //Erhalten Sie eine Angabe des Namens der Eigenschaft, in der die eingegebene Anzahl von Benutzern gespeichert ist.

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

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface List {
        SeatingCapacityValid[] value();
    }
}

2. Erstellen Sie eine Validatorklasse, an die die Validierungsverarbeitung aus der Annotation übertragen wird.

Implementieren Sie die Schnittstelle "ConstraintValidator". Das erste Typargument ist eine Annotation, die das annotierte Ziel angibt (in diesem Fall die Form-Klasse, aus Gründen der Vielseitigkeit jedoch den Objekttyp).

SeatingCapacityValidator.java


public class SeatingCapacityValidator implements ConstraintValidator<SeatingCapacityValid, Object> {

    @Autowired
    private RoomRepository roomRepository;
    
    private String roomIdProperty;
    private String timesProperty;
    private String message;
    
    @Override
    public void initialize(CommodityTimesValid constraintAnnotation) {
        roomIdProperty = constraintAnnotation.roomIdProperty();
        numberOfUsersProperty = constraintAnnotation.numberOfUsersProperty();
        message = constraintAnnotation.message();
    }

    @Override
    public boolean isValid(Object value, ConstraintValidatorContext context) {        
        BeanWrapper beanWrapper = new BeanWrapperImpl(value);
        Integer roomId = (Integer)beanWrapper.getPropertyValue(roomIdProperty);
        Integer numberOfUsers = (Integer) beanWrapper.getPropertyValue(numberOfUsersProperty);

        if (roomId == null || numberOfUsers == null) {
            return true;
        }

        Optional<Room> mayBeRoom = roomRepository.findOne(roomId);

        return mayBeRoom.map(room -> {
            Integer capacity = room.getCapacity();
            if (capacity >= numberOfUsers) {
                return true;
            //Passen Sie TODO-Nachrichten an
            context
                    .buildConstraintViolationWithTemplate(message)
                    .addPropertyNode(numberOfUsersProperty)
                    .addConstraintViolation();
            return false;
        }).orElse(true);
    }
}

3. Zeigen Sie benutzerdefinierte Nachrichten an

Die Nachrichtenanzeigelogik wird in dem als TODO geschriebenen Teil von SeatingCapacityValidator.java beschrieben. In der Eigenschaftendatei definieren wir `{0} als die Anzahl der Personen unter {1} und das Ziel ist es, die Anzahl der Personen pro Raum in {1} anzuzeigen.

SeatingCapacityValidator.java


public class SeatingCapacityValidator implements ConstraintValidator<SeatingCapacityValid, Object> {
    //Unterlassung
    @Override
    public boolean isValid(Object value, ConstraintValidatorContext context) {
        //Unterlassung
        return mayBeRoom.map(room -> {
            Integer capacity = room.getCapacity();
            if (capacity >= numberOfUsers) {
                return true;
            }
            HibernateConstraintValidatorContext hibernateContext =
                    context.unwrap(HibernateConstraintValidatorContext.class);

            hibernateContext.disableDefaultConstraintViolation();
            hibernateContext
                    .addMessageParameter("1", capacity) //Hier ist die Anzahl der Personen in jedem Raum{1}Einstellen.
                    .buildConstraintViolationWithTemplate(message)
                    .addPropertyNode(numberOfUsersProperty)
                    .addConstraintViolation();
            return false;
        }).orElse(true);
    }
}

Memo

Bei der Validierung mithilfe von Anmerkungen sollten Sie Folgendes beachten.

1. Die durch das Argument von "@ Target" angegebene Konstante.

Wo kann die Anmerkung hinzugefügt werden? Handelt es sich um eine Einzelfeldvalidierung oder eine Korrelationsprüfung? Ist es wirklich notwendig, eine Anmerkung zu machen?

Dieses Mal wollte ich den Eingabewert vom Bildschirm an ein Objekt binden, das ihn in die Domänenebene einfügt. Deshalb habe ich eine Anmerkung erstellt, damit sie zum Zeitpunkt der Bindung ausgewertet wird.

2. Die durch das Argument von "@ Constraint" angegebene Klasse.

An welche Klasse soll die Validierungslogik delegiert werden?

3. Mit Annotationen deklarierte Methoden, Annotationsargumente.

Stellen Sie sicher, dass die für die Validierung erforderlichen Informationen aus der Anmerkung stammen.

4. Anzeigen anderer Informationen als Anmerkungsargumente in der Nachricht.

Die Platzhalter für Nachrichtenvorlagen ("{0}" oder "{1}") werden durch die Informationen ersetzt, die aus der Anmerkung abgerufen werden können. {0} ist der Feldname und nach {1} das Argument der Annotation.

Verwenden Sie zum Festlegen einer anderen als der oben genannten Methode die Methode "ConstraintValidatorContext # unwrap (HibernateConstraintValidatorContext.class)", um sie in die Klasse "HibernateConstraintValidatorContext" zu konvertieren, und legen Sie dann die anzuzeigende Zeichenfolge fest.

Der Name der zu verwendenden Methode Platzhalternotation
addMessageParameter(String s, Object o) {s}
addExpressionVariable(String s, Object o) ${s}

schließlich

Es gibt viele Teile, die ich nicht über die Voraussetzungen geschrieben habe, daher denke ich, dass ich sie organisieren werde, wenn der gesamte Code veröffentlicht wird.

Recommended Posts

Implementieren Sie eine benutzerdefinierte Validierung mit Anmerkungen in Spring Framework und geben Sie eine Nachricht aus
Wechseln der Beans mit Profilanmerkung im Frühjahr
[Rails] Ich habe die Validierungsfehlermeldung mit asynchroner Kommunikation implementiert!