这是怎么回事? :)
我一直在从事一些项目,这些项目值得庆幸的是将Apache Wicket用于表示层。 我自然想到Java的8个lambda表达式如何与Wicket完美匹配。 而不仅仅是我, Wicket团队似乎已经在努力更改API,以为开箱即用的lambda提供支持。
如果您已经知道Java中的lambda如何工作,那么本文将更加有趣。 如果您不这样做,那么这是一个很好的起点 。 还建议您了解一些有关Apache Wicket的知识,但是,如果您曾经使用过任何面向GUI的API(例如Swing或GWT),那么足以理解它。
在开始之前,我只想发表一个声明,说明为什么我比JSF更喜欢Wichet。 如果您不在乎,请跳过此部分:)
我对JSF的狂热
综上所述,如果您正在考虑为项目使用基于服务器端基于组件的框架,那么我认为没有理由选择Wicket上的JSF。 这是我的一些论点:
1. Wicket代码更易于阅读和维护
JSF强迫您将表示逻辑分散在xHTML文件和Java类(托管Bean)之间,这要归因于render , render等所有方面。 另一方面,Wicket使我们能够编写Java代码。 所有逻辑都包含在controller类中,以我的拙见,它更易于阅读和维护。
有人可能会争辩说,与所有其他面向GUI的API一样,由于最终编写了所有匿名内部类 ,Wicket的代码更加冗长。 对我来说,这仅是部分正确。 该代码确实比JSF的Managed Bean更为冗长,但是更易于阅读。 它只是一个地方的Java代码。 在Facelets页内,没有Java与EL混合在一起。
对于所有匿名内部类 ,通过使用lambda表达式 ,它们可以并且比以往任何时候都可以被阻止。 这就是我在本文中向您展示的内容。
2.使用Wicket可以更清楚地划分角色
Wicket的构建前提是我们可以使用纯HTML来构建页面。 有一些标记需要使用,但最终结果仍然是95%纯HTML 。 这样就可以使对Java或Wicket一无所知的Web设计人员与开发人员并肩工作。 设计人员会做自己最擅长的事情,而开发人员几乎完全使用他们创建的内容,而只担心常规的Java代码。
JSF是完全不同的野兽。 您几乎有两种选择:1)迫使您的设计师学习他们讨厌的JSF。 2)如果他们制作纯HTML原型,则有人将不得不在JSF中“重新编码”它们。
我知道有很多替代方法可以解决此问题,他们甚至在JSF 2.2中引入了“友好标记”功能 。 不过,我所知道的方法都没有Wicket这么简单。
3.在Wicket中,扩展/创建组件要容易得多
在JSF中从头开始创建组件是一场噩梦。 即使在谈论小面组成时,它也没有Wicket一样简单。
总而言之,这只是我的看法。 当然,JSF受到关注是因为它是Java EE规范的一部分,并且该镇的每个新开发人员都希望学习JSF,而不是Wicket。 虽然当然可以使用JSF构建出色的Web应用程序,但Wicket却可以承受一半的麻烦。
还需要注意的是,我对JSF团队没有任何反对。 相反,情况恰恰相反:JSF专家组中充满了才华横溢的人。 不可否认。 我只想知道如果设置为使用完全不同的解决方案,他们可以实现什么。
最后,Wicket和Lambdas
一旦被匿名内部类填充,Lambdas将填补这一空白。 通常,与任何GUI API一样,处理GUI事件将诱使您编写匿名类。 这是Swing的一个简单示例:
JButton button = new JButton("Save");
button.addActionListener(new ActionListener() { //anonymous class@Overridepublic void actionPerformed(ActionEvent e) {System.out.println("Button clicked");//Our button was clicked. Here we perform//everything needed to make the action//of clicking a button work.}
});
就是这样 我们最终传递了一个状态,一个对象,应该传递一种行为,一种方法的位置。 该代码比应该的更加冗长。
使用Wicket时,问题几乎相同:
AjaxFallbackLink<Void> link = new AjaxFallbackLink<Void>("linkId") {@Overridepublic void onClick(AjaxRequestTarget target) {System.out.println("Link clicked!");}
};
为了减轻处理GUI事件的痛苦,使用lambda表达式和几个帮助器类,我们可以在同一行代码中像上面这样编写相同的代码:
AjaxFallbackLink<Void> link = ComponentFactory.newAjaxLink("linkId", (target) -> System.out.println("Link clicked!"));
当然,大多数事件处理将需要的不仅仅是一个简单的“ System.out”。 因此,出于这个原因,最好将这些详细信息隐藏在同一类的私有方法中。 这是一个看起来更完整的代码示例:
public class MyPage extends WebPage {public MyPage(final PageParameters parameters) {super(parameters);AjaxFallbackLink<Void> link = ComponentFactory.newAjaxLink("linkId", (target) -> linkClick(target));}//this method is called in line 6private void linkClick(AjaxRequestTarget target) {//do a bunch of stuff here}
}
钉下来
和往常一样,我在GitHub上用完整的代码建立了一个小项目。 你可以在这里得到它。 代码虽然不多,但是我认为足够了,因此您可以创建一个自己的启用了lambda的API。
该项目由一个小的用例组成,该用例用于将用户插入到make make believe数据库中(该数据库实际上是一个ArrayList,如您在代码中看到的那样)。 看起来像这样。 丑陋,但功能强大:
那里没有神秘。 新插入的用户显示在下面的红色表格中,每个用户都有一个“编辑”链接。 现在让我们看一下代码。
首先,我们需要一些“功能接口” 。 首先,您可能会想使用JDK已经提供的功能接口 。 它们很多,而且确实确实可以满足您的需求。 问题是,作为序列化的怪胎,Wicket会抱怨它们都不是可序列化的 。 因此,我决定提出自己的建议:
提示: 如果您不知道Java的lambda是如何工作的,那么这一切都没有道理。 首先阅读本文 。
@FunctionalInterface
public interface AjaxAction extends Serializable { public abstract void onClick(AjaxRequestTarget target);
}
@FunctionalInterface
public interface FormAction extends Serializable { public abstract void onSubmit();
}
@FunctionalInterface
public interface StringSupplier extends Serializable {public String get();
}
很快我们将采取行动。 就像我之前说过的那样,请注意,它们都扩展了Serializable 。
动态标签
该页面的一个相当烦人的方面是某些标签必须根据我们正在执行的实际操作进行更改。 也就是说,如果我们正在编辑现有用户,则在顶部显示“ 插入用户”是没有意义的。 “ 编辑用户”标签更合适。 下面的“ 保存 ”按钮也可以更改为“ 更新 ”。 请记住这一点,因为这就是我创建StringSupplier功能接口的原因。
我使用的方法是使用单个HTML元素并根据需要更改其值,而不必在必要时隐藏和显示两个不同的元素。 为了提供一些观点,这是通常的做法:
<div style="text-align: center;"><h2 wicket:id="titleLabel">Insert User/Update User</h2>
</div>
titleLabel = new Label("titleLabel", new Model<String>() {@Overridepublic String getObject() {if (form.getModelObject().getId() == null) {return "Insert User";} else {return "Edit User";}}
});
我们将提供一个带有“匿名类”的标签作为模型。 然后, getObject()方法将根据“用户”(我们的实体)模型对象的当前状态来确定它是插入还是更新。 真麻烦
使用lambda,我的建议是这样的(HTML页面保持不变):
titleLabel = ComponentFactory.newLabel("titleLabel", () -> form.getModelObject().getId() == null ? "Insert User" : "Edit User");
add(titleLabel);
如您在第一行中看到的,我们有一个lambda,其表达式为三元运算符。 通常可以使用if / else语句来完成if,但是看起来很丑。 我已经向您展示了StringSupplier功能界面,现在该看一下我们的帮助器ComponentFactory类了。
顾名思义,它只是一个带有一些静态工厂方法的常规类来创建组件。 这是我们的newLabel()工厂方法的样子:
//Remember, StringSupplier is a functional interface that returns a String.public static Label newLabel(String wicketId, StringSupplier supplier) {Label label = new Label(wicketId, new Model<String>() {@Overridepublic String getObject() {return supplier.get();}});label.setOutputMarkupId(true);return label;
}
纽扣
现在到“保存/更新”按钮。 除了其标签也应根据表单的模型状态而改变的事实之外,我们还将使用lambda表达式来分配一个处理“单击事件”的方法。 通常,没有lambda,这就是我们要做的:
//this would go inside the class constructor
Button saveUpdateButton = new Button("saveUpdateButton") {@Overridepublic void onSubmit() {//saveUpdate(User) is a private method//in this very same classsaveUpdate(form.getModelObject());}
};
saveUpdateButton.add(new AttributeModifier("value", new Model<String>() {@Overridepublic String getObject() { return form.getModelObject().getId() == null ? "Save" : "Update";}
}));
form.add(saveUpdateButton);
//this is a private method inside the same class
private void saveUpdate(User user) {//Logic to insert or update an User.
}
我们创建了一个覆盖其onSubmit()方法的Button,然后附加了AttributeModifier行为来处理标签切换。 看起来我们有15行代码。 现在是lambda对应项:
Button saveUpdateButton = ComponentFactory.newButton("saveUpdateButton",() -> form.getModelObject().getId() == null ? "Save" : "Update",() -> saveUpdate(form.getModelObject()));
form.add(saveUpdateButton);
而已。 请注意,它很容易只有2行,但是由于第一条语句太长,因此我决定将其分成 3行。newButton()方法采用3个参数:wicket id和两个lambda表达式,分别为StringSupplier和FormAction 。 这是代码:
public static Button newButton(String wicketId, StringSupplier labelSupplier, FormAction action) {Button button = new Button(wicketId) {@Overridepublic void onSubmit() {action.onSubmit();}};AttributeModifier attrModifier = new AttributeModifier("value", new Model<String>() {@Overridepublic String getObject() { return labelSupplier.get();}});button.add(attrModifier);return button;
}
好吧,就是这样。 希望你喜欢它。 如果需要,请在下面留下问题。
- 您可以在此处获取源代码。
同样,您可以在此处找到有关lambda表达式的很好的介绍。
翻译自: https://www.javacodegeeks.com/2015/03/apache-wicket-with-lambda-expressions.html