`
hu437
  • 浏览: 194412 次
  • 性别: Icon_minigender_1
  • 来自: 昆明
社区版块
存档分类
最新评论

Liferay Portal 6学习笔记1:Portal介绍

阅读更多

LifeRay Portal 6于7月15日正式发布了,从今天起在这里写下自己的LifeRay Portal学习笔记

 

Liferay是一个开源的Portal产品,提供对多个独立系统的内容集成,为企业信息、流程等的整合提供了一套完整的解决方案,和其他商业产品相比,Liferay有着很多优良的特性(但是缺点也很明显,文档太少,学习成本有点高),而且免费,对于Liferay portal的详细介绍可以看其官网:http://www.liferay.com/zh/products/liferay-portal,本文主要介绍Portal和Portlet。

portal 规范

随着Portal的兴起,有众多的厂商开始涉足Portal产品开发,并构建自己的Portal组件和基于他的产品,比如IBM、ORACLE、Microsoft、apache、SAP等,但是各个产品之间互不兼容,给开发者和各个厂商带来了诸多不便。

JSR168

在这种情况下,JSR168规范应运而生,2003年10月7日,JCP组织发布了JSR168(Java Specification Request),Portlet Specification V1.0,用来提供不同的Portal和Portlet之间的互通性。只要开发的Portlet遵循JSR168,就可以在所有遵循JSR168的Portal上部署运行。JSR168中定义了Portal的实现规范和接口,并对理想的Portlet进行了详细规划和描述。

WSRP

wsrp是OASIS Web Service For Remote Rortlet的缩写。WSRP是Web Service的一种新的商业应用,一种新的标准,主要用来简化portal对于各种资源或程序整合的复杂度,可以避免编程带来的整合麻烦和问题。而且Portal管理员可以从海量的WSRP服务中选择需要的功能用以整合到目前所有的Portal中。它有三种角色:

 

①、     生产者   ==》  提供Portlet

②、     消费者   ==》  使用Portlet

③、     终端用户 ==》  最终用户

 

它的特点在于生产者将消费者所需要的信息通过WSRP 返回给消费者,这些信息是相对标记片断,例如HTMLXHTML 等,可以直接嵌入用户的页面中,而不用像Web Service一样开发用户端接口。

实现这个规范,Portal 可以跟各式各样的数据源打交道,彻底终结信息孤岛的窘境。

 

什么是Portal

Portal服务器

 

Portal 服务器是容纳Portlet 容器,支持Portlet 呈现的普通或者特殊Web 服务器。Portal 服务器通常会提供个性化设置、单点登录、内容聚合、信息发布、权限管理等功能,支持各种信息数据来源,并将这些数据信息放在网页中组合而成,提供个性化的内容定制,不同权限的浏览者能够浏览不同的信息内容。通常,Portal 提供以下功能:

 

单点登录:Portal 通常采用ACL、SSL、LDAP 等业界标准的安全技术,提供对所有现有应用系统的安全集成,只需在Portal 的唯一入口上登录一次,就可以访问所有应用系统和数据。对于安全性要求较高的应用系统,如电子商务平台、交易系统等,通过扩展接口传递用户身份信息,如数字证书信息、数字签名信息等,进行二次身份认证,保证单点登陆的安全性。

 

权限控制:系统采用LDAP 对用户资源进行统一的管理,同时提供二次开发接口,可以与其他应用系统的用户管理模块对接,并能随相关业务系统实时更新访问权限。通过完善的授权机制及存取控制,用户访问权限控制到字段级别,确保用户只能访问具有权限的应用系统及相关信息。

 

内容管理: 实现应用系统之间实时交换信息。采用多种缓存机制,保证内容交换的性能和准确性。采用基于XML 的Rich Site Summary (RSS)标准,迅速在各应用系统之间传播最新变化。

 

信息发布: 实现信息门户内容的动态维护。动态网站系统可与OA 协同办公系统、知识管理系统等集成,网站信息须经OA 系统的审批流程流转通过后或知识管理平台设置具有外部共享权限后才可正式发布,真正实现内外信息发布的同步。

文件管理: 系统实现无缝集成多种数据源,包括:数据库、文档(Office 文档、PDF、AutoCAD、甚至ZIP 文档)、Web 网页、FTP 站点等,并对数据按业务要求和职务特点加以分析整理,通过统一Web 界面主动推送(Push)至用户的门户桌面,帮助用户做出及时、正确的决策。

portlet容器

Portlet 容器提供Portlet 执行的环境,包含很多Portlet 并管理它们的生命周期,保存Portlet 的定制信息。
一个Portal 容器接收到来自Portal 的请求后,接着将这个请求传递给存在Portal 容器的Portlet 执行。Portlet 容器没有义务去组合Portlet 产生的信息內容,这个工作必须由Portal 来处理。Portal 和 Portal 容器可以放在一起视为同一个系统的组件,或者分开成为两个独立的组件。
Portlet 容器是普通Web Servlet 容器的扩展,所以一个Portlet 容器可以构建于一个已经存在的Servlet 容器或者可能实现全部Web Servlet 容器的全部功能。无论Portlet容器怎么实现,它的运行环境总是假定它支持Servlet2.3 规范。通常,Portlet 容器扩展自普通的Servlet 容器。

什么是Portlet

Portlet 是Portal 中最重要的组件,负责在Portal 中呈现信息内容,有相应的生命周期。通过自定义Portlet,用户很容易定义个性化的Portal 页面。Portlet 由Portlet 容器负责管理、处理请求并返回动态页面,可以作为Portal 的可即插即用的界面组件。

Portlet

一个Portlet是以Java技术为技术的Web组件,由Portlet容器所管理,专门处理客户的信息请求以及产生各种动态的信息内容。Portlet 为可插式的客户界面组件,提供呈现层成为一个信息系统。

 

这些由Portlet产生的内容也被称为片段,而片段是具有一些规则的标记( HTML、XHTML、WML ),而且可以和其他的片段组合而成一个复杂的文件。一个或多个 Portlet 的内容聚合而成为一个 Portal 网页。而 Portlet 的生命周期是被 Portlet 容器所管理控制的。

 

客户端和Portlet的互动是由Portal通过典型的请求/响应方式实现,正常来说,客户会和Portlet所产生的内容互动,举例来说,根据下一步的连接或者是确认送出的表单,结果Portal将会接收到Portlet的动作,将这个处理状况转向到目标Portlet。这些Portlet 内容的产生可能会因为不同的使用者而有不同的变化,完全是根据客户对于这个Portlet的设置。

Portlet 与Servlet 的关系

Portlet 被定义成为一个新的组件,具有新的明确的界面与行为。为了尽可能与现有的Servlet 结合达到重复使用的目的,Portlet 的规范利用了 Servlet 的规范,许多观念都很相似的,结合 PortletServlet Jsp 在同一个网站系统中,我们称为Portlet 应用 。在同一个 Portlet 应用 中,他们将分享同一个类加载器(ClassLoader),上下文(Context) Session

①、     Portlet Servlet 的相似之处

Ø  Portlet 也是 Java 技术的 web 组件

Ø  Portlet 也是有特定的 container 在管理

Ø  Portlet 可以动态产生各种内容

Ø  Portlet 的生命周期由 container 所管理

Ø  Portlet 和客户端的互动是通过 request/response 的机制

 

②、     Portlet Servlet 也有一些不同

Ø  Portlet 只产生 markup 信息片段,不是完整的网页文件。而 Portal 会将所有的Portlet markup 信息片段放到一个完整的 Portal 网页。

Ø  Portlet 不会和 URL 有直接的关系客户端必须通过 portal 系统才能和 Portlet 互动

Ø  Portlet 有一些定义好的 request 处理,action request 以及 render request

Ø  Portlet 默认定义 Portlet modes 及窗口状态可以指出在网页中该 Portlet 的哪个功能正在执行及现在的 状态。

Ø  Portlet 可以在同一个 portal 网页之中存在多个。

 

③、     Portlet 有一些附加的功能是 Servlet 所没有的

Ø  Portlet 能够存取及储存永久配置文件及定制资料。

Ø  Portlet 可以存取使用者数据

Ø  Portlet 具有 URL 的重写功能在文件中去动态建立连结,允许 portal server 不用去知道如何在网页的片 段之中建立连结及动作。

Ø  Portlet 可以储存临时性的数据在 Portlet session 之中,拥有两个不同的范围 :application-wide scope Portlet private scope

④、     Portlet 不具有一些功能, 但是 Servlet 却有提供

Ø  Servlet 具有设置输出的文字编码( character set encoding)方式

Ø  Servlet 可以设置 HTTP 输出的 header

Ø  Servlet 才能够接收客户对于 portal 发出的 URL 请求

Portlet 的生命周期

一个Portlet有着良好的生命周期管理,定义了怎样装载,实例化和初始化,怎样响应来自客户端的请求及怎样送出服务。这个Portlet生命周期由Portlet接口的init,processAction,render和destroy方法来表达。

 

载入和实例化:Portlet 容器负责载入和实例化Portlet。当Portlet 容器运行Portlet 应用或者延迟到Portlet 需要服务使用者的请求时,Portlet 就会被载入并实例化。载入Portlet 类后,Portlet 类随即被实例化。

 

初始化:Portlet 类实例化后,Portlet 容器还需要初始化Portlet。以调用Portlet 去响应客户端的请求。Portlet 容器呼叫Portlet 接口中的init 方法初始化Portlet。扩展自PortletConfig的类可以取出定义在部署描述文件中的初始化参数,以及Resource Bundle。

 

初始化异常:在 Portlet 初始化期间,Portlet 可能会丟出 UnavailableException 或PortletException 异常。此时,Portlet 容器不能把 Portlet 置入已启动的服务,并且 Portlet容器必需释放这个 Portlet。 destory 方法不能被呼叫,因为初始化被认为执行失败。发生 失败后,Portlet 容器会尝试着重新实例化及初始化 Portlet。这个异常处理的规则是:由一个UnavailableException 指定一个不能执行的最小时间,当此异常发生时,Portlet 容器必需等到指定时间过去后才产生并且初始化一个新的 Portlet。

在初始化过程中所丟出的 Runtime Exception 异常,被当作 PortletException 来处理。

Portlet标签

Servlet 一样,Portlet 也自定义了很多灵活的标签。通过这些标签,可以调用Portlet内部的参数比如renderResponserenderRequestPortletConfig 等,在JSP 中跟Portlet 通信。当然,在使用之前,除了要在web.xml 中声明标签库外,还要在JSP 的头部声明标签库调用:

 

<%@ taglib uri="http://java.sun.com/portlet" prefix="portlet" %>

defineObjects 标签


在使用Portlet 典型标签之前,要见声明<portlet:defineObjects/>,这样才可以使用其他的标签。defineObjects 中间不允许定义任何属性和包含任何内容。 

renderURL 标签

属性

值类型

对应值

windowState

String

minimized

normal

maximized

portletMode

String

view

edit

help

var

String

 

secure

String

true

false

 

<portlet:renderURL portletMode="view" windowState="maximized">
<portlet:param name="number" value="1"/>
<portlet:param name="page" value="2"/>
</portlet:renderURL>

 

 创建一个当前RenderURL,当访问它时将使Portlet 窗口变为最大化状态,模式变为浏览。<portlet:param/>子元素会在生成的RenderURL 中增加numberpage 两个参数和值。

actionURL 标签

属性

值类型

对应值

windowState

String

minimized

normal

maximized

portletMode

String

view

edit

help

var

String

 

secure

String

true

false


<portlet:actionURL windowState="normal" PortletMode="edit">
<portlet:param name="action" value="login"/>
</portlet:actionURL>

创建一个当前ActionURL,当访问它时将使Portlet 窗口变为正常状态,模式变为编辑。<Portlet:param/>子元素会在生成的ActionURL 中增加action 参数和值。renderURL actionURL 两个标签在诸如生成form 表单的action 等方面特别有用。  

param 标签

 

属性

值类型

name

String

用在renderURL actionURL 标签内部,用来在生成的URL 中增加参数和值。param标签不运行body 内容存在。

namespace标签

为目前的Portlet 产生一个唯一的Value,防止与其他Portlet 或者Portal 上面的Value 冲突。上述标签的具体属性及其约束, 请参阅${CATALINA_HOME}/liferay/WEB-INF/tld/liferay-portlet.tld

Portal 的对象

JSR168 给Portal 定义了几个特别的对象,用来操作Portal 特有的信息。这些对象跟Servlet的对象有点类似, 又有点不同。这些对象都封装在${CATALINA_HOME}/common/lib/ext/portlet.jar 包中,具体支持实现要视Portal 服务器而定。

Request 对象

Portlet 中的Request 与Servlet 的Request 一样接受客户端发送的请求,但是与Servlet不同,Portlet 的Request 分为Action Request 及Render Request 两种类型,因此Portlet 接口中定义了两种方法用来处理不同的Request。分别是processAction(ActionRequest request,ActionResponse response) 和render(RenderRequest request,RenderResponse response),分别用以处理Action Request 和Render Request。某种意义上来讲,render 方法类似Servlet 中的service 方法,doView,doEdit,doHelp 方法又类似doGet,doPost 方法。

 

①、    RenderRequest ActionRequest

 

PortletRequest 分为RenderRequest ActionRequest 两种,分别由renderURL actionURL来触发。renderURL actionURL 的一种优化。Portlet 的开发过程中尽量使用renderURL 而避免actionURLactionURL 适用于有确实的Action(行为)的情况下。比如说,表单form提交后Persistent 状态的改变、session 的改变、perference 的修改等等。renderURL 通常用来处理Portlet 的导航。举个例子:

使用actionURL

 

<%
PortletURL pu = renderResponse.createActionURL();
pu.setParameter("ACTION","LOGIN");
<form name="usrform" method="post" action="<%=pu.toString()%>">
%>

 

说明:表单提交最好使用Post 方法而不是Get 方法,因为某些Portal 服务器可能会将内部状态编码到URLQuery 字符串中。使用renderURL:  

 

<%
PortletURL pu=renderResponse.createRenderURL();
Pu.setParameter("PAGE",Number);
%>
<a href="<%=pu%>">下一页</a>

②、     renderURL actionURL 的处理方式

当客户端请求是由一个renderURL 触发的时候,Portal 服务器会调用该Portal 页面所有Portlet render 方法。

而当客户端请求是由一个actionURL 触发的时候,Portal 服务器会先按用该页面所有Portlet processAction方法再调用render 方法。所以,要明确自己到底使用那种URL 来出发客户端请求。

 

③、    RenderRequest ActionRequest parameter 参数作用范围

 

当客户端请求由一个actionRequest 触发时,所有parameter 参数的取得都必须在processAction方法中进行。比如:

 

public void processAction(ActionRequest req,ActionResponse res){
String str = req.getParameter("ACTION");
//response.setRenderParameter("ACTION",action);
}
public void doView(ActionRequest req,ActionResponse res){
String str = req.getParameter("ACTION");
} 

  如上processAction 方法中,getParameter 方法将能成功得到表单中的参数ACTION 所对应的值,因为我们知道,当目标Portlet processAction 方法运行完后,Portlet Container 将调用Portal 页面中所有Portlet render方法.但是实际上doView 方法中使用getParameter不会得到任何值.但是如果把processAction 方法中注释了的一行解除注释的话,你就可以在doView 方法中的得到参数ACTION 对应的值. 这说明action request 的参数,render方法中不可以直接取到.必须使用了setRenderParameter 方法,再次传递一次. 

Response 对象

与Request 对象一样,Response 对象也有两种:RenderResponse 和ActionResponse,分别用来封装对应的RenderRequest 和ActionRequest 的返回信息,比如重定向、窗口状态、Portlet 模式等。他们两者的父类PortletResponse 拥有serPorperty 和getPorperty 两个方法,用来递信息给Portal 容器。

 

ActionResponse 主要用来处理以下功能:

a)   重定向

b)  改变窗口状态、Portlet 模式

c)  传递parameter 参数到RenderRequest 中去RenderResponse 主要用来提供以下功能:

d)  设置ContentType

e)  得到OutputStream 和Writer 对象,用来输出页面内容

f)   Buffering 缓冲

g)  设定Portlet 的标题,但是必须在Portlet 输出前调用,否则将被忽略

PortletConfig 对象

和ServletConfig 对象类似, PortletConfig 对象提供对Portlet 初始化信息以及PortletContext 对象存取的方法。

和ServletConfig 对象不同的是,PortletConfig 对象提供对Portlet 的标题等资源的I18N支持,可以通过设定不同的Resource Bundle 文件以提供多种语言支持。

Session 对象

由于容器不同,Portal 的Session 对象与Servlet 的Session 对象略有不同。由于Portlet 处于Portal 服务器的缘故,Portlet 的Session 分为Application Scope 和PortletScope。

 

两者的区别在于:

 

①、    Application Scope 范围的Session 中保存的对象,对于同一个Portlet 应用范围内的所有Portlet 都是可用的。

②、     Portlet Scope 范围的Session 中保存的对象,只对本Portlet 可用,其他Portlet 即使在同一个应用中,也不可用。

但是对于Portlet 应用来说,可以通过HttpSession 来访问。毕竟Portlet 应用也是Web应用。在使用Session 对象的时候,最好能明确指出使用的是那个Scope 范围的Session。比如:

 

<portlet:actionURL windowState="NORMAL" portletMode="view" var="pu1">
<portlet:param name="ACTION" value="ApplicationScope"/>
</portlet:actionURL>
<portlet:actionURL windowState="NORMAL" portletMode="view" var="pu2">
<portlet:param name="ACTION" value="PortletScope"/>
</portlet:actionURL>

 这个JSP 创建了两个ActionURL,分别产生了两种PortletSession 对象。

 

PortletSession ps = req.getPortletSession();
if(ps.getAttribute("PortletSession.AS",PortletSession.APPLICATION_SCOPE)!=null){
app=ps.getAttribute("PortletSession.AS",PortletSession.APPLICATION_SCOPE).
toString();
}
if(ps.getAttribute("PortletSession.PS",PortletSession.PORTLET_SCOPE)!=null){
portlet=ps.getAttribute("PortletSession.PS",PortletSession.PORTLET_SCOPE).
toString();
}

 以上代码根据需要取得不同Scope 范围的Session 对象值。同一个应用下,可以直接通过ServletSession 取得

 

PortletSession.APPLICATION_SCOPE范围下的Session 对象值。
HttpSession se = request.getSession();
if(se.getAttribute("PortletSession.AS")!=null){
app=se.getAttribute("PortletSession.AS");
}

Preference 对象

Preference 对象被设计用来实现用户的个性化设置,可以帮助用户对Portlet 进行符合用户需求的显示定制和行为定制,可以替代部分的数据库功能。需要指出的是,Preference 对象只是用来存取简单的配置信息,并不能完全替代数据库应用。

Preference 对象对于配置信息采用键-值的形式存取,用户可以将需要的信息暂时保存在Preference 中。

 

PortletPreference p= req.getPortletPreferences();
p.setValue("educhina.username","educhina");
p.store();
 

Preference 对象用来存取用户的个性化信息,所以不同用户的Preference 

对象不能共享,这点跟Session 不同。可以在Portlet.xml 中配置Preference 信息,如下:

 

<portlet-preferences>
<preference>
<name>educhina.username</name>
<value>educhina</value>
<read-only>true</read-only>
</preference>
</portlet-preferences>
 

另外,还可以配套使用PreferencesValidator 对象,对Portlet 的Preference 在存储之前进行验证,以确保Preference 的正确性。具体规范可以参照http://java.sun.com/xml/ns/Portlet/Portlet-app_1_0.xsd 的<complexTypename="preferenceType">部分。


PS:下一章介绍Liferay 6.03的开发环境配置和安装以及LiferayIDE的安装使用
分享到:
评论

相关推荐

    Liferay_Portal_6学习之路-学习笔记完整版

    ### Liferay Portal 6 学习之路:全面解析与实践指南 #### 一、Portal与Liferay Portal简介 ##### Portal概念 Portal,即门户网站,...希望本篇学习笔记能够帮助大家更好地理解和掌握 Liferay Portal 6 的相关知识。

    荷露叮咚Liferay Portal 6学习笔记完整版.

    1. Portal介绍: - Liferay Portal是一个开源的企业级Portal产品,其主要功能是集成了多个独立系统的相关内容,为企业信息、流程等的整合提供了一套解决方案。与其他商业产品相比,Liferay具有成本低、开源等特点,...

    liferay Portal 的学习书籍

    6. **作者介绍**:Dr. Jonas X. Yuan是这本书的主要作者,担任着CIGNEX公司的高级技术分析师,并且拥有计算机科学的博士学位。作者的背景为本书内容的专业性提供了保障。 7. **Liferay版本信息**:提到了Liferay ...

    liferay portal 6 使用文档

    #### 一、Liferay Portal 6:企业级门户解决方案 Liferay Portal 6是一款先进的企业级门户平台,旨在帮助企业构建和维护高效、安全、用户友好的内部网(Intranets)。它不仅提供了丰富的功能模块,如文档管理、工作...

    liferay portal开发大全

    1. **Liferay Portal 架构** Liferay Portal的核心架构基于Java EE标准,包括Servlet容器、EJB、JMS和JPA等。它采用MVC(模型-视图-控制器)设计模式,提供了一个可扩展的框架,支持portlet、主题、布局和服务的...

    liferay portal 开发指南

    ### Liferay Portal 开发指南知识点概述 ...通过学习本文档,开发者不仅可以掌握 Portlet 的开发技巧,还能深入了解 Liferay Portal 的架构和技术特点,从而更好地利用该平台来满足企业的业务需求。

    liferay portal 开发实例

    Liferay Portal是一款开源的企业级门户平台,用于构建和管理复杂的企业级Web应用程序。在这个开发实例中,我们将深入探讨四个Liferay Portal MVC(Model-View-Controller)应用的实践案例,这些实例可以帮助开发者更...

    Liferay Portal 6 Enterprise Intranets

    ### Liferay Portal 6 Enterprise Intranets:构建与维护企业级内部网 #### Liferay Portal 6概述 Liferay Portal 6是一款强大的企业级门户平台,它为组织提供了构建、管理和扩展内部网的能力。该平台支持多种应用...

    (英文版)liferay portal 6 企业网络版(Liferay Portal 6 Enterprise Intranets.pdf)

    《Liferay Portal 6 企业内网》一书详尽地介绍了如何利用Liferay Portal 6构建和维护高效的企业内部网络。Liferay Portal是一款开源的企业级应用平台,它集成了内容管理、工作流、社区工具等多种功能,为组织提供了...

    Liferay Portal Systems Development

    总之,《Liferay Portal Systems Development》是一本深入介绍Liferay门户系统开发的专业书籍。它不仅提供了理论知识,还包含了实用的开发技巧,对于想要构建企业级门户和Web应用的开发者来说,是一本宝贵的参考资料...

    Liferay_Portal_6[1].1源码部署

    《Liferay Portal 6.1.1源码部署在Eclipse中的详细步骤》 Liferay Portal是一款开源的企业级门户平台,具有高度可定制性。...1. **Bundled with Tomcat**: 这是包含了Tomcat服务器的Liferay Portal,下载地址为...

    Liferay Portal文档

    《Liferay Portal文档》是一份详尽的指南,主要介绍了Liferay Portal的架构、工作原理及其核心组件——Portlet。Liferay Portal是一款开源的企业级门户平台,它提供了丰富的功能,如内容管理、社交网络、协作工具等...

    Liferay Portal 数据库介绍

    Liferay Portal 数据库介绍 Liferay Portal 数据库是指Liferay Portal系统中存储的所有数据,包括用户信息、组织结构、页面布局、portlet配置等。下面将从数据库的角度来介绍Liferay Portal 的页面布局和相关知识点...

    LifeRay_Portal6.0.6学习手册

    《LifeRay Portal 6.0.6 学习手册》是一份针对LifeRay Portal初学者的详细教程,旨在帮助读者深入了解和掌握LifeRay Portal的使用和开发。下面将对其中的关键知识点进行深入探讨。 1. **LifeRay Portal初体验** ...

    liferay portal介绍

    关于liferay portal介绍的ppt

    搭建liferay portal的开发环境.doc

    1. **下载所需文件**:包括JDK 1.5.0.06版本、Liferay Portal与Tomcat组合包、Liferay Portal源码包以及Liferay Portal SQL脚本包。 2. **安装JDK**:确保计算机上已安装Java Development Kit (JDK) 1.5.0.06版本,...

    liferay-portal-sql-6.1.1-ce-ga2-20120731132656558

    1. **安装脚本**:通常在安装或更新Liferay Portal时,会有一系列的SQL脚本用于创建必要的数据库结构,包括表、视图、存储过程等。 2. **升级脚本**:随着Liferay版本的升级,这些脚本可能用于将现有数据库从一个...

    Using Liferay Portal 6.1

    Using Liferay Portal 6.1

    Liferay Portal 内容管理

    【Liferay Portal 内容管理】是企业级门户平台Liferay Portal的重要组成部分,它提供了丰富的文档管理和信息发布功能,便于组织内部的信息共享与协作。 在Liferay Portal中,文档管理主要通过【Document Library】...

Global site tag (gtag.js) - Google Analytics