twitterクライアントを作ってみるテスト
どうも、Ramencozoです(´ω`)
東北から関東にかけて、大地震で大変です。
被災者のみなさま、自分からはほとんどなにもできないのですが、ご無事をお祈りいたします。
救出にあたった自衛隊員さん、海外から派遣された方々、現場で直接手伝った方々、みなさまおつかれさまです。
素っ気無い書き方になってしまい申し訳ありませんが、自分の技術ネタのお話に入ります。
自己プロジェクトのひとつでいろいろやる中で、Twitter使ったうんぬんなものを思いついてまして。
内容的にはPCとマイコンをシリアル通信させといて(ryというのですが、全貌はできあがってからお見せします(´ω`)
さて。今回作ろうとしたクライアントの仕様としては下記。
・PC(Ubuntu)で動作
・リプライをコマンドとして受信
・シリアルポートの先のマイコンへそのコマンドを伝達
・Java Swing(GUI) + Twitter4J(つぃったラッパクラス) + RXTX(COMポートライブラリ)を使う
でもって。今回やったのは下記な実装。
・GUI周り
・TwitterアカウントのOAuth認証
・クライアントからのTweet
・クライアントにてリプライ取得&最新リプのみ抽出
とりあえずここにひとまずのソース置いてみます。
上左から右下へ向かって順に、OAuth認証用PINナンバー入力エリア、認証ボタン、認証ページ(Webブラウザ経由)起動ボタン、Post用入力エリア、最新リプ取得ボタン、もろもろログ表示窓。
たぶん後々PostするためのTextFieldはいらなくなるかと。(そういうクライアントではないので。今はとりあえず挙動確認のためつけたけども)
とりあえずソース下記。
Main.java(GUI担当)
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Desktop;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.List;import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.border.EtchedBorder;class Main extends JFrame implements ActionListener {
private final String title = "こんとろーらーだッ!";
private final String version = "ver0.1";// アプリ固有のつぃったコンシューマキー・シークレット
private final String consumerKey = "自分のソレ";
private final String consumerSecret = "自分のソレ";//画面パーツ関連
private JTextField pincode;
private JButton authButton;
private JButton authPageButton;
private JLabel authStatus;private JTextField tweetField;
private JButton getMentionButton;private JTextArea logArea;
//Twitter4J含んだヲレヲレクラス(後述)
private TwiUtils twiUtils;//メンション一覧関連
private ListpreviousMentions;
private ListnewMentions;
private boolean isFirstReply;
public static void main(String[] args) {
Main mainWindow = new Main();
mainWindow.setVisible(true);
}Main() {
//初回メンション取得のためのフラグ
isFirstReply = true;//ヲレヲレクラスのインスタンス生成
twiUtils = new TwiUtils(consumerKey, consumerSecret);//JFrameなウィンドウ(x=800,y=600)の設定
setTitle(title + " " + version);
setBounds(100, 100, 800, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container contentPane = getContentPane();//親パネル、上段パネル、中段パネル、下段パネル
JPanel parentPanel = new JPanel();
JPanel authPanel = new JPanel();
JPanel tweetPanel = new JPanel();
JPanel logPanel = new JPanel();//各部品の準備(new、パネルに貼り付け、リスナ登録)
pincode = new JTextField(8);
authPanel.add(pincode, BorderLayout.CENTER);
pincode.addActionListener(this);authButton = new JButton("認証");
authButton.addActionListener(this);
authPanel.add(authButton, BorderLayout.CENTER);authPageButton = new JButton("OAuth認証ページへ");
authPageButton.addActionListener(this);
authPanel.add(authPageButton, BorderLayout.CENTER);authStatus = new JLabel("認証状態:未");
authPanel.add(authStatus, BorderLayout.CENTER);tweetField = new JTextField(50);
tweetPanel.add(tweetField, BorderLayout.CENTER);
tweetField.addActionListener(this);getMentionButton = new JButton("リプライ取得");
getMentionButton.addActionListener(this);
tweetPanel.add(getMentionButton, BorderLayout.CENTER);//ログウィンドウの生成(書き込み不可、枠付き)
logArea = new JTextArea(20, 60);
logArea.setEditable(false);
logArea.setBorder(new EtchedBorder(EtchedBorder.RAISED));//ログウィンドウにスクロール(縦・横、必要時に自動出現)をセット
JScrollPane scrollPane = new JScrollPane(
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scrollPane.getVerticalScrollBar().setUnitIncrement(25);
scrollPane.getViewport().add(logArea);logPanel.add(scrollPane, BorderLayout.CENTER);
parentPanel.add(authPanel, BorderLayout.NORTH);
parentPanel.add(tweetPanel, BorderLayout.CENTER);
parentPanel.add(logPanel, BorderLayout.SOUTH);
contentPane.add(parentPanel, BorderLayout.CENTER);
}//各部品のイベント
@Override
public void actionPerformed(ActionEvent ae) {
// TODO Auto-generated method stub
if (ae.getSource() == authButton || ae.getSource() == pincode) {
boolean authFlag = twiUtils.getOAuth(pincode.getText());
if (authFlag) {
logArea.append("OAuth認証完了しました。本アプリケーションが使用可能となります" + "\n");
authStatus.setText("認証状態:済");
} else {
logArea.append("OAuth認証に失敗しました。再起動してやり直してみてください。" + "\n");
}
logArea.setCaretPosition(logArea.getText().length());
}
if (ae.getSource() == authPageButton) {
Desktop desktop = Desktop.getDesktop();
logArea.append("認証のためブラウザを起動します・・・" + "\n");
try {
desktop.browse(twiUtils.getPinViaWebPage());
logArea.append("ブラウザが起動しました。認証してください" + "\n");
} catch (IOException e) {
e.printStackTrace();
logArea.append("ブラウザの起動に失敗しました" + "\n");
}
logArea.setCaretPosition(logArea.getText().length());
}
if (ae.getSource() == tweetField) {
new Thread() {
public void run() {
twiUtils.Tweet(tweetField.getText());
logArea.append("あなたのツィート-> " + tweetField.getText() + "\n");
tweetField.setText("");
logArea.setCaretPosition(logArea.getText().length());
}
}.start();
}
if (ae.getSource() == getMentionButton) {
new Thread() {
public void run() {
newMentions = twiUtils.getMention();
int latestMention = 0;if(!isFirstReply){
latestMention = newMentions.indexOf(previousMentions.get(0));
}else{
latestMention = -1;
}if (latestMention == -1) {
logArea.append("すべて最新のリプライのようです・・・\n");
latestMention = newMentions.size();
} else if(latestMention > 0){
logArea.append("更新されたリプライがあります\n");
latestMention = newMentions.indexOf(previousMentions.get(0));
} else{
logArea.append("リプライは来てないようです\n");
latestMention = 0;
}
for (int i = 0; i < latestMention; i++) {
logArea.append("リプライ-> " + newMentions.get(i) + "\n");
}
previousMentions = newMentions;
isFirstReply = false;
logArea.setCaretPosition(logArea.getText().length());
}
}.start();
}
}
}
TwiUtils.java(つぃった周り担当)
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;//twitter4j-core-2.2.0.jar(バージョンは変動)をビルドパスに含むべし
import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.auth.AccessToken;
import twitter4j.auth.RequestToken;class TwiUtils {
private TwitterFactory factory;
private AccessToken accessToken;
private Twitter twitter;
private String url;
private RequestToken requestToken;//Main.javaからコンシューマキー・シークレットもらう
//コンストラクタ内では認証URL生成までしとく
TwiUtils(String consumerKey, String consumerSecret) {
factory = new TwitterFactory();twitter = factory.getInstance();
twitter.setOAuthConsumer(consumerKey, consumerSecret);
try {
requestToken = twitter.getOAuthRequestToken();
url = requestToken.getAuthorizationURL();
} catch (TwitterException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}//コンストラクタで得た認証URLを与える
public URI getPinViaWebPage() {
URI uri = null;
try {
uri = new URI(url);
System.out.println("URI getting is OK.");
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println(e.getMessage());
}
return uri;
}//ブラウザで表示されたPINコードをMain.javaのTextFieldから与えてもらう
//ソレ使って正式にユーザー認証完了する
public boolean getOAuth(String pin) {
try {
if (pin.length() > 0) {
accessToken = twitter.getOAuthAccessToken(requestToken, pin);
twitter.setOAuthAccessToken(accessToken);
} else {
accessToken = twitter.getOAuthAccessToken();
twitter.setOAuthAccessToken(accessToken);
}
return true;
} catch (TwitterException te) {
// TODO Auto-generated catch block
if (te.getStatusCode() == 401) {
System.out.println("Unable to get the access token");
} else {
te.printStackTrace();
}
return false;
}
}//アプリからPostを行う
public void Tweet(String message) {
try {
twitter.updateStatus(message + " [from 自作クラ]"); //フッタ要らんけど
System.out.println("Tweet Done!");
} catch (TwitterException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("Something Wrong...");
}
}//最新メンションゲトー(初回:最新18件リプ取得、次回:更新されたリプのみ)
public ListgetMention() {
Listmentions = null;
try {
Listmentionstatus = twitter.getMentions();
for(Status status : mentionstatus){
mentions.add(status.getUser().getScreenName() + ":" + status.getText());
}
} catch (TwitterException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Getting Reply Done!");
return mentions;
}
}
ひとまず細かい部分のネタは後日(ry