GWTでTwitter
GWTを使って、発言、検索、TLの表示をするアプリを作成する
■アプリ概要
- ページを開くとTimeLineの取得をする
- Sayボタンを押すとTextBoxの内容をつぶやく
- Searchボタンを押すとTextBoxの内容を検索する
- 更新ボタンを押すとTimeLineを更新する
■レイアウト
- RootPane
- SendPanel
- TextBox
- SendButton
- SearchPanek
- TextBox
- SendButton
- TLPanel
- 更新Button
- SendPanel
■プロジェクト概要
- プロジェクト名:GwtTwitter
■作成手順
- twitter4jの追加
- Beansの作成
- twitterのラッパークラスを用意してRPC通信をする
- ユーザ名、つぶやき、Icon、などをフィールドにもつ
- twitterのラッパークラスを用意してRPC通信をする
- Service・ServiceAsync作成
- つぶやきメソッド定義
- 検索メソッド定義
- TL取得定義
- Cliantクラス作成
- コールバックを作成
- ServiceImpleの作成
上記メソッドの実装
■twitter4jの追加
- twitter4jを用意する
- プロジェクト右クリック → Buildpath → Configure Build Path → Liblaryタブ → AddExternal JARs → twitter4jを選択
- war\WEB-INF\libフォルダにjarファイル配置する
■TwitterBeans
つぶやきデータのラッパークラスを作成する。
- client以下にentityパッケージを作成する
- IsSerializableインタフェースを実装
- Beansクラスを作成
- 以下のプロパティを定義
- 名前
- スクリーン名前
- ImageIcon
- ホームURL
- つぶやき
- つぶやき時間
をもたせる
private String userName; private String userScreenName; private String profileImageURL; private String home; private String tubuyaki; private String tubuyakiTime;
■Service
以下のメソッドを定義する
- タイムラインの取得の定義
- つぶやくメソッドの定義
- つぶやき検索の定義
/** * タイムラインの取得 * @return */ ArrayList<TwitterBeans> getFriendTimeline(); /** * つぶやく * @param input * @return */ String say(String input); /** * つぶやき検索 * @param input * @return */ ArrayList<TwitterBeans> search(String input); /** * ユーザ情報を取得する * @param id * @param pass * @return */ TwitterBeans getUser(String id, String pass);
■GreetingServiceAsync
Serviceに対応したメソッドを定義する
void say(String input, AsyncCallback<String> callback); void search(String input, AsyncCallback<ArrayList<TwitterBeans>> callback); void getFriendTimeline(AsyncCallback<ArrayList<TwitterBeans>> callback); void getUser(String id, String pass, AsyncCallback<TwitterBeans> callback);
■GreetingServiceImpl
Serviceインタフェースを実装する
各メソッドにはTwitterBeansをセットするsetBeansDataメソッドを呼び出す。
※setBeansDataの内容については後述するソースを参照
sayメソッド
引数inputの内容をつぶやく
つぶやくにはTwitterオブジェクトのupdateStatusメソッドを呼び出す
Twitter twitter = new Twitter(ID, PASS);
twitter.updateStatus(input);
searchメソッド
PublicTimelineを取得し、引数の内容と一致したものを取得する
取得したデータをTwitterBeansリストに格納する
@Override public ArrayList<TwitterBeans> search(String input) { Twitter twitter = new Twitter(); Query query = new Query(input); QueryResult result; ArrayList<TwitterBeans> listTwitter = new ArrayList<TwitterBeans>(); try { result = twitter.search(query); for (Tweet tweet : result.getTweets()) { TwitterBeans bean = new TwitterBeans(); setBeansData(bean, tweet); listTwitter.add(bean); } } catch (TwitterException e) { e.printStackTrace(); } return listTwitter; }
getFriendTimelineメソッド
FriendTimelineを取得する
@Override public ArrayList<TwitterBeans> getFriendTimeline() { // get timeline Twitter twitter = new Twitter(ID, PASS); List<Status> statuses = null; ArrayList<TwitterBeans> listTwitter = new ArrayList<TwitterBeans>(); try { statuses = twitter.getFriendsTimeline(); } catch (TwitterException e) { e.printStackTrace(); } for (Status status : statuses) { TwitterBeans bean = new TwitterBeans(); setBeansData(bean, status); listTwitter.add(bean); } return listTwitter; }
getUserメソッド
指定したIDのユーザを取得し、TwitterBeansに格納する
@Override public TwitterBeans getUser(String id, String pass) { Twitter twitter = new Twitter(ID, PASS); TwitterBeans bean = new TwitterBeans(); try { User user = twitter.showUser(id); setBeansUserData(bean, user); } catch (TwitterException e) { e.printStackTrace(); } return bean; }
■GwtTwitterSample
今回はUI関係が多いので各UIの作成メソッドを用意する
画面の初期化が完了したら、FriendTimeLineを表示する
クライアント側のコードを作成する
- UIを初期化しコールバック関数を作成する
- Profile
- つぶやき
- 検索
- FlendTimeLine
今回はUI関係が多いので各UIの作成メソッドを用意する
■Constant
定数定義クラス
TwitterID/Passを定義
■実行結果
■ソース
■TwitterBeans
package gwt.twitter.sample.client.beans; import com.google.gwt.user.client.rpc.IsSerializable; public class TwitterBeans implements IsSerializable { private String userName; private String userScreenName; private String profileImageURL; private String home; private String tubuyaki; private String tubuyakiTime; private String description; public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } /** * コンストラクタ */ public TwitterBeans() { super(); } //UserName accesser public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } //UserScreenName public String getUserScreenName() { return userScreenName; } public void setUserScreenName(String userScreenName) { this.userScreenName = userScreenName; } //ProfileImageURL public String getProfileImageURL() { return profileImageURL; } public void setProfileImageURL(String profileImageURL) { this.profileImageURL = profileImageURL; } //Home public String getHome() { return home; } public void setHome(String home) { this.home = home; } //Tubuyaki public String getTubuyaki() { return tubuyaki; } public void setTubuyaki(String tubuyaki) { this.tubuyaki = tubuyaki; } //TubuyakiTime public String getTubuyakiTime() { return tubuyakiTime; } public void setTubuyakiTime(String tubuyakiTime) { this.tubuyakiTime = tubuyakiTime; } }
■GreetingService
package gwt.twitter.sample.client; import gwt.twitter.sample.client.beans.TwitterBeans; import java.util.ArrayList; import com.google.gwt.user.client.rpc.RemoteService; import com.google.gwt.user.client.rpc.RemoteServiceRelativePath; /** * The client side stub for the RPC service. */ @RemoteServiceRelativePath("greet") public interface GreetingService extends RemoteService { /** * タイムラインの取得 * @return */ ArrayList<TwitterBeans> getFriendTimeline(); /** * つぶやく * @param input * @return */ String say(String input); /** * つぶやき検索 * @param input * @return */ ArrayList<TwitterBeans> search(String input); /** * ユーザ情報を取得する * @param id * @param pass * @return */ TwitterBeans getUser(String id, String pass); }
■GreetingServiceAsync
package gwt.twitter.sample.client; import gwt.twitter.sample.client.beans.TwitterBeans; import java.util.ArrayList; import com.google.gwt.user.client.rpc.AsyncCallback; /** * The async counterpart of <code>GreetingService</code>. */ public interface GreetingServiceAsync { void say(String input, AsyncCallback<String> callback); void search(String input, AsyncCallback<ArrayList<TwitterBeans>> callback); void getFriendTimeline(AsyncCallback<ArrayList<TwitterBeans>> callback); void getUser(String id, String pass, AsyncCallback<TwitterBeans> callback); }
■Constant
public final class Constants { public static final String ID = "XXXXXXXX"; public static final String PASS = "XXXXXXX"; }
■GreetingServiceImpl
package gwt.twitter.sample.server; import gwt.twitter.sample.client.GreetingService; import gwt.twitter.sample.client.beans.TwitterBeans; import gwt.twitter.sample.client.constnats.Constants; import java.util.ArrayList; import java.util.List; import twitter4j.Query; import twitter4j.QueryResult; import twitter4j.Status; import twitter4j.Tweet; import twitter4j.Twitter; import twitter4j.TwitterException; import twitter4j.User; import com.google.gwt.user.server.rpc.RemoteServiceServlet; /** * The server side implementation of the RPC service. */ @SuppressWarnings("serial") public class GreetingServiceImpl extends RemoteServiceServlet implements GreetingService { /** * TweetオブジェクトからTwitterBeansを作成する * @param bean * @param tweet */ private void setBeansData(TwitterBeans bean, Tweet tweet){ bean.setUserName(tweet.getFromUser()); bean.setProfileImageURL(tweet.getProfileImageUrl()); bean.setTubuyaki(tweet.getText()); bean.setTubuyakiTime(tweet.getCreatedAt().toString()); } /** * StatusオブジェクトからTwitterBeansオブジェクトを作成する * @param bean * @param status */ private void setBeansData(TwitterBeans bean, Status status){ User user = status.getUser(); //Beansを設定する //Userオブジェクトからデータを追加 setBeansUserData(bean, user); //Tweetデータの追加 bean.setTubuyaki(status.getText()); } /** * TwitterBeansにUserオブジェクトのデータを追加 * @param bean * @param user */ private void setBeansUserData(TwitterBeans bean, User user){ bean.setUserName(user.getName()); bean.setUserScreenName(user.getScreenName()); bean.setProfileImageURL(user.getProfileImageURL().toString()); bean.setHome("http://www.twitter.com/" + user.getName()); bean.setDescription(user.getDescription()); } @Override public TwitterBeans getUser(String id, String pass) { Twitter twitter = new Twitter(Constants.ID, Constants.PASS); TwitterBeans bean = new TwitterBeans(); try { User user = twitter.showUser(id); setBeansUserData(bean, user); } catch (TwitterException e) { e.printStackTrace(); } return bean; } @Override public ArrayList<TwitterBeans> getFriendTimeline() { // get timeline Twitter twitter = new Twitter(Constants.ID, Constants.PASS); List<Status> statuses = null; ArrayList<TwitterBeans> listTwitter = new ArrayList<TwitterBeans>(); try { statuses = twitter.getFriendsTimeline(); } catch (TwitterException e) { e.printStackTrace(); } for (Status status : statuses) { TwitterBeans bean = new TwitterBeans(); setBeansData(bean, status); listTwitter.add(bean); } return listTwitter; } @Override public String say(String input) { try { Twitter twitter = new Twitter(Constants.ID, Constants.PASS); twitter.updateStatus(input); } catch (TwitterException e) { e.printStackTrace(); } return null; } @Override public ArrayList<TwitterBeans> search(String input) { Twitter twitter = new Twitter(); Query query = new Query(input); QueryResult result; ArrayList<TwitterBeans> listTwitter = new ArrayList<TwitterBeans>(); try { result = twitter.search(query); for (Tweet tweet : result.getTweets()) { TwitterBeans bean = new TwitterBeans(); setBeansData(bean, tweet); listTwitter.add(bean); } } catch (TwitterException e) { e.printStackTrace(); } return listTwitter; } }
■GwtTwitterSample
package gwt.twitter.sample.client; import gwt.twitter.sample.client.beans.TwitterBeans; import gwt.twitter.sample.client.constnats.Constants; import java.util.ArrayList; import com.google.gwt.core.client.EntryPoint; import com.google.gwt.core.client.GWT; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.FlexTable; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.Panel; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.VerticalPanel; /** * Entry point classes define <code>onModuleLoad()</code>. */ public class GwtTwitterSample implements EntryPoint { /** * Create a remote service proxy to talk to the server-side Greeting service. */ private final GreetingServiceAsync greetingService = GWT .create(GreetingService.class); //Debug private Panel panelServerRes; private Label serverResponseLabel; private HTML htmlError; //profile private Panel panelProfile; private HTML htmlProfileImage; private HTML htmlProfileDetaile; private AsyncCallback<TwitterBeans> callbackProfile; //つぶやき private Panel panelSendForm; private TextBox txtSay; private Button btSend; private AsyncCallback<String> callbackSay; //タイムライン static final int FRIEND_TIME_LINE_START_ROW = 1; private Panel panelFriendTimeLine; private FlexTable flexTtminline; private HTML htmlTwittwerRes; private Button btGet; private AsyncCallback<ArrayList<TwitterBeans>> callbackGetFriendTimeline; //検索 private Panel panelSerch; private Button btSearch; private TextBox txtSearch; private AsyncCallback<ArrayList<TwitterBeans>> callbackSearch; //検索結果格納リスト private ArrayList<TwitterBeans> resultTwitterBeans = new ArrayList<TwitterBeans>(); /** * This is the entry point method. */ public void onModuleLoad() { initWidget(); RootPanel.get("error").add(this.panelServerRes); RootPanel.get("panelProfile").add(this.panelProfile); RootPanel.get("panelSend").add(this.panelSendForm); RootPanel.get("panelSearch").add(this.panelSerch); RootPanel.get("FriendTimeLine").add(this.panelFriendTimeLine); } private void initWidget(){ //Debug的 this.htmlError = new HTML(); this.serverResponseLabel = new Label(); this.panelServerRes = new VerticalPanel(); this.panelServerRes.add(this.htmlError); this.panelServerRes.add(this.serverResponseLabel); this.createProfile(); this.createTweetForm(); this.createSearchForm(); this.createFriendTimelineForm(); //Profileを表示 greetingService.getUser(Constants.ID, Constants.PASS, callbackProfile); //フレンドラインを表示 greetingService.getFriendTimeline(callbackGetFriendTimeline); } /** * プロフィールフォームの作成 */ private void createProfile(){ this.panelProfile = new HorizontalPanel(); this.htmlProfileImage = new HTML(); this.htmlProfileDetaile = new HTML(); this.panelProfile.add(this.htmlProfileImage); this.panelProfile.add(this.htmlProfileDetaile); //コールバックの作成 this.callbackProfile = new AsyncCallback<TwitterBeans>(){ @Override public void onFailure(Throwable caught) { serverResponseLabel.setText("Server Response Error"); htmlError.setHTML(caught.getMessage()); } @Override public void onSuccess(TwitterBeans result) { String username = "<b>" + result.getUserScreenName() + "/" + result.getUserName() + "</b>"; htmlProfileImage.setHTML("<img src=\"" + result.getProfileImageURL() + "\" />"); htmlProfileDetaile.setHTML(username + "<br>" + result.getDescription()); } }; } /** * つぶやきフォームを作成する */ private void createTweetForm(){ //つぶやき領域 this.btSend = new Button("say"); this.txtSay = new TextBox(); this.panelSendForm = new VerticalPanel(); this.panelSendForm.add(this.txtSay); this.panelSendForm.add(this.btSend); //つぶやきコールバック this.callbackSay = new AsyncCallback<String>(){ @Override public void onFailure(Throwable caught) { serverResponseLabel.setText("Server Response Error"); htmlError.setHTML(caught.getMessage()); } @Override public void onSuccess(String result) { serverResponseLabel.setText("Success"); } }; //つぶやくRPC this.btSend.addClickHandler(new ClickHandler(){ @Override public void onClick(ClickEvent event) { greetingService.say(txtSay.getText(), callbackSay); greetingService.getFriendTimeline(callbackGetFriendTimeline); } }); } /** * 検索フォームを作成する */ private void createSearchForm(){ //検索 this.panelSerch = new VerticalPanel(); this.btSearch = new Button("Seach"); this.txtSearch = new TextBox(); this.panelSerch.add(this.txtSearch); this.panelSerch.add(this.btSearch); //検索コールバック this.callbackSearch = new AsyncCallback<ArrayList<TwitterBeans>>(){ @Override public void onFailure(Throwable caught) { htmlError.setHTML("<b>Error</b><br>" + caught.getMessage()); } @Override public void onSuccess(ArrayList<TwitterBeans> result) { display(result); } }; //探すRPC this.btSearch.addClickHandler(new ClickHandler(){ @Override public void onClick(ClickEvent event) { flexTtminline.clear(); greetingService.search(txtSearch.getText(), callbackSearch); } }); } /** * フレンドラインを取得する */ private void createFriendTimelineForm(){ //FriendTimeline領域 this.panelFriendTimeLine = new VerticalPanel(); this.btGet = new Button("更新"); this.flexTtminline = new FlexTable(); this.flexTtminline.setBorderWidth(1); this.flexTtminline.setHTML(FRIEND_TIME_LINE_START_ROW, 0, "<b>UserID</b>"); this.flexTtminline.setHTML(FRIEND_TIME_LINE_START_ROW, 1, "<b>Comment</b>"); this.flexTtminline.setHTML(FRIEND_TIME_LINE_START_ROW, 2, "<b>time</b>"); this.htmlTwittwerRes = new HTML(); this.panelFriendTimeLine.add(this.btGet); this.panelFriendTimeLine.add(this.flexTtminline); this.panelFriendTimeLine.add(this.htmlTwittwerRes); //コールバック //フレンドラインコールバックBeans this.callbackGetFriendTimeline = new AsyncCallback<ArrayList<TwitterBeans>>(){ @Override public void onFailure(Throwable caught) { htmlError.setHTML("<b>Error</b><br>" + caught.getMessage()); } @Override public void onSuccess(ArrayList<TwitterBeans> result) { display(result); } }; //FriendTimeLineデータ取得RPC this.btGet.addClickHandler(new ClickHandler(){ @Override public void onClick(ClickEvent event) { //フレンドタイムラインを取得 greetingService.getFriendTimeline(callbackGetFriendTimeline); } }); } private void display(ArrayList<TwitterBeans> result){ int cnt = FRIEND_TIME_LINE_START_ROW; for( TwitterBeans bean : result){ String col1 = "<img src=\"" + bean.getProfileImageURL() + "\" />"; flexTtminline.setWidget(cnt, 0, new HTML(col1)); flexTtminline.setWidget(cnt, 1, new HTML("<b>" + bean.getUserName() + "</b><br>" + bean.getTubuyaki())); flexTtminline.setWidget(cnt, 2, new HTML(bean.getTubuyakiTime())); cnt++; } } }