无缝Wicket

发布者    |       Seam

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


回到顶部