使用 Maven 通过 IDEA 开发 JPA + EJB + JSF 项目

之前写过使用IDEA创建EJB工程的文章,不过现在有个课题需要结合 JPA + EJB + JSF, 虽然可以按照前文所述方法进行,但是我想使用 Maven 进行管理,因此直接在新建工程时选择 EJB 项目就不行了,应该选择 Maven 项目。
你可以先看看之前的文章:使用 IDEA 创建 EJB 工程

使用 IDEA 创建 EJB 工程


分析

首先,我们分析一下项目所需结构。
JPA 主要是用于 ORM 了,因此都是实体类,相当于 Model 层。
EJB 则分为接口和实现类,接口应该复制给客户端(JSF Web 层)调用,而实现类则是 EJB 的 Bean, 相当于 DAO 层。
最后是 JSF Web模块,页面展示 View 层。

因此得到如下依赖关系:

EJB -> EJB-API -> JPA
Web -> EJB-API -> JPA

这么分模块是为了使用 Maven 管理时更好地处理模块之间的依赖关系。

新建各模块

下一步我们就可以新建一个 Maven 父项目。
给他配置全局的依赖,如 slf4j 和 logback, Java EE API 等。
配置内容:

JPA

之后按照依赖顺序新建 JPA 模块。注意需要配置打包类型为 jar(默认是 pom )以供 EJB 模块和 web 模块使用。

EJB-API

然后添加 EJB-api 模块,因为 Web 层只需要 EJB 的接口,不需要其实现类,因此在这里我们把接口和实现分在两个模块中。
这个模块也需要打包成 jar. 该模块需要依赖于 JPA 模块。

EJB

添加 EJB 模块。依赖中设置其依赖于 api 模块。

Web

最后添加 web 模块。在新建 Module 时可以选择 Create from archetype, 然后选择 maven-archtype-webapp.

新建web模块
新建web模块

注意:可以添加 archetypeCatalog=internal属性以使得创建模块时更快,不至于卡死。
新建web模块:属性设置
新建web模块:属性设置

该模块的依赖是:

其中 junit 是创建 web 模块时选择的模板自动添加的,EJB-api 是我们需要手动添加的,api 层已经依赖 jpa 模块了,不需重复指定。
Hibernate-entitymanager 作为 JPA 的规范的实现提供商,当然你也可以选择其他的,比如 Eclipse-Link 之类的。

项目结构

新建后项目结构如下:

项目结构 - 依赖关系
项目结构 – 依赖关系

演示

然后我们写个最简单的 Hello World 演示一下。

JPA

首先是实体类 User.

API

然后是 DAO 接口。

当然,使用 Remote 还是 Local 可以你自己选了,这里随便选了个:远程接口。

EJB

再次是 DAO 实现类。
首先我们在这个模块中配置 persisten.xml 和 ejb-jar.xml 两个文件。

上述代码为了演示方便,使用的是 JBoss 默认自带的内存数据库的数据源 ExampleDS (服务器关闭释放内存,则数据库中数据也将消失), 当用于实际项目中时,你需要自行配置 JBoss 数据源,相关操作可自行搜索。

该文件用于指明本项目是一个 EJB 项目,需要生成打包文件部署到服务器。

这里的 EntityManager 对象 em 使用 @PersistenceContext(name = "demo")注解表明,该对象由容器自动注入。name的值就是 persistence.xml 中配置的 unitName.

Web

最后是 Web 层。根据上面的接口,你也可以看出我打算只写一个功能:添加用户和列出用户。

第一部分定义 JSF 拦截器,所有 .xhtml 请求都由 JSF 处理。第二部分说明欢迎文件 index.xhtml.

目前演示 EJB 中只有一个类,若有多个类,那么每次获取远程 EJB 都要写个 Context.lookup 再强制转换是很烦人的,因此我把它提取出来作为一个工具类。不过这里约定了实现类和接口的命名规则:实现类必须以接口名加Impl命名。当然仅仅是为了获取方便(虽然实现类和客户端不应有关联,客户端只和 JNDI 名称有关联,但这里默认 JNDI 名称就是包含类名嘛),你也可以自己自定义啦。

JSF 中的Managed Bean 相当于 Action 层,你可以根据业务需要自行设置 Scope 为会话或请求范围。这里演示得很简单,为了减少获取 EJB 的次数,设置成了会话范围。(不过在 EJBUtil 里我们已经做了缓存了。)

页面很简单,甚至连 CSS 都没写,因为我是演示的目的。只涉及到了表单、循环,以及 XHTML 和 Bean 之间的关联。
#{bean.property} 就是 JSF 中的表达式写法了,在%lt;c:foreach>里还是用的美元符号 ${xxx}.

配置

写好后,打开 Project Structure 定位到 Modules – Demo-ejb – EJB 发现右边有提示

‘EJB’ Facet resources are not includeed in an artifact.

因此点击 Create Artifact,注意打包类型只能选择 Archived, 且后缀需要以 jarrar 结尾。并且需要加上 ejb 和 jpa 模块的编译内容到 Output 中,否则运行时会找不到类。

EJB 打包注意
EJB 打包注意

同样, web 打包也需要确保 api 和 jpa 模块的代码包含进来了。

web 模块打包
web 模块打包

最后,如果需要日志打印,这里配置的是 slf4j + logback, 但是 JBoss 的日志会和这个由冲突,还需要另外的配置文件

这样才能正常打印日志。

效果

启动服务器,就可以看到如下界面了:

 index 页面

index 页面

添加用户后:
添加用户后
添加用户后

总结

使用 Maven 分层次管理还是比较方便的,需要注意的就是,生成的 Artifact 包需要保护该模块依赖的模块的编译内容,否则将导致 ClassNotFound 异常。另外就是 JBoss 的日志冲突的坑需要略微注意。
你可以在 GitHub 上找到本文的完整代码,直接使用 IEDA 即可打开运行。

感谢阅读。
最后,祝大家中秋节快乐!


发表评论

电子邮件地址不会被公开。 必填项已用*标注