- 浏览: 61726 次
- 性别:
- 来自: 北京
最新评论
-
Hojave:
楼主,这种方式的中文资源应用应该怎么加呢?我在Portlet的 ...
Liferay中外部war方式整合portlet的处理流程 -
zxzheaven:
我通过
http://www.matrix.org.cn/th ...
Nutch中MapReduce的分析 -
952222:
我想问个问题,就是NUTCH在搜索具有交叉字的词语时,会有错误 ...
Nutch-0.9源代码:NutchConfiguration类 -
afadgaeg:
installComponents(init) 安装依赖 ...
jboss seam 中的 Component -
afadgaeg:
好文
jboss seam 中的 Component
本文介绍如何以外部war应用的方式向liferay portal集成portlet, 还是以sample-jsp-portlet为例来说明。
一,portlet如何被liferay portal调用?
在web-xml定义中,可以看到这样的一个servlet定义:
〈servlet〉
〈servlet-name〉sample_jsp_portlet〈/servlet-name〉
〈servlet-class〉com.liferay.portal.kernel.servlet.PortletServlet〈/servlet-class〉
〈init-param〉
〈param-name〉portlet-class〈/param-name〉
〈param-value〉com.sample.jsp.portlet.JSPPortlet〈/param-value〉
〈/init-param〉
〈load-on-startup〉0〈/load-on-startup〉
〈/servlet〉
〈servlet-mapping〉
〈servlet-name〉sample_jsp_portlet〈/servlet-name〉
〈url-pattern〉/sample_jsp_portlet/*〈/url-pattern〉
〈/servlet-mapping〉
在[Liferay中action的处理流程]一文中,分析了当portlet是一个war时,liferay portal将转发请求到war应用,代码如下:
CachePortlet
private void _invoke(
PortletRequest req, PortletResponse res, boolean action)
throws IOException, PortletException {
if (_portletConfig.isWARFile()) {
String path =
StringPool.SLASH + _portletConfig.getPortletName() + "/invoke";
RequestDispatcher rd =
_portletCtx.getServletContext().getRequestDispatcher(path);
// 一些初始化代码....
httpReq.setAttribute(WebKeys.JAVAX_PORTLET_PORTLET, _portlet);
rd.include(httpReq, httpRes);
}
else {
// 略...
}
}
在本文中portletName为sample_jsp_portlet,则path为/sample_jsp_portlet/invoke,这个url对应的servlet就是PortletServlet了,
这样liferay portlet就将请求转发到了sample-jsp-portlet应用。
这里要注意的是servlet-name与url-pattern的名称一定要保持一致!
// PortletServlet
public class PortletServlet extends HttpServlet {
public static final String JAVAX_PORTLET_PORTLET = "javax.portlet.portlet";
public static final String JAVAX_PORTLET_REQUEST = "javax.portlet.request";
public static final String JAVAX_PORTLET_RESPONSE = "javax.portlet.response";
public static final String PORTLET_CLASS_LOADER = "PORTLET_CLASS_LOADER";
public void service(HttpServletRequest req, HttpServletResponse res)
throws IOException, ServletException {
PortletRequest portletReq =
(PortletRequest)req.getAttribute(JAVAX_PORTLET_REQUEST);
PortletResponse portletRes =
(PortletResponse)req.getAttribute(JAVAX_PORTLET_RESPONSE);
Portlet portlet = (Portlet)req.getAttribute(JAVAX_PORTLET_PORTLET);
LiferayPortletSession portletSes =
(LiferayPortletSession)portletReq.getPortletSession();
portletSes.setHttpSession(req.getSession());
if (portletReq instanceof ActionRequest) {
ActionRequest actionReq = (ActionRequest)portletReq;
ActionResponse actionRes = (ActionResponse)portletRes;
portlet.processAction(actionReq, actionRes);
}
else {
RenderRequest renderReq = (RenderRequest)portletReq;
RenderResponse renderRes = (RenderResponse)portletRes;
portlet.render(renderReq, renderRes);
}
}
}
PortletServlet很简单,它根据PortletRequest的类型来决定是让portlet执行processAction还是render,
portlet由servlet定义的init-param参数指定,它必须继承自javax.portlet.GenericPortlet类, 这是jsr168规范所指定的,
本文中为com.sample.jsp.portlet.JSPPortlet。
// JSPPortlet.
public class JSPPortlet extends GenericPortlet {
public void init() throws PortletException {
editJSP = getInitParameter("edit-jsp");
helpJSP = getInitParameter("help-jsp");
viewJSP = getInitParameter("view-jsp");
}
public void doDispatch(RenderRequest req, RenderResponse res)
throws IOException, PortletException {
// 略...
}
public void doEdit(RenderRequest req, RenderResponse res)
throws IOException, PortletException {
// 略...
}
public void doHelp(RenderRequest req, RenderResponse res)
throws IOException, PortletException {
include(helpJSP, req, res);
}
public void doView(RenderRequest req, RenderResponse res)
throws IOException, PortletException {
include(viewJSP, req, res);
}
public void processAction(ActionRequest req, ActionResponse res)
throws IOException, PortletException {
}
protected void include(String path, RenderRequest req, RenderResponse res)
throws IOException, PortletException {
PortletRequestDispatcher prd =
getPortletContext().getRequestDispatcher(path);
if (prd == null) {
_log.error(path + " is not a valid include");
}
else {
prd.include(req, res);
}
}
}
这里一个很简单的portlet实现,它直接包含jsp文件。
二,portlet中的预定义对象.
portlet 页面上能使用的对象.
首先在portlet页面上加入如下tag定义,
<portlet:defineobjects></portlet:defineobjects>
DefineObjectsTag.doStartTag() {
ClassLoader contextClassLoader =
Thread.currentThread().getContextClassLoader();
try {
// 切换ClassLoader,对于采用War方式的portlet,这是必须的?
Thread.currentThread().setContextClassLoader(
PortalClassLoaderUtil.getClassLoader());
MethodWrapper methodWrapper = new MethodWrapper(
_TAG_CLASS, _TAG_DO_START_METHOD, new Object[] {pageContext});
MethodInvoker.invoke(methodWrapper);
}
catch (Exception e) {
throw new JspException(e);
}
finally {
Thread.currentThread().setContextClassLoader(contextClassLoader);
}
return SKIP_BODY;
}
private static final String _TAG_CLASS =
"com.liferay.portlet.DefineObjectsTagUtil";
private static final String _TAG_DO_START_METHOD = "doStartTag";
DefineObjectsTag.doStartTag(PageContext pageContext) {
ServletRequest req = pageContext.getRequest();
PortletConfigImpl portletConfig =
(PortletConfigImpl)req.getAttribute(WebKeys.JAVAX_PORTLET_CONFIG);
if (portletConfig != null) {
pageContext.setAttribute("portletConfig", portletConfig);
pageContext.setAttribute(
"portletName", portletConfig.getPortletName());
}
RenderRequest renderRequest =
(RenderRequest)req.getAttribute(WebKeys.JAVAX_PORTLET_REQUEST);
if (renderRequest != null) {
pageContext.setAttribute("renderRequest", renderRequest);
pageContext.setAttribute(
"portletPreferences", renderRequest.getPreferences());
pageContext.setAttribute(
"portletSession", renderRequest.getPortletSession());
}
RenderResponse renderResponse =
(RenderResponse)req.getAttribute(WebKeys.JAVAX_PORTLET_RESPONSE);
if (renderResponse != null) {
pageContext.setAttribute("renderResponse", renderResponse);
}
if (portletConfig.isWARFile() && ServerDetector.isWebLogic()) {
PortletSessionImpl portletSession =
(PortletSessionImpl)renderRequest.getPortletSession();
PortletSessionPool.put(
portletSession.getPortalSessionId(), pageContext.getSession());
}
}
从上面的代码可以看出,在portlet的页面上可以直接使用的对象有:
portletConfig // portlet配置.
portletName // portlet名称.
renderRequest // portlet request.
portletPreferences // portlet 首选项.
portletSession // portlet 会话.
renderResponse // portlet response.
三,portlets如何部署到liferay portal中?
在portlets应用的web.xml中加入如下listener定义:
<listener></listener>
<listener-class></listener-class>
com.liferay.portal.kernel.servlet.PortletContextListener
加入了此listener后,当portlets应用启动时,将会向liferay portal注册此应用中的所有定义的portlet;
当portlets应用停止时,会向liferay portal取消所有定义的portlet, portlet定义当然是由portlet.xml文件给出。
PortletContextListener实现了ServletContextListener接口.
public class PortletContextListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
HotDeployUtil.fireDeployEvent(
new HotDeployEvent(
sce.getServletContext(),
Thread.currentThread().getContextClassLoader()));
}
public void contextDestroyed(ServletContextEvent sce) {
HotDeployUtil.fireUndeployEvent(
new HotDeployEvent(
sce.getServletContext(),
Thread.currentThread().getContextClassLoader()));
}
}
上面的两个方法直接调用HotDeployUtil的fireDeployEvent和fireUndeployEvent方法,HotDeployUtil是Liferay portal的热部署工具类,
下面来着重看看fireDeployEvent是如何执行portlet注册的,
public class HotDeployUtil {
// 构造一个实例,singlton模式.
private static HotDeployUtil _instance = new HotDeployUtil();
// 触发部署事件,通知HotDeployListener进行部署。
private synchronized void _fireDeployEvent(HotDeployEvent event) {
// 当_events不为空时,说明liferay portal还没启动,此时只是简单的保存event.
if (_events != null) {
_events.add(event);
return;
}
Iterator itr = _listeners.iterator();
// 遍历HotDeployListener,通知它们进行部署.
while (itr.hasNext()) {
HotDeployListener listener = (HotDeployListener)itr.next();
try {
listener.invokeDeploy(event);
} catch (HotDeployException hde) {
_log.error(StackTraceUtil.getStackTrace(hde));
}
}
}
// 在liferay portal启动后被调用,此设计的目的主要用于解决portals应用在liferay portal应用之前启动的情况。
private synchronized void _flushEvents() {
for (int i = 0; i < _events.size(); i++) {
HotDeployEvent event = (HotDeployEvent)_events.get(i);
Iterator itr = _listeners.iterator();
while (itr.hasNext()) {
HotDeployListener listener = (HotDeployListener)itr.next();
try {
listener.invokeDeploy(event);
}
catch (HotDeployException hde) {
_log.error(StackTraceUtil.getStackTrace(hde));
}
}
}
_events = null;
}
// 注册HotDeployListener
private void _registerListener(HotDeployListener listener) {
_listeners.add(listener);
}
private List _listeners;
private List _events;
}
这里就有个问题了,HotDeployListener是在哪里加入进来的了?答案是在liferay portal的初始化时加入的。
// liferay portal初始化
public class MainServlet extends ActionServlet {
public void init() {
// 其它初始化处理......
try {
// 执行全局启动事件.
EventsProcessor.process(PropsUtil.getArray(
PropsUtil.GLOBAL_STARTUP_EVENTS), true);
// 执行应用程序启动事件.
EventsProcessor.process(PropsUtil.getArray(
PropsUtil.APPLICATION_STARTUP_EVENTS),
new String[] {_companyId});
}
catch (Exception e) {
_log.error(e);
}
PortalInstances.init(_companyId);
}
}
EventsProcessor是liferay portal中的事件处理器,liferay portal中定义了一系列的事件点,
像上面的APPLICATION_STARTUP_EVENTS,就是应用程序启动事件点.
通过配置文件,就可以将我们的自定义事件加入到这些事件点里去执行了。
关于EventProcessor更详细的内容,将用另外一篇文章来详细介绍,这里只需要知道有两个事件被触发了。
// 全局启动事件。
public class GlobalStartupAction extends SimpleAction {
public void run(String[] ids) throws ActionException {
// JCR 处理...
// Portal initable
PortalInitableUtil.flushInitables();
// Hot deploy
// 注册layoutTemplate监听器.
HotDeployUtil.registerListener(new HotDeployLayoutTemplateListener());
// 注册portlet监听器.
HotDeployUtil.registerListener(new HotDeployPortletListener());
// 注册theme监听器.
HotDeployUtil.registerListener(new HotDeployThemeListener());
// 清理所有事件.
HotDeployUtil.flushEvents();
// Auto deploy 自动部署处理.....
}
// 部署Portlets
public class HotDeployPortletListener implements HotDeployListener {
public void invokeDeploy(HotDeployEvent event) throws HotDeployException {
String servletContextName = null;
try {
// Servlet context
ServletContext ctx = event.getServletContext();
servletContextName = ctx.getServletContextName();
// Company ids
String[] companyIds = StringUtil.split(
ctx.getInitParameter("company_id"));
if ((companyIds.length == 1) && (companyIds[0].equals("*"))) {
companyIds = PortalInstances.getCompanyIds();
}
// Initialize portlets, 初始化portlets
String[] xmls = new String[] {
Http.URLtoString(ctx.getResource("/WEB-INF/portlet.xml")),
Http.URLtoString(ctx.getResource(
"/WEB-INF/liferay-portlet.xml")),
Http.URLtoString(ctx.getResource("/WEB-INF/web.xml"))
};
List portlets = PortletLocalServiceUtil.initWAR(
servletContextName, xmls);
// Class loader, 类装载器
ClassLoader portletClassLoader = event.getContextClassLoader();
ctx.setAttribute(
PortletServlet.PORTLET_CLASS_LOADER, portletClassLoader);
// portlet context wrapper, portlet上下文包装器.
boolean strutsBridges = false;
Iterator itr1 = portlets.iterator();
while (itr1.hasNext()) {
Portlet portlet = (Portlet)itr1.next();
// 构造portlet实例.
Class portletClass = portletClassLoader.loadClass(
portlet.getPortletClass());
javax.portlet.Portlet portletInstance =
(javax.portlet.Portlet)portletClass.newInstance();
// 检查是否struts桥接portlet.
if (ClassUtil.isSubclass(portletClass,
StrutsPortlet.class.getName())) {
strutsBridges = true;
}
// 构造lucene indexer实例.
Indexer indexerInstance = null;
if (Validator.isNotNull(portlet.getIndexerClass())) {
indexerInstance = (Indexer)portletClassLoader.loadClass(
portlet.getIndexerClass()).newInstance();
}
// 构造scheduler实例.
Scheduler schedulerInstance = null;
if (Validator.isNotNull(portlet.getSchedulerClass())) {
schedulerInstance = (Scheduler)portletClassLoader.loadClass(
portlet.getSchedulerClass()).newInstance();
}
// 验证preferences.
PreferencesValidator prefsValidator = null;
if (Validator.isNotNull(portlet.getPreferencesValidator())) {
prefsValidator =
(PreferencesValidator)portletClassLoader.loadClass(
portlet.getPreferencesValidator()).newInstance();
try {
if (GetterUtil.getBoolean(PropsUtil.get(
PropsUtil.PREFERENCE_VALIDATE_ON_STARTUP))) {
prefsValidator.validate(
PortletPreferencesSerializer.fromDefaultXML(
portlet.getDefaultPreferences()));
}
}
catch (Exception e1) {
_log.warn(
"Portlet with the name " + portlet.getPortletId() +
" does not have valid default preferences");
}
}
// 资源处理.
Map resourceBundles = null;
if (Validator.isNotNull(portlet.getResourceBundle())) {
resourceBundles = CollectionFactory.getHashMap();
Iterator itr2 = portlet.getSupportedLocales().iterator();
while (itr2.hasNext()) {
String supportedLocale = (String)itr2.next();
Locale locale = new Locale(supportedLocale);
try {
ResourceBundle resourceBundle =
ResourceBundle.getBundle(
portlet.getResourceBundle(), locale,
portletClassLoader);
resourceBundles.put(
locale.getLanguage(), resourceBundle);
}
catch (MissingResourceException mre) {
_log.warn(mre.getMessage());
}
}
}
// 定制用户特性。
Map customUserAttributes = CollectionFactory.getHashMap();
Iterator itr2 =
portlet.getCustomUserAttributes().entrySet().iterator();
while (itr2.hasNext()) {
Map.Entry entry = (Map.Entry)itr2.next();
String attrCustomClass = (String)entry.getValue();
customUserAttributes.put(
attrCustomClass,
portletClassLoader.loadClass(
attrCustomClass).newInstance());
}
PortletContextWrapper pcw = new PortletContextWrapper(
portlet.getPortletId(), ctx, portletInstance,
indexerInstance, schedulerInstance, prefsValidator,
resourceBundles, customUserAttributes);
PortletContextPool.put(portlet.getPortletId(), pcw);
}
// Struts bridges
if (strutsBridges) {
ctx.setAttribute(
ServletContextProvider.STRUTS_BRIDGES_CONTEXT_PROVIDER,
new LiferayServletContextProvider());
}
// Portlet display,portlet展示处理,显示在portlet添加面板上位置.
String xml = Http.URLtoString(ctx.getResource(
"/WEB-INF/liferay-display.xml"));
PortletCategory newPortletCategory =
PortletLocalServiceUtil.getWARDisplay(servletContextName, xml);
for (int i = 0; i < companyIds.length; i++) {
String companyId = companyIds[i];
PortletCategory portletCategory =
(PortletCategory)WebAppPool.get(
companyId, WebKeys.PORTLET_CATEGORY);
if (portletCategory != null) {
portletCategory.merge(newPortletCategory);
}
else {
_log.error(
"Unable to register portlet for company " + companyId +
" because it does not exist");
}
}
// Variables
_vars.put(
servletContextName, new ObjectValuePair(companyIds, portlets));
if (_log.isInfoEnabled()) {
_log.info(
"Portlets for " + servletContextName +
" registered successfully");
}
}
catch (Exception e2) {
throw new HotDeployException(
"Error registering portlets for " + servletContextName, e2);
}
}
}
关于layoutTemplates和theme的部署这里就不列出了,请自行参考源代码。
发表评论
-
liferay中的preferences处理
2006-12-29 17:22 4581<div> <script type=&qu ... -
liferay portlet配置文件介绍
2006-12-25 12:46 8663portlet.xml portlet定义描述文件,它描述p ... -
liferay中的图片处理
2006-12-22 09:12 3401一、图片显示 启动liferay或浏览liferay官方网站 ... -
liferay中portlet action的处理流程
2006-11-30 13:54 9004本文用一个实例来说明liferay中portlet actio ... -
liferay portlet处理流程之一
2006-11-24 12:56 3918// 初始化 portal.servlet.MainServ ...
相关推荐
在Liferay中,MVC Portlet是最常见的portlet类型,它通过分离业务逻辑(Model)、用户界面(View)和控制流程(Controller)来实现代码的清晰组织。开发者可以使用Java Servlet和JSP来编写MVC Portlets,它们在...
Liferay Portal是一款开源的企业级门户系统,它允许用户创建、管理和集成各种Web应用程序,而portlet就是这些应用的基本构建块。下面将详细阐述Liferay Portlet开发的相关知识点。 1. **Liferay Portal简介** ...
Liferay Portlet SDK 5.2.3是该系列的一个特定版本,专为Liferay Portal 5.2.3版本设计,它包含了开发portlet所需的类库、文档和示例代码,使得开发者能够高效地集成自定义功能到Liferay Portal环境中。 **portlet...
在Liferay Portal中,Portlet是可重用的Web组件,用于展示动态内容和服务。随着时间的推移,项目中可能会积累许多不再使用的Portlet代码,这不仅会占用服务器资源,还可能影响系统的性能和维护效率。因此,定期清理...
通过深入学习和理解这个项目,开发者可以掌握如何在Liferay中创建和部署Spring Portlet,了解portlet的生命周期和交互方式,以及Spring框架在portlet开发中的应用。同时,如果进一步集成Hibernate,还可以学习到如何...
通过上述步骤,我们可以了解到在Liferay环境中使用Struts2开发Portlet的具体流程。整个过程涉及了开发环境的搭建、项目创建、Portlet类的编写以及Struts配置文件的设置等多个环节。这些步骤不仅为初学者提供了清晰的...
Portlet是Liferay中的核心组件,是构建门户应用程序的基本模块。这篇博文将深入探讨如何在Liferay中创建一个简单的Portlet,帮助开发者更好地理解Liferay的开发过程。 首先,让我们了解Portlet的基本概念。Portlet...
在Liferay中,跨页面Portlet之间的调用与数据传递是一项关键任务,因为这涉及到不同Portlet间的协作和信息共享。Liferay提供了多种通信机制,包括PortletSession、Public Render Parameters以及Portlet事件,但这些...
在IT领域,特别是企业级应用开发中,Liferay作为一个强大的企业门户平台,提供了丰富的功能和服务,其中Liferay Portlet的开发是构建定制化企业应用的关键技术之一。本文将基于提供的文件信息,深入解析Liferay ...
通过这个实例,开发者可以深入理解Liferay与Struts的集成方式,以及如何在实际项目中应用这种整合,提高开发效率和系统稳定性。对于初学者,这是一个很好的起点,可以从中学习到portlet开发、MVC设计模式以及企业级...
Liferay Spring Portlet MVC 使用 Maven 的 Liferay Spring Portlet MVC 项目模板。 Liferay EE 6.2.10.11 (GA1, SP... $ cp target/liferay-spring-mvc-portlet.war $LIFERAY_HOME/deploy/ 配置 默认设置为 Liferay
liferay portlet例子 liferay portlet例子
总的来说,portlet开发涉及了Java Web技术、portlet规范和特定的开发工具,而将portlet整合到Tomcat中则需要对服务器配置和部署流程有深入理解。通过学习和实践,开发者可以创建出高效、灵活的企业级portlet应用。
Portlet 技术的理解和应用是开发 Liferay 应用程序的关键。本文将深入解析 Portlet 的关键概念,包括 Portlet 请求与 URL、Portlet 模式和窗口状态。 1. Portlet 请求与 URL 在 Liferay 的 Portal 页面中,多个 ...
4. **工作流程整合**:利用Alfresco的工作流程引擎,可以为Liferay中的portlet定义和执行复杂的业务流程,提高工作效率。 为了实现这样的整合,我们需要进行以下步骤: 1. **配置CAS服务器**:首先,要在CAS服务器...
"Liferay Portlet Demo"是一个示例项目,旨在展示如何在Liferay环境中开发、部署和使用portlet。这个项目通常包含一系列的源代码、配置文件以及必要的资源,用于帮助开发者理解和实践portlet开发。 【描述】:...
Liferay5.2.3的样例,通过war.bat打包后发布到相应的liferay环境即可。 另外,需要配置context,tomcat中的代码如下: </Context>
在Liferay中,Portlet是一种用于显示内容和服务的应用程序组件,它是门户应用程序的核心部分。本文档旨在详细介绍如何通过插件(plugin)方式开发Liferay Portlet。 #### 二、开发模式的选择 Liferay提供了两种主要...
《Liferay Portlet 开发——全面指南》:深入解析与实战技巧 ...通过理论结合实践的方式,本书将带领读者深入了解Liferay平台,掌握portlet开发的全过程,为成为优秀的Liferay开发者打下坚实的基础。
liferay-display.xml文件用来定义portlet在Liferay控制台中的分类,以及在页面布局中的显示方式。这有助于用户管理和组织他们的portlet,同时控制用户的访问权限。 Liferay在其基础上扩展了Portlet模式,除了标准的...