twitter4j java 検索したツイートをDB（MySQL）に格納する。

# あるワードについて、過去分（Max8,9日分くらい）取れるだけ取得して、DB（mysql）に格納していくソース。

### 開発環境
　 Eclipse 4.8
　 jdk 1.8

### APIを叩くインターバル
　MAX100件/1APIを、３秒間隔で叩きに行く。
　１インスタンスで１５回叩け、その後１０秒待つ。
　API上限に達すると、エラーコード429が返るので、その場合は、６０秒待つ。

##リソースクラス　SearchWordResource 

```
package CollectionTweet;


import java.util.Date;

import twitter4j.Status;
import twitter4j.TwitterException;
/**
 * 任意のワードを検索し、過去分のツイートをDBに格納するResourceクラス
 */
public class SearchWordResource {

    public static void main(String[] args) {

        // 無限ループ
        for (;;) {

            TrendSearch trendSearchPRG = new TrendSearch();

                WordSearch wordSearchPRG = new WordSearch();
                Status retweetStatus = null;

                try {
                    // 検索し、DBへ格納
                    String wordSearch = "働き方改革";
                    retweetStatus = wordSearchPRG.wordSearch(wordSearch);

                } catch (TwitterException e) {
                    e.printStackTrace();
                }

            // sleep
            try {
                Date date = new Date();
                System.out.println(date.toString());
                Thread.sleep(TwitterContents.TIME_INTERVAL);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
```


## ワード検索クラス　WordSearch

```
package CollectionTweet;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import twitter4j.Query;
import twitter4j.QueryResult;
import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;

/**
 * 特定ワードを検索するクラス　
 */
public class WordSearch {

    public Status wordSearch(String seachWord) throws TwitterException {

        // 初期化
        Twitter twitter = new TwitterFactory().getInstance();
        Query query = new Query();
        // 1度のリクエストで取得するTweetの数（100が最大）
        query.setCount(TwitterContents.MAX_GETTWEET_NUMBER);
        // 検索ワードをセット
        query.setQuery(seachWord);

        // DB接続
        ConnectionDB connectionDB = new ConnectionDB();
        Connection connection = null;
        Statement statement = null;
        try {
            connection = connectionDB.getConnection();
            statement = connection.createStatement();
        } catch (ClassNotFoundException | SQLException e3) {
            e3.printStackTrace();
        }

        String getMaxIdSQL = "select min(tweet_id) as min_tweet_id from t_tweet where search_word  =?;";

        List<String>  minUntilCreateDatetimeList = new ArrayList<String>();

        // DBより、検索ワードのツイート作成日時の最小値を取得
        try(
            PreparedStatement ps = connection.prepareStatement(getMaxIdSQL)){

            ps.setString(1,seachWord);

            try(ResultSet rs = ps.executeQuery()){
                while (rs.next()) {
                    System.out.println("◆◆DB格納済　ツイートIDの最小値：" + rs.getString("min_tweet_id") + "◆◆");
                    minUntilCreateDatetimeList.add(rs.getString("min_tweet_id"));
                }
            };

        } catch (SQLException e2) {
            e2.printStackTrace();
        }

        // 過去にDBに登録済の場合は、クエリ検索条件に、最小ツイートIDを指定
        if(minUntilCreateDatetimeList.get(0) != null) {

            // 指定ツイートIDより前のツイートIDを取得
            query.setMaxId(Long.valueOf(minUntilCreateDatetimeList.get(0)));
            System.out.println(minUntilCreateDatetimeList.get(0) + "_JST");
        }

        // もっともリツイート数の多いツイート
        Status popularTweet = null;

        // 検索結果
        QueryResult result = null;

        // API残基
        GetAPIRestCount getAPIRestCount = new GetAPIRestCount();

        // 検索実行
        for (int i = 0; i < TwitterContents.SERACH_PAGE_NUMBER; i++) {

            // 検索実行
            try {
                result = twitter.search(query);
                System.out.println("ヒット数 : " + result.getTweets().size());
                System.out.println("ページ数 : " + i);
            } catch (TwitterException twi_e) {
                twi_e.printStackTrace();
                if (twi_e.getStatusCode() == 429) {
                    intarvalTime();
                }
                break;
            } catch (Exception ee) {
                ee.printStackTrace();
                break;
            }

            // 取得結果が0件の場合は、nullを返す
            if(result.getTweets().size() == 0) {
                return null;
            }

            // APIをたたくインターバル：３秒
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }

            // 検索結果を見てみる
            for (Status tweet : result.getTweets()) {

                popularTweet = tweet;
//                System.out.println("◆◆◆◆◆◆検索したトレンドワード：" + seachWord + "◆◆◆◆◆◆");
                //System.out.println("ステータスID：" + popularTweet.getId()); // リツイートのときに必要
                //System.out.println("本文：" + popularTweet.getText());
                // 発言したユーザ
//                System.out.println("ユーザID_num：" + popularTweet.getUser().getId());
//                System.out.println("ユーザID@：" + popularTweet.getUser().getScreenName());
                System.out.println("ユーザ名表記：" + popularTweet.getUser().getName());
                // 発言した日時
//                System.out.println("ツイート日時：" + popularTweet.getCreatedAt());
//                System.out.println("言語：" + popularTweet.getLang());
//                System.out.println("地域：" + popularTweet.getGeoLocation());
//                System.out.println("お気に入られ数:" + popularTweet.getFavoriteCount());
//                System.out.println("リツイート数:" + popularTweet.getRetweetCount());

                // insert実行
                try {

                    String sql = "INSERT INTO T_tweet VALUES ("
                    + "'" +  popularTweet.getId()  + "'" +  "," // ツイートID　これでリツイート可能
                    + "'" + popularTweet.getUser().getScreenName() + "'" + "," // ユーザID
                    + "'" + popularTweet.getUser().getName() + "'" + "," // ユーザ名
                    + "'" + popularTweet.getText() + "'" + "," // ツイート本文
                    + "'" + popularTweet.getGeoLocation() + "'" + "," // 地域
                    + "'" + popularTweet.getLang() + "'" + "," // 言語
                    + "'" + seachWord + "'" + "," // 検索ワード
                    + popularTweet.getFavoriteCount() + "," // お気に入り数
                    + popularTweet.getRetweetCount() + "," // リツイート数
                    + "'" + new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(popularTweet.getCreatedAt()) + "'"   // ツイート日時
                    + ");";

                    int resultInsert = statement.executeUpdate(sql);
                    System.out.println("結果１：" + resultInsert);

                } catch (SQLException e) {
                    e.printStackTrace();
                }
                query = result.nextQuery(); // 次ページ参照
            }
        }

        // 検索した結果、該当ツイートがない場合は、NULLを返す
        if(popularTweet == null ){
            return null;
        }

        return popularTweet;
    }

   // タイム
    public void intarvalTime() {
        Date date = new Date();
        System.out.println(date.toString());
        try {
            // 60秒
            Thread.sleep(60000);
        } catch (InterruptedException e) {
            // TODO 自動生成された catch ブロック
            e.printStackTrace();
        }
    }
}
```

## DB接続クラス　ConnectionDB 

```
package CollectionTweet;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class ConnectionDB {

    public Connection getConnection() throws ClassNotFoundException {

        Class.forName("com.mysql.cj.jdbc.Driver");

        try {

            Connection connection = DriverManager.getConnection(
                    "jdbc:mysql://localhost:3306/twitter?serverTimezone=JST", "user", "password");

                        return connection;
                    } catch (SQLException ex) {
                        ex.printStackTrace();
                    }
        return null;
        }
}

```

## API残基　GetAPIRestCount 

```
package CollectionTweet;

import java.util.HashMap;
import java.util.Map;

import twitter4j.RateLimitStatus;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;

/**
 * API制限情報を取得　
 *
 */
public class GetAPIRestCount {

    public static void getAPIRestCount() {

        Twitter twitter = new TwitterFactory().getInstance();

        Map<String , RateLimitStatus> helpmap = new HashMap<String,RateLimitStatus>();// API制限情報を格納変数を作成
        try {
            helpmap = twitter.help().getRateLimitStatus();


                for(Map.Entry<String, RateLimitStatus> e : helpmap.entrySet()){

                    if(e.getKey().equals("/application/rate_limit_status") ||
                       e.getKey().equals("/statuses/retweeters/ids") ||
                       e.getKey().equals("/search/tweets") ||
                       e.getKey().equals("/friendships/show")){
                        System.out.println(e.getKey() + "\nremain: " + e.getValue().getRemaining());
                    }
                }
        } catch (TwitterException e1) {
            e1.printStackTrace();
        }
    }
}

```

## 定数クラス　TwitterContents 

```

package CollectionTweet;

/**
 * 定数を管理するクラス
 */
public class TwitterContents {

        // privateコンストラクタでインスタンス生成を抑止
        private TwitterContents(){};
        // 検索するトレンドワード数
        public static final int TRENDWORD_NUMBER = 2;
        // 最低リツイート数
        public static final int MIN_RETWEET_NUMBER = 150;
        // 最低リツイート数
        public static final int LOCALNUMBER_JAPAN = 23424856;
        // 処理間隔タイム
        public static final int TIME_INTERVAL = 10000;
        // リクエストで取得するTweetの数（100が最大）
        public static final int MAX_GETTWEET_NUMBER = 100;
        // 検索するページ数 max 15ページ
        public static final int SERACH_PAGE_NUMBER = 15;
    }

```

## DDL 
```
CREATE TABLE `t_tweet` (
  `tweet_id` varchar(256) NOT NULL,
  `user_id` varchar(256) NOT NULL,
  `user_name` varchar(256) DEFAULT NULL,
  `tweet` text,
  `location` varchar(256) DEFAULT NULL,
  `langeuge` varchar(256) DEFAULT NULL,
  `search_word` varchar(256) NOT NULL,
  `favarite_count` bigint(20) DEFAULT NULL,
  `retweet_count` bigint(20) DEFAULT NULL,
  `create_datetime` datetime DEFAULT NULL,
  PRIMARY KEY (`tweet_id`,`user_id`,`search_word`),
  UNIQUE KEY `tweet_id_UNIQUE` (`tweet_id`,`user_id`,`search_word`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

```