Google Analytics(GA) API v3 をjavaで実装する2(Server側実装)
前回の準備
Google Analytics(GA) API v3 をjavaで実装する1(準備) - isuta3's diary
今回行うのは、以下を想定。
- 諸々の準備(済)
- 複数のプロファイルをまとめてGA API実行(★)
- 出力に利用する指標(Metric, Dimension)は複数パタンの固定とする(★)
- jsp、angularJSを利用したクライアントからservletでサーバー側からAPI実行のデータの取得
複数のプロファイルをまとめて実行する
複数のプロファイルはjson形式のファイルを読み込む形にした。
//gaTableList.json
[ {"profile":"ga:68430111","profileNm":"dummy"}, {"profile":"ga:68430112","profileNm":"dummy"}, {"profile":"ga:68430113","profileNm":"dummy"}, {"profile":"ga:68430114","profileNm":"dummy"}, {"profile":"ga:68430115","profileNm":"dummy"} ]
これをjavaで読み取り、プロファイルごとにAPIをループさせて実行する。実際には、
- jsonファイルから該当のプロファイルを読み込む
- dataStoreDirという認証データのディレクトリを指定する。
- 取得する指標のパタンを指定する(Metric&Dimension)
- プロファイルごとにAPIを実行し、結果データのリストを生成する。
- 結果データのリストを出力やファイル生成する。(今回はGsonを利用してjsonに変換)
//table(プロファイル)用のclass
public class GaProfile { private String profile; private String profileNm; }
//table(プロファイル)のリストを取得する(TODO DB設定化)
private static final java.io.File TABLE_LIST = new java.io.File(System.getProperty("user.home"), "gaTableList.json"); public List<GaProfile> execProfileList(){ List<GaProfile> list = null; try { JsonReader reader = new JsonReader(new BufferedReader(new FileReader(TABLE_LIST))); list = fromListJson(reader); } catch (IOException e) { System.err.println("ホームディレクトリに'gaTableList.json'ファイルを配置してください。\n" + "Ex.Jsonfile \n" + "[{\"profile\":\"ga:xxxxxxx\",\"profileNm\":\"appNm\"}]"); } return list; }
//認証データのディレクトリ(TODO DB設定化)
private static final java.io.File DATA_STORE_DIR = new java.io.File(System.getProperty("user.home"), ".store/analytics_main");
//指標のパタン、これに好きな条件を突っ込む
//Metric&Dimensionの詳細:
https://developers.google.com/analytics/devguides/reporting/core/dimsmets?hl=ja
public class GaSearchPtn { public String sDate; public String eDate; public String metric; public String dimension; public String sort; public String filter; public int maxResults; }
//プロファイルごとにAPIを実行する(ほぼsampleから拝借)
//sortとFiterは今のところ利用しない。
public class GaApiExec { private static FileDataStoreFactory dataStoreFactory; /** Global instance of the JSON factory. */ private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance(); /** Global instance of the HTTP transport. */ private static HttpTransport httpTransport; @SuppressWarnings("unused") private static Analytics client; public GaData gaSearchExec(GaProfile profile, File dataStoreDir, GaSearchPtn ptn ){ gaSearchConfig(profile.getProfileNm(), profile.getProfile(), dataStoreDir); GaData gaData = null; try { gaData = executeDataQuery(client, profile.getProfile(), ptn); if (gaData.getTotalResults() <= 0) { System.out.println("No data"); return null; } } catch (IOException e) { e.printStackTrace(); } return gaData; } public void gaSearchConfig(String appNm, String tableId, File dataStoreDir) { try { // initialize the transport httpTransport = GoogleNetHttpTransport.newTrustedTransport(); // initialize the data store factory dataStoreFactory = new FileDataStoreFactory(dataStoreDir); // authorization Credential credential = authorize(); // set up global Analytics instance client = new Analytics.Builder(httpTransport, JSON_FACTORY, credential) .setApplicationName(appNm).build(); } catch (GoogleJsonResponseException e) { System.err.println(e.getDetails().getCode() + ":" + e.getDetails().getMessage()); } catch (IOException e) { System.err.println(e.getMessage()); } catch (Throwable t) { t.printStackTrace(); } //System.exit(1); } /** Authorizes the installed application to access user's protected data. */ private static Credential authorize() throws Exception { // load client secrets GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(GaApiExec.class.getResourceAsStream("/client_secrets.json"))); if (clientSecrets.getDetails().getClientId().startsWith("Enter") || clientSecrets.getDetails().getClientSecret().startsWith("Enter ")) { System.out.println( "Overwrite the src/main/resources/client_secrets.json file with the client secrets file " + "you downloaded from the Quickstart tool or manually enter your Client ID and Secret " + "from https://code.google.com/apis/console/?api=analytics#project:414826239625 " + "into src/main/resources/client_secrets.json"); System.exit(1); } // Set up authorization code flow. // Ask for only the permissions you need. Asking for more permissions // will // reduce the number of users who finish the process for giving you // access // to their accounts. It will also increase the amount of effort you // will // have to spend explaining to users what you are doing with their data. // Here we are listing all of the available scopes. You should remove // scopes // that you are not actually using. Set<String> scopes = new HashSet<String>(); scopes.add(AnalyticsScopes.ANALYTICS); scopes.add(AnalyticsScopes.ANALYTICS_EDIT); scopes.add(AnalyticsScopes.ANALYTICS_MANAGE_USERS); scopes.add(AnalyticsScopes.ANALYTICS_READONLY); GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder( httpTransport, JSON_FACTORY, clientSecrets, scopes) .setDataStoreFactory(dataStoreFactory) .build(); // authorize return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user"); } private GaData executeDataQuery(Analytics analytics, String tableId, GaSearchPtn ptn) throws IOException { return analytics.data().ga().get(tableId, ptn.sDate, ptn.eDate, ptn.metric) .setDimensions(ptn.dimension) //.setSort(ptn.sort) //.setFilters(ptn.filter) .setMaxResults(ptn.maxResults).execute(); } }
//結果データをStringで取得しjsonで出力する
//※取得するパタンが固まったら、mapはやめて結果データ用のclassファイルを作成する
public String resultToJson(List<GaData> gaDataList) { List<LinkedHashMap<String, String>> dataList = new ArrayList<LinkedHashMap<String, String>>(); GaAccountSettingService svc = new GaAccountSettingService(); for(GaData gaData : gaDataList){ if (gaData.getTotalResults() <= 0|| gaData == null) continue; int columnQty = gaData.getColumnHeaders().size(); Query query = gaData.getQuery(); String shopNm = svc.getShopNameFromJson(query.getIds()); for (List<String> rowValues : gaData.getRows()) { LinkedHashMap<String, String> map = new LinkedHashMap<String, String>(); map.put("shopNm", shopNm); for(int i=0; i<columnQty; i++){ String header = gaData.getColumnHeaders().get(i).getName(); String data = rowValues.get(i); header = gaHeaderReplace(header); map.put(header, data); } dataList.add(map); } } Gson gson = new GsonBuilder().setPrettyPrinting().create(); Map<String, List<LinkedHashMap<String, String>>> result = new HashMap<String, List<LinkedHashMap<String,String>>>();//TODO mapはやめてentity化 result.put("normal", dataList); String json = gson.toJson(result); return json; }
//GAのAPIからプロファイルの名称に良いのがないので後から、
//idからshopNmを大本のgaTableList.jsonから取得(GaAccountSettingService.class)
private List<GaProfile> profileList = null; public String getShopNameFromJson(String ids) { if(profileList == null) { profileList = execProfileList(); } for(GaProfile profile : profileList){ if(ids.equals(profile.getProfile())){ return profile.getProfileNm(); } } return "NoProfileNm"; }
//最終的に出力されるjson形式の結果イメージ
{ "normal": [ { "shopNm": "dummy", "visitorType": "New Visitor", "pageviews": "369", "visits": "96", "percentNewVisits": "100.0", "bounces": "40", "timeOnSite": "15078.0", "exitRate": "26.01626016260163", "visitBounceRate": "41.66666666666667" }, { "shopNm": "dummy", "visitorType": "Returning Visitor", "pageviews": "83", "visits": "30", "percentNewVisits": "0.0", "bounces": "10", "timeOnSite": "2910.0", "exitRate": "36.144578313253014", "visitBounceRate": "33.33333333333333" } ] }
ソースはまとめてこちらにアップ
https://github.com/isuta/ga-api/tree/master/GaApiApps
プログラム初心者なので、書き方が悪いところがあるはずです。
実行中のエラーやコンパイルエラー
これもライブラリが足りていない。
google-collect-1.0-rc1.jarというjarが必要なんだけど、
2013/12時点ではguavaというライブラリにかわっている。
https://code.google.com/p/google-collections/
なのでguava-15.0.jarをダウンロードしてビルドパスにさせばOK。
下記ライブラリがビルドパスに刺さっていない。
これだけダウンロード時のlibsに一緒に入っていないので注意。
google-api-services-analytics-v3-rev78-1.17.0-rc.jar