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组件上的注解来控制会话、触发事件以及更多注入(包括出射)。