Liferay-6-x-门户企业内部网络秘籍-全-

Liferay 6.x 门户企业内部网络秘籍(全)

原文:zh.annas-archive.org/md5/6ac18c5800f09361a0512e334a144b5f

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

Liferay Portal 是市场上最受欢迎的门户框架之一,提供了许多开箱即用的功能来构建、安装、配置和定制门户或内部网解决方案。本书的主要目的是通过提供逐步的食谱来帮助您成功构建内部网系统。您将经历一个涵盖处理 Liferay 时最常见问题的旅程。在每一个食谱中,您都会找到许多解释的针对现实生活问题的解决方案。章节的组织和顺序旨在帮助您逐步完成内部网配置。

本书涵盖内容

第一章,安装和基本配置,为您提供了如何在 Apache Tomcat 上安装和运行 Liferay 的基本知识。它还教授您如何创建一个新的基本 portlet。

第二章,认证和注册流程,描述了正确配置认证的几种有用方法。它帮助您了解与流行的单点登录机制 CAS 的集成,以及如何与 LDAP 进行通信。

第三章,与 Liferay 用户/用户组/组织协同工作,向您介绍了 Liferay 中用户、用户组和组织管理的概念。它还解释了如何将它们一起使用。

第四章,Liferay 站点配置,提供了许多与站点配置相关的有用食谱,例如创建站点、它们的模板以及启用预发布和版本控制。

第五章,角色和权限,讨论了角色和权限以及根据用户在公司中的职位构建可扩展的角色网格的可能性。

第六章,Liferay 中的文档和媒体,向您介绍了一个提供媒体和文档文件存储的 portlet。本章还提供了如何正确配置它的建议。您还将学习如何将文档和媒体 portlet 与 Amazon S3 存储集成。

第七章,与内容协同工作,讨论了最常用的 CMS 功能,即网络内容管理。

第八章,搜索和内容展示工具,介绍了与搜索和内容展示工具相关的各种功能。本章还讨论了资产标记和分类。

第九章,Liferay 工作流功能,教你如何将工作流应用于资产并部署 Kaleo Web 插件。

第十章,协作工具,提供了与 Wiki、博客、论坛、日历等协作的食谱。

第十一章,快速技巧和高级知识,包含一系列各种食谱,帮助你为你的内部网站执行特定任务。有许多主题,例如启用 SMTP、配置集群环境或使用 Liferay 服务总线。

第十二章,基本性能调优,提供了关于可扩展基础设施的信息,并讨论了与性能相关的大部分常见问题。

你需要为这本书准备什么

本书使用 Liferay Portal 版本 6.2,以下是一些设置:

  • MySQL 数据库 5.5

  • Java JRE 和 JDK 7

  • Apache Ant 1.7 版本或更高版本

  • Apache Maven 3.0.5 或更高版本

  • 与 Tomcat 7 捆绑的 Liferay Portal 6.2

  • Eclipse IDE Indigo 或更高版本

所有食谱都是基于 Linux 操作系统,但它们都可以在 Windows 或 iOS 上完成(只需稍加努力)。

本书面向对象

如果你是一位具有技术背景的 Java 开发人员或管理员,并希望将 Liferay Portal 作为企业内部网进行安装和配置,这本书就是为你准备的。简而言之,可重用的食谱可以帮助你将业务目标实现为 Liferay 中的工作功能。这本书还将为你提供有关如何轻松改进系统默认功能及其性能的有用提示。

部分

在本书中,你会发现几个经常出现的标题(准备工作、如何做、如何工作、更多内容、参见)。

为了清楚地说明如何完成食谱,我们使用以下部分如下:

准备工作

本节将告诉你在食谱中可以期待什么,并描述如何设置任何软件或任何为食谱所需的初步设置。

如何做...

本节包含遵循食谱所需的步骤。

如何工作...

本节通常包含对上一节发生情况的详细解释。

更多内容...

本节包含有关食谱的附加信息,以便使读者对食谱有更多的了解。

参见

本节提供了对其他有用信息的链接,这些信息对食谱很有帮助。

惯例

在本书中,你会发现许多经常出现的标题(准备工作、如何做、如何工作、更多内容、参见),以下是一些这些样式的示例及其含义的解释。

文本中的代码单词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 昵称将如下所示:“我们可以通过使用include指令来包含其他上下文。”

代码块将如下所示:

    <div>$curEntry.getTitle($locale)</div>
    <div>$curEntry.getDescription($locale)</div>
    <div>
      $taglibLiferay.assetTagsSummary(
        $curEntry.getClassName(), $curEntry.getClassPK(), 
        null, null, $renderResponse.createRenderURL()
      )
    </div>

当我们希望将你的注意力引到代码块的一个特定部分时,相关的行或项目将以粗体显示:

</timer-notification>
  <reassignments>
 <user>
 <email-address>
 test@liferay.com
 </email-address>
 </user>
 </reassignments>
</timer-actions>

任何命令行输入或输出将如下所示:

$ java -version
java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode).

新术语重要词汇将以粗体显示。你在屏幕上看到的单词,例如在菜单或对话框中,将以如下方式显示:“点击控制面板链接。”

注意

警告或重要提示将以如下方式显示。

小贴士

小贴士和技巧如下所示。

读者反馈

我们欢迎读者的反馈。告诉我们你对这本书的看法——你喜欢或不喜欢什么。读者反馈对我们来说很重要,因为它帮助我们开发出你真正能从中获得最大收益的标题。

要发送给我们一般性的反馈,只需发送电子邮件至<feedback@packtpub.com>,并在你的邮件主题中提及书籍的标题。

如果你在一个领域有专业知识,并且你对撰写或为书籍做出贡献感兴趣,请参阅我们的作者指南www.packtpub.com/authors

客户支持

现在你已经是 Packt 书籍的骄傲拥有者,我们有一些事情可以帮助你从你的购买中获得最大收益。

下载示例代码

你可以从你购买的所有 Packt 出版物的账户中下载示例代码文件。www.packtpub.com。如果你在其他地方购买了这本书,你可以访问www.packtpub.com/support,并注册以将文件直接发送给你。

勘误

尽管我们已经尽最大努力确保内容的准确性,但错误仍然可能发生。如果你在我们的某本书中发现了错误——可能是文本或代码中的错误——如果你能向我们报告这一点,我们将不胜感激。通过这样做,你可以帮助其他读者避免挫败感,并帮助我们改进本书的后续版本。如果你发现任何勘误,请通过访问www.packtpub.com/submit-errata,选择你的书籍,点击勘误提交链接,并输入你的勘误详情。一旦你的勘误得到验证,你的提交将被接受,勘误将被上传到我们的网站或添加到该标题的勘误部分下的现有勘误列表中。

要查看之前提交的勘误表,请访问www.packtpub.com/books/content/support,并在搜索字段中输入书籍名称。所需信息将在勘误部分显示。

侵权

在互联网上侵犯版权材料是一个跨所有媒体的持续问题。在 Packt,我们非常重视保护我们的版权和许可证。如果您在互联网上发现任何形式的我们作品的非法副本,请立即提供位置地址或网站名称,以便我们可以寻求补救措施。

请通过链接将涉嫌盗版材料发送至 <copyright@packtpub.com>,与我们联系。

我们感谢您在保护我们的作者和为您提供有价值内容的能力方面的帮助。

问题

如果您对本书的任何方面有问题,您可以联系 <questions@packtpub.com>,我们将尽力解决问题。

第一章:安装和基本配置

在本章中,我们将涵盖以下主题:

  • 在 Tomcat 捆绑包上快速运行 Liferay

  • Liferay 设置向导和首次登录

  • 设置开发者环境

  • 创建自定义 portlet

简介

Liferay 是市场上领先的开源门户解决方案提供商。它提供了一个稳固的平台来服务于所有客户。很难说 Liferay 是什么。一方面,Liferay 是一个优秀的内容管理系统,另一方面,它为用户之间的协作和通信提供了许多工具。它也可以是一个具有许多功能的社会平台,如墙、论坛、聊天等。此外,它还是一个符合 JSR-168 和 JSR-286 规范的 portlet 容器。Java 规范请求JSRs)描述了 Java 平台的最终规范。portlet 是一个小的 Web 应用程序,它生成 HTML 代码片段,这些片段被聚合到门户中。JSR-168 和 JSR-286 规范标准化了 portlet 与 portlet 容器之间的交互方式。这些规范还描述了 Java portlet 开发的标准化应用程序编程接口。换句话说,Liferay 只负责聚合在任何特定页面上要显示的 portlet 集合。这种方法为用户提供了一个强大的工具来组织和定制 portlet,以构建整个门户、社交平台或内联网。在 Liferay 中,一个门户由多个 portlet 组成,这些是按照特定标准编写的自包含的交互元素。许多出版物描述了 Liferay 的优势。在这本书中,我们将尝试深入了解 Liferay 的架构和其功能。

本章的主要目的是让您了解 Liferay 的安装和管理,包括基本配置。我们意识到有许多方法可以下载、编译、安装和运行 Liferay Portal。我们的主要目的是提供一些清晰和基本的信息,关于我们将依赖和工作的起始包。本章解释了在每次编译操作或每次启动操作上执行的主要过程。

Liferay Portal 以两种不同的版本发行:

  • Liferay Portal 社区版 (CE): 这是一个免费的开放源代码版本的 Liferay

  • Liferay Portal 企业版 (EE): 这是一个包含 Liferay 工程师、支持和服务的商业产品

本书基于最新的 Liferay Portal 社区版 (CE) 版本,版本号为 6.2。

要开始使用 Liferay 的旅程,有几个起点包含大量有用的信息,如下所示:

URL 描述
www.liferay.com/ 官方 Liferay 网站
www.liferay.com/downloads/liferay-portal/available-releases 可用版本放置处
www.liferay.com/documentation/liferay-portal/6.2/user-guidedev.liferay.com/ 用户指南和文档

| svn.liferay.com/repos/public/portal | Liferay 代码的旧式仓库。

  • 登录:在此字段输入 guest

  • 密码:此字段应留空

|

github.com/liferay/liferay-portal/tree/6.2.x [推荐] GitHub 仓库

提示

Liferay 推出了 7.0 版本,该版本将于 2015 年 9 月发布。不要从主干分支检出 Liferay 源代码。6.2 版本和主干版本之间有很多变化。在 7.0 版本中,Liferay 将提供 OSGi 集成和许多新功能。这些新功能帮助用户和开发者实现一系列开箱即用的功能(例如,基于 Lucene 框架的 Elasticsearch 作为搜索服务器)。

快速在 Tomcat 捆绑包上运行 Liferay

运行 Liferay 最简单的方法是从 Liferay 官方网站下载一个特定的捆绑包。Liferay 捆绑包只是一个包含托管 Liferay Portal 所需所有内容的压缩归档文件。捆绑包由一个基于 Java 的应用服务器和部署的 Liferay Portal 核心应用程序组成。Liferay 提供了不同应用程序服务器(即 Tomcat、JBoss、Geronimo 等)的捆绑运行时,以便您可以根据自己的选择使用任何一个。此方法推荐给只想运行 Liferay Portal、查看其功能并使用 GUI 配置网站的人。在本菜谱中,您将学习在 Tomcat 和 MySQL 数据库引擎上设置 Liferay 的技巧。

准备工作

首先,确保已正确安装 JRE 或 JDK。输入以下命令行:

$ java -version

结果应该类似于以下内容:

$ java -version
java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode).

还要检查 Java SDK 版本。Liferay 推荐 Java 7 或更高版本。

此外,确定 MySQL 服务器安装是否完成:

$ mysql --version

因此,实际安装的版本应显示出来。以下是一个示例:

mysql  Ver 14.14 Distrib 5.5.34, for debian-linux-gnu (x86_64)

还要检查 MySQL 版本。我们推荐 5.5 版本或更高版本。

如何操作...

要在 Tomcat 捆绑包上运行 Liferay,请按照以下步骤操作:

  1. 创建一个名为lportal的数据库:

    CREATE DATABASE lportal CHARACTER SET utf8 COLLATE utf8_general_ci;
    grant all privileges on lportal.* to '{USERNAME}'@'%' identified by 'PASSWORD';
    

    确保 MySQL 用户有创建表的权限。

  2. www.liferay.com/downloads/liferay-portal/available-releases下载适用于 Tomcat 捆绑包的正确 Liferay 版本。

  3. 解压下载的归档文件。

  4. 进入提取的文件夹liferay-portal-6.2-ce-ga2。此路径将被称作${liferay.home}文件夹。

  5. 前往${liferay.home}文件夹,创建一个名为portal-ext.properties的文件。

  6. 编辑portal-ext.properties并设置数据库属性:

    jdbc.default.driverClassName=com.mysql.jdbc.Driver
    jdbc.default.url=jdbc:mysql://localhost/lportal?useUnicode=true&characterEncoding=UTF-8&useFastDateParsing=false
    jdbc.default.username={USERNAME}
    jdbc.default.password={PASSWORD}
    
  7. 找到 Tomcat 文件夹并转到tomcat-7.0.42/bin/位置。

  8. 运行./startup.sh脚本(Windows 操作系统为startup.bat)并查看tomcat-7.0.42/logs/catalina.out日志。

  9. 在浏览器中,输入http://localhost:8080位置。默认情况下,Tomcat 监听 8080 端口。它应该默认渲染 Liferay 设置向导。这个向导将要求提供基本信息,例如,门户名称、默认语言和管理员用户详情。

它是如何工作的...

从准备好的 bundle 中运行 Liferay Portal 是一项相当容易完成的任务。然而,了解当 Tomcat 启动时到底发生了什么是有价值的。简要查看catalina.out日志并尝试逐行检查它。

加载配置描述符

第一件事是部署ROOT.xml。在我们的catalina.out文件中,有一行显示如下:

INFO: Deploying configuration descriptor /home/piotr/liferay-portal-6.2-ce-ga2/tomcat-7.0.42/conf/Catalina/localhost/ROOT.xml

这意味着配置文件在 Tomcat 7 中打开了crossContext属性。这个设置是必需的,因为 Liferay 是一个 portlet 容器。因此,它是一个应该能够访问其他称为 portlets 的应用程序的应用程序。Apache Tomcat 文档说:

"设置为 true,如果在这个应用程序内部调用 ServletContext.getContext()需要成功返回一个请求分发器,以便访问在这个虚拟主机上运行的其他 Web 应用程序。"

加载系统属性和门户属性

日志文件中的下一行显示了从特定位置加载的门户属性和系统属性:

Loading jar:file:/home/piotr/liferay-portal-6.2-ce-ga2/tomcat-7.0.42/webapps/ROOT/WEB-INF/lib/portal-impl.jar!/system.properties
Loading jar:file:/home/piotr/liferay-portal-6.2-ce-ga2/tomcat-7.0.42/webapps/ROOT/WEB-INF/lib/portal-impl.jar!/system.properties
Loading jar:file:/home/piotr/liferay-portal-6.2-ce-ga2/tomcat-7.0.42/webapps/ROOT/WEB-INF/lib/portal-impl.jar!/portal.properties
Loading file:/home/piotr/liferay-portal-6.2-ce-ga2/portal-ext.properties

Liferay Portal 的主要配置文件是portal.properties,其中包含关于它定义的属性的详细说明。至少有三种可能的方法可以覆盖portal.properties。有一个功能可以将portal-ext.properties放在ext插件中,在${liferay.home}目录中,或者放在portal-setup-wizard.properties中。但哪个文件最重要?答案在portal.properties文件中。默认的读取顺序是portal.propertiesportal-bundle.propertiesportal-ext.properties,然后是portal-setup-wizard.properties

    include-and-override=portal-bundle.properties
    include-and-override=${liferay.home}/portal-bundle.properties
    include-and-override=portal-ext.properties
    include-and-override=${liferay.home}/portal-ext.properties
    include-and-override=portal-setup-wizard.properties
    include-and-override=${liferay.home}/portal-setup-wizard.properties

检测数据库和数据库方言

下一步是识别数据库的方言:

12:35:47,469 INFO  [localhost-startStop-1][DialectDetector:71] Determine dialect for MySQL 5
12:35:47,504 INFO  [localhost-startStop-1][DialectDetector:136] Found dialect org.hibernate.dialect.MySQLDialect

Liferay 支持许多数据库引擎,如 DB2、Derby、Hypersonic、Ingres、MySQL、Oracle、P6Spy、PostgreSQL 和 Sybase。默认数据库是 Hypersonic,它将所有数据存储在${liferay.home}/data/hsql/lportal目录中。这对于想要运行 JUnit 测试的开发者来说是一个好选择,这些测试通过测试持久层或业务流程来修改数据。

在每次重启时,Liferay 都会尝试从Release_表获取构建号(Liferay 版本)。如果这个表不存在,它将调用ReleaseLocalService.createTablesAndPopulate()

如果无法获取构建号,Liferay 会记录以下信息:

WARN  [localhost-startStop-1][ReleaseLocalServiceImpl:171] Table 'lportal.Release_' doesn't exist

createTablesAndPopulate 方法运行以下脚本:

  • liferay-portal/sql/portal-tables.sql:这创建了所需的表

  • liferay-portal/sql/portal-data-common.sql:这添加了默认数据

  • liferay-portal/sql/portal-data-counter.sql:这初始化了唯一键生成器

  • liferay-portal/sql/portal-data-release.sql:这设置了发布日期

  • liferay-portal/sql/indexes.sql:这添加了数据库索引

  • liferay-portal/sql/sequences.sql:默认情况下,此文件为空。

除了创建表和填充数据外,Liferay 还会触发 VerifyProcess 机制。此过程将在每次启动时运行,以验证和修复数据库中发现的任何完整性问题。这是开发者添加自定义代码以检查特定案例完整性的完美位置。

启动 autodeploy 扫描器和部署插件

最后一步是初始化 autodeploy 和 hotdeploy 监听器。通常,这些机制将所有插件安装到 Tomcat 容器中,并将它们注册为 portlets、hooks、themes 等。特别是,至少有三种部署方法:sandbox 部署、autodeploy 和 hotdeploy。

注意

默认情况下,Liferay 使用 autodeploy 和 hotdeploy 监听器。实际上,sandbox 目前只能部署 themes 和 portlets。

autodeploy 机制负责监听特定目录以即时安装新插件并将它们复制到 Tomcat hotdeploy 过程中。该目录的定义放置在 portal.properties 中,默认情况下位于 deploy 文件夹:

auto.deploy.deploy.dir=${liferay.home}/deploy

每种类型的插件都有自己的 autodeploy 机制。这个机制运行所有必要的步骤,以确保它在 Liferay 容器中正确安装。简单来说,autodeploy 机制生成 web.xml 文件,并将所需的库添加到特定的插件中。这些类的定义放置在带有 auto.deploy.* 前缀的 portal.properties 文件中。每个类都扩展 BaseAutoDeployListener

第二个过程,hotdeploy,负责在 Liferay 中注册插件。这包括许多步骤,例如创建数据库表、设置首选项、注册 Spring 应用程序上下文等。当然,每个步骤都取决于插件的类型。在 portal.properties 中,为每种类型的类都有定义:

hot.deploy.listeners=
com.liferay.portal.deploy.hot.PluginPackageHotDeployListener,
com.liferay.portal.deploy.hot.SpringHotDeployListener,
com.liferay.portal.deploy.hot.ServletContextListenerHotDeployListener,
com.liferay.portal.deploy.hot.ExtHotDeployListener,
com.liferay.portal.deploy.hot.HookHotDeployListener,
com.liferay.portal.deploy.hot.JSONWebServiceHotDeployListener,
com.liferay.portal.deploy.hot.LayoutTemplateHotDeployListener,
com.liferay.portal.deploy.hot.PortletHotDeployListener,
com.liferay.portal.deploy.hot.SocialHotDeployListener,
com.liferay.portal.deploy.hot.ThemeHotDeployListener,
com.liferay.portal.deploy.hot.ThemeLoaderHotDeployListener,
com.liferay.portal.deploy.hot.MessagingHotDeployListener

小贴士

在部署过程中,Liferay 部署器修改 web.xml 文件,添加特定的依赖项,并将其重新打包。请确保您不要直接将 WAR 文件复制到 Tomcat 的 webapps 文件夹中。如果您这样做,插件将无法工作。

还有更多...

通常,企业已经建立了一个 Java EE 基础设施,他们希望在之上安装 Liferay。你还必须考虑企业的安全策略。这些策略有时会阻止将 Tomcat 捆绑包下载并安装到您选择的位置。在这种情况下,捆绑包就不够了,您必须手动将 Liferay 从其 WAR 存档安装到已存在的 Apache Tomcat 应用程序服务器中。

实现此目标有六个步骤。它们如下:

  1. 将特定的 JAR 文件及其依赖项复制到 Tomcat 全局lib文件夹,$TOMCAT_HOME/lib/ext

  2. 通过将ROOT.xml文件添加到$TOMCAT_HOME/conf/Catalina/localhost文件夹中启用crossContext

  3. $TOMCAT_HOME/bin/setenv.sh文件中设置自定义$JAVA_OPTS参数:

    JAVA_OPTS="$JAVA_OPTS -Dfile.encoding=UTF8 -Dorg.apache.catalina.loader.WebappClassLoader.ENABLE_CLEAR_REFERENCES=false -Duser.timezone=GMT -Xmx1024m -XX:MaxPermSize=256m"
    
  4. 使用以下代码行更新位于$TOMCAT_HOME/conf/catalina.properties中的common.loader属性:

    common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar,${catalina.home}/lib/ext,${catalina.home}/lib/ext/*.jar
    
  5. $TOMCAT_HOME/conf/server.xml中将 URI 编码指定为 UTF-8,如下所示:

    <Connector port="8080" protocol="HTTP/1.1"
      connectionTimeout="20000"
      redirectPort="8443" URIEncoding="UTF-8" />
    
  6. 使用 Tomcat 管理器部署 Liferay Portal 或将 WAR 存档手动放入$TOMCAT_HOME/webapps文件夹中。WAR 文件可在www.liferay.com/downloads/liferay-portal/available-releases#additional-versions找到。

注意

如何在 Tomcat 服务器上安装 Liferay 的更详细说明可在官方 Liferay 文档中找到,请参阅www.liferay.com/documentation/liferay-portal/6.2/user-guide/-/ai/installing-liferay-on-tomcat-3

参见

有关在集群环境中运行 Liferay 的信息,请参阅第十一章中的Clustering Liferay Portal配方,快速技巧和高级知识,以及第十二章中的Scalable infrastructure配方,基本性能调整。有关设置开发者环境的信息,请参阅下一配方。

Liferay 设置向导和首次登录

在 Apache Tomcat 服务器上成功运行 Liferay 后,系统会要求用户填写一些必要的信息以完成设置向导。这只是一个包含基本字段的单个屏幕,例如管理员名称或门户名称。

如何操作…

首次运行 Liferay 后,Liferay 平台会显示基本配置表单,其外观如下:

如何操作…

要完成安装,必须按照以下方式填写前面的表单:

  1. 提供有关门户的详细信息:

    • 门户名称:这是网站名称,例如,企业内部网

    • 默认语言:这有助于选择门户的默认语言

    • 添加示例日期:这决定了是否用默认数据填充门户

  2. 提供有关管理员用户的详细信息:

    • 名字姓氏

    • 电子邮件地址

  3. 选择数据库引擎(可选)。在先前的菜谱中,我们设置了 MySql 连接的属性。

  4. 确认表单。

  5. 点击转到我的门户按钮。

  6. 点击使用条款屏幕上的我同意按钮。

  7. 填写密码提示表单并确认表单。

    确认密码提示表单后,您将能够查看和使用主要的 Liferay 导航工具。

按以下步骤导航到控制面板

  1. 点击侧边栏菜单上的管理员按钮。

  2. 点击控制面板链接。

它是如何工作的...

运行 Liferay 第一次后,Liferay 需要关于门户、数据库和管理员的基本信息。数据库连接已在portal-ext.properties中设置,并在前面的菜谱中进行了描述。

在门户向导中提供的所有数据都存储在${liferay.home}/portal-setup-wizard.properties文件中。以下表格描述了最重要的设置:

属性名称 描述
admin.email.from.name 这描述了管理员的名称。
admin.email.from.address 这是管理员的电子邮件地址。
liferay.home 这是${liferay.home}目录的路径。这个属性非常重要,必须设置。
setup.wizard.enabled 此标志禁用设置向导。

登录后,用户能够看到仅授权用户可用的导航工具。以下是导航工具:

  • 侧边栏菜单位于屏幕顶部边缘下方。侧边栏由以下三个按钮组成:

    • 允许我们导航到站点管理控制面板部分的管理员按钮

    • 我的站点按钮,列出用户是成员的站点的链接

    • 带有用户名姓氏的按钮,允许我们导航到用户的个人资料(我的个人资料)、用户仪表板(我的仪表板)、用户账户(我的账户),并允许用户注销

  • 快速编辑菜单位于屏幕左侧边缘附近。菜单由以下图标组成:

    • 允许我们向页面添加新页面、新应用程序或新内容的添加图标

    • 允许我们编辑当前查看页面设置的编辑图标

    • 允许我们以不同分辨率和设备查看当前查看页面的预览图标

    • 允许我们隐藏或显示小部件控制的编辑控件图标

还有更多...

在内部项目,如内联网中,用户账户通常在外部系统中创建和管理,例如 LDAP。因此,允许用户管理他们的身份验证数据(例如,设置密码提示查询)或直接在 Liferay 中要求他们同意使用条款是不必要的(有时甚至是不被接受的)。在 Liferay 中,有许多属性可以帮助自定义首次登录操作,其中一些如下:

属性名称 描述
terms.of.use.required=false 这将关闭使用条款查询功能
terms.of.use.journal.article.group.idterms.of.use.journal.article.id 这指定了将显示为使用条款的组 ID 和文章 ID
users.reminder.queries.enabled=false 这将禁用提醒查询功能

参见

  • 关于添加新用户和定义角色和权限的信息,请参考第三章中的添加新用户配方,使用 Liferay 用户/用户组/组织

  • 创建和配置角色分配用户角色配方在第五章中,角色和权限

  • 关于默认登录页面的信息,请参考第二章中的使用管理员定义的页面覆盖默认登录页面配方,身份验证和注册过程

设置开发环境

许多开发者希望定制 Liferay Portal 以满足客户的需求。此外,本书中还将提供许多代码示例,因此设置环境是开始的重要步骤。Liferay 提到有两种类型的发展和两种获取源代码的方式:

  • GitHub:对于贡献者

  • sourceforge.net:对于非贡献者

对于本书的目的,仅使用非贡献者版本就足够了。

准备工作

使用 Liferay Portal 的最小要求是Java 开发工具包JDK),Apache Ant 1.7 版本或更高版本,以及 Eclipse IDE Indigo 或更高版本。通过输入以下代码行来确保安装成功:

$ ant -version
Apache Ant(TM) version 1.8.2 compiled on May 18 2012

$ java -version
java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)

如何操作...

本配方分为三个部分。第一部分包含描述准备活动,如下载 Liferay 源代码或解压缩它们。第二部分提供了关于所需配置的描述。最后一部分专注于编译所有 Liferay 源代码并将它们部署到 Apache Tomcat 服务器。

将源代码导入到 Eclipse IDE

第一步是将 Liferay 源代码作为项目导入到我们的 IDE 中。以下步骤基于 Eclipse IDE。为了实现这一点,请按照以下步骤操作:

  1. ${liferay.home}中创建一个workspace文件夹。

  2. 访问 sourceforge.net/projects/lportal/files/Liferay%20Portal/ 并选择最新的 6.x 版本的文件夹。接下来,找到以 liferay-portal-src-* 为前缀的文件并下载它。

  3. 将此文件解压到 workspace 文件夹。

  4. 通过访问 文件 | 导入 | 通用 | 现有 项目到工作空间 并点击 下一步 按钮,将此项目导入 Eclipse IDE。在下一屏幕上,选择 选择根目录 并指向包含 Liferay 源代码的文件夹,即 ${liferay.home}/workspace/liferay-portal-src-${VERSION}。要完成此任务,请点击 完成 按钮。

  5. 在这一步之后,需要在项目中创建一个名为 /portal-web/test/functional 的文件夹。这个操作可以解决 Eclipse IDE 中的以下警告:构建路径条目缺失:Liferay-portal-src.6.2-ce-ga2/portal-web/test/functional

覆盖 app.server.properties

为了与放置在 ${liferay.home}/tomcat-7.0.42 文件夹中的现有 Tomcat 兼容,需要更改 app.server.parent.dir 属性。为此,请按照以下步骤操作:

  1. 在项目的根目录中创建 app.server.${username}.properties,即 ${liferay.home}/workspace/liferay-portal-src-${VERSION}

  2. 覆盖 服务器目录 属性并设置新值:

    app.server.parent.dir=${project.dir}/../../
    

    这也可以是 Tomcat 父文件夹的绝对路径。

    ${liferay.home} 文件夹应该具有以下层次结构:

      .
      |-data
      |---document_library
      |---hsql
      |---lucene
      |-deploy
      |-license
      |-logs
      |-tomcat-7.0.42
      |---bin
      |---conf
      |---lib
      |---logs
      |---temp
      |---webapps
      |-workspace
      |---liferay-portal-src-6.2-ce-ga2
    

编译和部署

访问 {$liferay.home}/workspace/liferay-portal-src-${VERSION} 并使用命令行中的 ant all 目标编译所有 Liferay 源代码。

注意

在这本书中,我们将使用控制台方法来编译、部署等。Liferay 为 Eclipse 提供了 Liferay IDE。为了更好地理解,我们将使用命令行作为主要工具。

它是如何工作的

这可能成为对 Liferay 使用 Apache Ant 而不是 Maven、Gradle 或其他构建自动化工具的批评来源。实际上,Apache Ant 工具足以管理和编译 Liferay 核心。如果有人想使用 Maven,他们可以在自定义插件中使用它。Liferay 提供了许多原型,以帮助创建多个插件的 Maven 项目。

让我们更详细地看看 Eclipse IDE 中的项目。有许多包含大量包的文件夹。让我们检查与 Liferay 架构最相关的最重要文件夹:

文件夹名称 描述
定义 这包含 dtdxsd 定义,例如,portlet.xml 定义或 service.xml 定义。
portal-impl 这是门户的核心。它实现了在全局 lib 中暴露的所有接口,并且包含模型定义。永远不要将 portal-impl 放置在它来源之外的地方。
portal-service 这提供了接口定义,可用于自定义实现,例如钩子、端口、主题等。
util-bridges 这包含桥梁和实用工具,有助于实现自定义端口,例如 AlloyPortlet、BSFPortlet、MVCPortlet 等。
portal-web 这包含 Web 应用程序根目录,其中包含所有配置文件和视图层。

让我们回到编译命令ant all。这里到底发生了什么?门户有其自己的运行时结构。它提供了带有 Tomcat、JBoss 或其他应用程序服务器的即用型包。它提供了一个可以构建运行时包的工具。在主要的build.xmlAnt 文件中,有一个 Ant 目标定义ant.apache.org/manual/targets.html

<target name="all">
  <antcall target="clean" />
  <antcall target="start" />
  <antcall target="deploy" />
</target>

构建过程由三个部分组成:清理、启动和部署。

清理过程

ant clean命令执行以下步骤:

  • 它清理以下文件夹下的 Java 类:classesportal-serviceutil-bridgesutil-javautil-slf4jutil-taglibportal-implportal-paclosgi/bootrstapportal-websql

  • 它删除了具有掩码*.ear*.jar*.war*.zip的文件

  • 它清理了worktemplogsTomcat 文件夹,并从/conf/Catalina/localhost目录中删除了*-hook.xml*-portlet.xml文件

根据应用程序服务器,还有一些额外的步骤,用于清理或删除许多配置文件。为了理解本书中使用的流程,不需要了解每个步骤和深度清理过程。

启动过程

ant start目标调用以下任务:

  • 它运行编译目标,编译portal-serviceutil-bridgesutil-javautil-slf4jutil-taglibportal-implportal-paclosgi/bootstrap文件夹下的源代码

  • 它构建数据库并重新构建 Hypersonic 数据库

  • 它在portal-impl文件夹下构建主题

  • 它调用生成 Liferay 核心 JAR 和 WAR 的jar目标

部署过程

此目标严格依赖于应用程序服务器。通常,此构建将应用程序部署到特定的 Servlet 容器或应用程序服务器。此外,此构建在${liferay.home}下创建所需的文件夹或文件。此构建创建的文件夹如下:

  • 热部署过程的deploy文件夹

  • 包含二进制数据(如文档库、Jackrabbit、HSQLDB 或 Lucene)的data文件夹

  • ${app.server.dir}/conf/Catalina/localhost/中的ROOT.xml上下文配置文件以及许多其他依赖于应用程序服务器的任务

还有更多...

如前所述,可以创建一个完整的包,而无需手动下载 Tomcat 或其他应用程序服务器。为了实现这一目标,只需两个步骤:

  • 调用ant -buildfile build-dist.xml unzip-tomcat任务

  • 调用ant all命令

在不同的应用程序服务器上部署 Liferay 是可能的。有一系列命令可以完成这个任务:

ant -buildfile build-dist.xml build-dist-geronimo
ant -buildfile build-dist.xml build-dist-glassfish
ant -buildfile build-dist.xml build-dist-jboss
ant -buildfile build-dist.xml build-dist-jboss-eap
ant -buildfile build-dist.xml build-dist-jetty
ant -buildfile build-dist.xml build-dist-jonas
ant -buildfile build-dist.xml build-dist-resin
ant -buildfile build-dist.xml build-dist-tcat
ant -buildfile build-dist.xml build-dist-tomcat

创建一个自定义组件

这个菜谱非常具体,因为它展示了如何生成一个新的组件,将其安装在 Liferay 上,并将其导入到 Eclipse IDE 中。本书中的许多菜谱都假设用户知道如何生成一个新的插件,例如组件、钩子或 Web。我们将向您展示如何使用 Apache Maven 架构生成一个新的组件。整本书都假设您使用 Apache Maven 编译和部署新的组件。

准备工作

为了正确生成一个新的组件,您需要以下软件栈:

  • Java SDK 1.7 或更高版本

  • Apache Maven,我们使用 3.0.5 版本

  • Eclipse IDE(Kepler 或更高版本)

我们还假设您已经正确设置了开发环境,这在之前的菜谱中已经描述过。

如何操作…

实现我们的目标有三个阶段:生成一个新的组件,编译它,并将其部署和导入到 Eclipse IDE。

生成一个新的组件

我们需要做的第一件事是创建一个 Maven 项目。为了生成它,请按照以下步骤操作:

  1. 进入 ${liferay.home}/workspace 文件夹。

  2. 执行 mvn archetype:generate -Dfilter=liferay-portlet-archetype

  3. com.liferay.maven.archetypes:liferay-portlet-archetype 选择一个数字。在我们的列表中,它是编号 1

    Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): : 1
    
  4. 选择正确的 Liferay 版本。在我们的例子中,它将是 6.2.2,编号为 24

  5. 按照以下方式提供所有所需的 Maven 项目信息:

    Define value for property 'groupId': : com.packtpub.portlet
    Define value for property 'artifactId': : first-portlet
    Define value for property 'version':  1.0-SNAPSHOT: : 
    Define value for property 'package':  com.packtpub.portlet: : 
    Confirm properties configuration:
    groupId: com.packtpub.portlet
    artifactId: first-portlet
    version: 1.0-SNAPSHOT
    package: com.packtpub.portlet
    Y: : y
    
  6. 在我们的 workspace 文件夹中,应该生成一个名为 first-portlet 的组件。

编译组件并部署它

使用 Apache Maven,编译和部署一个组件非常容易。在调用 Maven 命令之前,用户必须在 pom.xml 文件中设置特定的属性。

  1. 进入 ${liferay.home}/workspace/first-portlet 文件夹并编辑 pom.xml 文件。

  2. <build> 部分,添加以下属性定义:

    <properties>
      <liferay.version>6.2.2</liferay.version>
      <liferay.maven.plugin.version>6.2.2</liferay.maven.plugin.version>
      <liferay.auto.deploy.dir>${liferay.home}/deploy</liferay.auto.deploy.dir>
      <liferay.app.server.deploy.dir>${liferay.home}/tomcat-7.0.42/webapps</liferay.app.server.deploy.dir>
      <liferay.app.server.lib.global.dir>${liferay.home}/tomcat-7.0.42/lib/ext</liferay.app.server.lib.global.dir>
      <liferay.app.server.portal.dir>${liferay.home}/tomcat-7.0.42/webapps/ROOT</liferay.app.server.portal.dir>
    </properties>
    

    小贴士

    ${liferay.home} 替换为你的文件夹的实际路径。

  3. 保存 pom.xml 文件。

  4. 通过执行以下命令构建一个新的项目:

    mvn clean install
    
    
  5. 确保您的 Apache Tomcat 正在运行 Liferay。

  6. 调用 mvn liferay:deploy 命令并跟踪 catalina.out 日志文件。您应该看到类似的消息:

    [PortletHotDeployListener:343] Registering portlets for first-portlet
    [PortletHotDeployListener:490] 1 portlet for first-portlet is available for use
    
    

将组件导入到 Eclipse IDE

通过 Maven 架构插件成功生成源代码后,我们的组件源代码可以导入到我们的 Eclipse IDE 中。要导入它们,请按照以下步骤操作:

  1. 确保您位于 ${liferay.home}/workspace/first-portlet 文件夹中。

  2. 运行 mvn eclipse:clean eclipse:eclipse 命令。

  3. 打开您的 IDE,通过访问 文件 | 导入 | 通用 | 将现有项目导入到工作空间 来将 first-portlet 作为项目导入。

它是如何工作的…

com.liferay.maven.archetypes:liferay-portlet-archetype 创建的端口项目具有现成的端口实现。实际上,它非常基础,但整个文件夹结构和配置文件都创建得正确。每个端口都有四个配置文件:portlet.xmlliferay-portlet.xmlliferay-display.xmlliferay-plugin-package.properties。所有这些文件都放置在 first-portlet/src/main/webapp/WEB-INF 文件夹中。

portlet.xml 文件是端口描述符。它包含端口定义,例如名称、端口类等。

liferay-portlet.xml 文件是 portlet.xml 的一种扩展。它只被 Liferay Portal 所理解。它提供了额外的信息,例如端口的图标、cssjs 文件路径等。

liferay-display.xml 文件告诉我们我们的端口将在哪个部分可用。我们将在本书的后续部分对其进行描述。

liferay-plugin-package.properties 文件是我们端口的度量标准。这是一个指定版本、标签、页面 URL、作者和许可证的好地方。

关于端口的详细信息可在 JSR-168 和 JSR-286 规范中找到。有许多关于如何使用端口、如何建立端口之间的通信或端口请求生命周期的示例。

参见

关于端口的更多信息,请参阅以下菜谱:

  • 在第五章 角色和权限创建基于角色的端口 菜谱中,第五章

  • 在第五章 角色和权限在自定义端口中检查权限 菜谱中,第五章

  • 在第十一章 快速技巧和高级知识语言属性钩子 菜谱中,第十一章

  • 在第十一章 快速技巧和高级知识使用 Liferay 服务总线进行端口间通信 菜谱中,第十一章

第二章. 认证和注册流程

在本章中,我们将涵盖以下主题:

  • 修改默认认证设置

  • 设置电子邮件通知

  • 自定义注册表单

  • 用管理员定义的页面覆盖默认登录页面

  • 设置密码策略

  • 与 CAS SSO 集成

  • CAS 和 Liferay 用户数据库

  • Liferay 和 LDAP 集成

  • 神奇的三重奏:Liferay、CAS 和 LDAP

简介

认证和注册流程对于构建内部网络系统非常重要。在这种类型的软件中,必须保护数据免受未经授权的用户访问。我们决定描述在许多项目中常用的典型解决方案。这将帮助您配置 Liferay 的即用型认证系统并定义密码策略。您还将了解与最流行的单点登录机制(SSO)的集成。SSO 的目的是允许用户一次提供凭证即可访问多个应用程序。中央认证服务CAS)是 Web 的单点登录协议。它也是一个实现此协议的软件包。

修改默认认证设置

Liferay 提供了一个内置的认证机制,默认情况下允许用户使用他们的电子邮件地址登录。此外,还有一些功能,如自动登录或忘记密码功能,这些功能可以帮助用户并帮助他们完成认证过程。然而,在某些情况下,必须修改标准的认证行为。

准备工作

使用管理员凭证登录 Liferay。默认情况下,凭证如下:

  • 电子邮件:test@liferay.com

  • 密码:test

如何操作…

为了修改默认认证设置,请执行以下步骤:

  1. 以管理员身份登录,然后转到管理 | 控制面板 | 配置 | 门户设置 | 认证部分如何操作…

  2. 确保您在常规选项卡上。

  3. 认证类型下拉列表中选择您喜欢的选项。

  4. 启用/禁用允许用户自动登录?选项。

  5. 启用/禁用允许用户请求忘记密码?选项。

  6. 启用/禁用允许用户请求密码重置链接?选项。

  7. 启用/禁用允许陌生人创建账户?选项。

  8. 启用/禁用允许陌生人使用公司电子邮件地址创建账户?选项。

  9. 启用/禁用要求陌生人验证他们的电子邮件地址?选项。

  10. 点击保存按钮。

为了仅设置登录小部件特定实例的认证类型,您不需要在控制面板范围内执行额外的步骤。在这种情况下,只需更改登录小部件的配置即可。执行以下步骤:

  1. 前往放置登录小部件的公共页面。

  2. 点击添加按钮。

  3. 点击应用程序按钮。

  4. 使用搜索选项或通过浏览可用小部件列表找到登录小部件。

  5. 点击小部件名称旁边的添加链接。带有基本配置的登录小部件将被添加到页面上。

  6. 前往登录小部件配置。

  7. 身份验证类型列表中选择您喜欢的选项。

  8. 点击保存按钮。

它是如何工作的…

在 Liferay 门户中,用户可以通过电子邮件地址、屏幕名称或数字序列,或自动生成的用户 ID 进行身份验证。有两个地方允许您设置首选的身份验证方法:门户设置部分和登录小部件的配置屏幕。控制面板设置允许您定义默认的身份验证类型。此设置也可以通过portal-ext.properties中的属性进行修改:

company.security.auth.type=emailAddress
company.security.auth.type=screenName
company.security.auth.type=userId

小贴士

请记住,比portal-ext.properties更重要的是来自 GUI(控制面板)的配置。

然而,登录小部件配置选项允许您决定特定登录小部件将使用哪种身份验证方式。在小部件内部,可以选择默认选项或之前描述的三个可用选项之一。默认选项与company.security.auth.type属性相同。

除了选择身份验证类型外,Liferay 还允许您设置影响授权和身份验证过程的其他参数。默认情况下,除了要求陌生人验证他们的电子邮件地址?选项外,所有选项都启用。

允许用户自动登录?选项允许您决定网站是否应该记住用户的登录信息,并在登录表单中显示记住我复选框。此选项可以通过设置以下属性来启用(true)或禁用(false):

company.security.auto.login=true

允许用户请求忘记的密码?选项负责启用或禁用忘记密码功能。此功能使得用户可以请求将新密码发送到他们的电子邮件地址。默认情况下,此选项在以下属性中启用:

company.security.send.password=true

允许用户请求密码重置链接?选项负责启用或禁用重置密码功能。此功能允许用户请求将密码重置链接发送到他们的电子邮件地址。此选项由以下属性表示:

company.security.send.password.reset.link=true

允许陌生人创建账户?选项负责创建账户链接的可用性。此选项让您决定网站访客是否可以自行创建账户。默认情况下,它如下启用:

company.security.strangers=true

允许陌生人使用公司电子邮件地址创建账户?选项允许您决定是否可以使用门户设置中“常规”部分提供的域中的电子邮件地址创建新账户:

company.security.strangers.with.mx=true

是否要求陌生人验证他们的电子邮件地址?选项启用电子邮件验证功能。此功能也可以通过在portal-ext.properties中设置以下属性来启用:

company.security.strangers.verify=false

尽管身份验证部分包含多个标签页,提供了一系列额外的身份验证方法,但身份验证标签页的常规选项卡上收集的所有设置仅影响 Liferay 功能。它们对剩余标签页上分组集成的选项没有影响。

在某些情况下,前面的配置可能不够。例如,许多公司有自己的隐私政策,要求HTTPS连接。Liferay 在portal.properties中提供了几个设置,这些设置可以在portal-ext.properties中覆盖,具体如下:

属性 描述
company.security.auth.requires.https=false 将此设置为true以确保用户使用 HTTPS 登录
company.security.auto.login.max.age=31536000 指定启用记住我功能的浏览器 cookie 的最大有效期(以秒为单位)
company.security.login.form.autocomple=true 允许用户根据之前输入的值自动完成登录表单

小贴士

需要修改portal-ext.properties文件以重启服务器。

还有更多...

与登录和注销机制严格相关的还有两个选项。第一个选项是默认登录页面字段,位于门户设置网页上。此字段允许您指定用户在完成授权和认证后将被重定向到的页面。第二个选项是默认注销页面字段,位于门户设置中,允许您定义用户在注销后将被重定向到的页面。

为了设置这些字段的自定义值,请按照以下步骤操作:

  1. 前往管理 | 控制面板 | 配置 | 门户设置 | 常规

  2. 默认登录页面设置为用户登录后希望访问的页面地址,例如,/web/guest/login

  3. 默认注销页面设置为用户注销后希望访问的页面地址,例如,/web/guest/logout

  4. 点击保存按钮。

这些设置也可以通过以下名称由portal-ext.properties覆盖:

default.landing.page.path={PATH}
default.logout.page.path={PATH}

参见

关于覆盖默认登录页面的信息,请参阅使用管理员定义的页面覆盖默认登录页面配方。

设置电子邮件通知

在 Liferay 中,有四种自动发送的电子邮件通知。具体如下:

  • 账户创建通知,在用户成功创建新账户时发送

  • 电子邮件验证通知,提供电子邮件验证链接和代码

  • 密码更改通知,通知用户其密码已被更改

  • 密码重置通知,允许用户通过提供密码重置 URL 来重置当前密码

本食谱提供有关如何自定义这些默认通知的信息。

准备工作

确保 Java 邮件会话已正确配置。为了检查其是否工作,请查看portal-ext.properties并查找和/或配置以下设置:

mail.session.mail.pop3.host=localhost
mail.session.mail.pop3.password=
mail.session.mail.pop3.port=110
mail.session.mail.pop3.user=
mail.session.mail.smtp.auth=false
mail.session.mail.smtp.host=localhost
mail.session.mail.smtp.password=
mail.session.mail.smtp.port=25
mail.session.mail.smtp.user=
mail.session.mail.store.protocol=pop3
mail.session.mail.transport.protocol=smtp

如何操作…

为了更改发件人的姓名和电子邮件地址,请按照以下步骤操作:

  1. 以管理员身份登录并前往管理员 | 控制面板 | 配置 | 门户设置 | 电子邮件通知

  2. 确保您处于发件人选项卡。

  3. 提供发件人的姓名和电子邮件地址。

  4. 点击保存按钮。

为了设置账户创建通知,请执行以下步骤:

  1. 前往管理员 | 控制面板 | 配置 | 门户设置 | 电子邮件通知

  2. 前往账户创建通知选项卡。

  3. 设置启用选项。

  4. 提供主题

  5. 提供带有密码正文消息文本。

  6. 提供不带密码正文消息文本。

  7. 点击保存按钮。

以下截图捕捉了前面的步骤

如何操作…

除了账户创建通知之外,Liferay 还提供了三个选项卡以进行自定义。具体如下:

  • 电子邮件验证通知

  • 密码更改通知

  • 密码重置通知

为了设置电子邮件验证通知密码更改通知密码重置通知,请执行以下步骤:

  1. 前往管理员 | 控制面板 | 配置 | 门户设置 | 电子邮件通知

  2. 前往电子邮件验证通知密码更改通知密码重置通知选项卡。

  3. 提供消息的主题和正文。

  4. 点击保存按钮。

工作原理…

每封电子邮件通知都由消息的主题和正文组成。消息的主题和正文都可以使用一组称为术语的可用变量(每个通知不同)和自定义文本来编写。消息正文的文本也可以提供简单的文本样式。

值得注意的是,账户创建通知选项卡提供了一个额外的启用选项,允许您决定是否发送此特定通知。

默认情况下,portal.properties包含基本的电子邮件通知设置(默认发件人姓名、默认发件人电子邮件、主题、正文等)。当然,所有这些设置都可以根据特定要求进行自定义:

admin.email.from.name=Joe Bloggs
admin.email.from.address=test@liferay.com
admin.email.user.added.enabled=true
admin.email.user.added.subject=com/liferay/portlet/admin/dependencies/email_user_added_subject.tmpl

admin.email.user.added.body=com/liferay/portlet/admin/dependencies/email_user_added_body.tmpl

admin.email.user.added.no.password.body=com/liferay/portlet/admin/dependencies/email_user_added_no_password_body.tmpl

admin.email.password.reset.subject=com/liferay/portlet/admin/dependencies/email_password_reset_subject.tmpl

admin.email.password.reset.body=com/liferay/portlet/admin/dependencies/email_password_reset_body.tmpl

admin.email.password.sent.subject=com/liferay/portlet/admin/dependencies/email_password_sent_subject.tmpl

admin.email.password.sent.body=com/liferay/portlet/admin/dependencies/email_password_sent_body.tmpl

admin.email.verification.subject=com/liferay/portlet/admin/dependencies/email_verification_subject.tmpl

admin.email.verification.body=com/liferay/portlet/admin/dependencies/email_verification_body.tmpl

上述配置定义了每种类型通知的默认设置。例如,admin.email.password.reset.body属性定义了密码重置操作的 HTML 模板,该模板位于com/liferay/portlet/admin/dependencies/email_password_reset_body.tmpl文件中。

参见

关于如何配置 SMTP 服务器的信息,请参阅第十一章中“配置 Liferay 与 SMTP 服务器”食谱,快速技巧和高级知识

自定义注册表单

注册过程完成后,注册表单的内容和系统的行为可能会根据系统的功能和非功能需求而有所不同。默认的注册表单配置允许您收集创建账户所需的数据。配置还提供了一些额外的字段,如出生日期或性别,这些字段可能并不总是需要的。本食谱描述了如何更改默认的注册表单字段集,并在注册和授权过程中修改它们的基本首选项和系统行为。

如何操作…

为了自定义注册表单,请执行以下步骤:

  1. 以管理员身份登录并转到管理 | 控制面板 | 配置 | 门户设置 | 用户如何操作…

  2. 确保您处于字段选项卡。

  3. 启用/禁用使用条款必填选项。

  4. 启用/禁用自动生成用户屏幕名称选项。

  5. 启用/禁用姓氏必填选项。

  6. 启用/禁用启用生日选项。

  7. 启用/禁用启用性别选项。

  8. 点击保存按钮。

工作原理…

有三个选项卡将注册表单设置分组:字段选项卡、预留凭据选项卡和默认用户关联选项卡。

字段选项卡包含负责注册表单内容和用户首次登录时系统行为的选项列表。这些选项中的每一个在portal.properties中都有自己的表示,可以被portal-ext.properties覆盖。请记住,最高优先级的设置来自控制面板。以下是一些选项:

  • 使用条款必填选项启用和禁用使用条款屏幕,该屏幕在用户首次授权后显示。默认情况下,它被启用:

    terms.of.use.required=true
    
  • 自动生成用户屏幕名称选项禁用注册表单中的屏幕名称字段,并设置 Liferay 自动从电子邮件地址创建屏幕名称。如果此选项启用,屏幕名称将根据用户的电子邮件地址(电子邮件地址的本地部分)生成。默认情况下,它被禁用:

    users.screen.name.always.autogenerate=false
    
  • 姓氏必填选项将姓氏设置为必填字段。默认情况下,它被禁用:

    users.last.name.required=false
    
  • 启用生日选项允许您决定是否应在注册表中提供生日字段。默认情况下,它是启用的:

    field.enable.com.liferay.portal.model.Contact.birthday=true
    
  • 启用性别选项允许您决定是否应在注册表中提供性别字段。默认情况下,它是启用的:

    field.enable.com.liferay.portal.model.Contact.male=true
    

保留凭据选项卡允许您定义保留的屏幕名称和电子邮件地址,这些地址不能被用户和管理员用于创建用户账户。它也可以在以下属性中重写:

admin.reserved.screen.names
admin.reserved.email.addresses

默认用户关联选项卡提供了一组字段,允许您将站点、组织站点、角色和用户组分配给每个新创建的用户。

此外,还可以使用应用于现有用户选项扩展现有用户的功能。但是,更改将在用户登录时生效。

更多内容…

可以更改登录表单中创建账户链接的默认行为,并使用自定义创建账户小部件页面而不是默认的(登录小部件)页面。为了做到这一点,定义自定义注册小部件放置的 URL,并在portal-ext.properties文件中设置以下属性:

company.security.strangers.url=/create-account

参见

关于添加用户的更多信息,请参阅第三章中的添加新用户食谱,与 Liferay 用户/用户组/组织一起工作

用管理员定义的页面覆盖默认登录页面

Liferay 提供了使用或替换默认对话框登录功能与自定义登录页面的可能性。自定义页面可以用来展示一些附加信息,例如说明、利益描述等。本食谱提供了如何在内部网络中设置此类页面的指南。

如何操作…

为了在登录过程中设置自定义页面,请按照以下步骤操作:

  1. 以管理员身份登录并转到管理 | 站点管理 | 页面

  2. 确保您处于公共页面选项卡。

  3. 点击添加页面按钮。

  4. 为页面提供一个名称(例如,登录)。

  5. 启用隐藏于导航菜单选项。

  6. 点击添加页面按钮。新页面将被创建。

  7. 通过单击树中创建的页面来查看页面详情并复制友好 URL值。

  8. 通过在浏览器的地址栏中输入(或粘贴)其地址来转到创建的页面。

  9. 点击添加按钮(这是左侧的+符号)。

  10. 点击应用程序选项卡。

  11. 使用搜索功能或通过浏览可用小部件列表来查找登录小部件,

  12. 点击小部件名称旁边的添加链接。带有基本配置的登录小部件将被添加到页面中。

  13. 通过在portal-ext.properties文件中定义auth.login.site.url=/login属性来将此站点的 URL 设置为portal-ext.properties文件。

注意

如果有自定义登录端口和自定义登录页面,则需要通过设置 login.dialog.disabled=true 属性来禁用对话框登录功能。

它是如何工作的…

如前所述,第一步是创建一个包含登录端口的新的标准页面。此页面将用作新的登录页面。第二步是覆盖默认的 Liferay 配置,并设置在用户导航网站且需要身份验证时使用此新创建的登录页面。为了做到这一点,您需要在 auth.login.site.url 属性中设置新链接。同样重要的是要记住,当将 登录 链接重定向到自定义页面时,需要禁用标准登录弹出对话框。这可以通过将 login.dialog.disabled 属性设置为 true 来实现。

参见

如果您想了解创建页面或定义页面模板,请参考以下来自 第四章,Liferay 网站配置 的食谱:

  • 为网站创建和自定义私有和公共页面

  • 使用页面模板和网站模板快速创建网站和页面

设置密码策略

Liferay 密码策略创建器允许您设置密码生命周期和其使用规则。您可以决定是否需要更改密码。您还可以指定密码语法、过期规则、锁定选项和密码历史。

Liferay 默认提供的密码策略非常简单。它允许您更改用户的密码,并指定重置密码链接应有效期为一天。本食谱详细说明了如何创建一个新、更严格的密码策略。

本例中的密码策略将要求用户提供八位字符的密码,这些密码在字典中找不到。用户必须在密码中包含数字和大写字母,并且每六十天必须更改一次密码(不应可能设置最后十次使用过的密码)。此外,系统将计算失败登录尝试次数,在三次不成功尝试后,将账户锁定 10 分钟。

如何操作…

为了设置所描述的密码策略,请按照以下步骤操作:

  1. 以管理员身份登录并转到 Admin | 控制面板 | 用户 | 密码策略

  2. 点击 添加 按钮。如何操作…

  3. 为新密码策略提供一个名称。

  4. 提供新密码策略的描述。

  5. 启用 可更改 选项。

  6. 重置票据最大年龄 选项设置为 1 天

  7. 启用 语法检查启用 选项。

  8. 禁用 允许字典单词 选项。

  9. 最小长度 设置为 8

  10. 最小大写字母 设置为 1

  11. 最小数字 设置为 1

  12. 启用 历史启用 选项。

  13. 历史计数 选项设置为 10

  14. 启用 过期启用 选项。

  15. 最大年龄设置为8 周

  16. 警告时间设置为6 天

  17. 设置锁定启用选项。

  18. 最大失败次数设置为3

  19. 锁定持续时间设置为10 分钟

  20. 点击保存按钮。

它是如何工作的…

新密码策略表单中有五组选项:通用密码语法检查密码历史密码过期锁定部分

通用部分包括以下选项:

  • 可更改选项允许您决定用户是否可以更改他们的密码

  • 更改要求选项确定用户是否需要在首次登录时更改密码

  • 最小年龄选项指定用户在允许更改密码之前必须等待的时间

  • 重置票据最大年龄选项确定密码重置链接的有效时长

密码语法检查部分包括以下选项:

  • 语法检查启用选项确定是否应该检查密码语法

  • 允许字典选项确定是否允许在密码中使用常用单词

  • 最小字母数字选项允许您设置密码中所需的最小字母数字数量

  • 最小长度选项确定密码所需的最小长度

  • 最小小写字母选项确定密码中所需的最小小写字母数量

  • 最小数字选项确定密码中所需的最小数字数量

  • 最小符号选项确定密码中所需的最小符号数量

  • 最小大写字母选项确定密码中的最小大写字母数量

  • 正则表达式选项确定用户密码的验证模式

密码历史部分包括以下选项:

  • 历史启用选项允许您决定门户是否应该保留用户之前密码的历史记录,以防止他们重用旧密码

  • 历史计数选项确定在历史记录中保留的旧密码数量,在设置新密码时不能使用

密码过期部分包括以下选项:

  • 过期启用选项允许您决定是否强制用户定期更改密码

  • 最大年龄选项确定密码的有效时长

  • 警告时间指定密码过期前的时长;在此日期后将会发送通知

  • 宽限期指定用户密码过期后可以登录的次数

锁定部分包括以下选项:

  • 锁定启用选项让您统计失败的登录尝试并启用账户锁定机制

  • 最大失败选项指定了最大失败登录尝试次数

  • 重置失败计数选项指定了保留失败登录信息的时间

  • 锁定持续时间选项表示用户账户被锁定且无法使用的时长

与 CAS SSO 集成

CAS 是一个单点登录协议。官方规范如下介绍它:

"中央认证服务 (CAS) 是一个用于网络的单点登录/单点登出协议。它允许用户在只向中央 CAS 服务器应用程序提供一次凭据(如用户名和密码)的情况下访问多个应用程序。"

Liferay 提供了基于 JASIG CAS (CAS 于 2004 年 12 月成为 Java in Administration Special Interest Group (JASIG) 项目,现在也被称为 JASIG CAS) 的现成功能。在许多项目中,尤其是内部项目(例如,企业内部网),提供单点登录是必要的。CAS 与以下认证机制集成:

  • Active Directory

  • 通用

  • JAAS

  • JDBC

  • LDAP

  • 旧版

  • RADIUS

  • SPNEGO

  • 受信任

  • X.509 证书

这个配方涵盖了安装 CAS 服务器并将其与 Liferay 集成的基本步骤。

如何操作...

为了安装和运行与 Liferay 兼容的 CAS 服务器,有四个主要步骤:

  1. 在 Tomcat 服务器上安装 CAS 系统。

  2. 配置 HTTPS 连接。

  3. 设置 CAS 服务器。

  4. 配置 Liferay 门户。

安装 CAS 系统

第一步是在 Apache Tomcat 服务器上安装 CAS 系统。CAS 可以与 Liferay 部署在同一实例中,但在实际示例中,它是一个专用应用程序服务器。我们假设第一种方法。第二个重要假设是我们依赖于 Tomcat 的热部署存档。因此,请确保将 autoDeploy 选项设置为 true。这是一个默认设置。要安装 CAS,请按照以下步骤操作:

  1. downloads.jasig.org/cas/ 下载 CAS 的最新版本并解压存档。目前,4.0 是最新版本。

  2. cas-server-4.0.0/modules/cas-server-webapp-4.0.0.war 部署到 Tomcat 服务器,通过将 cas-server-webapp-4.0.0.war 应用程序复制到 ${TOMCAT_HOME}/webapps 文件夹或使用 Tomcat 管理器(如果可用)。在 catalina.out 日志文件中,你应该看到类似的信息:

    INFO: Deploying web application archive /home/user/apps/liferay/liferay-portal-6.2-ce-ga2/tomcat-7.0.42/webapps/cas-server-webapp-4.0.0.war
    

配置 HTTPS 连接

下一个重要步骤是在 Liferay 和 CAS 之间建立 HTTPS 连接。默认情况下,CAS 仅在安全连接上发送单点登录 cookie(CASTGC)。在我们的情况下,我们将使用 Java keytool生成 SSL 证书。Java keytool 是一个密钥和证书管理工具。它允许用户管理自己的公钥/私钥对和证书。基本上,此工具将密钥和证书存储在keystore中。这是一个作为文件实现的存储库,并放置在本地硬盘上。我们的目标是生成一个证书,将其导出为文件,并将其放置在信任库中($JAVA_HOME/jre/lib/security/cacerts)。以下说明设置了 Tomcat 的 keystore 文件,并使用自签名证书(自签名证书绝不应用于开发环境之外的任何用途):

  1. 在任何目录中,输入生成新密钥并将其放入名为keystore.jks的本地密钥库中的命令:

    keytool -genkey -alias tomcat -keypass changeit -keyalg RSA -keystore keystore.jks
    

    注意

    确保您提供了$JAVA_HOME/jre/lib/security/cacerts密钥库密码。两个密码必须相同。

    以下列表显示了密钥生成过程:

    Enter keystore password: 
    Re-enter new password:
    What is your first and last name?
      [Unknown]:  $REPLACE_WITH_FULL_MACHINE_NAME
    What is the name of your organizational unit?
      [Unknown]:  IT
    What is the name of your organization?
      [Unknown]:  Liferay
    What is the name of your City or Locality?
      [Unknown]:  Warsaw
    What is the name of your State or Province?
      [Unknown]:  
    What is the two-letter country code for this unit?
      [Unknown]:  PL
    Is CN=$FULL_MACHINE_NAME, OU=IT, O=Liferay, L=Warsaw, ST=, C=PL correct?
      [no]:  yes
    

    注意

    之前提到的first and last name字段值必须设置为完全限定域名。在 Windows 上,完全限定的机器名显示为完整的计算机名。在 Linux 上,这是主机名。

  2. 将密钥导出到名为tomcat.cert的文件中:

    keytool -export -alias tomcat -keypass changeit -file tomcat.cert -keystore keystore.jks
    
  3. 将密钥导入到$JAVA_HOME/jre/lib/security/cacerts信任库中:

    keytool -import -alias tomcat -file tomcat.cert -keypass changeit -keystore $JAVA_HOME/jre/lib/security/cacerts
    
  4. 检查您的证书是否成功导入到 Java 信任库中:

    keytool -list -v -alias tomcat -keystore $JAVA_HOME/jre/lib/security/cacerts
    
  5. 编辑${TOMCAT_HOME}/conf文件夹中的server.xml文件,取消注释 SSL 部分以打开端口 8443:

    <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true" maxThreads="150" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" />
    

设置 CAS 服务器

在此步骤中,我们将定义一个映射,其中包含可以在我们的 Liferay 系统中进行身份验证的用户。为了实现这一点,请转到${TOMCAT_HOME}/webapps/cas-server-webapp-4.0.0/WEB-INF文件夹,编辑deployerConfigContext.xml,并修改 bean 定义。

通过将用户添加到users属性中来设置用户列表。以下是一个示例:

<bean id="primaryAuthenticationHandler" class="org.jasig.cas.authentication.AcceptUsersAuthenticationHandler">
  <property name="users">
    <map>
      <entry key="casuser" value="Mellon"/>
      <entry key="joebloggs" value="test" />
    </map>
  </property>
</bean>

小贴士

记住必须在 Liferay Portal 中创建用户。

配置 Liferay Portal

最后一步是 Liferay 配置。我们的目标是更改身份验证类型,该类型应基于screenName(登录),并启用 CAS 身份验证方法。为此,请按照以下步骤操作:

  1. 在 Liferay 中,根据screenName(登录)设置身份验证类型。门户可以根据用户的电子邮件地址、screenNameuserId对用户进行身份验证。更改默认选项,并在${liferay.home}/portal-ext.properties中设置新的身份验证类型值:

    company.security.auth.type=screenName
    
  2. 通过在${liferay.home}/portal-ext.properties中设置特定属性来启用 CAS 身份验证:

    cas.auth.enabled=true
    cas.import.from.ldap=false
    cas.login.url=https://localhost:8443/cas-server-webapp-4.0.0/login
    cas.logout.url=https://localhost:8443/cas-server-webapp-4.0.0/logout
    cas.server.name=localhost:8443
    cas.server.url=https://localhost:8443/cas-server-webapp-4.0.0
    cas.no.such.user.redirect.url=https://localhost:8443
    cas.logout.on.session.expiration=false
    
  3. 启动 CAS 服务器和 Liferay。当主页加载时,单击登录链接。系统应将用户重定向到使用 HTTPS 协议的 CAS 登录页面。

  4. 使用以下凭据尝试进行身份验证:

    Login: joebloggs
    Password: test
    

它是如何工作的…

中央认证服务CAS)为应用程序提供单一登录。SSO 的主要目的是只提供一次用户凭据,并允许他们访问所有支持 SSO 协议的客户端应用程序。因此,CAS 分为两部分:CAS 客户端和 CAS 服务器。为了清晰起见,这意味着 CAS 客户端组件(jar)放置在 Liferay 库中,而 CAS 服务器是一个独立的应用程序。CAS 服务器负责认证用户。CAS 客户端获取并保护授予用户的身份。客户端和服务器之间的通信可以通过四种协议实现:

  • CAS 3.0(默认启用)

  • SAML 1.1

  • OpenID

  • OAuth(1.0,2.0)

让我们逐步分析登录过程:

  1. 用户在 Liferay 网站上点击登录按钮。系统将用户重定向到https://localhost:8443/cas-server-webapp-4.0.0/login?service=https://localhost:8443/c/portal/login的 CAS 应用程序。

  2. 用户输入正确的登录名和密码并调用提交操作。CAS 服务器认证用户并设置 CASTGCcookie(例如,CASTGC=TGT-4-HASH-cas01.example.org)。然后,认证后的用户带着服务票据(ST)参数返回到 Liferay:https://localhost:8443/c/portal/login?ticket=ST-6-HASH-cas01.example.org

  3. 下一步是调用验证。这是一个后台过程,通过后端通道通信发送 GET 请求,并获取包含用户详细信息的 XML 响应:https://localhost:8443/cas-server-webapp-4.0.0/proxyValidate?{PARAMETERS}

  4. 用户成功登录到 Liferay 系统。

在 Liferay 中,有两个类实现了 CAS 认证:

  • com.liferay.portal.servlet.filters.sso.cas.CASFilter

  • com.liferay.portal.security.auth.CASAutoLogin

CASFilter负责 CAS 认证过程,特别是登录操作。最重要的代码片段调用验证:

TicketValidator ticketValidator = getTicketValidator(companyId);
Assertion assertion = ticketValidator.validate(ticket, serviceUrl);
if (assertion != null) {
  AttributePrincipal attributePrincipal = assertion.getPrincipal();
  login = attributePrincipal.getName();
  session.setAttribute(WebKeys.CAS_LOGIN, login);
}

过滤器验证票据并将登录设置为会话属性。

CASAutoLogin读取会话CAS_LOGIN属性并尝试在数据库中找到用户。如果用户存在于数据库中,AutoLogin过程将返回用户的凭据并成功将其登录到 Liferay 门户。

没有任何外部认证处理器的 CAS 服务器是无用的。因此,以下菜谱将展示如何集成 CAS 服务器和 Liferay 用户数据库或 LDAP 服务器。

参见

更多关于 CAS 和 LDAP 配置的信息,请参考以下菜谱:

  • CAS 与 Liferay 用户数据库

  • Liferay 与 LDAP 集成

  • 神奇的三元组:Liferay、CAS 和 LDAP

CAS 与 Liferay 用户数据库

以下配方展示了一个如何使用 Liferay 用户功能以便由 CAS 服务器进行认证的想法。这个想法可以用作 LDAP 或 Active Directory 系统的替代。在小公司中,如果 Liferay 将成为包含所有用户详情的主要系统,那么以下方式实现 SSO 将是一个很好的概念:

  • Liferay 向 CAS 服务器提供用户详情,如登录名和密码

  • 当用户尝试登录 Liferay 门户时,CAS 服务器会向 Liferay 数据库查询并检查用户数据的正确性

准备工作

此配方是前一个配方的延续。为了准备就绪,请检查 CAS 服务器是否正确安装并且正在与 Liferay(CAS 客户端)通信。要检查它,请尝试通过调用https://localhost:8443/cas-server-webapp-4.0.0/login以默认 Liferay 用户身份通过 CAS 进行身份验证。

如何操作…

从 6.2 版本开始,Liferay 使用 PBKDF2WithHmacSHA1/160/128000 算法进行密码加密。为了配置 CAS 服务器而不进行任何自定义,必须更改密码加密(例如,SHA 算法)。

注意

警告!更改加密对现有账户是危险的。数据库中存储的所有密码都将丢失。如果发生这种情况,必须为每个用户设置新密码。

为了配置 CAS 服务器与 Liferay 数据库一起工作,请按照以下步骤操作:

  1. 将以下库添加到${TOMCAT_HOME}/webapps/cas-server-webapp-4.0.0/WEB-INF/lib目录下:

    • c3p0(例如,c3p0-0.9.1.2.jar):从github.com/swaldman/c3p0下载

    • cas-server-support-jdbc-4.0.0.jar:从cas-server-4.0.0/modules/复制

  2. 通过在${liferay.home}/portal-ext.properties中设置新密码来更改密码加密:

    passwords.encryption.algorithm=SHA
    passwords.digest.encoding=hex
    
  3. 在 CAS 服务器中设置passwordEncoder bean。打开${TOMCAT_HOME}/webapps/cas-server-webapp-4.0.0/WEB-INF/deployerConfigContext.xml并定义 bean:

    <bean id="passwordEncoder" class="org.jasig.cas.authentication.handler.DefaultPasswordEncoder"
    c:encodingAlgorithm="SHA1"
    p:characterEncoding="UTF-8" />
    
  4. 最后,需要在deployerConfigContext.xml中设置dataSource并更改primaryAuthenticationHandler

    • 设置一个新的 bean,其id="dataSource"

      <bean id="dataSource"
      class="com.mchange.v2.c3p0.ComboPooledDataSource"
      p:driverClass="org.mysql.jdbc.driver"
      p:jdbcUrl="jdbc:mysql://HOST:3306/lportal?useUnicode=true&amp;characterEncoding=UTF-8"
      p:user="USERNAME"
      p:password="PASSWORD"
      p:initialPoolSize="6"
      p:minPoolSize="6"
      p:maxPoolSize="18"
      p:maxIdleTimeExcessConnections="120"
      p:checkoutTimeout="10000"
      p:acquireIncrement="6"
      p:acquireRetryAttempts="5"
      p:acquireRetryDelay="2000"
      p:idleConnectionTestPeriod="30"
      p:preferredTestQuery="1" />
      
    • 查找并更改具有id="primaryAuthenticationHandler"的 bean:

      <bean id="primaryAuthenticationHandler" class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler"
      p:dataSource-ref="dataSource"
      p:passwordEncoder-ref="passwordEncoder"
      p:sql="select password_ from User_ where screenName=? and status=0" />
      
      

它是如何工作的…

CAS 服务器支持许多常见的认证系统,如数据库、LDAP、OpenID、OAuth、Radius、Windows(NTLM)等。在这个配方中,我们已经展示了一个示例配置,其中 Liferay 数据库向 CAS 服务器提供用户详情。这种处理器称为QueryDatabaseAuthenticationHandler。CAS 还提供了两个其他数据库处理器,称为SearchModeSearchDatabaseAuthenticationHandlerBindModeSearchDatabaseAuthenticationHandler。有关这些处理器的信息,请参阅github.com/Jasig/cas/wiki/Configuring-Authentication-Components

如开头所述,Liferay 和 CAS 必须使用相同的密码加密算法(SHA1)。必须相同,因为 CAS 服务器通过比较(散列的)用户的密码与数据库中存储的密码来验证用户。为了定义数据库连接,有必要创建一个名为dataSource的新 bean。

最后也是最重要的一步是使用以下查询定义处理程序:

select password_ from User_ where screenName=? and status=0

此查询返回由 Liferay 用户数据库通过 SHA1 算法加密的密码。正确比较编码的密码并验证用户就足够了。

还有更多…

许多系统通过电子邮件地址而不是screenName(登录名)提供认证。默认情况下,Liferay 实现了这种认证。所以,让我们更改之前的食谱并部署电子邮件认证。为了实现它,有两个步骤:

  1. ${liferay.home}/portal-ext.properties中更改认证类型:

    company.security.auth.type=emailAddress.
    
  2. 在 CAS 的deployerConfigContext.xml文件中修改primaryAuthenticationHandler

    <bean id="primaryAuthenticationHandler" class="org.jasig.cas.adaptors.jdbc.SearchModeSearchDatabaseAuthenticationHandler">
      <property name="tableUsers">
        <value>User_</value>
      </property>
      <property name="fieldUser">
        <value>emailAddress</value>
      </property>
      <property name="fieldPassword">
        <value>password_</value>
      </property>
      <property name="passwordEncoder" ref="passwordEncoder" />
      <property name="dataSource" ref="dataSource"></property>
    </bean>
    

在这个时候,我们决定使用一个名为SearchModeSearchDatabaseAuthenticationHandler的不同authenticationHandler来展示多种实现数据库通信的可能方式。

第二个非常重要的事实是,出于安全考虑,不使用 SALT 的 SHA1 或 MD5 算法不是一个好主意。此外,Liferay 开发者决定使用非常强大的加密:

"PBKDF2(基于密码的密钥派生函数 2)是 RSA 的 PKCS(公钥加密标准)系列的一部分:PKCS #5,版本 2.0。它也在 IETF 的 RFC 2898 中描述。PBKDF2WithHmacSHA1/160/128000 算法使用基于密钥的哈希消息认证码,使用 SHA-1 生成 160 位哈希,并使用 128,000 轮。"

如果有人想在 CAS 服务器中使用相同的算法,则必须实现新的passwordEncoder并在 CAS 的deployerConfigContext.xml中定义它:

<bean id="passwordEncoder" class="com.example.LiferayPasswordEncoder"
  c:encodingAlgorithm="PBKDF2WithHmacSHA1/160/128000"
  p:characterEncoding="UTF-8" />

LiferayPasswordEncoder必须实现org.jasig.cas.authentication.handler.PasswordEncoder接口。

参见

关于 CAS 和 LDAP 的信息,请参考Liferay 和 LDAP 集成神奇三重奏:Liferay、CAS 和 LDAP食谱。

Liferay 和 LDAP 集成

在许多公司中,LDAP(OpenLDAP、Active Directory 或其他 LDAP 实现)是保存用户详细信息(尤其是登录、密码、电子邮件地址、姓名和姓氏)的系统。将 Liferay 与 LDAP 集成是一个好主意。幸运的是,Liferay 开发者已经考虑到了这一点。Liferay 提供开箱即用的功能,可以读取和从 LDAP 导入用户。

准备工作

要开始配置,您需要正确安装 LDAP 服务器,如 OpenLDAP 或 Active Directory,或 ApacheDS。作为一个集成示例,它将作为在线的 LDAP 测试服务器使用:

  • 服务器:ldap.forumsys.com

  • 端口:389

  • 绑定 DN:cn=read-only-admin,dc=example,dc=com

  • 绑定密码:password

  • 所有用户密码都是:password

如何操作…

有两种配置方式:通过 GUI 或通过门户属性。在这种情况下,我们将通过控制面板展示配置。

  1. 以超级管理员身份登录您的 Liferay 实例(默认为joebloggs/test)。

  2. 前往 管理 | 控制面板 | 配置 | 门户设置 | 身份验证

  3. 选择LDAP标签。

  4. 选择启用选项。

  5. 在 LDAP 服务器部分点击添加按钮。

  6. 使用以下数据填写表单:

    • 服务器名称<YOUR_SERVER_NAME>(例如,ldap.forumsys.com)。

    • 默认值<CHOOSE ONE OF THEM>(例如,其他目录服务器)。

    • 连接部分:这些设置包含到 LDAP 的基本连接。

    • 基础提供者 URL<ldap://host:port>(例如,ldap://ldap.forumsys.com:389)。

    • 基础 DN<区分名称>(例如,dc=example,dc=com)。

    • 主体<LDAP 管理员 ID>(例如,cn=read-only-admin,dc=example,dc=com)。

    • 凭据<LDAP 管理员密码>(在我们的例子中是password)。

    • 检查配置并点击测试 LDAP 连接按钮。它应该显示以下消息:

      Liferay 已成功连接到 LDAP 服务器

    • 用户部分:这些设置涵盖搜索过滤器和用户映射功能。

      注意

      此表单中的值严格依赖于 LDAP 目录模式。管理员应知道哪些 LDAP 字段可以映射为 Liferay 值。

    • 身份验证搜索过滤器<用户登录搜索条件>(例如,(uid=@screen_name@))。

    • 导入搜索过滤器<识别用户的方式>(例如,(objectClass=inetOrgPerson))。

    • 用户映射部分(将 LDAP 属性映射为 Liferay 值):

      屏幕名称 = uid

      电子邮件地址 = mail

      密码 = userPassword

      姓名 = cn

      姓氏 = sn

    配置完成后,尝试通过点击测试 LDAP 用户来检查正确性。系统应列出 LDAP 目录中的用户。

    • 组部分:这些设置将 LDAP 用户组映射到 Liferay 用户组。不需要填写此表单。如果管理员想要配置它,步骤与之前显示的示例非常相似。可能存在导入搜索过滤器字段的问题。通常有(objectClass=groupOfNames)(objectClass=groupOfUniqueNames)值。
  7. 保存LDAP 服务器门户设置表单。

  8. 注销并尝试以 LDAP 用户身份登录,例如newton/password

注意

在 GUI 中不可用的参数有几个。如果配置出现问题,请检查键前缀为ldap.*下的portal.properties文件。LDAP 配置是一个庞大的主题,可能难以理解和正确配置。

它是如何工作的…

Liferay 提供了一个身份验证管道机制,允许您定义多种身份验证类型。默认情况下,有一个启用的LdapAuth身份验证器,如下所示:

 auth.pipeline.pre=com.liferay.portal.security.auth.LDAPAuth

通常,每个登录过程,而不是默认认证,都会尝试调用在 auth.pipeline.pre 中定义的认证器列表。如果任何认证器返回成功,则表示用户已正确登录到 Liferay 门户。

LDAPAuth 类实现了 com.liferay.portal.security.auth.Authenticator 接口,该接口提供了以下方法:

  • authenticateByEmailAddress

  • authenticateByScreenName

  • authenticateByUserId

为了与 LDAP 服务器通信,Liferay 使用 javax.naming.ldap 包中的类。它提供了对 LDAPv3 扩展操作和控制的支持。

魔法三人组:Liferay、CAS 和 LDAP

下一挑战是连接 Liferay、CAS 和 LDAP 认证。在这个组合中,CAS 系统提供单点登录机制,LDAP 系统存储用户的凭证,Liferay 使用这两个系统来认证来自 LDAP 的用户。这种配置在许多部署中使用。此外,我们敢说,当人们在公司内思考内部网时,它应该被视为一个标准解决方案。

准备工作

研究之前解释的 与 CAS SSO 集成Liferay 与 LDAP 集成 菜单。根据这些菜单设置系统。检查 Liferay 到 LDAP 服务器的连接,并验证 CAS 认证是否已启用。

如何操作…

要将 Liferay 与 CAS 服务器集成,其中 LDAP 是认证提供者,请按照以下步骤操作:

  1. 找到从 downloads.jasig.org/cas/ 下载的 CAS 服务器存档。将 cas-server-4.0.0/modules/cas-server-support-ldap-4.0.0.jar 复制到 ${TOMCAT_HOME}/webapps/cas-server-webapp-4.0.0/WEB-INF/lib 目录中。

  2. 默认情况下,CAS 使用 ldaptive 库与 LDAP 进行通信。下载 ldaptive.jar (central.maven.org/maven2/org/ldaptive/ldaptive/1.0.3/ldaptive-1.0.3.jar) 并将此存档放置在 ${TOMCAT_HOME} /webapps/cas-server-webapp-4.0.0/WEB-INF/lib 目录中。

  3. 打开 ${TOMCAT_HOME}/webapps/cas-server-webapp-4.0.0/WEB-INF/deployerConfigContext.xml 文件并指定以下 Bean:

    首先,定义将作为主要认证处理器的 Bean,并将其设置为 LDAP 认证。

    注意

    确保您没有使用先前配置的数据库认证处理器。

    主要认证处理器包含 LDAP 和 CAS 之间的映射字段。键是 LDAP 属性名称,值是 CAS 属性名称。此定义引用了将在下一节中描述的认证器 Bean:

    <bean id="primaryAuthenticationHandler"
          class="org.jasig.cas.authentication.LdapAuthenticationHandler"
          p:principalIdAttribute="uid"
          c:authenticator-ref="authenticator">
        <property name="principalAttributeMap">
          <map>
            <entry key="uid" value="username" />
            <entry key="givenname" value="first_name" />
            <entry key="sn" value="last_name" />
            <entry key="mail" value="email" />
          </map>
        </property>
    </bean>
    

    认证器 Bean 定义了认证方法。它包含对 DN(区分名称)解析器和认证处理器的引用,该处理器负责建立连接。它应包含在我们的 deployerConfigContext.xml 文件中:

    <bean id="authenticator" class="org.ldaptive.auth.Authenticator"
          c:resolver-ref="dnResolver"
          c:handler-ref="authHandler" />
    

    被区分名称解析器定义了解析实现。在这种情况下,使用FormatDnResolver

    <bean id="dnResolver"
          class="org.ldaptive.auth.FormatDnResolver"
          c:format="uid=%s,${ldap.authn.baseDn}" />
    

    接下来,bean 定义负责与 LDAP 建立连接。有许多设置,这些设置在ldaptive库文档中有描述:

    <bean id="authHandler" class="org.ldaptive.auth.PooledBindAuthenticationHandler"
      p:connectionFactory-ref="pooledLdapConnectionFactory" />
    
    <bean id="pooledLdapConnectionFactory"
      class="org.ldaptive.pool.PooledConnectionFactory"
      p:connectionPool-ref="connectionPool" />
    
    <bean id="connectionPool"
      class="org.ldaptive.pool.BlockingConnectionPool"
      init-method="initialize"
      p:poolConfig-ref="ldapPoolConfig"
      p:blockWaitTime="${ldap.pool.blockWaitTime}"
      p:validator-ref="searchValidator"
      p:pruneStrategy-ref="pruneStrategy"
      p:connectionFactory-ref="connectionFactory" />
    
    <bean id="ldapPoolConfig"   class="org.ldaptive.pool.PoolConfig"
    p:minPoolSize="${ldap.pool.minSize}"
    p:maxPoolSize="${ldap.pool.maxSize}"
    p:validateOnCheckOut="${ldap.pool.validateOnCheckout}"           p:validatePeriodically="${ldap.pool.validatePeriodically}"
    p:validatePeriod="${ldap.pool.validatePeriod}" />
    
    <bean id="connectionFactory" class="org.ldaptive.DefaultConnectionFactory"
      p:connectionConfig-ref="connectionConfig" />
    
    <bean id="connectionConfig" class="org.ldaptive.ConnectionConfig"
      p:ldapUrl="${ldap.url}"
      p:connectTimeout="${ldap.connectTimeout}"
      />
    
    <bean id="pruneStrategy" class="org.ldaptive.pool.IdlePruneStrategy"
      p:prunePeriod="${ldap.pool.prunePeriod}"
      p:idleTime="${ldap.pool.idleTime}" />
    
    <bean id="searchValidator" class="org.ldaptive.pool.SearchValidator" />
    
  4. 将以下属性添加到${TOMCAT_HOME}/webapps/cas-server-webapp-4.0.0/WEB-INF/cas.properties文件中:

    #========================================
    # General properties
    #========================================
    ldap.url=ldap://ldap.forumsys.com
    
    # LDAP connection timeout in milliseconds
    ldap.connectTimeout=3000
    
    # Whether to use StartTLS (probably needed if not SSL connection)
    ldap.useStartTLS=false
    
    #========================================
    # LDAP connection pool configuration
    #========================================
    ldap.pool.minSize=3
    ldap.pool.maxSize=10
    ldap.pool.validateOnCheckout=false
    ldap.pool.validatePeriodically=true
    
    # Amount of time in milliseconds to block on pool  
    # exhausted condition before giving up.
    ldap.pool.blockWaitTime=3000
    
    # Frequency of connection validation in seconds
    # Only applies if validatePeriodically=true
    ldap.pool.validatePeriod=300
    
    # Attempt to prune connections every N seconds
    ldap.pool.prunePeriod=300
    
    # Maximum amount of time an idle connection is allowed to #be in pool before it is liable to be removed/destroyed
    ldap.pool.idleTime=600
    
    #========================================
    # Authentication
    #========================================
    
    # Base DN of users to be authenticated
    ldap.authn.baseDn=dc=example,dc=com
    
    # Manager DN for authenticated searches
    ldap.authn.managerDN=cn=read-only-admin,dc=example,dc=com
    
    # Manager password for authenticated searches
    ldap.authn.managerPassword=password
    
    # Search filter used for configurations that require searching for DNs
    ldap.authn.searchFilter=(uid={user})
    
    # Search filter used for configurations that require searching for DNs
    ldap.authn.format=uid=%s,dc=example,dc=com
    
    
  5. portal-ext.properties文件中检查是否启用了 CAS 认证:

    cas.auth.enabled=true
    
  6. 重新启动 Tomcat 服务器。

完成之前描述的配置后,应该可以通过 CAS 服务器和 LDAP 用户凭证(登录名和密码)如newton/password来认证 Liferay。

如何工作…

在许多情况下,LDAP 架构的配置是不同的。无法提供灵活的正确配置。在之前提到的配置中,高亮显示的短语是敏感的,应该适应特定的 LDAP 架构。

这个解决方案的最大优点是,只有一个地方存储用户的凭证(LDAP 服务器)和确切的一个地方提供认证机制(CAS SSO)。Liferay 只是这些服务的客户端。

如何工作…

让我们跟随这个流程:

  1. 新用户想要登录到 Liferay 系统。Liferay 没有关于此用户的信息。

  2. Liferay 检查 CAS SSO 是否启用,并将用户重定向到 CAS 认证提供者。

  3. CAS 认证提供者渲染登录表单。

  4. 用户输入 LDAP 登录名和 LDAP 密码,并将请求发送到 CAS 服务器。

  5. CAS 服务器请求 LDAP 服务器凭证并检查 LDAP 的答案。

  6. 如果答案是 OK,CAS 服务器将发送成功消息到 Liferay 认证票据。

  7. Liferay 检查其数据库中是否有该用户。如果没有,它将询问 LDAP 服务器有关用户详情,如登录名、姓名、姓氏、电子邮件地址等。

  8. Liferay 在其数据库中创建账户并成功登录新用户。

参见

  • 关于如何导出 Liferay 用户的信息,请参考第三章中的导出用户配方,与 Liferay 用户/用户组/组织一起工作

  • 关于如何构建可伸缩基础设施的信息,请参考第十二章中的可伸缩基础设施配方,基本性能调整

第三章. 与 Liferay 用户/用户组/组织协作

在本章中,我们将介绍基本功能,使我们能够管理内网的结构和用户。在本章中,我们将涵盖以下主题:

  • 管理组织结构

  • 创建新的用户组

  • 添加新用户

  • 将用户分配给组织

  • 将用户分配给用户组

  • 导出用户

简介

创建内网的第一个步骤,除了回答用户是谁的问题之外,就是确定其结构。内网的结构通常是公司或机构组织结构的衍生。Liferay Portal CMS 提供了几个工具,允许在系统中映射公司的结构。层次结构是通过与公司功能或本地化部门相匹配的组织构建的。每个组织代表一个部门或本地化,并汇集代表这些部门员工的用户。然而,有时公司中还有其他员工群体。这些群体存在于公司的组织结构之外,可以通过用户组功能在系统中反映出来。

管理组织结构

在 Liferay 中构建组织结构类似于在计算机驱动器上管理文件夹的过程。一个组织可以拥有其子组织,并且——除了第一级组织——同时,它也可以是另一个组织的子组织。这种类似文件夹的机制允许您创建组织的树状结构。

让我们假设我们被迫为一家软件开发公司创建一个内网。该公司的总部位于伦敦。还有两个其他办事处在利物浦和格拉斯哥。公司分为财务、市场、销售、IT、人力资源和法律部门。来自格拉斯哥和利物浦的员工属于 IT 部门。

如何操作…

为了创建之前描述的结构,以下是步骤:

  1. 以管理员身份登录并转到管理 | 控制面板 | 用户 | 用户和组织

  2. 点击添加按钮。

  3. 选择您想要创建的组织类型(在我们的示例中,它将是一个名为软件开发公司的普通组织,但也可能选择一个地点):如何操作…

  4. 为顶级组织提供一个名称。

  5. 选择父组织(如果创建了顶级组织,则必须跳过)。

  6. 点击保存按钮:如何操作…

  7. 点击更改按钮并上传一个文件,其中包含您公司的图形表示(例如,标志)。

  8. 使用右侧菜单导航到您想要填写信息的部分。

  9. 点击保存按钮。

  10. 通过点击返回图标(位于编辑软件开发公司标题旁边的左箭头图标)返回用户和组织列表。

  11. 点击位于新创建的组织名称附近操作按钮。

  12. 选择添加常规组织选项。

  13. 为组织提供名称(在我们的例子中,它是 IT)。

  14. 点击保存按钮。

  15. 通过点击返回图标(位于编辑 IT标题旁边的左箭头图标)返回用户和组织列表。

  16. 点击位于新创建的组织名称附近操作按钮(在我们的例子中,它是 IT)。

  17. 选择添加位置选项。

  18. 为组织提供名称(例如,IT 利物浦)。

  19. 提供一个国家。

  20. 提供一个区域(如果有的话)。

  21. 点击保存按钮。

它是如何工作的...

让我们看看在前一个菜谱中我们做了什么。在第 1 步到第 6 步中,我们创建了一个名为软件开发公司的顶级新组织。在第 7 步到第 9 步中,我们定义了新创建组织的属性集。从第 11 步开始,我们创建了子组织:标准组织(IT)及其位置(IT 利物浦)。

创建组织

有两种类型的组织:常规组织和位置。常规组织提供了创建多层结构的能力,每个单位都可以有父组织和子组织(有一个例外:顶级组织不能有任何父组织)。定位是一种特殊的组织类型,允许我们提供一些额外的数据,例如国家和区域。然而,它不能让我们创建子组织。在创建组织树时,可以将常规组织和位置结合起来,例如,顶级组织将是常规组织,同时位置和常规组织都将用作子组织。

备注

在创建新组织时,非常重要的是要明智地选择组织类型,因为这是唯一不能进一步修改的组织参数。

如前所述,组织可以按树状结构排列。组织在树中的位置由父组织参数确定,该参数通过创建新组织或编辑现有组织来设置。如果没有设置父组织,则始终创建顶级组织。

创建子组织有两种方式。可以通过使用添加按钮并手动选择父组织来添加一个新的组织。另一种方式是进入特定组织的操作菜单,并选择添加常规组织操作。使用此选项创建新组织时,父组织参数将自动设置。

设置属性

类似地,就像现实中的对应物一样,Liferay 中的每个组织都有一组属性,这些属性被分组并可以通过组织配置文件表单进行修改。此表单在点击组织操作列表中的编辑按钮后可用(参见更多内容…部分)。所有可用属性分为以下几组:

  • 组织信息组,其中包含以下部分:

    • 详细信息部分,允许我们更改组织名称、父组织、国家或地区(仅适用于位置)。组织名称是唯一的必需组织参数。它被搜索机制用于搜索组织。它也是组织站点 URL 地址的一部分。

    • 组织站点部分,允许我们启用组织的私有和公共页面。

    • 分类部分,它提供标签和分类。可以将它们分配给组织(有关标签和分类的更多信息,请参阅第八章的标签和分类内容配方,搜索和内容展示工具)。

  • 标识,它将地址电话号码附加电子邮件地址网站服务部分分组。

  • 杂项,它包括:

    • 评论部分,允许我们管理组织的评论。

    • 提醒查询部分,其中可以设置不同语言的提醒查询

    • 自定义字段部分,它提供了一个管理组织定义的自定义属性值的工具

定制组织功能

Liferay 提供了定制组织功能的可能性。在portal-impl/src文件夹中位于portal.properties文件中的组织部分。所有这些设置都可以在portal-ext.properties文件中覆盖。我们提到顶级组织不能有任何父组织。如果我们深入研究门户设置,我们可以挖掘出以下属性:

organizations.rootable[regular-Organization]=true
organizations.rootable[location]=false

这些属性确定可以创建为根组织的组织类型。

在许多情况下,用户希望添加一个新的组织类型。为了实现这一目标,需要设置一些描述新类型的属性:

organizations.types=regular-Organization,location,my-Organization
organizations.rootable[my-organization]=false
organizations.children.types[my-organization]=location
organizations.country.enabled[my-organization]=false
organizations.country.required[my-organization]=false

第一个属性定义了一个可用类型的列表。第二个属性禁止以根组织创建组织。下一个属性指定了我们可以创建为子组织的类型列表。在我们的案例中,这仅是位置类型。最后两个属性在创建过程中关闭了国家列表。当位置不重要时,此选项很有用。

另一个有趣的功能是能够自定义组织的个人资料表单。可以指定在创建表单上哪些部分是可用的,以及在修改表单上哪些部分是可用的。以下属性聚合了这一功能:

organizations.form.add.main=details,organization-site
organizations.form.add.identification=
organizations.form.add.miscellaneous=

organizations.form.update.main=details,organization-site,categorization
organizations.form.update.identification=addresses,phone-numbers,additional-email-addresses,websites,services
organizations.form.update.miscellaneous=comments,reminder-queries,custom-fields

还有更多…

也可以修改现有的组织及其属性,并使用组织中的操作菜单中的操作来管理其成员。

可以对组织执行几种可能的操作:

  • 编辑操作使我们能够修改组织的属性。

  • 管理站点操作将用户重定向到控制面板中的站点设置部分,并允许我们管理组织的公共和私有站点(如果组织站点已经创建)。

  • 分配组织角色操作使我们能够为组织的成员设置组织角色。

  • 分配用户操作使我们能够将已经存在于 Liferay 数据库中的用户分配给特定的组织。

  • 添加用户操作使我们能够创建一个新用户,该用户将自动分配到这个特定的组织。

  • 添加常规组织操作使我们能够创建一个新的子常规组织(当前组织将自动设置为新组织的父组织)。

  • 添加位置操作使我们能够创建一个新的位置(当前组织将自动设置为新组织的父组织)。

  • 删除操作使我们能够删除组织。在删除组织时,所有包含端口和内容的页面也将被删除。

注意

如果有子组织或用户分配给组织,则无法删除组织。

为了编辑组织、分配或添加用户、创建新的子组织(常规组织或位置)或删除组织,请执行以下步骤:

  1. 以管理员身份登录并转到管理 | 控制面板 | 用户 | 用户和组织

  2. 点击你想要修改的组织名称附近的操作按钮:还有更多…

  3. 点击所选操作的名称。

参见

关于组织站点信息,请参阅第四章中关于创建组织和独立站点以及站点配置的配方,来自Liferay 站点配置

创建新的用户组

有时,除了层次结构之外,在公司内部,还有其他由共同兴趣或职业联系在一起的人群,例如从事特定项目的人、担任相同职位的人等等。在 Liferay 中,这些群体由用户组表示。此功能类似于 LDAP 用户组,其中可以设置组权限。一个用户可以被分配到多个用户组中。

如何操作…

为了创建一个新的用户组,请按照以下步骤操作:

  1. 以管理员身份登录并前往管理 | 控制面板 | 用户 | 用户组

  2. 点击添加按钮。

  3. 提供用户组的名称(必需)和描述

  4. 用户组站点部分保留默认值。如何操作…

  5. 点击保存按钮。

它是如何工作的…

用户组功能允许我们创建用户集合,并为它们提供一个公共和/或私有站点,这些站点包含一系列协作工具。与组织不同,用户组不能用来创建多级结构。它使我们能够创建非层次结构的用户组,这些用户组可以被其他功能使用。例如,用户组可以用作公告插件的附加信息定位工具,该插件展示由授权用户发送的简短消息(公告插件允许我们将消息定向到来自特定组织或用户组的所有用户)。

还可以为用户组设置权限,并决定在此特定用户组内哪些角色可以执行哪些操作。

值得注意的是,用户组可以聚集已经是组织成员的用户。这种机制通常用于除了公司组织结构之外,还存在其他需要共同存储数据或进行信息交流的人群时。

更多…

还可以修改现有的用户组及其属性,并使用用户组操作菜单中的操作来管理其成员。

可以对用户组执行几种可能的操作。具体如下:

  • 编辑操作允许我们修改用户组的属性

  • 权限操作允许我们决定哪些角色可以分配此用户组的成员、删除用户组、管理公告、设置权限、更新或查看用户组

  • 管理站点页面操作将用户重定向到控制面板中的站点设置部分,并允许我们管理用户组的公共和私有站点

  • 转到站点的公共页面操作在新窗口中打开用户组的公共页面(如果已创建用户组站点的公共页面)

  • 转到站点的私有页面操作在新窗口中打开用户组的私有页面(如果已创建用户组站点的公共页面)

  • 分配成员操作允许我们将已经存在于 Liferay 数据库中的用户分配到这个特定的用户组

  • 删除操作允许我们删除用户组

注意

如果有用户被分配到用户组,则无法删除该用户组。

为了编辑用户组、设置权限、分配成员、管理站点页面或删除用户组,请执行以下步骤:

  1. 前往管理 | 控制面板 | 用户 | 用户组

  2. 点击位于您想要修改的用户组名称附近的操作按钮:更多…

  3. 点击所选操作的名称。

参见

关于用户组站点的信息,请参阅第四章中的创建组织和独立站点站点配置食谱,Liferay 站点配置

添加新用户

每个系统都是为用户创建的。Liferay Portal CMS 提供了一些不同的方法来向系统添加用户,这些方法可以根据需求启用或禁用,如第二章中所述,认证和注册过程。第一种方法是启用用户通过创建自己的账户来创建账户。此功能允许所有可以进入包含表单的站点的用户注册并获得访问网站指定内容的权限。在这种情况下,系统自动分配默认用户账户参数,这些参数表示他们在系统中可能执行的活动范围。第二种解决方案(我们在本食谱中介绍了)是将用户账户创建保留给管理员,管理员将决定应分配给每个账户的参数。

如何操作…

要添加新用户,您需要遵循以下步骤:

  1. 以管理员身份登录并转到管理 | 控制面板 | 用户 | 用户和组织

  2. 点击添加按钮。

  3. 选择用户选项。

  4. 通过在电子邮件地址(必填)标题名(必填)中间名后缀生日职位字段中提供用户的详细信息来填写表格(如果门户设置 | 用户部分中的自动生成用户屏幕名称选项被禁用,则屏幕名称字段将可用):如何操作…

  5. 点击保存按钮:如何操作…

  6. 使用右侧菜单导航到您想要填写信息的数据库部分。

  7. 点击保存按钮。

它是如何工作的…

在步骤 1 到 5 中,我们创建了一个新用户。通过步骤 6 和 7,我们定义了新创建用户的一组属性。此用户是活跃的,并且可以根据其成员资格和角色执行活动。要了解影响用户在系统中可能行为的所有机制,我们必须深入了解这些属性。

用户作为组织、用户组和站点的成员

关于用户的第一件和最重要的事情是,他们可以是组织、用户组和站点的成员。用户在其所属的每个组织、用户组或站点中执行的活动范围由分配给他们的角色决定。必须为组织中的每个用户和站点的每个用户单独分配所有角色。这意味着,例如,可以将用户指定为一个组织的管理员,而仅将其指定为另一个组织的强力用户。

用户属性

Liferay 中的每个用户都有一组属性,这些属性被分组,并且可以通过用户配置文件表单进行修改。此表单在点击用户操作列表中的编辑按钮后可用(参见更多内容…部分)。

所有可用的属性分为以下几组:

  • 用户信息,包含以下部分:

    • 详细信息部分使我们能够提供基本用户信息,例如屏幕名称电子邮件地址标题名字中间名姓氏后缀生日职位头像

    • 密码部分允许我们设置新密码或强制用户更改当前密码

    • 组织部分使我们能够选择用户是成员的组织

    • 网站部分使我们能够选择用户是成员的网站

    • 用户组部分使我们能够选择用户是成员的用户组

    • 角色选项卡允许我们分配用户角色

    • 个人网站部分帮助将公众和私人网站导向用户

    • 分类部分提供标签和分类,可以分配给用户

  • 身份验证允许我们设置额外的用户信息,例如地址电话号码附加电子邮件地址网站即时消息社交网络短信OpenID

  • 杂项,包含以下部分:

    • 公告部分允许我们设置警报和公告的投递选项

    • 显示设置部分涵盖了语言时区问候语文本选项

    • 评论部分允许我们管理用户的评论

    • 自定义字段部分提供了一个工具来管理为用户定义的自定义属性值

用户网站

如前所述,Liferay 中的每个用户都可能访问不同类型的网站:组织网站、用户组网站和独立网站。然而,除此之外,用户还可以拥有自己的公共和私人网站,这些网站可以由他们自己管理。用户的公共和私人网站可以通过位于工具栏上的用户菜单(我的个人资料我的仪表板链接)访问。也可以使用它们的地址进入这些网站,分别是/web/username/home/user/username/home

自定义用户

Liferay 在用户部分下提供了portal.properties文件中的大量设置。如果您想覆盖一些属性,请将它们放入portal-ext.properties文件中。

通过设置以下属性,可以阻止删除用户:

users.delete=false

与组织的情况一样,有一个功能允许我们在创建或修改表单上自定义部分:

users.form.add.main=details,Organizations,personal-site
users.form.add.identification=
users.form.add.miscellaneous=

users.form.update.main=details,password,Organizations,sites,user-groups,roles,personal-site,categorization
users.form.update.identification=addresses,phone-numbers,additional-email-addresses,websites,instant-messenger,social-network,sms,open-id
users.form.update.miscellaneous=announcements,display-settings,comments,custom-fields

有许多其他属性,但我们不会讨论所有这些。在portal.properties文件中,位于portal-impl/src文件夹下,在用户部分,可以找到所有设置,并且每一行都有注释进行说明。

更多信息...

系统中的每个用户都可以是活跃的或非活跃的。活跃用户可以登录到他们的用户账户,并使用他们在其角色和成员资格内可用的所有资源。非活跃用户不能进入他的账户,访问特定区域和执行活动,这些活动仅限于授权和认证的用户。

值得注意的是,活跃用户不能被删除。要从 Liferay 中删除用户,您需要先停用他们。

要停用用户,请按照以下步骤操作:

  1. 以管理员身份登录并转到管理 | 控制面板 | 用户 | 用户和组织

  2. 点击用户名称附近的位置的操作按钮。

  3. 前往所有用户选项卡。

  4. 找到您想要停用的活跃用户。

  5. 点击停用按钮。

  6. 通过点击确定按钮确认此操作。

要激活用户,请按照以下步骤操作:

  1. 以管理员身份登录并转到管理 | 控制面板 | 用户 | 用户和组织

  2. 前往所有用户选项卡。

  3. 找到您想要激活的不活跃用户。

  4. 点击用户名称附近的位置的操作按钮。

  5. 点击激活按钮。

有时,当使用系统时,用户会报告一些异常或有些困惑,需要帮助。您需要从用户的角度查看页面。Liferay 提供了一个非常有用的功能,允许授权用户模拟其他用户。为了使用此功能,请执行以下步骤:

  1. 以管理员身份登录并转到控制面板 | 用户 | 用户和组织

  2. 点击用户名称附近的位置的操作按钮。

  3. 点击模拟用户按钮。

参见

  • 有关用户可以执行的操作的更多信息,请参阅第五章的分配用户角色配方,角色和权限以及第九章的用户创建过程的单一审批者工作流配方,Liferay 工作流功能

  • 有关如何自定义和使用用户注册表单的信息,请参阅第二章的自定义注册表单配方,认证和注册过程

  • 有关管理用户的更多信息,请参阅以下配方

    • 本章的导出用户配方

    • 第五章的分配用户角色配方。

    • 来自第二章的自定义注册表单配方,认证和注册过程

将用户分配给组织

用户可以以多种方式被分配到组织。可以通过编辑已创建的用户账户来完成(请参阅添加新用户配方中的用户属性部分)或使用组织操作菜单中的分配用户操作。在本配方中,我们将向您展示如何使用组织操作菜单中的选项将用户分配给组织。

准备工作

要完成此配方,您需要一个组织和用户(参考本章中的管理组织结构添加新用户配方)。

如何操作…

为了将用户从组织菜单分配到组织,请按照以下步骤操作:

  1. 以管理员身份登录并转到Admin | 控制面板 | 用户 | 用户和组织

  2. 点击位于您想要分配用户的组织名称附近的操作按钮。

  3. 选择分配用户选项。

  4. 点击可用选项卡。

  5. 标记您想要分配的用户或用户组。如何操作…

  6. 点击更新关联按钮。

它是如何工作的…

Liferay 中的每个用户都可以被分配到所需的任何常规组织,并且恰好一个位置。当用户被分配到组织时,他们会在组织的用户列表中显示。他们成为组织的成员,并根据分配的角色和权限访问组织的公共和私有页面。正如前一个配方所示,在编辑组织菜单中分配用户的列表时,可以分配多个用户。

值得注意的是,管理员可以分配她或他可以管理的组织和子组织的任务。要允许组织的任何管理员将任何用户分配给该组织,请在portal-ext.properties文件中设置以下属性:

Organizations.assignment.strict=true

在许多情况下,当我们的组织具有树状结构时,子组织的成员不需要访问祖先组织。要禁用此结构,请设置以下属性:

Organizations.membership.strict=true

参见

  • 关于如何创建用户账户的信息,请参阅

    • 本章的添加新用户配方

    • 来自第二章的自定义注册表单配方,认证和注册过程

  • 关于将用户分配给用户组的信息,请参阅本章的将用户分配给用户组配方

将用户分配给用户组

除了是组织的成员外,每个用户还可以成为一个或多个用户组的成员。作为用户组的成员,用户可以通过访问用户组的网站或其他仅针对其成员提供的信息(例如,公告插件的发送的消息)来受益。当用户被分配到该组时,他们成为该组的成员。这种分配可以通过编辑已创建的用户账户来完成(请参阅添加新用户配方中的用户属性描述)或使用用户组操作菜单中的分配成员操作。在本配方中,我们将向您展示如何使用用户组操作菜单中的选项将用户分配到用户组。

准备工作

要逐步完成此配方,首先,您必须创建一个用户组和用户(请参阅创建新用户组添加新用户配方)。

如何操作…

为了从用户组菜单将用户分配到用户组,请执行以下步骤:

  1. 以管理员身份登录并转到Admin | 控制面板 | 用户 | 用户组

  2. 点击您想要分配用户的用户组名称附近的位置的操作按钮。

  3. 点击分配成员按钮。

  4. 点击可用选项卡。如何操作…

  5. 标记您想要分配的用户或用户组。

  6. 点击更新关联按钮。

工作原理…

如本配方所示,可以通过编辑用户组菜单中分配用户的列表将一个或多个用户分配到用户组。分配给用户组的每个用户都成为该组的成员,并根据分配的角色和权限访问用户组的公共和私有页面。

相关信息

  • 关于如何创建用户账户的信息,请参阅

    • 本章的添加新用户配方

    • 第二章的自定义注册表单配方,认证和注册过程

  • 关于如何将用户分配到组织的信息,请参阅本章的将用户分配到组织配方

导出用户

Liferay Portal CMS 提供了一个简单的导出机制,允许我们将数据库中存储的所有用户列表或特定组织中的所有用户列表导出到一个文件中。

如何操作…

为了将数据库中所有用户的列表导出到文件,请按照以下步骤操作:

  1. 以管理员身份登录并转到Admin | 控制面板 | 用户 | 用户和组织

  2. 点击导出用户按钮。如何操作…

为了将特定组织的所有用户列表导出到文件,请按照以下步骤操作:

  1. 以管理员身份登录并转到Admin | 控制面板 | 用户 | 用户和组织

  2. 点击所有组织选项卡。

  3. 点击用户应导出的组织的名称。

  4. 点击导出用户按钮。

它是如何工作的…

如前所述,Liferay 允许我们将特定组织的用户导出为 .csv 文件。该 .csv 文件包含用户名和相应的电子邮件地址列表。您也可以通过点击位于所有用户选项卡上的导出用户按钮来导出所有用户。您可以通过访问管理 | 控制面板 | 用户 | 用户和组织来找到此选项卡。

参见

  • 关于如何创建用户账户的信息,请参阅

    • 本章的添加新用户配方

    • 来自第二章的自定义注册表单配方,认证和注册流程

  • 关于如何将用户分配给组织的信息,请参阅本章的将用户分配给组织配方

第四章 Liferay 站点配置

在本章中,我们将涵盖以下主题:

  • 创建组织和独立站点

  • 站点配置

  • 为站点创建和自定义公共和私有页面

  • 使用页面模板和站点模板快速创建站点和页面

  • 启用本地实时预览

  • 启用远程实时预览

  • 启用页面版本控制

简介

在前一章中,我们描述了如何使用组织和用户组在内部网络中建模组织结构。我们还讨论了它们的属性,如地址、电话号码、网站、服务等等。有一个属性使得组织和用户组成为 Liferay Portal CMS 非常重要的组成部分。这个属性是站点。站点是一组可能包含应用程序和内容的页面。组织或用户组内的用户可以拥有自己的站点,该站点存储和展示由其用户(文件、文章、日历事件、书签等)产生和发布的信息。也存在一些与任何结构化用户集合无关的站点。在本章中,我们将讨论如何创建、自定义和管理站点。

创建组织和独立站点

每个组织和用户组都可以拥有一个站点,该站点由一组公共和私有页面组成,组织成树状结构。公共页面是任何人只要拥有站点链接就可以访问的页面。私有页面是只有登录用户,即组织、用户组或独立站点的成员才能访问的页面。还可以创建一个未分配给任何组织或用户组的独立站点。独立站点还可以形成类似于前一章中描述的组织结构(例如,可以有一个顶级站点,它有子站点)。组织站点通常创建用于存储和展示内容,并为来自特定部门或公司本地化的用户提供工具。用户组站点将共享共同兴趣或属于同一项目团队的人使用的信息和工具分组。独立站点或站点结构用于在组织结构之外提供站点或站点组,这对于不同用户组的成员来说是常见的。

如何操作…

在这个菜谱中,我们将向您展示如何创建组织站点和独立站点。用户组站点是在设置用户组时创建的。与组织不同,没有站点无法创建用户组。

为了为现有组织创建站点,执行以下步骤:

  1. 以管理员身份登录并转到管理 | 控制面板 | 用户| 用户和组织

  2. 点击位于您想要修改的组织名称附近的操作按钮。

  3. 选择编辑选项。

  4. 在右侧菜单中点击组织站点链接。

  5. 选择创建站点复选框:如何操作…

  6. 点击保存按钮。

为了创建一个独立的站点,执行以下步骤:

  1. 以管理员身份登录并转到管理 | 控制面板 | 站点

  2. 点击添加按钮。

  3. 选择空白站点选项。如何操作…

  4. 为站点提供名称(必需)描述

  5. 启用活动选项。

  6. 选择会员类型

  7. 启用允许手动会员管理选项。

  8. 选择父站点。

  9. 点击保存按钮。

一旦创建站点,就可以添加页面,在它们上放置和配置端口,并展示内容。然而,在添加第一个页面之前,无法进入站点。有关向站点添加页面的更多信息,请参阅为站点创建和自定义私有和公共页面食谱。在添加第一个页面后进入站点,请执行以下步骤:

  1. 转到管理 | 控制面板 | 站点

  2. 点击特定站点名称旁边的操作按钮。

  3. 点击站点管理操作。

  4. 转到页面 | 站点页面部分。

  5. 通过点击公共页面私有页面标签,选择您想要进入的页面集。

  6. 点击公共页面私有页面链接(取决于第 5 步中选择的标签)。

  7. 点击查看页面链接。

您也可以通过输入 URL 来进入站点。默认 URL 地址如下:

  • http://localhost:8080/web/site-name 用于公共页面

  • http://localhost:8080/group/site-name 用于私有页面

它是如何工作的…

在食谱的第一部分,我们创建了一个组织站点。食谱的第二部分描述了如何添加一个独立站点。我们创建的组织和独立站点都是空的,需要我们添加和配置页面和端口。所有组织和独立站点都可以通过访问管理 | 控制面板 | 站点来访问。

活动和非活动站点

每个站点都可以设置为活动状态或非活动状态。活动站点可供用户访问。非活动站点用户无法进入,但它仍然可用,并且可以随时激活。激活选项可以在我们想要暂时关闭站点或需要永久关闭站点同时保留所有内容作为存档时使用。

公共和私有页面及其会员类型

每个组织、用户组或独立网站都由公共和私有页面组成,这些页面组织在两个独立的树中。公共页面是任何人只要有网站链接就可以访问的页面。在 Liferay 中,这些用户被称为访客。私有页面是只有登录用户才能访问的页面,他们是组织、用户组或独立网站的成员。当管理员将他们分配给用户或他们通过“我的网站”面板自行加入时,用户可以成为组织、用户组或独立网站的成员。我的网站面板是管理员可以放置在网站页面上的许多应用程序之一。其主要目的是显示用户是成员的网站,并列出用户可以加入或请求会员资格的其他网站。

用户成为网站成员的方式由会员资格类型定义;该参数可以在添加新网站时指定。

有三种会员资格类型:

  • 公开: 这允许任何用户加入和离开该网站。公开网站显示在“我的网站”面板中。

  • 受限: 在这种会员资格类型中,管理员或所有者管理用户的网站会员资格。尽管用户没有加入网站的能力,但他们可以请求会员资格并自行离开。重要的是他们的会员资格是否可以被管理员授予。受限网站也列在“我的网站”面板中。

    如果用户想加入该网站,他们可以请求会员资格。当用户发送请求或管理员批准请求时,系统会发送一封电子邮件。可以在portal-ext.properties中定义通知模板:

    sites.email.from.name=
    sites.email.from.address=
    
    sites.email.membership.reply.subject=com/liferay/portlet/sites/dependencies/email_membership_reply_subject.tmpl
    sites.email.membership.reply.body=com/liferay/portlet/sites/dependencies/email_membership_reply_body.tmpl
    
    sites.email.membership.request.subject=com/liferay/portlet/sites/dependencies/email_membership_request_subject.tmpl
    sites.email.membership.request.body=com/liferay/portlet/sites/dependencies/email_membership_request_body.tmpl 
    
  • 私有: 拒绝用户加入、请求会员资格或离开网站的机会。用户必须由其管理员手动分配给网站。私有网站不会显示在“我的网站”面板中。

    会员资格类型严格关联到允许手动管理会员资格选项,该选项确定管理员是否可以手动将用户添加到网站或从网站中删除。如果该选项启用(除手动会员管理外),它还允许用户使用“我的网站”面板加入公开网站或请求受限网站的会员资格。默认情况下,该选项对独立网站启用,对组织网站禁用,在网站管理中的用户部分不可用。

创建空网站与使用网站模板创建网站的方式

当创建一个新的站点时,页面树是空的。值得注意的是,当创建一个空站点(如本食谱中所述)时,在添加第一个页面之前无法进入该站点。更重要的是,新创建的站点默认设置为活动状态,这意味着用户可以立即访问它们。然而,可以使用站点模板创建预配置的公共和/或私有页面集,这些模板由预配置的站点组成,可以包含页面、小部件和内容。您可以在使用页面模板和站点模板快速创建站点和页面食谱中找到更多关于模板的信息。

技术视图

从技术角度来看,一个站点是一组布局。在数据库中,每个站点都存储在Group_表中。理解这个概念可能很困难。然而,它是 Liferay 中最重要功能之一。

Liferay 允许管理员在同一服务器上运行多个门户实例。在基本安装中,它被称为 Liferay.com。请记住,门户实例会将其数据与每个门户实例(在同一数据库或不同数据库中)分开存储。

每个门户实例可以聚合许多组:组织、用户组、团队、用户和站点。所有这些设置都有一个不同的groupId,但它们都存储在同一个名为Group_的表中。此外,布局(页面)可以从模板(页面模板或/和站点模板)创建。此外,用户可以有他们的私人页面和公共页面。这些信息也存储在Group_表中。总的来说,Group_包含以下设置:

  • 组(站点)

  • 组织

  • 用户组

  • 用户

  • 团队

  • 布局原型

  • 布局集原型

为了在Group_表中区分这些记录,有两个列:

  • classNameId包含className(类的名称存储在ClassName_)表的 ID

  • classPK是该特定类的键,例如,用户、团队或仅仅是组

每个站点只能有私人页面或公共页面,或两者都有。公共页面对任何人可访问,特别是未登录的用户。私人页面仅对属于此站点的组织的用户可访问。每个都是一组页面(布局),定义了默认主题、语言、标志等。Liferay 将这些信息包含在LayoutSet表中。这些设置是每个布局的默认设置。例如,如果一个布局没有定义主题,这个设置来自LayoutSet

更多...

同样,也可以通过站点操作菜单中的操作来管理站点。

可以在站点上执行几种可能的操作:

  • 站点管理操作将用户重定向到控制面板中的站点设置部分,并允许他们管理组织的公共和私有站点

  • 添加子站点操作允许我们创建子站点

  • 查看子站点操作允许我们浏览子站点的列表。

  • 转到公共页面操作在新窗口中打开站点的公共页面。

  • 转到私有页面操作在新窗口中打开站点的私有页面。

  • 激活操作允许我们激活站点。

  • 停用操作允许我们停用站点。

  • 删除操作允许我们删除一个站点。

  • 离开操作允许用户离开站点。此选项仅当用户是站点的成员时才可用。

为了执行前面列出的操作之一,请按照以下步骤操作:

  1. 前往控制面板 | 站点

  2. 点击位于您想要修改的站点的名称附近的操作按钮。还有更多…

  3. 点击所选操作的名称。

参见

您还可以参考以下菜谱:

  • 有关创建组织和用户组的信息,请参阅第三章 与 Liferay 用户/用户组/组织一起工作中的管理组织结构创建新用户组菜谱。

  • 有关自定义站点和向其添加页面的信息,请参阅站点配置为站点创建和自定义私有和公共页面菜谱。

  • 有关创建站点的更多信息,请参阅使用页面模板和站点模板快速创建站点和页面菜谱。

站点配置

当创建站点后,您可以配置每个站点的参数,但可能的选项范围由站点的来源(它是否是组织、用户组或独立站点)决定。创建组织站点后,站点设置部分的链接将出现在组织菜单及其操作菜单中。所有新的组织和独立站点也将在您前往管理 | 控制面板 | 站点时看到的列表中可见。用户组页面不包括在这个列表中,但可以通过前往管理 | 控制面板 | 用户组从特定用户组的操作菜单中访问。

准备工作

要逐步完成这个菜谱,您必须首先创建一个站点(有关如何创建站点的更多信息,请参阅创建组织和独立站点菜谱)。

如何操作…

在这个菜谱中,我们将向您展示如何设置组织站点和独立站点的参数。

为了配置组织的站点,请按照以下步骤操作:

  1. 以管理员身份登录并前往管理 | 控制面板 | 用户和组织

  2. 点击位于您想要配置的组织的名称附近的操作按钮。

  3. 选择管理站点选项。

  4. 填写详细信息搜索引擎优化高级杂项字段。如何操作…

  5. 点击保存按钮。

为了配置独立网站,请执行以下步骤:

  1. 以管理员身份登录并转到管理 | 控制面板 | 网站

  2. 点击位于网站名称附近的操作按钮。

  3. 选择网站管理选项。

  4. 前往配置部分。

  5. 填写详细信息搜索引擎优化高级杂项字段。

  6. 点击保存按钮。

它是如何工作的…

所有可用参数分为以下几组:

  • 基本信息组,包含以下部分:

    • 详细信息部分包含一组选项,允许更改名称、描述、会员选项、创建公共和私有页面、选择父站点或激活和停用网站

    • 分类部分,提供了可以分配给网站的标签和分类

    • 网站 URL部分,允许用户输入将被公共和私有页面使用的友好 URL

    • 网站模板部分,显示了用于创建公共和私有页面的模板名称及其基本设置

  • 搜索引擎优化,包括以下部分:

    • 网站地图部分,允许用户发送网站地图信息以进行预览

    • 机器人部分,允许我们为公共和私有页面设置机器人参数

  • 高级,包括以下部分:

    • 默认用户关联部分,允许我们定义应分配给网站用户的默认网站角色和团队

    • 预览部分,允许我们启用预览功能

    • 分析部分,允许用户定义用于此组页面的 Google Analytics ID 或 Piwik 脚本

    • 内容共享部分,允许我们决定子站点是否可以显示此网站的内容

    • 回收站部分,允许用户启用回收站功能并移动垃圾箱中的条目;垃圾箱会在指定天数后自动删除存储的内容

  • 杂项,包含以下部分:

    • 自定义字段部分,提供了一个工具来管理为网站定义的自定义属性值。

    • 显示设置部分,允许用户设置网站的语言。可以使用默认语言选项或定义一个自定义默认语言以及此网站的其他可用语言。

每个部分都可以通过设置以下属性在portal-ext.properties中进行自定义:

sites.form.add.main=details,categorization
sites.form.add.seo=
sites.form.add.advanced=
sites.form.add.miscellaneous=

sites.form.update.main=details,categorization,site-url,site-template
sites.form.update.seo=sitemap,robots
sites.form.update.advanced=default-user-associations,staging,analytics,content-sharing,recycle-bin
sites.form.update.miscellaneous=custom-fields,display-settings

另一个有趣的功能是在网站之间共享内容(从父站点到子站点)。可以通过sites.content.sharing.with.children.enabled属性进行设置。以下是可能的值:

  • 0禁用了所有网站与子站点的共享内容

  • 1默认禁用了内容共享,同时允许网站管理员按站点启用它

  • 2默认启用内容共享,同时允许站点管理员按站点禁用

下一个设置对应于前面的设置。管理员可以是多个站点的成员。允许或拒绝管理员管理的站点之间内容共享是可能的。要启用或禁用此功能,设置以下属性:

sites.content.sharing.through.administrators.enabled=true

最后的属性设置对应于站点地图。每个站点地图都可以通过特定的时间单位(总是、每小时、每天、每周、每月、每年或更新)刷新。在站点地图中,页面可以有一个默认优先级(介于 0.0 到 1.0 之间)。设置以下属性以排序这些设置:

sites.sitemap.default.change.frequency=daily

sites.sitemap.default.priority=

相关链接

有关创建站点的更多信息,请参阅创建组织和独立站点使用页面模板和站点模板快速创建站点和页面指南。

创建和自定义站点的公共和私有页面

如前所述,一个站点内有两组页面:公共页面和私有页面。组内的每个页面都是单独的树状结构的一部分,反映了网站的信息架构层级。树中的页面可能因目的和来源而有所不同。页面可能只是显示在端口中排列的信息的地方。它可以提供一系列工具供网站内容管理员使用。还可以添加一个链接到同一站点或不同站点的另一个页面的页面。此外,页面可以创建为空页面、现有页面的副本或基于定义的模板。

准备工作

要逐步完成此指南,您必须首先创建一个站点(有关如何创建站点的更多信息,请参阅创建组织和独立站点指南)。

如何操作…

以下指南将说明如何创建页面并安排其结构。

为了创建公共页面,请按照以下步骤操作:

  1. 以管理员身份登录并转到管理 | 控制面板 | 站点

  2. 点击位于站点名称附近的操作按钮。

  3. 选择站点管理选项。

  4. 点击左侧菜单中的页面部分中的站点页面链接。

  5. 确保您处于公共页面选项卡。

  6. 点击添加页面按钮(由+图标表示)。如何操作…

  7. 提供页面的名称(在我们的例子中,它是主页)。

  8. 启用从导航菜单中隐藏选项。

  9. 选择空页面类型。

  10. 选择页面布局。

  11. 点击添加页面按钮。

  12. 点击公共页面树中新增页面的名称。

  13. 点击添加子页面按钮。

  14. 提供页面的名称(例如,新闻)。

  15. 禁用从导航菜单中隐藏选项。

  16. 选择空页面类型。

  17. 选择页面布局。

  18. 点击添加页面按钮。

工作原理…

如前一个示例所示,创建页面是一个非常简单的操作,需要我们提供一些基本信息,例如:

  • 名称,用于标识页面。名称将在所有列出页面的端口中显示,并且(如果未设置页面标题)将用作页面 HTML 标题。

  • 页面布局决定了它是否应由一列、两列或其他列的组合组成。

  • 从导航菜单中隐藏选项允许我们管理页面的可见性。如果启用此选项,则页面在导航菜单、导航端口、网站地图端口等中不可见。

  • 类型选项允许用户选择新创建页面的类型。以下是一些页面类型:

    • 空白页面:将添加一个空白页面

    • 面板:这允许我们创建一个带有预定义应用程序和导航的页面

    • 嵌入式页面:这展示了来自另一个网站的内容

    • 链接到 URL:这是指向另一个网站的链接

    • 链接到本站页面:这是指向当前站点内另一个页面的链接

    • 本站页面副本:这是从本站点复制现有页面的副本

    此外,还有一个可以使用的页面模板列表。

值得注意的是,正如前一个示例所示,页面的级别是在我们点击添加子页面按钮之前选择的标记的页面所决定的。如果我们想创建一个顶级页面,必须选择公共页面或(私人页面)分支。更重要的是,我们还可以通过简单地将页面拖放到不同的树级别来管理页面在树中的本地化。

有许多其他参数会影响页面的外观和行为。这些参数可以通过访问管理 | 控制面板 | 站点 | 页面 | 站点页面来管理。

页面参数

页面定制选项(在管理 | 控制面板 | 站点 | 页面 | 站点页面)中点击页面名称链接的相应选项卡后可用,分为以下部分:

  • 详细信息部分,允许我们更改在添加页面时设置的参数,例如名称类型友好 URL页面布局,例如1 列2 列(50/50)2 列(30/70)等等,并决定是否将页面从导航菜单中隐藏。

  • SEO部分,允许我们提供有助于优化页面以供搜索引擎使用的信息,例如 HTML 标题、元标签、描述、关键词、机器人信息以及网站地图选项。

  • 外观和感觉部分,允许我们决定应使用哪种外观和感觉来构建网站。可以使用与整个树相同的配置(选择使用公共页面的外观和感觉选项)或通过选择为该页面定义特定的外观和感觉选项来自定义它。

  • JavaScript 部分,允许我们定义将在页面底部执行的 JavaScript 代码。

  • 自定义字段 部分,提供管理为页面定义的自定义属性值的工具。

  • 高级 部分,允许我们设置出现在导航菜单中的页面的目标和图标。

  • 移动设备规则 部分,允许我们决定是否使用公共页面的移动设备规则或为此页面定义特定的移动设备规则。

  • 自定义设置 部分,允许我们决定哪些页面部分将对具有所需权限的用户可自定义。

整个树参数

还可以设置整个页面树的某些参数(在点击 Admin | 控制面板 | 站点 | 页面 | 站点页面 对应选项卡上的公共页面或私有页面链接后可用)。以下参数如下:

  • 外观和感觉 部分,允许我们选择此组页面的图形主题、项目符号样式和配色方案;决定是否默认显示端口边界;或插入在主题之后加载的自定义 CSS。

  • Logo 部分,允许我们设置此特定页面树的标志,并决定是否显示站点名称

  • JavaScript 部分,允许我们定义将在页面底部执行的 JavaScript 代码

  • 高级 部分,允许我们将我们门户默认站点的公共页面与当前站点的公共页面合并。

  • 移动设备规则 部分,允许用户定义设备组和相应的规则

技术视图

布局存储在 Layout 表中。此表有以下列:

  • plid: 唯一标识符

  • 审计字段(groupId, companyId, userId, userName, createDate, modifiedDate

  • name: 布局名称

  • type_: 以下值之一—portlet, panel, embedded, url, link_to_layout

  • friendlyURL: 指向特定布局的友好 URL

  • typeSettings: 布局聚合设置

  • 任何其他对理解此配方不重要的列

还有更多…

还可以使用可用的操作来管理页面。

在站点页面上可以执行以下几种可能的操作:

  • 权限 操作允许我们设置站点页面的权限

  • 复制应用程序 操作用于从另一个页面复制所有端口(及其配置)

  • 转到私有页面 操作在新窗口中打开站点的私有页面

  • 删除 操作允许我们删除一个页面

为了执行前面列出的操作之一,请执行以下步骤:

  1. 以管理员身份登录并转到 Admin | 控制面板 | 站点

  2. 点击你想要修改的站点名称附近的 操作 按钮。

  3. 点击 站点管理 选项。

  4. 选择要修改的页面。还有更多…

  5. 点击所选操作的名称。

使用页面模板和站点模板快速创建站点和页面

在某些情况下,所选组或甚至整个内网中的所有站点都应该包含相同的页面集,包括相同的组件集。例如,当站点用作部门网站或项目空间时,可以采用此模型。Liferay 提供了一个非常有效的工具,允许我们使用预先准备的模板创建整个预配置的站点或页面。还可以启用模板与站点之间的连接,这将确保变更的实时传播。

如何操作…

在这个菜谱中,我们将向您展示如何使用站点模板创建独立站点,以及如何从页面模板创建单个页面。

为了使用站点模板创建独立站点,请执行以下步骤:

  1. 以管理员身份登录并转到管理 | 控制面板 | 站点

  2. 点击添加按钮。

  3. 从下拉列表中选择您想要使用的模板(例如,社区站点)。如何操作…

  4. 提供站点的名称(必需)描述

  5. 确保已启用激活选项。

  6. 选择成员类型

  7. 启用或禁用允许手动成员管理选项。

  8. 选择复制为 | 公共页面选项。

  9. 设置启用从站点模板传播变更选项。

  10. 选择父站点

  11. 点击保存按钮。

为了使用页面模板创建页面,请执行以下步骤:

  1. 点击位于站点名称附近操作按钮。

  2. 选择站点管理选项。

  3. 点击站点页面部分。

  4. 点击公共页面标签页。

  5. 点击添加页面按钮:如何操作…

  6. 提供页面的名称(例如,博客)。

  7. 启用从导航菜单中隐藏选项。

  8. 选择页面的博客页面类型。

  9. 点击添加页面按钮。

它是如何工作的…

模板有两种类型:页面模板站点模板

页面模板是创建单个页面的基础,可以在创建新页面时选择。可以通过访问管理 | 控制面板 | 页面模板进行配置。页面模板不仅存储页面配置,还存储组件及其配置,在某些情况下,还包括内容。

站点模板用于创建整个站点,可以通过访问管理 | 控制面板 | 站点模板进行管理。在创建独立站点、用户组或组织站点时,可查看模板列表。站点模板可能包含一组页面及其配置、组件和内容。

变更传播

在创建站点表单模板时,重要的是决定是否应该启用从站点模板的更改传播。当传播被启用时,对模板所做的更改将自动应用于连接到它的站点。

值得注意的是,模板可能允许站点管理员根据模板修改站点。当模板允许修改(启用从站点模板传播更改 选项已启用)时,对站点页面(站点配置和端口配置)的每次修改都会导致与模板断开连接。当不允许模板修改时,站点管理员无法更改页面的配置及其端口。

技术视图

站点模板和页面模板存储在 LayoutSetPrototypeLayoutPrototype 表中。LayoutSetPrototype 包含属于特定布局集的布局的默认信息。如前所述,站点模板定义了一组在创建新站点后可以复制的页面。

页面模板是为了在其他页面中复制而创建的页面。LayoutPrototype 表存储有关页面原型的所有必要信息。

相关链接

关于创建新空站点的信息,请参考 创建组织和独立站点 菜单。

启用本地实时预览

预览是一个强大的工具,它允许用户在将新站点的配置投入生产之前对其进行更改、部署和测试。换句话说,它提供了一个只有管理员才能看到的测试环境。用户可以预览他们的工作;这意味着他们有在网站工作副本上工作的能力。

Liferay 为站点管理员提供了使用本地实时预览和远程实时预览的可能性。当我们谈论本地实时预览时,预览站点和实时站点位于同一个 Liferay 实例和同一服务器上。远程实时预览提供了在不同的主机(在生产环境中不可见)配置和测试更改的可能性,并将更改部署到生产环境。

如何操作…

要启用本地实时预览,请按照以下步骤操作:

  1. 以管理员身份登录并转到 Admin | 站点管理 | 配置 | 站点设置

  2. 高级 部分中选择 预览 选项卡。

    小贴士

    当启用从站点模板传播更改时,无法使用预览功能。

  3. 选择 本地实时 选项。

  4. 决定是否需要页面版本控制。

  5. 选择应进行预览的端口。Liferay 定义以下规则:

    注意

    当端口被选中时,其数据将被复制到预览中,并且可能无法直接在实时中编辑。当取消选中端口时,请确保首先发布在预览中进行的任何更改;否则,它们可能会丢失。

  6. 保存此配置后,网站工具栏上应该有另外两个按钮:预览实时如何操作…

它是如何工作的…

预览是一个强大的功能,为用户提供了一个测试区域。启用预览后,门户为用户提供两个区域:

  • 实时: 提供一个现实世界的视图

  • 预览: 提供一个测试和配置特定布局或端口的区域

实时视图是一个真实视图,展示给所有有权访问该页面的用户。预览视图是一个技术区域,用户可以在此更改设置而不会影响实时视图。如果管理员准备提交和发布更改,他们可以通过点击 发布到实时 按钮来完成。

从技术上讲,这是一个简单的机制。Liferay 创建一个新的组,其 友好 URL 值带有后缀 -staging(例如,/guest-staging)。此组包含其布局、端口设置、内容等。

启用预览后,Liferay 会调用一个后台进程,该进程将布局、端口设置和特定内容复制到预览组(带有新的 groupId)。

注意

此过程可能相当耗时,因此 Liferay 提供以下信息:

初始预览发布正在进行中。发布状态可以在发布屏幕上检查。

此外,Liferay 还在 Group_.typeSettings 列中存储有关预览的信息:

staged-portlet_{NUMBER}=true
stagedRemotely=false
staged=true

启用预览后,Liferay 会将大量数据复制到数据库中。如果您有大量数据,请小心操作并跟踪数据库性能。

参见

如果您想配置远程实时预览,请参阅下一道菜谱。有关启用页面版本的信息,请参阅 启用页面版本 菜谱

启用远程实时预览

Liferay 为单独的测试区域和生产环境提供远程实时预览。在本地服务器上,我们可以在发布事件更改传播到生产环境后配置和测试新的布局或整个站点。为了实现这一点,两个服务器都必须了解彼此。

如何操作…

假设测试环境的本地服务器名为 STAGING_SERVER,生产环境的服务器机器为 PRODUCTION_SERVER

要正确配置远程实时预览,请按照以下步骤操作:

  1. 在本地服务器(STAGING_SERVER)的 portal-ext.properties 中,设置以下属性:

    tunnel.servlet.hosts.allowed=127.0.0.1,PRODUCTION_SERVER_IP
    axis.servlet.hosts.allowed=127.0.0.1, PRODUCTION_SERVER_IP
    tunneling.servlet.shared.secret=SHARED_SECRET
    auth.verifier.TunnelingServletAuthVerifier.hosts.allowed=
    
  2. 在远程服务器(PRODUCTION_SERVER)的 portal-ext.properties 中,设置以下属性:

    tunnel.servlet.hosts.allowed=127.0.0.1,LOCAL_SERVER_IP
    axis.servlet.hosts.allowed=127.0.0.1, LOCAL_SERVER_IP
    tunneling.servlet.shared.secret=SHARED_SECRET
    auth.verifier.TunnelingServletAuthVerifier.hosts.allowed=
    

    注意

    确保共享密钥 SHARED_SECRET 由 16、32 或 64 个字符组成。

  3. 重启两个服务器。

  4. 在本地(STAGING_SERVER)服务器上,转到 管理 | 站点管理 | 配置 并从右侧菜单打开 预览 选项卡。

  5. 选择 远程实时 单选按钮。

  6. 在表单中填写以下输入:

    • 远程主机/IP: PRODUCTION_SERVER 的 IP 地址

    • 远程端口: PRODUCTION_SERVER 的端口号

    • 远程路径上下文:Liferay 实例的上下文名称(如果它是根(/)上下文,则留空)

    • 远程站点 ID:我们配置将要安装的站点的标识符(groupId)。如果该站点不存在,则创建它。

      小贴士

      可以通过转到站点 | 管理 | 配置 | 站点设置 | 站点 ID来找到groupId编号。

  7. 点击保存按钮。

  8. 在停靠栏区域成功配置后,我们应该看到以下视图:如何操作…

它是如何工作的…

远程预览比本地预览更复杂。Liferay Portal 使用两种开箱即用的机制:

  • 将布局导出到本地服务器的 LAR 文件,并在远程服务器上导入

  • 通过使用StagingServiceHttp类使用 SOAP API 传输文件

portal-ext.properties中设置的属性允许我们通过外部客户端调用门户 API。为了允许这样做,我们设置了PRODUCTION_SERVER_IPLOCAL_SERVER_IP。还有一个名为tunneling.servlet.shared.secret的属性,它用于创建一个授权上下文(权限检查器),以帮助确保远程发布过程的安全。

在建立服务器之间的连接后,系统将所有设置导出到 LAR 文件(一个称为 Liferay 存档文件的特殊文件)并通过调用updateStagingRequest进行传输。整个过程在com.liferay.portal.lar.backgroundtask.LayoutRemoteStagingBackgroundTaskExecutor类中实现。

远程预览的信息保存在Group_.typeSettings数据库列中,具有以下属性:

staged-portlet_{NUMBER}=true
staged=true
stagedRemotely=true
remoteGroupId=GROUP_ID
remoteAddress=ADDRESS
remotePort=PORT_NUMBER
secureConnection=false

注意

本地实例和远程实例中的用户必须相同,包括相同的凭据以及角色和权限。

启用页面版本控制

页面版本控制仅在启用预览时才有效。这个功能有两个主要优点:

  • 允许用户以并行方式在不同的页面版本上工作

  • 保留页面历史记录并为用户提供备份点

如何操作…

启用页面版本控制是一个简单的过程。执行以下步骤:

  1. 以管理员身份登录,转到管理 | 站点管理 | 配置并打开预览选项卡。

  2. 版本控制部分选择在公共页面上启用

  3. 通过点击保存按钮进行确认。

  4. 启用版本控制后,停靠栏应显示以下信息:如何操作…

它是如何工作的…

使用页面版本控制与使用代码仓库(如 Git 或 Subversion)类似。此机制与所有站点(LayoutSet)和特定页面(Layout)相关联。这意味着可以版本化整个站点或单个页面。此外,Liferay 提供了一个分支更改的功能。如果用户想要重新组织整个站点,此功能将非常有用。下一个重要的按钮是停靠栏右上角的撤销/重做箭头。

从技术角度来看,Liferay 定义了另一个表来保存分支和版本:

  • LayoutSetBranch:存储站点分支

  • LayoutBranch:存储布局(页面)分支

  • LayoutRevision:存储布局(页面)修订——撤销/重做和版本控制功能

参见

如果您想配置预发布,请参考 启用本地实时预发布启用远程实时预发布 的配方。

第五章。角色和权限

在本章中,我们将涵盖以下主题:

  • 创建和配置角色

  • 分配用户角色

  • 创建基于角色的端口

  • 在自定义小部件中检查权限

简介

就像现实世界中的公司员工一样,系统中的用户可以执行不同的任务。其中一些人可能负责整个内联网的管理——创建新的组织、位置、用户组和站点;分配用户;以及设置权限。其他人可能负责特定站点及其页面的配置和管理小部件。也可能有一组用户负责创建和发布内容。更重要的是,同一个用户也可能同时是某个站点的管理员,但同时又无法执行除查看另一个站点内容之外的操作。为了能够管理这样一个复杂的权限网络,Liferay 引入了角色功能,允许我们定义在定义的位置哪些用户可以执行哪些操作。

角色是一组用户可以执行的动作集合。在 Liferay 门户级别定义了三种类型的角色可供使用:常规角色、站点角色和组织角色。常规角色定义了可以在其定义中指定的系统区域(范围)中执行的动作列表。使用常规角色允许我们在一个特定的范围内执行操作。站点角色包括在站点内执行的动作。组织角色将可以在组织内执行的动作分组(有关组织和个人站点的更多信息,请参阅第三章,与 Liferay 用户/用户组/组织一起工作和第四章,Liferay 站点配置)。

创建和配置角色

无论我们处理的是哪种类型的角色,创建新角色的过程都包括两个步骤——创建一个新的空角色和为该角色定义一组权限。

如何操作…

在本食谱中,我们将向您展示如何创建新的常规站点和组织角色以及如何为它们定义一组权限。

为了创建一个新的常规角色,请执行以下步骤:

  1. 前往管理 | 控制面板 | 角色

  2. 点击添加按钮。

  3. 选择常规角色站点角色组织角色选项。如何操作…

  4. 为角色提供名称(必需)标题描述

  5. 点击保存按钮,您将返回包含所有定义角色的列表。

  6. 点击新创建的角色旁边的操作按钮。

  7. 选择编辑操作。

  8. 点击定义权限选项卡。

  9. 使用左侧列导航菜单,选择您想要定义权限的类别(例如网站管理 | 页面 | 网站页面)。

  10. 对于每个选定的类别,勾选您想要添加角色的权限旁边的复选框。

    注意

    如果您已经知道您正在寻找哪些类别,那么您可以使用搜索文本字段相应地过滤功能。

    如何操作…

    注意

    当为网站管理组内的类别设置普通角色权限时,您还需要选择此角色将能够执行操作的网站列表。

  11. 点击保存按钮。

它是如何工作的…

在菜谱的第一部分,我们向您展示了如何创建一个新的空角色。在第二部分,我们描述了如何为此新创建的角色定义权限。

角色参数

每个角色都有一个名称、标题和描述。描述标识系统中的角色,并包含权限。这些权限定义了分配给此角色的用户可以执行哪些操作。普通角色还有分配给它们的用户列表。

普通角色可能包含对控制面板网站管理我的账户功能的权限。组织角色包括用户和组织以及网站管理权限。网站角色只能定义网站管理权限。

控制面板、网站管理和我的账户权限

大多数控制面板类别权限分为两组:常规权限资源权限。例如,当配置用户和组织功能的权限时,我们可以定义该组中所有应用程序可以执行哪些操作——它们是否可以查看、在控制面板中访问、配置,以及分配给角色的用户是否可以执行用户导出操作或为用户和组织功能设置权限等。所有这些都是常规权限。此外,对于用户和组织功能,还可以设置资源权限。这定义了具有此角色的用户可以对用户和组织执行哪些操作,例如,他们是否可以删除、模拟、更新或查看用户;添加组织;分配成员;使用用户和组织部分管理子组织等。

网站管理权限,在大多数情况下,也分为常规权限资源权限。然而,在定义网站管理权限时,我们还可以决定具有此角色的用户可以在哪些网站上执行操作。例如,可以设置允许用户仅管理所选网站页面或添加内容的普通角色。

我的账户权限仅与应用程序操作相关。

更多内容…

还可以通过 角色 动作菜单中的操作来管理角色。

在一个角色上可以执行几个可能的行为:

  • 编辑 操作允许我们更改角色的 名称标题描述,定义权限并为角色分配成员。

  • 权限 操作允许我们为此角色上可以执行的操作设置权限。

  • 定义 权限操作允许我们为角色定义权限。

  • 分配成员 操作允许我们为用户分配角色。此操作仅适用于常规角色。

  • 查看用户 操作打开具有此特定角色的所有用户的列表。此操作仅适用于常规角色。

  • 删除 操作允许我们删除角色。默认的 Liferay 角色无法删除。

为了执行上述操作之一,请按照以下步骤操作:

  1. 前往 控制面板 | 角色

  2. 点击想要修改的角色的名称附近的位置的 操作 按钮:还有更多…

  3. 点击所选操作的名称。

参见

有关组织和站点的更多信息,请参阅以下配方:

  • 管理组织结构 的配方在 第三章,与 Liferay 用户/用户组/组织协作

  • 创建组织和独立站点 在 第四章,Liferay 站点配置

分配用户角色

为了定义用户可以执行的操作,您需要为他们分配角色。每个用户可以有多个角色,包括常规、站点和组织角色。分配给用户的每个角色都可在用户账户的角色部分中找到。

如何操作...

在本配方中,我们将向您展示如何为常规角色分配成员。

为了为常规角色分配成员,请按照以下步骤操作:

  1. 前往 管理员 | 控制面板 | 角色

  2. 点击想要分配用户的角色的名称附近的位置的 操作 按钮。

  3. 点击 分配成员 操作,您将看到该角色的当前成员列表。

  4. 点击 可用 选项卡:如何操作…

  5. 选择 用户站点组织用户组 选项卡。

  6. 标记您想要分配角色的用户、站点、组织或用户组。

  7. 点击 更新关联 按钮。

它是如何工作的...

常规角色可以分配给用户或用户集合,例如 组织站点用户组。如果角色分配给用户,则该用户将获得为此角色定义的所有权限。您可以通过访问编辑用户表单中的 角色 | 常规角色 来查看角色(要进入编辑用户表单,请转到 用户和组织 | 所有用户 并点击您想查看账户的用户名称)。如果角色分配给用户集合,则该站点、组织或用户组的每个成员都将继承此角色。您可以通过在编辑用户表单中导航到 角色 | 继承角色 来查看此信息。

工作原理…

控制面板 中的 角色 部分允许我们仅将用户或用户集合分配给 常规角色组织角色 可以通过 组织 动作菜单中可用的 分配组织角色 动作进行分配。站点角色 可以在 站点管理站点成员资格 部分进行分配。重要的是要记住,无法将组织角色和站点角色分配给用户集合。

参见

有关分配组织角色和站点角色的更多信息,请参阅以下食谱:

  • 管理组织结构 在 第三章,与 Liferay 用户 / 用户组 / 组织一起工作

  • 创建组织和独立站点 在 第四章,Liferay 站点配置

创建基于角色的端口

Liferay 提供了两种检查权限的方法。第一种机制实现了 Java 端口规范 2.0JSR 286)并提供了一个 XML 定义来映射 Liferay 角色和端口角色。第二种机制使用 Liferay 权限检查器来验证用户及其执行的操作。在本食谱中,我们将向您展示 Java 端口规范和 Liferay 如何协同工作。

准备工作…

使用 Maven 架构生成器生成或创建一个空的端口。我们已在 第一章 中描述了它,安装和基本配置。使用哪个 PortletBridge 并不重要。我们将决定使用一个简单的名为 MVCPortlet 的端口。

假设我们的目标是编写一个问候端口,它可以识别当前用户是否以用户或访客的身份登录。在任何情况下,我们的端口都应该显示问候语,欢迎访客!欢迎用户

如何操作…

我们的概念基于以下方法:每种问候都将位于不同的 JSP 文件中,并且我们的控制器将决定应该使用哪个 JSP 文件。请按照以下步骤操作:

  1. 打开位于 src/main/webapp/WEB-INF 文件夹中的 portlet.xml,并向其中添加 init 参数:

    <init-param>
      <name>view-user-template</name>
      <value>/html/user.jsp</value>
    </init-param>
    <init-param>
      <name>view-guest-template</name>
      <value>/html/guest.jsp</value>
    </init-param>
    
  2. 创建src/main/webapp/html文件夹并添加两个文件,user.jspguest.jsp。在每个文件中定义问候语。在guest.jsp文件中添加以下内容:

    <h1>Welcome Guest!</h1>
    

    user.jsp文件中添加以下行:

      <h1>Welcome User!</h1>
    
  3. portlet.xml中的<security-role-ref>标签中定义角色:

    <security-role-ref>
      <role-name>logged-user</role-name>
    </security-role-ref>
    <security-role-ref>
      <role-name>guest-user</role-name>
    </security-role-ref>
    

    注意

    我们故意更改了默认的角色名称,以便向您展示之前的角色与 Liferay 中的角色不同。

  4. 打开liferay-portlet.xml并将端口角色映射到 Liferay 角色如下:

    <role-mapper>
      <role-name>guest-user</role-name>
      <role-link>Guest</role-link>
    </role-mapper>
    <role-mapper>
      <role-name>logged-user</role-name>
      <role-link>User</role-link>
    </role-mapper>
    
  5. 按如下方式定义端口的渲染方法:

    public void render(RenderRequest request, RenderResponse response) throws PortletException, IOException {
      String renderPagePath = getInitParameter("view-guest-template");
      if (request.isUserInRole("logged-user")) {
        renderPagePath = getInitParameter("view-user-template");
      }
    
      include(renderPagePath, request, response);
      super.render(request, response);
    }
    
  6. 编译并部署端口。

  7. 将我们的端口放在欢迎页面上并测试它。我们的问候语应取决于用户是否已认证。

它是如何工作的…

端口规范 JSR-286 定义了PortletRequest接口的一组方法。这些方法允许我们检查用户的主体名称或角色:

  • getUserPrincipal

  • getRemoteUser

  • isUserInRole

getUserPrincipal方法返回当前认证用户的主体名称,并返回java.security.Principal对象。同样,getRemoteUser返回已登录用户的名称。实际上,这两个方法在 Liferay 实现中返回相同的值,即userId。如果用户未认证,这两个方法都返回 null。第三个方法期望一个字符串参数,该参数是portlet.xml中定义的角色名称。它检查当前用户角色并返回一个boolean值。

JSR-286 规范确定每个security-role-ref定义都应该映射到端口容器实现内部系统角色。这种映射可以在web.xml中以role-namerole-link标签对的形式指定。以下是一个示例:

<role-mapper>
  <role-name>logged-user</role-name>
  <role-link>User</role-link>
</role-mapper>

Liferay 在liferay-portlet.xml中指定了这些映射。

然而,这种方法有一个限制。JSR-286 文档包含以下句子:

"开发者必须意识到使用此默认机制可能会限制在无需重新编译调用端口的端口的情况下更改应用程序中角色名称的灵活性。"

参见

如果您想了解如何创建新的端口或钩子,请参考以下食谱:

  • 在第一章中创建自定义端口安装和基本配置

  • 在第十一章中的语言属性钩子快速技巧和高级知识

  • 在第十一章中使用 Liferay 服务总线进行端口之间的通信,快速技巧和高级知识

在自定义端口中检查权限

Liferay 的权限非常灵活,但理解起来非常复杂。在这个菜谱中,我们将向您展示权限的基本用法,但我们希望这个教程将是实现更复杂权限的起点。让我们假设我们的目标是扩展之前的端口,只为具有特定权限的用户显示秘密消息。这个权限应该在端口权限中可配置。

准备工作...

我们假设您已经有一个由 Maven 原型生成的可用的 Maven 端口。在第一章中,安装和基本配置,我们描述了如何实现这一点。

如何做到这一点...

为了实现我们的目标,我们必须定义并添加一个特定的权限到我们之前的端口。接下来,我们应该注册我们的权限列表。最后,我们将使用这些权限在我们的端口中显示秘密区域。执行以下步骤:

  1. 创建src/main/resources/resource-actions文件夹。

  2. resource-actions文件夹中创建一个名为roles.xml的文件,内容如下:

    <?xml version="1.0"?>
    <!DOCTYPE resource-action-mapping PUBLIC "-//Liferay//DTD Resource Action Mapping 6.2.0//EN" "http://www.liferay.com/dtd/liferay-resource-action-mapping_6_2_0.dtd">
    
    <resource-action-mapping>
      <portlet-resource>
        <portlet-name>roles-portlet</portlet-name>
        <permissions>
          <supports>
            <action-key>ADD_SECTION</action-key>
            <action-key>CONFIGURATION</action-key>
            <action-key>VIEW</action-key>
            <action-key>ACCESS_IN_CONTROL_PANEL</action-key>
          </supports>
          <site-member-defaults>
            <action-key>VIEW</action-key>
          </site-member-defaults>
          <guest-defaults>
            <action-key>VIEW</action-key>
          </guest-defaults>
          <guest-unsupported>
            <action-key>ACCESS_IN_CONTROL_PANEL</action-key>
            <action-key>CONFIGURATION</action-key>
          </guest-unsupported>
        </permissions>
      </portlet-resource>
    </resource-action-mapping>
    
  3. resource-actions文件夹中创建名为default.xml的文件,内容如下:

    <?xml version="1.0"?>
    <!DOCTYPE resource-action-mapping PUBLIC "-//Liferay//DTD Resource Action Mapping 6.2.0//EN" "http://www.liferay.com/dtd/liferay-resource-action-mapping_6_2_0.dtd">
    
    <resource-action-mapping>
      <resource file="resource-actions/roles.xml" />
    </resource-action-mapping>
    
  4. src/main/resources文件夹中创建名为portlet.properties的文件(如果尚不存在),并设置以下属性:

    resource.actions.configs=resource-actions/default.xml
    
  5. 编辑liferay-portlet.xml并在<portlet>部分添加以下标签:

    <add-default-resource>true</add-default-resource>
    
  6. 编译并部署端口。

  7. 将端口放置在布局中,然后转到选项 | 配置菜单

  8. Power User设置action.ADD_SECTION权限。

  9. 返回到 Eclipse IDE。在端口渲染方法中,添加以下代码:

    ThemeDisplay themeDisplay = (ThemeDisplay) request.getAttribute(WebKeys.THEME_DISPLAY);
    boolean secretSection = true;
    try {
      PermissionChecker permissionChecker = themeDisplay.getPermissionChecker();
      String portletId = themeDisplay.getPortletDisplay().getId();
      PortletPermissionUtil.check(permissionChecker, portletId, "ADD_SECTION");
    } catch (PrincipalException pe) {
      secretSection = false;
    } catch (SystemException | PortalException e) {}
    request.setAttribute("secretSection", secretSection);
    

    小贴士

    在我们的例子中,渲染方法位于com.packtpub.portlet.RolesPortlet类中。

  10. src/main/webapp/html文件夹中创建名为secret.jspf的文件,内容如下:

    <c:if test="${requestScope.secretSection}">
      <h2>Secret section</h2>
    </c:if>
    
  11. 将此文件包含在guest.jspuser.jsp中:

    <%@ include file="/html/secret.jspf" %>
    
  12. 编译、部署并运行您的端口。

    注意

    您还必须在 JSP 文件和liferay-plugin-package.properties文件中定义c.tld。本书中包含一个可用的端口。

它是如何工作的...

通常,Liferay 将权限分为portlet-resourcesmodel-resources。端口资源与端口及其本身可能进行的操作(例如,查看、配置)相关联。模型资源描述了特定模型上的可能权限(例如,创建、更新和删除)。在这个例子中,我们只展示了portlet-resources定义,但model-resources类似。

端口资源和模型资源应在 XML 文件中定义,并放在类路径中。在这个菜谱中,我们创建了两个文件:default.xmlroles.xml。这是 Liferay 在核心实现中应用的典型表示法。第一个文件列出了所有定义了权限的资源。第二个文件定义了实际的权限。可能只有一个文件包含 roles.xml 的内容。典型的资源动作映射包括:

  • 端口名称,其定义应该与 portlet.xml 文件中的定义相同

  • portlet-resource 部分,它指定了我们端口中支持的权限、特定角色的默认权限以及特定角色的不支持权限

  • model-resource 部分,在这个菜谱中没有使用

一个非常有用的选项是 <add-default-resource>true</add-default-resource>,我们在 liferay-portlet.xml 中添加了它。Liferay DTD 定义解释了这个标签如下:

"如果将 add-default-resource 的值设置为 false,并且端口不属于页面但已被动态添加,则用户将没有权限查看端口。如果将 add-default-resource 的值设置为 true,则默认端口资源和权限将被添加到页面,然后用户可以查看端口。这对于需要动态添加到页面的端口来说是有用(且必要)的。然而,为了防止安全漏洞,默认值是 false。"

最后一件事情是检查权限。Liferay 给我们提供了一个名为 PermissionChecker 的类,它在每个端口中都是启用的。ThemeDisplay 聚合了这个实现。为了检查权限,Liferay 提供了一个实现 PermissionChecker 接口的方法:

permissionChecker.hasPermission(groupId, name, primKey, actionId);

此方法参数如下:

  • groupId:这是包含资源的组的主键

  • name:这是资源的名称,可以是类名或端口 ID

  • primKey:这是资源的主键

  • actionId:这是动作 ID

可以直接使用这种检查方式,或者从 PortletPermissionUtil 中调用权限检查器。第二种方式由 Liferay 推荐使用。这个实用工具类至少有九个名为 check 的静态方法,根据具体情况,参数有很多变体。check 方法不返回任何值。如果没有权限,该方法会抛出 PrincipalException 异常。

第二个静态方法是 contain,如果特定权限被启用则返回 true,如果权限被禁用则返回 false

实际上,这个菜谱只涉及了 Liferay 中权限的基本知识。在互联网上,有很多关于如何使用 Liferay 权限以及如何实现新功能的教程。如果我们使用基于 Liferay 模型的 服务构建器 机制,实现正确的权限相当简单。Liferay 默认添加了很多功能。

参见

如果你想学习如何创建新的端口或钩子,请参考以下食谱:

  • 在第一章的创建自定义端口安装和基本配置

  • 在第十一章的语言属性钩子使用 Liferay 服务总线进行端口间的通信快速技巧和高级知识

第六章:Liferay 中的文档和媒体

在本章中,我们将涵盖以下主题:

  • 使用文档和媒体小部件在 Liferay 中管理文件

  • 管理文档类型和元数据集

  • 与亚马逊 S3 云服务集成

  • 之间存储钩子的数据迁移

简介

任何内联网的主要任务都是允许公司员工之间高效地交换信息。在大多数情况下,业务知识以文件的形式存储,如果公司没有专用的系统,则分布在邮箱、网络驱动器、FTP 服务器、员工计算机驱动器和外部数据载体之间。在这种情况下,通常存在一个问题,即确定谁拥有当前版本的文件,是否真的存在这样的文档,或者在哪里可以找到它们。Liferay 通过提供文件内部存储库来帮助处理信息的分散。

使用文档和媒体小部件在 Liferay 中管理文件

Liferay 中的每个站点都有自己的独立存储库,可以通过转到管理 | 站点管理 | 内容 | 文档和媒体来访问。此外,还可以将文档和媒体小部件放置在可以由没有访问管理功能的用户之间共享的页面之一上。文档和媒体小部件允许我们管理可以在站点内发布的所有文件夹和文档。

如何操作…

文档和媒体小部件提供了创建、编辑和删除文件夹、文档和快捷方式的工具。它还使我们能够通过上传整个文件组来创建多个文档。本食谱将涵盖所有基本操作,以便创建一个高效且易于搜索的文档和文件夹结构。

创建新文件夹

要添加新文件夹,请执行以下步骤:

  1. 以管理员身份登录并转到管理 | 站点管理 | 内容 | 文档和媒体

  2. 点击添加按钮。

  3. 选择文件夹子文件夹选项。创建新文件夹

  4. 输入文件夹的名称(必填)

  5. 输入文件夹的描述

  6. 通过设置特定角色可能执行的所有操作来确定文件夹的权限(您可以在点击更多选项链接后找到更多权限)。

  7. 点击保存按钮。

编辑文件夹

要编辑文件夹,请执行以下步骤:

  1. 以管理员身份登录并转到管理 | 站点管理 | 内容 | 文档和媒体

  2. 前往您想要编辑的文件夹。

  3. 点击其操作图标(当悬停在文件夹缩略图上时可见的向下箭头图标)。编辑文件夹

  4. 点击编辑按钮。

  5. 为文件夹提供新的名称

  6. 输入文件夹的新描述

  7. 确定文档类型限制和工作流定义设置对此特定文件夹的工作方式。您可以通过转到文档类型限制和工作流选项,设置使用父文件夹的文档类型限制和工作流

  8. 点击保存按钮。

添加新文档

要添加新文档,请执行以下步骤:

  1. 以管理员身份登录并转到管理 | 站点管理 | 内容 | 文档和媒体

  2. 点击添加按钮。

  3. 选择适当的文档类型,例如,基本文档。添加新文档

  4. 点击选择文件按钮并从您的驱动器中选择要添加到存储库的文件。

  5. 输入文档的标题(如果您不提供标题,将使用文件名作为标题)。

  6. 输入文档的描述

  7. 展开分类部分

  8. 选择类别并输入或选择描述文档的标签

    如果没有可见的分类可以分配给文档,这意味着要么特定站点的分类尚未创建,要么正在工作的用户的账户没有访问现有字典分类的权限。

  9. 通过设置特定角色可能执行的所有操作来确定文档的权限。

  10. 点击相关资产按钮,查找并选择将设置为相关内容的文档(或其他内容类型)。

  11. 点击发布按钮。

上传多个文档

您还可以一次性添加多个文档并设置多个文档的元数据。

要添加多个文档,请转到文档和媒体部分。然后,按照以下步骤操作:

  1. 以管理员身份登录并转到管理 | 站点管理 | 内容 | 文档和媒体

  2. 点击添加按钮。

  3. 选择多个文档选项。

  4. 点击选择文件按钮并选择您想要上传的所有文件。

    备注

    您还可以通过拖放选择应上传的文件组。

  5. 上传所有文件后,勾选与文件名相同的类型、标签组和权限旁边的复选框:上传多个文档

  6. 输入描述,选择文档类型,并定义这些文档的分类、标签和权限。

  7. 点击保存按钮。

  8. 重复步骤 6 和 7,直到所有上传的文件都保存。

编辑文档

要编辑文档,请执行以下步骤:

  1. 以管理员身份登录并转到管理 | 站点管理 | 内容 | 文档和媒体

  2. 前往您想要编辑的文档。

  3. 点击其操作图标:编辑文档

  4. 点击编辑按钮。

  5. 为编辑的文档提供新的标题描述,选择文档类型,定义分类标签,并为编辑的文档选择相关内容

  6. 点击发布按钮。

删除文件夹和文档

每个文件夹和文档都可以从存储库中临时或永久删除。临时和永久删除都通过回收站机制完成。

要临时删除文件夹或文档,请执行以下步骤:

  1. 前往要删除的文件夹或文档。

  2. 点击其操作图标。

  3. 点击移动到回收站操作。

    小贴士

    您可以通过点击移动文档到回收站后立即出现的撤销按钮来撤销此操作。默认情况下,回收站是启用的,并保留已删除的项目 30 天。可以通过前往管理 | 站点管理 | 配置 | 站点设置 | 回收站来更改特定站点的回收站可用性和回收站条目的最大年龄。

要永久删除文件夹或文档,请按照以下步骤操作:

  1. 前往管理 | 站点管理 | 内容 | 回收站

  2. 点击要删除的文档名称附近的操作按钮:删除文件夹和文档

  3. 点击删除操作,并通过点击确定来确认您的意愿。

注意

注意,删除文件夹时,其全部内容也会被删除。

还可以使用操作菜单中的恢复操作来恢复文档。

它是如何工作的…

Liferay 的文档和媒体库允许我们创建文件夹和文档的树状结构。这意味着每个文件夹可以包含子文件夹和文档。Liferay Portal 中的每个文档由一个文件和一组描述它的元数据组成。

Liferay 提供了许多属性来配置文档和媒体小部件。它们在portal-impl/src/portal.properties文件中本地化,可以被位于${liferay.home}文件夹中的portal-ext.properties覆盖。其中一个属性是拒绝文件或文件夹的名称,无论扩展名如何:

dl.name.blacklist=con,prn,aux,nul,com1,com2,com3,com4,com5,com6,com7,com8,com9,lpt1,lpt2,lpt3,lpt4,lpt5,lpt6,lpt7,lpt8,lpt9

还可以定义扩展名的限制,并仅允许添加定义的扩展名(默认情况下,此属性允许所有文件扩展名)。要减少或添加可用的扩展名,设置以下属性:

dl.file.extensions=.bmp,.css,.doc,.docx,.dot,.gif,.gz,.htm,.html,.jpg,.js,.lar,.odb,.odf,.odg,.odp,.ods,.odt,.pdf,.png,.ppt,.pptx,.rtf,.swf,.sxc,.sxi,.sxw,.tar,.tiff,.tgz,.txt,.vsd,.xls,.xlsx,.xml,.zip,.jrxml

下一个重要且有用的属性是文件最大大小的定义。默认情况下,它是无限的。要更改它,定义允许的字节数:

dl.file.max.size=3072000

Liferay 搜索索引器试图索引文件的内容。可以定义应忽略哪些类型的扩展名。还可以定义索引文件的尺寸:

dl.file.indexing.ignore.extensions=.exe,.sh,.pdf
dl.file.indexing.max.size=10485760

在文档库小部件部分中,portal-impl/src/portal.properties提供了更多设置。

文档类型

有五种默认的文档类型:基本文档、合同、营销横幅、在线培训和销售演示。每种文档类型可能包含不同的元数据集。例如,当添加新的合同时,用户可以提供有效日期、到期日期、合同类型、法律审查员、状态等信息。基本文档只包含基本信息,如名称、描述、标签、分类和权限。

非常常见的是,Liferay 提供的这些默认文档类型或元数据集不足以满足需求。需要创建包含非常特定元数据信息的个性化文档类型。这可以通过以下菜谱中描述的文档类型和元数据集创建工具来实现。

可以限制文件夹只包含一种或多种特定类型的文档。文档类型限制可以单独为每个文件夹设置,也可以从父文件夹继承。

权限

每个文件夹和文档都有自己的权限集,它定义了分配给不同角色的用户可以执行的操作列表。例如,可以设置这样的权限,使得具有特定角色的用户可以访问特定的文件夹,但不会看到存储在那里的某些文件。

注意

关于权限的更多信息,请参阅第五章,角色和权限

分类和标签

如果一个内网包含非常大量的文档,一个设计良好的结构可能不足以帮助用户找到正确的文档。分类和标签提供了一种额外的机制来标记、列表和搜索文件,并允许通过专门的端口(如分类导航、资产发布者或标签云)进行后续选择。分类以及文档可以创建一个树状结构。每个分类都放在字典中,可以拥有子分类。相反,标签不存储在字典中,创建一个平面结构。可以为文档分配一个或多个分类和标签。

相关资产

在 Liferay 中,资产是可以显示在页面上的内容片段,例如文档、网页内容、博客条目等。每个文档都可以连接到另一个文档(或其他类型的资产)。这些文档将通过端口(如资产发布者)列出。

其他信息

让我们详细了解 Liferay 在默认配置下如何存储文件。首先,系统读取文件的元数据,如扩展名、标题、大小。接下来,它识别文件的 MIME 类型(image/pngaudio/mpegapplication/pdf等)。此设置取决于文件的扩展名。接下来,小部件所做的下一件事是创建一个版本。默认情况下,第一个上传的文件版本为 1.0。Liferay 还识别文件添加的文件夹和存储库。所有这些信息都存储在DLFileEntry表中。这类数据称为元数据。

默认情况下,每个文件都存储在本地硬盘上的${liferay.home}/data/document_library文件夹中。文件夹的层次结构非常具体。很难识别每个文件存储的位置。让我们检查一个文件路径:data/document_library/10157/11501/303/1.0

如我们之前所说,每个文件都放置在data/document_library文件夹中。下一个文件夹名称是instanceId,可以通过转到管理 | 控制面板 | 配置 | 门户实例来设置。下一个标识符是folderId。了解这个标识符是这个文件的父文件夹是很有帮助的。如果文件放置在文件夹的层次结构中,它就是最后一个文件夹的标识符。303 是存储在DLFileEntry.name列中的数字。每个文件只有一个版本名称。在这个例子中,文件的名称是 1.0。在现实世界中,这是一个 PNG 图像。所有必要的文件数据,如其名称,都放置在数据库中。

小贴士

请注意并记住,文件条目由存储在数据库中的元数据和存储在硬盘特定位置的字节组成。

还有更多……

用户也可以创建指向他们可以访问的任何文档的快捷方式。快捷方式上设置的权限使用户能够通过快捷方式访问原始文档。

为了创建快捷方式,请按照以下步骤操作:

  1. 以管理员身份登录并转到管理 | 站点管理 | 内容 | 文档和媒体

  2. 点击添加按钮。

  3. 选择合适的快捷方式。还有更多……

  4. 点击站点按钮,选择包含您想要创建快捷方式的文档的站点。

  5. 点击文档按钮并选择文档。

  6. 通过设置特定角色可能执行的所有操作来确定快捷方式的权限。

  7. 点击保存按钮。

参见

  • 关于权限的信息,请参阅第五章的创建和配置角色配方,角色和权限

  • 来自第九章的Kaleo Web 安装配方,Liferay 工作流功能

  • 关于文档分类的更多信息,请参阅第八章中的标签和内容分类配方,搜索和内容展示工具

管理文档类型和元数据集

如前一个配方中提到的,每个文件虽然提供了元数据,但变成了文档。默认情况下,每个文档包含诸如名称、描述、类别、标签、权限或相关资产等信息。非常常见的是,基本集是不够的。在这种情况下,可能需要创建一个新的文档类型,这样我们就可以为文件提供特定的附加信息。

如何做到这一点…

在本配方中,我们将描述如何定义不同类型的文档,并教授如何组合和使用元数据集。

使用元数据集创建新文档类型

要添加新的文档类型,请执行以下步骤:

  1. 以管理员身份登录并转到管理 | 站点管理 | 内容 | 文档和媒体

  2. 点击管理按钮。

  3. 选择文档类型选项。

  4. 点击添加按钮。

  5. 输入文档类型的名称

  6. 输入文档类型的描述。

  7. 通过从左侧菜单拖放字段到右侧区域,确定将在此类文档中可用的元数据字段

  8. 通过点击每个字段并定义其属性(字段标签显示标签必填名称预定义值提示可索引可重复选项多选)来设置所有添加的字段。使用元数据集创建新文档类型

  9. 点击选择附加元数据集并选择一个可用的元数据集(参见本配方的下一节以了解如何处理元数据集)。

  10. 通过设置特定角色可能执行的所有操作来确定文档类型的权限。

  11. 点击保存按钮。

定义元数据集

要定义新的元数据集,请执行以下步骤:

  1. 以管理员身份登录并转到站点管理 | 内容 | 文档和媒体

  2. 点击管理按钮。

  3. 选择元数据集选项。

  4. 点击添加按钮。定义元数据集

  5. 输入元数据集的名称(必填)

  6. 输入元数据集的描述

  7. 选择父元数据集

  8. 确定将在此类文档中可用的元数据字段

  9. 点击保存按钮。

它是如何工作的…

当定义一种新的文档类型时,我们不仅定义了与文件存储的信息范围,还创建了一个表单,以便我们输入信息。文档类型表单和元数据集表单都可以使用简单的表单编辑器来创建。这个编辑器包含了一个不同表单字段的库,例如布尔值日期十进制文档和媒体HTML整数页面链接数字单选按钮选择文本文本框。值得注意的是,也可以通过拖放一个字段(或多个)到另一个字段上来创建字段组。

当定义一种新的文档类型时,我们必须决定我们想要包含的字段集是仅用于特定文档还是用于不同的文档类型。在前一种情况下,我们可以在新的文档类型中直接创建表单。在后一种情况下,最好创建一个元数据集,它可以作为许多文档类型的一部分使用,但管理在一个地方。同样,与 Liferay 资产的情况一样,元数据集可以仅在一个特定范围内创建和使用,或者当在全局范围内创建时,可以在一个 Liferay Portal 实例的所有范围内使用。

此外,元数据集可以继承来自其他元数据集的一组字段。

字段可以通过以下属性来定义:

类型 定义字段的类型
字段标签 这允许我们为字段提供标签
显示标签 这让您决定是否显示标签
必填 这让您决定填写字段是否是必需的或可选的
名称 这允许我们定义字段的名称
预定义值 这允许我们定义在用户输入自己的值之前默认显示的值
提示 这允许您提供一段简短文本,该文本将作为字段的工具提示显示
可索引 这让您决定文件内容是否应该被索引和搜索
可重复 这允许我们确定字段是否可以被重复
选项 这允许您为所有字段提供可能的选项,使用户可以从定义的列表中选择选项
多选 这允许我们确定用户是否可以选择多个选项

参见

有关文档管理的信息,请参阅使用“文档和媒体”小部件在 Liferay 中管理文件的食谱

与 Amazon S3 云的集成

Liferay 提供了与 Amazon S3 云通信的内置功能。这个功能为用户提供了一个非常强大的工具,可以将他们的文档存储在基于云的解决方案中。Amazon 简单存储服务Amazon S3)是一个可扩展的、高速的、低成本且基于网络的在线备份和存档服务,适用于文档、演示文稿、电子表格、图片、照片等数据。Amazon 存储最伟大的特点是它声称在给定一年内对象可用性达到 99.99%。此外,这些服务提供高度可扩展的存储,可以随着数据的增加而轻松扩展。整个基础设施具有安全的 SSL 数据传输和加密。Amazon Simple Storage Service 是更大项目 Amazon Web Servicesaws.amazon.com)的一部分。这是一个包含许多网络服务的集合,如计算云、存储云、数据库、网络以及管理和安全。

Liferay 为用户提供了一个在远程存储库中存储和管理文档的功能。这种类型的存储库可以是 Amazon S3。为了允许门户与 Amazon S3 之间的通信,Liferay 使用 JetS3t 工具包。这是一个基于 Java 的开源项目。有关此解决方案的更多详细信息,请参阅 www.jets3t.org/。技术上,它是一个放置在已部署 Liferay 实例的 ROOT/WEB-INF/lib/ 文件夹中的 jets3t.jar 归档。

如何操作…

Liferay 与 Amazon S3 之间的通信是通过 Amazon S3 API 实现的。为了正确配置此访问权限,您需要以下三项内容:访问密钥、秘密密钥和存储桶名称。要生成这些数据(访问密钥、秘密密钥和存储桶名称),请按照以下步骤操作:

  1. 登录到 Amazon Web 服务控制台:console.aws.amazon.com

  2. 在工具栏上,转到 您的姓名 | 安全凭证

  3. 展开 访问密钥(访问密钥 ID 和秘密访问密钥)。

  4. 点击 创建新访问密钥 按钮。

  5. 在弹出窗口中,您将看到以下消息:

    您的访问密钥(访问密钥 ID 和秘密访问密钥)已成功创建。

    如何操作…

  6. 点击 显示访问密钥 并复制 访问密钥 ID秘密访问密钥。这对密钥将在稍后使用。

接下来的几个步骤负责创建一个新的存储桶,其中 Liferay 将存储其文件:

  1. console.aws.amazon.com,转到 服务 | S3

  2. 要创建一个新的存储桶,请点击 创建存储桶 按钮。如何操作…

  3. 填写所有必填字段并保存表单。

  4. 记住您的存储桶名称。

最后一件事情是 Liferay 门户配置。正如我们一开始所说的,Liferay 提供了与 Amazon 通信的内置功能,因此配置并不困难。它只是一个简单的设置,位于 ${liferay.home}/portal-ext.properties

dl.store.impl=com.liferay.portlet.documentlibrary.store.S3Store
dl.store.s3.access.key=<ACCESS KEY ID>
dl.store.s3.secret.key=<SECRET ACCESS KEY>
dl.store.s3.bucket.name=<BUCKET NAME>

最后,重新启动您的门户实例,并尝试在文档和媒体端口中上传文件。从用户的角度来看,上传操作不应该有任何不同。为了看到差异,您可以登录到 S3 存储桶以检查上传的文件。

如何工作…

门户提供了许多可配置的钩子,用于将文档上传到各种持久化系统。所有这些都作为 Liferay 核心功能实现。基本和默认的持久化系统是 FileSystemStore,它将数据存储在本地硬盘上。Liferay 提供了其他实现,例如 AdvancedFileSystemStoreCMISStoreDBStoreJCRStoreS3Store。可以在 portal-ext.properties 中设置其中一种类型:

dl.store.impl=com.liferay.portlet.documentlibrary.store.AdvancedFileSystemStore
dl.store.impl=com.liferay.portlet.documentlibrary.store.CMISStore
dl.store.impl=com.liferay.portlet.documentlibrary.store.DBStore
dl.store.impl=com.liferay.portlet.documentlibrary.store.FileSystemStore
dl.store.impl=com.liferay.portlet.documentlibrary.store.JCRStore
dl.store.impl=com.liferay.portlet.documentlibrary.store.S3Store

以下描述显示了存储实现中的差异:

  • FileSystemStore:此工具将文档直接保存到本地文件系统。

  • AdvancedFileSystemStore:类似于 FileSystemStore,但将数据划分为桶(文件夹),从而避免了单个目录中文件过多的限制。

  • DBStore:将二进制数据以 blob 的形式存储在数据库中。

  • CMISStore内容管理互操作性服务CMIS)是一个规范,旨在提高 企业内容管理ECM)系统之间的互操作性。文档和媒体允许用户连接到多个支持 CMIS 1.0、AtomPub 和 Web 服务协议的第三方存储库。可以与许多符合 CMIS 标准的 ECM 供应商集成 Liferay,例如 SharePoint、Alfresco、Documentum、IBM FileNet 等。

  • JCRStore:实现了 Java 内容存储库 API。著名的实现是 Apache Jackrabbit。因此,如果设置了此钩子,则可以在 Apache Jackrabbit 内容存储库中保留二进制数据。

  • S3Store:将数据存储在 Amazon 简单存储服务中。

让我们检查负责此集成的代码。S3Store 类实现了 Store 接口。因此,它提供了对文件的所有必要操作,例如 addFileaddDirectorydeleteFiledeleteDirectory 等。在 portal-ext.properties 中,我们将 dl.store.impl 属性设置为 S3Store 类。

Liferay 使用 JetS3t 工具包与 Amazon 服务进行通信。此工具包负责将文件从/到 Amazon 云传输。

在 Amazon S3 存储库中,文件夹和文件的结构与本地文件系统中的结构相同。以下截图显示了文件夹层次结构的示例:

如何工作…

还有更多…

如果文档库存储库较小,与 Amazon S3 云的集成工作得非常完美。当并发用户数量和文件数量巨大时,问题就会出现。问题出在HttpClient和 S3 及其并行通信(并发通信线程)之间。可以通过覆盖jets3t.properties来增加连接数。为了正确更改它,将此文件放入 Tomcat 类路径中,例如,在${CATALINA_BASE}/lib文件夹中。之后,更改以下属性,并尝试将值调整到您的环境中:

s3service.internal-error-retry-max=10 (Liferay 6.0 and 6.1)
cloudfront-service.internal-error-retry-max=10 (Liferay 6.2)
threaded-service.max-thread-count=100
httpclient.retry-max=10
httpclient.connection-timeout-ms=90000
httpclient.socket-timeout-ms=90000
httpclient.max-connections=100

jets3t.s3.amazonaws.com/toolkit/configuration.html的官方文档中,属性描述如下:

属性名称 描述
s3service.internal-error-retry-max 这指的是ThreadedStorageService / SimpleThreadedStorageService服务为上传和下载操作启动的最大并发通信线程数。这个值不应过高。否则,在传输大量大文件时,可能会由于带宽不足而出现 I/O 错误。它仅适用于 Liferay 6.0 和 Liferay 6.1
cloudfront-service.internal-error-retry-max 这指的是当 CloudFront 连接因内部服务器错误失败时将尝试的最大重试次数。要禁用内部错误失败的重试,请将此设置为 0。它仅适用于 Liferay 6.2
threaded-service.max-thread-count 这是指ThreadedStorageService / SimpleThreadedStorageService服务为上传和下载操作启动的最大并发通信线程数。这个值不应过高。否则,在传输大量大文件时,可能会由于带宽不足而出现 I/O 错误。默认值为2。这个值不能超过 JetS3t 可用的最大 HTTP 连接数,该连接数由httpclient.max-connections属性设置。
httpclient.retry-max 这决定了在连接失败时因 I/O 错误而重试连接的次数。将其设置为0以禁用重试。默认值为5
httpclient.connection-timeout-ms 这决定了在连接超时之前要等待的毫秒数。0表示无限。默认值为60000
httpclient.socket-timeout-ms 这决定了在套接字连接超时之前要等待的毫秒数。0表示无限。默认值为60000
httpclient.max-connections 这指的是全局允许的最大并发连接数。默认值是20。如果你有快速的互联网连接,可以通过增加此设置以及相应的 S3 服务属性,s3service.max-thread-counts3service.admin-max-thread-count来提高你的 S3 客户端性能。然而,请注意,如果你为你的连接增加太多,可能会超过你的可用带宽并导致通信错误。

参见

有关构建可伸缩系统的信息,请参阅第十二章中的可伸缩基础设施配方,基本性能调整

存储钩子之间的数据迁移

此配方献给那些因任何原因需要从一种存储实现更改为另一种存储实现的管理员。此示例展示了我们如何将存储在文档库中的二进制文件迁移到其他存储库。在我们的示例中,我们将检查从 S3Store(Amazon S3)迁移到本地FileSystemStore存储钩子的过程。

如何操作…

Liferay 内置了在存储钩子之间迁移文档的功能。假设我们的 Liferay 实例已经启动,并且库已连接到 Amazon S3 云。为了将文档迁移到文件系统,请按照以下步骤操作:

  1. 以管理员身份登录到 Liferay 实例。

  2. 转到管理 | 控制面板

  3. 然后转到配置 | 服务器管理 | 数据迁移

  4. 滚动到从一个存储库迁移文档到另一个存储库部分。

  5. 选择一个新的存储钩子,称为com.liferay.portlet.documentlibrary.store.FileSystemStore如何操作…

  6. 点击执行按钮。

  7. Liferay 临时将状态更改为维护模式。

  8. 查看并检查catalina.out日志的执行情况。日志文件应如下所示:

    DEBUG [liferay/convert_process-1][MaintenanceUtil:64] Please set dl.store.impl in your portal-ext.properties to use com.liferay.portlet.documentlibrary.store.FileSystemStore
    [liferay/convert_process-1][ConvertProcess:47] Finished conversion for com.liferay.portal.convert.ConvertDocumentLibrary in 3010 ms
    

工作原理…

Liferay 提供了迁移存储钩子之间数据的功能。当我们的 Liferay 实例运行时,我们的项目经理或产品所有者想要将存储系统更改为另一个系统,例如 Amazon S3 或 SharePoint 时,这是一个重要的工具。此外,无需你的开发者编写自定义脚本即可完成此操作。此功能在com.liferay.portal.convert.ConvertDocumentLibrary类中实现。doConvert方法调用以下文件的迁移过程:

  • 迁移图片

  • 迁移文档库

  • 迁移论坛附件

  • 迁移维基附件

实际上,这四种方法调用动态查询来获取数据库中放置的所有文件定义,并将它们从一处复制到另一处。所有文件夹和文件的结构都是逐个映射的。

小贴士

仔细检查你的日志文件,以确保所有数据都正确迁移。

参见

关于如何更改数据库引擎的信息,请参考第十一章中的从数据库迁移到另一个数据库配方,快速技巧和高级知识

第七章. 与内容协作

在本章中,我们将涵盖以下主题:

  • 管理和显示网页内容

  • 创建新结构

  • 创建新模板

简介

如前一章所述,Liferay 提供了一套完整的工具,使我们能够管理存储公司员工之间交换数据的文件。然而,在许多情况下,对于最终用户来说,在文件中操作存储的信息并不太方便。例如,在阅读新闻或浏览企业知识库时,在网页上直接导航内容比在文件中更容易。新闻、项目描述、程序等信息可以使用网页内容提供。可以使用一些特定的端口,如网页内容显示端口或资产发布端口,在页面上显示网页内容。

管理和显示网页内容

Liferay 中的每个站点都有自己的独立网页内容集,可以通过访问管理 | 站点管理 | 内容 | 网页内容来访问。所有存储在网页内容部分的内容都可以组织成树状文件夹结构。网页内容可以包含文本、图形、表格、列表以及指向其他网页内容、文档或页面的链接。此外,每个网页内容都可以被标记和分类,或者提供与其相关的资产列表。此列表将在网页内容的主要内容下的相关资产部分列出。还可以定义权限,指定不同角色的用户可以对网页内容执行哪些操作。

如何操作…

本菜谱将涵盖所有基本操作,以便在站点内管理网页内容。

创建新文件夹

要添加一个新文件夹,请执行以下步骤:

  1. 以管理员身份登录并转到管理 | 站点管理 | 内容 | 网页内容

  2. 点击添加按钮。

  3. 选择文件夹选项(如果您在已创建的文件夹内添加文件夹,则将可用子文件夹选项)。创建新文件夹

  4. 输入文件夹的名称(必填)。

  5. 输入文件夹的描述

  6. 通过设置特定角色可能执行的所有操作来确定文件夹的权限(您可以在点击更多选项链接后找到更多权限)。

  7. 点击保存按钮。

    小贴士

    下载示例代码

    您可以从您在www.packtpub.com的账户下载示例代码文件,以获取您购买的所有 Packt Publishing 书籍。如果您在其他地方购买了这本书,您可以访问www.packtpub.com/support并注册,以便将文件直接通过电子邮件发送给您。

编辑文件夹

要编辑一个文件夹,请按照以下步骤操作:

  1. 以管理员身份登录并转到管理 | 站点管理 | 内容 | 网页内容

  2. 找到你想要编辑的文件夹。

  3. 点击其操作图标(当悬停在文件夹缩略图上时可见的向下箭头图标)。编辑文件夹

  4. 点击编辑按钮。

  5. 为文件夹提供新的名称(必填)

  6. 输入文件夹的新描述

  7. 通过设置特定角色可能执行的所有操作来确定文件夹的新权限

  8. 保持与父文件夹合并选项未选中。

  9. 点击保存按钮。

创建新的网页内容

要创建新的基本网页内容,请执行以下操作:

  1. 以管理员身份登录并转到管理 | 站点管理 | 内容 | 网页内容

  2. 点击添加按钮。

  3. 选择基本网页内容选项。

  4. 提供必要的标题(必填)内容创建新的网页内容

  5. 转到摘要标签页。

  6. 提供一个摘要

  7. 通过提供 URL 或从你的电脑驱动器上传它来设置小图像。然后,选择使用小图像选项。

  8. 转到分类标签页。

  9. 从类型下拉列表中选择类型,例如,新闻

  10. 通过点击字典旁边的按钮并标记分类来从可用的分类字典(由名称和相关选择按钮表示)中选择分类

    小贴士

    如果没有可见的分类可以分配给文档,这意味着要么特定站点的分类尚未创建,要么正在工作的账户用户没有访问现有分类字典的权限。

  11. 通过添加新标签来提供标签。你可以从现有标签列表中选择它们或使用建议功能。

  12. 转到计划标签页。

  13. 设置显示日期审核日期过期日期功能(或启用永不过期永不审核功能)。

  14. 转到显示页面标签页。

  15. 选择你想要完整显示网页内容的页面。

    注意

    如果至少有一个包含启用将此页面设置为默认资产发布者选项的资产发布器小部件的页面,则显示页面将可用。没有资产发布器小部件的页面名称以灰色显示而不是黑色。有关更多信息,请参阅第八章中关于资产发布器作为基于搜索的内容展示工具的配方,搜索和内容展示工具

  16. 转到相关资产标签页。

  17. 选择相关资产,它应该列在你的网页内容的全文下方。

  18. 点击发布按钮。

    小贴士

    在发布之前,可以使用基本预览选项预览网页内容。此选项在保存网页内容的第一稿后可用。然而,基本预览功能不允许我们在主题上下文中预览网页内容。相反,它以默认视图呈现。

在网页内容显示组件中显示网页内容

为了在网页内容显示组件中显示网页内容,请执行以下步骤:

  1. 前往您想要显示网页内容的页面。

  2. 点击添加图标(这是左侧的+号)。

  3. 点击应用程序标签。

  4. 使用搜索功能或浏览可用组件列表来查找网页内容显示组件。

  5. 点击它旁边的添加链接或将其拖放到您想要的页面上。在网页内容显示组件中显示网页内容

  6. 点击添加的组件选项图标(这将在组件右上角显示为一个齿轮图标)。

  7. 选择配置选项。

  8. 从列表中选择您想要在组件中显示的网页内容(通过点击其名称)。在网页内容显示组件中显示网页内容

  9. 选择应在组件中可用的附加功能列表(例如,启用打印启用评论选项)。

  10. 点击保存按钮。

编辑网页内容

为了修改现有网页内容,请按照以下步骤操作:

  1. 以管理员身份登录并转到管理 | 站点管理 | 内容 | 网页内容

  2. 从可用网页内容列表中选择您想要修改的网页内容。

  3. 点击所选网页内容的名称,或从其操作菜单中选择编辑操作。编辑网页内容

  4. 当表单打开时,编辑您想要更改的字段。

  5. 点击发布按钮。

向现有网页内容添加翻译

要向现有网页内容添加翻译,请执行以下步骤:

  1. 以管理员身份登录并转到管理 | 站点管理 | 内容 | 网页内容

  2. 从可用网页内容列表中选择您想要定义翻译的网页内容。

  3. 点击所选网页内容的名称或从其操作菜单中选择编辑操作。

  4. 点击添加翻译按钮。

  5. 选择您想要为其创建翻译的语言(如果您愿意,可以通过参考第十一章中的语言属性钩子配方,快速技巧和高级知识来更改可用语言)。向现有网页内容添加翻译

  6. 为此语言提供标题内容摘要

  7. 点击保存按钮。

    注意

    所有可用的翻译都列在编辑内容页面中添加翻译按钮之后放置的可用翻译部分。您可以通过在此部分点击翻译名称后访问的表单来管理(包括删除)翻译。

  8. 点击发布按钮。

过期网页内容

有两种使网页内容过期的方法。第一种方法,如前所述,是在添加或编辑网页内容时设置过期日期。第二种选项是使用网页内容操作菜单中可用的过期操作。按照以下步骤执行此过期网页内容的选项:

  1. 以管理员身份登录并转到管理 | 站点管理 | 内容 | 网页内容

  2. 从可用的网页内容列表中选择您想要修改的内容。

  3. 点击所选网页内容的操作菜单。

    小贴士

    选择过期操作。为了使过期的网页内容对用户可用,您需要再次编辑和发布它。

删除文件夹和网页内容

每个文件夹和网页内容都可以临时或永久删除。临时和永久删除都通过回收站机制完成。

要临时删除文件夹或网页内容,请按照以下步骤操作:

  1. 前往需要删除的文件夹或网页内容。

  2. 点击其操作图标。

  3. 点击移动到回收站操作。

    注意

    您可以通过点击将网页内容移动到回收站后出现的撤销按钮来撤销此操作。

要永久删除文件夹或网页内容,请按照以下步骤操作:

  1. 以管理员身份登录并转到管理 | 站点管理 | 内容 | 回收站

  2. 点击位于您要删除的网页内容或文件夹名称附近的操作按钮:删除文件夹和网页内容

  3. 点击删除操作,并通过点击确定来确认您的选择。

    注意

    注意,当您删除文件夹时,其全部内容也会被删除。默认情况下,回收站已启用,并保留删除的项目 30 天。可以通过转到管理 | 站点管理 | 配置 | 站点设置 | 回收站来更改特定站点的回收站可用性和回收站条目的最大年龄。

您还可以使用操作菜单中可用的恢复操作来恢复网页内容或网页内容文件夹。

它是如何工作的...

网页内容部分允许我们创建树状文件夹结构来组织存储在站点内的网页内容。可以创建或移动网页内容到默认文件夹(“首页”)或用户定义的文件夹之一。还可以将一个文件夹(及其内容)与另一个文件夹合并。在创建或编辑网页内容时,用户可以选择将其保存为草稿或发布。只有授权用户可以通过访问管理 | 站点管理 | 内容 | 网页内容来访问网页内容的草稿版本。已发布的版本可供最终用户查看。每次发布网页内容时,其版本号都会增加。所有版本都可在网页内容历史记录中查看,这可以通过网页内容编辑表单访问。

如果需要隐藏之前发布的网页内容以供最终用户查看,但保留在系统中,应使用过期操作。如前所述,可以安排网页内容的发布和过期时间。

每个网页内容都有一个唯一的 ID、标题、状态和版本号。有三种可用的状态:

  • 已批准: 这是为了已发布的网页内容,可以放置在页面上的端口中,并对最终用户可用

  • 草稿: 这些是为尚未发布的最新版本内容保留的网页内容

  • 过期: 这标记了所有已过期的网页内容,对最终用户不可用

权限

每个文件夹和网页内容都有自己的权限设置,这定义了分配给不同角色的用户可以对其执行的操作列表。例如,可以设置这样的权限,使得具有特定角色的用户可以对某个特定的网页内容提供评论,但不会允许他们对其他网页内容执行相同的操作。

分类

在网页内容添加和编辑表单中的分类选项卡允许我们定义网页内容的类型、类别和标签。类别和标签提供了一种额外的机制来标记、列出和搜索网页内容,并允许通过专门的端口(如分类导航、资产发布者或标签云)进行后续选择。类别可以创建树状结构。每个类别都位于字典中,可以具有子类别。标签则相反,不存储在字典中,创建平面结构。可以将网页内容分配给一个或多个类别和标签。类型用于在网页内容部分内搜索网页内容。

相关资产

在 Liferay 中,资产是指可以显示在页面上的内容片段,例如文档、网页内容、博客条目等。每个网页内容都可以连接到另一个网页内容、文档或不同类型的资产,例如评论、博客条目等。这些网页内容将由资产发布者等端口列出。

在页面上放置网页内容

如前所述,Web 内容部分允许我们以文件夹结构组织 Web 内容,帮助我们管理网站内的 Web 内容。然而,这种结构对网站的信息架构没有任何影响。为了将 Web 内容放置在页面上,您需要使用专用的小部件,例如 Web 内容显示或资产发布器小部件。Web 内容显示小部件允许我们一次显示一个 Web 内容的全部内容。资产发布器小部件(在第以下章节中描述)要复杂得多,并允许我们创建不同的内容列表。它还允许我们以全文视图显示 Web 内容。

显示页面

显示页面参数允许我们决定在资产发布器小部件中哪个页面将以全文视图显示特定的 Web 内容。

参见

  • 关于如何在页面上展示 Web 内容的更多信息,请参阅第八章的“标记和分类内容”和“资产发布器作为基于搜索的内容展示工具”食谱,搜索和内容展示工具

  • 关于权限的更多信息,请参阅以下食谱:

    • 创建和配置角色 来自 第五章,角色和权限

    • Kaleo Web 安装用户创建过程的单一审批者工作流 来自 第九章,Liferay 工作流能力

  • 关于 Web 内容的更多信息,请参阅本章的“创建新结构”和“创建新模板”食谱。

创建新结构

Liferay 为用户提供有趣的功能:结构和模板。结构提供有关我们内容中可能字段的详细信息,而模板负责将这些字段作为前端(例如,在资产发布器或 Web 内容显示小部件)中的文章进行渲染。

假设我们的目标是定义一个名为 内部发布 的新结构和模板。此结构包含以下字段:

名称 类型 必需 可重复
作者 文本
部门 选择
项目 文本框
客户 文本
内容 HTML
附件 文档和媒体

如何操作...

为了定义一个新的结构,您需要在Web 内容部分的添加结构权限的用户身份登录。为了实现这一目标,请按照以下步骤操作:

  1. 以管理员身份登录。

  2. 前往管理 | 站点管理 | 内容 | Web 内容

  3. 点击管理选项并选择结构

  4. 点击添加按钮。

  5. 输入结构的名称,该名称为内部发布

  6. 可以选择默认语言并添加一些描述。我们将保持默认设置。

  7. 前往具有拖放功能以定义字段的区域。

  8. 选择文本字段,并将其拖放到灰色区域。

  9. 点击添加的元素,转到设置选项卡,并设置以下属性:

    • 字段标签作为作者

    • 必填作为

    • 可索引作为可索引 - 关键字

    • 不可重复作为

  10. 点击关闭按钮以保存信息并返回到字段选项卡。

  11. 重复步骤 8 和 9 以定义所有必要的字段,这些字段已在我们的假设中描述。结果应如下所示:如何操作…

  12. 点击保存按钮。

  13. 要查看新创建的结构,请转到网页内容 | 添加 | 内部发布

它是如何工作的…

结构是网页内容表单的 XML 定义。它为用户提供以下十三种预定义类型:

  • 布尔值:在结构中添加一个带有真/假值的复选框

  • 日期:添加一个带有日历(日期选择器)的输入文本

  • 小数:添加一个只接受数字和小数点的输入

  • 文档和媒体:将现有上传的文档附加到结构

  • HTML:添加一个所见即所得编辑器

  • 图像:添加一个浏览图像应用程序

  • 整数:添加一个只接受数字的输入

  • 链接到页面:添加一个选择列表以选择链接到另一个页面

  • 数字:类似于整数,只允许数字

  • 单选按钮:添加单选按钮

  • 选择:添加一个带有选项的选择列表

  • 文本:添加一个输入文本

  • 文本框:添加一个文本区域组件

在后台,每个定义都存储为一个名为 <dynamic-element> 的 XML 节点。可以通过点击结构编辑模式中的选项卡来查看定义是如何构建的。以下是我们 Author 定义的示例:

<dynamic-element dataType="string" indexType="keyword" name="Author" readOnly="false" repeatable="false" required="true" showLabel="true" type="text" width="small">
  <meta-data locale="en_US">
    <entry name="label">
      <![CDATA[Author]]>
    </entry>
    <entry name="predefinedValue">
      <![CDATA[]]>
    </entry>
    <entry name="tip">
      <![CDATA[]]>
    </entry>
  </meta-data>
</dynamic-element>

这个定义描述了我们设置的所有字段,例如 dataType: stringindexType: keywordname: Author 等等。

每一行都有许多属性,例如 predefinedValuetiprequired 等。以下表格显示了最重要的属性:

属性名称 描述
类型 预定义字段类型 字段定义的类型
字段标签 字符串 字段的标签
显示标签 是/否 决定标签的可见性
必填 是/否 将字段设置为必填字段
名称 字符串 字段的名称,通常与标签相同
预定义值 字符串 设置默认值
提示 字符串 字段的提示(描述)
可索引 不可索引 / 可索引—关键字 / 可索引—文本 定义索引器类型并指示将使用哪种类型的搜索索引器
可重复 是/否 允许我们将字段设置为可重复字段
宽度 小/中/大 允许我们定义字段的宽度

还有更多…

期刊结构提供了设置从该结构创建的文章默认值的有趣功能。其中一种可能性是在编辑结构屏幕上设置预定义值。然而,Liferay 也提供了一个名为 编辑默认值 的选项。当我们的需求是每个从这个结构生成的文章都应该有一个预定义的特定类别、标签、显示页面等时,这个设置非常有意思。在后台,这是一篇在数据库中有特定设置的文章,以防止它被资产发布者、网页内容显示或甚至搜索选中或找到。

要设置默认值,请遵循以下步骤:

  1. 以管理员身份登录。

  2. 前往 管理 | 站点管理 | 内容

  3. 点击 管理 选项并选择 结构

  4. 在所选结构中,例如 内部发布,转到 操作 | 编辑默认值

  5. 填写默认值并点击 保存 按钮。

创建新模板

此配方需要基本的编程技能。一般来说,模板是一个从具有特定结构的文章中渲染值的模式。根据这一事实,模板相对于结构,因此结构和模板是一对定义,不能单独存在。结构定义了表单的外观;模板确定期刊文章的渲染和排列方式。

准备工作…

准备一个名为 内部发布 的结构。要了解如何实现,请参考之前的配方。

假设我们的模板分为四个部分:

  • 包含 作者部门 的元数据定义

  • 带有 客户端项目 信息的度量定义

  • 带有 内容 的描述部分

  • 附件 部分

如何操作…

Liferay 为用户提供了三种语言来编写模板:Velocity (.vm),FreeMarker (.ftl) 和可扩展样式表语言 (.xsl)。无论语言定义如何,创建新模板的过程都遵循相同的规则。为了创建一个新模板,请按照以下步骤操作:

  1. 以管理员身份登录。

  2. 前往 管理 | 站点管理 | 内容 | 网页内容

  3. 点击 管理 选项并选择 模板

  4. 点击 添加 按钮。

  5. 使用以下值填写表格:

    • 名称: 输入 内部发布

    • 结构: 选择 内部发布

    • 语言: 选择 Velocity (.vm)

  6. 编写一个脚本,将我们的假设渲染如下:

      <div class="article-container">
        <div class="article-metadata">
          <span>Create Date: $dateTool.format( 'medium_date', $dateTool.toDate( "EEE, dd MMM yyyy hh:mm:ss Z" , $reserved-article-display-date.getData(), $localeUtil.getDefault()) , $locale), Author: $Author.getData(), Department: $Department.getData()</span>
        </div>
        <hr />
        <div class="article-metric">
          <table>
            <tr>
              <td>Client:</td>
              <td>$Client.getData()</td>
            </tr>
            <tr>
              <td>Project:</td>
              <td>$Project.getData()</td>
            </tr>
          </table>
        </div>
    
      #if($Content.getData().length() > 0)
        <hr />
          <div class="article-content">  
            $Content.getData()
          </div>
        #end
    
        #if($Attachment.size() > 0) 
        <hr />
          <div class="article-attachment">
            <div>Attachments:</div>
            #foreach($file in $Attachment.getSiblings())
            <a href="$file.getData()">Attachment # $velocityCount</a><br />
            #end
            </div>
          #end
          </div>
    
  7. 点击 保存 按钮。

它是如何工作的…

正如我们一开始提到的,Liferay 为用户提供了三种(语言)编写文章模板的方式:Velocity (.vm)、FreeMarker (.ftl) 和可扩展样式表语言 (.xls)。在这个菜谱中,我们选择了 Velocity 宏,这允许我们将逻辑(宏)与 HTML 和 CSS 混合。如果我们打开一个编辑器,我们可以看到左侧有一个菜单,包括通用变量字段工具,如下面的截图所示:

如何工作…

变量

通用变量部分包含可以在脚本中使用的变量。实际上,这些定义很少使用,并且仅在复杂的 VM 或 FTL 脚本中使用。以下变量可用:

名称 变量 Liferay 类 描述
门户实例 $company 公司 代表当前门户实例的对象
门户实例标识符 $companyId Long 当前门户实例的标识符
设备 $device 设备 代表当前用于访问站点的设备的对象
站点 ID $groupId Long 当前站点的标识符
视图模式 $viewMode String 内容期望的视图模式;打印模式下的值将是 print

字段

这些对象可以在我们的脚本中使用。例如,$Content.getData() 调用会从结构的 Content 字段打印一个值。正如前面的代码所示,我们使用了此调用以下字段:

$Author.getData() 
$Department.getData()
$Client.getData()
$Project.getData()
$Content.getData()
$file.getData()

下一个有用的调用是 $Attachment.getSiblings()。当我们的字段是可重复的并且包含多个值时,使用此方法。在我们的例子中,Attachment 字段有两个兄弟。

要遍历兄弟节点,我们使用了 foreach 宏,这与 Java 语言中著名的 foreach 构造非常相似。

考虑到前面的代码,字段还有其他方法,例如以下这些:

  • $field.getName(): 这将打印字段的名称

  • $field.getType(): 这将返回字段类型,该类型在结构中定义

  • $field.getChildren(): 当字段有嵌套字段时使用

工具

在脚本中可用的最强大的工具是 utils。实际上,这里有一些基于 Java 的真实类,提供了广泛的功能。在我们的例子中,我们使用了一个来打印文章的显示日期:

$dateTool.format( 'medium_date', $dateTool.toDate( "EEE, dd MMM yyyy hh:mm:ss Z" , $reserved-article-display-date.getData(), $localeUtil.getDefault())

可用服务的完整列表放在以下 Java 类中:

  • com.liferay.portal.template.TemplateContextHelper

  • com.liferay.portal.velocity.VelocityTemplateContextHelper(用于 Velocity)

  • com.liferay.portal.freemarker.FreeMarkerTemplateContextHelper(用于 FreeMarker)

保留变量

上述代码有一个特殊的调用:$reserved-article-display-date.getData()。这是一个全局可用的保留变量,在每一个模板中都可以访问。在我们的例子中,它显示文章的display date。Liferay 提供了许多保留变量,例如reserved-article-titlereserved-article-typereserved-article-version等等。

这些变量的完整列表定义在com.liferay.portlet.journal.model.JournalStructureConstants类中。

第八章。搜索和内容展示工具

在本章中,我们将涵盖以下主题:

  • 标记和分类内容

  • 资产发布者作为基于搜索的内容展示工具

  • 为资产发布者定义应用显示模板

  • 搜索端口的基本配置

  • Solr 的安装和配置

简介

Liferay 提供了一个强大的内置工具,允许我们搜索内容。这是 Liferay 最重要的功能之一。为什么?答案很简单:搜索无处不在是必需的。没有好的搜索引擎,在内容混乱中无法找到或定位文章、维基或文档。Liferay 架构提供了一个有用的工具来索引、搜索和显示此类文档作为分面结果。分面意味着按特定的主题类别分组,按特定的实体类型分组,或其他此类标准。

实际上,Liferay 中有一系列搜索功能。可以使用 SQL 查询以及使用称为 Apache Lucene 的专用搜索引擎来查找实体(lucene.apache.org)。在许多地方(尤其是在配置或控制面板中),Liferay 使用 SQL 查询查找实体。另一方面,门户提供了一个称为搜索端口的专用端口,允许我们使用 Lucene 引擎进行搜索。

标记和分类内容

类别和标签提供了一种强大的机制来标记、列出和搜索不同的资产,并允许通过专门的端口如类别导航、资产发布者或标签云等来帮助后续选择。该机制非常简单:标签和类别被分配给网络内容、文档或其他类型的资产。然后,可以设置端口来仅显示具有特定类别和/或标签的资产。可以为资产分配一个或多个类别和/或标签。

如何做到这一点...

在添加或编辑此资产时,可以为任何资产分配类别和标签。例如,如前几章所示(第六章,Liferay 中的文档和媒体和第七章,内容处理),新的(和编辑过的)网络内容或新的(和编辑过的)文档表单提供了一个分类部分。此部分允许我们选择类别集并定义在提交表单后将分配给文档或网络内容的标签列表。然而,重要的是要知道,分配类别和标签的过程是不同的。标签可以直接在内容添加表单中定义,而类别必须在站点管理中创建,以便可供分配。

类别存储在词汇表中。为了创建类别,您必须首先使用以下步骤创建一个词汇表:

  1. 以管理员身份登录并转到管理 | 网站管理 | 内容 | 类别

  2. 点击添加词汇按钮。如何操作…

  3. 为新词汇提供名称描述

  4. 启用允许多个类别选项。

  5. 选择资产类型下拉列表中设置所有资产类型

  6. 启用必需选项。

  7. 通过设置特定角色可能执行的所有操作来确定词汇的权限(点击更多选项链接后可以找到更多权限)。

  8. 点击保存按钮。

词汇准备就绪时,可以填充类别。要添加类别,请按照以下步骤操作:

  1. 以管理员身份登录并转到管理 | 网站管理 | 内容 | 类别

  2. 点击添加类别按钮。如何操作…

  3. 为新类别提供名称描述

  4. 到词汇下拉列表中选择您想要创建类别的词汇。

  5. 通过设置特定角色可能执行的所有操作来确定该类别的权限(点击更多选项链接后可以找到更多权限)。

  6. 点击保存按钮。

创建类别后,可以将其分配给资产。以下是如何使用以下步骤将之前创建的类别分配给现有网页内容的步骤:

  1. 以管理员身份登录并转到管理 | 网站管理 | 内容 | 网页内容

  2. 点击一个已存在的网页内容的名称。

  3. 导航到分类选项卡。

  4. 点击位于您想要分配类别的词汇名称附近的位置的选择按钮。

  5. 标记您想要选择的类别或类别,然后关闭窗口。如何操作…

  6. 点击发布按钮以保存网页内容的更改。

与类别不同,标签不需要在进入添加/编辑资产表单的分类部分之前创建。您可以使用以下步骤在单个任务中创建一个标签并将其分配:

  1. 以管理员身份登录并转到管理 | 网站管理 | 内容 | 网页内容

  2. 点击一个已存在的网页内容的名称。

  3. 导航到分类选项卡。

  4. 标签字段中输入标签。

  5. 点击+添加按钮或按Enter键。

    备注

    您可以在标签字段中输入所有标签的完整列表,并通过逗号分隔它们来添加多个标签。

    如何操作…

  6. 点击发布按钮以保存网页内容的更改。

还可以在网站管理部分定义标签列表,以便供创建网页内容、文档和其他类型资产的用户稍后使用。要定义标签,请按照以下步骤操作:

  1. 以管理员身份登录并转到管理 | 网站管理 | 内容 | 标签

  2. 点击添加标签按钮。如何做…

  3. 为标签提供一个名称

  4. 点击保存按钮。

要分配一个已存在的标签,请按照以下步骤操作:

  1. 以管理员身份登录并转到管理 | 网站管理 | 内容 | 网页内容

  2. 点击一个已存在的网页内容的名称。

  3. 导航到分类选项卡。

  4. 点击标签字段下方的选择按钮。如何做…

  5. 标记您想要选择的标签或标签。

    注意

    您也可以通过输入其名称(自动完成功能将帮助找到现有标签)并按Enter按钮来选择一个现有的标签。

  6. 点击发布按钮以保存网页内容的更改。

它是如何工作的…

类别和标签都使用网站管理部分中提供的工具进行管理,并通过资产添加/编辑表单(新的网页内容表单、编辑网页内容表单、新的文档表单、编辑文档表单等)分配给资产。当提供了类别和/或标签时,每个资产都可以通过特定的组件(如资产发布者)进行选择并在页面上显示。

类别

类别存储在词汇表中,并形成一个树状结构——每个类别可以有子类别。可以通过访问管理 | 网站管理 | 内容 | 类别来管理网站内所有可用的类别。此部分允许我们创建、编辑和删除词汇和类别。

每个词汇都通过其名称来识别,并且可以提供描述。词汇可以设置为与所有或仅与一个特定资产一起工作(选择资产类型选项)。例如,可以创建一个只能将类别分配给网页内容的词汇。这样的词汇将不会在其他资产的添加和编辑表单中可用。

在创建词汇时,我们可以决定在分配类别给资产时,用户是否必须至少分配其一个类别(必需选项)或者他们是否可以使用此特定词汇中的多个类别(允许多个类别选项)。

类别通过其名称来识别,并且可以提供描述。还可以为词汇和类别设置权限。

标签

相反,标签不存储在词汇表中,但它们构建了一个平面结构。可以通过访问管理 | 网站管理 | 内容 | 标签来访问网站内分配给资产的标签。标签部分允许我们添加、编辑、删除或合并标签。与类别不同,标签在分配给资产时可以创建。

参见

有关管理网页内容和文件的信息,请参阅以下食谱:

  • 在第六章的使用文档和媒体组件管理 Liferay 中的文件食谱中,Liferay 中的文档和媒体

  • 在第七章的管理和显示网络内容配方中,与内容一起工作

资产发布者作为基于搜索的内容展示工具

资产发布者是一个非常复杂且高度可配置的组件,它允许我们在页面上展示网络内容文件夹、网络内容、文档文件夹、文档、留言板消息、书签文件夹、书签条目、博客条目、日历事件和维基页面。由特定资产发布者展示的资产可以是授权用户手动选择,也可以根据配置的规则自动选择。

在本配方中,我们将向您展示如何配置资产发布者,以使用手动和动态资产选择变体展示网络内容。

准备工作

要逐步完成此配方,您需要添加包含新闻类别的词汇表并创建网络内容。

如何操作…

假设我们每周都需要在我们的内网主页上发布由负责新闻发布的员工选择的前五条最重要的新闻条目。这些新闻可以通过配置为列出手动选择的网络内容文章的资产发布者组件来显示。要配置此类资产发布者组件,请按照以下步骤操作:

  1. 以管理员身份登录并前往您想要配置新资产发布者的页面。

  2. 点击添加图标(这是左侧的+符号)。

  3. 点击应用程序标签。

  4. 使用搜索功能或通过浏览可用组件列表查找资产发布者组件。

  5. 点击位于资产发布者旁边的添加链接(当您将鼠标悬停在组件名称上时,该链接会出现)。

  6. 点击新添加组件的选项图标(这将是组件右上角的齿轮图标)。

  7. 选择配置选项。

  8. 资产选择部分选择手动选项。

  9. 点击资产条目部分的选择按钮。

  10. 选择网络内容文章选项。

  11. 点击您想要选择的网络内容旁边的选择按钮。

    备注

    根据需要重复步骤 9-11,以创建所需的新闻列表。

    如何操作…

  12. 点击保存按钮。

  13. 通过点击x按钮关闭弹出窗口。您刚刚配置的资产发布者组件将仅展示所选网络内容的列表。

还可以将资产发布者设置为根据指定的类别自动选择新闻文章(在我们的示例中,我们将使用新闻类别)。

为了将资产发布者配置为仅展示具有新闻类别的网络内容文章,请按照以下步骤操作:

  1. 点击之前添加组件的选项图标。

  2. 选择配置选项。

  3. 资产选择部分选择动态选项。

  4. 资产类型列表中选择网络内容文章选项。

  5. 过滤器部分设置包含以下任一类别规则。

  6. 点击选择按钮。

  7. 标记新闻类别并关闭窗口。如何操作…

  8. 按字段排序设置为发布日期降序

  9. 点击保存按钮。通过点击x按钮关闭弹出窗口。您刚刚配置的资产发布器小部件将仅显示包含新闻类别的网络内容列表。

它是如何工作的…

用户可以通过手动选择(手动资产选择)或根据一组规则自动选择(动态资产选择)来选择小部件显示的资产。正如配方的第一部分所示,手动资产选择允许我们在资产类型字段中设置的类型以及资产发布器工作范围内的可用范围内选择任何资产(在范围字段中定义)。

范围是一个非常重要的参数,因为它定义了资产发布器显示的资产的原产地。资产发布器可以展示在当前站点全局范围或从其他站点列表中选择的任何其他站点内创建的资产。

配方的第二部分提供了一个动态资产选择的示例,其中资产发布器从定义的范围中选择所有符合定义的资产类型并且分配到过滤器部分中指定的类别或标签的资产。可以指定资产发布器应仅列出具有分配(或未分配)的类别、一组类别、一个标签或一组标签的资产。此外,过滤器部分允许我们指定资产是否必须分配到集合中的所有类别(所有选项)或者是否只需至少分配集合中的一个类别即可(任何选项)。例如,如果我们希望资产发布器小部件仅展示同时具有新闻和体育类别的资产,我们必须设置包含所有类别规则并从列表中选择新闻和体育类别。如果我们希望列出所有资产,除了那些分配了新闻类别的资产,我们必须使用不包含任何类别规则并从列表中选择新闻类别。

资产发布器小部件提供了许多配置选项,允许我们自定义其外观和可用功能。可以通过访问资产发布器 | 配置 | 设置 | 显示设置来访问配置选项。以下是最重要的选项的描述:

  • 显示模板选项允许我们选择资产应该如何显示(如标题列表、完整内容、摘要等)。

  • 摘要长度允许定义将显示为摘要的文本字符数。

  • 资产链接行为定义了在点击列表中显示的标题后,是否应显示完整内容。

  • 显示项目数量选项定义了资产发布器小部件将显示多少资产。

  • 分页类型允许我们选择是否以及显示何种类型的分页来组织长列表的资产。

  • 将此页面设置为默认资产发布器选项允许我们将此特定的资产发布器设置为用于展示与此页面相关的内容。将资产发布器设置为默认的页面将在添加新网页内容时可供选择作为显示页面。

  • 启用打印选项启用网页内容的打印版本。

  • 启用标志选项启用标志功能,该功能提供了一种通知任何不规则性的联系表单。

  • 启用相关资产选项启用相关资产功能,该功能列出了在添加/编辑资产表单中定义为相关的所有资产。

  • 启用评分选项启用允许我们评分资产发布器显示的内容的功能。

  • 启用评论选项允许我们对资产发布器显示的资产进行评论。

  • 启用社交书签选项显示 Google+、Facebook 和 Twitter 分享按钮。

  • 选择元数据选项允许我们选择资产发布器小部件显示的每个资产的元数据信息。

参见

关于管理网页内容和文件的信息,请参阅以下配方:

  • 在第六章的使用文档和媒体小部件管理 Liferay 中的文件配方中,Liferay 中的文档和媒体

  • 在第七章的管理和显示网页内容配方中,与内容一起工作

定义资产发布器的应用程序显示模板

由于 Liferay 版本 6.2 是可用的选项,它允许我们为资产发布器设置一个新的显示模板。在实际应用中,这是一个非常有用且强大的工具,有助于定义资产的自定义显示模板,例如期刊文章、博客条目、论坛等。例如,您可能只想显示资产描述或添加选定的分类和标签。

假设我们有一个用例,该用例描述了资产发布器视图需求如下:

  • 显示标题

  • 显示描述

  • 显示选定的标签和分类

  • 显示资产链接

  • 显示“阅读更多”链接

如何做…

为了定义一个新的显示模板,以管理员身份登录并按照以下步骤操作:

  1. 以管理员身份登录。转到管理 | 配置并从左侧菜单中选择应用程序显示模板

  2. 点击添加按钮并选择资产发布器模板

  3. 在表单中输入名称内网模板的值,并选择Velocity (.vm)语言。

  4. 在脚本区域,编写以下代码:

    #if (!$entries.isEmpty())
      #foreach ($curEntry in $entries)
        <div>$curEntry.getTitle($locale)</div>
        <div>$curEntry.getDescription($locale)</div>
        <div>
          $taglibLiferay.assetTagsSummary(
            $curEntry.getClassName(), $curEntry.getClassPK(), 
            null, null, $renderResponse.createRenderURL()
            )
        </div>
        <div>
          $taglibLiferay.assetCategoriesSummary(
            $curEntry.getClassName(), 
            $curEntry.getClassPK(), null, $renderResponse.createRenderURL()
          )
        </div>
        <div>
          $taglibLiferay.assetLinks(
            $curEntry.getEntryId(), 
            $curEntry.getClassName(), $curEntry.getClassPK()
          )
        </div>
    
        <div>
          <a href="$assetPublisherHelper.getAssetViewURL(
            $renderRequest, $renderResponse, $curEntry)">
          Read more</a>
        </div>
        <hr />
        #end
    #end
    
  5. 点击保存按钮。

  6. 创建一个新页面,并放置资产发布者组件(参见本章的将资产发布者作为基于搜索的内容展示工具配方)。

  7. 前往资产发布者配置,并选择显示设置选项卡。

  8. 显示模板字段中,选择内网模板,然后点击保存按钮。

  9. 关闭配置弹出窗口。在资产发布者视图中,你应该看到新的模板。

它是如何工作的…

在之前的 Liferay 版本中,无法从控制面板中为资产发布者添加新的显示模板。唯一的方法是在钩子插件中添加新的 Java 服务器页面文件。在 Liferay 6.2 中,可以在控制面板下定义视图为 Velocity 或 Freemarker 脚本。Liferay 开发者实现了一个强大的编辑器,有助于创建新模板。编辑器指定可能的字段,显示提示,并提供出色的自动完成选项。

让我们尝试理解我们的脚本。第一行检查条目集合中是否有任何元素。$entries对象是一个资产条目元素的集合,这些元素是根据组件配置中的特定标准选择的。

下一行遍历条目集合,并将元素分配给$curEntry变量。

下一个部分显示标题和描述。接下来的三个部分显示标签、类别和相关的资产。最后一个部分显示阅读更多选项。

在这个过程中最困难的事情是理解每个助手和工具的工作方式,哪些参数是必需的,哪些不是必需的。不幸的是,没有简单的方法来理解它。唯一的方法是在 Liferay 源代码或示例中搜索帮助。

参见

为了了解更多关于模板的信息,请参阅第七章中的创建新模板配方,处理内容

搜索组件 – 基本配置

假设我们的内网只包含分布在多个文件夹中的文章和文件。我们的目标是配置搜索组件,以便只查找这些内容。然而,我们的搜索结果应显示以下方面:

  • 资产类型方面

  • 资产标签和资产类别方面

  • 用户方面

  • 时间方面

准备工作…

为了开始我们的搜索之旅,我们的 Liferay 实例应该有一些内容,例如期刊文章、文件和文件夹、用户等。

如何操作…

为了使用基本配置正确配置搜索组件,请按照以下步骤操作:

  1. 以管理员身份登录。

  2. 使用单列模板创建搜索页面。

  3. 前往搜索页面。

  4. 点击左侧的应用程序选项卡。

  5. 通过滚动或输入文本搜索字段来查找搜索组件。

  6. 点击添加按钮或将端口件拖放到布局的正确位置。

  7. 进入端口件的配置模式。

  8. 确保选择以下选项:

    • 基本显示设置

    • 显示资产类型方面

    • 显示资产标签方面

    • 显示资产类别方面

    • 显示文件夹方面

    • 其他设置部分中的在上下文中查看

  9. 拼写检查设置保留为默认配置。

  10. 点击保存按钮并关闭弹出窗口。

  11. 在搜索表单中输入您的关键词并按Enter键。Liferay 应该显示以下结果:如何做…

它是如何工作的…

Liferay 提供了一个基于 Lucene 的内置搜索系统。Liferay 中的每个实体(例如,网页内容、文档库文件条目、博客、论坛等)都有自己的Indexer类。这个类负责解析内容并将它们放入搜索索引。当用户使用搜索端口并输入特定的关键词时,搜索引擎会在索引中查找结果。

Lucene 引擎有自己的查询语法来查询其索引。相应地,Lucene 索引看起来像带有键和值的映射。如果用户询问特定的关键词,后台会生成一个查询。要浏览 Lucene 索引,有一个名为 Luke 的工具(code.google.com/p/luke)。

还有更多…

当我们分析搜索端口显示的结果时,我们注意到有许多不必要的条目,例如用户、论坛等。我们的假设是只展示网页内容和文档库实体。此外,我们还想禁用未使用的方面,如文件夹方面。要实现这一结果,需要更改分面配置。按照以下步骤修改分面搜索:

  1. 进入搜索端口件的配置模式。

  2. 显示设置部分的高级选项上勾选。

  3. 修改 JSON 搜索配置。使用以下行更改值节点:

    "data": {
      "values": [
      "com.liferay.portlet.documentlibrary.model.DLFileEntry",
        "com.liferay.portlet.journal.model.JournalArticle"
        ],
      "frequencyThreshold": 1
    }
    
  4. 删除任何不必要的方面:

    {
      "displayStyle": "folders",
      "weight": 1.2,
      "static": false,
      "order": "OrderHitsDesc",
      "data": {
        "maxTerms": 10,
        "frequencyThreshold": 1,
        "showAssetCount": true
      },
      "label": "folder",
      "className": "com.liferay.portal.kernel.search.facet.MultiValueFacet",
      "fieldName": "folderId"
    }
    
  5. 点击保存按钮。

  6. 关闭弹出窗口,执行之前所做的相同搜索,并注意差异。

参见

关于管理网页内容和文件的信息,请参考以下菜谱:

  • 第六章中的使用文档和媒体端口件管理 Liferay 中的文件菜谱,Liferay 中的文档和媒体

  • 第七章中的管理和显示网页内容菜谱,处理内容

关于标记和分类的信息,请参阅本章中的标记和分类内容菜谱

Solr 安装和配置

Apache Solr (lucene.apache.org/solr) 是建立在 Apache Lucene 之上的功能强大的搜索引擎。实际上,Apache Solr 是一个具有 REST API 的独立企业级搜索引擎。此解决方案的主要优势是它可以轻松地作为云服务安装。Apache Solr 有许多其他优势,例如高流量优化、管理界面、易于监控、高可扩展性和容错性,等等。有关这些功能的更多信息,请参阅官方站点 lucene.apache.org/solr/features.html

Apache Solr 支持模式模式和无模式模式。模式是一个构建索引并定义由其组成的字段的地方。无模式模式允许用户通过简单地索引样本数据来快速构建一个有效的模式,而无需手动编辑模式。名为 solr4-web 的 Liferay 插件提供模式和 Solr 配置。因此,我们将使用此配置在定义的模式模式下运行 Solr。

如何做到这一点…

在这个菜谱中,我们将向您展示安装和运行带有 Liferay 的 Solr 服务器的最简单方法。

首先,我们需要安装 Apache Solr 4。最新的 Solr 4 版本是 4.10.4。按照以下步骤使用 Liferay 模式和配置运行 Solr:

  1. 从官方站点 archive.apache.org/dist/lucene/solr/ 下载捆绑了 Jetty 的 Apache Solr 4 版本(4.10.4)。

  2. 在您的本地机器上解压缩 solr-4.10.4.tgz

    tar -xzvf solr-4.10.4.tgz
    
    
  3. 从官方 Liferay 仓库 github.com/liferay/liferay-plugins/tree/6.2.x/webs/solr4-web/docroot/WEB-INF/conf 下载 solrconfig.xmlschema.xml

  4. solrconfig.xmlschema xml 复制到 solr-4.10.3/example/solr/collection1/conf

  5. 运行 Apache Solr:

    solr-4.10.3/bin/solr start
    
    

    Solr 应该打印以下消息:

    等待看到 Solr 在端口 8983 上监听 [/]

    在端口 8983 上启动 Solr 服务器(pid=2821)。祝您搜索愉快!

  6. 在 Liferay 实例中,从市场安装 solr4-web 插件。

  7. 编辑 tomcat-7.0.42/webapps/solr4-web/WEB-INF/classes/META-INF/solr-spring.xml 文件,并更改 com.liferay.portal.search.solr.server.BasicAuthSolrServer 实例中的 url 属性:

    <property name="url" value="http://localhost:8983/solr" />
    
  8. 重启 Liferay 实例。

  9. 以管理员身份登录到 Liferay 门户。

  10. 前往 管理 | 控制面板 | 服务器管理,然后在 重新索引所有搜索索引 部分的 执行 按钮上单击。

  11. 在前端,添加带有 搜索 小部件的 搜索 页面。

  12. 搜索 小部件中输入关键词以查找您的数据。

它是如何工作的…

Apache Solr 是一个功能强大的搜索引擎,拥有许多配置文件。为了运行 Apache Solr 和 Liferay,我们需要覆盖两个文件:schema.xmlsolrconfig.xml

第一个文件定义了 Liferay 中可用的字段和字段类型。schema.xml 文件有两个部分:typesfields

The Types 部分定义了所有可能的字段类型,例如布尔值、整数、浮点数、双精度浮点数等。最重要的字段是文本,其定义如下:

<fieldType class="solr.TextField" name="text" positionIncrementGap="100">
  <analyzer type="index">
    <tokenizer class="solr.WhitespaceTokenizerFactory" />
    <filter class="solr.LowerCaseFilterFactory" />
    <filter class="solr.RemoveDuplicatesTokenFilterFactory" />
    <filter class="solr.StopFilterFactory" enablePositionIncrements="true" ignoreCase="true" words="stopwords.txt" />
    <filter catenateAll="0" catenateNumbers="1" catenateWords="1" class="solr.WordDelimiterFilterFactory" generateNumberParts="1" generateWordParts="1" />
  </analyzer>
  <analyzer type="query">
    <tokenizer class="solr.WhitespaceTokenizerFactory" />
    <filter class="solr.LowerCaseFilterFactory" />
    <filter class="solr.RemoveDuplicatesTokenFilterFactory" />
    <filter class="solr.StopFilterFactory" enablePositionIncrements="true" ignoreCase="true" words="stopwords.txt" />
    <filter class="solr.SynonymFilterFactory" expand="true" ignoreCase="true" synonyms="synonyms.txt" />
    <filter catenateAll="0" catenateNumbers="0" catenateWords="0" class="solr.WordDelimiterFilterFactory" generateNumberParts="1" generateWordParts="1" />
  </analyzer>
</fieldType>

让我们尝试分析这个定义:

  • 这一定义的第一行包含了一个名为 text 的字段类型名称,以及实现该类型的 solr.TextField 类。在这个例子中,solr. 前缀代表 org.apache.solr.schemaPositionIncrementGap 属性指定了多个值之间的距离,这可以防止虚假的短语匹配。

  • 接下来的几行是 index analyzerquery analyzer 的定义。index 类型表示数据在添加到索引时进行分析。query 类型指定了查询时间(搜索)中的分析器。

现在,让我们尝试查看代码中使用的其他术语:

  • solr.WhitespaceTokenizerFactory:这会在空白处分割文本流。以下是一个示例:

    输入:This is an example

    输出:"This", "is", "an", "example"

  • solr.LowerCaseFilterFactory:这会将标记中的任何大写字母转换为等效的小写字母。以下是一个示例:

    输入:"This", "is", "an", "example"

    输出:"this", "is", "an", "example"

  • solr.RemoveDuplicatesTokenFilterFactory:这会从流中移除重复的标记。以下是一个示例:

    输入:"one", "two", "two", "three"

    输出:"one", "two", "three"

  • solr.StopFilterFactory:这会移除给定停用词列表中的标记。

    • stopwords.txt 包含诸如 hatelove 等单词。以下是一个示例:

    输入:"I", "hate", "my", "job"

    输出:"I", "my", "job"

  • solr.WordDelimiterFilterFactory:这会根据特定规则分割标记。请参阅官方 Solr 文档wiki.apache.org/solr/AnalyzersTokenizersTokenFilters#solr.WordDelimiterFilterFactory,了解可能的配置。

  • schema.xml 的下一部分是字段部分。它包含所有字段定义。通常,Apache Solr 提供三种类型的字段:

    • defining fields:这是一个典型的声明性字段定义。每个定义都有以下属性:

      <field indexed="true" name="content" stored="true" termPositions="true" termVectors="true" type="text" />
      
    • copying fields:这是制作具有不同分析器或过滤器的字段副本的机制。在我们的 schema.xml 文件中未使用。

    • dynamic fields:这允许我们定义没有明确定义的字段。在我们的 schema.xml 中,它用于多语言字段:

      <dynamicField indexed="true" multiValued="true" name="*_en" stored="true" termPositions="true" termOffsets="true" termVectors="true" type="text_en" />
      

每个字段定义都可以包含以下属性:

  • name:字段的名称

  • type:一个引用,指向在 <types> 部分中定义的字段类型

  • default:一个默认值,将自动添加到任何没有值的文档中

其他属性是可选的。官方 Apache Solr 文档中提供了可选属性的完整列表,请参阅cwiki.apache.org/confluence/display/solr/Defining+Fields

下一个文件名为solrconfig.xml的是 Solr 搜索引擎中最重要的配置文件。

solrconfig.xml中更常用的元素包括:

  • 使用<datadir>参数指定索引数据目录的位置

  • <query>标签的子元素中配置的查询和缓存设置

  • 处理发送到 Solr 的请求的<requestHandle>部分

  • <searchComponent>部分定义了SearchHandler用于执行用户查询的逻辑

所有文档均可在官方 Apache Solr 网站上找到:cwiki.apache.org/confluence/display/solr/Configuring+solrconfig.xml

第九章:Liferay 工作流功能

在本章中,我们将涵盖以下主题:

  • Kaleo 网页安装

  • 用户创建过程中的单一审批者工作流

  • 网页内容创建和分叉-合并工作流程

  • 消息板示例中的 Kaleo 条件

  • Kaleo 定时器

简介

工作流是一系列完成任务的必要活动。换句话说,工作流由一系列通过转换连接的状态组成。每个状态在其之前都有一个特定的步骤,在其之后也有一个特定的步骤。一般来说,它是一个线性定义的过程,描述了状态之间的流程。术语工作流表明人们如何工作以及他们如何处理信息。为了理解工作流定义,让我们定义其特定的词汇:

  • 状态:这个术语描述了一个唯一的状态,将在工作项上执行特定的动作(或多个动作)。例如,新创建、批准、提交、完成、删除等。

  • 任务:这定义了在状态之间对工作项执行的活动。

  • 转换:这定义了从一种状态到另一种状态的转换规则。这意味着转换描述了一个任务列表,这些任务必须完成以将项目从一种状态转换到另一种状态。

Liferay Portal 包含一个名为 Kaleo 的工作流引擎。此引擎提供定义和部署工作流定义的功能。Kaleo 是一个外部网页插件,需要像其他插件一样进行部署。当前版本的 Kaleo 可在 Liferay 市场中找到。

Kaleo 网页安装

Kaleo 工作流引擎被定义为网页插件。简而言之,网页插件是一个普通的网页应用程序,它还提供了使用基于 Service Builder 和其他 Liferay 插件(如钩子、插件等)构建的 Liferay 服务层的功能。一般来说,它是一个典型 servlet 应用程序和 Liferay 特定插件的混合体。

准备工作

为了正确安装 Liferay 插件,需要在官方 Liferay 网站上创建一个账户。此账户允许你在市场上下载插件,在论坛上讨论,创建博客等。

如何操作...

在 Liferay 6.1.1 GA2 版本中,Liferay 提供了一个市场插件来安装所有可用的插件。在 Liferay 6.2 中,市场插件已经安装,因此 Kaleo 插件的安装非常简单。为了安装 Kaleo 工作流,请按照以下步骤进行:

  1. 在内联网上以管理员身份登录。

  2. 导航到 Admin | Control Panel

  3. Apps 部分中选择 Store 选项。

  4. 通过输入 Liferay 登录名和密码进行身份验证。

    备注

    如果 Liferay 提供了一个新的市场插件,将会有一个向导来更新插件并下载最新版本。

  5. 在市场搜索表单中,输入 Kaleo Workflow CE 并选择正确的结果。

  6. 点击 Free 按钮。

  7. 选择或创建一个新的项目进行购买;阅读并接受使用条款。填写法人实体名称并点击购买按钮。

  8. 系统应显示以下消息:

    谢谢!

    您的收据 ID 号码是<RECEIPT_ID>

    此订单的确认邮件已发送至您的收件箱

    点击“查看已购买”以在线查看和管理您的购买,或者您可以通过 Liferay 门户实例进入市场并从那里管理您的购买

  9. 导航至已购买的应用并点击安装按钮。

  10. 确认控制面板 | 配置部分中有一个工作流标签。

它是如何工作的…

Liferay 使用其自己的产品进行工作流实现。所有 Kaleo 实体都是由服务构建器机制生成的。

这意味着service.xml定义了一组实体:Kaleo Action、Kaleo Condition、Kaleo Definition、Kaleo Instance、Kaleo Instance Token、Kaleo Log、Kaleo Node、Kaleo Notification、Kaleo Notification Recipient、Kaleo Task、Kaleo Task Assignment、KaleoTask Assignment Instance、Kaleo Task Instance Token、Kaleo Timer、Kaleo Timer Instance Token、Kaleo Transition。不需要了解所有这些实体及其关系的含义。

安装成功后,Liferay 环境中将出现几个新选项:

  • 控制面板 | 配置部分中的工作流选项:这是一个全局工作流配置,允许您定义新的工作流定义并管理资产之间的默认工作流(例如,网页内容文章、用户、博客等)。

  • 管理员 | 站点管理 | 配置中的工作流配置:这定义了当前站点的工作流。

  • 我的工作流任务标签在{USERNAME} | 我的账户部分:此功能列出分配给特定用户的所有挂起和完成的工作流任务。

  • 我的提交{USERNAME} | 我的账户部分:这提供了提交审查流程的资产列表。

此外,Kaleo 添加了特定的角色,这些角色可用于工作流定义:

  • 组织内容审查员

  • 门户内容审查员

  • 网站内容审查员

参见

有关如何管理文件或网页内容的更多信息,请参阅

  • 在第六章的在 Liferay 中使用文档和媒体组件管理文件配方中,Liferay 中的文档和媒体

  • 在第七章的使用内容管理网页内容配方中,使用内容在 Liferay 中使用文档和媒体组件管理文件配方在第六章中,Liferay 中的文档和媒体

用户创建过程的单个审批者工作流

默认情况下,Kaleo 工作流提供单个审批者定义。此工作流在发布任何资产之前需要经过一个审批状态。

我们将向您展示如何使用此工作流进行用户创建过程。

如何做到这一点…

启用单个审批者定义是一个简单的过程。为了激活用户创建的工作流,请执行以下步骤:

  1. 导航到管理员 | 控制面板 | 配置 | 工作流标签页。

  2. 选择默认配置标签页

  3. 找到用户资源并选择单个审批者(版本 1)定义。

  4. 点击保存按钮。

    小贴士

    要检查单个审批者如何工作,请尝试在登录端口创建一个新账户。

  5. 打开登录端口页面。默认情况下,它位于主页上。

  6. 选择创建账户选项并填写表格。

  7. 提交表单后,系统应显示以下消息:

    感谢您创建账户。您的账户被批准后,将通过电子邮件通知您,电子邮件地址为 your-mail@example.com。

这个过程的最后一步是批准一个新用户。为了实现这一点,请按照以下步骤操作:

  1. 以管理员身份登录。

  2. 导航到我的账户 | 我的工作流任务。

  3. 查找一个处于审查状态的任务,并通过点击表格中的超链接来编辑它。

  4. 分配给字段旁边选择分配给我选项。

  5. 批准用户(在对话框中,可以写评论)。如何操作…

  6. 前往完成标签页并检查结果。批准的用户应该在该列表中。

    注意

    只有分配了任务的用户才能将其转移到下一个任务或状态。

如何工作…

为了理解这个过程,让我们检查单个审批者定义(位于webapps/kaleo-web/WEB-INF/classes/META-INF/definitionssingle-approver-definition.xml)。这个定义可以表示如下:

如何工作…

状态

此流程的起点是一个名为created的状态。该状态的定义位于single-approver-definition.xml文件的开始部分:

<state>
  <name>created</name>
  [..]
  <initial>true</initial>
  <transitions>
    <transition>
      <name>review</name>
      <target>review</target>
    </transition>
  </transitions>
</state>

状态节点包含:

  • name:这是状态的名字

  • initial:这是一个表示初始状态的标志

  • transitions列表:在这个例子中,只有一个名为review的转换

转换节点可以定义:

  • name:这是转换的名字

  • target:这是目标状态或任务的名字

  • default:这是一个标记转换为默认的标志

任务

我们流程的下一步是一个名为reviewreview任务,它由一个名为review的转换定义。任务是在工作流定义中最复杂的结构。任务审查是用户可以决定是否批准或拒绝资产的地方。此任务的定义如下:

<task>
  <name>review</name>
  <actions>
    <notification>
      <name>Review Notification</name>
      <template>${userName} sent you a ${entryType} for review in the workflow.</template>
      <template-language>freemarker</template-language>
      <notification-type>email</notification-type>
      <notification-type>user-notification</notification-type>
      <execution-type>onAssignment</execution-type>
    </notification>
     [...]
  </actions>
  <assignments>
    <roles>
      [...]
    </roles>
  </assignments>
  <transitions>
     [...]
  </transitions>
</task>

任务的主要属性包括:

  • name:这是任务的名字,例如,review。

  • actions:这指定了动作元素或通知元素的列表。在这个例子中,动作只包含电子邮件通知。

  • assignments:这指定了分配给特定任务的角色的列表或用户列表。

  • transitions: 这指定了转换元素列表,描述了改变状态或任务的所有可能方式。在这个例子中,是批准或拒绝。

通知

让我们更深入地了解动作定义。正如我们之前提到的,动作可以包含通知元素和/或动作元素:

<notification>
  <name>Review Notification</name>
  <template>${userName} sent you a ${entryType} for review in the workflow.</template>
  <template-language>freemarker</template-language>
  <notification-type>email</notification-type>
  <notification-type>user-notification</notification-type>
  <execution-type>onAssignment</execution-type>
</notification>

通知节点有以下选项:

  • name: 这是通知的名称

  • template: 这定义了通知的消息

  • template-language: 这是三个选项之一:freemarker、velocity 和 text

  • notification-type: 这指定了电子邮件、IM、私信或用户通知

  • execution-type: 这指定了三个选项之一:onAssignment(当特定用户被分配到特定资产时发送通知),onExit(当特定资产离开状态或任务时发送通知),以及onEntry(当特定资产进入状态时发送通知)

    注意

    IM 类型和私信类型目前是占位符。这意味着 Kaleo Web 不支持这些类型。

动作

第二种可能性是定义一个动作,如下面的代码所示:

<action>
  <name>approve</name>
  <script>
    <![CDATA[ {script here} ]]>
  </script>
  <script-language>groovy</script-language>
  <execution-type>onEntry</execution-type>
</action>

动作元素具有简单的结构,但它是一个强大的工具,可以调用 Liferay 中的每一块代码。动作包含:

  • name: 这指定了动作的名称。

  • script: 这指定了脚本定义。在本节中,可以编写将在定义执行类型时调用的代码。

  • script-language: 这定义了脚本中将使用的语言,例如 Groovy、BeanShell、DRL、JavaScript、Python、Ruby。最常用的是 BeanShell。

  • execution-type: 这指定了三个选项之一:onAssignment(当特定用户被分配到特定资产时发送通知),onExit(当特定资产离开状态或任务时发送通知),以及onEntry(当特定资产进入某个状态时发送通知)。

网页内容创建和分支-合并工作流程

假设我们的目标是创建一个 Kaleo 定义,以便根据以下要求发布文章。每个人都可以撰写文章并将其提交给审稿人。审查阶段有两个独立的(并行)步骤:

  • UI 质量审查

  • 内容质量审查

只有在这些步骤之后,才有可能发布文章。在这个菜谱中,我们将展示如何使用分支和合并功能来创建 Kaleo 定义。分支和合并用于并行处理目的。因此,它们将是解决我们问题的良好方案。

如何做到这一点…

首先,让我们可视化工作流程并定义状态、任务和转换。此图将帮助我们理解整个过程:

如何做到这一点…

如前图所示,在我们的工作流程中有以下组件:

  • 创建批准状态

  • UI 质量审查内容质量审查任务

  • Fork 和 join 功能。

第二步是编写一个原型,它定义了之前列出的状态、任务和转换:

注意

这只是一个真实定义的草稿。你将在本章的代码文件以及这本书中找到工作定义。

<?xml version="1.0"?>
<workflow-definition>
  <name>Fork-Join Example</name>
  <state>
    <name>created</name>
    <transitions>
      <transition>
        <name>review-process</name>
        <target>review-process</target>
      </transition>
    </transitions>
  </state>
  <fork>
    <name>review-process</name>
    <transitions>
      <transition>
        <name>UI Quality Review</name>
      </transition>
      <transition>
        <name>Content Quality Review</name>
      </transition>
    </transitions>
  </fork>
  <task>
    <name>UI Quality Review</name>
    <transitions>
      <transition>
        <name>Submit</name>
        <target>join-tasks</target>
      </transition>
    </transitions>
  </task>
  <task>
    <name>Content Quality Review</name>
    <transitions>
      <transition>
        <name>Submit</name>
        <target>join-tasks</target>
      </transition>
    </transitions>
  </task>
  <join>
    <name>join-tasks</name>
    <transitions>
      <transition><name>approved</name></transition>
    </transitions>
</join>
  <state><name>approved</name></state>
</workflow-definition>

第三步是通过指定每个节点来完成前面的定义。这可以通过从单个审批者定义中复制部分内容来完成。

下一步是将这个定义上传到 Kaleo 工作流配置中,该配置位于 管理员 | 控制面板 | 配置 | 工作流 部分。上传 Kaleo 定义后,应该会显示成功消息。现在,新的定义将在 定义 选项卡中可见。

最后一步是为网络内容文章启用新的工作流定义。这一步在之前的配方中已有描述。

它是如何工作的...

这个定义使用了网络内容文章的 fork 和 join 功能。一般来说,当作者添加新的网络内容并将其提交以供发布时,Kaleo 工作流会创建两个任务:UI 质量审查和内容质量审查。只有在这两个任务被接受后,文章状态才会变为批准。当审查过程正在进行时,文章具有挂起状态。

让我们深入探讨 forkjoin 的定义。

Fork 元素

Fork 的结构与状态元素类似。fork 的主要功能是以并行方式创建任务列表。主要元素包括:

  • name:这指定了在转换定义中使用的 fork 名称

  • transitions:这指定了要创建的转换(任务或状态)列表

Fork 元素具有许多其他功能和元素,例如脚本、定时器、操作等。它可以具有非常复杂的结构,具有大量功能。在本配方中,我们只描述了该元素的基本功能。

Join 元素

Join 是 fork 的永恒伴侣。这对总是在一起。这个元素的主要责任是等待,除非所有并行任务都执行并被接受。join 元素具有以下结构:

  • name:这指定了 join 的名称,该名称用于转换定义

  • transitions:这指定了转换列表。通常只有一个转换,它描述了连接过程后的状态或任务。

Join 的结构完全与 fork 相同。它可以具有非常复杂的结构,具有众多功能。

还有更多...

除了 join 元素外,还可以使用 join-xor 元素。joinjoin-xor 之间的主要区别在于,join 等待所有并行任务完成,而 join-xor 只等待第一个完成的任务。

Join-xor 元素

join-xor 元素与 join 的定义相同:

  • name:这指定了在转换定义中使用的 join 名称。

  • transitions: 这指定了转换列表。通常只有一个转换,它描述了连接过程后的状态或任务。

参见

有关管理网络内容的更多信息,请参阅第七章中的管理和显示网络内容配方,与内容一起工作

消息板示例中的 Kaleo 条件

Kaleo 工作流程包含条件。可以使用条件来分支工作流程并执行不同的任务。让我们假设我们是消息板管理员。在我们的公司中,有一个用户必须接受新线程,许多用户接受线程中的回复。可以使用 Kaleo 工作流程条件实现这种允许消息板这样工作的功能。

如何做…

此定义类似于分支和合并工作流程,但存在很大差异。没有并行工作流程任务。相反,有一个条件,它将实体移动到不同的状态。显然,工作流程是相同的:用户创建一个新的实体,管理员接受它。在定义特定任务的角色之间几乎没有差异。

如前一个示例所示,让我们可视化工作流程并定义状态、任务和转换。以下图表将帮助您更好地理解整个过程:

如何做…

上述图表包含以下组件:

  • 创建批准状态

  • 正常审查主线程审查任务

  • 条件语句。

让我们定义这些定义:

<?xml version="1.0"?>
<workflow-definition>
  <name>Condition Example</name>
  <state>
    <name>created</name>
    <transitions>
      <transition>
        <name>determine-branch</name>
        <target>determine-branch</target>
      </transition>
    </transitions>
  </state>
  <condition>
    <name>determine-branch</name>
    <script>
      <![CDATA[SCRIPT DEFINITION]]>
    </script>
    <script-language>groovy</script-language>
    <transitions>
      <transition>
        <name>Normal Review</name>
        <target>Normal Review</target>
        <default>false</default>
      </transition>
      <transition>
        <name>Main Thread Review</name>
        <target>Main Thread Review</target>
        <default>false</default>
      </transition>
    </transitions>
  </condition>

  <task>
    <name>Normal Review</name>
    <transitions>
      <transition>
        <name>Submit</name>
        <target>approved</target>
      </transition>
    </transitions>
  </task>
  <task>
    <name>Main Thread Review</name>
    <transitions>
      <transition>
        <name>Submit</name>
        <target>approved</target>
      </transition>
    </transitions>
  </task>

  <state><name>approved</name></state>
</workflow-definition>

在定义 Kaleo 之后,让我们编写一个表示我们的 Kaleo 条件的条件脚本。在这个例子中,我们将使用 Groovy 脚本,它将被放置在<condition>定义中的<script>标签内。所以,让我们定义它:

import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.workflow.WorkflowConstants;
import com.liferay.portlet.messageboards.service.MBMessageLocalServiceUtil;
import com.liferay.portlet.messageboards.model.MBMessage;

String className = (String)workflowContext.get(
WorkflowConstants.CONTEXT_ENTRY_CLASS_NAME);
boolean isMBMessage = false;
if (className.equals(MBMessage.class.getName())) {
  isMBMessage = true;
}
returnValue = "Answers Review";
long classPK = GetterUtil.getLong(
(String)workflowContext.get(WorkflowConstants.CONTEXT_ENTRY_CLASS_PK));
if (isMBMessage) {
  MBMessage mbMessage = MBMessageLocalServiceUtil.getMBMessage(classPK);
  if (mbMessage.isRoot()) {
 returnValue = "Main Thread Review";
  }
}

它是如何工作的…

在前一个示例中,我们解释了工作流程定义,它可以应用于所有类型的资产(例如,用户、网络内容文章、消息板等)。在每种类型中,都有一个典型的流程:已创建 | 正常审查任务 | 批准。然而,如果我们将此工作流程应用于消息板实体,它将有一个不同的流程:已创建 | 主线程审查 | 批准

为什么会发生这种情况?Groovy 脚本定义了一个条件并确定了完整的流程。

第一行获取className定义。接下来,if 语句检查这是否是MBMessage实体。

接下来的几行获取特定的mbMessage对象并检查此对象是否是MBMessage的根。值得注意的是,有一些预定义的值:

  • returnValue: 这包含转换的目标

  • workflowContext: 此对象实现了WorflowContext接口

条件语句

<condition>标签具有以下结构:

  • name: 这是条件的名称。

  • script: 这定义了一个条件。

  • script-language: 这定义了在脚本中将使用的语言,例如:Groovy、BeanShell、DRL、JavaScript、Python、Ruby。最常见的是 BeanShell。

  • transitions: 这指定了转换列表。

Kaleo 计时器

最后一个配方涉及计时器。此功能允许用户定义在特定时间后应执行的具体操作。让我们通过条件示例稍微修改一下之前的配方,并添加一个计时器定义。我们的假设是,名为 Main Thread Review 的任务不应等待超过一小时才分配给任何用户。一小时后,此任务应分配给具有test@liferay.com电子邮件地址的用户。

如何操作...

首先,打开之前的定义并找到 Main Thread Review 任务。在 assignments 标签和 transitions 标签之间,输入以下代码:

<?xml version="1.0" encoding="UTF-8"?>
<task-timers>
  <task-timer>
    <name>default-assignment</name>
    <delay>
      <duration>1</duration>
      <scale>hour</scale>
    </delay>
    <blocking>true</blocking>
    <timer-actions>
      <timer-notification>
        <name />
        <template />
        <template-language>text</template-language>
        <notification-type>im</notification-type>
      </timer-notification>
      <reassignments>
        <user>
          <email-address>test@liferay.com</email-address>
        </user>
      </reassignments>
    </timer-actions>
  </task-timer>
</task-timers>

它是如何工作的...

Kaleo 网络插件使用户能够在特定时间后对用户的行为做出反应。它允许您将任务分配给特定用户,发送通知等等。

<task-timers>标签具有以下结构:

  • task-timer: 这指定了具有计时器定义的复杂类型。

  • name: 这指定了计时器的名称。

  • delay: 这指定了延迟定义并定义了计时器在执行其操作之前将等待多长时间。例如,1 小时、5 分钟等等。

  • recurrence(在此示例中未使用):根据指定的参数触发操作多次。例如,每 1 小时,定义调用特定操作。

  • blocking: 如果这是 true,则停止工作流引擎执行,直到计时器执行。

  • timer actions: 这指定了在延迟定义之后要执行的操作列表。

第十章. 协作工具

在本章中,我们将涵盖以下主题:

  • 设置内网的博客

  • 设置维基端口

  • 设置内网的论坛

  • 因不适当帖子禁止用户

  • 将日历设置为个人任务管理工具

  • 使用书签来存储喜欢的链接

  • 跟踪站点成员的社会活动

  • 使用公告端口进行群组消息传递

简介

Liferay 提供了一系列协作工具,这些工具可以通过鼓励员工在其项目团队、部门或整个公司内部生成和共享信息,从而有效地提高员工之间的沟通。内网用户可以创建博客、参与论坛、构建企业知识库作为一系列维基页面、收集有用的链接、接收或发布重要消息,并在日历中规划他们的工作。他们还可以跟踪其他员工的活动。

设置内网的博客

Liferay 中的每个站点都有自己的独立博客,可以通过访问管理 | 站点管理 | 内容 | 博客来访问。此外,还可以将博客端口放置在其中一个页面上,这样没有访问管理功能的用户之间也可以共享。

博客端口显示由站点成员创建的博客条目。一个博客条目可以包含文本、图形、表格、列表以及指向其他资产的链接。此外,每个博客条目都可以被标记和分类,或者提供与其相关的资产列表,这些列表将显示在博客条目主要内容下的相关资产部分。还可以定义权限,指定不同角色的用户可以执行哪些操作。

在这个菜谱中,我们将向您展示如何通过在此站点内放置博客端口来为站点成员创建一个共享博客。我们还将向您展示如何配置此博客端口以最好地满足用户的需求。

如何操作…

让我们假设我们公司的公关部门希望启动一个由不同部门的员工撰写的博客,向其他员工介绍有趣的商业倡议。他们希望在页面上显示 10 个最新博客条目的列表(列表中的每个博客条目应以摘要形式呈现,用户点击后可跳转到完整内容),但不想允许用户对其他用户的条目进行评论或评分。该博客还应提供一些电子邮件通知和 RSS 功能,以帮助人们保持更新。

在第一步中,我们将添加博客端口到页面。为了做到这一点,请按照以下步骤操作:

  1. 以管理员身份登录并转到应放置博客端口的页面。

  2. 点击添加按钮(这是左侧的+符号)。

  3. 点击应用程序选项卡。

  4. 使用搜索机制或通过浏览可用端口的列表(博客端口可在 协作 部分找到)查找博客端口。

  5. 点击端口名称旁边的 添加 链接。带有基本配置的博客端口将被添加到页面中。

在将博客端口添加到页面后,我们可以更改其默认配置。要配置博客端口,请按照以下步骤操作:

  1. 点击新添加的端口的选项图标(这将在端口的右上角显示为一个齿轮图标)。

  2. 选择 配置 选项。如何操作…

  3. 显示最大项数 设置为 10

  4. 显示模板 设置为 摘要

  5. 禁用 启用旗帜 选项。

  6. 禁用 启用相关资产 选项。

  7. 禁用 启用评分 选项。

  8. 禁用 启用评论 选项。

  9. 禁用 启用评论评分 选项。

  10. 禁用 启用社交书签 选项。

  11. 点击 保存 按钮。

  12. 点击 发件人 标签。

  13. 提供发件人的 姓名地址

  14. 点击 保存 按钮。

  15. 点击 条目添加电子邮件条目更新电子邮件 标签。

  16. 设置 启用 选项。

  17. 提供主题 Subject 和正文 Body

  18. 点击 保存 按钮。

  19. 点击 RSS 标签。

  20. 保持 启用 RSS 订阅 选项启用。

  21. 显示最大项数 设置为 10

  22. 显示样式 列表中选择 摘要 选项。

  23. 保持 格式 选项不变。

  24. 点击 保存 按钮。

它是如何工作的…

博客端口的配置允许我们设置以下选项:

  • 显示最大项数:此选项定义了博客端口单页上显示的博客条目数量

  • 显示模板:此选项允许我们选择资产应如何显示(作为标题列表、完整内容、摘要等)

  • 启用旗帜:此选项启用旗帜功能,提供用于通知异常的联系方式表单

  • 启用社交书签:此选项显示 Google+、Facebook 和 Twitter 分享按钮

  • 启用相关资产:此选项启用博客条目的相关资产部分,显示为每个维基页面定义的相关资产列表

  • 启用评分:此选项启用评分功能,允许我们为每个博客条目评分,并显示每个条目的平均评分

  • 启用评论:此选项启用评论功能,允许您对每个博客条目进行评论

  • 启用评论评分:此选项启用评论评分功能,允许您为博客中的每个评论投票,并显示每个评论的投票数

  • 显示模板:此选项允许您选择用于显示维基页面的模板

  • 发件人:此标签允许您提供发件人的姓名和电子邮件地址

  • 新增条目电子邮件更新条目电子邮件:这些标签允许您启用电子邮件消息功能,并使用可用的变量设置主题和消息内容

  • 启用 RSS 订阅:此选项允许用户使用 RSS 跟踪活动

  • 显示样式:此选项允许您决定是否显示完整内容、摘要或标题

  • 最大显示项目数:此选项允许我们设置 RSS 频道显示的最大项目数

  • 格式:此选项允许我们决定 RSS 是否应以 Atom 1.0、RSS 1.0 或 RSS 2.0 格式提供服务

相关链接

关于如何配置 SMTP 服务器的信息,请参阅第十一章“快速技巧和高级知识”中的配置 Liferay 与 SMTP 服务器配方,快速技巧和高级知识

设置维基小部件

Liferay 提供了维基功能,允许我们创建一个由员工社区协作开发的类似常见维基百科的企业数据库。可以通过访问管理|站点管理|内容|维基或使用维基小部件来访问维基功能,该小部件允许用户在位于站点页面上的页面上管理和展示维基页面。

维基小部件展示的每个维基页面都可能包含文本、标题、列表、图片、表格和链接,这些可以使用简单的 creole、MediaWiki 或 HTML 语言定义。此外,维基还包括链接跟踪机制,它提供有关传入和传出链接的信息,并允许我们通过定义到它们的链接来创建新页面。在编辑维基页面时,用户可以提供对所做工作的额外描述。这使用户能够跟踪不同用户所做的更改。

在本配方中,我们将向您展示如何配置维基小部件以最好地满足用户需求。

如何操作...

假设我们公司内部网络中的维基功能(除所有管理功能外)应提供对维基页面进行评论和评分的可能性。此外,当页面添加或修改时,用户应收到电子邮件通知。但是,不需要 RSS 功能。

要将维基小部件添加到页面,请执行以下步骤:

  1. 以管理员身份登录并转到应放置维基小部件的页面。

  2. 点击添加按钮(这是左侧的+号)。

  3. 点击应用程序标签。

  4. 使用搜索功能或通过浏览可用小部件列表(博客小部件可在协作维基部分找到)来查找维基小部件。

  5. 点击小部件名称旁边的添加链接。带有基本配置的维基小部件将被添加到页面中。

在将维基小部件添加到页面后,可以更改其默认配置。要配置维基小部件,请按照以下步骤操作:

  1. 点击新添加的端口的选项图标(这将在端口的右上角显示为一个齿轮图标)。

  2. 选择配置选项。如何操作…

  3. 确保您在显示设置选项卡上。

  4. 取消勾选启用相关资产选项。

  5. 保持启用页面评分选项启用。

  6. 保持启用评论选项启用。

  7. 取消勾选启用评论评分选项。

  8. 保持显示模板可见 Wiki选项不变。

  9. 点击保存按钮。

  10. 点击发件人选项卡。

  11. 提供发送者的姓名地址

  12. 点击保存按钮。

  13. 点击页面添加电子邮件页面更新电子邮件选项卡。

  14. 设置启用选项。

  15. 提供一个主题正文签名

  16. 点击保存按钮。

  17. 点击RSS选项卡。

  18. 取消勾选启用 RSS 订阅选项。

  19. 点击保存按钮。

它是如何工作的…

Wiki 端口配置允许我们设置以下选项:

  • 启用相关资产:此选项启用 Wiki 页面的相关资产部分,显示为每个 Wiki 页面定义的相关资产列表

  • 启用页面评分:此选项启用评分功能,允许您对每个 Wiki 页面进行评分,并显示每个页面的平均评分

  • 启用评论:此选项启用评论功能,允许我们在每个 Wiki 页面上进行评论

  • 启用评论评分:此选项启用评论评分功能,允许您对 Wiki 页面上的每个评论进行投票,并显示每个评论的投票数

  • 显示模板:此选项允许您选择用于显示 Wiki 页面的模板

  • 可见 Wiki:此选项允许您定义哪些可用的 Wiki 应在此特定的 Wiki 端口中可见

  • 发件人:此选项允许您提供发送者的姓名和电子邮件地址

  • 页面添加电子邮件页面更新电子邮件:这些选项卡允许您启用电子邮件消息功能,并使用可用的变量设置主题和消息内容

  • 启用 RSS 订阅:此选项允许用户使用 RSS 跟踪活动

  • 显示样式:此选项允许您决定是否显示完整内容、摘要或标题

  • 最大显示项目数:此选项允许您设置 RSS 频道显示的最大项目数

  • 格式:此选项允许您决定 RSS 应以 Atom 1.0、RSS 1.0 或 RSS 2.0 格式提供服务

参见

有关如何配置 SMTP 服务器的信息,请参阅第十一章使用 SMTP 服务器配置 Liferay配方,快速技巧和高级知识

为内联网设置论坛

论坛是一个非常强大的协作和社会工具,允许多用户通信。Liferay Portal CMS 提供了一个基本的、现成的论坛功能,称为消息板。可以通过访问管理 | 站点管理 | 内容 | 消息板来使用消息板组件,使用消息板组件的是我们内网的用户。

如何操作…

在这个菜谱中,我们将向您展示如何将消息板组件添加到页面,以及如何设置它以最佳地满足我们的需求。

让我们从将消息板组件添加到页面开始。为此,请按照以下步骤操作:

  1. 以管理员身份登录并转到应放置消息板页面的页面。

  2. 点击添加按钮(这是左侧的+号)。

  3. 点击应用程序标签页。

  4. 使用搜索功能或通过浏览可用组件列表(消息板组件可在协作部分找到)查找消息板组件。

  5. 点击组件名称旁边的添加链接。具有基本配置的消息板将被添加到页面。

要配置消息板组件,请按照以下步骤操作:

  1. 点击新添加组件的选项图标(这将是组件右上角的齿轮图标)。

  2. 选择配置选项。如何操作…

  3. 确保您位于常规标签页。

  4. 禁用允许匿名发布选项。

  5. 保持默认订阅选项启用。

  6. 消息格式下拉列表中选择 HTML。

  7. 保持启用旗帜启用评分选项启用。

  8. 禁用默认将线程作为问题选项。

  9. 显示最近帖子列表中设置30 天选项。

  10. 点击保存按钮。

  11. 点击发件人邮箱标签页。

  12. 提供发件人的姓名地址

  13. 点击消息添加电子邮件消息更新电子邮件标签页。

  14. 设置启用选项。

  15. 提供一个主题正文签名

  16. 点击保存按钮。

  17. 点击线程优先级标签页。

  18. 以降序顺序输入每个级别的名称、图像和优先级等级。

  19. 点击保存按钮。

  20. 点击用户排名标签页。

  21. 通过输入排名和最小帖子对(例如,尤达 = 1000)来提供排名名称。

  22. 点击保存按钮。

  23. 点击RSS标签页。

  24. 确保已启用启用 RSS 订阅选项。

  25. 最大显示项目数设置为10

  26. 显示样式列表中选择摘要选项。

  27. 保持格式选项不变。

  28. 点击保存按钮。

它是如何工作的…

留言板提供典型的论坛机制,允许我们创建由类别和子类别构建的类似文件夹的结构。类别和子类别都可以包含其他子类别或线程,每个线程至少包含一个帖子。留言板中的线程可以被拆分(拆分的结果是从一个线程创建两个线程)或移动(通过移动,我们从一个已存在的两个线程中创建一个线程)。可以锁定线程以阻止用户添加更多帖子,并使其对用户以只读模式可用。更重要的是,留言板为留言板用户管理提供了禁止机制。禁止机制将在下一道菜谱中描述。

留言板端口配置允许我们设置以下选项:

  • 常规

    • 允许匿名发布:此选项允许您决定是否允许匿名用户创建帖子

    • 默认订阅:此选项允许您默认将用户订阅到他们参与的线程

    • 消息格式:此选项允许您选择添加消息的格式

    • 启用标记:此选项启用标记功能,提供用于通知异常的联系方式

    • 启用评分:此选项启用帖子评分功能,允许我们对每个帖子进行评分并显示其评分

    • 默认将线程标记为问题:启用此选项后,所有新线程默认标记为问题(新线程表单中的标记为问题选项被标记)。在线程列表中标记为问题的线程会标记为“等待回答”标志。

    • 显示最近帖子:此选项允许我们设置最近帖子标签页的周期。

  • 电子邮件通知

    留言板提供两种类型的电子邮件通知:新增留言电子邮件和更新留言电子邮件。以下是留言板电子邮件通知的配置选项:

    • 发件人:此标签页允许我们提供发件人的姓名和电子邮件地址

    • 新增留言电子邮件更新留言电子邮件:这些标签页允许我们启用电子邮件消息功能,并使用可用的变量设置主题、签名和消息内容。

  • 线程优先级

    可以为线程设置优先级。优先级较高的线程会显示在优先级较低的线程之前。线程优先级标签页允许我们通过为每个线程提供以下信息来定义多个优先级:

    • 名称:此选项显示优先级的名称

    • 图像:此选项显示优先级的图像(URL 或相对于主题的路径)

  • 用户等级用户等级标签页允许我们定义用户将获得的等级,以创建指定数量的帖子。

  • RSS:消息板组件还允许用户使用 RSS 跟踪活动。正如前一个配方中所示,组件配置允许我们选择:

    • RSS 频道显示的项目数量

    • 应显示全文、摘要还是标题

    • 应该以 Atom 1.0、RSS 1.0 还是 RSS 2.0 格式提供 RSS

参见

  • 关于如何配置 SMTP 服务器的信息,请参阅第十一章的使用 SMTP 服务器配置 Liferay配方,快速技巧和高级知识

  • 关于如何封禁和解封用户的信息,请参阅本章的因不当帖子封禁用户配方

因不当帖子封禁用户

消息板组件提供了一个内置的封禁机制,允许我们阻止用户查看和参与论坛。

如何操作…

要封禁一个用户,请执行以下步骤:

  1. 以管理员身份登录并转到消息板应放置的页面。

  2. 前往您想封禁的用户添加的帖子。

  3. 点击位于用户屏幕名(或姓名和姓氏)下的封禁此用户链接。如何操作…

  4. 点击消息板菜单中的封禁用户选项卡。您刚刚封禁的用户将出现在列表中。

要解封一个用户,请执行以下步骤:

  1. 点击消息板菜单中的封禁用户选项卡。

  2. 点击位于您想解封的用户屏幕名附近的解封此用户链接。该用户将从列表中消失,并且不再被阻止使用消息板。如何操作…

它是如何工作的…

如前一个配方所示,每个在消息板上添加过任何帖子的用户都可以被网站所有者和管理员(或任何具有允许执行此操作的定制角色的其他用户)封禁和解封。

被封禁的用户无法查看消息板的内容或添加新的类别、线程或帖子。如果消息板管理员(或具有封禁和解封其他用户权限的其他用户)没有解封,则被封禁的用户将在 10 天后自动解封。此默认值可以在message.boards.expire.ban.interval属性中更改(设置为 0 以禁用自动到期)。为了覆盖每个属性,您可以将特定属性放入${liferay.home}/portal-ext.properties文件中。

注意,还有一个message.boards.expire.ban.job.interval属性,允许我们输入解封用户作业运行的分钟数。这可能会影响解封用户的实际时间。如果封禁预计在中午 12:05 到期,而作业在下午 2 点运行,则到期将在下午 2 点的运行期间发生。

参见

关于如何配置消息板组件的信息,请参阅本章的为内联网设置论坛配方。

将日历设置为个人任务管理工具

Liferay 日历帮助用户管理他们的任务、时间和资源。日历端口允许我们创建事件、邀请其他用户参与,设置提醒,并管理其他用户可以预订的资源(如汽车或会议室)。事件可以按日、周、月或议程视图显示。日历端口提供了一些配置选项,有助于根据我们的需求调整日历功能。

如何操作…

要设置日历端口,您必须将其添加到页面上。为此,请执行以下步骤:

  1. 前往应放置日历端口的页面。

  2. 点击添加按钮(这是左侧的+号)。

  3. 点击应用程序选项卡。

  4. 使用搜索功能或浏览可用端口的列表(日历端口可在协作部分找到)查找日历端口。

  5. 点击端口名称旁边的添加链接。带有基本配置的日历端口将被添加到页面上。

要配置日历端口,请按照以下步骤操作:

  1. 点击新添加的端口的选项图标(这将在端口的右上角显示为一个齿轮图标)。

  2. 选择配置选项。如何操作…

  3. 确保您处于用户设置选项卡。

  4. 时间格式设置为24 小时

  5. 默认持续时间设置为60 分钟

  6. 默认视图设置为

  7. 周开始于选项设置为星期一

  8. 禁用使用全局时区选项。

  9. 时区设置为UTC

  10. 点击保存按钮。

  11. 点击RSS选项卡。

  12. 保持启用 RSS 订阅选项启用。

  13. 最大显示项目数设置为10

  14. 显示样式列表中选择摘要选项。

  15. 保持格式选项不变。

  16. 点击保存按钮。

它是如何工作的…

在配置日历端口时,您可以设置以下属性:

  • 时间格式:此选项允许您决定日历是否以 A.M./P.M.或 24 小时格式显示小时

  • 默认持续时间:此选项允许您设置事件的默认持续时间(仅适用于快速事件创建)

  • 默认视图:此选项允许您设置日历的默认视图

  • 周开始于:此选项允许您选择作为一周第一天的日期

  • 使用全局时区:此选项允许您决定日历是否根据全局时区设置或日历端口配置中时区字段指定的时区工作

  • 启用 RSS 订阅:此选项允许用户使用 RSS 跟踪活动

  • 显示样式:此选项允许您决定是否显示完整内容、摘要或标题

  • 最大显示项目数:此选项允许您设置 RSS 频道显示的最大项目数

  • 格式:此选项允许您决定是否以 Atom 1.0、RSS 1.0 或 RSS 2.0 格式提供 RSS

使用书签作为存储收藏链接的良好容器

书签功能允许用户收集、组织和共享有用的或喜欢的链接。Liferay 中的每个站点都有自己的独立书签存储库,可以通过访问管理 | 站点管理 | 内容 | 书签来访问。此外,还可能将书签端口放置在可以由没有访问管理功能的用户之间共享的页面上。

书签端口提供创建、编辑和删除书签文件夹和书签的工具。在本教程中,我们将向您展示如何配置书签端口以适应用户的需求。

如何做到这一点...

首先,让我们添加一个新的书签端口。为了做到这一点,请执行以下步骤:

  1. 前往应放置书签端口的页面。

  2. 点击添加按钮。

  3. 点击应用程序标签。

  4. 使用搜索功能或通过浏览可用端口的列表(书签端口可在社区部分找到)查找书签端口。

  5. 点击端口名称旁边的添加链接。带有基本配置的书签端口将被添加到页面上。

在将书签端口添加到页面后,我们可以更改其默认配置。要配置书签端口,请执行以下步骤:

  1. 点击新添加端口的选项图标(这将在端口的右上角显示为一个齿轮图标)。

  2. 选择配置选项。

  3. 通过点击选择按钮然后点击想要设置为根的文件夹旁边的选择按钮来选择根文件夹

  4. 启用显示搜索选项。

  5. 启用显示子文件夹选项。

  6. 每页文件夹数字段中输入10

  7. 显示列字段中保留选定的列。

  8. 点击保存按钮。

  9. 点击电子邮件来自选项卡。

  10. 提供发件人的姓名地址

  11. 点击保存按钮。

  12. 点击条目添加电子邮件条目更新电子邮件选项卡。

  13. 设置启用选项。

  14. 提供主题正文。

  15. 点击保存按钮。

它是如何工作的...

书签端口配置允许我们设置文件夹列表、书签列表和电子邮件通知消息。

以下是列出文件夹的以下选项:

  • 根文件夹:此选项允许我们选择将成为书签端口显示的最高(根)文件夹

  • 显示搜索:此选项启用书签端口内的搜索功能

  • 显示子文件夹:此选项允许我们定义在一页列表中显示的公告数量

  • 每页文件夹数:此选项允许我们决定在列表单页上显示的文件夹数量

  • 显示列:此选项允许我们在文件夹列表屏幕上选择要显示的列集。

以下是以下书签列表选项:

  • 启用相关资产:此选项启用相关资产功能,该功能在添加/编辑资产表单中列出所有定义为相关的资产。

  • 每页文档数:此选项允许我们决定在单个列表页面上显示的文件夹数量。

  • 显示列:此选项允许我们在文件夹列表屏幕上选择要显示的列集。

  • 发件人电子邮件:此选项卡允许我们提供发件人的姓名和电子邮件地址。

  • 页面添加电子邮件页面更新电子邮件:这些选项卡允许我们启用电子邮件消息功能,并使用可用的变量设置主题和消息内容。

相关信息

关于如何配置 SMTP 服务器的信息,请参阅第十一章“快速技巧和高级知识”中的使用 SMTP 服务器配置 Liferay配方,快速技巧和高级知识

跟踪网站成员的社会活动

活动端口显示了位于其中的网站成员的社会活动,并允许我们通过显示它们的位置来跟踪这些活动的产品。端口通知我们谁在网站上执行了某些活动以及这些活动何时执行,并展示这些产品的 URL 地址。

如何操作…

要在页面上配置活动端口,请执行以下步骤:

  1. 前往应放置活动端口的页面。

  2. 点击添加按钮(这是左侧的+符号)。

  3. 点击应用程序选项卡。

  4. 使用搜索功能或浏览可用端口的列表(活动端口可在社交部分找到)来查找活动端口。

  5. 点击端口名称旁边的添加链接。带有基本配置的活动端口将被添加到页面上。

  6. 点击新添加端口的选项图标(这将是端口右上角的齿轮图标)。

  7. 选择配置选项。如何操作…

  8. 确保您位于设置选项卡。

  9. 最多显示活动数列表中选择10

  10. 保持启用 RSS 订阅选项启用。

  11. 最多显示项目数设置为10

  12. 显示样式列表中选择摘要选项。

  13. 保持格式选项不变。

  14. 点击保存按钮。

工作原理…

活动端口列出了用户执行的活动,例如添加或编辑网页内容、Wiki 页面、论坛分类、帖子、线程、文档、快捷方式、博客条目、书签和日历事件。端口还通知我们用户对某些内容进行了评分。

组件列出了与组件配置中指示的相同数量的活动,该数量由最多显示活动数选项中设置的值确定。它还允许用户通过使用 RSS 跟踪活动。如前所述的配方中所示,组件配置允许我们选择以下内容:

  • RSS 频道显示的项目数量

  • 是否显示完整内容、摘要或标题

  • 是否以 Atom 1.0、RSS 1.0 或 RSS 2.0 格式提供 RSS。

更多内容

还可以在用户个人资料页面上使用活动组件。如果组件位于用户的个人资料页面上,它只显示此用户的操作。要配置用户个人资料页面上的活动组件,请点击用户菜单中的我的个人资料链接,并遵循之前指示的所有步骤。

使用公告组件进行群组消息传递

公告组件允许我们展示和管理称为公告的群组消息。公告功能允许我们向员工提供一些提醒或重要的组织信息。在公告组件中,每个用户只能看到针对他们所属的群组的消息。用户将通过电子邮件通知新的公告。

如何操作…

要配置公告组件,请执行以下步骤:

  1. 前往放置公告组件应放置的页面。

  2. 点击添加按钮(这是左侧的+符号)。

  3. 点击应用程序标签页。

  4. 使用搜索功能或通过浏览可用组件列表(公告组件可在社交部分找到)查找公告组件。

  5. 点击组件名称旁边的添加链接。带有基本配置的公告组件将被添加到页面中。

  6. 点击新添加组件的选项图标(这将是组件右上角的齿轮图标)。

  7. 确保您在设置标签页上。

  8. 选择配置选项。

  9. 最多显示条目数列表中选择10

  10. 点击保存按钮。

要创建新的公告,请执行以下步骤:

  1. 前往放置公告组件的页面。

  2. 点击管理条目标签页。

  3. 分发范围列表中选择站点成员角色。将出现添加条目按钮:如何操作…

  4. 点击添加条目按钮。

  5. 为公告提供标题(必填)。

  6. 为用户点击公告标题后将被重定向的页面提供URL

  7. 为公告提供内容

  8. 选择类型,例如,新闻

  9. 优先级设置为重要

  10. 保持显示日期不变。

  11. 保持立即显示选项启用。

  12. 设置过期日期

  13. 点击保存按钮。

要编辑公告,请执行以下步骤:

  1. 前往放置公告组件的页面。

  2. 点击位于您想要编辑的公告标题旁边的编辑链接。如何操作…

  3. 修改公告的标题、内容、优先级和类型。

  4. 设置显示日期或启用立即显示选项。

  5. 设置过期日期

  6. 点击保存按钮。

要删除公告,请执行以下步骤:

  1. 前往放置公告组件的页面。

  2. 前往条目标签页。

  3. 点击位于您想要删除的公告标题旁边的删除链接。

  4. 点击确定按钮。公告将被永久删除。

工作原理…

公告可以由网站管理员或具有创建公告权限的角色的其他用户创建。此类用户可以向特定用户组分发公告。然而,收到公告的用户无法回答或将其发送给其他用户(单向通信)。可以将公告分发给特定组织、网站、组或具有特定角色的所有用户。公告组件包含两个标签页:条目和管理条目标签页。条目标签页对所有用户可用,并列出针对每个用户的所有公告。管理标签页对具有管理公告权限的用户可见,允许我们创建、编辑和删除公告。

公告管理

在创建新的公告时,用户必须定义以下属性:

  • 分发范围:这允许您选择将收到消息的用户组。提供分发范围是强制性的。

  • 标题:将代表公告在列表中的标题文本。定义标题是强制性的。

  • URL:点击公告标题后显示的页面。

  • 内容:公告的内容。提供内容是强制性的。

  • 类型:公告的类型。类型在管理条目标签页的条目列表中显示为参数。

  • 优先级:这允许您定义公告的优先级。优先级决定了公告在列表中的位置。具有“重要”优先级的公告列在“正常”优先级之前。

  • 显示日期:这允许您定义公告显示的时间和日期。

  • 立即显示:此公告将在保存后立即显示。

  • 过期日期:这允许您定义公告过期的时间和日期。过期的公告不会在条目标签页中列出。

在添加新公告时,选择分发组非常重要。这是因为分发组是唯一不能通过编辑公告来更改的参数。

与其他类型的内容(如网页内容或文档,这些内容最初总是被移动到回收站)不同,删除公告会导致公告永久删除。

端口配置

Liferay 允许我们自定义此端口设置。为了更改设置,请将特定属性放入 ${liferay.home}/portal-ext.properties 文件中。

公告端口配置允许我们定义一个列表页上显示的公告数量。要设置每页显示公告数量的可用值,请使用 announcements.entry.page.delta.values=5,10,20,30,50,75 属性。

要设置公告类型列表,请使用 announcements.entry.types=general,news,test 属性。

您还可以设置 CheckEntryMessageListener 检查新公告的频率(以分钟为单位),并在发现新公告后通过电子邮件通知用户。要设置此间隔,请使用 announcements.entry.check.interval 属性。

第十一章。快速技巧和高级知识

在本章中,我们将涵盖以下主题:

  • 语言属性钩子

  • 设置门户会话时间和会话策略

  • 使用 SMTP 服务器配置 Liferay

  • 通过 antisamy-hook 插件进行内网保护

  • 将内容从一个数据库迁移到另一个数据库

  • 使用 Liferay 服务总线进行插件间的通信

  • 集群 Liferay 门户

简介

本章涵盖了各种相互之间没有关联的主题。食谱涵盖了 Liferay 管理员可能会遇到的一些标准场景,并提供了解决方案。这将帮助您为您的内网站点执行这些特定任务。几乎每个人都应该知道如何配置 SMTP 以发送电子邮件和接收通知。下一个重要方面是安全性。管理员和开发者应该知道如何安装 antisamy-hook 插件或如何设置会话时间和会话策略。这对于 Liferay 将用于任何类型的门户来说都极为重要。此外,本章还将介绍有关 Liferay 高级技巧的重要知识。它将描述 Liferay 服务总线,并展示用户如何使用它。此外,它还将详细说明 Liferay 中集群的工作原理以及如何将内容从一个数据库迁移到另一个数据库。

语言属性钩子

Liferay 拥有多语言架构,并允许用户添加具有多种翻译的内容。此外,它还提供了开箱即用的功能来更改语言。除此之外,内容门户还包含许多标签,这些标签也有自己的翻译。这意味着 Liferay 的设计具有一种功能,可以翻译标签或字段。如果我们查看源代码(portal-impl/src/content),会发现许多具有以下名称的文件:Language_en.propertiesLanguage_de.propertiesLanguage_pl.properties 等等。ISO 639-1 标准为每种语言定义了一组可能的代码,例如 en 代表英语,de 代表德语,等等。Liferay 门户支持多达 47 种语言,这些语言在名为 localesportal-impl/src/portal.properties 文件中定义。默认翻译并不总是符合我们的期望。因此,在本食谱中,我们将向您展示如何使用钩子插件更改现有的标签。

如何做到这一点…

钩子插件的一个功能是覆盖现有翻译中的消息。我们的目标是将登录标签更改为内网登录。第一步是生成一个新的钩子,称为language-hook。要实现它,请使用 Liferay 插件 SDK(${SDK_HOME}/hook/create.sh language "Language hook")或 Maven 存档生成器(mvn archetype:generate -Dfilter=liferay-hook)。如果您在生成语言钩子时遇到问题,请返回并研究第一章中的创建自定义端口食谱,安装和基本配置。我们假设用户将此插件作为 Maven 项目生成。接下来,将项目导入您喜欢的 IDE,例如 Eclipse、IntelliJ IDEA 或 NetBeans,并按照以下步骤操作:

  1. 打开src/main/webapp/WEB-INF/liferay-hook.xml文件。

  2. 定义一个新的语言属性文件:

    <language-properties>
      i18n/Language_en.properties
    </language-properties>
    
  3. src/main/resources中创建i18n文件夹,并创建Language_en.properties文件。

  4. Language_en.properties中添加以下行:

    sign-in=Intranet login
    
  5. 编译插件并通过执行mvn clean install liferay:deploy命令来部署它。

它是如何工作的...

正如我们一开始所说的,Liferay 支持许多语言和翻译。每个翻译都保存在具有特定后缀的Language.properties文件中,例如_pl_en_de等。所有可用的区域设置都在以下门户属性中定义:

locales=ar_SA,eu_ES,bg_BG,ca_AD,ca_ES,zh_CN,zh_TW,hr_HR,cs_CZ,da_DK,nl_NL,nl_BE,en_US,en_GB,en_AU,et_EE,fi_FI,fr_FR,fr_CA,gl_ES,de_DE,el_GR,iw_IL,hi_IN,hu_HU,in_ID,it_IT,ja_JP,ko_KR,lo_LA,lt_LT,nb_NO,fa_IR,pl_PL,pt_BR,pt_PT,ro_RO,ru_RU,sr_RS,sr_RS_latin,sl_SI,sk_SK,es_ES,sv_SE,tr_TR,uk_UA,vi_VN

locales.beta=ar_SA,eu_ES,bg_BG,ca_AD,zh_TW,hr_HR,cs_CZ,da_DK,nl_NL,nl_BE,en_GB,en_AU,et_EE,gl_ES,el_GR,hi_IN,in_ID,it_IT,ko_KR,lo_LA,lt_LT,nb_NO,fa_IR,pl_PL,pt_PT,ro_RO,ru_RU,sr_RS,sr_RS_latin,sl_SI,sk_SK,sv_SE,tr_TR,uk_UA,vi_VN

locales.enabled=ca_ES,zh_CN,en_US,fi_FI,fr_FR,de_DE,iw_IL,hu_HU,ja_JP,pt_BR,es_ES

第一个属性指定了 Liferay Portal 中所有可用的区域设置。第二个属性列出处于 beta 测试的语言。一组 beta 属性意味着翻译尚未完成,Liferay 可能包含一些错误或错误。

注意

您可以加入与翻译一起工作的社区,并参与其中。所有必要的信息都可在translate.liferay.com找到。

最后一个属性列出 Liferay 默认支持的语言。如果我们创建一个新项目并满足我们的要求,则需要更改它。这可以在控制面板部分稍后更改。此操作在控制面板部分可用。

在本食谱中,我们向您展示了如何覆盖现有的属性。覆盖对于在portal-impl/src/content/Language.properties中定义的每个属性都有效。此外,在我们的i18n/Language_en.properties中,可以添加一个新属性,该属性可以用于我们的新功能。

在 Liferay 语言属性中,有一个portal-impl/src/content/Language.properties文件(没有语言后缀)。这组属性用于系统找不到特定国家/语言属性时。

还有更多...

除了自定义语言属性外,Liferay 允许您选择国际化如何工作。要了解此功能,您首先应该知道如何更改 Liferay 语言。默认情况下,Liferay 为特定语言提供唯一的 URL。以下是一些示例:

  • http://localhost:8080/pl/web/guest/home

  • http://localhost:8080/en_US/web/guest/home

此上下文(/pl/en_US)由 I18nServlet 处理,该 Servlet 定义在 web.xml 文件中。此 Servlet 更改语言并渲染带有专用翻译的页面。

详细来说,有一个名为 locale.prepend.friendly.url.style 的属性位于 portal-impl/src/portal.properties 中。它有四个可能的值,如下表所示:

描述
0 本地化不会自动添加到 URL 前面。这意味着每个 URL 可能指向多种不同的语言。例如,如果用户在账户设置中设置了德语,门户默认显示英语网站。如果此属性设置为 0,页面 http://localhost:8080/web/guest 将以英语显示。然而,当用户登录时,它会自动翻译成德语。URI 的值相同,为 /web/guest,没有语言上下文。
1 当请求的语言不是默认语言时,本地化会自动添加到 URL 前面。这意味着每个 URL 只指向一种语言。让我们从第一个例子开始分析,其中用户设置了与默认语言不同的语言。第一次访问 http://localhost:8080 门户时,内容以默认语言(英语)显示。在登录操作后,用户被重定向到 http://localhost:8080/de URL。在每一页上,都有 /de/web/guest/{PAGE} URI。在注销后,门户会记住语言并显示德语翻译。
2 本地化会自动添加到每个 URL 前面。这意味着每个 URL 只指向一种语言。
3 当请求的语言不是默认用户语言时,本地化会自动添加到 URL 前面。对于访客用户,行为与值为 1 时相同。然而,在我们的情况下(用户具有与门户不同的本地化设置),存在以下情况:默认情况下,门户以英语显示内容,没有语言上下文。URL 看起来像 http://localhost:8080/。当用户登录时,语言是德语,但 URL 仍然是相同的,http://localhost:8080(没有语言上下文)。在注销操作后,URL 仍然是相同的,但语言仍然是德语。要更改语言,需要调用 http://localhost:8080/en URL。

与语言设置相关的最后一件事是默认语言定义。它位于 portal-impl/src/system.properties 中,可以被 system-ext.properties 覆盖。要设置默认语言,覆盖以下属性:

user.country=PL
user.language=pl

参见

为了了解如何创建插件(尤其是端口),请参考第一章中的创建自定义端口配方,安装和基本配置

设置门户会话时间和会话策略

在每个项目中,尤其是在企业内部网项目中,主要功能是身份验证和授权,以便为已验证用户提供正确的权限并为他们提供专用内容。每个已登录用户都有自己的会话;到期时间可以具体设置。您还可以使用任何其他设置来设置会话,例如自动扩展会话或会话过期时的重定向。所有关于会话的设置都可以在portal.properties中找到。

假设我们的目标是配置以下会话策略:

  • 会话在 10 分钟后过期

  • 在会话过期后,系统将用户重定向到默认页面(如果所有页面都没有为未经认证的用户显示访客权限,系统应显示登录页面)

  • 在会话结束前两分钟,系统应显示一个带有倒计时的警告

  • 会话标识符不应在 URL 中可见

如何做到这一点...

如我们一开始所说,Liferay 通过portal-ext.properties覆盖了会话特定的属性。为了达到我们的目标,打开portal-impl/src/portal-ext.properties并设置以下定义:

session.timeout=10
session.timeout.redirect.on.expire=true
session.timeout.auto.extend=false
session.timeout.warning=2
session.enable.url.with.session.id=false

除了session.timeout设置外,您还必须在web.xml中设置相同的值。为了完成此任务,打开位于{$TOMCAT_HOME}/webapps/ROOT/WEB-INF文件夹中的主web.xml文件。找到一个名为session-config的 XML 标签,并按以下方式更改:

<session-config>
  <session-timeout>10</session-timeout>
</session-config>

最后,保存此文件并重新启动您的应用程序服务器。

它是如何工作的...

我们的首要目标是更改默认会话超时,它原本是 30 分钟。我们将其减少到 10 分钟。重要的是要知道,更改session.timeout属性是不够的,因为web.xml配置会覆盖此设置。为了完成我们的配置,我们还需要将此值更改到web.xml描述符中。

接下来,假设与超时后的用户重定向相关。为了达到我们的目标,我们需要更改两个属性:

  • session.timeout.redirect.on.expire:此设置为true,当会话过期时将用户重定向到默认页面

  • session.timeout.auto.extend:此设置为false以拒绝自动扩展会话

session.timeout.warning属性指定了在警告用户会话过期之前的时间(分钟数)。我们将此值设置为 2 分钟。

最后一个假设与安全要求相关。当然,它默认是禁用的,但我们决定展示如何进行配置。因此,最后一个名为session.enable.url.with.session.id的属性被设置为false

使用 SMTP 服务器配置 Liferay

Liferay 在许多情况下发送电子邮件,例如添加日历事件和论坛帖子,或者当用户创建账户时。为了启用此功能,需要正确配置 SMTP 服务器并设置适当的属性。在本食谱中,我们将解释如何以最简单的方式配置 SMTP 服务器。

如何操作…

正确配置 SMTP 服务器有三种方法。最简单的方法是使用 Liferay 的控制面板,并通过 GUI 界面配置 SMTP 设置。要实现它,请转到 管理 | 控制面板 | 服务器管理,然后选择 邮件 选项卡。之后,在 发件 SMTP 服务器 部分下输入您的邮件会话设置,并点击 保存 按钮。当只有一个 SMTP 服务器实例或 SMTP 是第三方外部服务器时,这种设置是一个很好的选择。在许多情况下,这种设置是不够的。最好的例子是运行在集群环境中的应用程序,其中每个节点(Liferay 实例)都有自己的 SMTP 本地服务器。

在许多情况下,例如在集群环境中,将 SMTP 服务器安装在 Liferay 实例所在的同一节点上是一种非常常见的做法。在这种情况下,无法使用 GUI 界面配置 SMTP 服务器,但可以在 portal-ext.properties 中完成此设置。在这个文件中,我们可以放置以下列出的设置:

mail.session.mail.pop3.host=localhost
mail.session.mail.pop3.password=
mail.session.mail.pop3.port=110
mail.session.mail.pop3.user=
mail.session.mail.smtp.auth=false
mail.session.mail.smtp.host=localhost
mail.session.mail.smtp.password=
mail.session.mail.smtp.port=25
mail.session.mail.smtp.user=
mail.session.mail.store.protocol=pop3
mail.session.mail.transport.protocol=smtp

最后一种可能性是使用应用服务器的邮件会话通过 Java 命名和目录接口JNDI)来查找 Java 邮件会话。为了启用 JNDI 名称,请在 portal-ext.properties 文件中放置以下配置:

mail.session.jndi.name=mail/MailSession

确保在您的 {$TOMCAT_HOME}/conf/Catalina/localhost/ROOT.xml 文件中定义了一个类似于以下标签的资源:

<Resource name="mail/MailSession" auth="Container" type="javax.mail.Session" mail.imap.host="localhost" mail.pop3.host="localhost" mail.smtp.host="localhost" mail.store.protocol="imap" mail.transport.protocol="smtp" />

Liferay 门户推荐使用 SMTP 配置,而不是通过 GUI 或将属性设置为 Java 邮件的统一配置,因为这种配置不依赖于应用服务器。

它是如何工作的…

Liferay 有自己的消息总线实现。这是一个服务级 API,用于在 Liferay 内部交换消息。在这个特定案例中,电子邮件发送机制使用 Liferay 消息总线。与每个消息总线实现一样,有一个发送者,它将消息发送到目的地。这种功能在 com.liferay.mail.service.impl.MailServiceImpl 类的 sendEmail 方法中实现:

public void sendEmail(MailMessage mailMessage) {
  MessageBusUtil.sendMessage(DestinationNames.MAIL, mailMessage);
}

如前所述的方法所示,发送操作具有相当简单的实现,仅调用 com.liferay.portal.kernel.messaging.MessageBusUtil.sendMessage 方法,并传递目的地和邮件消息参数。MailMessageListener 负责将电子邮件正确发送到指定地址。

在相反的一侧,有一个可以识别消息并消费它的监听器。例如,它会发送一封电子邮件。这是com.liferay.mail.messaging.MailMessageListener类,它接收事件(在这种情况下,邮件事件)并调用适当的操作来发送电子邮件。

antisamy-hook插件通过内部网络进行保护

Liferay 6.x 提供了一个名为 sanitizers 的新功能。这是一个保护内容(HTML 和 JavaScript)免受用户可能传递给期刊文章、维基、论坛等恶意代码的实现。如果用户从任何互联网资源复制并粘贴内容,就可能发生这种情况。在 Liferay 核心实现中,没有 sanitizers。其中一个原因是 Liferay 允许用户实现自己的策略并将其作为钩子插件安装。幸运的是,Liferay 在官方 GitHub 仓库中有一个名为antisamy-hook的插件github.com/liferay/liferay-plugins/tree/master/hooks/antisamy-hook

在这个菜谱中,我们将向您展示如何安装此插件,并给您一个关于它是如何工作的想法。

如何做到这一点…

与其他插件一样,antisamy-hook插件可在官方 Liferay 市场上找到。因此,安装过程非常简单且统一。为了实现您的目标,以管理员身份登录,转到Admin | Control Panel | Store,找到Antisamy CE插件,并点击Free按钮购买它。如果您有一个有效的市场账户,此插件是免费的。之后,转到Purchased标签页并点击Install按钮。

在日志文件中,您应该找到以下消息:

INFO  [localhost-startStop-2][HookHotDeployListener:687] Registering hook for antisamy-hook
Loading file:/home/piotr/clients/packt/project/tomcat-7.0.42/temp/6-antisamy-hook/WEB-INF/classes/portal.properties
INFO  [localhost-startStop-2][HookHotDeployListener:814] Hook for antisamy-hook is available for use

它是如何工作的…

antisamy-hook插件添加了一个OWASP AntiSamy实现,这意味着该插件包含了位于org.owasp.validator.html.AntiSamy包中的 OWASP antisamy.jar库。OWASP AntiSamy 项目是一个保护内容免受恶意代码侵害的 API。

注意

更多详细信息可在官方 OWASP 网站上找到www.owasp.org/index.php/Category:OWASP_AntiSamy_Project

从技术角度来看,antisamy-hook插件是一个非常简单但功能强大的工具。它之所以简单,是因为它只是按照以下方式覆盖了sanitizer.impl属性:

sanitizer.impl=com.liferay.antisamy.hook.sanitizer.AntiSamySanitizerImpl 

它非常强大,因为它使用了一个开源的 OWASP Antisamy 项目来过滤我们的内容。

主要实现位于sanitize方法中的AntiSamySanitizerImpl类(实际上,这个插件中只有一个类):

public String sanitize([arguments])
  throws SanitizerException {

  if (Validator.isNull(contentType) ||
    !contentType.equals(ContentTypes.TEXT_HTML)) {
    return s;
  }
  try {
    AntiSamy antiSamy = new AntiSamy();
    CleanResults cleanResults = antiSamy.scan(s, _policy);
    return cleanResults.getCleanHTML();
  }
  catch (Exception e) {
    _log.error("Unable to sanitize input", e);
    throw new SanitizerException(e);
  }
}

此实现会检查contentType是否为 HTML,然后AntiSamy实现会过滤内容并返回干净的结果。OWASP 库负责正确过滤内容。

将内容从一个数据库迁移到另一个数据库

内容迁移工具是 Liferay 提供的一个有趣的功能,作为开箱即用的核心实现。正如您所知,Liferay 允许管理员选择数据库引擎之一,例如 MySQL、PostgreSQL、Oracle 等。它允许用户在不丢失数据的情况下更改数据库引擎。

假设我们的 Liferay 实例使用的是 PostgreSQL 数据库,而我们想将其更改为 MySQL 引擎。

准备中…

为了迁移我们的内容,我们需要创建一个新的 MySQL 数据库。为了实现它,请登录到您的数据库:

mysql -u {USER} -p

然后,使用以下命令创建一个新的数据库:

CREATE DATABASE lportal
DEFAULT CHARACTER SET utf8
DEFAULT COLLATE utf8_general_ci;

如何操作…

此功能是开箱即用的。此外,它不需要开发人员支持。所有迁移过程都可以通过 GUI 完成。要迁移数据,请按照以下步骤操作:

  1. 以管理员身份登录。

  2. 前往管理 | 控制面板 | 服务器管理,并选择数据迁移选项卡。

  3. 按以下方式填写表格:

    • JDBC 驱动类名称中,输入com.mysql.jdbc.Driver

    • JDBC URL中,输入jdbc:mysql://localhost/lportal?useUnicode=true&characterEncoding=UTF-8&useFastDateParsing=false

    • JDBC 用户名中,输入数据库的用户

    • JDBC 密码中,输入数据库用户的密码

    如何操作…

  4. 点击执行按钮。有关操作详细信息的所有信息都将出现在日志文件中。以下消息将逐渐出现在屏幕上:如何操作…

  5. 确保过程成功完成。在catalina.out日志文件中,您将找到以下消息:

    Finished conversion for com.liferay.portal.convert.ConvertDatabase in 18652 ms.
    
  6. 然后,关闭您的应用程序服务器,更改数据库属性以指示新的数据库,并使用新的配置启动应用程序服务器。

它是如何工作的…

数据库迁移过程由 Liferay 支持,以保留与数据库的兼容性。此过程使用 Liferay 消息总线,它公开了数据迁移的监听器。在这种情况下,一个事件准备并调用com.liferay.portlet.admin.action.EditServerAction类。以下列表显示了其实现方式:

protected String convertProcess([Arguments]) throws Exception {
  [..]
  MaintenanceUtil.maintain(portletSession.getId(), className);
  MessageBusUtil.sendMessage(DestinationNames.CONVERT_PROCESS, className);
}

此方法负责准备特定数据,显示维护窗口,并向消息总线发送事件。

监听器由com.liferay.portal.convert.ConvertDatabasedoConvert()方法表示。此方法负责准备所有数据库数据并将其放入新数据库中。此方法中的所有细节都很复杂,但主要思想是取每个表、其数据和索引并将它们迁移到新的数据库模式中。

参见

如果您想迁移存储数据,请参考:

  • 来自第六章,“Liferay 中的文档和媒体”的与 Amazon S3 云集成配方

  • 来自第六章的存储钩子之间的数据迁移食谱,Liferay 中的文档和媒体

使用 Liferay 服务总线进行端口组件之间的通信

消息总线是一种将消息发送到 Liferay 中不同组件的机制。这种方法非常常见,因为它可以防止类加载问题。它非常重要,因为 Liferay 是一个端口组件容器,每个端口组件都没有关于其他组件的信息。因此,Liferay 提供了一个消息总线,允许端口组件之间进行通信。发送事件/消息的应用程序称为生产者,而接收消息的应用程序称为消费者。

消息总线架构支持异步和同步消息。同步消息等待响应,而异步消息发送消息、忘记它或接收回调。同步消息和异步消息之间的主要区别是第一个会阻塞线程并等待响应。

在本食谱中,我们将向您展示如何在真实示例中使用消息总线。假设我们的目标是编写一个具有自动完成功能的单输入搜索端口组件。这将是一个只有一个输入的简单表单,可以自动完成我们的查询。提交表单后,搜索条件应发送到现有的内置搜索端口组件。我们将使用 Liferay 消息总线与 Lucene 索引器进行通信。

由于无法展示和解释所有实现,我们将通过带有消息总线的代码片段进行解释。在下面的如何做…部分,我们将向您展示编译、部署和安装我们的端口组件的步骤。在本食谱的如何工作…部分,我们将解释消息总线实现。

如何做…

为了正确编译、部署和安装端口组件,请按照以下步骤操作:

  1. www.liferay-guru.com/code/ch11/quicksearch-portlet.zip下载quicksearch-portlet

  2. 将端口组件复制到工作区文件夹。

  3. 打开quicksearch-portlet/pom.xml,并在<properties>部分设置适当的路径。

  4. 调用mvn clean install liferay:deploy命令。

  5. 运行您的 Liferay 实例,并检查日志文件中是否有成功部署的消息:

    INFO  [DispatcherPortlet:282] FrameworkPortlet 'quicksearchportlet': initialization completed in 81 ms
    INFO  [DispatcherPortlet:119] Portlet 'quicksearchportlet' configured successfully
    INFO  [localhost-startStop-3][PortletHotDeployListener:490] 1 portlet for quicksearch-portlet is available for use
    
  6. 以管理员身份登录,创建一个名为搜索的页面,并将搜索端口组件放入左侧菜单中名为添加的工具类别下的搜索端口组件。

  7. 创建第二个页面,例如,快速搜索,并添加快速搜索端口组件。

  8. 打开搜索端口组件配置窗口,并将布局设置为搜索端口组件(在我们的例子中,它将是搜索页面)。

  9. 点击保存按钮,并通过X按钮关闭弹出配置窗口。

  10. 尝试在QuickSearch端口中输入一个单词(至少三个字母),并享受自动完成功能。

它是如何工作的...

在这个端口中,Liferay 消息总线用于询问搜索引擎关于自动完成的结果。在我们的例子中,生产者是一个名为com.liferay.guru.portlet.quicksearch.util.QSMessageBusUtil的类。其代码如下:

public class QSMessageBusUtil {

  public static JSONArray sendSynchronousMessage(SearchContext searchContext)
  throws MessageBusException {
    Message message = new Message();
    message.setDestinationName(QSDestinationNames.SEARCH_AUTOCOMPLETE);
    message.setPayload(searchContext);
    message.setResponseDestinationName(DestinationNames.MESSAGE_BUS_DEFAULT_RESPONSE);

    Object response = MessageBusUtil.sendSynchronousMessage(message.getDestinationName(), message,
      SearchConstants.AUTOCOMPLETE_TIMEOUT);

    if (response instanceof JSONArray) {
      return (JSONArray) response;
    } else {
      throw new MessageBusException("Invalid message response");
    }
  }
}

此类只有一个方法,该方法返回一个包含搜索结果的 JSON 数组。前三行负责创建Message对象,该对象将被发送到消息总线。Message对象是com.liferay.portal.kernel.messaging.Message类的一个实例,具有以下字段:

  • String _destinationName:这是我们目标的名字。这是我们发送消息的地方

  • Object _payload:此字段表示一个将被发送到消费者的对象(有效载荷)

  • Object _response:此字段包含一个表示响应消息的对象

  • String _responseDestinationName:消费者(监听器)发送响应的地方。在我们的例子中,这是DestinationNames.MESSAGE_BUS_DEFAULT_RESPONSE,它定义了返回给目标、生产者的响应

  • String _responseId:此值表示响应标识符

  • Map<String, Object> _values:将发送到消费者或生产者的额外对象映射

在我们的实现中,我们将有效载荷设置为SearchContext(我们的 Lucene 查询)并将responseDestinationName设置为默认响应。

要将我们的消息发送到消息总线,我们调用了以下方法:

Object response = MessageBusUtil.sendSynchronousMessage(
  message.getDestinationName(), message,
  SearchConstants.AUTOCOMPLETE_TIMEOUT);

有一个问题:哪个类应该接收我们的消息?答案和所有配置都在applicationContext-messaging.xml文件中,其内容如下:

<util:constant id="destination.name.search.autocomplete"
  static-field="com.liferay.guru.portlet.quicksearch.util.
  QSDestinationNames.SEARCH_AUTOCOMPLETE" />
<bean id="messageListener.autocomplete.lucene" 
  class="com.liferay.guru.search.lucene.AutocompleteListener" />
<bean id="destination.search.autocomplete"
  class="com.liferay.portal.kernel.messaging.
  SynchronousDestination">
  <property name="name" ref="destination.name.
    search.autocomplete" />
</bean>
<!-- Configurator -->
<bean id="messagingConfigurator"
  class="com.liferay.portal.kernel.messaging.config.
  PluginMessagingConfigurator">
  <property name="messageListeners">
    <map key-type="java.lang.String" value-
      type="java.util.List">
      <entry key-ref="destination.name.search.autocomplete">
        <list>
          <ref bean="messageListener.autocomplete.lucene" />
        </list>
      </entry>
    </map>
  </property>
  <property name="destinations">
    <list>
      <ref bean="destination.search.autocomplete" />
    </list>
  </property>
</bean>

上述配置指定了以下豆类:

  • 带有messageListener.autocomplete.lucene ID 的listener豆。

  • 带有destination.search.autocomplete ID 的destination豆。

  • 将监听器映射到其目标位置的configurator豆。在我们的例子中,它将我们的destination.search.autocomplete目标映射到messageListener.autocomplete.lucene豆。换句话说,它将目标与监听器连接起来。

让我们看看我们的监听器实现:

public class AutocompleteListener extends BaseMessageListener {
  @Override
  protected void doReceive(Message message) throws Exception {

    Message response = MessageBusUtil.createResponseMessage( message );

    Object payload = message.getPayload();
    if ( payload instanceof SearchContext ) {
      response.setPayload( getSuggestions( (SearchContext) payload ) );
    }
    else {
      _log.error( "Message payload is invalid: " + Objects.toString( payload ) );
      response.setPayload( JSONFactoryUtil.createJSONArray() );
    }

    MessageBusUtil.sendMessage( response.getDestinationName(), response );
  }
[...]
}

AutocompleteListener扩展了BaseMessageListener并重写了doReceive方法。

此方法的主体负责创建一个新的响应并将其发送回我们的生产者。接收到的对象将被放入有效载荷字段。因此,我们的实现从有效载荷中获取一个对象,检查它是否是SearchContext,寻找新的建议,并将建议作为新的有效载荷设置。

总结这个配方,请记住以下事项:

  • Liferay 消息总线实现了生产者和消费者之间的通信

  • Message对象在生产者和消费者之间发送

  • 生产者创建一个具有以下属性的Message对象:

    • payload:此字段表示将要发送给消费者的对象(有效载荷)

    • responseDestinationName:这是提供给监听器用于回复的名称

    • 可选地,responseIdsetResponseId方法)和其他应作为键/值对发送给消费者的对象

  • 要发送同步消息,应使用MessageBusUtil.sendSynchronousMessage方法

  • 监听器(消费者)必须在 XML 定义中注册

  • 监听器有一个doReceive方法,该方法发送回消息

  • 消费者从消息中提取值并准备响应消息

  • 应使用MessageBusUtil.createResponseMessage来创建响应消息

  • 消费者通过MessageBusUtil.sendMessage方法向生产者发送消息

还有更多...

在本配方中,我们仅讨论了同步通信,这是使用消息总线的基本示例。实际上,在许多情况下使用同步消息并不是一个好主意。为什么?答案很简单:这种类型的通信会阻塞等待接收者的响应。消息通信基本上是为异步通信设计的。存在两种类型的异步消息:

  • 发送并忘记:这意味着推送一个事件然后忘记它。这种类型的通信在通知情况下很有用,例如,如果生产者想通知监听器关于某些操作。

  • 回调:生产者在responseDestinationName中为消息定义了一个回调目的地。监听器可以将消息发送回特定的responseDestinationName。重要的是,生产者可以自由地进行进一步处理。

从技术角度来看,异步实现与我们示例非常相似。主要区别在于它调用MessageBusUtil中的不同方法。要发送异步消息,应使用以下调用,正如你在发送响应时在监听器代码中所看到的:

MessageBusUtil.sendMessage(message.getDestinationName(), message);

重要的是,sendMessage方法不返回任何值,因为它是一个异步消息,我们不知道是否有回调信息。所有应该发送回调的配置都放置在messaging.xml文件中。以下是一个示例:

<entry key="YOUR_RESPONSE_DESTINATION_NAME">
  <list value-type="com.liferay.portal.kernel.messaging.MessageListener">
    <ref bean="messageListener.listener1" />
    <ref bean="messageListener.listener2" />
    <ref bean="messageListener.listenerN" />
  </list>
</entry>

参见

为了了解如何创建插件(尤其是端口组件),请参考第一章中的创建自定义端口组件配方,安装和基本配置

集群 Liferay Portal

Liferay 在社区版CE)和企业版EE)版本中都支持开箱即用的集群功能。它旨在构建可扩展的系统,可以由拥有大量数据的大公司使用,因此它允许我们在并行服务器上运行多个门户实例。为了构建 Liferay 集群,您需要知道哪些组件对集群敏感。集群过程对以下组件有巨大影响:

  • 数据库,Liferay 实例存储数据的地方

  • 将文档和媒体作为硬盘上的文件夹

  • Lucene 搜索引擎文件

  • Liferay 缓存

此配方将逐点说明并展示如何正确地集群 Liferay。

准备工作…

此配方不是关于如何正确运行集群环境(如 Apache 服务器、负载均衡器等)的教程。相反,我们的目标是向您展示如何正确配置 Liferay,使其能够在并行环境中工作。假设您已正确配置所有组件。最后一步是配置 Liferay 以正确地在集群中工作。

如何操作...

正如我们一开始所说的,在运行 Liferay 集群之前,应该检查几个点。

检查数据库配置

第一件事,其实很简单,就是检查数据库配置。应该在所有 Liferay 节点之间共享一个数据库实例。为了检查配置的正确性,打开包含数据库访问配置的属性文件。通常,它是portal-ext.properties。确保在每个节点上配置都是相同的。以下是一个示例:

jdbc.default.driverClassName=com.mysql.jdbc.Driver
jdbc.default.url=jdbc:mysql://localhost/lportal?useUnicode=true&characterEncoding=UTF-8&useFastDateParsing=false
jdbc.default.username=<USERNAME>
jdbc.default.password=<PASSWORD>

文档和媒体集群

在第六章中,我们解释了 Liferay 中的文档和媒体插件的工作原理。了解文件元数据存储在数据库中,但二进制数据(文件)存储在硬盘上也很重要。正如你所猜到的,当 Liferay 作为集群环境运行时,这将会成为一个问题,因为每个节点可以有自己的存储库,文件在节点之间不共享。为了解决这个问题,有三种方法:

  • 通过存储区域网络SAN)、网络附加存储NAS)、GlusterFS 等方式在节点之间共享存储库:询问您的系统管理员在特定机器上哪种选项可用,并正确安装集群文件系统。在许多解决方案中,我们看到了一个 GlusterFS 系统,它在节点之间共享数据文件夹。此解决方案确保每个节点都有相同的文件存储库。确保以下属性指示共享磁盘存储的正确位置:

    dl.store.file.system.root.dir=${liferay.home}/data/document_library
    
  • 使用数据库存储:所有数据,包括二进制文件,都存储在数据库表中。要启用此配置,设置以下属性:

    dl.store.impl=com.liferay.portlet.documentlibrary.store.DBStore
    

    此设置会自动使用数据库而不是文件系统。数据库应支持 BLOB 字段。

  • 使用以下外部存储系统:

    • 亚马逊云:我们在第六章(part0050.xhtml#aid-1FLS41 "第六章。Liferay 中的文档和媒体")与亚马逊 S3 云的集成配方中展示了如何配置此存储,Liferay 中的文档和媒体

    • 内容管理互操作性服务CMIS)存储,例如 Alfresco:在成功安装 Alfresco(或其他 CMIS 存储系统)后,设置以下属性:

      dl.store.impl=com.liferay.portlet.documentlibrary.store.CMISStore
      dl.store.cmis.credentials.username=none
      dl.store.cmis.credentials.password=none
      dl.store.cmis.repository.url=http://localhost:8080/alfresco/service/api/cmis
      dl.store.cmis.system.root.dir=Liferay Home
      
    • 一个 Java 内容仓库JCR)存储,例如 Jackrabbit:这是一个作为 JSR-170 规范实现的 Apache 项目。Liferay 支持它,但由于性能问题和并发冲突,此配置已被弃用。在此解决方案中,Jackrabbit 仓库必须放置在 SAN 共享存储(挂载在每个节点上)。

搜索引擎

我们已经在第八章(part0059.xhtml#aid-1O8H61 "第八章。搜索和内容展示工具")搜索和内容展示工具中提到了搜索引擎主题。我们展示了两个搜索引擎:Apache Lucene 和 Apache Solr。如果您使用 Solr 或 Solr Cloud 作为搜索引擎,一切都将完美运行,因为 Solr 是一个外部应用程序,Liferay 与其建立连接。在集群环境中,这是最佳选择,因为性能和搜索结果的质量。

正如您所知,Lucene 将其数据存储在本地存储文件系统中。在集群环境中,保持每个 Liferay 节点的最新索引是一个问题。我们不能通过 GlusterFS 复制索引文件,因为 Lucene 在写入索引或优化它时有时会锁定数据。为了解决这个冲突,Liferay 提供了一个功能,它提供了所有 Liferay 节点之间的复制机制。要启用此功能,请设置以下属性:

cluster.link.enabled=true
lucene.replicate.write=true

这些属性需要为 Liferay 的所有节点设置。cluster.link.enabled 属性打开整个缓存复制机制,我们将在下一节中描述。

缓存复制

Liferay 使用 EhCache 缓存一些内容,例如 SQL 查询的结果。在集群环境中,缓存分布是一个非常重要的问题。每个节点都应该了解数据库上的更改和缓存失效。Phil Karlton 曾经引用:

"在计算机科学中,只有两件难事:缓存失效和命名事物。"

我完全同意他的观点。

多播

节点间的缓存分布与多播完美配合。请确保您的服务器支持多播。接下来,设置以下属性以启用复制:

cluster.link.enabled=true

此属性打开集群模式。

以下属性定义了五个节点间消息分发的通道:

    multicast.group.address["cluster-link-control"]=239.255.0.1
    multicast.group.port["cluster-link-control"]=23301

    multicast.group.address["cluster-link-udp"]=239.255.0.2
    multicast.group.port["cluster-link-udp"]=23302

    multicast.group.address["cluster-link-mping"]=239.255.0.3
    multicast.group.port["cluster-link-mping"]=23303

    multicast.group.address["hibernate"]=239.255.0.4
    multicast.group.port["hibernate"]=23304

    multicast.group.address["multi-vm"]=239.255.0.5
    multicast.group.port["multi-vm"]=23305

为前面的属性(设置)设置适当的 IP 地址和端口号。在许多环境中,它将自动运行。

单播

在某些服务器上,可能无法通过多播发送消息。幸运的是,可以强制 Liferay 使用单播协议而不是多播。配置并不非常困难,但很难发现。为了减少在 Google 上花费的时间,请遵循以下配方部分并正确设置此类通信。

首先,通过将cluster.link.enabled属性设置为true值来打开集群模式。

接下来,您必须使用JGroups库通过 TCP 建立通信。为了实现这一点,设置以下属性:

ehcache.bootstrap.cache.loader.factory=com.liferay.portal.cache.ehcache.JGroupsBootstrapCacheLoaderFactory
ehcache.cache.event.listener.factory=net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory
ehcache.cache.manager.peer.provider.factory=net.sf.ehcache.distribution.jgroups.JGroupsCacheManagerPeerProviderFactory

ehcache.multi.vm.config.location.peerProviderProperties=file=unicast-ehcache.xml
net.sf.ehcache.configurationResourceName.peerProviderProperties=file=unicast-ehcache.xml

cluster.link.channel.properties.control=unicast-ehcache.xml
cluster.link.channel.properties.transport.0=unicast-ehcache.xml

分析上一节中突出显示的部分。所有通道都引用了unicast-ehcache.xml文件。因此,在类路径上创建unicast-ehcache.xml文件(${TOMCAT_HOME}webapps/ROOT/WEB-INF/classes)。它也可以在ext插件中的ext-impl/src/main/resources/unicast-ehcache.xml创建。文件内容如下:

<config 

  xsi:schemaLocation="urn:org:jgroups http://www.jgroups.org/schema/JGroups-2.8.xsd"
> 
      <TCP singleton_name="liferay" 
           bind_port="7800" 
           loopback="true" 
           recv_buf_size="${tcp.recv_buf_size:20M}" 
           send_buf_size="${tcp.send_buf_size:640K}" 
           discard_incompatible_packets="true" 
           max_bundle_size="64K"
           max_bundle_timeout="30" 
           enable_bundling="true" 
           use_send_queues="true" 
           sock_conn_timeout="300" 
           timer.num_threads="4" 
           thread_pool.enabled="true" 
           thread_pool.min_threads="1" 
           thread_pool.max_threads="10" 
           thread_pool.keep_alive_time="5000" 
           thread_pool.queue_enabled="false" 
           thread_pool.queue_max_size="100" 
           thread_pool.rejection_policy="discard" 
           oob_thread_pool.enabled="true" 
           oob_thread_pool.min_threads="1" 
           oob_thread_pool.max_threads="8" 
           oob_thread_pool.keep_alive_time="5000" 
           oob_thread_pool.queue_enabled="false" 
           oob_thread_pool.queue_max_size="100" 
           oob_thread_pool.rejection_policy="discard"/> 

    <TCPPING timeout="3000" 
             initial_hosts="${jgroups.tcpping.initial_hosts:localhost[7800],localhost[7801]}" 
             port_range="1" 
             num_initial_members="3"/> 

    <MERGE2 min_interval="10000" max_interval="30000"/> 
    <FD_SOCK/> 
    <FD timeout="3000" max_tries="3" /> 
    <VERIFY_SUSPECT timeout="1500" /> 
    <BARRIER /> 
    <pbcast.NAKACK use_mcast_xmit="false" gc_lag="0" retransmit_timeout="300,600,1200,2400,4800" discard_delivered_msgs="true"/> 
    <UNICAST timeout="300,600,1200" /> 
    <pbcast.STABLE stability_delay="1000" desired_avg_gossip="50000" max_bytes="400K"/> 
    <pbcast.GMS print_local_addr="true" join_timeout="3000" view_bundling="true"/> 
    <FC max_credits="2M" min_threshold="0.10"/> 
    <FRAG2 frag_size="60K" /> 
    <pbcast.STREAMING_STATE_TRANSFER/> 
    <!-- <pbcast.STATE_TRANSFER/> --> 
</config>

最后一件要启用通信的事情是告诉JGroups关于可用节点(Liferay 实例)的信息。假设有两个 Liferay 节点,以下 IP 地址:

  • node1带有 192.168.0.10 地址

  • node2带有 192.168.0.11 地址

为了配置它,请在您的应用服务器中设置以下JAVA_OPTS变量(例如,在${TOMCAT_HOME}/bin/setenv.sh):

node1:

JAVA_OPTS="${JAVA_OPTS} -Djgroups.bind_addr=192.168.0.10" JAVA_OPTS="${JAVA_OPTS} -Djgroups.tcpping.initial_hosts=192.168.0.10[7800],192.168.0.11[7800] "

node2:

JAVA_OPTS="${JAVA_OPTS} -Djgroups.bind_addr=192.168.0.11" JAVA_OPTS="${JAVA_OPTS} -Djgroups.tcpping.initial_hosts=192.168.0.10[7800],192.168.0.11[7800] "

它是如何工作的…

在这个配方中,我们讨论了从数据库配置到 Ehcache 复制的几个主题。所有这些步骤都是正确在集群环境中运行 Liferay 所必需的。Liferay 是一个具有许多依赖项的庞大系统,因此在多个服务器实例中安装它相当困难。我们相信我们的建议将帮助您配置和运行 Liferay CMS。我们的目的是介绍可能的配置方式。每个公司都有自己的安装 Liferay 的想法和解决方案。根据我们的经验,以下是一些最佳配置:

  • 使用带有mod_jk模块和负载均衡器作为反向代理的 Apache

  • Squid 作为缓存代理

  • GlusterFS 作为共享文件系统,其中文档和媒体组件端口保留其数据

  • Solr 服务器和 Zookeeper 作为搜索引擎云

  • 带有主/从配置的 MySQL 数据库

  • 通过多播(或单播)的 EhCache 复制

    注意

    如果需要更详细的信息,请访问 Liferay 官方文档dev.liferay.com/discover/deployment/-/knowledge_base/6-2/liferay-clustering

参见

为了了解更多关于可伸缩基础设施的信息,请参考以下配方:

  • 来自第十二章的可伸缩基础设施配方,基本性能调整

  • 与亚马逊 S3 云的集成以及来自第六章,Liferay 中的文档和媒体中的存储钩子之间的数据迁移食谱

第十二章. 基本性能调优

在本章中,我们将涵盖以下主题:

  • 可扩展基础设施

  • 设置主/从配置的数据库访问

  • 启用 JS 和 CSS 压缩

  • 启用 CDN 主机

  • 禁用未使用的 Liferay 功能

  • JVM 调优

简介

成功项目实现最重要的方面之一是系统性能。众所周知,当下载网页时,Web 用户经常会遇到长时间的等待。网页下载的容忍等待时间是多长?在我们看来,舒适的响应时间应该少于 2 秒。如果用户不得不等待超过 4 秒,他们通常会离开。性能问题是大数据门户或内部网中最难的主题。系统架构影响性能。拥有大量图像、电影和音频的门户网站与内部网相比应该有不同的架构,因为这些门户网站有大量用户同时登录。

幸运的是,有一些通用规则可以帮助提高 Liferay 的性能:

  • 具有 HTTP 缓存代理的可扩展基础设施

  • 快速数据库

  • 适当的 Java 设置,例如垃圾收集器引擎或内存设置

  • 包含的最小文件数量,如 JS、CSS、图像等

  • 内容分发 网络 (CDN) 用于静态资源

  • Liferay 门户调优,例如禁用未使用的过滤器、更改属性等

可扩展基础设施

定义架构是成功安装最重要的部分。一个好的架构应该是容错性的,并且具有高可用性。为了实现这一点,有必要将所有可能的节点,如 Tomcat 节点、搜索节点等,进行集群。第二重要的是构建一个可扩展的基础设施,使我们能够添加新的节点。

如何做到这一点…

在这个菜谱中,我们将尝试定义参考基础设施,这可以在生产部署中使用。这种类型的基础设施在我们的项目中使用,并且运行得非常好。我们环境的主要部分包括:squid 缓存、带有mod_jk模块的 Apache 服务器和软件负载均衡器、Apache Tomcat 应用服务器、Solr 云和数据库服务器。以下图像显示了最重要的部分:

如何做到这一点…

Squid 缓存

我们架构的第一层是 Squid 缓存(www.squid-cache.org/)。它是一个 Web 缓存代理。它支持 HTTP、HTTPS 和其他协议。它减少了发送到另一层的请求数量,尤其是发送到 Liferay 实例的请求数量。Squid 缓存读取 HTTP 头信息,并决定是否可以将特定请求缓存以及可以缓存多长时间。此选项可用于不经常更改的内容,如图像、CSS、JS 等。这种解决方案对我们的应用程序提供了明显的提升。

Apache Web 服务器和软件负载均衡器

下一层是带有负载均衡器软件的 Apache 网络服务器实例。每个 Apache 服务器实例都与所有 Liferay 节点连接。这种连接是通过mod_jk Tomcat-Apache插件(tomcat.apache.org/tomcat-3.3-doc/mod_jk-howto.html)建立的。此插件通过 AJP 协议处理 Tomcat 和 Apache 之间的通信。每个 Apache 服务器实例都有一个负载均衡器配置。最常见的负载均衡器配置使用mod_jk插件。配置放在$APACHE_HOME/conf目录下的workers.properties文件中。以下列表显示了mod_jk和负载均衡器配置的示例:

worker.list=node1,node2,loadbalancer
worker.template.port=8009
worker.template.type=ajp13
worker.template.ping_mode=A
worker.template.reply_timeout=60000
worker.template.socket_connect_timeout=10000

worker.node1.reference=worker.template
worker.node1.host=<IP_ADDRESS>

worker.node2.reference=worker.template
worker.node2.host=<IP_ADDRESS>

worker.loadbalancer.type=lb
worker.loadbalancer.balance_workers=node1, node2
worker.loadbalancer.sticky_session=True
worker.loadbalancer.retries=1

第一行指定了一个工作者列表。在我们的例子中,有三个工作者:node1node2loadbalancer。名为node1node2的工作者描述了与 Liferay 的连接(主机、端口和超时定义)。

粗体定义描述了负载均衡器配置。它包含一个工作者列表(worker.loadbalancer.balance_workers属性),并指定了请求失败时的粘性会话策略和重试次数。负载均衡器可以通过以下两种模式进行配置:

  • 粘性会话:这会将特定会话的所有请求分配给特定的 Liferay Portal 服务器节点。

  • 会话复制:这提供了一种会话复制的机制。从业务角度来看,这是一个非常棒的功能,因为它不受故障影响。如果一个节点失败,负载均衡器会决定将请求发送到另一个节点。用户不会看到任何区别。

从性能调优的角度来看,最佳选项是粘性会话,因为它与会话复制相比消除了许多请求。换句话说,粘性会话减少了流量并节省了资源。

Apache Tomcat 应用服务器

这一层是应用程序的核心,因为在这一层,放置了带有我们的 Liferay Portal 实例的 Tomcat 容器。在集群环境中,正确配置 Liferay Portal 很重要,因为所有组件都必须有专门的配置,例如共享文档和媒体文件、配置对数据库的相同访问权限,以及配置缓存和搜索索引复制。

如果我们使用 Apache 的mod_jk模块,在每一个 Apache Tomcat 实例中设置jvmRoute标识符是很重要的。为此,将以下配置放在${TOMCAT_HOME}/conf/server.xml中:

<Engine name="Catalina" defaultHost="localhost" jvmRoute="node{X}">

要共享文档和媒体文件,我们建议您使用 glusterFS 系统(www.gluster.org/),该系统在节点之间共享文档和文件。在集群环境中,配置文档和媒体文件有不同方式,我们已在上一章中描述。我们将在接下来的食谱中描述其他配置。

数据库服务器

数据库服务器层负责在数据库系统中存储数据。在一个大型系统中,数据库通常是主要的瓶颈之一,数据库管理员经常在性能上遇到很多问题。在我们的项目中,我们通常使用具有主/从配置的 MySQL 数据库。主数据库负责写入,而从数据库负责读取。Liferay 提供了开箱即用的机制,允许我们进行配置。我们将在接下来的菜谱中描述它们。

Solr 搜索引擎服务器

最后一层是一个 Apache Solr 搜索引擎服务器(lucene.apache.org/solr/)。Solr 具有高度可靠性、可扩展性和容错性,提供分布式索引、复制和负载均衡查询、自动故障转移和恢复、集中式配置等功能。如果我们一起安装 Apache Zookeeper (zookeeper.apache.org/) 和 Apache Solr,这些功能都是可以配置的。Zookeeper 是一个集中式服务,负责维护配置信息、命名并提供分布式同步和群组服务,例如 Apache Solr。因此,Apache Zookeeper 可以作为一个云解决方案安装,以消除单点故障。Zookeeper 服务器选择一个 Solr 节点,即主节点,并分配一个令牌。

参见

关于集群和配置环境的更多信息,请参考以下菜谱:

  • 来自第六章(part0050.xhtml#aid-1FLS41 "第六章. Liferay 中的文档和媒体")的 与 Amazon S3 云集成 菜单,Liferay 中的文档和媒体

  • 来自第八章(part0059.xhtml#aid-1O8H61 "第八章. 搜索和内容展示工具")的 Solr 安装和配置 菜单,搜索和内容展示工具

  • 来自第十一章(part0080.xhtml#aid-2C9D01 "第十一章. 快速技巧和高级知识")的 集群 Liferay 门户和配置 Liferay 与 SMTP 服务器 菜单

  • 本章的 设置主/从配置的数据库访问 菜单

设置主/从配置的数据库访问

Liferay 允许我们配置两个不同的数据源:一个用于写入,另一个用于读取。这种配置以简单的方式允许用户分离写入和读取请求。这种类型的配置使我们能够构建可扩展和高性能的基础设施。

准备工作…

正如我们一开始提到的,我们专注于 Liferay 配置方面。我们的假设是您已经准备好使用具有主/从复制的数据库服务器。MySQL 官方文档在 dev.mysql.com/doc/refman/5.1/en/replication-configuration.html 中描述了如何配置复制。

如何操作…

为了实现我们的目标,打开 portal-ext.properties 并配置以下设置:

jdbc.write.driverClassName=com.mysql.jdbc.Driver
jdbc.write.url=jdbc:mysql://<DB_WRITE_ADDRESS>/lportal?useUnicode=true&characterEncoding=UTF-8&useFastDateParsing=false
jdbc.write.username=<USERNAME>
jdbc.write.password=<PASSWORD>

jdbc.read.driverClassName=com.mysql.jdbc.Driver
jdbc.read.url=jdbc:mysql://<DB_READ_ADDRESS>/lportal?useUnicode=true&characterEncoding=UTF-8&useFastDateParsing=false
jdbc.read.username=<USERNAME>
jdbc.read.password=<PASSWORD>

下一步是启用 Spring 配置,其中包含读取/写入数据源的设置。将以下属性添加到 portal-ext.properties 文件中:

spring.configs=\
META-INF/base-spring.xml,\
META-INF/hibernate-spring.xml,\
META-INF/infrastructure-spring.xml,\
META-INF/management-spring.xml,\
META-INF/util-spring.xml,\
META-INF/editor-spring.xml,\
META-INF/jcr-spring.xml,\
META-INF/messaging-spring.xml,\
META-INF/scheduler-spring.xml,\
META-INF/search-spring.xml,\
META-INF/counter-spring.xml,\
META-INF/document-library-spring.xml,\
META-INF/lock-spring.xml,\
META-INF/mail-spring.xml,\
META-INF/portal-spring.xml,\
META-INF/portlet-container-spring.xml,\
META-INF/wsrp-spring.xml,\
META-INF/mirage-spring.xml,\
META-INF/dynamic-data-source-spring.xml,\
#META-INF/shard-data-source-spring.xml,\
META-INF/ext-spring.xml

最后,重新启动您的应用程序服务器。确保数据库复制工作正常。

它是如何工作的...

在我们的配置中,所有写入事务都将针对 jdbc.write.* 数据源,而读取事务将使用 jdbc.read.* 数据源。为了验证此配置,请按照以下步骤操作:

  1. 关闭主数据库实例 (jdbc.write)。

  2. 运行您的 Liferay 实例。

  3. 尝试浏览 Liferay Portal 并上传新内容,例如文章或文件。

  4. catalina.out 日志文件中,应该有适当的错误消息。

从技术角度来看,Liferay 扩展了 org.springframework.aop.TargetSource Spring 类,该类可以识别方法是否包含读取或写入操作。规则非常简单:如果服务层上的方法有 @Transactional 注解,则所有查询都转到写入数据源。在其他情况下,查询转到读取数据源。

还有更多...

一些项目使用 Liferay 与许多 Portal 实例。在这种情况下,术语“Portal 实例”意味着 Liferay 允许管理员在单个服务器上运行多个 Portal 实例。每个 Portal 实例的数据可以与其他每个 Portal 实例分开保存。这种分离可以在数据库层组织。每个数据库节点可以存储不同类型的数据,具体取决于 Portal 实例。这种分离称为数据库分片。

Portal 实例配置允许我们选择数据将存储在哪个分片。数据库分片是数据库中数据的水平分区。每个分片都存储在单独的数据库服务器实例上,以分散负载。要在 Liferay 中配置分片,请遵循以下说明:

  1. portal-ext.properties 文件中,指定一个算法,用于在创建 Portal 实例时选择新的分片。使用 ManualShardSelector 通过 Web 界面进行分片选择,或在其他情况下使用轮询。轮询算法在分片之间均匀分配数据。手动选择器让我们可以将每个 Liferay 实例分配到特定的分片:

    shard.selector=com.liferay.portal.dao.shard.RoundRobinShardSelector
    #shard.selector=com.liferay.portal.dao.shard.ManualShardSelector
    
  2. 接下来,设置您的分片数据源:

    jdbc.default.driverClassName=com.mysql.jdbc.Driver
    jdbc.default.url=jdbc:mysql://<SERVER1>/lportal?useUnicode=true&characterEncoding=UTF-8&useFastDateParsing=false
    jdbc.default.username=<USERNAME>
    jdbc.default.password=<PASSWORD>
    
    jdbc.shard1.driverClassName=com.mysql.jdbc.Driver
    jdbc.shard1.url=jdbc:mysql://<SERVER2>/lportal1?useUnicode=true&characterEncoding=UTF-8&useFastDateParsing=false
    jdbc.shard1.username=<USERNAME>
    jdbc.shard1.password=<PASSWORD>
    
    jdbc.shard2.driverClassName=com.mysql.jdbc.Driver
    jdbc.shard2.url=jdbc:mysql://<SERVER3>/lportal2?useUnicode=true&characterEncoding=UTF-8&useFastDateParsing=false
    jdbc.shard2.username=<USERNAME>
    jdbc.shard2.password=<PASSWORD>
    
    shard.available.names=default,shard1,shard2
    
  3. 最后一个是 spring.configs 配置,其外观应如下所示:

    spring.configs=<DEFAULT_CONFIGURATION>,\
      META-INF/shard-data-source-spring.xml
    

    <DEFAULT_CONFIGURATION> 占位符保留所有原始的 spring.configs 配置,这些配置在 portal.porperties 文件中定义。

启用 JS 和 CSS 压缩

当您的网页在浏览器中加载时,浏览器会向 Web 服务器发送一个 HTTP 请求以获取 URL 中的页面。然后,随着 HTML 的传递,浏览器解析它并查找对图像、脚本、CSS 等的附加请求。每次它看到对新元素的新请求时,都会向服务器发送另一个 HTTP 请求。为了减少附加请求的数量,Liferay 有以下现成的机制:

  • 允许您压缩和精简 JavaScript 和 CSS 文件的 Minifier(压缩器)

  • 使用 barebone.jspeverything.jsp 合并 JavaScript 文件以减少 HTTP 请求

  • 合并 CSS 文件和图像以加快加载

  • 启用 Gzip 压缩

如何操作...

要设置 Liferay 的快速加载机制,请在 portal-ext.properties 文件中设置以下属性:

minifier.enabled=true
javascript.fast.load=true
theme.css.fast.load=true
theme.images.fast.load=true
layout.template.cache.enabled=true

此外,如果您使用自定义脚本,请将它们添加到 portal-ext.properties 文件中的 javascript.barebone.filesjavascript.everything.files 属性。最后一步是启用 Gzip 压缩。可以通过开启以下属性来实现:

com.liferay.portal.servlet.filters.gzip.GZipFilter=true

一个更好的选择是将此责任委托给 Apache 服务器,因为它减少了 Apache Tomcat 服务器中的请求数量。要在 Apache 服务器上启用 Gzip 压缩,打开 ${APACHE_HOME}/conf/httpd.conf 并添加以下配置:

SetOutputFilter DEFLATE
SetEnvIfNoCase Request_URI \.(?:exe|t?gz|zip|bz2|sit|rar)$ no-gzip dont-vary
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ no-gzip dont-vary

确保已启用 deflate 模块。查找以下行:

LoadModule deflate_module modules/mod_deflate.so

它是如何工作的...

在这个菜谱中,我们专注于减少请求数量和减小响应大小。Liferay 将 JS 文件合并成一个文件,并存储在应用服务器的 temp 目录中。对于未认证用户,该文件在页面上的链接如下所示:

<script src="img/barebone.jsp?browserId=other&amp;themeId=classic&amp;colorSchemeId=01&amp;minifierType=js&amp;minifierBundleId=javascript.barebone.files&amp;languageId=en_US&amp;b=6201&amp;t=1414241572000" type="text/javascript"></script>

对于认证用户,非常相似。而不是 barebone.jsp,有 everything.jsp 文件。

如果我们深入查看生成的 HTML 源代码,会发现带有 minifierType=css 参数的 CSS 文件链接。此参数启用文件精简,从而减小文件大小。

最后一个神奇的配置是 Gzip 压缩。如果我们的浏览器发送带有 Accept-Encoding: gzip,deflate 头部的请求,我们的系统将返回 Gzipped 内容。要测试它,从您的命令行调用以下命令:

curl -I -H "Accept-Encoding: gzip,deflate" http://localhost:8080

在响应中,应该有 Content-Encoding: gzip 头部。

打开 CDN 主机

在之前的菜谱中,您学习了如何连接到压缩 CSS 和 JS 文件并减少对 Liferay 门户的请求数量。我们配置的下一步是减少 Liferay 所在的应用服务器的请求数量。想法是某些静态资源可以由 Apache 服务器或更好的 Squid 缓存提供。通过 Apache 服务器或 Squid 缓存而不是应用服务器提供静态资源可以提高响应时间。

Liferay 支持 CDN。维基百科将此术语定义为如下:

"内容分发网络(CDN)或内容分发网络(CDN)是在互联网上多个数据中心部署的大型分布式服务器系统。CDN 的目标是以高可用性和高性能向最终用户提供内容。"

准备工作…

我们的构想是使用 CDN 域名来提供静态资源并将它们缓存在 Squid 缓存中。最难的部分是 Squid 配置,它缓存来自 CDN 主机的所有静态文件。在这个菜谱中,我们将假设这个配置已经完成,并且我们有一个用于资源的静态域名,例如,static.mysite.com

如何操作...

在 Liferay 中,CDN 配置非常简单。只有两个属性需要在portal-ext.properties中设置。这些属性如下:

cdn.host.http=http://static.mysite.com
cdn.host.https=https://static.mysite.com

它是如何工作的...

CDN 配置成功后,所有静态资源都从外部域名提供。当我们查看 HTML 源代码时,我们会看到所有静态资源,如 CSS 文件、JavaScript 文件和图像,都来自在cdn.host.http属性中定义的不同域名。

在这个菜谱中,我们构建了我们的小型 CDN,其中我们的 Squid 缓存提供静态资源。

在庞大的系统中,当目标用户遍布全球时,使用真实的 CDN 主机是必要的,这些主机是部署在世界各地的服务器的大型网络。有几家公司提供此类服务,例如 Amazon、CloudFlare、Bootstrap CDN、CacheFly、OVH 等等。

禁用未使用的 Liferay 功能

每个人都知道 Liferay 是一个具有许多功能的庞大系统。这个门户的主要思想是:我们为您提供所有功能,您可以根据自己的需求进行适配。这个主题可以分为三个部分:禁用未使用的 servlet 过滤器、禁用未使用的自动登录钩子和禁用未使用的功能。

如何操作...

禁用未使用的过滤器可以提高性能,但您必须知道哪些过滤器可以禁用。这对初学者来说是一个难题。不幸的是,我们无法给您一个涵盖您需求的黄金法则。我们只能尝试提供一些关于可以在portal-ext.properties文件中关闭的过滤器的建议和信息:

  • 如果您不使用 CAS 身份验证,请禁用com.liferay.portal.servlet.filters.sso.cas.CASFilter=false过滤器

  • 如果您在 Apache 服务器上使用 Gzip 压缩,请禁用com.liferay.portal.servlet.filters.gzip.GZipFilter=false过滤器

  • 如果您不使用 NTLM 身份验证,请禁用以下过滤器:com.liferay.portal.servlet.filters.sso.ntlm.NtlmFilter=falsecom.liferay.portal.servlet.filters.sso.ntlm.NtlmPostFilter=false

  • 如果您不使用 OpenSSO 身份验证,请禁用com.liferay.portal.servlet.filters.sso.opensso.OpenSSOFilter=false过滤器

  • 如果您不使用 SharePoint,请禁用com.liferay.portal.sharepoint.SharepointFilter=false过滤器

  • 如果你使用 Tomcat 服务器从输出内容中删除空白行和空格,请禁用com.liferay.portal.servlet.filters.strip.StripFilter=false过滤器

下一个配置是连接到身份验证系统。Liferay 支持许多单点登录系统,默认情况下已启用。从以下属性中删除未使用的AutoLogin钩子:

auto.login.hooks=com.liferay.portal.security.auth.CASAutoLogin,\
com.liferay.portal.security.auth.FacebookAutoLogin,\
com.liferay.portal.security.auth.NtlmAutoLogin,\
com.liferay.portal.security.auth.OpenIdAutoLogin,\
com.liferay.portal.security.auth.OpenSSOAutoLogin,\
com.liferay.portal.security.auth.RememberMeAutoLogin,\
com.liferay.portal.security.auth.SiteMinderAutoLogin

小贴士

如果你禁用了auto.login.hooks定义,请确保在具有com.liferay.portal.servlet.filters.sso前缀的属性下也禁用了每个自动登录定义。例如,如果你禁用了com.liferay.portal.security.auth.NtlmAutoLogin,请检查com.liferay.portal.servlet.filters.sso.ntlm.NtlmFilter是否设置为false

最后一个配置禁用了一些影响性能的功能:

  • 如果你没有使用用户会话跟踪器或此功能不是必需的,请禁用:session.tracker.memory.enabled=false属性

  • 如果你没有使用文档库文件的阅读计数,请禁用dl.file.entry.read.count.enabled=false属性

  • 如果你没有使用文档库文件的文件排名,请禁用dl.file.rank.enabled=false属性

  • 如果你没有使用资产视图计数器,请禁用asset.entry.increment.view.counter.enabled=false属性

  • 如果你没有使用 pingback 和 trackback,请禁用它们:

    blogs.pingback.enabled=false
    blogs.trackback.enabled=false
    message.boards.pingback.enabled=false
    

它是如何工作的…

Liferay 提供了一个名为portal.properties的文件,该文件可以被portal-ext.properties配置文件覆盖。portal.properties文件位于portal-impl/src/文件夹中。这是自定义 Liferay 门户和禁用不必要的选项的主要工具。每个管理员和开发人员都应该研究这个文件,并尝试使门户符合项目的需求。这是一项艰巨的工作,因为配置文件有超过 10,000 行。好消息是每个属性都有注释。

JVM 调优

JVM 调优是一项应该在性能测试之后或在生产期间进行的操作。JVM 配置会影响 Java 应用程序的性能。有两个必要的配置:

  • 内存设置(如堆配置)

  • 垃圾收集器设置

关于 JVM 调优有很多出版物。因此,在这个菜谱中,我们只将提及主要方面。

如何操作…

每个 JVM 设置都可以在JAVA_OPTS(Java 环境选项)中设置。一个很好的地方是在${TOMCAT_HOME}/bin/setenv.sh文件中设置。

首先,让我们设置一个合适的垃圾收集器。对于门户系统来说,最佳选项是并发收集器G1(在 Java 8 中)。这些垃圾收集器大部分工作都是并发执行的,只有很短的停顿时间。这些垃圾收集器提供了最佳的性能。典型的设置如下:

JAVA_OPTS = "$JAVA_OPTS -XX:+UseParNewGC -XX:+UseConcMarkSweepGC 
-XX+CMSParallelRemarkEnabled -XX:ParallelGCThreads=8 
-XX:+CMSScavengeBeforeRemark
-XX:+CMSConcurrentMTEnabled -XX:ParallelCMSThreads=2"

以下设置与内存分配相关。正确配置的估计非常困难。我们的经验表明,当每个节点有 8 GB RAM 或更多时,性能最佳。我们的设置如下所示:

JAVA_OPTS = "$JAVA_OPTS -server -d64 -XX:NewSize=1024m 
-XX:MaxNewSize=1024m -Xms6144m -Xmx6144m -XX:PermSize=512m 
-XX:MaxPermSize=512m -XX:SurvivorRatio=10"

小贴士

每个项目都有不同的内存特性。给定的 JVM 设置形成初始配置,应由您的 Java 工程团队进行验证。

它是如何工作的…

我们提到,对于门户解决方案来说,最好的垃圾回收器是并发收集器或 G1。让我们分析一下我们的JAVA_OPTS变量中的每个设置:

  • +UseParNewGC: 这将开启并行年轻代收集器。

  • +UseConcMarkSweepGC: 这将开启旧代的并发标记清除收集。

  • +CMSParallelRemarkEnabled: 这使垃圾回收器能够在 CMS remark 阶段使用多个线程。这减少了这一阶段的暂停时间。

  • ParallelGCThreads: 垃圾回收器并行阶段使用的线程数。它不应超过服务器上的核心(处理器)数量。

  • +CMSScavengeBeforeRemark: 这将强制在 CMS remark 之前进行年轻空间收集。

  • +CMSConcurrentMTEnabled: 这允许 CMS 在并发阶段使用多个核心。

  • ParallelCMSThreads: 这控制用于 CMS(并发标记清除)垃圾回收器的线程数。

posted @ 2025-10-09 13:23  绝不原创的飞龙  阅读(3)  评论(0)    收藏  举报