Facebook于2004年2月启动,是世界上最大的社交网络,有超过9亿用户使用该网站与其亲朋好友共享内容。 2007年5月启动的Facebook平台使第三方能够编写与Facebook集成的应用程序。 该平台最初支持多种编程语言(包括Java),但现在仅提供JavaScript和PHP的本机SDK(以及对iOS和Android设备上的应用程序的支持)。 然而,开源RestFB项目已保持了Java API,因为Facebook的停产(见相关主题 )。
Google App Engine(GAE)是平台即服务(PaaS),可让注册的开发人员在Google的基础架构上运行用Python,Java或Go编写的应用程序。 本文向您展示如何注册Facebook应用程序,使用Java开发它以及如何在GAE上免费部署它以供任何已登录的Facebook用户使用。 (请注意,Google每天对GAE上部署的每个应用程序可以使用的资源施加限制。)
您将创建的简单应用程序列出用户的所有朋友及其ID和个人资料图片-类似于Facebook用户个人资料上朋友页面的先前外观。 要开发该应用程序,您需要:
- 一个Facebook帐户
- Google帐号
- 装有GAE插件的Eclipse IDE(请参阅参考资料 )
- 熟悉使用Eclipse
该应用程序的示例代码也可以下载 。
注册申请
第一步是在Facebook和GAE上注册您的应用程序。 最好在两个平台上同时创建应用程序,以确保输入的信息根据需要匹配。
注册一个Facebook应用程序
登录Facebook并通过https://developers.Facebook.com/apps启动开发人员应用程序。 (如果是第一次启动它,则必须授予该应用程序对您的个人资料的访问权限才能继续。)
单击“应用程序”页面右上方的“创建新应用程序”以显示“创建新应用程序”对话框,如图1所示:
图1. Facebook Create New App对话框

输入应用程序的有效名称和可用名称空间。 名称空间是在Facebook应用程序URL中使用的单字唯一标识符。 (在图1中 ,我输入My Old Friends
作为应用程序名称, myoldfriends
作为名称空间。)取消选择Heroku提供的免费托管选项,然后单击Continue 。 在下一个对话框中键入CAPTCHA代码,然后单击Submit弹出新应用程序的基本设置对话框,如图2所示:
图2. Facebook应用程序基本设置对话框

请注意屏幕顶部的App ID和App Secret键(在图2中隐藏)。 Facebook使用它们来识别您的应用程序。 将它们保密,不允许其他开发人员使用它们,因为在您不知情的情况下,它们可能会被恶意使用。
在“ 应用程序域”字段中输入应用程序域 。 这必须是您要在GAE开发人员网站上为该应用程序注册的GAE域,因此它必须以.appspot.com
结尾。 例如,在图2中 ,我输入了myoldfacebookfriends.appspot.com
。 由于该域不再可用,因此您必须使用其他域。 只要确保它与您注册GAE应用程序时使用的应用程序标识符匹配即可。
在“选择应用程序与Facebook的集成方式”下,选择“ 具有Facebook登录名的网站”,然后输入由您在“ 应用程序域”字段中输入的GAE域组成的站点URL,并以http://
。 (在图2中 ,我输入了http://myoldfacebookfriends.appspot.com
。)
选择Facebook上的App,然后输入将在其中运行应用程序的servlet的画布URL。 对于此应用程序,画布URL以一个问号结尾,以指示该应用程序的参数将通过发送到该应用程序的请求URL传递。 除了https
替换http
之外,安全画布URL与画布URL相同。 同样,URL末尾的问号很重要。 (我的应用程序servlet的URL是http://myoldfacebookfriends.appspot.com/myoldfacebookfriends,因此在图2中 ,我输入了http://myoldfacebookfriends.appspot.com/myoldfacebookfriends?
作为画布URL和https://myoldfacebookfriends.appspot.com/myoldfacebookfriends?
作为安全画布URL。)
这是在Facebook上设置应用程序所需要做的全部工作,但最好配置一些其他设置(例如,应用程序的图标及其类别),以修改将应用程序呈现给用户的方式。
向GAE注册应用程序
现在该应用程序已在Facebook中注册,接下来您将在GAE中注册它。
在GAE的应用程序页面(https://appengine.google.com/)上登录,然后点击创建应用程序 。 在“应用程序标识符”下,输入您在Facebook应用程序基本设置中使用的相同应用程序域名。 (为您提供了appspot.com部分。)您可以根据需要使用任何名称作为应用程序标题,该名称用于搜索已注册的应用程序。 将其余选项保留为默认值。
图3. GAE的“创建应用程序”对话框
单击创建应用程序以完成GAE注册过程。
开发应用程序
在Eclipse中,通过单击文件>新建> Web应用程序项目 ,或在Google服务和部署工具菜单下的新建Web应用程序项目按钮创建一个新的GAE项目。 输入项目名称和程序包名称。 取消选择使用Google Web Toolkit 。 下载RestFB JAR文件(请参阅相关信息 ),并将其添加到项目的WEB-INF / lib文件夹。
将应用程序的Servlet定义添加到项目的web.xml文件中。 清单1显示了我使用的定义:
清单1. Servlet定义
<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<servlet>
<servlet-name>myoldFacebookfriendsServlet</servlet-name>
<servlet-class>com.Facebook.friends.MyOldFacebookFriendsServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myoldFacebookfriendsServlet</servlet-name>
<url-pattern>/myoldFacebookfriends</url-pattern>
</servlet-mapping>
</web-app>
请注意, <url-pattern>
与Facebook应用程序基本设置对话框中的画布URL中的相同,但没有问号。
自2011年10月起,Facebook应用程序要求启用安全套接字层(SSL); 在GAE上默认为禁用。 要启用它,请将以下行添加到appengine-web.xml中:
<ssl-enabled>true</ssl-enabled>
Facebook签名请求
Facebook使用HTTP POST
方法将已签名的请求发送到应用程序servlet,以创建应用程序的内容。 该请求包含64位编码的有效负载,其中包含元数据以及当前用户应用程序的OAuth令牌。 仅当用户已授予应用程序对其个人资料的访问权限时,这才包括在请求的有效负载中。 您需要将其转换为Java对象,以便应用程序可以使用它。
清单2显示了签名请求的Java对象的源。 为了清楚起见,我省略了所有适当的get和set方法。 它们包含在源代码下载中(请参阅下载 )。
清单2.带签名的请求对象
import org.apache.commons.codec.binary.Base64;
import org.codehaus.jackson.map.ObjectMapper;
public class FacebookSignedRequest {
private String algorithm;
private Long expires;
private Long issued_at;
private String oauth_token;
private Long user_id;
private FacebookSignedRequestUser user;
public static class FacebookSignedRequestUser {
private String country;
private String locale;
private FacebookSignedRequestUserAge age;
public static class FacebookSignedRequestUserAge {
private int min;
private int max;
}
}
}
您可以使用Apache Commons Codec库中的Base64解码有效负载。 解码后的有效负载采用JavaScript对象表示法(JSON),可以使用Jackson JSON处理器将其转换为Java对象。 下载其JAR文件并将其添加到项目中(请参阅参考资料 )。 将清单3中所示的静态帮助器方法添加到FacebookSignedRequest
类中以创建对象:
清单3.用于编码和解码有效负载的Helper方法
public static FacebookSignedRequest getSignedRequest(String signedRequest)
throws Exception {
String payload = signedRequest.split("[.]", 2)[1];
payload = payload.replace("-", "+").replace("_", "/").trim();
String jsonString = new String(Base64.decodeBase64(payload.getBytes()));
return new ObjectMapper().readValue(jsonString,
FacebookSignedRequest.class);
}
创建servlet
现在,您可以开始编码将在servlet中运行的应用程序。 创建一个新类,其签名与web.xml中的<servlet-class>
定义相同。 首先,您需要使用SignedRequest
类从有效负载中提取OAuth令牌,如清单4所示:
清单4.提取OAuth令牌
String signedRequest = (String) request.getParameter("signed_request");
FacebookSignedRequest FacebookSR = null;
try {
FacebookSR = FacebookSignedRequest.getSignedRequest(signedRequest);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String oauthToken = FacebookSR.getOauth_token();
如果oauthToken
对象为null,则用户尚未授予对应用程序的访问权限,必须将其重定向到身份验证URL。 所有应用程序中的标准URL格式如下:
https://www.Facebook.com/dialog/oauth?client_id=API KEY&redirect_uri=
https://apps.Facebook.com/Application Namespace/&scope=Permissions
身份验证URL中的API KEY
和Application Namespace
是该Application Namespace
的Facebook基本设置对话框中显示的API KEY
。 Permissions
是您的应用程序所需的权限列表。 默认情况下,所有应用程序都具有基本权限,您无需为本文的目的添加任何其他权限。 (请参阅相关主题的链接,获得许可的完整列表。)
您可以在Facebook开发人员应用程序的“设置”>“身份验证对话框”页面中自定义此页面的外观。 通常,您将使用Servlet HttpServletRequest.sendRedirect()
方法,但是由于该应用程序将在apps.Facebook.com域的<iframe>
运行,因此清单5所示的简短JavaScript代码段更改了Javascript的位置。浏览器窗口中的应用程序URL:
清单5.引用到应用程序URLJavaScript代码
PrintWriter writer = response.getWriter();
if(oauthToken == null) {
response.setContentType("text/html");
String authURL = "https://www.Facebook.com/dialog/oauth?client_id="
+ API_KEY
+ "&redirect_uri=https://apps.Facebook.com/myoldfriends/&scope=";
writer.print("<script> top.location.href='" + authURL + "'</script>");
writer.close();
}
使用有效的OAuth令牌,您可以从RestFB库创建DefaultFacebookClient
,并使用它通过fetchConnection()
调用从Facebook的Graph API中检索数据。 在https://developers.Facebook.com/tools/explorer上访问Facebook上的Graph Explorer。 从右上角的下拉框中选择您正在开发的应用程序,然后单击“ 获取访问令牌”以授予访问权限。 单击“连接”标题下的各种链接以查看结果。
要获取用户的朋友,请单击“ 朋友”链接并查看结果。 请注意,资源管理器中URL的值为user id /friends
。 函数调用中的连接参数通常将使用与“图形资源管理器”中相同的值。 但是,由于该应用程序使用已登录用户的数据,因此您可以用me
替换用户ID,从而使值成为me/friends
。 该调用返回原始Connection
类型,并且由于类类型为User
,您需要将其添加为参数。 最后的电话是:
Connection<User> myFriends = FacebookClient.fetchConnection("me/friends", User.class);
所述的结果fetchConnection()
方法调用以保持List
的List
中的对象Connection
类。 的Connection
类实现Iterable
接口,这样就可以得到各List
中的对象List
通过使用增强的for
循环:
for (List<User> myFriendsList : myFriends)
在循环的每次迭代中, myFriendsList
对象都包含该返回数据页的当前用户列表。 此列表中的每个User
对象用于在Servlet将创建的用户表中创建一行。 尽管可以从User
对象中检索用户ID和名称,但个人资料图片不能。 但是,Facebook提供了一个用于检索任何用户的个人资料图片的URL:https://graph.facebook.com/ 用户ID / picture。 因此,通过将URL中的用户ID替换为来自User
对象的用户ID来创建个人资料图片的URL。 使用与以前相同的PrintWriter
对象,将带有标题行的表写入画布:
writer.print("<table><tr><th>Photo</th><th>Name</th><th>Id</th></tr>");
如上所述,遍历User
对象的列表,然后使用每个User
对象的实例变量为此表写一个新行:
for (List<User> myFriendsList : myFriends) {
for(User user: myFriendsList)
writer.print("<tr><td>" +
"<img src=\"https://graph.facebook.com/" + user.getId() + "/picture\"/>" +
"</td><td>" + user.getName() +"</td><td>" + user.getId() + "</td></tr>");
}
最后,关闭<table>
标记,并关闭PrintWriter
对象以完成servlet:
writer.print("</table>");
writer.close();
清单7显示了最终的servlet doPost()
方法:
清单7. doPost()
方法
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String signedRequest = (String) request.getParameter("signed_request");
FacebookSignedRequest facebookSR = null;
try {
facebookSR = FacebookSignedRequest.getSignedRequest(signedRequest);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String oauthToken = facebookSR.getOauth_token();
PrintWriter writer = response.getWriter();
if(oauthToken == null) {
response.setContentType("text/html");
String authURL = "https://www.facebook.com/dialog/oauth?client_id="
+ Constants.API_KEY +
"&redirect_uri=https://apps.facebook.com/myoldfriends/&scope=";
writer.print("<script> top.location.href='" + authURL + "'</script>");
writer.close();
}
else {
FacebookClient facebookClient = new DefaultFacebookClient(oauthToken);
Connection<User> myFriends = facebookClient.fetchConnection("me/friends",
User.class);
writer.print("<table><tr><th>Photo</th><th>Name</th><th>Id</th></tr>");
for (List<User> myFriendsList : myFriends) {
for(User user: myFriendsList)
writer.print("<tr><td><img src=\"https://graph.facebook.com/" +
user.getId() + "/picture\"/></td><td>" + user.getName() +
"</td><td>" + user.getId() + "</td></tr>");
}
writer.print("</table>");
writer.close();
}
}
部署应用程序
创建了Servlet之后,就可以部署应用程序了。 点击Eclipse中的Google图标,然后选择部署到App Engine 。 将应用程序编译并上传到服务器后,您(和任何其他Facebook用户)可以通过http://apps.facebook.com/APP ID /在Facebook中安装该应用程序,然后查看结果。
结论
本文演示了如何在Java上注册,实现和部署Google应用程序服务上托管的Facebook应用程序。 现在您已经熟悉了基础知识,建议您尝试一些变体。
您可以通过使用对JavaServer Pages(JSP)页面的标准RequestDispatcher.forward()
调用来实现更传统的Model-View-Controller(MVC)方法,而不是将内容HTML直接编写到页面中。
您可以尝试创建一个对Graph API提供的数据使用某些额外权限的应用程序。 通过将每个请求添加到scope
请求参数,将应用程序所需的权限列表传递给身份验证URL。 RestFB提供了一个辅助方法StringUtils.join()
来正确创建列表。 它使用单个String
数组作为参数; 数组中的每个条目都是一个权限名称。
最后,你可以尝试重新使用Facebook-Java的API谷歌代码项目的示例应用程序-替代实现Facebook的API的-而不是RestFB(参见相关主题 )。
翻译自: https://www.ibm.com/developerworks/java/library/j-fb-gae/index.html