本博客文章的目的是带您从简单的静态网页开始,直到我们拥有以下列表中的完整堆栈。我将这个堆栈称为“Summer”,因为在漫长的寒冬之后,春天可能很美好,但等到夏天到来时,那就更美了 ;-)
- CDI (Weld)
- JSF 2 (facelets, ICEfaces 2)
- JPA 2 (Hibernate, Envers)
- EJB 3.1 (无本地视图,异步,单例,调度)
- Bean Validation (Hibernate Validator)
- JMS (MDB)
- JAX-RS (RESTEasy)
- JAX-WS
- Arqullian (incontainer-AS6)
我们将将这些功能打包到一个单独的WAR文件中。因为我们能这样做(剧透:在第 IV 部分)。请注意,除了组件和测试框架外,它们都是标准?这有很多东西。幸运的是,应用服务器已经提供了大部分东西,所以您的应用程序仍然相对较小。
至于我使用的环境
- Eclipse (Galileo SR2)
- JBoss 6.0 M3
- Maven 3 (beta1)
- Sun JDK 6
- m2eclipse 0.10
这不会是一篇典型的博客文章,其中一切都很顺利——我们会遇到错误。会有诅咒、鲜血和内脏,以及戏剧性的情节,我们将随着进程进行而进行工作区间的解决方案和重写。这几乎与您作为软件开发商的平均一天看起来几乎一样。我在这篇文章中使用的技术也不是专家,所以可能有些事情可以做得更好。将此视为我在EE6领域的经验记录,这可能与其他人的经历相呼应。我也不会提供链接或额外信息,假设如果您说“RESTEasy”,那么如果您感兴趣,您可以通过谷歌搜索更多相关信息。
而且我差点忘了:不要慌张。
开始:项目设置
那么,让我们开始吧 - 如果您还没有,请下载环境中提到的内容。我不会通过引导您来完成这个任务来侮辱您的智商(稍后提醒我侮辱它)。此外,这很简单。
让我们创建一个新的Maven项目(文件 -> 新建 -> 项目... -> Maven -> Maven项目。我们跳过存根选择,只创建一个简单的项目,组ID为com.acme
,构件ID为Greetings
,版本为1.0.0-SNAPSHOT
,打包为WAR。现在完成向导,现在您应该有一个完美、理想的项目。我们的下一步是向其中添加代码,它将永远保持这种完美。
针对Windows用户的Maven每日小贴士。在Google上搜索如何更改本地仓库的路径,因为它可能位于文档和设置
下的某个位置,这将有两个影响:类路径会变得非常大,并且由于空格可能会导致问题。将其更改为类似于c:\java\m2repo的位置。
我们首先注意到m2eclipse默认使用J2SE-1.4。这是2002年吗?此外,这将使得使用注解变得不可能,因此让我们将其更改为。编辑pom.xml并添加以下内容
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.1</version> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin> </plugins> </build>
保存并右键单击项目根目录,然后选择Maven -> 更新项目配置。啊,这样好多了
JSF
让我们唤醒JSF。我们在src/main/webapp下创建一个WEB-INF文件夹,并添加一个web.xml,因为没有web应用是完整的(由maven war插件强制)。好的,实际上这可以在插件中配置,但让我们保留web.xml,因为稍后我们还需要它。
<?xml version="1.0" encoding="ISO-8859-1"?> <web-app version="3.0" 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_3_0.xsd"/>
并在旁边放置一个空的faces-config.xml
<faces-config 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_2_0.xsd" version="2.0"/>
然后在webapp中添加一个greeting.xhtml,如下所示
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets"> <h:head> <title> Greetings </title> </h:head> <h:body> <h:outputText value="Hello world"/> </h:body> </html>
它会融合吗?我是说,它会部署吗?执行mvn clean package
,您应该在项目的target目录下看到一个Greetings-1.0.0-SNAPSHOT。将其放入AS服务器/default/deploy目录中,启动服务器,然后访问
http://localhost:8080/Greetings-1.0.0-SNAPSHOT/faces/greetings.xhtml
URL不够美观,但服务器端口、Web上下文根、欢迎文件和JSF映射都可以稍后调整,让我们现在关注技术和依赖项。但是等等 - 我们在web.xml中定义了JSF.servlet和映射在哪个点?我们没有。对于启用了JSF的应用程序,这是自动的。
EJB和CDI
下一步是引入一些后端bean,让我们将问候外包出去。我们创建一个无状态的EJB并在CDI中使用它。
package com.acme.greetings;
@Stateful @Model public class GreetingBean { public String getGreeting() { return "Hello world"; } }
@Stateful定义了一个有状态的会话EJB(由于是POJO,所以是3.1版本),@Model是一个CDI泛型,它具有@RequestScoped和@Named属性(这意味着生命周期绑定到一个单个HTTP请求,并且它有一个可以在EL中引用的名称,在本例中默认为greetingBean
)。但是我们有问题 - 注解没有解析到任何内容。因此,我们需要从某处获取它们(tm)。幸运的是,我们可以通过在pom.xml中添加以下内容来自动获取所有API
<dependencies> <dependency> <groupId>org.jboss.spec</groupId> <artifactId>jboss-javaee-6.0</artifactId> <version>1.0.0.Beta4</version> <type>pom</type> <scope>provided</scope> </dependency> </dependencies>
Sun Java API构件有点有趣,因为获取它们可能有点棘手。首先,它们在JSR中发布它们,然后它们像对待绝密一样对待它们。幸运的是,Glassfish和JBoss现在开始在自己的存储库中提供它们(尽管使用自己的构件名称,但仍然)...
我们还必须确保根据http://community.jboss.org/wiki/MavenGettingStarted-Users设置了JBoss存储库。看看项目中的Maven Dependencies
发生了什么。好的。现在关闭它并退后。那里的事情变得复杂了,所以最好相信Maven从此跟踪依赖项。
现在应该在bean中可用,所以我们导入
import javax.ejb.Stateful; import javax.enterprise.inject.Model;
并将bean与
<h:body> <h:outputText value="#{greetingBean.greeting}"/> </h:body>
在greeting.xhtml中EL挂钩。
就像没有web.xml的web应用是不完整的,没有bean.xml的CDI应用也是不完整的。让我们将其添加到WEB-INF中。
<?xml version="1.0" encoding="ISO-8859-1"?> <beans 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/beans_1_0.xsd" />
打包和重新部署。编译时我们收到关于编码的警告,所以让我们将这个添加到我们的pom.xml文件中。
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties>
回到http://localhost:8080/Greetings-1.0.0-SNAPSHOT/faces/greetings.xhtml SUCCESS! 等等。一大堆堆栈跟踪信息让你受到300点伤害。让我们回到我们的EJB上,在AS 6 M3的WAR-only打包中3.1风格的EJB还有一些问题。移除@Stateful注解,它就变成了一个普通的CDI管理POJO。重新打包。重新部署。回收。
测试
现在测试很流行,所以我们引入Arquillian。Arquillian是EE测试(嵌入式或容器内)的最新和最伟大工具。现在就开始使用它。大约一年后,当其他人赶上来时,你可以去说 "我从Alpha版本就开始使用了
"。将以下属性添加到pom.xml中
<arquillian.version>1.0.0.Alpha2</arquillian.version>
以及这些依赖项
<dependency> <groupId>org.jboss.arquillian</groupId> <artifactId>arquillian-junit</artifactId> <version>${arquillian.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.8.1</version> <scope>test</scope> </dependency>
以及这个配置文件
<profiles> <profile> <id>jbossas-local-60</id> <dependencies> <dependency> <groupId>org.jboss.arquillian.container</groupId> <artifactId>arquillian-jbossas-local-60</artifactId> <version>1.0.0.Alpha2</version> </dependency> <dependency> <groupId>org.jboss.jbossas</groupId> <artifactId>jboss-server-manager</artifactId> <version>1.0.3.GA</version> </dependency> <dependency> <groupId>org.jboss.jbossas</groupId> <artifactId>jboss-as-client</artifactId> <version>6.0.0.20100429-M3</version> <type>pom</type> </dependency> </dependencies> </profile> </profiles>
Maven现在可能会为你下载整个互联网。
让我们编写我们的第一个测试并将其放置在测试源文件夹中
package com.acme.greetings.test; import javax.inject.Inject; import org.jboss.arquillian.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.shrinkwrap.api.ArchivePaths; import org.jboss.shrinkwrap.api.ShrinkWrap; import org.jboss.shrinkwrap.api.spec.JavaArchive; import org.jboss.shrinkwrap.impl.base.asset.ByteArrayAsset; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import com.acme.greetings.GreetingBean; @RunWith(Arquillian.class) public class GreetingTest { @Inject GreetingBean greetingBean; @Deployment public static JavaArchive createTestArchive() { return ShrinkWrap.create("test.jar", JavaArchive.class).addClass( GreetingBean.class).addManifestResource( new ByteArrayAsset("<beans/>".getBytes()), ArchivePaths.create("beans.xml")); } @Test public void testInjection() { Assert.assertEquals("Hello World", greetingBean.getGreeting()); } }
然后我们使用 mvn test -Pjbossas-local-60
来尝试它。如果我们有AS运行,我们可以节省一些时间,否则管理器会自动启动它。设置JBOSS_HOME环境变量有帮助。这里发生的事情是,我们使用Shrinkwrap创建一个部署,其中包含我们的GreetingBean和一个空的beans.xml文件(用于CDI),然后该bean被注入以供测试中使用。
这完成了第一部分。在第二部分中,我们将设置ICEfaces并扩展我们的应用程序,在第三部分中我们将设置JPA。第四部分是用于MDB和EJB,第五部分是添加JAX-RS和JAX-WS以导入和导出内容。