“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";
}
}
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>
代码不想再一点点上贴,直接发个包儿吧 见附件。