升级到Liferay 7.3后,覆盖user_action.jsp失败



我们在Liferay 7.0.6中实现了一个corejsphook模块来自定义user_action.jsp,效果很好。

升级到Liferay 7.3.6后,它停止工作。我已经通过在gogo shell中搜索来确保我们要将jsp替换为的模块是正确的。我还查看了源代码,以确认包含.jsp的包是正确的。我将版本号更新为Liferay 7.3捆绑包版本(5.0.53(。我的bnd.bnd中的条目是:片段主机:com.liferay.users.admin.web;捆绑版本=";5.0.53〃;

当我部署模块时,它没有像它应该的那样重新启动片段主机捆绑包(在Liferay 7.0中也是如此(。手动重新启动捆绑包也不起作用——没有使用修改后的.jsp。

顺便说一句,我们还有其他运行良好的corejsphook。这是唯一一个不起作用的,所以我一定错过了什么。

更新:我正在根据要求包含代码。以下是模块中的四个文件(不包括创建模块时创建的build.gradle和Language_en.properties等默认文件(。

bnd.bnd

Bundle-Version: 7.3.6.1
Fragment-Host: com.liferay.users.admin.web;bundle-version="5.0.53"
-sources: true
-jsp: *.jsp,*.jspf

user_action.jsp

<%--
/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
--%>
<%@ include file="/init.jsp" %>

<%@ page import="com.liferay.petra.encryptor.Encryptor" %>
<%@ page import="com.liferay.portal.kernel.util.HtmlUtil" %>
<%
UserSearch searchContainer = (UserSearch)request.getAttribute("liferay-ui:search:searchContainer");
String redirect = searchContainer.getIteratorURL().toString();
ResultRow row = (ResultRow)request.getAttribute(WebKeys.SEARCH_CONTAINER_RESULT_ROW);
User user2 = (User)row.getObject();
long userId = user2.getUserId();
String userLandingPage = null;
User currentUser = user2;
List<Organization> userOrganizations = currentUser.getOrganizations();

if (Validator.isNotNull(userOrganizations) && !userOrganizations.isEmpty())
{
// If user is member of more than one organization then it will take
// first organization from list
Organization organization = userOrganizations.get(0);
if (Validator.isNotNull(organization))
{
Group organizationGroup = organization.getGroup();
if (organizationGroup.getPrivateLayoutsPageCount() > 0)
{

String privateGroupURL = PropsUtil.get(PropsKeys.LAYOUT_FRIENDLY_URL_PRIVATE_GROUP_SERVLET_MAPPING);
String groupFriendlyURL = organizationGroup.getFriendlyURL();
userLandingPage = privateGroupURL + groupFriendlyURL;
String encDoAsUserId = Encryptor.encrypt(
company.getKeyObj(), String.valueOf(userId));

userLandingPage = userLandingPage + "?doAsUserId=" + HtmlUtil.escapeURL(encDoAsUserId);
System.out.println("userLandingPage is: " + userLandingPage);
} 
else
{
System.out.println(organizationGroup.getName() + " organization site doesn't have any private page. So default landing page will be used");
}
}
}
// System.out.println("Landing page is: " + userLandingPage);

%>
<liferay-ui:icon-menu
direction="left-side"
icon="<%= StringPool.BLANK %>"
markupView="lexicon"
message="<%= StringPool.BLANK %>"
showWhenSingleIcon="<%= true %>"
>
<%
boolean hasUpdatePermission = UserPermissionUtil.contains(permissionChecker, userId, ActionKeys.UPDATE);
%>
<c:if test="<%= hasUpdatePermission %>">
<portlet:renderURL var="editUserURL">
<portlet:param name="mvcRenderCommandName" value="/users_admin/edit_user" />
<portlet:param name="redirect" value="<%= redirect %>" />
<portlet:param name="p_u_i_d" value="<%= String.valueOf(userId) %>" />
</portlet:renderURL>
<liferay-ui:icon
message="edit"
url="<%= editUserURL %>"
/>
</c:if>
<c:if test="<%= UserPermissionUtil.contains(permissionChecker, userId, ActionKeys.PERMISSIONS) %>">
<liferay-security:permissionsURL
modelResource="<%= User.class.getName() %>"
modelResourceDescription="<%= user2.getFullName() %>"
resourcePrimKey="<%= String.valueOf(userId) %>"
var="permissionsUserURL"
windowState="<%= LiferayWindowState.POP_UP.toString() %>"
/>
<liferay-ui:icon
message="permissions"
method="get"
url="<%= permissionsUserURL %>"
useDialog="<%= true %>"
/>
</c:if>
<c:if test="<%= (PropsValues.LAYOUT_USER_PRIVATE_LAYOUTS_ENABLED || PropsValues.LAYOUT_USER_PUBLIC_LAYOUTS_ENABLED) && hasUpdatePermission %>">
<%
PortletURL managePagesURL = PortletProviderUtil.getPortletURL(request, user2.getGroup(), Layout.class.getName(), PortletProvider.Action.EDIT);
managePagesURL.setParameter("redirect", redirect);
%>
<liferay-ui:icon
message="manage-pages"
url="<%= managePagesURL.toString() %>"
/>
</c:if>
<c:if test="<%= !PropsValues.PORTAL_JAAS_ENABLE && PropsValues.PORTAL_IMPERSONATION_ENABLE && (userId != user.getUserId()) && !themeDisplay.isImpersonated() && UserPermissionUtil.contains(permissionChecker, userId, ActionKeys.IMPERSONATE) %>">
<liferay-security:doAsURL
doAsUserId="<%= userId %>"
var="impersonateUserURL"
/>
<liferay-ui:icon
message="impersonate-user"
target="_blank"
url="<%= Validator.isNotNull(userLandingPage) ? userLandingPage : impersonateUserURL %>"
/>
</c:if>
<c:if test="<%= UserPermissionUtil.contains(permissionChecker, userId, ActionKeys.DELETE) %>">
<c:if test="<%= !user2.isActive() %>">
<portlet:actionURL name="/users_admin/edit_user" var="restoreUserURL">
<portlet:param name="<%= Constants.CMD %>" value="<%= Constants.RESTORE %>" />
<portlet:param name="redirect" value="<%= redirect %>" />
<portlet:param name="deleteUserIds" value="<%= String.valueOf(userId) %>" />
</portlet:actionURL>
<liferay-ui:icon
message="activate"
url="<%= restoreUserURL %>"
/>
</c:if>
<portlet:actionURL name="/users_admin/edit_user" var="deleteUserURL">
<portlet:param name="<%= Constants.CMD %>" value="<%= user2.isActive() ? Constants.DEACTIVATE : Constants.DELETE %>" />
<portlet:param name="redirect" value="<%= redirect %>" />
<portlet:param name="deleteUserIds" value="<%= String.valueOf(userId) %>" />
</portlet:actionURL>
<c:if test="<%= userId != user.getUserId() %>">
<c:choose>
<c:when test="<%= user2.isActive() %>">
<liferay-ui:icon-deactivate
url="<%= deleteUserURL %>"
/>
</c:when>
<c:when test="<%= !user2.isActive() && PropsValues.USERS_DELETE %>">
<liferay-ui:icon-delete
url="<%= deleteUserURL %>"
/>
</c:when>
</c:choose>
</c:if>
</c:if>
</liferay-ui:icon-menu>

corejsphook.UserActionCustomJspBag.java

/**
* Copyright 2000-present Liferay, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package corejsphook;
import com.liferay.portal.deploy.hot.CustomJspBag;
import com.liferay.portal.kernel.url.URLContainer;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
/**
* @author Scott McIntosh, ICF
*/
@Component(
immediate = true,
property = {
"context.id=UserActionCustomJspBag",
"context.name=User Action Custom JSP Bag",
"service.ranking:Integer=111"
}
)
public class UserActionCustomJspBag implements CustomJspBag 
{
@Override
public String getCustomJspDir() {
return "META-INF/resources/";
}
@Override
public List<String> getCustomJsps() {
System.out.println("In getCustomJsps().  _customJsps is null?");
System.out.println(_customJsps == null);
return _customJsps;
}
@Override
public URLContainer getURLContainer() {
System.out.println("In getURLContainer()");
return _urlContainer;
}
@Override
public boolean isCustomJspGlobal() {
System.out.println("In isCustomJspGlobal()");
return true;
}
@Activate
protected void activate(BundleContext bundleContext) {
System.out.println("In activate()");
bundle = bundleContext.getBundle();
_customJsps = new ArrayList<>();
Enumeration<URL> entries = bundle.findEntries(
getCustomJspDir(), "*.jsp", true);
while (entries.hasMoreElements()) {
URL url = entries.nextElement();
System.out.println("Processing jsp: " + url);
_customJsps.add(url.getPath());
}
}
private List<String> _customJsps;
private final URLContainer _urlContainer = new URLContainer() {
@Override
public Set<String> getResources(String path) {
System.out.println("In getResources()");
Set<String> paths = new HashSet<>();
for (String entry : _customJsps) {
if (entry.startsWith(path)) {
paths.add(entry);
}
}
return paths;
}
@Override
public URL getResource(String name) {
System.out.println("In getResource()");
return bundle.getEntry(name);
}
};
private Bundle bundle;
}

gov.nysdot.rideshare.NYRideshareEnUsResourceBundle.java

ackage gov.nysdot.rideshare;
import com.liferay.portal.kernel.language.UTF8Control;
import java.util.Enumeration;
import java.util.ResourceBundle;
import org.osgi.service.component.annotations.Component;
@Component(
property = { "language.id=en_US" }, 
service = ResourceBundle.class
)
public class NYRideshareEnUsResourceBundle extends ResourceBundle {
@Override
protected Object handleGetObject(String key) {
return _resourceBundle.getObject(key);
}
@Override
public Enumeration<String> getKeys() {
return _resourceBundle.getKeys();
}
private final ResourceBundle _resourceBundle = ResourceBundle.getBundle(
"content.Language_en_US", UTF8Control.INSTANCE);
}

更新:我从零开始,但我得到了同样的结果。我使用创建了一个新模块

$ blade create -t fragment gov.nysdot.user-action-hook --host-bundle-symbolic-name com.liferay.users.admin.web --host-bundle-version 5.0.53

然后,我从源文件(/modules/apps/users-admin/users-admin-web/src/main/resources/META-INF/resources/user_action.jsp(中复制了user_actionjsp

为了测试,我只是在第156行复制了分隔线( )这样我就有了视觉线索。如果覆盖有效,我会看到两条分隔线。

我用"等级构建"构建并部署到我的服务器上。它没有重新启动com.liferay.users.admin.web捆绑包,也没有任何更改。

现在,模块创建脚本所创建的内容实际上没有任何变化。

您的代码/描述中让我印象深刻的是:

  • jsp是模块的jsp,而不是核心jsp。因此,我不会期望CustomJspBag,而是遵循module_jsp_override示例
  • 片段捆绑包永远不会是活动的,只会被解析(就像OSGi捆绑包的生命周期一样(。因此,它可以传递覆盖主机捆绑包文件的文件,但不能传递自己的代码。你提供的是单独的服务,当然不会提供和启动——它们应该存在于其他捆绑包中。将碎片束视为被动的

因此,如果不将您的文件变成一个项目来尝试,我认为这就是眼前的问题。

将bundle转换为模块jsp覆盖项目(没有java代码,请注意bnd.bnd(。确保JSP仍然是它所需要的:您不能仅仅将7.0 JSP复制到7.3,并假设这些更改仍然准确地实现了您所需要的。相反,您需要在stock 7.0版本、您的修改和stock 7.3 jsp之间进行3向迁移。

最新更新