[JAVA] Die Geschichte der Begegnung mit Spring Custom Annotation

Freut mich, dich kennenzulernen

Dieser Artikel ist der Artikel zum 9. Tag von MicroAd Adventskalender 2017 . Da dies mein erster Versuch bei Qiita war, beschloss ich, eine Aufzeichnung als mein eigenes Memo zu führen. Bitte teilen Sie uns mit, wenn Sie Vorschläge wie falsche Informationen oder Auslassungen haben.

Tor

Lassen Sie uns ein Tool erstellen, das einfach ist, aber wiederverwendet werden kann. Originalanmerkungen sind ein kleiner Schritt in diese Richtung. Und ich kenne den Inhalt ein wenig.

Servicelogik ist genug

~~ Das stimmt ~~

Ich möchte etwas ausprobieren, das mich anspricht. Aus irgendeinem Grund @ Dieses Symbol schien immer attraktiv. Wenn in Zukunft dieselbe Überprüfungslogik benötigt wird, müssen Sie lediglich eine Anmerkung hinzufügen, und es ist leicht zu erkennen, welche Art von Überprüfung durchgeführt wird.

Anmerkung (@interface)

Derzeit werden Anmerkungen in Java als Schnittstellen positioniert. Laut verknüpftem Zitat

The motivation for the introduction of annotations into the Java programming language was the need for semantic information for a given piece of code

Es wird als aus der Notwendigkeit heraus beschrieben, sich mit der "Bedeutung" eines bestimmten Codes in der Java-Programmierung zu befassen.

Im Folgenden sind typische Annotationsüberschreibungen aufgeführt, die als Standard-APIs bereitgestellt werden.

Override.java


@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

Die der Anmerkung beigefügte Anmerkung lautet Dies ist eine Meta-Annotation, die vom Paket java.lang.annotation bereitgestellt wird.

@Target Es ist das zu kommentierende Ziel. Sie können mehrere angeben, indem Sie sie in `` {} `einfügen. Als Zieltyp

Es gibt mehrere, aber im Fall von @Override wird METHOD als Ziel ausgewählt. Tatsächlich kann @Override nicht an andere Elemente als Methoden angehängt werden.

@Retention Beschreibt den Bereich, der von der Anmerkung betroffen ist. Retention gibt eine RetentionPolicy zurück, und es gibt nur drei Arten von RetentionPolicy.

Im Fall von @Override ist RetentionPolicy SOURCE Am Ende der Kompilierung hat dies keine Bedeutung == Die Bytecode-Konvertierung wird nicht durchgeführt.

In einigen Fällen werden sowohl Ziel als auch Aufbewahrung aus Gründen der Lesbarkeit einfach als "Import statisch" geschrieben.

Dieses Beispiel

Was ich diesmal wollte, war eine Anmerkung, um halbe Breite und volle Breite getrennt zu zählen </ b> und die maximale Länge </ b> zu begrenzen. Für die Vorlage habe ich allgemein auf das Paket javax.validation.constraints verwiesen (@Size und @NotNull, richtig?).

Tatsächlich hat diese ursprüngliche Annotation, dh die Constraint-Annotation, eine feste Vorlage (message (), groups (), payload () muss festgelegt werden). Erstellen Sie sie daher entsprechend.

Ich werde es einen Namen geben.

CustomSize.java


@Target({FIELD})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {CustomSizeValidator.class})
public @interface CustomSize {

  String message() default "{validation.CustomSize.message}";
  Class<?>[] groups() default {};
  Class<? extends Payload>[] payload() default {};
  int max();

  @Target({FIELD})
  @Retention(RUNTIME)
  @Documented
  @interface List {
    CustomSize[] value();
  }
}

@Documented Gibt an, dass zum Verwenden dieser Anmerkung das Schreiben mit Javadoc usw. erforderlich ist. Um ehrlich zu sein, habe ich es diesmal vielleicht nicht gebraucht.

@Constraint Geben Sie die Klasse an, die die spezifische Logik beschreibt, die Sie mit dieser Annotation einschränken (prüfen) möchten. Das Folgende ist die Validierungsimplementierungsklasse für diese Annotation.

CustomSizeValidator.java


public class CustomSizeValidator implements ConstraintValidator<CustomSize, String> {

  private int max;

  @Override
  public void initialize(CustomSize customSize) {
    max = customSize.max();
  }

  @Override
  public boolean isValid(String value, ConstraintValidatorContext context) {
    //CustomSizeUtil ist eine Klasse, die nur die Prüflogik beschreibt
    //Der Rückgabewert von getLength ist int
    return CustomSizeUtil.getLength(value) <= max;
  }
}

initialize </ b> ist der Initialisierungsprozess zum Aufrufen von `` `isValid```.

isValid </ b> implementiert die eigentliche Validierungslogik. Der als Parameter übergebene `<T> -Wert `ist das tatsächlich zu überprüfende Objekt. Dieses Mal wird die Länge der eingegebenen Zeichenfolge überprüft, sodass eine Zeichenfolge vom Typ Zeichenfolge dieser entspricht.

Wenn `` `value``` die Prüfung aufgrund einer ungültigen Werteingabe nicht bestehen kann, wird false zurückgegeben.

message() Diese Meldung ist als Warnung (?) Auszugeben, wenn eine falsche Eingabe erfolgt. Enthält den Wortlaut, der in den Nachrichteneigenschaften definiert werden soll (z. B. ValidationMessages.properties von Hibernate). Außerdem wird der Schlüssel mit einem vollständig qualifizierten Klassennamen geschrieben.

Zum Beispiel denke ich, dass es so aussehen wird.

ValidationMessages_jp.properties


validation.CustomSize.message = {0}Bitte nicht überschreiten

groups() Diese Einstellung kann für eine bestimmte Validierungsgruppe angepasst werden. Muss mit einem leeren Klassentyp <?> Initialisiert werden.

Die Gruppierung dient zum Bestellen von Einschränkungen.

@GroupSequence({CheckA.class, CheckB.class}) //Nach Überprüfung von A B.
public interface GroupedChecks {
}

payload() Es handelt sich lediglich um eine Deklaration, um dem zu überprüfenden Objekt einige Metainformationen zu geben. Tatsächlich denke ich, dass der Inhalt der `` `javax.validation.Payload``` -Schnittstelle leer ist und für Markierungen oder Kategorisierung dient.

Zum Beispiel

CustomSize.java


@Target({FIELD})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {CustomSizeValidator.class})
public @interface CustomSize {

  String message() default "{validation.CustomSize.message}";
  Class<?>[] groups() default {};
  class Text implements Payload{} // Add Payload
  // omit
}

SampleModel.java


public class SampleModel {
  @CustomSizeValidator(max = 20, payload = {CustomSizeValidator.Text.class})
  private String memo;
  // omit
}

Es ist nicht korrekt, aber Sie können dem Feld "Memo" eine Bedeutung geben, damit es als Kategorisierung wie "Text" identifiziert werden kann.

Lassen Sie es leer, sofern nicht anders angegeben.

max() Dieses Mal habe ich den Namen max festgelegt, da es sich um eine Validierung handelt, die die "maximale Länge" einschränkt.

 @CustomSizeValidator(max = 20) //Name hier eingeben
 private String memo;

List { A[] value() } Definieren Sie die überprüfbaren Ziele in Abhängigkeit von der Implementierung von ConstraintValidator.

@interface List {
  CustomSizeValidator value();
  AnotherValidator aaa();
}

Sofern Sie keinen bestimmten Grund haben, kann ein Element ausreichen.

verwenden

Es ist dasselbe wie bei anderen Eingabeprüfungen, fügt jedoch @Valid zum oberen Modell hinzu, das als Parameter des Controllers übergeben wurde, und definiert BindingResult, indem es direkt daneben angeordnet wird.

SampleController.java


  @RequestMapping(value = "/sample", method = RequestMethod.POST)
  public String samplePost(@ModelAttribute @Valid BigModel model, BindingResult result) {
    // omit
   }

Fügen Sie bei verschachtelten Modellen dem oberen Modell ebenfalls @Valid hinzu.

BigModel.java


public class BigModel {
  @Valid
  private SmallModel smallModel;
  // omit
}

Diese benutzerdefinierte Anmerkung lautet @Target ({ElementType.FIELD}) und zielt daher auf Felder ab. Fügen Sie es dem Feld hinzu, das tatsächlich überprüft werden soll.

SmallModel.java


public class SmallModel {
  @CustomSize(max = 20)
  private String input;
  // omit
}

Prüfung

  • Testen Sie, um die App auszuführen und versuchen Sie es direkt (Fehler wird in `` `BindingResult``` gespeichert)

  • Test mit Testcode (geben Sie einige Werte an und berechnen Sie wirklich genau)

Da es sich um eine Zeichenanzahl mit einer festen Grenze handelt, habe ich sie mit einer Grenzwertanalyse getestet. Ich teste die Implementierungsklasse für Annotationsbeschränkungen `isValid ()`.

CustomTest.groovy


   // omit
   when:
      def result = validator.isValid("", null)
    then:
      assert result == excepted
    where:
      testCase                | maxLen | doubleLen || excepted
      "Boundary value, small" | 5      | 4.5       || true
      "Boundary value, same"  | 5      | 5         || true
      "Boundary value, big"   | 5      | 5.5       || false

Das Ende

Es war einfach, so etwas zu tun. Ich wollte es in ungefähr beenden Immerhin war es sehr interessant, die Inhalte zu kennen, und es war eine sehr gute Gelegenheit, um zu studieren.

Referenz

Hibernate Community Documentation

das ist alles

Recommended Posts