OpenSocial:跨社交網站的通用 API 規范,開發者使用 JavaScript/HTML 構建 Gadget,標準化訪問 People、Activities、AppData 等社交數據。
Apache Shindig:OpenSocial 參考實現,核心組件:
gadgets.js,提供 UI Layout、Security、RPC 通信。opensocial.js,封裝 REST/RPC 數據訪問 API。GadgetRenderingServlet、DataServiceServlet、JsonRpcServlet。服務端架構基於 Java Servlet Stack,JsonDbOpensocialService 實現 ActivityService/PersonService/AppDataService 接口,默認提供基於 JSON 文件的數據存儲。
https://m2eclipse.sonatype.org/update/。https://svn.apache.org/repos/asf/incubator/shindig/trunk/。shindig-server,Goals: jetty:run。https://localhost:8080/gadgets/files/samplecontainer/samplecontainer.html 驗證。Shindig 通過 Guice 依賴注入 綁定 SPI 實現。需實現三大服務接口:
PersonService:用戶/好友數據ActivityService:動態/活動流AppDataService:應用數據存儲public class SocialTestJsonPersonService implements PersonService {
private static final String PEOPLE_TABLE = "people";
private static final String FRIEND_LINK_TABLE = "friendLinks";
private JSONObject db; // 從 JSON 文件加載
private BeanConverter converter;
@Override
public Future<RestfulCollection<Person>> getPeople(Set<UserId> userIds, GroupId groupId,
CollectionOptions options, Set<String> fields, SecurityToken token) {
List<Person> result = Lists.newArrayList();
try {
JSONArray people = db.getJSONArray(PEOPLE_TABLE);
Set<String> idSet = getIdSet(userIds, groupId, token);
for (int i = 0; i < people.length(); i++) {
JSONObject person = people.getJSONObject(i);
if (!idSet.contains(person.get(Person.Field.ID.toString()))) continue;
result.add(filterFields(person, fields, Person.class));
}
int totalSize = result.size();
return ImmediateFuture.newInstance(new RestfulCollection<>(
result, options.getFirst(), totalSize, options.getMax()));
} catch (JSONException je) {
throw new ProtocolException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, je.getMessage(), je);
}
}
@Override
public Future<Person> getPerson(UserId id, Set<String> fields, SecurityToken token) {
// 單用戶查詢邏輯類似...
}
// 其他接口方法...
}
public class SampleModule extends SocialApiGuiceModule {
@Override
protected void configure() {
super.configure();
bind(String.class).annotatedWith(Names.named("shindig.socialtest.json.db"))
.toInstance("sampledata/socialtestdb.json"); // 數據文件路徑
bind(ActivityService.class).to(JsonDbOpensocialService.class);
bind(AppDataService.class).to(JsonDbOpensocialService.class);
// 關鍵:綁定自定義 PersonService 實現
bind(PersonService.class).to(SocialTestJsonPersonService.class);
bind(MessageService.class).to(JsonDbOpensocialService.class);
bind(OAuthDataStore.class).to(SampleOAuthDataStore.class);
requestStaticInjection(SampleRealm.class);
}
}
<Module>
<ModulePrefs title="Social Application Test">
<Require feature="osapi"/> <Require feature="dynamic-height"/>
</ModulePrefs>
<Content type="html"><![CDATA[
<button onclick="fetchPeople()">Fetch people and friends</button>
<div><span id="viewer"></span><ul id="friends"></ul></div>
<script>
function fetchPeople() {
var fields = ['id','age','name','gender','profileUrl','thumbnailUrl'];
var batch = osapi.newBatch();
batch.add('viewer', osapi.people.getViewer({sortBy:'name', fields:fields}));
batch.add('viewerFriends', osapi.people.getViewerFriends({sortBy:'name', fields:fields}));
batch.execute(render);
}
function render(data) {
document.getElementById('viewer').innerHTML = data.viewer.id;
data.viewerFriends.list.forEach(p =>
document.getElementById('friends').innerHTML += '<li>' + p.name.formatted + '</li>');
gadgets.window.adjustHeight();
}
</script>
]]></Content>
</Module>
部署至 samplecontainer/socialtest.html,瀏覽器訪問測試。
public class SocialAppTest {
private static final String BASE_URI = "https://localhost:8080/social/rest/";
private static final String VIEWER_ID = "john.doe";
public static void main(String[] args) {
OpenSocialClient client = new OpenSocialClient("SocialAppTest");
client.setProperty(OpenSocialClient.Property.REST_BASE_URI, BASE_URI);
client.setProperty(OpenSocialClient.Property.VIEWER_ID, VIEWER_ID);
OpenSocialPerson viewer = client.fetchPerson(VIEWER_ID);
System.out.println("Viewer: " + viewer.getId());
for (OpenSocialPerson friend : client.fetchFriends(viewer.getId())) {
System.out.println("Friend: " + friend.getId());
}
}
}
OpenSocial 平台兩端選擇:
本文示例完整源碼可參考附件資源鏈接。