SeamFramework.orgCommunity Documentation
Web Bean 參照實作(Web Beans Reference Implementation)開發於 the Seam project。您可藉由 the downloads page 來下載最新開發人員版本的 Web Bean。
Web Bean RI 包含了兩個可建置的範例應用程式:webbeans-numberguess
,這是個 war 範例,並且只包含著基本的 bean,以及 webbeans-translator
,這是個 ear 範例,並包含著企業級的 bean。若要執行這些範例,您將需要滿足下列需求:
最新版本的 Web Beans RI、
JBoss AS 5.0.0.GA,以及
Ant 1.7.0。
目前,Web Beans RI 只能在 JBoss Application Server 5 上執行。您將需要由 jboss.org 來下載 JBoss AS 5.0.0.GA,然後再將它解壓縮。例如:
$ cd /Applications $ unzip ~/jboss-5.0.0.GA.zip
接下來,請由 seamframework.org 下載 Web Beans RI 並將它解壓縮。例如
$ cd ~/ $ unzip ~/webbeans-$VERSION.zip
接下來,我們需要讓 Web Bean 知道 JBoss 的位置在哪裡。請編輯 jboss-as/build.properties
然後設置 jboss.home
內容。例如:
jboss.home=/Applications/jboss-5.0.0.GA
因為 Web Bean 是個新的軟體,您需要更新 JBoss AS 才可執行 Web Bean RI。未來版本的 JBoss AS 將會包含這些更新,因此這個步驟將可被忽略。
目前您需要兩個更新。首先一個新的建置器 webbeans.deployer
被新增了。這可為 JBoss AS 提供 Web Bean archive,並能讓 Web Bean RI 查詢 EJB3 container,並找出安裝在您應用程式中的 EJB 為何。接下來,您需要 JBoss EJB3 的更新。
若要安裝更新,您將需要先安裝 Ant 1.7.0,並設置 ANT_HOME
環境變數。例如:
$ unzip apache-ant-1.7.0.zip $ export ANT_HOME=~/apache-ant-1.7.0
接下來,您便可安裝更新。更新 script 將會使用 Maven 來自動地下載 Web Bean 以及 EJB3。
$ cd webbeans-$VERSION/jboss-as $ ant update
現在,您已準備好建置您的第一個範例!
這些範例的建置 script 提供了一些目標,它們包含了:
ant restart
- 以分解的格式來建置範例
ant explode
- 在不重新建置的情況下更新一個已分解的範例
ant deploy
- 以 jar 格式來建置範例
ant undeploy
- 將範例由伺服器中移除
ant clean
- 清除範例
若要建置 numberguess 範例:
$ cd examples/numberguess ant deploy
Start JBoss AS:
$ /Application/jboss-5.0.0.GA/bin/run.sh
If you use Windows, use the run.bat
script.
請等待應用程式的建置,然後在 http://localhost:8080/webbeans-numberguess 花上幾個小時!
Web Bean RI 包含了第二個基本範例,它可將您的文字轉譯為拉丁文。numberguess 範例為一個 war 範例,並且只使用基本的 bean;轉譯器範例則為 ear 範例,並且包含著企業級的 bean,封裝於一個 EJB 模組中。若要嘗試:
$ cd examples/translator ant deploy
請等待應用程式的建置並進入 http://localhost:8080/webbeans-translator!
在 numberguess 應用程式中,您將會有 10 次機會來猜一個介於 1 至 100 之間的號碼。每當猜過一遍,系統便會告知您您所輸入的數字是否太大或太小。
numberguess 範例包含了 Web Bean 的一個數字、配置檔案,以及 Facelet JSF 頁面,並且封裝為 war。讓我們先從配置檔案開始。
此範例的所有配置檔案都位於 WEB-INF/
中,並且它又儲存在來源樹中的 WebContent
裡。首先,我們有個可使用來指定 JSF 來使用 Facelet 的 faces-config.xml
:
<?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 Bean 應用程式。
最後為 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 the Web Beans RI 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
類別負責透過產生器的方式來建立亂數號碼。它也會透過一個產生器的方式來顯示最大的可能號碼:
@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 為 session 導向的 Game
。
您將會注意到我們使用了 @Named
標記,如此一來我們便可在 JSF 頁面中的 EL 上使用這個 bean。最後,我們使用了 constructor injection 來利用亂數號碼來初始化了這個遊戲。當然,當玩家贏時我們將需要告知玩家,並藉由一個 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
>(){});
}
}
轉譯器範例能接受您所輸入的任何句子,然後將它們翻譯成拉丁文。
轉換器範例被建置為一個 ear 並包含著 EJB。正因如此,它的結構比 numberguess 範例要複雜得多。
EJB 3.1 和 Jave EE 6 能讓您將 EJB 封裝為 war,並使得該結構變得更為簡樸!
首先,讓我們先來看一下 ear 聚合器,它位於 webbeans-translator-ear
模組中。Maven 會自動地為我們產生 application.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>
</configuration>
</plugin
>
在此我們將設置 context 路徑,它能提供給我們一個網址(http://localhost:8080/webbeans-translator)。
若您不使用 Maven 來產生這些檔案,那麼您將需要 META-INF/application.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。就和 numberguess 範例中一樣,我們在 WebContent/WEB-INF
中有個 faces-config.xml
(用來啟用 Facelets)以及一個 web.xml
(用來啟用 JSF)。
還有更有趣的就是使用來轉換文字的 facelet。就和 numberguess 範例中一樣,我們有個圍繞著 form 的頁面格式(在此將省略不提):
<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
中只有一個用來將 archive 標記為包含著 Web Bean 的空 web-beans.xml
。
我們將最有趣的部份保留到了最後,那就是程式碼!該專案含有兩個基本的 bean,SentenceParser
和 TextTranslator
,以及兩個企業級的 bean,TranslatorControllerBean
和 SentenceTranslator
。到了現在您應該已經很熟悉 Web Bean 長得如何了,因此我們在此將只著重於其它較有趣的部份。
SentenceParser
和 TextTranslator
兩者皆為相依性的 bean,並且 TextTranslator
使用了 constructor 初始化:
public class TextTranslator {
private SentenceParser sentenceParser;
private Translator sentenceTranslator;
@Initializer
TextTranslator(SentenceParser sentenceParser, Translator sentenceTranslator)
{
this.sentenceParser = sentenceParser;
this.sentenceTranslator = sentenceTranslator;
TextTranslator
是個無狀態的 bean(以及一個本地的商業介面)- 當然,我們無法開發一個完整的轉譯器。
最後,有個 UI 導向的控制器,它會藉由用戶收集文字然後將它發送給轉譯器。這是個請求導向、被命名,而有狀態的 session bean,並且會注入轉譯器。
@Stateful
@RequestScoped
@Named("translator")
public class TranslatorControllerBean implements TranslatorController
{
@Current TextTranslator translator;
這個 bean 針對於頁面上所有欄位都有 getter 與 setter。
因為這是個 stateful(有狀態)的 session bean,因此我們必須要有個 remove method:
@Remove
public void remove()
{
}
當 bean 被毀掉後,Web Bean 管理員會為您調用 remove 這個 method;在此情況下為請求結束之後。
這結束了我們簡短的 Web Bean RI 範例。如欲取得更多有關於 RI 的相關資訊,或是提供相關協助,請參閱 http://www.seamframework.org/WebBeans/Development。
我們在所有層面都需要協助 - 錯誤修正、編寫新功能、編寫範例,以及翻譯此參照指南。