apache wicket
Apache Wicket是一个功能强大的,轻量级的基于组件的Web应用程序框架,将表示和业务逻辑高度分离。 它使您能够创建易于测试,调试和支持的高质量Web 2.0应用程序。 假设您必须扩展另一个团队提供的基于Wicket的应用程序而不更改其代码,或者您必须提供一个易于被其他团队扩展和定制的模块化Web应用程序。 本文介绍如何在没有冗余源代码,标记和配置的情况下解决此问题。 通过使用maven-war-plugin来合并项目,使用wicketstuff批注来动态安装Web页面,使用Spring框架作为控制反转(IoC)容器,由wicket-spring-annot项目提供动力以及对Maven进行微调来实现此目标。依赖性。
本文的目的是展示如何从头开始设计和构建高度模块化且可扩展的基于Wicket的Web应用程序。 将引导读者完成该过程的所有步骤,从编写初始Maven POM文件并选择所需的依赖项开始,并通过配置组件,自动装配服务和安装Web页面结束讨论。
本文包括两个由Maven管理的示例应用程序-Warsaw和Global。 第一个是具有两个简单网页的完全配置的Web应用程序。 第二个应用程序使用Warsaw项目作为依赖项,并引入了服务,几个新的网页以及从第一个应用程序复制的组件的修改版本。 这两个Web应用程序都打包为WAR文件,并配置为可在Jetty或任何其他servlet容器中工作。 通过从命令行运行mvn jetty:run-war可以轻松启动它们。
设想一种情况,您必须为基于Wicket应用程序框架构建的所提供Web应用程序创建自定义版本。 例如,您需要将一些指向外部资源的链接添加到主网页标题。 要实现此功能,您可以创建一个新的Wicket面板组件并将其实例添加到所需的网页。 如果它是应用程序主版本的功能,这听起来可能很简单。 但是,如果您有权访问现有应用程序的源代码和资源,但又不允许对应用程序进行任何功能更改,那么如何完成此任务? 这个问题可以通过几种方式解决。 本文将进一步讨论其中之一。
可以用Java编写的简单Web应用程序作为包含编译类,JSP和XML文件,静态网页和其他资源的单个WAR文件分发。 Maven使我们可以使用maven-war-plugin合并多个WAR文件。 我们需要做的就是在应用程序的pom.xml文件中将包装属性值设置为WAR,并使用另一个WAR工件作为依赖项。 在本文中,我们将使用两个示例应用程序-华沙(主)和全局(派生,取决于华沙项目)。 清单1中显示了Warsaw pom.xml文件的基本版本,清单2中显示了Global项目的基本版本。
清单1:华沙项目Maven pom.xml文件的基本版本。
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.modular</groupId>
<artifactId>warsaw</artifactId>
<packaging>war</packaging>
<version>1.0</version>
<name>Modular Wicket Warsaw Project</name>
<dependencies>
<!-- Warsaw project dependencies -->
</dependencies>
</project>
清单2:Global项目Maven pom.xml文件的基本版本,它依赖于Warsaw项目。
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.modular</groupId>
<artifactId>global</artifactId>
<packaging>war</packaging>
<version>1.0</version>
<name>Modular Wicket Global Project</name>
<dependencies>
<dependency>
<groupId>com.example.modular</groupId>
<artifactId>warsaw</artifactId>
<version>1.0</version>
<type>war</type>
</dependency>
</dependencies>
</project>
编译并打包两个项目后,即使Global项目没有任何类或资源,生成的WAR文件的内容也几乎相同(比较warsaw-1.0.war和global-1.0.war)。 重要的是,所有依赖库和配置都存在于两个归档中。
根据Java规范,我们不能在类路径上使用WAR文件。 在我们的情况下,这意味着在编译时无法在Global项目中访问Warsaw项目中定义的类,因此我们无法扩展它们或将它们用作常规类组件。 为了克服这个问题,我们必须通过覆盖maven-war-plugin的默认设置之一来对其进行微调,下面的清单3显示了该设置。
清单3:添加到Warsaw项目Maven pom.xml文件的配置。
<build>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<attachClasses>true</attachClasses>
</configuration>
</plugin>
<plugins>
<build>
启用attachClasses选项会导致将其他JAR文件(warsaw-1.0-classes.jar)与标准WAR文件一起安装到Maven存储库中。 要访问此工件,我们必须修改Global项目的依赖项列表,如清单4所示。
清单4:全局项目Maven pom.xml文件的修改后的依赖项
<dependencies>
<dependency>
<groupId>com.example.modular</groupId>
<artifactId>warsaw</artifactId>
<version>1.0</version>
<type>war</type>
</dependency>
<dependency>
<groupId>com.example.modular</groupId>
<artifactId>warsaw</artifactId>
<version>1.0</version>
<type>jar</type>
<classifier>classes</classifier>
<scope>provided</scope>
</dependency>
</dependencies>
如我们所见,Global项目使用Warsaw WAR创建最终的Web归档文件,并将其类打包为JAR进行编译。 通过将classifier属性设置为类,我们定义必须从存储库中选择哪个工件。 将范围设置为提供可告知Maven,仅在编译期间需要此工件,并且在运行时将从其他来源提供该工件。 这个“其他来源”当然是华沙项目的WAR工件,它将通过WAR插件与此项目合并。 现在,已经正确配置了依赖项,我们可以开始构建派生的Wicket应用程序。
要开始使用Apache Wicket冒险,建议构建和探索Apache Wicket QuickStart应用程序。 如果您发现此框架有用且有趣,我还建议您阅读《 Wicket in Action》一书。 在Wicket框架中,可以将网页安装在主应用程序类的init()方法中,该方法必须从org.apache.wicket.protocol.http.WebApplication继承。 这种技术非常常用,但有一个缺点。 如果此主应用程序类是在基础项目中定义的(在这种情况下为华沙),则我们无法在从属应用程序(全局)中添加新的网页。 当然,我们可以在另一个项目中再次扩展此类,但随后我们还应该修改web.xml文件中对该类的引用,如清单5所示。解决此问题的方法之一是引入一个自动运行的系统。在类路径上查找并安装本地化为JAR文件的Wicket网页。 在示例应用程序中,使用了WicketStuff的注释驱动解决方案。
清单5. Wicket QuickStart应用程序中web.xml文件的片段。
<filter>
<filter-name>wicket.base</filter-name>
<filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
<init-param>
<param-name>applicationClassName</param-name>
<param-value>com.example.modular.warsaw.WicketApplication</param-value>
</init-param>
</filter>
该软件包提供了智能安装机制,可通过使用@MountPath类注释和AnnotatedMountScanner实用程序简化添加和注册Wicket网页的过程。 如清单6和7所示,配置很简单。
清单6:WicketStuff AnnotatedMountScanner的用法示例。
// package and imports were here
public class WicketApplication extends WebApplication {
public Class
getHomePage() {
return HomePage.class;
}
@Override
protected void init() {
super.init();
new AnnotatedMountScanner().scanPackage("com.example.modular.**.pages").mount(this);
}
}
Wicketstuff-annotations项目使用Spring Framework PathMatchingResourcePatternResolver在类路径中查找匹配的资源。 在上面的示例中,此解析器搜索带有@MountPath批注的任何类,该类位于com.example.modular包内任何名为“ pages”的包中。
清单7:WicketStuff @MountPath注释的用法示例。
package com.example.modular.warsaw.pages;
import org.apache.wicket.markup.html.WebPage;
import org.wicketstuff.annotation.mount.MountPath;
@MountPath(path = "warsaw")
public class WarsawPage extends WebPage {
// we don't need any extra stuff at this point
}
通过使用这种技术,我们可以在华沙和Global项目中定义和安装网页。 Maven WAR插件保证部署的Global项目将在与Warsaw项目相同的目录结构中包含所有这些类。 AnnotatedMountScanner确保网页正确安装,即使它们位于单独的程序包中,例如在com.example.modular.warsaw.pages和com.example.modular.global.pages中。 但是,如果我们在com.example.modular.warsaw.pages包中的Global项目中创建网页,该怎么办? 在这种情况下,存在此页面可能会意外覆盖华沙项目中已定义的具有相同名称的其他页面的风险。 另一方面,这种行为可以帮助我们从全局项目级别修改华沙项目的组件来解决问题。
在一般情况下,使用Maven WAR插件覆盖类,配置或其他资源听起来确实是个坏主意。 在大多数情况下是这样。 但是,在极少数情况下,没有其他简单的选择。 如果快速搜索Wicket Web应用程序的源代码,我们会发现大多数Wicket组件都是使用new关键字实例化的。 这是一种常用技术,被认为是标准做法。 那么我们如何从派生项目的角度修改这些类的行为呢? 大概我们想到的第一个想法是使用Control的Spring Inversion容器将组件注入特定的Web页面,并尝试使用内置的bean替换机制。 听起来不错,但是在我们阅读的wicket-spring项目Wiki网站上,“从IOC容器注入依赖项的大多数问题来自以下方面-wicket是不受管理的框架(并且)wicket组件和模型经常被序列化”。 简而言之,这意味着Wicket无法管理其组件的生命周期,而序列化可能会导致一些严重的问题,例如在集群期间。 即使我们找到解决此问题的方法,那么XHTML标记文件又如何呢? 每个模板文件都与一个特定的Java类文件相关联。 例如,/com/example/modular/pages/WarsawPage.html与com.example.modular.pages.WarsawPage类紧密绑定。 为了解决这个问题,我们还需要一种机制来正确处理这些关联。 例如,它可以动态替换和实例化类,并与负责绑定标记文件的Wicket机制进行交互。 单独使用此机制可能是新文章的好话题,因此我们将在此处跳过。
如我们所见,此问题确实使扩展我们的应用程序的过程复杂化。 正如我在本文开头所写,我们可以尝试使用maven-war-plugin的默认覆盖功能,并希望基本项目不会经常被修改。
在Global项目中,我们看到maven-war-plugin覆盖了Warsaw项目中的文件,而没有任何确认对话框或警告。 这些是插件的默认设置,在这种情况下是需要的。 要查看其在现实生活中的工作方式,请参阅随附的示例应用程序代码。
Spring是一个非常强大且有用的框架,我们可以在基于Wicket的应用程序中利用它。 wicket-spring项目的贡献者在提供Spring集成机制方面做得很出色,该机制可以轻松地用于基于Wicket的Web应用程序中。 它提供了几种使用Spring IoC容器将依赖项注入Web组件的方法。 在本文提供的示例应用程序中(华沙和全球),选择了基于注释的方法。 不幸的是,它不能用于注入Wicket组件,但是可以将服务注入这些组件。
要充分利用此功能,首先我们需要编辑Warsaw应用程序servlet配置文件以使用Wicket和Spring。 清单8中最有趣的部分是带有两个参数的contextConfigLocation的定义。 第一个WEB-INF / applicationContext.xml定义了主应用程序上下文,其中定义了Wicket WebApplication类bean。 在此文件中,我们还可以定义可以在应用程序中使用的服务或DAO bean。 其次,classpath *:META-INF / example / extra-ctx.xml指出,如果在META-INF / example目录结构中的类路径的任何地方都存在一个名为extra-ctx.xml的文件,则它也是一个应用程序带有其他Spring Bean定义的上下文文件。 更重要的是,华沙项目的servlet配置文件web.xml也用于Global项目,因此将在Warsaw项目,Global项目以及这些应用程序使用的任何jar文件中搜索extra-ctx.xml文件。 这就是为什么Global项目几乎没有必要的Web应用程序配置文件的原因。 为了显示其工作原理,Global项目引入了一个名为RandomTzService的示例服务。 该服务只有一种方法,该方法返回随机选择的时区的标识符。 在我们的应用程序中,基于注释的方法用于注入Spring Bean。
清单8:华沙应用程序的web.xml文件片段。
<context-param>
<description>Spring Context</description>
<param-name>contextConfigLocation</param-name>
<param-value>
<string>WEB-INF/applicationContext.xml</string>
<string>classpath*:META-INF/example/extra-ctx.xml</string>
</param-value>
</context-param>
<servlet>
<servlet-name>WebClientApplication</servlet-name>
<servlet-class>org.apache.wicket.protocol.http.WicketServlet</servlet-class>
<init-param>
<param-name>applicationFactoryClassName</param-name>
<param-value>org.apache.wicket.spring.SpringWebApplicationFactory</param-value>
</init-param>
</servlet>
清单9:包含批注服务本地化的全局应用程序extra-ctx.xml文件片段。
<context:annotation-config />
<context:component-scan base-package="com.example.modular.global.service" />
RandomTzService的实现已放置在com.example.modular.global.service包中,并带有Spring的@Service注释。 根据清单9的定义,可以自动找到它。 要在应用程序中使用此服务,我们需要做的就是使用Spring的自动装配机制,并在应使用@Autowired标注注入该bean的地方标注字段。 首先,在Web应用程序类中,我们必须添加一个组件实例化侦听器,该侦听器负责将依赖项注入Wicket组件中。 听起来很复杂,但是wicket-spring-annot项目提供了完成所有这些工作的SpringComponentInjector类。 清单10显示了此代码。
清单10:华沙项目的主要应用程序类,其中包括Spring Bean注入机制和基于注释的网页扫描器的用法示例。
// package and imports were here
import org.apache.wicket.spring.injection.annot.SpringComponentInjector;
import org.wicketstuff.annotation.scan.AnnotatedMountScanner;
public class WicketApplication extends WebApplication {
@Override
protected void init() {
super.init();
addComponentInstantiationListener(new SpringComponentInjector(this));
new AnnotatedMountScanner().scanPackage("com.example.modular.**.pages").mount(this);
}
// other methods
}
要将服务注入Wicket组件类中,我们必须使用@SpringBean注释对正确类型的字段进行注释,该注释也在wicket-spring-annot项目中进行了定义。 实例化此组件后,SpringComponentInjector会使用此批注查找字段,并在需要时注入依赖项。 我们不必担心注入的依赖项的序列化,因为它们表示为序列化的代理,并且会自动完成。 在使用这种方法时,我们必须记住,该机制仅支持基于访问者的注入,不支持基于构造函数参数的注入。
现在,当我们设置了所有主要的构建块时,就可以开始使用Web 2.0组件来增强我们的应用程序。 Wicket框架对AJAX具有良好的本机支持,尽管该技术是可选的。 默认情况下,Wicket更喜欢传统的请求,但是向新的和现有的组件添加AJAX支持既简单又轻松。 甚至可以创建动态网页而无需编写一行JavaScript代码。 用户仍然可以使用常规js脚本,并将JavaScript函数调用添加到各个Wicket组件。 这以及将CSS动态添加到页面的过程,都是通过Java代码以编程方式完成的。
Wicket框架附带了一组可重用的AJAX行为和组件。 最简单的示例是AjaxFallbackLink。 此链接也可以在禁用或不支持JavaScript的Web浏览器中使用。 在这种情况下,通过单击链接可以重新加载整个页面。 如清单11所示,创建传统链接非常简单。 这个示例类是一个带有链接的Wicket面板,我们可以单击它,并带有一个标签,该标签显示单击此链接的次数。
清单11:带有经典链接的Wicket面板。
// package was here
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.PropertyModel;
public class ClassicApproach extends Panel {
private int clickCount = 0;
public ClassicApproach(String pId) {
super(pId);
add(new Label("clickLabel", new PropertyModel
(this, "clickCount")));
add(new Link
("link") {
@Override
public void onClick() {
clickCount++;
}
});
}
}
当用户单击此链接时,整个网页将重新加载。 在许多情况下,我们希望在后台执行此操作,并且仅更新或更改页面的一部分。 可以使用AJAX轻松完成,如清单12所示。
清单12:带有AJAX链接的Wicket面板。
// package was here
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxFallbackLink;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.PropertyModel;
public class AjaxApproach extends Panel {
private int clickCount = 0;
public AjaxApproach(String pId) {
super(pId);
final Label label = new Label("clickLabel", new PropertyModel
(this, "clickCount"));
label.setOutputMarkupId(true);
add(label);
add(new AjaxFallbackLink
("link") {
@Override
public void onClick(AjaxRequestTarget pTarget) {
clickCount++;
if (pTarget != null) {
pTarget.addComponent(label);
}
}
});
}
}
比较这两种方法时,我们看到只有几处发生了变化。 在AJAX链接的onClick方法中,我们收到一个AjaxRequestTarget对象。 它用于标识将在AJAX请求中更新的组件。 如果我们使用的Web浏览器不支持JavaScript,则AjaxRequestTarget对象将为null。 除此之外,源代码几乎相同,并且在两种情况下都可以使用清单13中所示的XHTML标记。 仅需几行Java代码,我们就可以使用一个可工作的网页组件,而无需刷新整个页面即可对其进行更新。 借助内置的Wicket AJAX引擎,我们不必编写单个JavaScript代码块或手动链接JavaScript库。 所有必需JavaScript函数均自动在后台添加。
下面的清单13显示了封装在HTML span标签中的Wicket标签。 如果Web浏览器支持JavaScript,则仅此标记的内容将被更新。
清单13:标记代码,显示链接(经典或AJAX)被单击的次数。
<a href="#" wicket:id="link">This link</a> has been clicked <span wicket:id="clickLabel">[link label]</span> times.
要查看Wicket AJAX支持的更多示例,请参阅Global Project中的时区面板。 其中之一使用AJAX行为负责给定组件的定期更新。 如清单14所示,向Wicket组件添加这种行为是微不足道的。
清单14:负责相关组件的定期更新的AJAX行为。
someWicketComponent.add(new AjaxSelfUpdatingTimerBehavior(Duration.seconds(1)));
Wicket库的示例部分提供了一些Wicket AJAX组件的出色示例。 这些微型应用程序已部署,因此我们不必下载它们即可找到它们的功能。 还包括Java源代码和XHTML标记文件。
现代Java Web框架的重要功能之一是能够对表示层进行单元测试,而不必将Web应用程序部署到容器中。 Wicket使用WicketTester帮助器类支持单元测试,该类直接在表示类上工作。 与协议级别的测试框架(如JWebUnit或HtmlUnit)相比,我们可以完全控制页面和单个组件,可以在servlet容器之外对它们进行隔离和单元测试。 这种方法使带有功能测试的测试驱动设计(TDD)成为可能,快速且可靠。
使用WicketTester创建和运行单元测试既快速又简单,如下所示。
清单15:使用JUnit和WicketTester的简单Wicket单元测试。
// package and imports were here
import junit.framework.TestCase;
import org.apache.wicket.util.tester.WicketTester;
public class MyHomePageTest extends TestCase {
public void testRenderPage() {
WicketTester tester = new WicketTester();
tester.startPage(MyHomePage.class);
tester.assertRenderedPage(MyHomePage.class);
}
}
在此示例中,WicketTester创建一个虚拟Web应用程序以进行测试。 在实际的应用程序中,我们更有可能需要在Wicket应用程序类的具体实例上进行操作。 例如,在华沙和全球项目中,我们严重依赖Spring来安装网页和注册服务。 因此,我们可以对所有与Wicket相关的单元测试使用基本测试类。
清单16:华沙和Global项目的Wicket单元测试的基本测试类。
package com.example.modular;
import junit.framework.TestCase;
import org.apache.wicket.spring.injection.annot.SpringComponentInjector;
import org.apache.wicket.spring.injection.annot.test.AnnotApplicationContextMock;
import org.apache.wicket.util.tester.WicketTester;
import org.springframework.context.ApplicationContext;
import com.example.modular.warsaw.WicketApplication;
public abstract class BaseTestCase extends TestCase {
protected WicketTester tester;
protected ApplicationContext mockAppCtx;
protected WicketApplication application;
@Override
public void setUp() {
mockAppCtx = new AnnotApplicationContextMock();
application = new WicketApplication();
SpringComponentInjector sci = new SpringComponentInjector(application, mockAppCtx);
application.setSpringComponentInjector(sci);
tester = new WicketTester(application);
}
}
在清单16中,我们看到创建了模拟应用程序上下文以及标准的Wicket应用程序实例。 一切设置完成后,我们就可以开始测试页面组件了。 WicketTester提供了单击链接,填写和提交表单,检查标签或任何其他组件等方法。 这些方法大多数都将组件ID作为第一个参数。 对于嵌入式组件,冒号用于分隔每个组件。
清单17:WicketTester帮助器方法的用法示例。
// open page for testing
tester.startPage(InfoPage.class);
// check if page is rendered
tester.assertRenderedPage(InfoPage.class);
// check class of a given component
tester.assertComponent("leftPanel", LeftTextPanel.class);
// check if label is properly displayed
tester.assertLabel("leftPanel:header", "My info page");
// get Wicket component by name
Component someLink = tester.getComponentFromLastRenderedPage("someLink");
// click a link
tester.clickLink("leftPanel:redirectLink");
// check if page has changed
tester.assertRenderedPage(AfterRedirectPage.class);
Wicket还提供了一个称为FormTester的实用程序类,专用于测试表单。 此类允许我们以编程方式设置文本字段,复选框和单选按钮的值,甚至可以在下拉框中选择值。 文件上传动作以及常规表单提交的模拟也是可能的。
清单18:FormTester帮助器方法的用法示例。
// open page for testing
tester.startPage(MyFormPage.class);
tester.assertComponent("form", TheForm.class);
// check status label
tester.assertLabel("status", "Please fill the form");
// prepare form tester
FormTester formTester = tester.newFormTester("form");
// check are name and age fields empty
assertEquals("", formTester.getTextComponentValue("name"));
assertEquals("", formTester.getTextComponentValue("age"));
// fill name and age fields
formTester.setValue("name", "Bob");
formTester.setValue("age", "30");
// submit form
formTester.submit("submitButton");
// check if status label has changed
tester.assertLabel("status", "Thank you for filling the form");
也可以在单元测试中测试表单验证(清单19显示了表单验证测试代码)。
清单19:使用WicketTester和FormTester来测试空表单提交的结果。
// check if there are no error messages
tester.assertNoErrorMessage();
// reset name and age fields
formTester.setValue("name", "");
formTester.setValue("age", "");
// submit empty form
formTester.submit("submitButton");
// check if proper error messages are shown
tester.assertErrorMessages(new String[] {"Field 'name' is required.", "Field 'age' is required."});
Wicket测试实用程序的有趣功能之一是可以测试与网页隔离的单个组件。 想象一下这种情况,网页由多个面板组成,例如leftPanel,centerPanel,页眉和页脚。 这些组件中的每一个都由不同类的实例表示。 在页面级别,我们可以测试每个面板是否可见以及它们之间的通信是否正确处理。 如果在多个网页上使用了相同的组件,那么我们应该对其进行独立测试。 在这种情况下,我们可以使用WicketTester#startPanel(Panel)方法,如清单20所示。
清单20:使用WicketTester帮助器方法测试隔离面板
// create panel for testing
tester.startPanel(new TestPanelSource(){
public Panel getTestPanel(String pId) {
return new CenterPanel(pId);
}
});
// check if header label is displayed properly
tester.assertLabel("panel:header", "This is center panel");
通过使用Wicket的TestPanelSource类,我们可以为测试目的延迟初始化给定的面板。 执行完此操作后,我们可以开始测试其特定行为。 我们必须记住,此组件是使用panel作为组件ID实例化的,因此要访问其子组件,我们必须使用panel:作为ID前缀。
测试Wicket网页和组件并非难事。 该框架提供了实用程序类,可用于测试内容呈现,导航和数据流。 当然,为丰富的组件编写单元测试需要一些经验,时间和精力,但这是应用程序开发的重要组成部分。 在测试驱动的开发中,与团队成员执行的手动测试相比,应该首先编写自动化测试。
我们可以在Apache Wiki页面上找到一些有关单元测试的有用技巧。 《 Wicket in Action》一书还包含有关测试的部分,可以用作该主题的良好起点。
提供了所有这些信息后,您应该自己尝试使用Wicket框架。 在本文中,为简单起见,省略了一些主要主题,例如组件模型和安全性。 幸运的是,在线上有几篇关于Wicket的介绍文章和其他指南。 了解Wicket用户的流行做法总是很高兴的。
首先,对面向对象编程的良好理解至关重要。 在每个Wicket应用程序源代码中,您都可以找到匿名内部类。 该技术有助于敏捷开发,而无需创建仅在一个组件中使用的许多具体类。 另一方面,当它们深深地嵌套时,可能看起来确实令人困惑。 特别是当我们收到由名为SomeClass $ 2 $ 2 $ 1的类引起的异常时。 我们还可以使用封装和继承向现有页面和组件添加新行为。 如果没有扎实的面向对象设计背景,我们很快就会迷失在对象,关系和类的世界中。
众所周知,Wicket是一个基于组件的框架。 每个组件都由一个Java类和一组具有相同名称但文件扩展名不同的文件表示。 这些是标记,CSS和消息资源。 默认情况下,所有这些文件都放在同一目录结构中。 如果我们正在开发的应用程序中包含丰富的专用组件,并且包含多个网页,那么我们可能要管理的文件数量可能会让您不知所措。 没有解决此问题的简便方法,但是将Java源代码与其他资源分开是一个好习惯。 这也有助于将应用程序逻辑与表示逻辑分离,因为整个页面逻辑仅以Java类的形式包含。
如果我们看一下Wicket的API,那么我们将看到,它是大量不同的类和方法。 该框架带有大量现成的组件,行为和实用程序,但是在许多情况下,这是Wicket学习曲线陡峭的主要原因。 与Struts或JSF相比,这是完全不同的,在Struts或JSF中,您可以找到许多有关这些技术的书。 如果您对此主题感兴趣,可以在Matt Raible主页上找到一些不错的演示,以比较不同的Java Web框架。 他们只有一两年的历史,但是其中包含的大多数信息仍然有用和有效。
如果我们在Internet上搜索基于Java平台构建的Web应用程序框架,则可能会发现至少有十二个可以满足我们大多数需求。 我们应该选择哪个选项通常取决于Web应用程序要求和我们的个人喜好。 如本文所示,Wicket是一个受良好支持的框架,其中包含许多有用且易于使用的扩展。 构建高度模块化的应用程序只是两个或三个组件的基本设置。 请参考提供的示例应用程序源代码,以了解它们在现实生活中如何协同工作。 您需要安装的只是JDK 1.5或更高版本以及Maven2。请享受模块化Wicket。
apache wicket