java - 应如何组织提供 REST Web 服务的 JEE6 企业应用程序?

标签 java design-patterns jakarta-ee rest jax-rs

从一个月前开始,我就非常努力地研究 restful web 服务。 现在我已经练习了语法并且理解了这些概念,我决定制作一个非常简单的企业应用程序,其中包括 EJB、JPA 和 REST。 我正在努力了解什么是组织这种系统的最佳方式。如果有该领域经验的人可以给我一些关于什么是最佳实践以及我如何解决当前问题的提示,我将不胜感激。

请让我给你看这张图片。抱歉,我无法获得更好的分辨率(使用 Ctrl+ 鼠标向上滚动可缩放):

enter image description here

如您所见,这是一个非常简单的企业应用程序,有 2 个模块。

此应用程序不使用 CDI(我想在没有 CDI 帮助的情况下实现我的目标并且)

当某些客户端(任何可互操作的客户端)发送带有某些参数的@GET 时,REST 服务应将这些参数传递给 EJB 模块,该模块将在数据库中搜索并发回适当的数据。最后,服务将在 JAXB 的帮助下自动编码并将 .XML 发送回客户端。

我的问题如下:

  • 我得到一个 ClassCastException,因为 EJB 模块中的实体与 WebModule 中的 JAXB 类不兼容(即使它们的变量相同)
  • 我不知道应该如何组织事情,以便前端可以编码和取消编码这些实体。
  • 实体类是否应该在前端与 JAXB 映射相结合?如果那样的话,就不会真的需要 EJB 模块了。但问题是,我想要 EJB 模块,因为我经常在那里进行 CRUD 操作。
  • 如何将 EJB 公开为 REST Web 服务(制作混合)?你认为这是个好主意吗?它对我有什么帮助?
  • 同样,如果我在 Web 模块中创建 JAXRS+EJB 的混合体,我将必须在前端创建我的 JPA 实体,这是我以前从未做过的事情。您认为这是一种好的做法吗?
  • 你有什么建议?使用 REST Web 服务的企业应用程序的组织方式通常是什么?

最佳答案

下面是一个将 JAX-RS 服务实现为 session bean 的示例,使用 JPA 实现持久化,使用 JAXB 实现消息传递。 (注意 EntityManager 被注入(inject) session bean,为什么要避免这种行为?):

package org.example;

import java.util.List;

import javax.ejb.*;
import javax.persistence.*;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;

@Stateless
@LocalBean
@Path("/customers")
public class CustomerService {

    @PersistenceContext(unitName="CustomerService",
                        type=PersistenceContextType.TRANSACTION)
    EntityManager entityManager;

    @POST
    @Consumes(MediaType.APPLICATION_XML)
    public void create(Customer customer) {
        entityManager.persist(customer);
    }

    @GET
    @Produces(MediaType.APPLICATION_XML)
    @Path("{id}")
    public Customer read(@PathParam("id") long id) {
        return entityManager.find(Customer.class, id);
    }

    @PUT
    @Consumes(MediaType.APPLICATION_XML)
    public void update(Customer customer) {
        entityManager.merge(customer);
    }

    @DELETE
    @Path("{id}")
    public void delete(@PathParam("id") long id) {
        Customer customer = read(id);
        if(null != customer) {
            entityManager.remove(customer);
        }
    }

    @GET
    @Produces(MediaType.APPLICATION_XML)
    @Path("findCustomersByCity/{city}")
    public List<Customer> findCustomersByCity(@PathParam("city") String city) {
        Query query = entityManager.createNamedQuery("findCustomersByCity");
        query.setParameter("city", city);
        return query.getResultList();
    }

}

如果你想在服务器端和客户端使用相同的域对象。然后我会通过 XML 而不是注释提供 JPA 映射,以避免客户端上的类路径依赖。

了解更多信息


更新

META-INF/persistence.xml

persistence.xml 文件是您指定指向包含 JPA 映射的 XML 文件的链接的地方:

<persistence-unit name="CustomerService" transaction-type="JTA">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>CustomerService</jta-data-source>
    <mapping-file>META-INF/orm.xml</mapping-file>
</persistence-unit>

META-INF/orm.xml

您将在这个文件中添加 JPA 元数据的 XML 表示。

<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings
    version="2.0"
    xmlns="http://java.sun.com/xml/ns/persistence/orm"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_2_0.xsd">
    <entity class="org.example.Customer">
         <named-query name="findCustomersByCity">
            <query>SELECT c FROM Customer c WHERE c.address.city = :city</query>
         </named-query>
         <attributes>
            <id name="id"/>
            <basic name="firstName">
                <column name="FIRST_NAME"/>
            </basic>
            <basic name="lastName">
                <column name="LAST_NAME"/>
            </basic>
            <one-to-many name="phoneNumbers" mapped-by="customer">
                <cascade>
                    <cascade-all/>
                </cascade>
            </one-to-many>
            <one-to-one name="address" mapped-by="customer">
                <cascade>
                    <cascade-all/>
                </cascade>
            </one-to-one>
         </attributes>
    </entity>
    <entity class="org.example.Address">
        <attributes>
            <id name="id"/>
            <one-to-one name="customer">
                <primary-key-join-column/>
            </one-to-one>
        </attributes>
    </entity>
    <entity class="org.example.PhoneNumber">
        <table name="PHONE_NUMBER"/>
        <attributes>
            <id name="id"/>
            <many-to-one name="customer">
                <join-column name="ID_CUSTOMER"/>
            </many-to-one>
        </attributes>
    </entity>
</entity-mappings>

了解更多信息

关于java - 应如何组织提供 REST Web 服务的 JEE6 企业应用程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10029976/

相关文章:

java - Jersey Rest API立即返回,长任务继续

java - 查找和替换字符串

java - android - 使用 firestore 而不是 auth

c# - 使用带有日期时间和 bool 值的自动映射器来表示 POCO 中的半天

java - EJB 的类加载器问题

java - RESTful 服务中的注释(@EJB、@Resource...)

java - 您的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册,了解在 'order 附近使用的正确语法

java - JBoss JMS 存储队列文件

python - 匹配文件中的行,例如 grep -f

c++ - 避免 "if failed cleanup"重复的模式