人人網 paoding 旗下 rose 項目實現服務器端 portal

“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" 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].
發佈了49 篇原創文章 · 獲贊 0 · 訪問量 5634
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章