20

EclipseGoogle Pluginを使用して Google Web Toolkit StockWatcher Tutorialを実行しました。RPCフレームワークをよりよく理解できるように、それにいくつかの基本的な変更を加えようとしています。

StockServiceImpl サーバー側クラスの「getStocks」メソッドを変更して、String オブジェクトではなく Stock オブジェクトの配列を返すようにしました。アプリケーションは完全にコンパイルされますが、Google Web Toolkit は次のエラーを返します:

「com.google.gwt.sample.stockwatcher.server.Stock 型のソース コードはありません。必要なモジュールを継承するのを忘れていませんか?」

Google Web Toolkit のホスト モード

クラスがインポートされているにもかかわらず、クライアント側のクラスは Stock オブジェクトの実装を見つけることができないようです。参考までに、私のパッケージ階層のスクリーンショットを次に示します。

Eclipse パッケージ階層

web.xml に何かが欠けているのではないかと思いますが、それが何かわかりません。誰かが私を正しい方向に向けることができますか?

編集: Stock クラスは持続可能であることを忘れていたので、サーバー側にとどまる必要があります。

4

8 に答える 8

23

多くの試行錯誤の後、私はこれを行う方法を見つけることができました。最善の方法ではないかもしれませんが、うまくいきます。この投稿が他の誰かの時間と労力を大幅に節約できることを願っています.

これらの手順は、基本的な StockWatcher チュートリアルGoogle App Engine StockWatcher の変更の両方を完了していることを前提としています。

Stock クラスのクライアント側実装を作成する

GWT については、次の点に注意してください。

  1. サーバー側のクラスはクライアント側のクラスをインポートできますが、その逆はできません (通常)。
  2. クライアント側は Google App Engine ライブラリをインポートできません (つまり、com.google.appengine.api.users.User)

上記の両方の項目により、クライアントは、com.google.gwt.sample.stockwatcher.server で作成した Stock クラスを実装できません。代わりに、StockClient という新しいクライアント側の Stock クラスを作成します。

StockClient.java:

package com.google.gwt.sample.stockwatcher.client;

import java.io.Serializable;
import java.util.Date;

public class StockClient implements Serializable {

  private Long id;
  private String symbol;
  private Date createDate;

  public StockClient() {
    this.createDate = new Date();
  }

  public StockClient(String symbol) {
    this.symbol = symbol;
    this.createDate = new Date();
  }

  public StockClient(Long id, String symbol, Date createDate) {
    this();
    this.id = id;
    this.symbol = symbol;
    this.createDate = createDate;
  }

  public Long getId() {
      return this.id;
  }

  public String getSymbol() {
      return this.symbol;
  }

  public Date getCreateDate() {
      return this.createDate;
  }

  public void setId(Long id) {
    this.id = id;
  }

  public void setSymbol(String symbol) {
      this.symbol = symbol;
  }
}

String[] の代わりに StockClient[] を使用するようにクライアント クラスを変更する

ここで、RPC 呼び出しが String[] ではなく StockClient[] を返すことを認識できるように、クライアント クラスに簡単な変更を加えます。

StockService.java:

package com.google.gwt.sample.stockwatcher.client;

import com.google.gwt.sample.stockwatcher.client.NotLoggedInException;
import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;

@RemoteServiceRelativePath("stock")
public interface StockService extends RemoteService {
  public Long addStock(String symbol) throws NotLoggedInException;
  public void removeStock(String symbol) throws NotLoggedInException;
  public StockClient[] getStocks() throws NotLoggedInException;
}

StockServiceAsync.java:

package com.google.gwt.sample.stockwatcher.client;

import com.google.gwt.sample.stockwatcher.client.StockClient;
import com.google.gwt.user.client.rpc.AsyncCallback;

public interface StockServiceAsync {
  public void addStock(String symbol, AsyncCallback<Long> async);
  public void removeStock(String symbol, AsyncCallback<Void> async);
  public void getStocks(AsyncCallback<StockClient[]> async);
}

StockWatcher.java:

1 つのインポートを追加します。

import com.google.gwt.sample.stockwatcher.client.StockClient;

addStock、loadStocks、displayStocks を除いて、他のすべてのコードは同じままです。

private void loadStocks() {
    stockService = GWT.create(StockService.class);
    stockService.getStocks(new AsyncCallback<String[]>() {
        public void onFailure(Throwable error) {
            handleError(error);
        }

        public void onSuccess(String[] symbols) {
            displayStocks(symbols);
        }
    });
}

private void displayStocks(String[] symbols) {
    for (String symbol : symbols) {
        displayStock(symbol);
    }
}

private void addStock() {
    final String symbol = newSymbolTextBox.getText().toUpperCase().trim();
    newSymbolTextBox.setFocus(true);

    // Stock code must be between 1 and 10 chars that are numbers, letters,
    // or dots.
    if (!symbol.matches("^[0-9a-zA-Z\\.]{1,10}$")) {
        Window.alert("'" + symbol + "' is not a valid symbol.");
        newSymbolTextBox.selectAll();
        return;
    }

    newSymbolTextBox.setText("");

    // Don't add the stock if it's already in the table.
    if (stocks.contains(symbol))
        return;

    addStock(new StockClient(symbol));
}

private void addStock(final StockClient stock) {
    stockService.addStock(stock.getSymbol(), new AsyncCallback<Long>() {
        public void onFailure(Throwable error) {
            handleError(error);
        }

        public void onSuccess(Long id) {
            stock.setId(id);
            displayStock(stock.getSymbol());
        }
    });
}

StockClient[] を返すように StockServiceImpl クラスを変更する

最後に、StockServiceImpl クラスの getStocks メソッドを変更して、配列を返す前にサーバー側の Stock クラスをクライアント側の StockClient クラスに変換するようにします。

StockServiceImpl.java

import com.google.gwt.sample.stockwatcher.client.StockClient;

生成された ID が返されるように、addStock メソッドを少し変更する必要があります。

public Long addStock(String symbol) throws NotLoggedInException {
  Stock stock = new Stock(getUser(), symbol);
  checkLoggedIn();
  PersistenceManager pm = getPersistenceManager();
  try {
    pm.makePersistent(stock);
  } finally {
    pm.close();
  }
  return stock.getId();
}

getStocks を除いて、他のすべてのメソッドは同じままです。

public StockClient[] getStocks() throws NotLoggedInException {
  checkLoggedIn();
  PersistenceManager pm = getPersistenceManager();
  List<StockClient> stockclients = new ArrayList<StockClient>();
  try {
    Query q = pm.newQuery(Stock.class, "user == u");
    q.declareParameters("com.google.appengine.api.users.User u");
    q.setOrdering("createDate");
    List<Stock> stocks = (List<Stock>) q.execute(getUser());
    for (Stock stock : stocks)
    {
       stockclients.add(new StockClient(stock.getId(), stock.getSymbol(), stock.getCreateDate()));
    }
  } finally {
    pm.close();
  }
  return (StockClient[]) stockclients.toArray(new StockClient[0]);
}

概要

上記のコードは、Google App Engine にデプロイすると完全に機能しますが、Google Web Toolkit のホスト モードではエラーが発生します。

SEVERE: [1244408678890000] javax.servlet.ServletContext log: Exception while dispatching incoming RPC call
com.google.gwt.user.server.rpc.UnexpectedException: Service method 'public abstract com.google.gwt.sample.stockwatcher.client.StockClient[] com.google.gwt.sample.stockwatcher.client.StockService.getStocks() throws com.google.gwt.sample.stockwatcher.client.NotLoggedInException' threw an unexpected exception: java.lang.NullPointerException: Name is null

同じ問題が発生したかどうかをお知らせください。Google App Engine で動作するという事実は、ホスト モードのバグを示しているようです。

于 2009-06-07T21:07:30.120 に答える
4

GWT は .class ファイルに加えて .java ファイルを必要とします。さらに、Stock は GWT モジュールの「クライアント」の場所にある必要があります。

于 2009-06-06T04:40:41.343 に答える
3

GWT コンパイラーは、Stock が参照する場所にないため、Stock について認識しません。それを client フォルダーに移動するか、より適切な場合は、そのままにして ModuleName.gwt.xml を作成することができます。必要な他のクラスを参照し、それから継承する Main.gwt.xml ファイルを取得します。

例: DomainGwt.gwt.xml

<module>
    <inherits name='com.google.gwt.user.User'/>
    <source path="javapackagesabovethispackagegohere"/>
</module>

と:

<module rename-to="gwt_ui">
    <inherits name="com.google.gwt.user.User"/>
    <inherits name="au.com.groundhog.groundpics.DomainGwt"/>

    <entry-point class="au.com.groundhog.groundpics.gwt.client.GPicsUIEntryPoint"/>
</module>
于 2009-06-06T04:51:24.530 に答える
1

ここにもっと良い答えがあります: GWT Simple RPC use case problem: Code included

基本的に、APPNAME.gwt.xml ファイルにパラメーターを追加して、コンパイラーがコンパイラーにサーバー側クラスへのパスを与えることができます。

于 2010-07-21T01:25:06.980 に答える
1

私は同じ問題を抱えていて、「mvn gwt:compile」の出力はあまり役に立ちませんでした。代わりに、(maven tomcat プラグイン: mvn tomcat:deploy を介して) tomcat にデプロイしようとすると、役立つエラー メッセージが表示されました。

私が修正しなければならなかったいくつかのこと:

  1. クライアントからサーバーに送信されるオブジェクトを Serializable に実装する
  2. その同じオブジェクトに空の引数コンストラクターを追加します
于 2010-10-12T11:35:26.177 に答える
0

上記のrustyshelfの答えをキーオフ...

私の場合、ModuleName.gwt.xmlファイルを編集して、以下を追加する必要がありました。

<source path='client'/>
<source path='shared'/>

[新規] ->[Webアプリケーションプロジェクト]ウィザードを使用してプロジェクトを作成しましたが、 [プロジェクトサンプルコードの生成]オプションをオフにしました。次に、共有パッケージを作成しました。チェックを外さなかった場合、パッケージは私のために作成され、xmlファイルは上記のように変更されていたでしょう。

于 2012-02-03T21:02:39.710 に答える
0

はい、サーバー オブジェクトをクライアントに取得するためにシリアライゼーションを使用する必要があることは確かです。これらのモディール?? ファイル設定は、クライアント側で Stock クラスを使用するために機能しません。

あなたの場合、Stock クラスは 1 つしかなく、クライアント側で StockClient を作成できます。簡単です。しかし、誰かがより多くのクラスを持っている場合、解決策は何でしょうか。このクラスのプロパティのようなものは、他のタイプのクラスでもあります。

例:stock.getEOD(date).getHigh();

getEOD指定された日付の別のクラスを返し、そのクラスにはgetHighメソッドがあります。

このような大きなケースではどうすればよいですか?クライアント側でシリアライゼーションを実装するすべてのクラスを作成することは、それには適していないと思います。次に、サーバーとクライアントの両方でコードを記述する必要があります。全クラス2回。

于 2009-08-19T14:00:34.613 に答える