以下のサイトを参考にGAEからSpreadsheetを参照するプロジェクトを作ってみたのですがOAuth2.0に対応させるのにえらく手こずったのでメモを残しておきます。
使用するのは「GData API」で環境構築の手順は下記の記事と同じです。また、フレームワークは「Slim3+Scenic3」を利用しています。こちらは公式サイトを参考に。
GData APIでGoogleスプレッドシートを参照するには
http://www.atmarkit.co.jp/ait/articles/1001/15/news121.html
Slim3
https://sites.google.com/site/slim3documentja/
Scenic3
https://sites.google.com/site/aboutscenic3/home
作ったものは http://localhost:8888/spreadsheet にアクセスするとspreadsheetの内容を出力する簡単なWEBアプリです。非常に手抜き処理ばかりですし、たいしてテストしていないプログラムですががご参考までに。
TestPage.java
package test.page;
import test.service.CredentialDataService;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import org.slim3.controller.Navigation;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.drive.DriveScopes;
import com.google.gdata.client.spreadsheet.SpreadsheetService;
import com.google.gdata.data.spreadsheet.ListEntry;
import com.google.gdata.data.spreadsheet.ListFeed;
import com.google.gdata.data.spreadsheet.SpreadsheetEntry;
import com.google.gdata.data.spreadsheet.WorksheetEntry;
import scenic3.annotation.ActionPath;
import scenic3.annotation.Page;
@Page("/")
public class TestPage extends CommonPage {
private static final String CLIENT_ID_DEBUG =
"<ローカルテスト用クライアントID>";
private static final String CLIENT_SECRET_DEBUG =
"<ローカルテスト用クライアントシークレット>";
private static final String REDIRECT_URI_DEBUG =
"http://localhost:8888/oauth2callback";
private static final String CLIENT_ID = "<GAE環境用クライアントID>";
private static final String CLIENT_SECRET = "<GAE環境用シークレット>";
private static final String REDIRECT_URI =
"http://<自分のプロジェクトのドメイン>/oauth2callback";
private static final List<String> SCOPES = Arrays.asList(
DriveScopes.DRIVE_FILE,
"https://spreadsheets.google.com/feeds");
private static final HttpTransport TRANSPORT = new NetHttpTransport();
private static final JsonFactory JSON_FACTORY = new JacksonFactory();
private static final String SERVICE_NAME = "<サービス名>";
CredentialDataService credentialService = new CredentialDataService();
/**
* デバッグ用サーバかどうか
*/
private boolean isDebug() {
String serverName = request.getServerName();
if (serverName.indexOf("localhost") != -1) {
return true;
} else {
return false;
}
}
/**
* 文字列をレスポンスに出力
*/
private void writeResponse(String str) {
try {
response.setCharacterEncoding("utf-8");
response.getWriter().println(str);
response.flushBuffer();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* OAuth認証用flowインスタンスを取得
*/
private GoogleAuthorizationCodeFlow getFlow() {
String clientId, clientSecret;
if (isDebug()) {
clientId = CLIENT_ID_DEBUG;
clientSecret = CLIENT_SECRET_DEBUG;
} else {
clientId = CLIENT_ID;
clientSecret = CLIENT_SECRET;
}
GoogleAuthorizationCodeFlow flow =
new GoogleAuthorizationCodeFlow.Builder(
TRANSPORT,
JSON_FACTORY,
clientId,
clientSecret,
SCOPES)
.setAccessType("online")
.setApprovalPrompt("auto")
.build();
return flow;
}
/**
* OAuth認証のリダイレクト先を取得
*/
private String getRedirectURL() {
String redirectUri;
if (isDebug()) {
redirectUri = REDIRECT_URI_DEBUG;
} else {
redirectUri = REDIRECT_URI;
}
return redirectUri;
}
/**
* OAuth認証/スタート
*/
@ActionPath("loginOAuth")
public Navigation loginOAuth() {
GoogleAuthorizationCodeFlow flow = getFlow();
String redirectUri = getRedirectURL();
String url =
flow.newAuthorizationUrl().setRedirectUri(redirectUri).build();
return redirect(url);
}
/**
* OAuth認証/コールバック
*/
@ActionPath("oauth2callback")
public Navigation oauth2callback() {
String code = request.getParameter("code");
GoogleAuthorizationCodeFlow flow = getFlow();
String redirectUri = getRedirectURL();
try {
GoogleTokenResponse response =
flow
.newTokenRequest(code)
.setRedirectUri(redirectUri)
.execute();
GoogleCredential credential =
new GoogleCredential().setFromTokenResponse(response);
credentialService.save(credential);
} catch (Exception e) {
e.printStackTrace();
writeResponse(e.getMessage());
return null;
}
return redirect("/spreadsheet");
}
/**
* スプレッドシートテスト
*
* @return
*/
@ActionPath("spreadsheet")
public Navigation spreadsheet() {
try {
GoogleCredential credential = credentialService.load();
if (credential == null) {
return redirect("loginOAuth");
}
SpreadsheetService service = new SpreadsheetService(SERVICE_NAME);
service.setOAuth2Credentials(credential);
String key = "<スプレッドシートのKey>";
URL entryUrl =
new URL("https://spreadsheets.google.com/feeds/spreadsheets/"
+ key);
SpreadsheetEntry spreadsheetEntry =
service.getEntry(entryUrl, SpreadsheetEntry.class);
// 検索対象のワークシートを取得
WorksheetEntry worksheetEntry =
spreadsheetEntry.getDefaultWorksheet();
// ワークシート内を検索
URL listFeedUrl = worksheetEntry.getListFeedUrl();
ListFeed listFeed = service.getFeed(listFeedUrl, ListFeed.class);
// ワークシートの内容を表示
String ret = "";
for (ListEntry row : listFeed.getEntries()) {
for (String tag : row.getCustomElements().getTags()) {
ret += row.getCustomElements().getValue(tag) + "\t";
}
ret += "\n";
}
writeResponse(ret);
} catch (Exception e) {
// ここ超テキトー
e.printStackTrace();
credentialService.delete();
writeResponse(e.getMessage());
}
return null;
}
}
CredentialData.java
package test.model;
import java.io.Serializable;
import org.slim3.datastore.Attribute;
import org.slim3.datastore.Model;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.users.User;
@Model(schemaVersion = 1)
public class CredentialData implements Serializable {
private static final long serialVersionUID = 1L;
@Attribute(primaryKey = true)
private Key key;
@Attribute(version = true)
private Long version;
private String accessToken;
private User user;
/** ------- Setter/Getter -------------------------------------- **/
public Key getKey() {
return key;
}
public void setKey(Key key) {
this.key = key;
}
public Long getVersion() {
return version;
}
public void setVersion(Long version) {
this.version = version;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
}
CredentialDataService.java
package test.service;
import java.util.List;
import org.slim3.datastore.Datastore;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.appengine.api.datastore.Transaction;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import test.meta.CredentialDataMeta;
import test.model.CredentialData;
public class CredentialDataService {
private CredentialDataMeta t = new CredentialDataMeta();
/**
* OAuth証明情報を保存する
*
* @param credential
* OAuth証明情報
*/
public void save(GoogleCredential credential) {
Transaction tx = Datastore.beginTransaction();
if (load() != null) {
delete();
}
UserService userService = UserServiceFactory.getUserService();
User user = userService.getCurrentUser();
CredentialData data = new CredentialData();
data.setUser(user);
data.setAccessToken(credential.getAccessToken());
Datastore.put(data);
tx.commit();
}
/**
* ログインしているユーザのOAuth証明情報を削除する
*/
public void delete() {
UserService userService = UserServiceFactory.getUserService();
User user = userService.getCurrentUser();
List<CredentialData> list =
Datastore.query(t).filter(t.user.equal(user)).asList();
for (CredentialData d : list) {
Datastore.delete(d.getKey());
}
}
/**
* ログインしているユーザのOAuth証明情報を取得する
*
* @return OAuth証明情報
*/
public GoogleCredential load() {
UserService userService = UserServiceFactory.getUserService();
User user = userService.getCurrentUser();
List<CredentialData> list =
Datastore.query(t).filter(t.user.equal(user)).asList();
if (list.size() == 0) {
return null;
} else {
String accessToken = list.get(0).getAccessToken();
GoogleCredential credential =
new GoogleCredential().setAccessToken(accessToken);
return credential;
}
}
}