Seam 2.1.0.BETA1 将 Wicket 支持带到了 Seam,但您如何使用这项支持呢?
在本教程的第一部分,我们将讨论如何创建一个 seam-wicket 项目,以及如何将 Seam 组件注入到 Wicket 组件中。后续教程将更深入地介绍如何使用 Seam 协调 Wicket 应用程序。
首先,让我们使用 seam-gen 设置一个新的项目,这将为我们创建一个骨架项目。尽管 seam-gen 旨在与 JSF 一起使用,但我们可以轻松地自定义它创建的项目以与 Wicket 一起使用。
$ ./seam setup
Buildfile: build.xml
init:
setup:
[echo] Welcome to seam-gen :-)
[input] Enter your Java project workspace (the directory that contains your Seam projects) [C:/Projects] [C:/Projects]
/workspace
[input] Enter your JBoss home directory [C:/Program Files/jboss-4.2.3.GA] [C:/Program Files/jboss-4.2.3.GA]
/Applications/jboss-4.2.3.GA
[input] Enter the project name [myproject] [myproject]
wicket-tutorial
[echo] Accepted project name as: wicket_tutorial
[input] Do you want to use ICEfaces instead of RichFaces [n] (y, [n])
n
[input] skipping input as property icefaces.home.new has already been set.
[input] Select a RichFaces skin [blueSky] ([blueSky], classic, ruby, wine, deepMarine, emeraldTown, japanCherry, DEFAULT)
ruby
[input] Is this project deployed as an EAR (with EJB components) or a WAR (with no EJB support) [ear] ([ear], war)
war
[input] Enter the Java package name for your session beans [com.mydomain.wicket_tutorial] [com.mydomain.wicket_tutorial]
<ENTER>
[input] Enter the Java package name for your entity beans [com.mydomain.wicket_tutorial] [com.mydomain.wicket_tutorial]
<ENTER>
[input] Enter the Java package name for your test cases [com.mydomain.wicket_tutorial.test] [com.mydomain.wicket_tutorial.test]
<ENTER>
[input] What kind of database are you using? [hsql] ([hsql], mysql, oracle, postgres, mssql, db2, sybase, enterprisedb, h2)
<ENTER>
[input] Enter the Hibernate dialect for your database [org.hibernate.dialect.HSQLDialect] [org.hibernate.dialect.HSQLDialect]
<ENTER>
[input] Enter the filesystem path to the JDBC driver jar [../lib/hsqldb.jar] [../lib/hsqldb.jar]
<ENTER>
[input] Enter JDBC driver class for your database [org.hsqldb.jdbcDriver] [org.hsqldb.jdbcDriver]
<ENTER>
[input] Enter the JDBC URL for your database [jdbc:hsqldb:.] [jdbc:hsqldb:.]
<ENTER>
[input] Enter database username [sa] [sa]
<ENTER>
[input] Enter database password [] []
<ENTER>
[input] Enter the database schema name (it is OK to leave this blank) [] []
<ENTER>
[input] Enter the database catalog name (it is OK to leave this blank) [] []
<ENTER>
[input] Are you working with tables that already exist in the database? [n] (y, [n])
n
[input] Do you want to drop and recreate the database tables and data in import.sql each time you deploy? [n] (y, [n])
y
[propertyfile] Creating new property file: /workspace/seam/seam-gen/build.properties
[echo] Installing JDBC driver jar to JBoss server
[copy] Copying 1 file to /Applications/jboss-4.2.3.GA/server/default/lib
[echo] Type 'seam create-project' to create the new project
BUILD SUCCESSFUL
Total time: 44 seconds
接下来,我们需要创建项目
$ ./seam create-project
现在,我们需要修改项目以支持 Wicket。首先,让我们删除 JSF 特定的配置文件/resources/WEB-INF/pages.xml, /resources/WEB-INF/faces-config.xml, /view/*.xhtml和/view/*.page.xml。接下来,我们需要编辑/resources/WEB-INF/web.xml以删除 JSF Servlet、其映射以及任何 JSF、Facelets 和 RichFaces 配置参数。您最终应该得到一个类似的 web.xml
<?xml version="1.0" ?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<listener>
<listener-class>org.jboss.seam.servlet.SeamListener</listener-class>
</listener>
<filter>
<filter-name>Seam Filter</filter-name>
<filter-class>org.jboss.seam.servlet.SeamFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Seam Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>Seam Resource Servlet</servlet-name>
<servlet-class>org.jboss.seam.servlet.SeamResourceServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Seam Resource Servlet</servlet-name>
<url-pattern>/seam/resource/*</url-pattern>
</servlet-mapping>
</web-app>
最后,我们需要将 wicket 库和 seam-wicket 集成库添加到项目中。首先,从 Seam 分发的jboss-seam-wicket.jar从/lib/目录复制到您项目的/lib/目录。然后,确保 wicket 库被部署到存档中,首先从jsf-facelets.jar和文件中删除各种 Seam-JSF 集成库/deployed-jars.list,并添加jboss-seam-wicket.jar和wicket.jar的条目。文件现在应包含以下列表
antlr-runtime.jar core.jar drools-compiler.jar drools-core.jar janino.jar jboss-el.jar jboss-seam.jar jboss-seam-wicket.jar jboss-seam-debug.jar jbpm-jpdl.jar mvel14.jar slf4j-log4j12.jar slf4j-api.jar wicket.jar
现在是一个很好的时候,更新您的 IDE 以反映您正在使用的库。您可能需要使用 IDE 的项目构建路径屏幕编辑 IDE 的类路径。
现在让我们设置项目中的源目录。我们需要将具有 Seam 超能力的 Wicket 组件部署到特殊目录/WEB-INF/wicket,这样 Seam 就可以抓住它们并增强它们。不幸的是,这有点棘手,因为您需要修改 Ant 构建脚本。
首先,创建一个新的源目录,称为/src/web我们将使用它来存储Wicket视图。然后,我们需要修改构建脚本,以便将编译后的类复制到/WEB-INF/wicket,你可以添加这个目标
<target name="compileweb"
depends="init"
description="Compile the Wicket views from java source code">
<mkdir dir="${war.dir}/WEB-INF/wicket"/>
<!-- Compile the Wicket classes -->
<javac classpathref="build.classpath"
destdir="${war.dir}/WEB-INF/wicket"
debug="${javac.debug}"
deprecation="${javac.deprecation}"
nowarn="on">
<src path="src/web" />
</javac>
<!-- Copy the html markup to the same location -->
<copy todir="${war.dir}/WEB-INF/wicket">
<fileset dir="src/web">
<include name="**/*.html"/>
</fileset>
</copy>
</target>
并确保它被运行,通过添加compileweb作为war目标的依赖项
<target name="war"
depends="compilemodel,compileactions, compileweb, copyclasses"
description="Build the distribution .war file">
提示 你可能想创建一个名为compile的目标,它依赖于compilemodel, compileactions, compileweb, copyclasses然后让war目标依赖于compile,如果这个更改已经在Seam中完成。
Wicket使用一个类来配置应用程序(类似于JSF中的/WEB-INF/faces-config.xml);因此,在我们可以将应用程序部署到服务器之前,我们需要在com.mydomain.wicket_tutorial.web包中创建以下类,位于src/web目录下
public class TutorialApplication extends SeamWebApplication {}
我们通过向Seam组件描述符(即/resources/WEB-INF/components.xml)中添加组件定义来告诉Wicket使用此类。首先,添加wicket命名空间
<components xmlns="http://jboss.com/products/seam/components" ... xmlns:wicket="http://jboss.com/products/seam/wicket">
然后通过添加以下组件定义来配置Wicket应用程序
<wicket:web-application application-class="com.mydomain.wicket_tutorial.web.TutorialApplication"/>
现在我们可以开始实际开发了。首先,让我们为Wicket定义一个主页;我们现在将创建一个非常简单的页面。首先,我们需要一些html来布局和样式化我们的页面
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
</head>
<body>
<div style="font-weight:bold">
<p wicket:id="replace">Wicket will replace this text at runtime.</p>
</div>
</body>
</html>
Wicket中的每个页面都伴随着一个在Java中匹配的组件树。以下类与刚刚创建的主页相匹配
public class HomePage extends WebPage {
public HomePage(PageParameters parameters) {
add(new Label("replace", "Hello World!"));
}
}
最后,我们需要告诉Wicket使用我们的主页作为应用程序的起始页面
public class TutorialApplication extends SeamWebApplication {
@Override
public Class getHomePage() {
return HomePage.class;
}
...
}
诚然,设置Wicket项目花费了一些时间,但现在我们已经完成了,我们可以开始将Seam添加到项目中。
提示 对于那些敢于尝试并且可能熟悉Ant和Freemarker的人来说,我们鼓励你修改seam-gen模板来创建自己的Wicket启动应用程序。这样,你就永远不必再次重复这些步骤。
现在,让我们使应用程序做一些有趣的事情。我们将在主页添加一个登录框并使用Seam验证器来验证用户。以下是一个典型的Wicket登录表单可能的样子
<div style="border: 1px solid black; width: 400px; padding: 3px">
<form wicket:id="login">
<div>
<label for="username">Username</label>
<input wicket:id="username" />
</div>
<div>
<label for="password">Password</label>
<input wicket:id="password" type="password" />
</div>
<div>
<input type="submit" value="Login"/>
</div>
</form>
</div>
当然,我们还需要在Java中构建一个匹配的组件树
public class HomePage extends WebPage {
public HomePage(PageParameters parameters) {
add(new Label("replace", "Hello World!"));
add(new LoginForm("login"));
}
public class LoginForm extends Form {
public LoginForm(String id) {
super(id);
add(new TextField("username"));
add(new PasswordTextField("password"));
}
}
}
注意Wicket标签如何充当插槽,Java代码可以注入真正的UI组件。但我们是如何捕获用户使用Wicket驱动的登录表单提交的信息的呢?这是Wicket真正发光的地方。我们不需要触摸html页面。我们只需操作Java组件就可以得到我们想要的结果。首先,让我们注入identitySeam组件,并告诉Wicket在表单提交时调用authenticate()。此时,我们并没有查看用户输入的值。
public class LoginForm extends Form {
@In Identity identity;
@Logger log log;
public LoginForm(String id) {
super(id);
add(new TextField("username"));
add(new PasswordTextField("password"));
}
protected void onSubmit() {
try {
identity.authenticate();
log.info("Login succeeded");
setResponsePage(HomePage.class);
} catch (LoginException e) {
log.info("Login failed");
error("Login failed");
}
}
}
当用户提交表单时,Wicket会调用onSubmit()回调方法。在其中,我们告诉Wicket在登录成功时将我们重定向回当前页面,或者在登录失败时引发错误。注意我们如何使用与在常规Seam应用程序中注入Seam组件时完全相同的注解,包括@Logger注解。有关Seam绑定机制的更多信息,请参阅Seam参考文档中的绑定部分。
剩下的事情是将输入控件绑定到内置Seam组件的username和password属性,即credentials,这样我们就可以在登录过程中访问用户提交的值。为此,我们注入该组件并使用WicketcredentialsPropertyModel进行绑定:
public class LoginForm extends Form {
@In Identity identity;
@In Credentials credentials;
public LoginForm(String id) {
super(id);
add(new TextField("username", new PropertyModel(credentials, "username")));
add(new PasswordTextField("password", new PropertyModel(credentials, "password")));
}
...
}
现在,尝试使用用户名admin进行登录,并查看控制台 - 你会看到登录成功的消息被打印出来。(seam-gen 2.1项目的默认验证器类要求用户名为admin,密码为空)。
使用Seam与Wicket的介绍到此结束。在本教程中,我们探讨了创建新的Seam项目、移除JSF视图层并将其替换为Wicket,以及使用注入从Wicket访问我们的Seam组件。在下一教程中,我们将探讨使用Wicket组件上的注解来控制会话、触发事件以及更多注入(包括出射)。