소셜네트워크 페이스북 API 개발 #4 Open API , facebook API , SNS
"페이스북 API 개발"
[2013.01.28] 페이스북 API 연동 안되는 오류부분 수정되었습니다.
원인 : 액세스토큰을 가져올때 불필요한 파라메터값까지 인증키로 사용하여 발생한 문제
태그 : 20130128
[연결 포스팅]
2012/04/09 - [개발노트/JAVA] - 오픈API 시작하며 #1 OpenAPI , JSON , XML , HTTP , OAuth
2012/04/09 - [개발노트/JAVA] - 소셜네트워크 트위터 API 개발 #2 Open API , Twitter API , SNS , OAuth
[필독]
1) 연결되는 포스팅입니다. 꼭 이전 포스팅을 참고하세요.
2) OAuth 와 SNS API 대해 기본적인 지식이 필요합니다.
3) 포함된 소스는 참고용이며, 그대로 사용할 경우 오류가 발생합니다. 직접 필요한 부분을 개발하세요.
- 직접 개발해야 할 부분은 임의적으로 주석처리 하였습니다.
4) 시간이 없어 급정리해서 올리는 글입니다. 부족한 부분이 많습니다. 이점 참고하세요.
5) 원문 그대로 사용하는 것을 방지하기 위해 소스파일은 제공하기 않습니다. 꼭 소스를 분석후 직접 개발하세요.
페이스북 API 사이트
http://developers.facebook.com/docs/
소셜네트워크 대명사 페이스북에서 제공되는 API를 이용하여 특화된 페이스북을 개발해보자.
페이스북은 OAuth 사용하나 2.0 버전과 약간 다른다.
> 이미 앞 장에서 설명했던 내용은 생략함.
1. 페이스북 앱 에서 어플리케이션을 생성하자. https://developers.facebook.com/apps
2. Http Classes (생략)
3. OAuth Classes (생략)
/* * FacebookAPI.java 2011.11.17 * * Copyright (c) 2010, MEI By Seok Kyun. Choi. (최석균) * http://syaku.tistory.com * * GNU Lesser General Public License * http://www.gnu.org/licenses/lgpl.html */ package com.syaku.modules.snsauth; import java.util.*; import java.net.*; // 20130128 시작 import java.util.regex.*; import java.text.*; // 20130128 끝 import org.apache.log4j.Logger; import org.apache.commons.lang.*; import org.apache.commons.collections.*; import oauth.signpost.*; import oauth.signpost.basic.*; import oauth.signpost.exception.*; import org.apache.http.NameValuePair; import org.apache.http.message.BasicNameValuePair; import org.apache.http.client.entity.UrlEncodedFormEntity; import net.sf.json.*; /* import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.digest.DigestUtils; import javax.servlet.*; import javax.servlet.http.*; import com.opensymphony.xwork2.*; import org.apache.struts2.ServletActionContext; import com.ibatis.sqlmap.client.SqlMapClient; import org.apache.commons.configuration.Configuration; import com.syaku.config.*; import com.syaku.common.*; import com.syaku.core.*; import com.syaku.util.*; */ public class FacebookAPI { //private Logger log = Logger.getLogger(FacebookAPI.class); //public SqlMapClient sqlMap = SqlMapConfig.getSqlMapInstance(); //public final Configuration MODULE_CONFIG = SyakuConfig.getInstance("com/syaku/modules/snsauth/info.properties"); public HttpServletRequest request = ServletActionContext.getRequest(); public HttpServletResponse response = ServletActionContext.getResponse(); public HttpSession session = request.getSession(); //private SnsAuthObject mSnsAuthObject = new SnsAuthObject(); //private SnsAuthStored mSnsAuthStored = new SnsAuthStored(); private SnsAuthHttp mSnsAuthHttp = new SnsAuthHttp(); // user_id 변경이 가능한 계정이며, uid 고유한 값이다. private String uid,user_id,nickname,profile_cover,post_send; public String getUid() { return this.uid; } // id public String getUser_id() { return this.user_id; } // username public String getNickname() { return this.nickname; } // name public String getProfile_cover() { return this.profile_cover; } // https://graph.facebook.com/ + uid + /picture public void setPost_send(String post_send) { this.post_send = post_send; } // 글 전송 여부 : 다중 SNS 용 public String getPost_send() { return this.post_send; } final String API_URL = "https://graph.facebook.com"; final String SNS_NAME = "FACEBOOK"; private String API_APPID; private String API_APPSECRET; private String API_SCOPE; private String API_CALLBACK; public FacebookAPI() { this.API_APPID = "appid"; this.API_APPSECRET = "appsecret"); this.API_SCOPE = "scope"); this.API_CALLBACK = "callback url"); } // 싱크 처리 public void getSignIn() throws Exception { try { String token = "쿠키에 저장된 access_token 을 읽어옴"; if (StringUtils.isNotEmpty(token)) { if (mSnsAuthStored.getAuthSessValid(this.SNS_NAME) == false) { // 세션이 없다면 디비에서 정보 조회 (아래의 소스는 직접 구현하기) //Map mapSch = new HashMap(); //mapSch.put("name",this.SNS_NAME); //mapSch.put("token",token); //SnsAuthBean objSns = (SnsAuthBean) mSnsAuthObject.getSnsAuthView(mapSch); if (objSns != null) { String access_token = objSns.getAccess_token(); getAuthSync(access_token); } } if (mSnsAuthStored.getAuthSessValid(this.SNS_NAME) == true) { Map<String,String> mapUser = this.getUserInfo(); // 계정 정보 //mSnsAuthStored.setUserInfo(this.SNS_NAME,mapUser); // 세션 저장 } //mSnsAuthStored.setAuthCookie(token); // 쿠키 갱신 } else { //mSnsAuthStored.getSessRemove(this.SNS_NAME); //세션 삭제 } } catch (Exception e) { //log.error(e.toString()); //mSnsAuthStored.getSessRemove(this.SNS_NAME); } } public String getAccess(ParameterUtils param) throws Exception { String auth_url = null; String oauth_token = param.value("code",""); String oauth_verifier = param.value("access_token",""); //String token = mSnsAuthStored.getAuthCookie(); // 저장된 쿠키 호출 String access_token = null; String access_token_secret = null; Map mapSch = new HashMap(); if (StringUtils.isEmpty(oauth_token)) { if (StringUtils.isNotEmpty(token)) { // 디비에 저장된 페이스북 정보 조회 //mapSch.clear(); //mapSch.put("name",this.SNS_NAME); //mapSch.put("token",token); //SnsAuthBean objSns = (SnsAuthBean) mSnsAuthObject.getSnsAuthView(mapSch); if (objSns != null) { access_token = objSns.getAccess_token(); } //mSnsAuthStored.setAuthCookie(token); // 쿠키 갱신 } if (access_token != null) { // access token 을 이용하여 재인증 처리 getAuthSync(access_token); auth_url = "SUCCESS"; } else { //mSnsAuthStored.getSessRemove(this.SNS_NAME); // 세션 삭제 auth_url = "https://www.facebook.com/dialog/oauth?client_id=" + this.API_APPID + "&redirect_uri=" + URLEncoder.encode(this.API_CALLBACK,"utf-8") + "&scope=" + URLEncoder.encode(this.API_SCOPE,"utf-8"); // 인증 url 요청 } } else { try { //sqlMap.startTransaction(); if (StringUtils.isEmpty(token)) { // 임의의 토큰 생성 및 토큰 디비저장 //token = DigestUtils.sha256Hex(DigestUtils.sha256("syaku" + DateUtils.date("yyyyMMddHHmmss") + "me")); } // access token 얻기 access_token = getSuccess(oauth_token); access_token_secret = oauth_token; // code // 싱크처리 getAuthSync(access_token); Map<String,String> mapUser = this.getUserInfo(); // 계정 정보 /* 디비에 저장할 정보를 기록 String uid = this.uid; String ip = request.getRemoteAddr(); String user_agent = request.getHeader("User-Agent"); mSnsAuthObject.getSnsAuthMainResetUpdate(token); SnsAuthBean snsauthbean = new SnsAuthBean(); snsauthbean.setToken(token); snsauthbean.setName(this.SNS_NAME); snsauthbean.setAccess_token(access_token); snsauthbean.setAccess_token_secret(access_token_secret); snsauthbean.setMain("Y"); snsauthbean.setPost_send("Y"); snsauthbean.setUid(uid); snsauthbean.setReg_date(DateUtils.date("yyyyMMddHHmmss")); snsauthbean.setIp(ip); snsauthbean.setUser_agent(user_agent); mSnsAuthObject.getSnsAuthInsert(snsauthbean); mSnsAuthStored.setAuthCookie(token); // 갱신 mSnsAuthStored.setUserInfo(this.SNS_NAME,mapUser); */ auth_url = "SUCCESS"; //sqlMap.commitTransaction(); } catch (Exception e) { //mSnsAuthStored.getSessRemove(this.SNS_NAME); // 세션 삭제 //log.error(e.toString()); // 로그 출력 } finally { //sqlMap.endTransaction(); } } return auth_url; } // 인증 완료 public String getSuccess(String oauth_token) throws Exception { String access_token = null; String result = mSnsAuthHttp.getHttpGet( this.API_URL + "/oauth/access_token?client_id=" + this.API_APPID + "&redirect_uri=" + URLEncoder.encode(this.API_CALLBACK,"utf-8") + "&client_secret=" + URLEncoder.encode(this.API_APPSECRET,"utf-8") + "&code=" + URLEncoder.encode(oauth_token,"utf-8")); // access_token 을 얻어옴. : OAuth 2.0 과 다른 방식 try { // 20130128 시작 //String[] at = result.split("="); //access_token = at[1]; Pattern para_patten = Pattern.compile("^(.*)=(.*)$",Pattern.MULTILINE); String para_tokens[] = result.split("&"); int para_cnt = para_tokens.length; Map accMap = new HashMap(); for (int i = 0; i < para_cnt; i++ ) { Matcher para_matcher = para_patten.matcher(para_tokens[i]); String para_name = para_matcher.replaceAll("$1"); String para_value = para_matcher.replaceAll("$2"); accMap.put(para_name,para_value); } access_token = (String) accMap.get("access_token"); // 20130128 끝 } catch (Exception e) { getException(result); } return access_token; } // 인증 싱크 (재인증) public void getAuthSync(String access_token) throws Exception{ if (StringUtils.isNotEmpty(access_token)) { //mSnsAuthStored.setAuthSess(this.SNS_NAME,access_token); // 세션에 저장된 인증 토큰 가져옴 } } // 계정 정보 public Map<String,String> getUserInfo() throws Exception { this.uid = null; this.user_id = null; this.nickname = null; this.profile_cover = null; //String access_token = (String) mSnsAuthStored.getAuthSess(this.SNS_NAME); // 세션에 저장된 인증 토큰 //Map<String,String> mapSS = (Map<String,String>) mSnsAuthStored.getUserInfo(this.SNS_NAME); // 세션에 저장된 계정 정보 Map<String,String> mapRet = new HashMap(); if (MapUtils.isNotEmpty(mapSS)) { this.uid = mapSS.get("uid"); this.user_id = mapSS.get("user_id"); this.nickname = mapSS.get("nickname"); this.profile_cover = mapSS.get("profile_cover"); } else { // 계정 정보 호출 String result = mSnsAuthHttp.getHttpGet(this.API_URL + "/me?access_token=" + URLEncoder.encode(access_token,"utf-8"),null); try { JSONObject objJson = JSONObject.fromObject(result); String uid = objJson.getString("id"); // id String user_id = (String) objJson.get("username"); String nickname = objJson.getString("name"); String profile_cover = "https://graph.facebook.com/" + uid + "/picture"; // 정보 기록 this.uid = uid; this.user_id = user_id; this.nickname = nickname; this.profile_cover = profile_cover; } catch (Exception e) { //mSnsAuthStored.getSessRemove(this.SNS_NAME); // 세션 삭제 getException(result); } } if (this.user_id != null || this.nickname != null || this.profile_cover != null) { mapRet.put("user_id",this.user_id); mapRet.put("nickname",this.nickname); mapRet.put("profile_cover",this.profile_cover); mapRet.put("uid",this.uid); } return mapRet; } // 글 쓰기 // getPost 메소드를 호출 후 msg_id 받아 글 내용과 같이 디비에 저장하자. msg_id 는 글을 나중에 삭제할때 필요하다. public String getPost(Map map) throws Exception { //String access_token = (String) mSnsAuthStored.getAuthSess(this.SNS_NAME); // 세션에 저장된 인증 토큰 String msg_id = null; String message = (String) map.get("message"); String parent_msg_id = (String) map.get("parent_msg_id"); String url = (String) map.get("url"); String description = (String) map.get("description"); String tag = "태그입력"; List<NameValuePair> formparams = new ArrayList<NameValuePair>(); formparams.add(new BasicNameValuePair("access_token", access_token)); formparams.add(new BasicNameValuePair("message", message)); formparams.add(new BasicNameValuePair("name", tag)); formparams.add(new BasicNameValuePair("description", description)); formparams.add(new BasicNameValuePair("picture", "")); formparams.add(new BasicNameValuePair("link", url)); UrlEncodedFormEntity formentity = new UrlEncodedFormEntity(formparams, "UTF-8"); String result = mSnsAuthHttp.getHttpPost(this.API_URL + "/me/feed",formentity,null); log.debug("[MEI FACEBOOK POST result]" + result); JSONObject objJson = JSONObject.fromObject(result); try { msg_id = objJson.getString("id"); } catch (Exception e) { getException(result); } log.debug("[MEI FACEBOOK POST ID]" + msg_id); return msg_id; } // 글 삭제 public void getDelete(String msg_id) throws Exception { String access_token = (String) mSnsAuthStored.getAuthSess(this.SNS_NAME); List<NameValuePair> formparams = new ArrayList<NameValuePair>(); formparams.add(new BasicNameValuePair("access_token", access_token)); formparams.add(new BasicNameValuePair("method", "DELETE")); UrlEncodedFormEntity formentity = new UrlEncodedFormEntity(formparams, "UTF-8"); String result = mSnsAuthHttp.getHttpPost(this.API_URL + "/" + msg_id,formentity,null); log.debug("FACEBOOK getDelete : " + result); } // result json 익셉션 출력 public void getException(String json) throws Exception { String msg_text = null; JSONObject objJson = JSONObject.fromObject(json); JSONObject objErr = objJson.getJSONObject("error"); try { msg_text = objErr.getString("message"); } catch (Exception e) { } if (StringUtils.isNotEmpty(msg_text)) { log.debug("FACEBOOK : " + msg_text); //throw new Exception("FACEBOOK : " + msg_text); } } }
아래의 내용에서 SNS라는 대상은 페이스북을 말합니다.
SNS 뷰(JSP)단의 필요한 UI 항목은 아래와 같다. JSP와 자바스크립트를 적절하게 혼합하여 구현하면 된다.
- SNS 에 등록된 글 목록
- 글을 삭제하는 삭제 버튼
- 글을 등록하는 쓰기 폼
- SNS 에 로그인 하거나 로그아웃하는 버튼
1단계. 세션이나 쿠키 존재를 파악하여 계정을 연결한다.
// 객체생성
FacebookAPI facebook = new FacebookAPI();
String token = ID 쿠키가져오기;
if token 존재할 경우 {
facebook.getSignIn(); // SNS 연결
facebook.getUid(); // 고유 아이디 (숫자)
facebook.getUser_id(); // 유동 아이디 (영문)
facebook.getNickname(); // 별명
facebook.getProfile_cover(); // 절대경로의 프로필 사진
}
2단계. SNS 글 목록
SNS에 연결하여 글을 가져오는 것이 아니라, 글을 쓸때마다 자신의 디비에 저장한다. 꼭 글 id도 함께 저장하여야 한다.
[참고] 프로필 사진는 id를 이용해 img 태그로 가져오면 된다.
3단계. SNS 로그인 , 로그아웃
1단계 SNS 계정이 연결되지 않을 경우 UI 상에서 로그인 버튼을 노출시켜 로그인을 유도한다.
로그인 버튼을 누를면 새 창이 뜬다. 이부분에 추가적인 UI 화면(JSP)이 필요하다.
이 화면에서 URL 이 SNS 애플리케이션(OAuth settings)의 콜백 URL이 되어야한다.
그래서 SNS 서버에 거친 후 다시 돌아오게 되고, oauth_token 파라미터 값을 얻을 수 있다.
FacebookAPI facebook = new FacebookAPI();
// 연결이 되지 않을 경우 (즉 토큰이나 세션이 없을 경우) auth_url 를 리턴받는 다.
auth_url = facebook.getAccess(request);
if (auth_url 값이 있을 경우) {
auth_url 페이지로 이동하게 함
} else {
자바스크립트를 이용하여 현재 창(팝업:새창)을 닫고 부모 페이지를 새로고침
}
로그아웃은 쿠키와 세션에 존재하는 해당 SNS 정보를 삭제하면 된다.
4단계. 글 쓰기 , 글삭제
FacebookAPI facebook = new FacebookAPI();
Map map = new HashMap();
map.put("message","글 내용");
이 외 필요한 기능은 해당 SNS DOCS 참고하여 추가하자.
String msg_id = facebook.getPost(map);
SNS에 정상적으로 등록되면 msg_id 와 message 를 서버 디비에 저장한다.
// 글 삭제
facebook.getDelete(msg_id);
'개발노트 > JAVA' 카테고리의 다른 글
프리마커 템플릿 소스 불러오기 : freemarker ftl (1) | 2012.09.07 |
---|---|
소셜네트워크 네이버 미투데이 API 개발 #5 Open API , Naver Me2day API , SNS (0) | 2012.06.05 |
소셜네트워크 다음 요즘 API 개발 #3 Open API , Daum YOZM API , SNS (0) | 2012.06.05 |
소셜네트워크 트위터 API 개발 #2 Open API , Twitter API , SNS (4) | 2012.04.09 |