带Lambda表达式的Apache Wicket

这是怎么回事? :)

我一直在从事一些项目,这些项目值得庆幸的是将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)之间,这要归因于renderrender等所有方面。 另一方面,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表达式,分别为StringSupplierFormAction 。 这是代码:

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/360867.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

React 父组件和子组件中的方法相互调用

目录父组件调用子组件方法子组件调用父组件方法父组件调用子组件方法 父组件中调用子组件的getTree方法 父组件 setFormValue()>{this.TreeList.getTree}<TreeList onSelect{this.setFormValue} onRef{(ref) > { this.TreeList ref }} />子组件 componentDidMount…

元素在父元素内垂直居中的思路

1.使用表格 的垂直居中特性 2.div的绝对定位 已知高度的情况下比较好弄. 3.用背景实现.前景元素visibility:hidden; 4.父元素table-cell 5.line-height 图片会跟随文字垂直居中.转载于:https://www.cnblogs.com/fumj/archive/2013/03/27/2984623.html

装饰者模式如何拯救了我的一天

在工作中&#xff0c;我正在处理庞大的Java代码库&#xff0c;该代码库是由许多不同的开发人员在15年的时间里开发的。 并不是所有的事情都由书来完成&#xff0c;但是同时我通常没有机会重构遇到的每一个奇怪之处。 尽管如此&#xff0c;仍可以每天采取提高代码质量的措施。 …

【虚拟主机篇】asp页面实现301重定向方法

301重定向在很多地方都需要用到&#xff0c;也是seo中常见的问题。比如确定首选域或更换网站域名的时候都要用到301重定向。301重定向的方法有好几种&#xff0c;拿ASP类网站来说有&#xff1a;首页301重定向和全站301重定向。 首页301重定向的方法&#xff1a; <% website…

快速的骆驼和云消息传递

Apache Camel是一个流行的&#xff0c;成熟的开源集成库。 它实现了企业集成模式 &#xff0c;这是在集成分布式系统时经常出现的一组模式。 过去&#xff0c;我写过很多关于Camel的文章&#xff0c; 包括为什么我比Spring Integration更喜欢它 &#xff0c; 路由引擎 如何 工作…

antd react dva在model中使用另一个model的state值

const oldData yield select(({ baseDictionary }) > {return ([...customPageSetting.list,]) });

三角形类1

/* 程序的版权和版本声明部分 Copyright (c)2012, 烟台大学计算机学院学生 All rightsreserved. 文件名称&#xff1a; object.cpp 作者&#xff1a;刘清远 完成日期&#xff1a; 2013年3月29日 版本号&#xff1a; v1.0 输入描述&#xff1a;无 问题描述&#xff1a;设计求三…

不可将您的方法命名为“等于”

&#xff08;当然&#xff0c;除非您确实重写了Object.equals() &#xff09;。 我偶然发现了用户Frank的一个非常奇怪的Stack Overflow问题 &#xff1a; 为什么Java的Area&#xff03;equals方法不能覆盖Object&#xff03;equals&#xff1f; 有趣的是&#xff0c;有一个A…

C#GRPC 服务端与客户端通信,故障排除记录

文章目录前言一、问题一解决方法二、问题二解决方法前言 第一次建立GRPC服务端&#xff0c;客服端一直通不到服务端&#xff1b; 问题1&#xff1a; One or more errors occurred. (Status(StatusCodeInternal, Detail"Error starting gRPC call. HttpRequestException:…

青禾BBS数据库查询语句(动网)

数据字典&#xff1a;http://files.cnblogs.com/ahauzyy/dvbbs.rar 查询用户信息: SELECT * FROM dbo.Dv_User WHERE UserName茗迹 查询用户发帖总数: SELECT UserTopic FROM dbo.Dv_User WHERE UserName茗迹 查询用户被删的帖子数&#xff1a; SELECT UserDel FROM dbo.Dv_Us…

EE JSP:Servlet的反向外套

仅当页面数量少或需要精确控制生成的内容&#xff08;二进制PDF等&#xff09;时&#xff0c;才可以从Servlet生成HTML。 对于大多数应用程序&#xff0c;输出将是HTML&#xff0c;我们需要一种更好的方法来完成此操作。 这就是JSP&#xff08;Java服务器页面&#xff09;出现的…

moment 24小时与12小时区别

moment(values.data).format(YYYY-MM-DD HH:mm:ss)--------------24小时 moment(values.data).format(YYYY-MM-DD hh:mm:ss)--------------12小时主要取决于format中的时分秒的大小写

android 自定义xml属性

Android 自定义组件 Android 提供了非常精致的和非常强大的组件化模型&#xff0c;能够更加方便的构建UI,这些UI组件都是基于基本的layout类:View 和 ViewGroup。 部分能够用的widgets包括&#xff1a;Button&#xff0c;TextView,EditText,ListView,CheckBox&#xff0c;Radio…

Neo4j:带密码的TF / IDF(和变体)

几周前&#xff0c;我写了一篇博客文章&#xff0c;介绍了如何使用scikit-learn在HIMYM成绩单上运行TF / IDF&#xff0c;以按情节找到最重要的短语&#xff0c;然后我很好奇在Neo4j中很难做到。 我首先将Wikipedia的TF / IDF示例之一翻译为cypher&#xff0c;以查看该算法的外…

验证码的设计,随机数的生成

只要将charNum改变就可以自定义设计生成随机数的个数。 //获取验证码的代码 void GetValidateCode() { validStr ""; Random rd new Random(); //创建随机数对象 //产生由 charNum 个字母或数字组成的一个字符串 …

There are multiple modules with names that only differ in ca

react antd 警告错误 原因&#xff1a;引用组件的大小写 // 原代码&#xff1a; import AddOrEditFrom from /components/Process/AddOrEditFrom; // 修改后代码 import AddOrEditFrom from /components/Process/AddOrEditFrom;

每个人都必须阅读的10篇Java文章

一个月前&#xff0c;我们发布了每个人都必须阅读的10篇SQL文章列表。 我们相信jOOQ博客上的文章列表将为我们的读者带来非凡的价值。 jOOQ博客是同时关注Java和SQL的博客&#xff0c;因此&#xff0c;一个月后的今天&#xff0c;我们发布了同样令人兴奋的10条Java文章列表&…

LeetCode: Longest Common Prefix

string.erase没掌握好&#xff0c;悲了个剧&#xff0c;2次过 1 class Solution {2 public:3 string longestCommonPrefix(vector<string> &strs) {4 // Start typing your C/C solution below5 // DO NOT write int main() function6 s…

React antd Descriptions span属性无效问题

label“Status” span{3}&#xff0c;但是span为3无效 <Descriptions title"User Info" layout"vertical" bordered><Descriptions.Item label"Product">Cloud Database</Descriptions.Item><Descriptions.Item label&quo…

如何在生产中检测和诊断慢速代码

开发人员面临的最困难的任务之一是查找和诊断生产中运行缓慢的代码。 首先&#xff0c;您如何监控生产代码而不放慢速度&#xff1f; 当然&#xff0c;您无法通过分析器运行生产代码。 即使您具有计时代码的机制&#xff0c;那么如何诊断问题呢&#xff1f; 如果您无法在开发环…