[JAVA] Ich möchte Apache Wicket 8 zusammenfassen, weil es eine gute Idee ist

Nachtrag

Nach der offiziellen Veröffentlichung haben wir in Was ist mit den typischen Änderungen in Apache Wicket 8 passiert zusammengefasst.


Dieser Artikel ist für den 23.12. Von Java EE Adventskalender 2016.

Gestern @ HirofumiIwasakis "Zukünftiges Bild von Java EE 8 (überarbeitet) durch JavaOne 2016" -2016-java-ee-advent-kalender /). Morgen ist @kikutaro.

Einführung

Das komponentenorientierte Webframework von Java ist heutzutage selten ein heißes Thema, aber JSF, Apache Wicket, Vaadin usw. sind typische Themen, die seit der zweiten Hälfte der 2000er Jahre kontinuierlich weiterentwickelt wurden. Kann erwähnt werden.

Apache Wicket-Anwendungsfälle sind hauptsächlich solche, die in Übersee veröffentlicht wurden https://twitter.com/apache_wicket, aber in Japan [Archivseite von Tagajo City](http :: Es gibt Berichte, dass es auch in //tagajo.irides.tohoku.ac.jp/index) und Meinungsfeld auf der Website der Polizeibehörde verwendet wird. Ich werde. Wicket selbst wird ebenfalls kontinuierlich von der Community weiterentwickelt, und Entwicklungsversionen von Wicket 8.0 für Java 8 werden ab sofort veröffentlicht.

Wicket 8.0 stellt Java 8 Lambda-Ausdrücke in Wicket-Komponenten und -Modellen zur Verfügung. Für Wicket-Benutzer, die sich in die Haltung eines Web-Frameworks verliebt haben, das für Java-Programmierer einfach zu entwickeln ist, kann dies als die lang erwartete Verbesserung bezeichnet werden, während sie sich fragen: "Wann wird es kommen?"

Vor diesem Hintergrund werden in diesem Artikel Wicket 8-Migrationshandbuch: Migration zu Wicket 8.0 und [ Ich möchte die Änderungen in der Art und Weise, wie Code aus Wicket 8.0 geschrieben wird, die in Zukunft veröffentlicht wird, unter Bezugnahme auf Dokumente des Kommissars auf der ApacheCon EU 2016 zusammenfassen.

Der Inhalt des Artikels basiert zum Zeitpunkt des Schreibens auf Wicket 8.0.0-M2 und kann sich in Zukunft ändern.

Änderung der Betriebsumgebung

Wicket 8.0 requires at least Java 8 Wicket 8.0 requires Servlet 3.1 (Jetty 9.2+, Apache Tomcat 8+, JBoss WildFly 10+)

(Von der Migration zu Wicket 8.0)

Wicket 8.0 erfordert Java 8 als Umgebung. Gleichzeitig wurde das Basisservlet auf 3.1 aktualisiert, sodass auf die entsprechende Version des Servlet-Containers [^ 1] geachtet werden muss.

[^ 1]: Aber web.xml bleibt immer noch ...

Modelländerungen

LambdaModel

Eine wesentliche Änderung ist die Hinzufügung des Lambda-Modells.

Wie der Name schon sagt, handelt es sich um ein ** Modell, mit dem Sie die Getter / Setter-Verarbeitung für ModelObject mit ** Java 8 Lambda-Ausdrücken und Methodenreferenzen angeben können.

// Wicket 8.Beispiel eines Lambda-Modells von 0
Order order = new Order();
IModel<String> model = LambdaModel.of(order::getUserName, order::setUserName);

Auf diese Weise wird die Methodenreferenz des ersten Arguments als "getModelObject ()" behandelt, und die Methodenreferenz des zweiten Arguments wird als Verarbeitung innerhalb des Prozesses "setModelObject (String)" behandelt.

Dieses Modell scheint die Absicht zu haben, als Alternative zu ** PropertyModel ** verwendet zu werden.

//Bisherige Beispiele für Eigenschaftsmodelle
Order order = new Order();
IModel<String> model = new PropertyModel(order, "userName");

PropertyModel ist praktisch, da es mit Instanzfeldern und Setter / Getter verknüpft werden kann. Andererseits ist es schwierig, es zu erstellen und zu ändern, da die referenzierte Feldvariable als Zeichenfolge angegeben werden muss. Wenn Sie LambdaModel verwenden, können Sie dieses Problem lösen und das Gleiche tun wie [^ 2].

[^ 2]: Ich persönlich benutze CompoundPropertyModel trotzdem ...

Modelleinstellungen für die Komponente

Komponenten wie Label arbeiten, indem sie ein Modell (oder ein darin enthaltenes Objekt) übergeben. ** Lambda-Ausdrücke und Methodenreferenzen können auch verwendet werden, wenn das Modell oder Objekt einer Komponente übergeben wird **.

Order order = new Order();

//Bis jetzt (selbst wenn Sie getUserName direkt übergeben, wird es intern in Model eingeschlossen)
add(new Label("foo", Model.of(order.getUserName())));
add(new Label("foo", order.getUserName()));

// Wicket 8.Ab 0 können Sie ein Modell oder Objekt mit einer Methodenreferenz oder einem Lambda-Ausdruck übergeben
add(new Label("foo", order::getUserName));
add(new Label("foo", () -> {...}));

Modellfabrikmethode

** Das Modell wird jetzt standardmäßig mit einer Werksmethode (von) geliefert **. Sie können Lambda-Ausdrücke und Methodenreferenzen in of verwenden.

IService service = new Service();

//Bisher
IModel<List<Dish>> model = new LoadableDetachableModel<List<Dish>>() {
  private static final long serialVersionUID = 1380883852804223557L;

  @Override
  protected List<Dish> load() {
    return service.fetchDishes();
  }
};

// Wicket 8.Wie schreibe ich von 0. Ich bin sehr froh, dass das LoadableDetachableModel in einer Zeile steht.
IModel<List<Dish>> model = LoadableDetachableModel.of(service::fetchDishes);

Auf diese Weise können Sie ein LoadableDetachableModel usw. in eine Zeile schreiben, was je nach Verwendung praktisch ist, aber Sie mussten es jedes Mal zu einer anonymen Klasse machen **. Das ist sehr nett. Persönlich war ich der Meinung, dass dies der größte Vorteil unter den Modelländerungen war.

Andererseits ist ** AbstractReadOnlyModel veraltet und es wird jetzt empfohlen, stattdessen die anonyme Klasse von IModel zu verwenden **. Bei der Migration auf Wicket 8.0 scheint es einige Zeit zu dauern, alle auf einmal zu suchen und zu ersetzen.

IService service = new Service();

//Bisher
IModel<Integer> model = new AbstractReadOnlyModel<Integer>() {
  private static final long serialVersionUID = 2631631544271526736L;

  @Override
  public Integer getObject() {
    return new Random().nextInt();
  }
};

// Wicket 8.Ab 0 ist AbstractReadOnlyModel veraltet. Wechseln Sie in IModel zu einer anonymen Klasse.
IModel<Integer> model = new IModel<Integer>() {
  private static final long serialVersionUID = -2636918853427797619L;

  @Override
  public Integer getObject() {
    return new Random().nextInt();
  }
};

Komponentenänderungen

Verwendung von Lambda-Ausdrücken in Link und Button

Bei Links, die zwischen Seiten und Schaltflächenkomponenten verschoben werden, die Werte mit Foam veröffentlichen, wurden häufig anonyme Klassen erstellt, um die Methoden onClick () und onSubmit () zu überschreiben, die Klickereignisse steuern.

** In Wicket8 können Sie mithilfe des Lambda-Ausdrucks Links und Schaltflächen erstellen, ohne sie zu einer anonymen Klasse zu machen **.

//Bisher
Link<Void> link = new Link<Void>("toHogePage") {
  private static final long serialVersionUID = 3391006051307639762L;

  @Override
  public void onClick() {
    //Verschiedene Verarbeitung
    setResponsePage(new HogePage(model));
  }
};

// Wicket 8.Verknüpfungskomponente von 0
add(Link.onClick("toHogePage", (l) -> {
  //Verschiedene Verarbeitung
  setResponsePage(new toHogePage(model));
}));

//Wenn Sie nur Seiten verschieben, ist dies eine Zeile
add(Link.onClick("toHogePage", (l) -> setResponsePage(new toHogePage(model))));
//Bisher
Button button = new Button("toHogePage") {
  private static final long serialVersionUID = 7447947126462635005L;

  @Override
  public void onSubmit() {
    //Hier gibt es verschiedene Verarbeitungsmöglichkeiten
    setResponsePage(new HogePage(model));
  }
};

// Wicket 8.Tastenkomponente von 0
Button button = Button.onSubmit("toHogePage", (b) -> {
  //Hier gibt es verschiedene Verarbeitungsmöglichkeiten
  setResponsePage(new HogePage(model));
}));

//Dies ist auch eine Zeile, wenn nur Seitenbewegung
Button button = Button.onSubmit("toHogePage", (b) -> setResponsePage(new CompletionPage(orderModel)));

Die Argumente l und b im Lambda-Ausdruck beziehen sich auf die Link- und Button-Instanzen selbst. Es kann in Lambda-Ausdrücken wiederverwendet werden, wenn Sie nach dem Klicken Link oder Button (oder Modell oder Formular, das daraus erhältlich ist) bedienen möchten.

** Gleiches gilt für Ajax-basierte Links und Buttons **. Wenn Sie beispielsweise eine Schaltfläche hatten, mit der eine Komponente mit dem Namen "wmc" beim Senden eines Formulars mit Ajax aktualisiert wird,

//Bisher
AjaxButton button = new AjaxButton("button") {
  private static final long serialVersionUID = 796871957135885247L;

  @Override
  protected void onSubmit(AjaxRequestTarget target) {
    target.add(getPage().get("wmc"));
  }

  @Override
  protected void onError(AjaxRequestTarget target) {
    target.add(getForm().get("feeedback"));
  }
};

// Wicket 8.Von 0, Ajax Link,Button kann auch kurz geschrieben werden.
//Der Lambda-Ausdruck des zweiten Arguments lautet onSubmit,Der Lambda-Ausdruck des dritten Arguments lautet onError.
AjaxButton button = AjaxButton.onSubmit("onSubmit",
  (b, t) -> t.add(getPage().get("wmc")),
  (b, t) -> t.add(b.getForm().get("feedback")));

Es wird so sein. Das Wicket8-Lambda-Ausdrucksargument b ist die Schaltfläche selbst, und das Argument t ist AjaxRequestTarget.

Ich benutze diese Komponenten oft, aber sie haben auch die Massenproduktion anonymer Klassen verursacht, daher würde ich mich sehr freuen, wenn ich sie (in kürzester Zeit) in einer Zeile schreiben könnte.

Behavior

Das Verhalten, das Komponenten mit Ajax usw. Verhalten und Funktionalität hinzufügt, enthält auch einen Teil, der mit Factory-Methoden und Lambda leicht geschrieben werden kann.

Unten finden Sie ein Beispiel für eine Label-Komponente mit Verhalten, die die Komponente selbst jede Sekunde aktualisiert (?).

// Wicket 8.AbstractAjaxTimerBehavior von 0. Die Variable t ist AjaxRequestTarget.
add(new Label("timer", LoadableDetachableModel.of(LocalDateTime::now))
  .setOutputMarkupId(true)
  .add(AbstractAjaxTimerBehavior.onTimer(ONE_SECOND, (t) -> t.add(getPage().get("timer")))));

In der Vergangenheit mussten bei der Vorbereitung solcher Verhaltensweisen anonyme Klassen und Unterklassen erstellt werden. Wicket 8.0 wurde entwickelt, um diese anonymen Klassen zu vermeiden und das Schreiben mit weniger Code zu vereinfachen.

Codebeispiel

Anhand der bisher vorgestellten Beispiele habe ich ein Beispiel für ein einfaches Einreichungsformular erstellt (Import entfällt). Wenn Sie Wicket bereits verwendet haben, werden Sie feststellen, dass der Java-Code kürzer ist.

Seite senden

<!DOCTYPE html>
<html xmlns:wicket="http://wicket.apache.org">
<head>
  <meta charset="utf-8"/>
</head>
<body>
<h1>Bestellformular</h1>
<form wicket:id="form">
  <dl>
    <div wicket:id="feedback"></div>
    <dt>Name</dt>
    <dd><input type="text" wicket:id="userName"></dd>
    <dt>Mahlzeit</dt>
    <dd>unten<span wicket:id="numberOfDish"></span>Bitte wählen Sie einen aus den Artikeln.</dd>
    <dd>
      <div wicket:id="dish"></div>
    </dd>
  </dl>
  <div>
    <button type="submit" wicket:id="onSubmit">bestellen</button>
  </div>
</form>
</body>
</html>
public class OrderPage01 extends WebPage {
  private static final long serialVersionUID = -8412714440456444538L;

  public OrderPage01() {
    IService service = new Service();
    IModel<Order> orderModel = CompoundPropertyModel.of(Model.of(new Order()));

    IModel<List<Dish>> dishes = LoadableDetachableModel.of(service::fetchDishes);

    //Ich verwende die Warteschlange, weil die Hierarchie problematisch ist
    queue(new Form<>("form", orderModel));
    queue(new FeedbackPanel("feedback"));
    queue(new TextField<>("userName").setRequired(true));
    queue(new Label("numberOfDish", dishes.getObject()::size));
    queue(new RadioChoice<>("dish", dishes).setSuffix("<br/>").setRequired(true));
    queue(Button.onSubmit("onSubmit", (b) -> setResponsePage(new CompletionPage(orderModel))));
  }

}

Bestätigungsseite (Abschlussseite)

<!DOCTYPE html>
<html xmlns:wicket="http://wicket.apache.org">
<head>
  <meta charset="utf-8"/>
</head>
<body>
<h1>Bestätigungsbildschirm</h1>
<p><span wicket:id="userName"></span>Ist<span wicket:id="dish"></span>ich bestellte</p>
<div><a wicket:id="toIndexPage">Rückkehr</a></div>
</body>
</html>
public class CompletionPage extends WebPage {
  private static final long serialVersionUID = 3057979294465321296L;

  public CompletionPage(IModel<Order> orderModel) {
    setDefaultModel(CompoundPropertyModel.of(orderModel));
    add(new Label("userName"));
    add(new Label("dish"));
    add(Link.onClick("toIndexPage", (link) -> setResponsePage(IndexPage.class)));
  }
}

Andere

Wie viel können anonyme Klassen vermieden werden?

Leider können nicht alle Modelle, Komponenten und Verhaltensweisen anonyme Klassen umgehen.

** ListView usw. sind ebenfalls typische Komponenten, die als anonyme Klassen verwendet werden. Es wurden jedoch keine besonderen Verbesserungen vorgenommen, und es ist erforderlich, sie wie zuvor als anonyme Klassen zu verwenden **.

Auch wenn es sich um eine Link- oder Button-Komponente handelt, sind die Methoden wie ** onInitialize () und onConfigure (), die die anonyme Klassenkomponente initialisieren, dieselben wie zuvor **. Wenn Sie also eine Komponente generieren möchten, die als Aktualisierungsziel von Ajax festgelegt ist (dh setOutputMarkupId (boolean) festlegen), oder eine Komponente, die Validierung und Sichtbarkeit festlegen muss, ist dies dieselbe wie zuvor. Muss anonyme Klasse sein [^ 3].

[^ 3]: Es ist möglich, Einstellungsmethoden wie "setOutputMarkupId (boolean)" in Form einer Methodenkette zu verbinden, aber der Rückgabewert dieser Methoden muss auf den Komponententyp festgelegt werden. Ja, Casting wird beim Hinzufügen untergeordneter Komponenten unverzichtbar. Sie können die Warteschlange gut nutzen und die Besetzung fortsetzen.

Ich denke jedoch, dass es bequem zu verwenden ist, selbst wenn Sie einfach Links, Schaltflächen und Modelle schreiben können, die sich wahrscheinlich auf einer Seite befinden, für die keine so detaillierte Steuerung erforderlich ist.

Einzigartige Funktionsschnittstelle

Um die bisher eingeführten Inhalte zu erreichen, verfügt Wicket 8.0 über eine eigene Funktionsschnittstelle. Sie sind "WicketBiConsumer", "WicketBiFunction", "WicketConsumer", "WicketFunction", "WicketSupplier". Diese werden jedoch nur von der Java-Standardfunktionsschnittstelle geerbt und serialisierbar gemacht.

Darüber hinaus ist IModel auch eine funktionale Schnittstelle, und Standardmethoden wie die Verarbeitung zum Zeitpunkt des Trennens und Standardmethoden für die Zwischenverarbeitung zum Generieren eines Modells aus einem Modell wie Filter und Karte werden vorbereitet.

Es scheint, dass diese verwendet werden können, wenn Sie Modelle und Komponenten selbst erstellen oder verbessern.

abschließend

Es gibt viele andere geringfügige Änderungen in Bezug auf Wicket 7.x → 8.0, aber in diesem Artikel wird der interessanteste Teil der täglichen Programmierung, der vereinfachte Teil der Beschreibung von Modellen und Komponenten und Ich habe die Aktualisierung des Teils zusammengefasst, die von anonymen Klassen mit Lambda vermieden werden kann.

Wir hoffen, dass dies für die Migration von Produkten nützlich sein wird, die bereits mit Wicket entwickelt wurden, und für diejenigen, die in Zukunft auf irgendeine Weise mit Wicket 8.0 oder höher entwickelt werden.

Ein Codebeispiel finden Sie unter github.

Recommended Posts

Ich möchte Apache Wicket 8 zusammenfassen, weil es eine gute Idee ist
[Java] Ich möchte es einfacher machen, weil es schwierig ist, System.out.println einzugeben
Ist es möglich, Funktionsaufrufe und bedingte Verzweigungen zu trennen? -Ich möchte eine gute Gelegenheit zum Schreiben von Code geben. 9 [C # Refactoring-Beispiel]
Ich möchte eine Webanwendung entwickeln!
Ich möchte ein schönes build.gradle schreiben
Ich möchte einen Unit Test schreiben!
Was ist Docker? Ich habe versucht zusammenzufassen
[Ruby] Ich möchte einen Methodensprung machen!
Ich möchte eine einfache Wiederholung einer Zeichenkette schreiben
Ich möchte eine Struktur für die Ausnahmebehandlung entwerfen
Was zu tun ist, wenn es ungültig ist, weil es nicht mit einem '-' beginnt
Ich möchte eine Verbindung herstellen, wenn eine Datenbank mit Spring und MyBatis erstellt wird
7 Dinge, die du behalten sollst, damit es kein verdammter Code wird
Beachten Sie, dass ich von den Einstellungen des Android-Projekts von IntelliJ IDEA abhängig war
Ich möchte es zusätzlich implementieren, während ich Kotlin auf einer Site verwende, auf der Java ausgeführt wird
Ich möchte eine Methode einer anderen Klasse aufrufen
Ich möchte NetBeans auf einem Mac verwenden → Ich kann es verwenden!
Ich möchte ein kleines Symbol in Rails verwenden
Ich möchte eine bestimmte Datei mit WatchService überwachen
Ich möchte eine Funktion in der Rails Console definieren
Ich möchte in RSpec auf einen GoogleMap-Pin klicken
Ich möchte eine generische Anmerkung für einen Typ erstellen
Ich möchte der Kommentarfunktion eine Löschfunktion hinzufügen
Wenn Sie eine Java-Anwendung in ein Docker-Image verwandeln möchten, ist es praktisch, Jib zu verwenden.
[Docker] Ist es gut genug, um es als mehrstufigen Build zu bezeichnen? → Die Geschichte, die so gut wurde
[Java] Ich möchte ein Byte-Array in eine Hexadezimalzahl konvertieren
Ich möchte einen relativen Pfad in einer Situation finden, in der Pfad verwendet wird
Ich möchte eine Produktinformationsbearbeitungsfunktion ~ part1 ~ implementieren
Ich möchte ein bestimmtes Modell von ActiveRecord ReadOnly erstellen
Ich möchte eine Liste mit Kotlin und Java erstellen!
Ich möchte eine Methode aufrufen und die Nummer zählen
Ich möchte eine Funktion mit Kotlin und Java erstellen!
Ich möchte ein Formular erstellen, um die Kategorie [Schienen] auszuwählen
Selbst in Java möchte ich true mit == 1 && a == 2 && a == 3 ausgeben
Ich möchte dem select-Attribut einen Klassennamen geben
Ich möchte eine Parkettdatei auch in Ruby erstellen
Ich möchte FireBase verwenden, um eine Zeitleiste wie Twitter anzuzeigen
Eine flüssige Schnittstelle? -Ich möchte Ihnen die Möglichkeit geben, guten Code zu schreiben. 3 [C # Refactoring Sample]
Ich habe versucht, Apache Wicket zu verwenden
Ich möchte rekursiv nach Dateien in einem bestimmten Verzeichnis suchen
Ich möchte mit link_to [Hinweis] eine Schaltfläche mit einem Zeilenumbruch erstellen.
Ich möchte eine Browsing-Funktion mit Ruby on Rails hinzufügen
Ich möchte Swipeback auf einem Bildschirm verwenden, der XLPagerTabStrip verwendet
[Einführung in JSP + Servlet] Ich habe eine Weile damit gespielt ♬
Ich habe versucht, einen Numeron zu erstellen, der mit Ruby nicht gut ist
Ich möchte mit einem regulären Ausdruck zwischen Zeichenketten extrahieren
Ich möchte eine Datei mit Ruby im Internet herunterladen und lokal speichern (mit Vorsicht).