The Java Persistence API offers a powerful standard for persisting POJOs.It includes all the most important features which you would expect from an object-relational mapping tool, but there are still some areas where you might need to use vendor-specific features. In this tutorial, we will show how to use Hibernate-specific features for validating and querying while using the standard API for the rest.
This tutorial assumes you have some basic knowledge of, or programming experience with, the following technologies:
This tutorial is partly based on the Using Hibernate With Java Persistence API tutorial, you might want to go through it first.
Before you begin, you need to install the following software on your computer:
First we will create a library in the IDE for the Hibernate entity manager.
<property name="hibernate.dialect" value="org.hibernate.dialect.DerbyDialect" />
Now we can quickly generate JSF pages for the entity classes with the NetBeans IDE CRUD generation.
At this point we will try to run the application and see whether everything is working as expected.
When creating a new customer you might have noticed that values were not validated before attempting to persist the newly created customer. We could use the validation facilities in JSF for ensuring that only correct values are inserted, but since this tutorial is about Hibernate we will instead demonstrate how to use the Hibernate validation framework. This approach has an additional advantage that the validation rules need to be specified only once even if another type of client is added.
Open Customer.java in the editor and add the following annotations on its member variables:
@Column(name = "STATE") @Length(min=2, max=2, message="not a valid state") private String state; @Column(name = "EMAIL") @Email private String email;For simplicity's sake we will only add validation to state and email properties. The @Length annotation validates that the length of the property will be within the range specified by min and max attributes. We apply it on the state property to make sure that it is exactly 2 characters long. We also specify a value for the message attribute, it will be the shown error message when the validation fails. The @Email annotation in turn validates that the property represents a valid email address, as you might have guessed.
Now that we have our domain object annotated, we need to add handling of validation errors to our controller class. So open CustomerController.java and add the following method there:
/** * Validates the given customer. * @return true if there were no validation errors, false otherwise. */ private boolean validate(Customer customer){ ClassValidator customerValidator = new ClassValidator(Customer.class); // get the invalid values InvalidValue[] msgs = customerValidator.getInvalidValues(customer); if (msgs.length > 0){ for(InvalidValue msg : msgs){ // add an error message for each invalid value, these // messages will be shown to the user addErrorMessage(msg.getMessage()); } return false; } return true; }This method will first create a class validator for our Customer class and then process the validation rules we specified earlier when. We collect the invalid value messages and add each of them as error messages to the FacesContext (this is done by the addErrorMessage method). If there were no validation errors the will return true, false otherwise. Of course, as such this method is not very useful unless we invoke it in the right places. We probably want to validate the values both when a new customer is created and when an existing customer is edited. So let's first modify the create method to check whether there were any validation errors before attempting to persist:
public String create() { if (!validate(customer)){ // return to the input page if there were any validation errors return null; } EntityManager em = getEntityManager(); try { utx.begin(); em.joinTransaction(); em.persist(customer); ...
As you can see, we return null if any errors were found - this means JSF will display the same page again. Make a similar modification to the edit method as well and run the application. Try to create a new customer with an invalid email address and with a 3 characters long state code. This is what you should see:
While the Java Persistence QL is an impressive query language, there are cases when a different kind of API is more suitable. Luckily, in addition to JPQL support, Hibernate features a criteria query API which you can leverage for the cases it is needed and stick to the standard API elsewhere in the application. In the following example we will demonstrate the Query By Example approach using Hibernate's Criteria API.
First we need to create a new page for our new query functionality. Create a new page named Query.jsp in the customer folder and paste the following to it:
<%@page contentType="text/html"%> <%@page pageEncoding="UTF-8"%> <%@taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <%@taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Query By Example</title> </head> <body> <f:view> <h1>Query By Example</h1> <h:messages errorStyle="color: red" infoStyle="color: green" layout="table"/> <h:form> <h:panelGrid columns="2"> <h:outputText value="Zip:"/> <h:inputText id="zip" value="#{customer.customer.zip}" converter="stringConverter" title="Zip" /> <h:outputText value="Name:"/> <h:inputText id="name" value="#{customer.customer.name}" converter="stringConverter" title="Name" /> <h:outputText value="State:"/> <h:inputText id="state" value="#{customer.customer.state}" converter="stringConverter" title="State" /> </h:panelGrid> <h:commandLink action="#{customer.queryByExample}" value="Search"/> </h:form> <h:form> <a href="/HibernateWithJPA/index.jsp">Back to index</a> <br> <h:dataTable value='#{customer.model}' var='item' border="1" cellpadding="2" cellspacing="0"> <h:column> <f:facet name="header"> <h:outputText value="CustomerId"/> </f:facet> <h:commandLink action="#{customer.detailSetup}" value="#{item.customerId}"/> </h:column> <h:column> <f:facet name="header"> <h:outputText value="Zip"/> </f:facet> <h:outputText value="#{item.zip}"/> </h:column> <h:column> <f:facet name="header"> <h:outputText value="Name"/> </f:facet> <h:outputText value="#{item.name}"/> </h:column> <h:column> <f:facet name="header"> <h:outputText value="Addressline1"/> </f:facet> <h:outputText value="#{item.addressline1}"/> </h:column> <h:column> <f:facet name="header"> <h:outputText value="Addressline2"/> </f:facet> <h:outputText value="#{item.addressline2}"/> </h:column> <h:column> <f:facet name="header"> <h:outputText value="City"/> </f:facet> <h:outputText value="#{item.city}"/> </h:column> <h:column> <f:facet name="header"> <h:outputText value="State"/> </f:facet> <h:outputText value="#{item.state}"/> </h:column> <h:column> <f:facet name="header"> <h:outputText value="Phone"/> </f:facet> <h:outputText value="#{item.phone}"/> </h:column> <h:column> <f:facet name="header"> <h:outputText value="Fax"/> </f:facet> <h:outputText value="#{item.fax}"/> </h:column> <h:column> <f:facet name="header"> <h:outputText value="Email"/> </f:facet> <h:outputText value="#{item.email}"/> </h:column> <h:column> <f:facet name="header"> <h:outputText value="CreditLimit"/> </f:facet> <h:outputText value="#{item.creditLimit}"/> </h:column> <h:column> <f:facet name="header"> <h:outputText value="DiscountCode"/> </f:facet> <h:outputText value="#{item.discountCode}"/> </h:column> <h:column> <h:commandLink value="Destroy" action="#{customer.destroy}"> <f:param name="customerId" value="#{item.customerId}"/> </h:commandLink> <h:outputText value=" "/> <h:commandLink value="Edit" action="#{customer.editSetup}"> <f:param name="customerId" value="#{item.customerId}"/> </h:commandLink> </h:column> </h:dataTable> </h:form> </f:view> </body> </html>There are a couple of things to note here. Firstly, we have specified "stringConverter" converter for the input fields. Secondly, the 'search' link will try to execute customer.queryByExample method, which we haven't yet implemented. Thirdly, the data table uses customer.model as its underlying model. We will get back to these in a minute, but before that we still need to create a link to our new page. To keep things simple, we will just add it to the customer/List.jsp page, right after the link to the New Customer page:
<h:commandLink action="#{customer.createSetup}" value="New Customer"/> <br> <h:commandLink action="#{customer.querySetup}" value="Query Customers"/>
Now, this link will cause querySetup method to be invoked in the CustomerController.java, so let's implement it next. To do that, add the following to the CustomerController.java:
public String querySetup(){ this.customer = new Customer(); this.model = null; return "customer_query"; }
And to complete the UI side of things, we still need to add a navigation rule to faces-config.xml:
<navigation-rule> <navigation-case> <from-outcome>customer_query</from-outcome> <to-view-id>/customer/Query.jsp</to-view-id> </navigation-case> </navigation-rule>
What is still missing is the actual implementation of the query, and the converter we mentioned earlier. Let's tackle the implementation of the query method first. In the Query.jsp page we defined that the 'Search' link will invoke customer.queryByExample method and that customer.model will be used for the data table. To satisfy the latter, we just need to create a getter for the model in CustomerController.java - press ctrl-space and choose 'create getter getModel for field model'. After that, add the following method:
/** * Queries customers based on the values in our <code>customer</code>. */ public String queryByExample(){ // get the native hibernate session Session session = (Session) getEntityManager().getDelegate(); // create an example from our customer, exclude all zero valued numeric properties Example customerExample = Example.create(customer).excludeZeroes(); // create criteria based on the customer example Criteria criteria = session.createCriteria(Customer.class).add(customerExample); // perform the query and set the result to our model. this.model = new ListDataModel(criteria.list()); return "customer_query"; }
You can see how easily you can access Hibernate's native API - just invoke getDelegate() on the entity manager and cast it to org.hibernate.Session. Once we have the access to Session we can take advantage of the Criteria API. In the above method we create an example criteria based on the customer and execute the query. If you are not familiar with the Criteria API, it is probably worth explaining a bit. By default, all null values will be excluded, which means that the properties on our customer that were null, will not be part of the criteria. In addition, we specify that all zero valued numeric properties will be excluded as well. Here it gets a bit complicated: since JSF by default converts strings without values to empty strings (instead of nulls), we need to create a special converter for dealing with the conversion of strings from the query page. The implementation of the converter is as simple as:
package sample.controller; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.faces.convert.Converter; /** * A converter for string values that does not * convert <code>null</code> values to empty strings. */ public class StringConverter implements Converter{ /** Creates a new instance of StringConverter */ public StringConverter() { } public Object getAsObject(FacesContext context, UIComponent component, String value) { if(value == null || "".equals(value)){ return null; } return value; } public String getAsString(FacesContext context, UIComponent component, Object value) { return value != null ? value.toString() : null; } }
Don't forget to register the converter in faces-config.xml:
<converter> <converter-id>stringConverter</converter-id>> <converter-class>sample.controller.StringConverter</converter-class> </converter>
Finally, we are ready to run the application once again and test the new functionality:
Download the source code for this tutorial here
HibernateWithJPA.zip | ![]() |
46352 bytes |
jsf-from-entities.JPG | ![]() |
50178 bytes |
list-of-customers.JPG | ![]() |
185621 bytes |
not-valid-customer.JPG | ![]() |
32670 bytes |
query-by-example.JPG | ![]() |
81683 bytes |
query-by-example.PNG | ![]() |
152412 bytes |
query-by-example.png | ![]() |
152355 bytes |
jsf-from-entities.png | ![]() |
151411 bytes |
list-of-customers.png | ![]() |
314586 bytes |
not-valid-customer.png | ![]() |
84493 bytes |
One of the main features of the new Java Persistence API that was introduced with the Java EE 5 platform is that you can plug in any persistence provider that you want. The Sun Java System Application Server 9 ships with Oracles's Toplink persistence provider. In this tutorial, we will install the Hibernate persistence provider on the application server and use it to develop a quick application that accesses a database with the Java Persistence API.
Before we start, we have to register the application server with the IDE and copy over the Hibernate JAR files to the application server's lib folder. We also have to create a library in the IDE for the Hibernate entity manager.
Now that we have added the Hibernate libraries to the lib directory of our application server, we can create the entity classes and web interface. We will create a web application named HibernateApp with entity classes and a JSF interface. We will use the NetBeans CRUD facilities.
<persistence-unit name="HibernateApp" transaction-type="JTA"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <jta-data-source>jdbc/sample</jta-data-source> <properties> <property name="hibernate.show_sql" value="true" /> </properties> </persistence-unit> </persistence>
Now we can quickly generate JSF pages for the entity classes with the NetBeans IDE CRUD generation.
Open CustomerController.java and DiscountCodeController.java in the Source Editor. Each of the files contains create, edit and destroy methods with the following code:
EntityManager em = getEntityManager(); try { utx.begin();
Modify the code in each of the methods to change the order in which we get the entity manager.
EntityManager em = null; try { utx.begin(); em = getEntityManager();
For example, the modified code in the create method of CustomerController.java should look like the following (changes in bold):
public String create() { EntityManager em = null; try { utx.begin(); em = getEntityManager(); em.persist(customer); utx.commit(); ...
After creating the JSF pages and modifying the code in the controller classes, you should be able to run and test the application.
Now we need to run the project to test whether the connection to our database is working correctly.
For more information about using NetBeans IDE 5.5 to develop Java EE applications, see the following resources:
To send comments and suggestions, get support, and keep informed on the latest developments on the NetBeans IDE Java EE development features, join the nbj2ee@netbeans.org mailing list.
Java API for XML Web Services (JAX-WS) 2.0,JSR 224 是 Java EE 5 平臺(tái)的重要組成部分。作為 Java API for XML-based RPC 1.1 (JAX-RPC) 的后續(xù)發(fā)行版本,JAX-WS 簡(jiǎn)化了使用 Java 技術(shù)開發(fā) Web 服務(wù)的工作。并且通過對(duì)多種協(xié)議(如 SOAP 1.1、SOAP 1.2、XML)的支持,以及提供用于支持其他協(xié)議和 HTTP 的工具,它解決了 JAX-RPC 1.1 中存在的一些問題。JAX-WS 使用 JAXB 2.0 提供數(shù)據(jù)綁定服務(wù),并支持通過定制來控制生成的服務(wù)端點(diǎn)接口。通過對(duì)標(biāo)注的支持,JAX-WS 簡(jiǎn)化了 Web 服務(wù)開發(fā),并縮小了運(yùn)行時(shí) JAR 文件的大小。
本文檔向您介紹了有關(guān)使用 IDE 開發(fā) JAX-WS Web 服務(wù)以及在三個(gè)不同的客戶端(Java SE 應(yīng)用程序中的 Java 類、Web 應(yīng)用程序中的 Servlet 或 JSP 頁(yè))中使用該服務(wù)的基礎(chǔ)知識(shí)。在本文檔中創(chuàng)建的三個(gè)客戶端是獨(dú)立的應(yīng)用程序,它們都使用同一個(gè) Web 服務(wù)。
預(yù)計(jì)持續(xù)時(shí)間:25 分鐘
在開始之前,您需要在計(jì)算機(jī)中安裝以下軟件:
如果尚未注冊(cè) Sun Java System Application Server 9.0 的實(shí)例,則必須先進(jìn)行注冊(cè),然后才可以著手開發(fā) Java EE 5 應(yīng)用程序:
注意:也可以部署到 Tomcat Web Server,但由于它僅具有一個(gè) Web 容器,因此應(yīng)在下一部分創(chuàng)建 Web 應(yīng)用程序,而不是 EJB 模塊。與 JSR-109 Web 服務(wù)不同的是,JAX-WS Web 服務(wù)可以成功地部署到 Tomcat Web 容器中。
本練習(xí)的目的是創(chuàng)建一個(gè)適用于您決定使用的部署容器的項(xiàng)目。在建立項(xiàng)目后,您將在其中創(chuàng)建 Web 服務(wù)。
您可以在 Web 容器或 EJB 容器中部署 Web 服務(wù)。這要取決于具體的選擇。例如,如果您計(jì)劃部署到僅具有 Web 容器的 Tomcat Web Server 上,則應(yīng)該選擇創(chuàng)建 Web 應(yīng)用程序,而不是 EJB 模塊。
將在“項(xiàng)目”窗口中顯示新建的 Web 服務(wù)。例如,對(duì)于 Web 應(yīng)用程序,現(xiàn)在“項(xiàng)目”窗口將如下所示:
IDE 將自動(dòng)創(chuàng)建服務(wù)器所需的部署描述符(如果有)。對(duì)于 Sun Java System Application Server,則不需要部署描述符。對(duì)于部署到 Tomcat Web Server 的 Web 服務(wù),將添加 sun-jaxws.xml 以及 web.xml 中的 WSServlet 項(xiàng)。
在本練習(xí)中,您創(chuàng)建了一個(gè) NetBeans 項(xiàng)目并建立了 Web 服務(wù)。
本練習(xí)的目的是對(duì) IDE 生成的文件和代碼執(zhí)行一些有意義的操作。您將添加一個(gè)操作,該操作將從客戶端接收到的兩個(gè)數(shù)字相加起來。
@WebMethod public int add(@WebParam(name = "i") int i, @WebParam(name = "j") int j) { // TODO implement operation return 0; }
@WebMethod public int add(@WebParam(name = "i") int i, @WebParam(name = "j") int j) { int k = i + j; return k; }
在本練習(xí)中,您已為 Web 服務(wù)添加了代碼。
在將 Web 服務(wù)部署到 Web 容器時(shí),IDE 允許您測(cè)試 Web 服務(wù)以查看它是否能夠按預(yù)期的那樣工作。鑒于此目的,我們?cè)?IDE 中集成了 Sun Java System Application Server 提供的 Tester 應(yīng)用程序。對(duì)于 Tomcat Web Server,也存在類似的工具。但是,Sun Java System Application Server 的 Tester 頁(yè)允許您輸入值并對(duì)其進(jìn)行測(cè)試,而 Tomcat Web Server 則不允許這樣做。在后一種情況下,您只能看到已部署了 Web 服務(wù),但是不能對(duì)值進(jìn)行測(cè)試。目前還沒有用于測(cè)試 EJB 模塊是否已成功部署的工具。
測(cè)試是否已成功部署到 Web 容器:
注意:由于部署的 EJB 模塊的結(jié)果不會(huì)顯示在瀏覽器中,因此,如果您使用的是 EJB 模塊,則不能執(zhí)行上述步驟。
IDE 將啟動(dòng)應(yīng)用服務(wù)器、生成應(yīng)用程序,并在瀏覽器中打開 tester 頁(yè)(如果已將 Web 應(yīng)用程序部署到 Sun Java System Application Server)。對(duì)于使用 Tomcat Web Server 和部署 EJB 模塊來說,情況則有所不同:
Deployment of application CalculatorWSApplication completed successfully Enable of CalculatorWSApplication in target server completed successfully Enable of application in all targets completed successfully All operations completed successfully run-deploy: run: BUILD SUCCESSFUL
在本練習(xí)中,您已部署了 Web 服務(wù)并對(duì)其進(jìn)行了測(cè)試。
部署 Web 服務(wù)后,我們需要?jiǎng)?chuàng)建一個(gè)客戶端來使用 Web 服務(wù)的 add 方法。在本練習(xí)中,我們將創(chuàng)建三個(gè)客戶端,即 Java SE 應(yīng)用程序中的 Java 類、Web 應(yīng)用程序中的 Servlet 和 JSP 頁(yè)。
注意:在編寫本文檔時(shí),問題 10 還仍未得到解決,您必須在其路徑不包含空格的項(xiàng)目文件夾中創(chuàng)建 Web 服務(wù)客戶端。例如,路徑不能為 "C:\Documents and Settings\..."。
單擊“完成”。
將在“項(xiàng)目”窗口中顯示新建的 Web 服務(wù)客戶端:
System.out.println("Sum: " + port.add(3,4));
現(xiàn)在“輸出”窗口會(huì)顯示以下內(nèi)容:
compile: run: Sum: 7 BUILD SUCCESSFUL (total time: 1 second)
注意:在編寫本文檔時(shí),問題 10 還仍未得到解決,您必須在其路徑不包含空格的項(xiàng)目文件夾中創(chuàng)建 Web 服務(wù)客戶端。例如,路徑不能為 "C:\Documents and Settings\..."。
單擊“完成”。
將在“項(xiàng)目”窗口中顯示新建的 Web 服務(wù)客戶端:
/* TODO output your page here
然后,刪除注釋掉代碼部分的結(jié)束行:
*/
在以下行之后添加一些空行:
out.println("<h1>Servlet ClientServlet at " + request.getContextPath () + "</h1>");
現(xiàn)在,在您添加的一個(gè)空行中單擊鼠標(biāo)右鍵,選擇“Web 服務(wù)客戶端資源”>“調(diào)用 Web 服務(wù)操作”。將出現(xiàn)“選擇要調(diào)用的操作”對(duì)話框。
現(xiàn)在 processRequest 方法應(yīng)該如下所示(下面以粗體顯示添加的代碼):
protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<head>"); out.println("<title>Servlet ClientServlet</title>"); out.println("</head>"); out.println("<body>"); out.println("<h1>Servlet ClientServlet at " + request.getContextPath () + "</h1>"); try { // Call Web Service Operation org.me.calculator.client.CalculatorWSService service = new org.me.calculator.client.CalculatorWSService(); org.me.calculator.client.CalculatorWS port = service.getCalculatorWSPort(); // TODO initialize WS operation arguments here int arg0 = 0; int arg1 = 0; // TODO process result here int result = port.add(arg0, arg1); System.out.println("Result = "+result); } catch (Exception ex) { // TODO handle custom exceptions here } out.println("</body>"); out.println("</html>"); out.close(); }
將 arg0 和 arg1 的值更改為其他數(shù)值,如 3 和 4。
將 System.out.println 語句更改為 out.println。
添加輸出異常的行(如果拋出異常)。
現(xiàn)在 try/catch 塊應(yīng)該如下所示(會(huì)突出顯示新行和更改行):
try { // Call Web Service Operation org.me.calculator.client.CalculatorWSService service = new org.me.calculator.client.CalculatorWSService(); org.me.calculator.client.CalculatorWSApplication port = service.getCalculatorWSApplicationPort(); // TODO initialize WS operation arguments here int arg0 = 3; int arg1 = 4; // TODO process result here int result = port.add(arg0, arg1); out.println("<p>Result: " + result); } catch (Exception ex) { out.println("<p>Exception: " + ex); }
將啟動(dòng)服務(wù)器(如果它尚未運(yùn)行),生成并部署應(yīng)用程序,并且打開瀏覽器以顯示計(jì)算結(jié)果。
注意:在編寫本文檔時(shí),問題 10 還仍未得到解決,您必須在其路徑不包含空格的項(xiàng)目文件夾中創(chuàng)建 Web 服務(wù)客戶端。例如,路徑不能為 "C:\Documents and Settings\..."。
單擊“完成”。
將在“項(xiàng)目”窗口中顯示新建的 Web 服務(wù)客戶端。
將 arg0 和 arg1 的值更改為其他數(shù)值,如 3 和 4。
將啟動(dòng)服務(wù)器(如果它尚未運(yùn)行),生成并部署應(yīng)用程序,并且打開瀏覽器以顯示計(jì)算結(jié)果:
有關(guān)使用 NetBeans IDE 5.5 開發(fā) Java EE 應(yīng)用程序的更多信息,請(qǐng)參見以下資源:
要發(fā)送意見和建議、獲得支持以及隨時(shí)了解 NetBeans IDE Java EE 開發(fā)功能的最新開發(fā)情況,請(qǐng)加入 nbj2ee@netbeans.org 郵件列表。
本文檔介紹了有關(guān)使用 EJB 3.0 技術(shù)(作為 Java EE 5 平臺(tái)的一部分)開發(fā)企業(yè)應(yīng)用程序的基礎(chǔ)知識(shí),同時(shí)說明了 EJB 3.0 技術(shù)是如何簡(jiǎn)化企業(yè)應(yīng)用程序的開發(fā)過程的。本文檔使用的是 NetBeans IDE 5.5 發(fā)行版本。
預(yù)計(jì)持續(xù)時(shí)間:30 分鐘
本文檔假定您已具備了以下技術(shù)的一些基本知識(shí)或編程經(jīng)驗(yàn):
在學(xué)習(xí)本教程之前,您需要在計(jì)算機(jī)中安裝以下軟件:
在學(xué)習(xí)本教程之前,您需要在 IDE 中注冊(cè) Sun Java System Application Server 的本地實(shí)例。
本練習(xí)的目的是:創(chuàng)建包含一個(gè) EJB 模塊和一個(gè) Web 模塊的 NewsApp 企業(yè)應(yīng)用程序項(xiàng)目。NewsApp 應(yīng)用程序使用消息驅(qū)動(dòng) Bean 接收和處理 Servlet 發(fā)送到隊(duì)列中的消息。該應(yīng)用程序使用 Servlet 將消息發(fā)送到消息驅(qū)動(dòng) Bean 并顯示消息。
在本練習(xí)中,我們創(chuàng)建了包含一個(gè) EJB 模塊和一個(gè) Web 模塊的 Java EE 5 企業(yè)應(yīng)用程序。
在本練習(xí)中,我們將在 EJB 模塊中創(chuàng)建對(duì)象。我們將創(chuàng)建實(shí)體類、消息驅(qū)動(dòng) Bean 和會(huì)話 Facade。我們還將創(chuàng)建一個(gè)持久性單元,以便為容器提供用于管理實(shí)體的信息,以及消息驅(qū)動(dòng) Bean 將使用的 Java 消息服務(wù) (Java Message Service, JMS) 資源。
首先,我們將創(chuàng)建一個(gè)持久性單元,它用于定義在應(yīng)用程序中使用的數(shù)據(jù)源和實(shí)體管理器。
單擊“完成”后,IDE 將創(chuàng)建 persistence.xml,并在源代碼編輯器中將其打開。關(guān)閉 persistence.xml。
在本練習(xí)中,我們將創(chuàng)建 NewsEntity 實(shí)體類。實(shí)體類是一個(gè)簡(jiǎn)單的 Java 類。在創(chuàng)建實(shí)體類時(shí),IDE 會(huì)添加 @Entity 標(biāo)注以將該類定義為實(shí)體類。當(dāng)創(chuàng)建了類后,我們將在該類中創(chuàng)建字段以表示表中所需的數(shù)據(jù)。
每個(gè)實(shí)體類都必須具有一個(gè)主鍵。在創(chuàng)建實(shí)體類時(shí),IDE 會(huì)添加 @Id 標(biāo)注以聲明要用作主鍵的字段。此外,IDE 還會(huì)添加 @Generated 標(biāo)注以指定主 Id 的鍵生成策略。
要?jiǎng)?chuàng)建 NewsEntity 類,請(qǐng)執(zhí)行以下操作:
單擊“完成”后,將在源代碼編輯器中打開實(shí)體類 NewsEntity.java。在源代碼編輯器中,請(qǐng)執(zhí)行以下操作:
String title; String body;
在接下來的步驟中,我們將創(chuàng)建 NewMessage 消息驅(qū)動(dòng) Bean。
現(xiàn)在我們將在 EJB 模塊中創(chuàng)建 NewMessage 消息驅(qū)動(dòng) Bean。我們將使用“新建消息驅(qū)動(dòng) Bean”向?qū)韯?chuàng)建 Bean 和所需的 JMS 資源。
要?jiǎng)?chuàng)建 NewMessage 消息驅(qū)動(dòng) Bean,請(qǐng)執(zhí)行以下操作:
單擊“完成”后,將在源代碼編輯器中打開新建的消息驅(qū)動(dòng) Bean 類 NewMessage.java。您可以看到該類具有以下標(biāo)注:
@MessageDriven(mappedName = "jms/NewMessage")
此標(biāo)注向容器說明:該組件是一個(gè)消息驅(qū)動(dòng) Bean 并且該 Bean 使用 JMS 資源。當(dāng) IDE 生成類時(shí),將從類 (NewMessage.java) 名稱派生資源的映射名 (jms/NewMessage)。JMS 資源被映射到目標(biāo)的 JNDI 名稱,Bean 從該目標(biāo)中接收消息。“新建消息驅(qū)動(dòng) Bean”向?qū)б褳槲覀儎?chuàng)建了 JMS 資源。通過 EJB 3.0 API,我們可以從 Bean 類中查找 JNDI 名稱空間中的對(duì)象,這樣就不需要配置部署描述符來指定 JMS 資源了。
EJB 3.0 規(guī)范允許您使用標(biāo)注將資源直接引入類中。現(xiàn)在,我們準(zhǔn)備使用標(biāo)注將 MessageDrivenContext 資源引入類中,然后注入 PersistenceContext 資源,EntityManager API 將使用該資源來管理持久性實(shí)體實(shí)例。我們要在源代碼編輯器中將標(biāo)注添加到類中。
public class NewMessage implements MessageListener { @Resource private MessageDrivenContext mdc;
@PersistenceContext private EntityManager em;并在代碼中生成以下方法:
public void persist(Object object) { // TODO: // em.persist(object); }
public void save(Object object) { em.persist(object); }
ObjectMessage msg = null; try { if (message instanceof ObjectMessage) { msg = (ObjectMessage) message; NewsEntity e = (NewsEntity) msg.getObject(); save(e); } } catch (JMSException e) { e.printStackTrace(); mdc.setRollbackOnly(); } catch (Throwable te) { te.printStackTrace(); }
接下來,我們將為 NewsEntity 實(shí)體類創(chuàng)建一個(gè)會(huì)話 Facade。要?jiǎng)?chuàng)建會(huì)話 Facade,請(qǐng)執(zhí)行以下操作:
單擊“完成”后,將創(chuàng)建會(huì)話 Facade 類 NewsEntityFacade.java,并在源代碼編輯器中將其打開。IDE 還將創(chuàng)建本地接口 NewsEntityFacadeLocal.java。
EJB 3.0 技術(shù)通過減少所需的代碼量來簡(jiǎn)化會(huì)話 Bean 的創(chuàng)建。您可以看到,標(biāo)注 @Stateless 用于將類聲明為無態(tài)會(huì)話 Bean 組件,并且該類不再需要實(shí)現(xiàn) javax.ejb.SessionBean 的語句。此外,代碼也更為簡(jiǎn)潔了,因?yàn)槔?EJB 3.0 技術(shù),業(yè)務(wù)方法不再需要使用代碼來聲明其拋出了所檢查到的異常。
您會(huì)看到,在創(chuàng)建會(huì)話 Facade 時(shí),PersistenceContext 資源已直接注入到會(huì)話 Bean 組件中。
在本練習(xí)中,我們已對(duì) EJB 模塊中的實(shí)體類和消息驅(qū)動(dòng) Bean 進(jìn)行了編碼,然后為實(shí)體類創(chuàng)建了會(huì)話 Facade。此外,我們還創(chuàng)建了應(yīng)用程序使用的 JMS 資源。
現(xiàn)在,我們將在 Web 模塊中創(chuàng)建 Servlet ListNews 和 PostMessage。這些 Servlet 將用于讀取和添加消息。
在本練習(xí)中,我們將創(chuàng)建一個(gè)用于顯示數(shù)據(jù)的簡(jiǎn)單 Servlet。我們將使用標(biāo)注從 Servlet 中調(diào)用實(shí)體 Bean。
單擊“完成”后,將在源代碼編輯器中打開類 ListNews.java。在源代碼編輯器中,請(qǐng)執(zhí)行以下操作:
out.println("<h1>Servlet ListNews at " + request.getContextPath () + "</h1>"); List news = newsEntityFacade.findAll(); for (Iterator it = news.iterator(); it.hasNext();) { NewsEntity elem = (NewsEntity) it.next(); out.println(" <b>"+elem.getTitle()+" </b><br />"); out.println(elem.getBody()+"<br /> "); } out.println("<a href='PostMessage'>Add new message</a>"); out.println("</body>");
在本練習(xí)中,我們將創(chuàng)建用于傳遞消息的 PostMessage Servlet。我們將使用標(biāo)注將所創(chuàng)建的 JMS 資源直接注入 Servlet 中,并且指定變量名稱及其映射到的名稱。然后,添加用于發(fā)送 JMS 消息的代碼,以及用于在 HTML 表單中添加消息的代碼。
單擊“完成”后,將在源代碼編輯器中打開類 PostMessage.java。在源代碼編輯器中,請(qǐng)執(zhí)行以下操作:
public class PostMessage extends HttpServlet { @Resource(mappedName="jms/NewMessageFactory") private ConnectionFactory connectionFactory; @Resource(mappedName="jms/NewMessage") private Queue queue;
response.setContentType("text/html;charset=UTF-8"); // Add the following code to send the JMS message String title=request.getParameter("title"); String body=request.getParameter("body"); if ((title!=null) && (body!=null)) { try { Connection connection = connectionFactory.createConnection(); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer messageProducer = session.createProducer(queue); ObjectMessage message = session.createObjectMessage(); // here we create NewsEntity, that will be sent in JMS message NewsEntity e = new NewsEntity(); e.setTitle(title); e.setBody(body); message.setObject(e); messageProducer.send(message); messageProducer.close(); connection.close(); response.sendRedirect("ListNews"); } catch (JMSException ex) { ex.printStackTrace(); } } PrintWriter out = response.getWriter();
out.println("Servlet PostMessage at " + request.getContextPath() + "</h1>"); // Add the following code to add the form to the web page out.println("<form>"); out.println("Title: <input type='text' name='title'><br/>"); out.println("Message: <textarea name='body'></textarea><br/>"); out.println("<input type='submit'><br/>"); out.println("</form>"); out.println("</body>");
現(xiàn)在可以運(yùn)行項(xiàng)目了。在運(yùn)行項(xiàng)目時(shí),我們希望瀏覽器打開包含 ListNews Servlet 的頁(yè)面。可以通過在企業(yè)應(yīng)用程序的“屬性”對(duì)話框中指定該頁(yè)的 URL 來實(shí)現(xiàn)這一目的。該 URL 是應(yīng)用程序的上下文路徑的相對(duì) URL。輸入相對(duì) URL 后,可以從“項(xiàng)目”窗口中生成、部署并運(yùn)行應(yīng)用程序。
要設(shè)置相對(duì) URL 并運(yùn)行應(yīng)用程序,請(qǐng)執(zhí)行以下操作:
運(yùn)行項(xiàng)目時(shí),將在瀏覽器中打開 ListNews Servlet,該 Servlet 用于顯示數(shù)據(jù)庫(kù)中的消息列表。如果您是第一次運(yùn)行項(xiàng)目,則數(shù)據(jù)庫(kù)為空,但是您可以單擊“添加消息”來添加消息。
當(dāng)您使用 PostMessage Servlet 添加消息時(shí),消息會(huì)發(fā)送到消息驅(qū)動(dòng) Bean 以寫入到持久性存儲(chǔ)中,并會(huì)調(diào)用 ListNews Servlet 來顯示數(shù)據(jù)庫(kù)中的消息。由 ListNews 檢索的數(shù)據(jù)庫(kù)中的消息列表通常不包含新消息,這是因?yàn)橄⒎?wù)是異步的。
下面是您創(chuàng)建項(xiàng)目時(shí)可能會(huì)遇到的一些問題。
使用向?qū)韯?chuàng)建 JMS 資源時(shí),您可能會(huì)在輸出窗口中看到以下服務(wù)器錯(cuò)誤消息:
[com.sun.enterprise.connectors.ConnectorRuntimeException: JMS resource not created : jms/Queue]
此消息可能表明沒有創(chuàng)建 JMS 資源,或者沒有在應(yīng)用服務(wù)器中注冊(cè)該資源。您可以使用 Sun Java System Application Server 管理控制臺(tái)來檢查、創(chuàng)建以及編輯 JMS 資源。
要打開管理控制臺(tái),請(qǐng)執(zhí)行以下操作:
您需要確保將 PostMessage Servlet 中的 JMS 連接工廠資源映射到在 Sun Java System Application Server 中注冊(cè)的 JMS 連接工廠資源的對(duì)應(yīng) JNDI 名稱上。
應(yīng)在 Sun Java System Application Server 中注冊(cè)以下資源:
有關(guān)使用 NetBeans IDE 5.5 開發(fā) Java EE 應(yīng)用程序的更多信息,請(qǐng)參見以下資源:
您可以在 Java EE 5 教程中找到有關(guān)使用 EJB 3.0 Enterprise Beans 的詳細(xì)信息。
要發(fā)送意見和建議、獲得支持以及隨時(shí)了解 NetBeans IDE Java EE 開發(fā)功能的最新開發(fā)情況,請(qǐng)加入 nbj2ee 郵件列表。
本文檔向您介紹了有關(guān)使用 Java™ 持久性開發(fā) Web 應(yīng)用程序的基礎(chǔ)知識(shí)。Java 持久性 API 是作為 Java EE 5 平臺(tái)的一部分引入的。在本教程中,您將創(chuàng)建一個(gè)簡(jiǎn)單的 Web 應(yīng)用程序項(xiàng)目。我們將在項(xiàng)目中使用持久性,但是 Java 持久性 API 允許我們?cè)跓o需創(chuàng)建 EJB 模塊的情況下使用持久性。
在項(xiàng)目中使用 Java 持久性可以大大簡(jiǎn)化應(yīng)用程序的開發(fā),因?yàn)槟恍枰渲貌渴鹈枋龇麨槌志眯宰侄位驅(qū)傩蕴峁?duì)象關(guān)系映射信息,而可以使用標(biāo)注直接在簡(jiǎn)單的 Java 類中定義這些屬性。
實(shí)體持久性是通過 EntityManager API 來管理的。EntityManager API 用于處理持久性上下文,而每個(gè)持久性上下文是一組實(shí)體實(shí)例。在開發(fā)應(yīng)用程序時(shí),您可以在類中使用標(biāo)注來指定實(shí)體實(shí)例的持久性上下文實(shí)例,然后通過容器處理實(shí)體實(shí)例的生命周期。
本文檔使用的是 NetBeans IDE 5.5 發(fā)行版本。
預(yù)計(jì)持續(xù)時(shí)間:15 分鐘
本文檔假定您已具備以下技術(shù)的一些基本知識(shí)或編程經(jīng)驗(yàn):
在學(xué)習(xí)本教程之前,您需要在計(jì)算機(jī)中安裝以下軟件:
在學(xué)習(xí)本教程之前,您需要在 IDE 中注冊(cè) Sun Java System Application Server 的本地實(shí)例。
本練習(xí)的目的是創(chuàng)建 ZooApp Web 應(yīng)用程序項(xiàng)目。此應(yīng)用程序?qū)⒗眯略龅?Java 持久性模型的功能。其中一項(xiàng)功能就是,實(shí)體對(duì)象可以成為簡(jiǎn)單的 Java 類,因此不再需要將它們放置在 EJB 模塊中并將其打包到 EAR 文件中。這意味著,我們可以直接在 Web 應(yīng)用程序內(nèi)創(chuàng)建實(shí)體類。
在本練習(xí)中,您創(chuàng)建了一個(gè)將包含實(shí)體類的 Java EE 5 Web 應(yīng)用程序。
在本練習(xí)中,我們將創(chuàng)建一個(gè)持久性單元,目的在于通知容器哪些實(shí)體類需要由實(shí)體管理器進(jìn)行管理,以及這些實(shí)體需要使用哪些數(shù)據(jù)源信息。
我們通過在 persistence.xml(將在 Web 模塊中創(chuàng)建此文件)中定義持久性單元的屬性來創(chuàng)建持久性單元。指定持久性單元的名稱后,將指定持久性提供程序,它包含容器將用于管理實(shí)體實(shí)例的 API。此外,還需要指定數(shù)據(jù)源和表生成策略。我們將使用“新建持久性單元”向?qū)?chuàng)建持久性單元。
注意:也可以在“新建 - 實(shí)體類”向?qū)е袆?chuàng)建持久性單元。創(chuàng)建實(shí)體類時(shí),如果不存在持久性單元,該向?qū)⑻崾疚覀冞M(jìn)行創(chuàng)建。
缺省提供程序是 TopLink Essential.jar。TopLink Essential.jar 包含了 Java 持久性的庫(kù)。并且實(shí)體管理器位于 TopLink Essential.jar 中。
缺省數(shù)據(jù)源 jdbc/sample 用于連接到與 Sun Java System Application Server 捆綁在一起的 Java DB 數(shù)據(jù)庫(kù)。
單擊“完成”后,IDE 將創(chuàng)建 persistence.xml,并在源代碼編輯器中將其打開。通過單擊源代碼編輯器工具欄中的 "XML",可以查看 persistence.xml 的 XML。此文件包含了 Java EE 5 容器管理應(yīng)用程序的實(shí)體和持久性所需的所有信息。
在本練習(xí)中,您創(chuàng)建了一個(gè)持久性單元,用來指定數(shù)據(jù)源、要永久保存的實(shí)體類以及容器將用于管理實(shí)體生命周期的實(shí)體管理器。
在本練習(xí)中,我們將創(chuàng)建兩個(gè)實(shí)體類,即 Animal.java 和 Pavilion.java,它們用于表示要?jiǎng)?chuàng)建的關(guān)系數(shù)據(jù)庫(kù)中的表。此外,還將在類中定義一些字段來表示數(shù)據(jù)。Java 持久性規(guī)范允許我們使用標(biāo)注為容器提供有關(guān)字段的信息,如對(duì)象關(guān)系映射信息。
首先,我們將創(chuàng)建實(shí)體類 Animal。此類用于表示數(shù)據(jù)庫(kù)中的 ANIMAL 表。在創(chuàng)建實(shí)體類時(shí),IDE 會(huì)添加 @Entity 標(biāo)注以將該類定義為實(shí)體類。創(chuàng)建類后,我們將在類中創(chuàng)建字段以表示表中所需的數(shù)據(jù),并使用標(biāo)注提供有關(guān)一些字段的其他信息。
每個(gè)實(shí)體類都必須具有一個(gè)主鍵。在創(chuàng)建實(shí)體類時(shí),IDE 會(huì)添加 @Id 標(biāo)注以聲明要用作主鍵的字段。此外,IDE 還會(huì)添加 @Generated 標(biāo)注以指定主 Id 的鍵生成策略。
要?jiǎng)?chuàng)建 Animal 類,請(qǐng)執(zhí)行以下操作:
單擊“完成”后,將在源代碼編輯器中打開新建的實(shí)體類 Animal.java。在源代碼編輯器中,請(qǐng)執(zhí)行以下操作:
String name; String kind; String weight; Pavilion pavilion;
@Column(name="animalName")
@ManyToOne
在下一步中,我們將創(chuàng)建 Pavilion 實(shí)體類。
現(xiàn)在我們將創(chuàng)建實(shí)體類 Pavilion,它用于表示數(shù)據(jù)庫(kù)中的 PAVILION 表。我們將再次在類中使用標(biāo)注指定一些字段的對(duì)象關(guān)系映射。要?jiǎng)?chuàng)建 Pavilion 類,請(qǐng)執(zhí)行以下操作:
單擊“完成”后,將在源代碼編輯器中打開新建的實(shí)體類 Pavilion.java。在源代碼編輯器中,請(qǐng)執(zhí)行以下操作:
String name; String address; Collection <Animal> animals;
@Column(name="pavilionName")
@OneToMany(mappedBy="pavilion")
在本練習(xí)中,您創(chuàng)建了兩個(gè)實(shí)體類并定義了字段,而且還使用標(biāo)注定義了在部署應(yīng)用程序時(shí)將在表中生成的某些列的屬性。
現(xiàn)在我們希望創(chuàng)建一些簡(jiǎn)單的 Web 頁(yè),以查看是否創(chuàng)建了數(shù)據(jù)庫(kù)表以及是否可以添加數(shù)據(jù)。我們將為應(yīng)用程序添加 Java Server Faces (JSF) 頁(yè),并使用“通過實(shí)體類創(chuàng)建 JSF 頁(yè)”向?qū)Э焖賱?chuàng)建一個(gè)簡(jiǎn)單的 Web 接口。
單擊“完成”后,IDE 將生成所需的 JavaServer Faces 文件,以便我們可以運(yùn)行并測(cè)試 ZooApp。
在本練習(xí)中,我們將部署 ZooApp Web 應(yīng)用程序項(xiàng)目并測(cè)試該應(yīng)用程序。
單擊“運(yùn)行項(xiàng)目”后,將在瀏覽器中打開一個(gè)頁(yè)面,您可以通過該頁(yè)面包含的菜單,查看場(chǎng)館 (Pavilions) 和動(dòng)物 (Animals) 的列表。
您還可以添加、編輯或刪除動(dòng)物 (Animals) 和場(chǎng)館 (Pavilions) 數(shù)據(jù)。
在本練習(xí)中,您生成了為 Java EE 5 平臺(tái)開發(fā)的 ZooApp Web 應(yīng)用程序,然后部署并測(cè)試了該 Web 應(yīng)用程序。
下面是您創(chuàng)建項(xiàng)目時(shí)可能會(huì)遇到的一些問題。
使用該向?qū)ㄟ^實(shí)體類創(chuàng)建 JSF 頁(yè)時(shí),您可能會(huì)在向?qū)е锌吹揭韵洛e(cuò)誤消息:
"This wizard can only be used in a web project with JSF support."(此向?qū)е荒茉诰哂?JSF 支持的 Web 項(xiàng)目中使用。)
如果看到此消息,則需要檢查是否已將 Java Server Faces 框架添加到項(xiàng)目屬性中。通過執(zhí)行以下操作,可以將 Java Server Faces 支持添加到 Web 項(xiàng)目中:
將 JSF 框架添加到項(xiàng)目屬性后,您應(yīng)該能夠使用該向?qū)?chuàng)建 JSF 頁(yè)了。
有關(guān)使用 NetBeans IDE 5.5 開發(fā) Java EE 應(yīng)用程序的更多信息,請(qǐng)參見以下資源:
您可以在 Java EE 5 教程中找到有關(guān)使用 Java 持久性的詳細(xì)信息。
要發(fā)送意見和建議、獲得支持以及隨時(shí)了解 NetBeans IDE Java EE 開發(fā)功能的最新開發(fā)情況,請(qǐng)加入 nbj2ee 郵件列表。
Java EE 5 教程
|
NetBeans IDE 5.5 的開發(fā)是在 Java EE 和 Glassfish 工作組的密切合作下完成的,它實(shí)現(xiàn)了與新的 Java EE 5 規(guī)范的完美集成,從而可以在此 IDE 中輕松地使用新規(guī)范。NetBeans IDE 5.5 是您快速學(xué)習(xí) Java EE 5 編程并使用它高效工作的最佳途徑。
本文檔介紹了 Java EE 5 規(guī)范的一些重要概念,以及它們?nèi)绾闻c您目前的編程項(xiàng)目相關(guān)聯(lián)的。下面將介紹以下主題:
您可以在 Java EE 5 教程中找到有關(guān)開發(fā) Java EE 5 應(yīng)用程序并在 Sun Java System Application Server Platform Edition 9 上部署該應(yīng)用程序的信息。
Java EE 5 平臺(tái)不需要任何部署描述符(Servlet 規(guī)范所需的部署描述符 web.xml 文件除外),從而簡(jiǎn)化了部署過程。其他部署描述符(如 ejb-jar.xml 以及在 web.xml 中與 Web 服務(wù)相關(guān)的條目)已過時(shí)。J2EE 1.4 部署描述符通常很復(fù)雜,在填充它們時(shí)很容易出錯(cuò)。但是,Java EE 5 平臺(tái)使用的是“標(biāo)注”。標(biāo)注是 Java 修飾符,與代碼中指定的 public 和 private 類似。例如,EJB 3 規(guī)范(Java EE 5 規(guī)范的子集)為 Bean 類型、接口類型、資源引用、事務(wù)屬性、安全性等定義了標(biāo)注。JAX-WS 2.0 規(guī)范為 Web 服務(wù)提供了一組類似的標(biāo)注。有些標(biāo)注用來生成工件,另外一些標(biāo)注用來描述代碼,還有一些標(biāo)注用來提供增強(qiáng)的服務(wù),如安全性或特定于運(yùn)行時(shí)的邏輯。總之,Java EE 5 平臺(tái)為以下任務(wù)(以及其他任務(wù))提供了標(biāo)注:
標(biāo)注使用 @ 字符來標(biāo)記。在 IDE 中,當(dāng)您創(chuàng)建了使用 Java EE 5 中的標(biāo)注的類型時(shí),將在生成的代碼中提供相關(guān)的占位符。例如,當(dāng)您使用 IDE 創(chuàng)建無態(tài)會(huì)話 Bean 時(shí),將生成以下代碼,其中包括 @Stateless() 標(biāo)注:
package mypackage; import javax.ejb.*; @Stateless() public class HelloWorldSessionBean implements mypackage.HelloWorldSessionLocal { }通過代碼完成,您可以對(duì)特定于光標(biāo)下的項(xiàng)的標(biāo)注屬性進(jìn)行訪問。例如,在 @WebService() 標(biāo)注的括號(hào)中按 Ctrl-空格鍵時(shí),將看到以下內(nèi)容:
每個(gè)屬性都具有缺省值。因此,除非您需要使用缺省值以外的其他值,否則不必指定任何屬性。在一些簡(jiǎn)單的示例中,使用缺省值就可以了,這意味著您根本不需要提供屬性。
使用新的 EJB 3.0 API,可以減少并簡(jiǎn)化開發(fā)者需要完成的工作量,從而可以更輕松地進(jìn)行軟件開發(fā)。換句話說,就是使用了更少的類和代碼。這是因?yàn)楝F(xiàn)在容器承擔(dān)了更多的工作,從而實(shí)現(xiàn)了這一目的。下面是新 EJB 3.0 API 的一些功能和優(yōu)點(diǎn):
EJBContext
直接在類中查找 JNDI 名稱空間中的對(duì)象。
在 IDE 中,您可以對(duì) Enterprise Beans 進(jìn)行編碼,就像對(duì)其他 Java 類進(jìn)行編碼一樣,方法是:使用代碼完成和編輯器提示實(shí)現(xiàn)正確的方法并使類與其接口保持同步。您不必使用特殊命令和對(duì)話框生成諸如業(yè)務(wù)方法或 Web 服務(wù)操作之類的內(nèi)容,雖然這些命令仍可以幫助您熟悉 Java EE 5 代碼的語法。
要請(qǐng)求資源注入,組件需要使用 @Resource
標(biāo)注或針對(duì)一些專用資源的 @EJB
和 @WebServiceRef
標(biāo)注。您可以注入以下資源:
SessionContext
對(duì)象
DataSources
對(duì)象
EntityManager
接口
在 IDE 中,源代碼編輯器為 Java EE 5 平臺(tái)提供的資源注入標(biāo)注提供了完整的代碼完成。此外,當(dāng)您運(yùn)行諸如“調(diào)用 EJB”和“使用數(shù)據(jù)庫(kù)”之類的命令時(shí),IDE 會(huì)自動(dòng)將資源注入到文件中。
Java EE 5 平臺(tái)引入了新的 Java 持久性 API(它是作為 JSR-220 的一部分開發(fā)的)。Java 持久性 API 不但可以在 EJB 組件外部使用(例如,在 Web 應(yīng)用程序和應(yīng)用程序客戶端中使用),而且還可以在 Java EE 平臺(tái)之外的 Java SE 應(yīng)用程序中使用。
Java 持久性 API 具有以下主要功能:
JAR
、應(yīng)用程序客戶端 JAR
、WEB-INF/lib
、WEB-INF/classes
的一部分,甚至是企業(yè)應(yīng)用程序歸檔 (Enterprise Application Archive, EAR) 文件中實(shí)用程序 JAR
的一部分。通過這些簡(jiǎn)單的打包規(guī)則,您不再需要?jiǎng)?chuàng)建 EAR 文件以使用來自 Web 應(yīng)用程序或應(yīng)用程序客戶端的實(shí)體 Bean。
創(chuàng)建、讀取、更新和刪除
(Create Read Update Delete, CRUD) 操作。 IDE 提供了處理新 Java 持久性 API 的工具。您可以通過數(shù)據(jù)庫(kù)自動(dòng)生成實(shí)體類,或手動(dòng)對(duì)實(shí)體類進(jìn)行編碼。IDE 還提供了用于創(chuàng)建和維護(hù)持久性單元的模板和圖形編輯器。有關(guān)使用新 Java 持久性 API 的詳細(xì)信息,請(qǐng)參見 Java EE 5 平臺(tái)中的 Java 持久性。
在 Java EE 5 平臺(tái)中,通過使用標(biāo)注顯著改進(jìn)和簡(jiǎn)化了 Web 服務(wù)支持。以下規(guī)范已應(yīng)用于此領(lǐng)域中:JSR 224,Java API for XML-Based Web Services (JAX-WS) 2.0;JSR 222,Java Architecture for XML Binding (JAXB) 2.0 以及 JSR 181,Web Services Metadata for the Java Platform。
JAX-WS 2.0 是 Java EE 5 平臺(tái)中用于 Web 服務(wù)的新 API。作為 JAX-RPC 1.1 的后繼者,JAX-WS 2.0 保留了自然的 RPC 編程模型,同時(shí)在以下幾個(gè)方面進(jìn)行了改進(jìn):數(shù)據(jù)綁定、協(xié)議和傳輸?shù)莫?dú)立性、對(duì) Web 服務(wù)的 REST
樣式的支持以及易開發(fā)性。
與 JAX-RPC 1.1 的主要區(qū)別在于,現(xiàn)在所有數(shù)據(jù)綁定都委托給了 JAXB 2.0。這樣,基于 JAX-WS 的 Web 服務(wù)就可以使用百分之百的 XML 架構(gòu),從而提高了互操作性和易使用性。這兩種技術(shù)已很好地集成在一起了,因此用戶不必再為使用兩套不同的工具而勉為其難了。從 Java 技術(shù)類開始開發(fā)時(shí),JAXB 2.0 可以生成自動(dòng)嵌入到 Web 服務(wù)描述語言 (Web Service Description Language, WSDL) 文檔內(nèi)的 XML 架構(gòu)文檔,從而用戶無需手動(dòng)執(zhí)行這一容易出錯(cuò)的集成。
現(xiàn)成的 JAX-WS 2.0 本身可以支持 SOAP 1.1、SOAP 1.2 和 XML/HTTP 協(xié)議。協(xié)議可擴(kuò)展性從一開始就是人們所希望實(shí)現(xiàn)的目標(biāo),JAX-WS 2.0 允許供應(yīng)商支持其他協(xié)議和編碼來獲取更佳的性能(例如 FAST Infoset)或?qū)S玫膽?yīng)用程序。Web 服務(wù)(使用附件來優(yōu)化大型二進(jìn)制數(shù)據(jù)的發(fā)送和接收)可以利用 W3C 制訂的 MTOM/XOP(“消息傳輸優(yōu)化機(jī)制/XML 二進(jìn)制優(yōu)化打包”的簡(jiǎn)稱)標(biāo)準(zhǔn),且對(duì)編程模型沒有任何不利的影響(有關(guān) MTOM/XOP 的信息,請(qǐng)參見此頁(yè))。在 Java EE 5 技術(shù)出現(xiàn)之前,定義 Web 服務(wù)需要使用很長(zhǎng)且復(fù)雜的描述符。現(xiàn)在,定義它卻非常簡(jiǎn)單,只需將 @WebService
標(biāo)注放置在 Java 技術(shù)類上即可。類上的所有公共方法會(huì)自動(dòng)發(fā)布為 Web 服務(wù)操作,并且其所有參數(shù)都將使用 JAXB 2.0 映射到 XML 架構(gòu)數(shù)據(jù)類型。
由于 Web 服務(wù)調(diào)用是通過網(wǎng)絡(luò)來實(shí)現(xiàn)的,因此這種調(diào)用所花費(fèi)的時(shí)間是無法預(yù)測(cè)的。許多客戶端(特別是交互式客戶端,如基于 JFC/Swing 的桌面應(yīng)用程序)由于必須等待服務(wù)器的響應(yīng)而嚴(yán)重地影響了它們的性能。為了避免出現(xiàn)性能降低,JAX-WS 2.0 提供了新的異步客戶端 API。使用此 API,應(yīng)用程序編程人員不再需要自己創(chuàng)建線程,而是依賴于 JAX-WS 運(yùn)行時(shí)為他們管理長(zhǎng)時(shí)間運(yùn)行的遠(yuǎn)程調(diào)用。
異步方法可以與 WSDL 生成的任何接口以及動(dòng)態(tài)性更強(qiáng)的 Dispatch
API 聯(lián)合使用。為了方便起見,在導(dǎo)入 WSDL 文檔時(shí),您可以要求為 Web 服務(wù)定義的任何操作生成異步方法。
以下提供了兩種使用模型:
請(qǐng)注意,異步調(diào)用支持是完全在客戶端上實(shí)現(xiàn)的,因此不需要對(duì)目標(biāo) Web 服務(wù)進(jìn)行任何更改。
IDE 提供了處理 JAX-WS 的工具。您可以使用“新建文件”向?qū)е械哪0迳?JAX-WS 工件。異步 Web 服務(wù)可以通過 Web 服務(wù)定制編輯器來創(chuàng)建。代碼完成功能包括可以在 Web 服務(wù)中使用的標(biāo)注。
有關(guān)使用 NetBeans IDE 5.5 開發(fā) Java EE 應(yīng)用程序的更多信息,請(qǐng)參見以下資源:
要發(fā)送意見和建議、獲得支持以及隨時(shí)了解 NetBeans IDE Java EE 開發(fā)功能的最新開發(fā)情況,請(qǐng)加入 nbj2ee@netbeans.org 郵件列表。