1 背景概述
javascript
Portlet是AEAI Portal組件API,是基於Java的Web組件,由Portlet容器管理,並由容器處理請求,生產動態內容。AEAI Portal中已經預置了許多Portlet組件,能夠直接配置使用。因爲不一樣業務需求也能夠將Portlet進行定製開發。本文是本人在綜合集成項目中因爲業務須要動態顯示風險統計信息,即對某一風險進行評估時引用不一樣的風險點對其的影響(可能性與影響程度的乘積)進行分析,並在頁面以個數的形式顯示不一樣區間所包含風險點的影響。故而對Portlet的定製開發的過程以及方法進行總結。css
2 預期讀者html
AEAI Portlet開發人員java
數通暢聯人員web
其餘相關人員ajax
3 技能要求sql
本文檔假定目標用戶具有如下技能:數據庫
瞭解Eclipse基本用法;json
瞭解基本數據庫知識安裝以及SQL基本技能;瀏覽器
瞭解AEAI Portal基本知識;
瞭解AEAI ESB基本知識。
4 名詞解釋
5 實現思路
Portlet工程的定製開發過程大體爲:初始化數據庫portal、portal_test,portal_test中初始化業務數據表(risk_level_setting、risk_analyze_entry)以便提供業務須要的數據(參見6.3數據表初始化),在ESB工程(TestPortlets)中建立數據源portal_test(鏈接數據庫portal_test)以及建立消息流程(測試Portlets)來提供頁面顯示的數據信息(參見7.3Json處理),本地搭建Portal環境,開發Portlet工程,配置開發的Portlet實現業務需求。
6 實現步驟
6.1 建立工程
1. 在
中點擊
建立工程,選擇集成Web項目,填寫應用名稱(可自定義)、主目錄(可自定義),點擊測試鏈接,鏈接成功後點擊Next按鈕。配置以下圖:

2. 填寫鏈接的數據庫名稱,對應的用戶名以及密碼點擊測試鏈接彈出鏈接成功後點擊Finish按鈕。

按鈕若建立的PortLet數據庫中沒有內容,則點擊初始化數據,將自動生成數據表。若數據庫已經存在且有內容,不可點擊初始化數據,不然將覆蓋已有的數據庫內容。
3. 因爲新版的PortalServer的加密機制升級與當前的
的加密機制不一樣,故需修改對應配置文件中的密碼(參見附件中密碼生成文檔)
4. 替換新的密碼位置(兩處)以下:
1) 工程中的配置文件


2) (你的設計器的路徑)\miscdp-studio-win32_x86\workspace\test_portlets下的

5. 點開新建立的項目,在業務管理上點擊右鍵,選擇建立功能。

6. 填寫功能名稱(可自定義),功能類型選擇Portlet功能模型,點擊Finish按鈕。

7. 以下圖所示,填寫目錄編碼(可自定義)保存。

8. 點擊
按鈕生成代碼,點擊
按鈕或者點擊
切換到Java透視圖能夠查看代碼。以下圖:

9. 開發Portlet的Java類(至關於Handler)
1) 定義四個方法(具體參見7.1四個方法)
1. @RenderMode(name ="view")—指向View頁面構造頁面須要的屬性
publicvoidview(RenderRequest request, RenderResponse response)
2. @RenderMode(name = "edit")—指向Edit頁面構造頁面須要的屬性
publicvoidedit(RenderRequest request, RenderResponse response)
3. @ProcessAction(name ="saveConfig")
publicvoidsaveConfig(ActionRequest request, ActionResponse response)
4. @Resource(id ="getAjaxData")支持異步傳遞傳遞迴調函數須要的Json等信息
publicvoidgetAjaxData(ResourceRequest request, ResourceResponse response)
2) 建立兩個頁面(具體參見7.2兩個頁面)
1. View—在js中添加回調函數(回調函數處理Json等顯示的信息)
2. Edit—傳遞屬性信息
10. 擴展方法以及頁面完成後點擊加載應用,重啓應用

6.2 數據表初始化
1. 初始化數據表(Json中用到的業務數據)
1) 在數據庫
中建立數據表risk_level_setting 步驟以下:
2) 在
下點擊
下的
將下面的SQL複製在其中
DROP TABLE IF EXISTS `risk_level_setting`; CREATE TABLE `risk_level_setting` ( `RL_ID` char(36) NOT NULL, `RLS_MIN` float DEFAULT NULL, `RLS_MAX` float DEFAULT NULL, `RLS_CORLOR` varchar(255) DEFAULT NULL, PRIMARY KEY (`RL_ID`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of risk_level_setting -- ---------------------------- INSERT INTO `risk_level_setting` VALUES ('29FE4961-6F01-4913-99E3-24551E3BCF1F', '0', '5', 'GREEN'); INSERT INTO `risk_level_setting` VALUES ('874494A8-CD87-4EC2-9E44-4AAF9A493976', '5', '12', 'YELLOW'); INSERT INTO `risk_level_setting` VALUES ('EE214872-FE74-4F7E-A80F-FDC127570725', '12', '25', 'RED'); |
3) 點擊
執行

結果以下

4) 在數據庫
中建立數據表risk_analyze_entry 步驟同上,SQL以下:
DROP TABLE IF EXISTS `risk_analyze_entry`; CREATE TABLE `risk_analyze_entry` ( `RAE_ID` char(36) NOT NULL, `RAE_HAPP_POSS` decimal(10,0) DEFAULT NULL, `RAE_INF_DEGREE` decimal(10,0) DEFAULT NULL, `RAE_RISK_LEVEL` decimal(10,0) DEFAULT NULL, `RAE_SORT` int(11) DEFAULT NULL, PRIMARY KEY (`RAE_ID`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of risk_analyze_entry -- ---------------------------- INSERT INTO `risk_analyze_entry` VALUES ('0EC07E27-5130-4EA8-A64B-6B3DE5DFD22E', '2', '2', '4', null); INSERT INTO `risk_analyze_entry` VALUES ('470840C1-086C-43C4-977A-7F16D14F7D33', '5', '3', '15', null); INSERT INTO `risk_analyze_entry` VALUES ('67815A3F-4B52-490B-A520-E787AE8585BE', '3', '3', '9', null); INSERT INTO `risk_analyze_entry` VALUES ('B76D5B92-FDE5-46E6-8E02-BD06CD6D5E6D', '1', '1', '1', null); |
6.3 配置說明
1. Portal配置說明
1) 瀏覽器輸入http://localhost:8080/portal/login.jsp訪問portal工程,界面以下:

2) 以admin身份登陸密碼爲admin,點擊門戶管理。

3) 點擊組件管理Portlet應用

4) 點擊
按鈕填寫編碼標識(爲自定義開發的portlets工程名)、編碼值(可自定義)、選擇編碼類型、編碼排序、選擇是否有效,後點擊保存按鈕。


5) 點擊組件管理中的Portlet設置

6) 點擊
按鈕填寫標題(可自定義)、選擇所屬應用、Portlet名稱、分組,後點擊保存按鈕。


7) 點擊
下的
點擊綜合門戶以下圖:

8) 選中
點擊右側的
彈出界面填寫編碼、名稱(可自定義)點擊保存按鈕。配置以下:

9) 點擊剛建立好的切換到頁面佈局點擊
按鈕添加容器

10) 彈出的界面選擇對應的Portlet

點擊保存按鈕

11) 點擊
下的
切換回主界面,點擊決策分析菜單中的
顯示以下圖:

12) 點擊
按鈕切換到
界面,將建立的ESB流程中的HttpRequest節點(參見7.3Json處理)的訪問地址填寫到數據URL中,設置高度,點擊保存按鈕。配置以下:

13) 結果以下:

6.4 參考技巧
因爲本人Portlet的開發並非十分了解,故在開發過程當中找到以下小技巧爲開發者提供參考。對根據需求開發不一樣功能的Portlet,定義所須要的屬性,可利用反編譯軟件打開已封裝完現有的Portlet組件功能,做爲實現的參考。達到Portlet的定製開發的目的。參考路徑爲:…..你的服務器的地址)\portal_server_x64_Vx.x.x.YYYYMMDD\webapps\portal_portlets\WEB-INF
\classes\com\agileai\portal\portlets

7 核心說明
7.1 四個方法
1. 自定義開發的Portlets中擴展開發下面的四個方法,本例位於

2. View方法中指向View頁面構造頁面須要的屬性
@RenderMode(name = "view") publicvoid view(RenderRequest request, RenderResponse response) throws PortletException, IOException { PortletPreferences preferences = PreferencesHelper.getPublicPreference(request); String chartHeight = preferences.getValue("chartHeight", "50"); String namespace = preferences.getValue("namespace", null); String defaultVariableValues = preferences.getValue("defaultVariableValues", null); String dataURL = preferences.getValue("dataURL", null); String defaultValueString = "namespace="+namespace+"&"+defaultVariableValues; PortletVariableHelper variableHelper = new PortletVariableHelper(request,defaultValueString); dataURL = variableHelper.getRealDataURL(dataURL); String portletId = request.getWindowID(); Integer height = Integer.parseInt(chartHeight); request.setAttribute("height", height); request.setAttribute("portletId", portletId); request.setAttribute("namespace", namespace); request.setAttribute("dataURL", dataURL); super.doView(request, response); } |
3. Edit方法中指向Edit頁面構造頁面須要的屬性
@RenderMode(name = "edit") publicvoid edit(RenderRequest request, RenderResponse response) throws PortletException, IOException { PortletPreferences preferences = PreferencesHelper.getPublicPreference(request); String dataURL = preferences.getValue("dataURL", null); String chartHeight = preferences.getValue("chartHeight", null); String namespace = preferences.getValue("namespace", null); String defaultVariableValues = preferences.getValue("defaultVariableValues", null); request.setAttribute("dataURL", dataURL); request.setAttribute("chartHeight", chartHeight); request.setAttribute("namespace", namespace); request.setAttribute("defaultVariableValues", defaultVariableValues); super.doEdit(request, response); } |
4. saveConfig方法保存配置信息
@ProcessAction(name = "saveConfig") publicvoid saveConfig(ActionRequest request, ActionResponse response) throws ReadOnlyException, PortletModeException, ValidatorException, IOException, PreferenceException { String dataURL = request.getParameter("dataURL"); String chartHeight = request.getParameter("chartHeight"); String namespace = request.getParameter("namespace"); String defaultVariableValues = request.getParameter("defaultVariableValues"); PreferencesWrapper preferWapper = new PreferencesWrapper(); preferWapper.setValue("dataURL", dataURL); preferWapper.setValue("chartHeight", chartHeight); preferWapper.setValue("namespace", namespace); preferWapper.setValue("defaultVariableValues", defaultVariableValues); PreferencesHelper.savePublicPreferences(request,preferWapper.getPreferences()); response.setPortletMode(PortletMode.VIEW); } |
5. getAjaxData支持異步傳遞傳遞迴調函數須要的Json等信息
@Resource(id = "getAjaxData") publicvoid getAjaxData(ResourceRequest request, ResourceResponse response) throws PortletException, IOException { String ajaxData = ""; try { String dataURL = getDataURL(request); StringWriter buffer = new StringWriter(); URL url = new URL(dataURL); InputStream inputStream = url.openStream(); IOUtils.copy(inputStream, buffer, "UTF-8"); IOUtils.closeQuietly(inputStream); ajaxData = buffer.toString(); } catch (Exception e) { this.logger.error("獲取取數據失敗getAjaxData", e); } PrintWriter writer = response.getWriter(); writer.print(ajaxData); writer.close(); } |
7.2 兩個頁面
1. 自定義開發的Portlets中擴展開發下面的兩個頁面,本例位於WebRoot下:

2. view頁面爲界面所顯示的信息,其中responseText爲getAjaxData方法中返回的參數Json

得到Java類中定義的height變量,將css的高度變量化


代碼以下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <%@page import="com.agileai.hotweb.domain.PageBean"%> <portlet:defineObjects/> <% Integer height = (Integer)request.getAttribute("height"); Integer tab2height = (Integer)request.getAttribute("height") - height/10; %> <style> .graphTable<portlet:namespace/>{ font-family: verdana,arial,sans-serif; border-width:1px; border-color: #000000; border-collapse: collapse; } .graphTable<portlet:namespace/>tr{ height:<%=height%>px; border-width: 1px; border-style: solid; border-color: #000000; } .graphTable<portlet:namespace/> tr td{ height:<%=height%>px; width:<%=height%>px; text-align:center; border-width: 1px; border-style: solid; border-color: #000000; } .table2<portlet:namespace/> tr td{ width:<%=height%>px; text-align:right; } .table1<portlet:namespace/> tr td{ height:<%=tab2height%>px; } </style> <portlet:resourceURL id="getAjaxData" var="getAjaxDataURL"> </portlet:resourceURL> <body> <span style="float:left"> <table border="0" style="float:left" class = "table1<portlet:namespace/>" id="table1"> <tr> <td>影</td> <td> </td> <td>5.0</td> </tr> <tr> <td>響</td> <td> </td> <td>4.0</td> </tr> <tr> <td>程</td> <td> </td> <td>3.0</td> </tr> <tr> <td>度</td> <td> </td> <td>2.0</td> </tr> <tr> <td> </td> <td> </td> <td>1.0</td> </tr> <tr> <td> </td> <td> </td> <td>0.0</td> </tr> </table> <table border="1" class="graphTable<portlet:namespace/>" id="graphTable1"> <tr> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> </tr> <tr> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> </tr> <tr> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> </tr> <tr> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> </tr> <tr> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td> </tr> </table> <table border="0" class="table2<portlet:namespace/>" id="table2"> <tr> <td>1.0</td> <td>2.0</td> <td>3.0</td> <td>4.0</td> <td>5.0</td> </tr> <tr> <td> </td> <td>可</td> <td>能</td> <td>性</td> <td> </td> </tr> </table> </span> </body> <% String portletId = (String)request.getAttribute("portletId"); %> <div>${someProperty}</div> <script type="text/javascript"> $(function(){ var __renderPortlet<portlet:namespace/> = function(){ sendAction('${getAjaxDataURL}',{dataType:'text',onComplete:function(ajaxData){ var allJson = $.parseJSON(ajaxData); var rowCountIndex = 0; for (var i=5;i > 0;i--){ rowCountIndex++; for (var j=0;j < 5;j++){ var rowIndex = i-1; var colIndex = j; var colCountIndex = j+1; var total = rowCountIndex * colCountIndex; if (total >= allJson.dataLine.GREEN.min && total <= allJson.dataLine.GREEN.max){ $("#graphTable1 tr:eq("+rowIndex+") td:eq("+colIndex+")").css("background-color","green"); } elseif (total >= allJson.dataLine.YELLOW.min && total <= allJson.dataLine.YELLOW.max){ $("#graphTable1 tr:eq("+rowIndex+") td:eq("+colIndex+")").css("background-color","yellow"); } else{ $("#graphTable1 tr:eq("+rowIndex+") td:eq("+colIndex+")").css("background-color","red"); } } } for (var i=0 ;i < 25 ;i++){ if(allJson.cellNumbers[i].count == 0){ $("#graphTable1 tr:eq("+allJson.cellNumbers[i].rowIndex+") td:eq("+allJson.cellNumbers[i].colIndex+")").text(""); }else{ $("#graphTable1 tr:eq("+allJson.cellNumbers[i].rowIndex+") td:eq("+allJson.cellNumbers[i].colIndex+")").text(allJson.cellNumbers[i].count); } } }}); }; __renderPortlets.put("<%=portletId%>",__renderPortlet<portlet:namespace/>); __renderPortlet<portlet:namespace/>(); }); </script> |
3. Edit頁面爲配置Portal中編輯頁面所顯示的屬性信息以下圖:

編輯頁面所顯示的屬性

代碼以下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <portlet:defineObjects/> <portlet:actionURL name="saveConfig" var="saveConfigURL"></portlet:actionURL> <portlet:renderURL portletMode="edit" var="editURL"></portlet:renderURL> <% String isCache = (String)request.getAttribute("isCache"); %> <form id="<portlet:namespace/>Form"> <table width="90%" border="1"> <tr> <td width="120">數據URL <span style="color: red;">*</span></td> <td><input type="text" size="50" name="dataURL" id="dataURL" value="${dataURL}" /></td> </tr> <tr> <td width="120">默認值</td> <td> <input type="text" name="defaultVariableValues" id="defaultVariableValues" size="50" value="${defaultVariableValues}" /> </td> </tr> <tr> <td width="120">高度 <span style="color: red;">*</span></td> <td><input type="text" size="50" name="chartHeight" id="chartHeight" value="${chartHeight}" /></td> </tr> <tr> <td colspan="2" align="center"> <input type="button" name="button" id="button" value="保存" /> <input type="button" name="button2" id="button2" value="取消" onclick="fireAction('${editURL}')"/></td> </tr> </table> </form> <script language="javascript"> </script> |
7.3 Json處理
1. ESB建立工程TestPortlets、建立數據源portal_test爲ESB的基礎知識,在這裏不作過多的贅述。(可參見AEAI ESB集成平臺技術手冊)
2. ESB建立消息流程
1) 在消息流程中添加數據查詢節點以及數據轉換節點
2) 在JdbcQueryer節點中建立DataSet接收查詢的結果集
3) 在JavaConverter中建立XXX用於接收轉換後的結果集,在擴展代碼中修改對應代碼
4) 在HttpResponse中打印轉換後的結果:@{XXX}
3. 流程圖以下:

查詢風險評價節點選擇數據源建立結果類型變量riskGraphMaxMinDataSet,點擊選擇表選擇數據表(risk_level_setting)生成SQL。配置以下:

點擊刷新按鈕後,點擊Finish按鈕。

查詢風險點節點(參見查詢風險評價節點)結果變量爲(riskGraphDataSet)數據表爲(risk_analyze_entry)配置以下:


下面咱們重點講解JOSN格式轉換節點。
雙擊改節點選擇轉換,DataSet裝換爲數據表格,點擊Next按鈕。

點擊選擇按鈕選擇來源變量,建立目標變量,選中擴展代碼,點擊Finish按鈕。

擴展代碼以下:


建立Json存儲、最外層的Json名稱爲dataLine

將rowIndex與colIndex放入到子Json中。

此方法是因爲業務須要設置默認值均爲0
import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import org.codehaus.jettison.json.JSONArray; import org.codehaus.jettison.json.JSONObject; import com.agileai.domain.DataRow; import com.agileai.domain.DataSet; import com.agileai.esb.component.Variable; import com.agileai.esb.component.transformer.JavaTransformer; import com.agileai.esb.core.AdapteException; publicclass JavaConverter1 extends JavaTransformer{ private List<DataRow> dataModel = new ArrayList<DataRow>(); publicvoid handleRequest() throws AdapteException{ try { this.initModel(); Variable riskGraphVariable = this.getVariable("riskGraphDataSet"); Variable riskGraphMaxMinVariable = this.getVariable("riskGraphMaxMinDataSet"); DataSet riskGraphDataSet = (DataSet)riskGraphVariable.getValue(); for (int i=0;i < riskGraphDataSet.size();i++){ DataRow row = riskGraphDataSet.getDataRow(i); BigDecimal degree = (BigDecimal)row.get("RAE_INF_DEGREE"); for (int m =0 ;m < 5;m++){ if (degree.compareTo(new BigDecimal(m)) > 0 && degree.compareTo(new BigDecimal(m+1)) <=0){ DataRow modelRow = this.dataModel.get(m); BigDecimal poss = (BigDecimal)row.get("RAE_HAPP_POSS"); for (int n = 0;n < 5;n++){ if (poss.compareTo(new BigDecimal(n)) > 0 && poss.compareTo(new BigDecimal(n+1)) <=0){ Integer currentCount = (Integer)modelRow.get(String.valueOf(n)); modelRow.put(String.valueOf(n),++currentCount); } } } } } DataSet riskGraphMaxMinDataSet = (DataSet)riskGraphMaxMinVariable.getValue(); JSONArray riskGraphjsonArray = new JSONArray(); JSONObject totalJsonObj = new JSONObject(); JSONObject riskGraphMaxMinJsonObj = new JSONObject(); for (int i=0;i < riskGraphMaxMinDataSet.size();i++){ DataRow dataLineRow = riskGraphMaxMinDataSet.getDataRow(i); JSONObject dataLinejsonObject = new JSONObject(); riskGraphMaxMinJsonObj.put(dataLineRow.stringValue("RLS_CORLOR"),dataLinejsonObject); dataLinejsonObject.put("min", dataLineRow.stringValue("RLS_MIN")); dataLinejsonObject.put("max", dataLineRow.stringValue("RLS_MAX")); } totalJsonObj.put("dataLine", riskGraphMaxMinJsonObj); for (int m=0;m < 5;m++){ DataRow row = this.dataModel.get(m); for (int n=0;n < 5;n++){ JSONObject cellNumsJsonObject = new JSONObject(); int rowIndex = 4-m; int colIndex = n; cellNumsJsonObject.put("rowIndex", rowIndex); cellNumsJsonObject.put("colIndex", colIndex); int count = row.getInt(String.valueOf(n)); cellNumsJsonObject.put("count", count); riskGraphjsonArray.put(cellNumsJsonObject); } } totalJsonObj.put("cellNumbers", riskGraphjsonArray); Variable targetVariable = this.getVariable("riskGraphJson"); targetVariable.setValue(totalJsonObj); } catch (Exception e) { logger.error(e.getLocalizedMessage(), e); thrownew AdapteException(e.getLocalizedMessage(),e); } } privatevoid initModel(){ for (int i=0;i < 5;i++){ DataRow row = new DataRow(); this.dataModel.add(row); for (int n=0;n < 5;n++){ row.put(String.valueOf(n),0); } } } } |
HttpResponse節點打印Json配置以下:

4. 在TestPortlets應用節點右鍵,以下:

5. 點擊部署ESB應用,彈出窗口以下:

6. 點擊「Finish」,因爲部署ESB應用可能較慢(5-10秒),可能在設計器上沒有及時響應,圖表處於變灰狀態,點擊
按鈕來刷新,左邊的菜單節點才能高亮顯示,以下:

7. 訪問HttpRequest節點的URL http://localhost:9090/TestPortlets/http/TestPortlets獲得Json以下:

8 附件說明
ESB文件夾/ TestPortlets.zip:消息流程--測試Portlets提供業務數據
Portal文件夾/ portal.zip:本地搭建portal環境
Portal文件夾/ portal_portlets.zip:封裝好的portlets
Portal文件夾/ test_portlets.zip:自定義開發的portlets
sqls文件夾/ portal.sql本地搭建portal環境須要的數據庫文件
sqls文件夾/ portal_test.sql提供自定義開發的portlets須要的數據庫信息,包含須要初始化的業務數據表
密碼生成:生成密文密碼的方法
AEAI Portlet開發心得相關附件及文檔 下載