Après la sortie officielle, nous avons résumé dans Qu'est-il arrivé aux changements typiques dans Apache Wicket 8.
Cet article concerne le 23/12 de Java EE Advent Calendar 2016.
Hier, @ HirofumiIwasaki's "Future image of Java EE 8 (révisée) via JavaOne 2016" -2016-java-ee-calendrier-de-l'avent /). Demain, c'est @kikutaro.
À propos, le framework Web Java orienté composants est rarement un sujet brûlant de nos jours, mais JSF, Apache Wicket, Vaadin, etc. sont des sujets typiques qui ont été développés en continu depuis la seconde moitié des années 2000. Peut être mentionné.
Les cas d'utilisation d'Apache Wicket sont principalement ceux publiés à l'étranger https://twitter.com/apache_wicket, mais au Japon [Site d'archives de Tagajo City](http: Il existe des rapports selon lesquels il est également utilisé dans //tagajo.irides.tohoku.ac.jp/index) et Opinion Box on Police Agency Site. Je vais. Wicket lui-même est également continuellement développé par la communauté, et des versions de développement de Wicket 8.0 pour Java 8 commencent à sortir.
Wicket 8.0 rend les expressions Java 8 Lambda disponibles dans les composants et modèles Wicket. Pour les utilisateurs de Wicket qui sont tombés amoureux de la position d'un framework Web facile à développer pour les programmeurs Java, on peut dire que c'est l'amélioration tant attendue tout en se demandant "quand cela viendra-t-il?"
Dans ce contexte, dans cet article, Wicket 8 Migration Guide: Migration to Wicket 8.0 et Je voudrais résumer les changements dans la façon dont le code est écrit à partir de la prochaine version de Wicket 8.0, en référence au document rédigé par le committer à ApacheCon EU 2016.
Le contenu de l'article est basé sur Wicket 8.0.0-M2 au moment de la rédaction et est susceptible de changer à l'avenir.
Wicket 8.0 requires at least Java 8 Wicket 8.0 requires Servlet 3.1 (Jetty 9.2+, Apache Tomcat 8+, JBoss WildFly 10+)
(De la migration vers Wicket 8.0)
Wicket 8.0 nécessite Java 8 comme environnement. Parallèlement à cela, le servlet de base a également été mis à niveau vers la version 3.1, il est donc nécessaire de faire attention à la version correspondante du conteneur de servlet [^ 1].
[^ 1]: Mais web.xml reste toujours ...
LambdaModel
Un changement majeur est l'ajout du modèle Lambda.
Comme son nom l'indique, il s'agit d'un ** Model qui vous permet de spécifier le traitement Getter / setter pour ModelObject avec des expressions ** Java 8 Lambda et des références de méthode.
// Wicket 8.Exemple de modèle Lambda à partir de 0
Order order = new Order();
IModel<String> model = LambdaModel.of(order::getUserName, order::setUserName);
De cette façon, la référence de méthode du premier argument est traitée comme getModelObject ()
, et la référence de méthode du deuxième argument est traitée comme le traitement à l'intérieur du processus setModelObject (String)
.
Ce modèle semble avoir l'intention d'être utilisé comme une alternative à ** PropertyModel **.
//Exemples de modèles de propriétés à ce jour
Order order = new Order();
IModel<String> model = new PropertyModel(order, "userName");
PropertyModel est pratique car il peut être lié aux champs d'instance et au setter / getter, mais il est difficile de le créer et de le modifier car la variable de champ référencée doit être spécifiée sous forme de chaîne de caractères. Si vous utilisez LambdaModel, vous pouvez résoudre ce problème et faire la même chose que [^ 2].
[^ 2]: Personnellement, j'utilise quand même CompoundPropertyModel ...
Les composants tels que Label fonctionnent en passant un modèle (ou un objet à l'intérieur). ** Les expressions Lambda et les références de méthode peuvent également être utilisées lors de la transmission du modèle ou de l'objet d'un composant **.
Order order = new Order();
//Jusqu'à présent (même si vous passez directement getUserName, il sera enveloppé dans Model en interne)
add(new Label("foo", Model.of(order.getUserName())));
add(new Label("foo", order.getUserName()));
// Wicket 8.À partir de 0, vous pouvez transmettre un modèle ou un objet avec une référence de méthode ou une expression Lambda
add(new Label("foo", order::getUserName));
add(new Label("foo", () -> {...}));
** Le modèle est maintenant livré en standard avec une méthode d'usine (de) **. Vous pouvez utiliser des expressions Lambda et des références de méthode dans of.
IService service = new Service();
//Jusque là
IModel<List<Dish>> model = new LoadableDetachableModel<List<Dish>>() {
private static final long serialVersionUID = 1380883852804223557L;
@Override
protected List<Dish> load() {
return service.fetchDishes();
}
};
// Wicket 8.Comment écrire à partir de 0. Je suis très heureux que le LoadableDetachableModel soit sur une seule ligne.
IModel<List<Dish>> model = LoadableDetachableModel.of(service::fetchDishes);
De cette façon, vous pouvez écrire LoadableDetachableModel etc. sur une seule ligne, ce qui est pratique selon l'utilisation, mais vous deviez en faire une classe anonyme à chaque fois **. C'est très gentil. Personnellement, j'ai senti que c'était le plus grand avantage parmi les changements dans Model.
Cependant, d'un autre côté, ** AbstractReadOnlyModel est obsolète et il est maintenant recommandé d'utiliser la classe anonyme d'IModel à la place **. Lors de la migration vers Wicket 8.0, il semble qu'il sera nécessaire de rechercher et de remplacer tous en même temps.
IService service = new Service();
//Jusque là
IModel<Integer> model = new AbstractReadOnlyModel<Integer>() {
private static final long serialVersionUID = 2631631544271526736L;
@Override
public Integer getObject() {
return new Random().nextInt();
}
};
// Wicket 8.À partir de 0, AbstractReadOnlyModel est obsolète. Basculez vers une classe anonyme dans IModel.
IModel<Integer> model = new IModel<Integer>() {
private static final long serialVersionUID = -2636918853427797619L;
@Override
public Integer getObject() {
return new Random().nextInt();
}
};
Pour les liens qui se déplacent entre les pages et les composants Button qui publient des valeurs avec Foam, il était courant de créer des classes anonymes afin de remplacer les méthodes onClick () et onSubmit () qui contrôlent les événements de clic.
** Dans Wicket8, en utilisant l'expression Lambda, vous pouvez créer des liens et des boutons sans en faire une classe anonyme **.
//Jusque là
Link<Void> link = new Link<Void>("toHogePage") {
private static final long serialVersionUID = 3391006051307639762L;
@Override
public void onClick() {
//Traitement divers
setResponsePage(new HogePage(model));
}
};
// Wicket 8.Lier le composant à partir de 0
add(Link.onClick("toHogePage", (l) -> {
//Traitement divers
setResponsePage(new toHogePage(model));
}));
//Si vous ne déplacez que des pages, ce sera une ligne
add(Link.onClick("toHogePage", (l) -> setResponsePage(new toHogePage(model))));
//Jusque là
Button button = new Button("toHogePage") {
private static final long serialVersionUID = 7447947126462635005L;
@Override
public void onSubmit() {
//Divers traitements entrent ici
setResponsePage(new HogePage(model));
}
};
// Wicket 8.Composant bouton à partir de 0
Button button = Button.onSubmit("toHogePage", (b) -> {
//Divers traitements entrent ici
setResponsePage(new HogePage(model));
}));
//Ceci est également une ligne si seulement le mouvement de la page
Button button = Button.onSubmit("toHogePage", (b) -> setResponsePage(new CompletionPage(orderModel)));
Les arguments «l» et «b» dans l'expression lambda sont des références aux instances de lien et de bouton elles-mêmes. Il peut être réutilisé dans les expressions Lambda au cas où vous souhaiteriez utiliser Lien ou Bouton (ou Modèle ou Formulaire pouvant être obtenu à partir de celui-ci) après avoir cliqué.
** Il en va de même pour les liens et boutons basés sur Ajax **. Par exemple, si vous aviez un bouton qui met à jour un composant nommé wmc
avec Ajax lorsque vous soumettez un formulaire,
//Jusque là
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.À partir de 0, Ajax Link,Le bouton peut également être écrit de manière concise.
//L'expression Lambda du deuxième argument est onSubmit,L'expression Lambda du troisième argument est onError.
AjaxButton button = AjaxButton.onSubmit("onSubmit",
(b, t) -> t.add(getPage().get("wmc")),
(b, t) -> t.add(b.getForm().get("feedback")));
Ce sera comme. L'argument d'expression Lambda Wicket8 b
est le bouton lui-même et l'argument t
est AjaxRequestTarget.
J'utilise souvent ces composants, mais ils ont également provoqué la production en masse de classes anonymes, donc je serais très heureux si je pouvais les écrire en une seule ligne (au plus court).
Behavior
Behavior, qui ajoute du comportement et des fonctionnalités aux composants avec Ajax, etc., a également une partie qui peut être facilement écrite par des méthodes d'usine et lambda.
Vous trouverez ci-dessous un exemple de composant Label avec Behavior qui met à jour le composant lui-même toutes les secondes (?).
// Wicket 8.AbstractAjaxTimerBehavior à partir de 0. La variable t est AjaxRequestTarget.
add(new Label("timer", LoadableDetachableModel.of(LocalDateTime::now))
.setOutputMarkupId(true)
.add(AbstractAjaxTimerBehavior.onTimer(ONE_SECOND, (t) -> t.add(getPage().get("timer")))));
Dans le passé, il était nécessaire de créer des classes et des sous-classes anonymes lors de la préparation de tels comportements. Wicket 8.0 a été conçu pour éviter ces classes anonymes et faciliter l'écriture avec moins de code.
Sur la base des exemples présentés jusqu'à présent, j'ai fait un exemple de formulaire de soumission simple (l'importation est omise). Si vous avez déjà utilisé Wicket, vous constaterez que le code Java est plus court.
<!DOCTYPE html>
<html xmlns:wicket="http://wicket.apache.org">
<head>
<meta charset="utf-8"/>
</head>
<body>
<h1>Bon de commande</h1>
<form wicket:id="form">
<dl>
<div wicket:id="feedback"></div>
<dt>Nom</dt>
<dd><input type="text" wicket:id="userName"></dd>
<dt>repas</dt>
<dd>au dessous de<span wicket:id="numberOfDish"></span>Veuillez en choisir un parmi les articles.</dd>
<dd>
<div wicket:id="dish"></div>
</dd>
</dl>
<div>
<button type="submit" wicket:id="onSubmit">commande</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);
//J'utilise la file d'attente car la hiérarchie est gênante
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))));
}
}
<!DOCTYPE html>
<html xmlns:wicket="http://wicket.apache.org">
<head>
<meta charset="utf-8"/>
</head>
<body>
<h1>écran de confirmation</h1>
<p><span wicket:id="userName"></span>Est<span wicket:id="dish"></span>j'ai commandé</p>
<div><a wicket:id="toIndexPage">Revenir</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)));
}
}
Malheureusement, tous les modèles, composants et comportements ne permettent pas de contourner les classes anonymes.
** ListView etc. sont également des composants typiques qui sont utilisés comme classes anonymes, mais aucune amélioration particulière n'a été apportée, et il est nécessaire de les utiliser comme classes anonymes comme auparavant **.
De plus, même s'il s'agit d'un composant Link ou Button, les méthodes qui initialisent les composants classés anonymement tels que ** ʻonInitialize () et ʻonConfigure ()
sont les mêmes qu'auparavant **. Par conséquent, si vous souhaitez générer un composant qui est défini comme cible de mise à jour d'Ajax (c'est-à-dire définir setOutputMarkupId (boolean)
) ou un composant qui doit définir la validation et la visibilité, c'est le même qu'avant. Doit être une classe anonyme [^ 3].
[^ 3]: Il est possible de connecter des méthodes de paramétrage telles que setOutputMarkupId (boolean)
sous la forme d'une chaîne de méthodes, mais la valeur de retour de ces méthodes doit être définie sur le type de composant. Oui, la diffusion devient indispensable lors de l'ajout de composants enfants. Vous pouvez bien utiliser la file d'attente et permettre au casting de se poursuivre.
Cependant, je pense qu'il est confortable à utiliser même si vous pouvez simplement écrire des liens, des boutons et des modèles qui sont susceptibles de se trouver sur n'importe quelle page ne nécessitant pas un contrôle aussi détaillé.
Afin d'atteindre le contenu introduit jusqu'à présent, Wicket 8.0 dispose de sa propre interface fonctionnelle. Ce sont «WicketBiConsumer», «WicketBiFunction», «WicketConsumer», «WicketFunction», «WicketSupplier». Cependant, ceux-ci sont juste hérités de l'interface fonctionnelle standard Java et rendus sérialisables.
En outre, IModel est également une interface fonctionnelle, et des méthodes par défaut telles que le traitement au moment du détachement et des méthodes par défaut pour le traitement intermédiaire pour générer un modèle à partir d'un modèle telles que le filtre et la carte sont préparées.
Il semble que ceux-ci peuvent être utilisés lors de la création ou de l'amélioration de modèles et de composants par vous-même.
Il y a beaucoup d'autres changements mineurs vers Wicket 7.x → 8.0, mais dans cet article, la partie la plus intéressante de la programmation au quotidien, la partie simplifiée de la description des modèles et des composants, et J'ai résumé la mise à jour de la partie qui peut être évitée par une classe anonyme utilisant lambda.
Nous espérons qu'il sera utile pour la migration de produits qui ont déjà été développés avec Wicket, et pour ceux qui développeront avec Wicket 8.0 ou une version ultérieure d'une manière ou d'une autre à l'avenir.
Un exemple de code peut être trouvé sur github.