“portal”一詞中文翻譯為“門戶”,所謂門戶是指各種資訊的內建。
rose portal基于rose架構,是rose的一個插件。這個技術不是基于JavaEE的portlet規範,您隻需要使用标準的servlet容器即可實作,而且更簡單。
本示例示範如何使用rose portal (基于servlet規範),在一個門戶可以顯示兩個獨立的“資訊”
建立控制器
1個是Portal主要,另外2個是視窗控制器 1) 在controllers或子目錄下建立Portal控制器:PortalController,建立處理方法,并聲明Portal參數
package ninja.paoding_rose.test.controllers;
import net.paoding.rose.web.annotation.Path;
import net.paoding.rose.web.annotation.rest.Get;
import net.paoding.rose.web.portal.Portal;
@Path("portal")
public class PortalController {
// 标注@Get,表示這個方法要處理的是對/portal的GET請求
// 在主要控制方法上聲明Portal參數即表示這個頁面是portal,就這樣!
@Get
public String home(Portal portal) throws Exception {
// 使用addWindow向這個portal頁面加入各種子資訊(我們成為視窗)
portal.addWindow("docin","/windows/docin");
// 第一個參數是用于辨別該視窗,使得portal頁面中可以引用到這個視窗的html //
// 第二個參數表示這個視窗的位址(可以包含參數),這個位址等價于forward的位址(也就是這裡隻要能forward的位址都可以,無論是否是rose架構的,甚至可以是一個jsp頁面)
// // 是以,位址沒有說一定要以"/windows"開始
portal.addWindow("ninja","/windows/ninja?name=value");
return "portal_page";
}
}
2) 在controllers.windows下建立可被/windows/docin,/windows/ninja 通路的控制器以及方法 DocinController.java
package ninja.paoding_rose.test.controllers.windows;
import net.paoding.rose.web.Invocation;
import net.paoding.rose.web.annotation.Path;
import net.paoding.rose.web.annotation.rest.Get;
@Path("docin")
public class DocinController {
// 這個方法處理"/windows/weather",它隻是傳回一串中文,而非jsp、vm等頁面
@Get
public String docin(Invocation inv) {
return "@豆丁豆丁豆丁豆丁豆丁豆丁豆丁!";
}
}
NinjaController.java
package ninja.paoding_rose.test.controllers.windows;
import java.util.ArrayList;
import java.util.List;
import net.paoding.rose.web.Invocation;
import net.paoding.rose.web.annotation.Path;
import net.paoding.rose.web.annotation.rest.Get;
import net.paoding.rose.web.portal.Window;
@Path("ninja")
public class NinjaController {
// 在控制器使用全局變量并不好,在此僅是一個示範而已
private int count;
// 方法名是什麼不要緊,關進是@Get代表了這個方法用于處理對/ninja的GET請求
@Get
public String ninja(Invocation inv, Window window) {
List<String> list = new ArrayList<String>();
list.add("偷襲");
list.add("忍術");
list.add(String.valueOf(count++));
inv.addModel("todolist", list); //
// 傳回頁面,rose将從這個子產品對應的/views/windows下找名字以ninja開始的頁面
return "ninja";
}
}
portal頁面
webapp/views下建立PortalController需要的portal_page.jsp (這裡亦可以用rose 所支援的.vm檔案)
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<html>
<head>
<link href="/static/portal.css" target="_blank" rel="external nofollow" rel="stylesheet" type="text/css" media="all" />
<title>Portal</title>
</head>
<body>
<h2>Portal</h2>
<div class="window">
<div class="title">豆丁</div>
<!--這裡使用$weather的"weather"即是第一個window的辨別-->
<div class="content">${docin}</div>
</div>
<div class="window">
<div class="title">忍者</div>
<!--$todo實際是一個Window對象,velocity會調用其toString()輸出html的-->
<div class="content">${ninja}</div>
</div>
</body>
</html>
window頁面
webapp/views/windows建立ninjaController需要的頁面 ninja.jsp (亦可以用ninja.vm 但寫法很不同。)
<%@ page import="java.util.*" %>
<ul>
<%
List<String> result = (List<String>)request.getAttribute("todolist");
for(String oneItem : result){
%>
<li><%=oneItem %></li>
<%
}
%>
</ul>
并發數配置
在web.xml的<web-app>下配置并發參數值:
<context-param>
<param-name>portalExecutorCorePoolSize</param-name>
<param-value>200</param-value>
</context-param>
如果沒有配置以上參數,預設portalExecutorCorePoolSize取1,相當于除了http主線程外隻有另外1個執行線程, 這對程式的正确性沒有任何影響,隻是并發能力下降了,整個portal的執行時間也會變長。
進階話題
1) 可以在PortalController.home方法上設定@PortalSetting(timeout = 100)表示最多等待各個視窗100ms(包括window的頁面渲染耗費時間)
2) 可以通過引入xiaonei-commons-interceptors的@Throughput(maxConcurrent = 20)放置在window的xxx方法上,控制最多并發數
3) 可在web.xml配置全局參數設定poral執行器的線程池參數:portalExecutorCorePoolSize、portalExecutorMaxPoolSize、portalExecutorKeepAliveSeconds
參數意義分别參考java.util.concurrent.ThreadPoolExecutor的corePoolSize、maximumPoolSize、keepAliveTime說明
4) 在portal-home頁面中的$weather實際是一個net.paoding.rose.web.portal.Window對象,是以可通過$weather.success 判斷window的執行是否完成并且是200的,通過$weather.statusCode等了解具體的執行情況。詳細請參考net.paoding.rose.web.portal.Window類屬性清單。
5) 可在window的控制器TodoController.xxx方法中聲明Window window對象,通過window.setTilte(title)或window.set(name, value)相關屬性,并在portal-home.vm使用$todo.title 在todo.vm中,則除了使用todo的名字使用$todo.title,也可以通過$window.title來使用。每個$window在不同的視窗的頁面代表自己的Window對象,不會“亂串”
啟動後,通路http://[yourlocal]/[yourprojectname]/portal
可以看到 兩個div(這裡可以叫做window) 分别通過不同的controller 傳回資料。
想了解vm頁面用法請參考:
http://code.google.com/p/paoding-rose/wiki/Rose_Portal_Demo
此連結為paoding-rose的project home 裡面也有paoding-rose 其它方面的介紹
國人罕見的開源項目, 用着也很不錯。 祝願其團隊日益強大、此項目風靡國内外。
-----------------------
補充些東西:
portal 的真正意義在于, 在一個頁面上如果一個子產品down 掉,其它子產品還能正常使用。
如人人網的使用者個性首頁,“使用者評論” 子產品出現異常,在之前的伺服器架構上則會導緻整個頁面出現異常(因為是由一個controller處理的請求) 。 可能有人說 我用ajax。可以。但ajax是一個頁面的多個子產品同時向伺服器發了多個請求。為伺服器增壓。而且完全用js 控制頁面,也會出現很多不相容問題。
現在最好的解決方案問世:rose 的portal 整個請求由一個控制器來處理并由這個控制器分發給每個window 的控制器。這些大家都能了解。但關鍵點在于它的意義。 就在于 portal 的 home 方法的逾時配置:@PortalSetting(timeout = 100)
和 并發配置:
<context-param>
<param-name>portalExecutorCorePoolSize</param-name>
<param-value>200</param-value>
</context-param>
沒有逾時配置的話,一個視窗逾時,controller會永遠等待這個視窗,而不傳回頁面。 沒有并發配置的話 預設一個線程處理controller 的轉發 會導緻如果前面的window 挂掉,會一直在這個window處于等待狀态,而其後面的window也就不會處理。雖然傳回了頁面 但挂掉的window 後面的所有window 也不會顯示。
以上代碼為本人初次測試的代碼,後來又做了新一步測試,實作了逾時的視窗不顯示而其他視窗正常。
代碼不想再一點點上貼,直接發個包兒吧 見附件。 項目用maven 建構 java代碼和配置檔案分别放在src/main/java 和src/main/resources web檔案放在src/main/webapp 。 如果需要項目依賴的jar email我 : [email protected]