SeamFramework.orgCommunity Documentation
Web Bean参考实现由Seam项目开发。你可以从the downloads page下载最新的开发者版本。
Web Beans RI自带了两个例子:webbeans-numberguess
(一个仅包含一个简单Bean的WAR应用例子)和webbeans-translator
(一个包含企业Bean的EAR应用例子)。为了运行例子,你需要:
最新的Web Bean参考实现版本,
JBoss AS 5.0.0.GA, 和
Apache Tomcat 6.0.X,和
Ant 1.7.0.
当前,Web Beans参考实现只能运行在JBoss AS 5之上。你需要从jboss.org下载JBoss AS 5.0.0.GA, 然后解压。例如:
$ cd /Applications $ unzip ~/jboss-5.0.0.GA.zip
然后从seamframework.org下载Web Beans的参考实现,然后解压。例如:
$ cd ~/ $ unzip ~/webbeans-1.0.0.ALPHA1.zip
然后,我们需要告诉Web Beans JBoss的位置。编辑jboss-as/build.properties
,设置jboss.home
属性。例如:
jboss.home=/Applications/jboss-5.0.0.GA
为了安装更新,你需要安装Ant 1.7.0,设置ANT_HOME
环境变量。例如:
$ unzip apache-ant-1.7.0.zip $ export ANT_HOME=~/apache-ant-1.7.0
然后,你需要安装更新,更新脚本使用Maven来自动下载Web Beans和EJB3。
$ cd webbeans-1.0.0.ALPHA1/jboss-as $ ant update
现在,你可以部署你的第一个例子了!
例子的构建脚本包含多个目标:
ant restart
- 以exploded形式部署例子
ant explode
- 无需重新部署,更新一个exploded形式部署的例子
ant deploy
- 以压缩jar包形式部署例子
ant undeploy
- 将例子从服务器中移除
ant clean
- 清除例子
部署猜数字(numberguess)例子:
$ cd examples/numberguess ant deploy
启动 JBoss AS:
jboss.home=/Applications/jboss-5.0.0.GA
如果你使用Windows操作系统,则使用run.bat
脚本。
等待应用部署完毕,好好体验一下http://localhost:8080/webbeans-numberguess!
Web Bean参考实现的第二个简单例子能够将你的文本翻译为拉丁文。猜数字例子是一个WAR应用,仅仅使用了一个简单Beans;翻译器例子是一个EAR应用,包含了打包在EJB模块中的企业Beans。试一下:
$ cd examples/traslator ant deploy
等待应用部署,试一下http://localhost:8080/webbeans-translator!
然后从seamframework.org下载Web Beans的参考实现,然后解压。例如:
$ cd /Applications $ unzip ~/jboss-5.0.0.GA.zip
然后从seamframework.org下载Web Beans的参考实现,然后解压。例如:
$ cd ~/ $ unzip ~/webbeans-1.0.0.ALPHA1.zip
然后,我们需要告诉Web Beans JBoss的位置。编辑jboss-as/build.properties
,设置jboss.home
属性。例如:
jboss.home=/Applications/jboss-5.0.0.GA
例子的构建脚本包含多个目标:
ant restart
- 以exploded形式部署例子
ant explode
- 无需重新部署,更新一个exploded形式部署的例子
ant deploy
- 以压缩jar包形式部署例子
ant undeploy
- 将例子从服务器中移除
ant clean
- 清除例子
部署猜数字(numberguess)例子:
$ cd examples/traslator ant deploy
启动Tomcat:
jboss.home=/Applications/jboss-5.0.0.GA
如果你使用Windows操作系统,则使用run.bat
脚本。
等待应用部署完毕,好好体验一下http://localhost:8080/webbeans-numberguess!
在猜数字应用中,你有十次机会来猜一个1到100之间的数字。每次猜测之后,应用都会告诉你你猜的数字是高了还是低了。
猜数字应用由Web Beans,配置文件,Facelete JSF页面组成,打包为一个WAR。我们先看一下配置文件。
猜数字应用的所有的配置文件位于WEB-INF/
,这个目录位于源码树的WebContent
中。首先,我们在faces-config.xml文件中告诉JSF使用Faceletes:
<?xml version='1.0' encoding='UTF-8'?>
<faces-config version="1.2"
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-facesconfig_1_2.xsd">
<application>
<view-handler
>com.sun.facelets.FaceletViewHandler</view-handler>
</application>
</faces-config
>
这有一个空的web-beans.xml
文件,标识这个应用是一个Web Beans应用。
最后,这有一个 web.xml
:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" 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"> <display-name >Web Beans Numbergues example</display-name> <!-- JSF --><servlet> <servlet-name >Faces Servlet</servlet-name> <servlet-class >javax.faces.webapp.FacesServlet</servlet-class> <load-on
-startup >1</load-on-startup> </servlet> <servlet-mapping> <servlet
-name >Faces Servlet</servlet-name> <url-pattern >*.jsf</url-pattern> </servlet-mapping>
<context-param> <param-name >javax.faces.DEFAULT_SUFFIX</param-name> <param-v
alue >.xhtml</param-value> </context-param> <session-config> <session-timeout >10</session-timeout> </session-config> </web-app >
![]() | Enable and load the JSF servlet |
![]() | Configure requests to |
![]() | Tell JSF that we will be giving our source files (facelets) an extension of |
![]() | Configure a session timeout of 10 minutes |
Whilst this demo is a JSF demo, you can use Web Beans with any Servlet based web framework.
Let's take a look at the Facelet view:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:s="http://jboss.com/products/seam/taglib"> <ui:composition template="template.xhtml"> <ui:define name="content"> <h1 >Guess a number...</h1> <h:form
id="NumberGuessMain"> <div style="color: red"> <h:messages id="messages" globalOnly="false"/> <h:outputText id="Higher" value="Higher!" rendered="#{game.number gt game.guess and game.guess ne 0}"/> <h:outputText id="Lower" value="Lower!" rendered="#{game.number lt game.guess and game.guess ne 0}"/> </div> <div
> I'm thinking of a number between #{game.smallest} and #{game.biggest}. You have #{game.remainingGuesses} guesses. </div> <div> Y
our guess: <h:inputText id="inputGuess" value="#{game.guess}" required="true" size="3"
disabled="#{game.number eq game.guess}"> <f:validateLongRange maximum="#{game.biggest}" minimum="#{game.smallest}"/> <
/h:inputText> <h:commandButton id="GuessButton" value="Guess" action="#{game.check}" disabled="#{game.number eq game.guess}"/> </div> <div> <h:commandButton id="RestartButton" value="Reset" action="#{game.reset}" immediate="true" /> </div> </h:form> </ui:define> </ui:composition> </html >
![]() | Facelets is a templating language for JSF, here we are wrapping our page in a template which defines the header. |
![]() | There are a number of messages which can be sent to the user, "Higher!", "Lower!" and "Correct!" |
![]() | As the user guesses, the range of numbers they can guess gets smaller - this sentance changes to make sure they know what range to guess in. |
![]() | This input field is bound to a Web Bean, using the value expression. |
![]() | A range validator is used to make sure the user doesn't accidentally input a number outside of the range in which they can guess - if the validator wasn't here, the user might use up a guess on an out of range number. |
![]() | And, of course, there must be a way for the user to send their guess to the server. Here we bind to an action method on the Web Bean. |
这个例子包括4个类,前面两个是绑定类型。首先,这有一个@Random
绑定类型,用来注入一个随机数:
@Target( { TYPE, METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
@Documented
@BindingType
public @interface Random {}
这还有一个@MaxNumber
绑定类型,用来注入一个最大值:
@Target( { TYPE, METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
@Documented
@BindingType
public @interface MaxNumber {}
Generator
类通过一个生产者(producer)方法创建一个随机数。它也通过一个生产者方法暴露可能的最大值:
@ApplicationScoped
public class Generator {
private java.util.Random random = new java.util.Random( System.currentTimeMillis() );
private int maxNumber = 100;
java.util.Random getRandom()
{
return random;
}
@Produces @Random int next() {
return getRandom().nextInt(maxNumber);
}
@Produces @MaxNumber int getMaxNumber()
{
return maxNumber;
}
}
你会注意到Generator
是应用范围的;因此我们不会每次都得到一个不同的随机对象。
最终的应用中的Web Bean是会话范围的 Game
。
你也许注意到我们使用了 @Named
注释,以便我们能够通过EL(表达式语言)在JSF页面中使用Bean。最后,我们通过构造器注入来初始化猜数字游戏并给它设一个随机数。当然,在玩家猜对数字后,我们需要告诉玩家他赢了,所以我们通过FacesMessage
反馈给玩家一条信息。
package org.jboss.webbeans.examples.numberguess;
import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.webbeans.AnnotationLiteral;
import javax.webbeans.Current;
import javax.webbeans.Initializer;
import javax.webbeans.Named;
import javax.webbeans.SessionScoped;
import javax.webbeans.manager.Manager;
@Named
@SessionScoped
public class Game
{
private int number;
private int guess;
private int smallest;
private int biggest;
private int remainingGuesses;
@Current Manager manager;
public Game()
{
}
@Initializer
Game(@MaxNumber int maxNumber)
{
this.biggest = maxNumber;
}
public int getNumber()
{
return number;
}
public int getGuess()
{
return guess;
}
public void setGuess(int guess)
{
this.guess = guess;
}
public int getSmallest()
{
return smallest;
}
public int getBiggest()
{
return biggest;
}
public int getRemainingGuesses()
{
return remainingGuesses;
}
public String check()
{
if (guess
>number)
{
biggest = guess - 1;
}
if (guess<number)
{
smallest = guess + 1;
}
if (guess == number)
{
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Correct!"));
}
remainingGuesses--;
return null;
}
@PostConstruct
public void reset()
{
this.smallest = 0;
this.guess = 0;
this.remainingGuesses = 10;
this.number = manager.getInstanceByType(Integer.class, new AnnotationLiteral<Random
>(){});
}
}
在Tomcat中部署猜数字应用有很多地方不同。首先,WebBean应该作为一个Web应用库文件,部署在WEB-INF/lib
目录中。为方便起见,我们提供了一个单一的jar库 webbeans-tomcat.jar
,能够让我们在Tomcat中运行Web Bean。
当然,你必须也要包含JSF和EL, 以及通用的注释(jsr250-api.jar
),这些都是一个Java EE服务器默认应该包含的。
第二,我们需要在web.xml
中显式地指定Tomcat的Servlet监听器(用来启动Web Bean,并且控制其与请求的交互):
<listener> <listener-class >org.jboss.webbeans.environment.tomcat.Listener</listener-class> </listener >
翻译器例子能够将你输入的句子翻译为拉丁文。
翻译器例子是一个EAR应用,包含EJBs和企业Beans。因此,它的结构比猜数字例子复杂。
EJB3.1和Java EE 6允许你在WAR包中打包EJBs, 这将让这个结构更加简单!
首先,让我们看一下EAR聚合器,它位于webbeans-translator-ear
模块下。Maven将为我们自动生成application.xml
和jboss-app.xml
文件:
<plugin>
<groupId
>org.apache.maven.plugins</groupId>
<artifactId
>maven-ear-plugin</artifactId>
<configuration>
<modules>
<webModule>
<groupId
>org.jboss.webbeans.examples.translator</groupId>
<artifactId
>webbeans-translator-war</artifactId>
<contextRoot
>/webbeans-translator</contextRoot>
</webModule>
</modules>
<jboss>
<loader-repository
>webbeans.jboss.org:loader=webbeans-translator</loader-repository>
</jboss>
</configuration>
</plugin
>
我们需要在这里做些事情-首先我们需要设置上下文路径为一个不错的URL(http://localhost:8080/webbeans-translator),我们还需要将JBoss AS的类加载器隔离配置激活。
如果你不使用Maven来生成这些文件,你将需要META-INF/jboss-app.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<application 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/application_5.xsd"
version="5">
<display-name
>webbeans-translator-ear</display-name>
<description
>Ear Example for the reference implementation of JSR 299: Web Beans</description>
<module>
<web>
<web-uri
>webbeans-translator.war</web-uri>
<context-root
>/webbeans-translator</context-root>
</web>
</module>
<module>
<ejb
>webbeans-translator.jar</ejb>
</module>
</application
>
然后,我们看一下WAR包。在猜数字例子中,我们需要faces-config.xml
(配置Facelets)和一个位于WebContent/WEB-INF
下的web.xml
(配置JSF并将Web Beans服务加入Servlet容器中)。
更有意思的是用来翻译文本的facelet。在猜数字应用中我们有一个模板,这个模板套着表单(省略了表单):
<h:form id="NumberGuessMain">
<table>
<tr align="center" style="font-weight: bold" >
<td>
Your text
</td>
<td>
Translation
</td>
</tr>
<tr>
<td>
<h:inputTextarea id="text" value="#{translator.text}" required="true" rows="5" cols="80" />
</td>
<td>
<h:outputText value="#{translator.translatedText}" />
</td>
</tr>
</table>
<div>
<h:commandButton id="button" value="Translate" action="#{translator.translate}"/>
</div>
</h:form
>
用户可以在左手边的文本区输入一些文本,点击翻译按钮查看右边的翻译结果。
最后,我们看一下EJB模块,webbeans-translator-ejb
。在src/main/resources/META-INF
下有两个配置文件,一个是空的web-beans.xml
,用来标识这个档案包包含Web Beans,一个是ejb-jar.xml
。Web Beans为所有的EJB提供注入和初始化服务,使用ejb-jar.xml
文件来配置。你将在使用Web Beans的EJB项目中需要这些配置:
我们将最有意思的部分放在最后,那就是代码!这个例子有两个简单Beans, SentanceParser
和TextTranslator
,还有两个企业Beans,TanslatorControllerBean
和SentenceTranslator
。现在你应该对Web Beans有点熟悉了,我们在这里着重最有意思的部分。
SentanceParser
和TextTranslator
是相互依赖的Beans,TextTranslator
使用构造器初始化:
public class TextTranslator {
private SentenceParser sentenceParser;
private Translator sentenceTranslator;
@Initializer
TextTranslator(SentenceParser sentenceParser, Translator sentenceTranslator)
{
this.sentenceParser = sentenceParser;
this.sentenceTranslator = sentenceTranslator;
TextTranslator
是一个无状态Bean(拥有一个本地业务接口),这里是魔术展现的地方-当然,我们不会开发一个完整的翻译器,但我们可以开发一个不错的小玩意!
最后,这里又要一个面向UI的控制器,从用户输入处搜集文本,转发给翻译器。这个控制器是请求范围的,具名的,有状态的会话Bean,它可以将翻译器注入进来。
@Stateful
@RequestScoped
@Named("translator")
public class TranslatorControllerBean implements TranslatorController
{
@Current TextTranslator translator;
这个Bean也拥有页面上所有域的getter和setter方法。
这个Bean是有状态会话Bean,我们需要有一个remove方法:
@Remove
public void remove()
{
}
Web Beans管理器在这个bean销毁的时候调用remove方法;在这个例子中是请求结束的时候。
Web Beans参考实现的例子到此结束。想要获得关于参考实现更多的知识或者帮助,请访问http://www.seamframework.org/WebBeans/Development。
我们在各个方面都需要帮助-bug修复,新特性开发,例子开发和参考指南的翻译等等。