4

1か月前から、私は安らかなWebサービスを本当に一生懸命勉強しています。構文を練習し、概念を理解したので、EJB、JPA、RESTを含む非常に単純なエンタープライズアプリケーションを作成することにしました。私は、この種のシステムを整理するための最良の方法を理解しようと懸命に努力しています。この分野での経験を持つ誰かが、ベストプラクティスとなるもの、および現在の問題をどのように解決できるかについてのヒントを教えてくれれば、とても感謝しています。

この画像を見せてください。申し訳ありませんが、より良い解像度を得ることができません(Ctrl +マウススクロールアップを使用してズームします):

ここに画像の説明を入力してください

ご覧のとおり、これは2つのモジュールを持つ非常にシンプルなエンタープライズアプリです。

このアプリケーションはCDIを使用していません(CDIの助けなしに目標を達成したいです)

一部のクライアント(相互運用可能なクライアント)がいくつかのパラメーターを含む@GETを送信する場合、RESTサービスはそれらのパラメーターをEJBモジュールに渡し、EJBモジュールはデータベースを検索して適切なデータを送り返します。最後に、サービスはJAXBの助けを借りて自動的にマーシャリングし、.XMLをクライアントに送り返します。

私の問題は次のとおりです。

  • EJBモジュール内のエンティティがWebModule内のJAXBクラスと互換性がないため、ClassCastExceptionが発生します(変数が同じであっても)
  • フロントエンドがそれらのエンティティをマーシャリングおよびアンマーシャリングできるように、物事をどのように編成する必要があるのか​​わかりません。
  • エンティティクラスは、JAXBマッピングと組み合わせてフロントエンドに配置する必要がありますか?その場合、EJBモジュールは実際には必要ありません。ただし、CRUD操作を頻繁に行うため、EJBモジュールが必要です。
  • EJBをRESTWebサービスとして公開する(ハイブリッドにする)のはどうですか?これはいい考えだと思いますか?どのように私を助けることができますか?
  • 繰り返しますが、WebモジュールでJAXRS + EJBのハイブリッドを作成する場合は、フロントエンドでJPAエンティティを作成する必要があります。これは、これまでに行ったことのないことです。それは良い習慣だと思いますか?
  • 何を指示してるんですか?多くの場合、REST Webサービスを使用するエンタープライズアプリケーションはどのように編成されますか?
4

3 に答える 3

5

以下は、永続性にJPAを使用し、メッセージングにJAXBを使用してセッションBeanとして実装されたJAX-RSサービスの例です。(EntityManagerセッションBeanにanが注入されていることに注意してください。なぜ、この種の動作を避けたいのですか?):

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>

詳細については

于 2012-04-05T14:53:48.323 に答える
0

ここでもう1つのコンポーネントであるアプリケーションサービスを見逃していると思います。さらに、あなたCRUDFacadeはただのCredentialRepositoryです。

上記のコンポーネントを使用すると、2つの可能な解決策があります。

  1. アプリケーションサービスが明確に分離されている場合、SampleServiceそのようなサービスを外の世界に公開するための多くの可能な方法の1つにすぎません。あなたはSampleRestResourceSampleYamlResource;)またはあなたの選択の他のものを持つことができます。CredentialDTO そのような場合は、フィールドを作成して注釈を付けることをお勧めします@XmlRootElement。アプリケーションサービスはこのDTOを外部に返し、SampleRestResource(以前はSampleService)転送するだけです。
  2. DTO(おそらくアセンブラーと一緒に)や個別のクラスのような追加のビルディングブロックを導入したくない場合はSampleRestResource、アプリケーションサービスメソッドにアノテーションを追加できます-ただし、すべてのJAXWS実装でそれが可能かどうかはわかりません。

私が説明したアプローチに従って、通常、残りのリソースとアプリケーションサービスを1つのモジュールに配置します。あなたのEJBモジュール(現在私を純粋なドメインモジュールとして探しています)は、その依存関係の1つにすぎません。

于 2012-04-05T14:39:15.457 に答える
0

公開しているドメインをモデルドメインから分離することをお勧めします。そのため、エンティティと生成されたクラスを切り離して、このように維持します。このClassCastExceptionを解決する簡単な方法は、Webモジュールでjaxbクラスを入力としてエンティティにマップし、その逆を出力としてマップすることです。手作業で行うことも、このマッピングに対処するためのさまざまなライブラリがあります。すなわちdozer(http://dozer.sourceforge.net/)

于 2012-04-05T14:42:29.013 に答える