最近有個任務,就是要作一個像Igoogle同樣能夠拖拽的頁面,而後開發一些小控件,能夠動態維護和佈局。以前沒有接觸過,感受可能就是些JS,外加兩張表存儲控件位置,以爲應該還能實現,就試着作了下,由於以前據說過Portal這個名詞,因而就本是遵循規範、借鑑開源、不重複造輪子的原則,在網上搜搜Portal相應規範和開源實現,開始了個人實現之路。在浪費了近一個月時間的仍但願渺茫的時候,接觸到了OpenSocial,才終於完成了任務。javascript
(一)Portalhtml
Portal一詞中文翻譯爲門戶,是基於Web的應用,一般提供個性化,單點登陸,整合不一樣資源的綜合信息展現平臺。Portal展示在最終用戶面前的是相似於Web網頁的Portal頁面。java
構成Portal頁面的是可以創建和展示不一樣內容的一系列Portlet。Portlet處理從Portal傳遞來的用戶請求,動態生成輸出內容的一個片斷,展示在Portal頁面的某個位置上。web
下圖顯示了Portal服務器、Portlet容器以及Portlet之間的關係。json
Portlet是一個符合JSR168標準的類,是運行於Portal上的真正表明業務邏輯的部件,負責展示內容、處理請求。在Portal搭建好後,主要的工做就是根據業務要求開發Portlet了。api
在部署Portlet到一個Portal時,除須要將邏輯代碼拷貝過去外,還須要定義一個portlet.xml的配置文件來註冊。Portal要支持Portlet須要是Portlet容器,就像tomcat是servlet容器同樣,也就是說,須要擴展servlet容器才能夠支持Portal功能。tomcat
咱們的實際狀況是有多個項目,每一個項目都有單獨的項目組維護,若是將每一個Portlet業務代碼(java代碼、js、jsp等)拷貝到Portal門面項目裏,會形成邏輯混亂、維護困難,這確定是不能接收的。服務器
Portal的開源項目有Pluto、Jetspeed、Liferay。項目的功能依次遞增,代碼複雜度也依次遞增。Pluto實現了JSR168規範,擴展servlet容器爲Portlet容器,Jetspeed和Liferay都是在它的基礎上構建的;Jetspeed實現了控件的動態增刪除和簡單的自定義;Liferay則是一個功能齊全的門戶解決方案。app
我借鑑Liferay的源碼來實現本身的Portal,但它的代碼混亂、邏輯複雜,顯示層struts一、servlet、volocity、FreeMarker 等各類技術濫用,後臺代碼組織更凌亂。並且代碼使用複雜的ant組織方式,讓人卻步。因爲Portlet固有的問題及Liferay實現方式的複雜,我最後放棄了使用這種技術。jsp
(二)OpenSocial
山窮水復疑無路,柳暗花明又一村。在絕望的時候我看到了OpenSocial。
OpenSocial是Google發佈的一個項目,定位於爲SNS平臺定義一套通用API,讓應用開發者只需使用OpenSocial API進行一次開發,就能夠將應用發佈在全部支持OpenSocial的平臺中。OpenSocial定義了一系列協議、標準和接口,用於將應用、容器和其餘客戶端融合在一塊兒。OpenSocial是基於Web的,開發人員可使用標準的javascript和html建立應用,應用可使用OpenSocial的接口,訪問SNS平臺提供的信息。
OpenSocial通常由如下幾部分組成:
Gadget
指由第三方開發人員開發的應用,通常由xml配置文件、javascript和html等其餘資源組成。經過javascript調用OpenSocial提供的標準通用API來和SNS平臺進行交互。應用的開發者可使用OpenSocial的Javascript接口編寫基於HTML和Ajax的Social應用,還可使用Flash/Flex技術,開發用戶界面更友好的富Internet應用。Gadget運行於Gadget容器中。
Gadget容器:
一個SNS平臺,若是能夠集成OpenSocial應用,咱們就稱其爲Gadget容器。做爲一個Gadget容器,須要執行渲染Gadgets、代理請求、響應REST和RPC請求等工做,還須要實現OpenSocial標準中描述的接口,這些接口包括:獲取用戶信息、存儲和讀取用戶活動、存儲和讀取數據、發送消息等。Apache Shindig是OpenSocial容器的一個參考實現。
第三方網站
提供js及rest等風格的API,供開發的Gadget調用。這些Gadget通常會部署到第三方的平臺,Gadget使用OpenSocial標準的Javascript接口作Ajax調用,經過SNS平臺代理調用第三方網站的API。
如圖:支持 OpenSocial 標準後的開發方式
控件簡介
Gadget 是一個獨立的應用。它由一個特定格式的 XML 文件定義,這個 XML 文件中包含定義 Gadget 應用行爲的 HTML、CSS、JavaScript 代碼和圖片、聲音、視頻等資源。HTML 能夠用來展示內容。JavaScript 用於獲取服務器數據,執行應用邏輯,動態修改展示內容。CSS 用來指定內容展示的樣式。下面的例子(helloworld.xml)展現了 Gadget 基本的元素。
<?xml version="1.0" encoding="UTF-8" ?> <Module> <ModulePrefs title="Hello World!"> <Require feature="dynamic-height"/> </ModulePrefs> <Content type="html"> <![CDATA[ Hello, world! ]]> </Content> </Module>
在這個例子中,開發人員能夠看到定義 Gadget 行爲的幾個重要元素:
<Module> 表示這個 XML 文件定義了一個 Gadget。
<ModulePrefs> 描述 Gadget 的元數據和做者信息。
<Require feature=" dynamic-height " /> 聲明瞭 Gadget 須要加載一個 Feature。Feature 實現了特定功能 JavaScript API。
<Content type="html"> 聲明 Gadget 的內容是 HTML。
<![ CDATA[ … ]]> 包含了 Gadget 的內容:JavaScript、CSS、HTML。這個元素相似於 HTML 頁面的 body 元素。
javaScript api
OpenSocial 中的 JavaScript API 經過 Feature 來組織。每一個 Feature 是一個能夠單獨加載的 JavaScript 模塊。經過如下的語法,Gadget 能夠聲明加載某個 Feature。
<Require feature="dynamic-height"/>
Feature能夠分爲如下幾類:
展示一個 Gadget 確定都會用到的特性,諸如 globals、core、rpc。
globals 定義了一些全局變量,如 gadgets、shindig、osapi。
core 特性提供了展示一個 Gadget 所須要的核心功能,包括 io 操做、用戶設置等。
rpc 特性提供了整個 rpc 調用的實現。shindig 默認使用 iframe 來展示 Gadget,若是 Gadget 須要訪問外部容器定義的某些方法,就須要經過 rpc 調用來完成。
Gadget 容器用到的特性,諸如 shindig-container、container。
OpenSocial 相關的一些特性,諸如 osapi、opensocial-data、opensocial-reference 等。
一些 util 特性,諸如 shindig.uri、shindig.xhrwrapper、xmlutil。
跟 Gadget 的用戶界面比較相關的特性,諸如 settitle、tabs、views、minimessages、flash。
settitle 顧名思義就是設置 Gadget 的標題,使用這個特性能夠在 Gadget 裏面根據須要來動態的設置 Gadget 的標題。
tabs 特性支持在 Gadget 裏面方便的建立多個 tab 和對應的內容。
views 特性提供了能夠在多個 view 之間切換的功能。Gadget能夠定義多個 view,使用 views 特性能夠自由的在多個 view 間切換。
minimessages 特性則提供了幾種類型的提示消息,好比顯示多長時間就自動消失的消息提示。
flash 特性則能夠在 Gadget 裏面嵌入 flash 文件。
爲了 Gadget之間的通訊所用到的特性,pubsub 和 pubsub-2。
經常使用的globals、core、rpc、util已經默認引入,其餘的Feature須要顯式require引入。
下面是一個複雜些的例子:
gadget.xml
<?xml version="1.0" encoding="UTF-8"?> <Module> <ModulePrefs title="Make Request Example"> <Require feature="dynamic-height"></Require> </ModulePrefs> <Content type="html"> <![CDATA[ <script type="text/javascript" src="makeRequest.js"></script> <h4>Select an NHL team and press "GO!" to see more information</h4> <select id="team"> <option value="BOS">Boston</option> <option value="PHI">Philadelphia</option> <option value="TBL">Tampa Bay</option> <option value="CHI">Chicago</option> <option value="VAN">Vancouver</option> <option value="SJS">San Jose</option> </select> <button type="button" onclick="lookupTeam()">GO!</button> <br /> Team ID: <span id="teamID"></span><br /> Team Name: <span id="name"></span><br /> Conference: <span id="conference"></span><br /> Division: <span id="division"></span> <script type="text/javascript"> gadgets.util.registerOnLoadHandler(init); </script> ]]> </Content> </Module>
makeRequest.js
function init(){ var miniMessage = new gadgets.MiniMessage(); miniMessage.createStaticMessage("Welcome to the OpenSocial Explorer!"); } function lookupTeam() { var index = document.getElementById('team').selectedIndex; var options = document.getElementById('team').options; var teamID = options[index].value; var params = {}; params[gadgets.io.RequestParameters.CONTENT_TYPE] = gadgets.io.ContentType.JSON; var url = 'http://www.nicetimeonice.com/api/teams/' + teamID; gadgets.io.makeRequest(url, function(response) { if (response.errors.length == 0) { var data = response.data; document.getElementById('teamID').innerHTML = data.teamID; document.getElementById('name').innerHTML = data.name; document.getElementById('conference').innerHTML = data.conference; document.getElementById('division').innerHTML = data.division; gadgets.window.adjustHeight(); } else { gadgets.error('There was an error making the request.'); } }, params); }
能夠看到,OpenSocial並非爲Portal打造的,它主要是爲SNS平臺的交互定義規範。但因爲它的交互都是基於rest和標準的html,系統間的耦合很小,部署也更簡單方便,是很好的一個選擇。去掉它的社交屬性,Gadget容器加上portal的管理方式,這不正是我想要的嗎!
(三)OpenSocial版Portal
說真來容易,真作起來,仍是不易,好在前人已經鋪路,我這個後來者就能夠乘涼了。
infoScoop這個項目已經實現了我想要的全部功能!portal+OpenSocial,完美的組合。並且這個開源項目代碼結構組織的很好,後臺只負責返回json和js格式的數據,前臺js負責處理Portlet(或叫Gadget)的展示邏輯、這樣後臺的代碼量就不多,並且技術選型也很好,只用了hibernate和servlet,沒有用什麼怪異的技術,它使用Apache Shindig這個標準套件來解析Gadget,代碼分層很清楚,很容易理解。
前臺使用js處理展示邏輯時,使用js面向對象組織,代碼可讀性很強,組織的也很清楚。
終於在經歷波折後實現了我想要的功能,感謝互聯網的改變,讓分佈式系統交互更容易,感謝開源的力量。