Googleコンタクトに連絡先情報を保存する

こんにちは、同僚!



以前の記事で約束したように、Google Contacts APIの使用に関する情報を共有したいと思います。 Google Apps EngineでJavaからGoogle Contacts APIを呼び出す方法を学びたい場合は、catへようこそ。



私の開発では、Java 1.8用のGoogle API Client Livraryを使用しました。このバージョンでは、OAuthによる承認を簡素化する革新があります。 実際、今ではすべての承認作業がライブラリによって行われています。



最初に、連絡先の構造を表示するクラスを宣言する必要があります。 連絡先情報の要素(住所、電子メール、電話、インスタントメッセンジャー)に対応するサブクラスを持つクラスを作成しました。



public class Contact implements Serializable { private static final String GDATA_URI = "http://schemas.google.com/g/2005#"; public static final String SOURCE_LABEL = "Source"; public class TypedSubElem implements Serializable{ protected String getURIPrefix(){ return Contact.GDATA_URI; } protected Map<String,String> getRelList(){ final Map<String,String> relList = Collections.unmodifiableMap(new HashMap<String,String>() {{put("home","."); put("other","."); put("work","."); }}); return relList; } @Key("@rel") protected String type = getURIPrefix()+"other"; @Key("@label") protected String label = null; public String getType(){ return (type == null)?null:type.substring(getURIPrefix().length()); } public String getLabel(){ return label; } public String getReadableType(){ String ret = getRelList().get(getType()); if(ret == null) ret = label; return ret; } public void setType(String type){ this.label = null; this.type = getURIPrefix()+(getRelList().containsKey(type)?type:"other"); } public void setLabel(String label){ this.type = null; this.label = label; } } public class FN implements Serializable { @Key("text()") public String text; } public class Content implements Serializable { @Key("text()") public String text; } public class Org extends TypedSubElem { @Key("gd:orgName") public String orgName; @Key("gd:orgTitle") public String orgTitle; @Key("gd:orgDepartment") public String orgDepartment; /** * @param type the type to set */ public void setWork(Boolean work) { setType(work?"work":"other"); } } public class Phone extends TypedSubElem { @Override protected Map<String,String> getRelList(){ final Map<String,String> relList = Collections.unmodifiableMap(new HashMap<String,String>() {{put("assistant",""); put("callback","."); put("car",""); put("company_main",". .")); put("fax",""); put("home","."); put("home_fax",". "); put("isdn","ISDN"); put("main","."); put("mobile","."); put("other","."); put("other_fax",". "); put("pager",""); put("radio",""); put("telex",""); put("tty_tdd","."); put("work","."); put("work_fax",". "); put("work_mob",". ."); put("work_pager",". "); }}); return relList; } @Key("text()") public String text; } public class Email extends TypedSubElem{ @Key("@address") public String address; } public class Address extends TypedSubElem{ @Key("gd:street") public String street; @Key("gd:city") public String city; @Key("gd:region") public String region; @Key("gd:postcode") public String postcode; @Key("gd:country") public String country; @Key("gd:formattedAddress") public String fullAddress; } public class Name extends SubElem{ @Key("gd:givenName") public String givenName; @Key("gd:additionalName") public String additionalName; @Key("gd:familyName") public String familyName; @Key("gd:namePrefix") public String namePrefix; @Key("gd:nameSuffix") public String nameSuffix; @Key("gd:fullName") private String fullName; } public class Link extends TypedSubElem { @Key("@href") public String url; @Override protected Map<String,String> getRelList(){ final Map<String,String> relList = Collections.unmodifiableMap(new HashMap<String,String>() {{put("home-page","."); put("blog",""); put("work","."); put("profile",""); put("other","."); }}); return relList; } @Override protected String getURIPrefix(){ return ""; } } public class IM extends Email { @Key("@protocol") public String protocol; @Override protected Map<String,String> getRelList(){ final Map<String,String> relList = Collections.unmodifiableMap(new HashMap<String,String>() {{put("home","."); put("other","."); put("netmeeting","NetMeeting"); put("work","."); }}); return relList; } protected Map<String,String> getProtoList(){ final Map<String,String> relList = Collections.unmodifiableMap(new HashMap<String,String>() {{put("AIM","AIM"); put("MSN","MSN"); put("YAHOO","Yahoo"); put("SKYPE","Skype"); put("QQ","QQ"); put("GOOGLE_TALK","GTalk"); put("ICQ","ICQ"); put("JABBER","Jabber"); }}); return relList; } public String getProtocol(){ return (protocol == null)?null:protocol.substring(protocol.lastIndexOf('#')+1); } public String getReadableProto(){ return getProtoList().get(getProtocol()); } public void setProtocol(String type){ this.protocol = (getProtoList().containsKey(type))?GDATA_URI+type:null; } } @Key("gContact:website") public List<Link> links = new ArrayList<Link>(); @Key public Content content; @Key("title") public FN fn; @Key("gd:phoneNumber") public List<Phone> phones = new ArrayList<Phone>(); @Key("gd:email") public List<Email> emails = new ArrayList<Email>(); @Key("gd:organization") public List<Org> orgs = new ArrayList<Org>(); @Key("gd:structuredPostalAddress") public List<Address> addresses = new ArrayList<Address>(); @Key("gd:im") public List<IM> IMs = new ArrayList<IM>(); @Key("gd:name") public Name name; }
      
      







クラスとそのサブクラスはSerializableとして宣言されます-これにより、Google APIクライアントは連絡先を正しいAtomに変換できます。 これを行うために、保存されることになっているすべてのフィールドに@‌Key



注釈が付けられます-これは、クラスのフィールドとAtom構造の対応を示します。



relおよびlabelフィールドには、個別の説明が必要です。 relは、定義済みリストからの連絡先情報の典型的なマーキングです。 たとえば、電子メールの場合、これは住所が自宅か職場かを示します。 「 schemas.google.com/g/2005# <view>」という形式の値がGoogle APIに渡されます。 ただし、通常のマーキングに加えて、連絡先情報には任意の指定を付けることができます。 これを行うには、ラベルフィールドを使用します。 Google APIでは、relまたはlabelのいずれかが入力されることを想定しています。



連絡先データ構造の詳細については、 こちらをご覧ください



連絡先をGoogleに送信するには、AbstractAppEngineAuthorizationCodeServletを継承するサーブレットを作成します。 このクラスを使用すると、ユーザーが承認されているかどうかを自動的に確認できます(Googleアカウントでの承認、またはGoogle Apps Engineで適切な設定を行った場合、フェデレーションログインを使用) ユーザーが承認された場合、ユーザーはGoogleコンタクトの連絡先にアクセスする許可を求められます(再びライブラリサーブレットを使用します-自分で何かを書く必要はありません)。 受信したトークンは、トークンストアでの将来の使用のために保存されます(AppEngineCredentialStoreを使用しました)。 アクションのシーケンス全体は、GoogleAuthorizationCodeFlowの責任です。



 import com.google.api.client.auth.oauth2.AuthorizationCodeFlow; import com.google.api.client.auth.oauth2.Credential; import com.google.api.client.extensions.appengine.auth.oauth2.AbstractAppEngineAuthorizationCodeServlet; import com.google.api.client.extensions.appengine.auth.oauth2.AppEngineCredentialStore; import com.google.api.client.extensions.appengine.http.urlfetch.UrlFetchTransport; import com.google.api.client.googleapis.GoogleHeaders; import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow; import com.google.api.client.http.*; import com.google.api.client.http.xml.atom.AtomContent; import com.google.api.client.json.JsonFactory; import com.google.api.client.json.jackson.JacksonFactory; import com.google.api.client.xml.XmlNamespaceDictionary; import java.io.IOException; import java.util.Collections; import java.util.ResourceBundle; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class Action extends AbstractAppEngineAuthorizationCodeServlet { private static final String DEFAULT_BASE_URL = "https://www.google.com/m8/feeds/contacts/default/full"; public static final String SCOPE = "https://www.google.com/m8/feeds/"; public static final String CALLBACK_URI = "/action/google_contacts/oauth2callback"; private static final String APP_NAME = "< >"; public static final String CLIENT_ID = "< >"; public static final String CLIENT_SECRET = "<>"; private static final HttpTransport transport = new UrlFetchTransport(); private static final JsonFactory jsonFactory = new JacksonFactory(); static final XmlNamespaceDictionary DICTIONARY = new XmlNamespaceDictionary() .set("", "http://www.w3.org/2005/Atom") .set("gd", "http://schemas.google.com/g/2005") .set("gContact", "http://schemas.google.com/contact/2008"); @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException{ Credential credential = getCredential(); Contact contact = (Contact) request.getSession().getAttribute("Contact"); if(credential != null && contact != null) { HttpRequestFactory requestFactory = transport.createRequestFactory(getCredential()); assert requestFactory!=null; HttpRequest req = requestFactory.buildPostRequest(new GenericUrl(DEFAULT_BASE_URL), null); GoogleHeaders headers = new GoogleHeaders(); headers.setApplicationName(APP_NAME); headers.setGDataVersion("3"); req.setHeaders(headers); AtomContent content = AtomContent.forEntry(DICTIONARY, contact); req.setContent(content); try{ HttpResponse resp = req.execute(); } catch (HttpResponseException e) { } } } @Override protected String getRedirectUri(HttpServletRequest req) throws ServletException, IOException { GenericUrl url = new GenericUrl(req.getRequestURL().toString()); url.setRawPath(CALLBACK_URI); return url.build(); } @Override protected AuthorizationCodeFlow initializeFlow() throws IOException { return new GoogleAuthorizationCodeFlow.Builder(new UrlFetchTransport(), new JacksonFactory(), CLIENT_ID, CLIENT_SECRET, Collections.singleton(SCOPE)).setCredentialStore( new AppEngineCredentialStore()).build(); } }
      
      







原則として、リクエストヘッダーを設定することはできませんが、この場合、Google APIは連絡先がバージョン2であると見なします。バージョン2は、特に連絡先の構造化名を使用せず、代わりにFNを使用します。 また、私が間違えなければ、IMデータはこのバージョンでは保存されません。



ドキュメントページで Contacts APIの他のメソッドの詳細を読むことができます



All Articles