在 ModelListener 中更新 Web 内容的类别
Update categories of a web content in ModelListener
我正在根据用户使用的结构链接一个类别。示例:我的结构是 "A" 那么使用此结构创建的任何内容都应具有 "A".
类别
我在 JournalArticle
模型上创建了一个扩展 BaseModelListener
的侦听器。我覆盖 onBeforeUpdate()
看起来像:
@Override
public void onBeforeUpdate(JournalArticle aModel) throws ModelListenerException {
try {
long[] assetCategoryIds = refactorCategories(anArticle); // this reads the structure key and updates the list of category to the correct one.
String[] assetTagNames = getTags(anArticle);
long[] assetEntryLinkIds = getEntryLinkIds(anArticle);
JournalArticleLocalServiceUtil.updateAsset(anArticle.getUserId(), anArticle, assetCategoryIds, assetTagNames, assetEntryLinkIds);
} catch (PortalException |SystemException ex) {
throw new ModelListenerException("Cannot update the categories for articleId" + anArticle.getArticleId(), ex);
}
}
我使用一组业务规则更正了 categoryIds
。
以下是两种可能的情况:
没有分配类别:
- 在这种情况下,上面的
onBeforeUpdate()
很有用,并且分配了正确的类别。
如果用户在调用之前分配了一个类别(可能是错误的):
- 在这种情况下,
onBeforeUpdate()
实施被调用并且我能够看到更新的资产(使用调试验证),但是当完成整个过程时,网络内容没有反映正确的类别。
我的理解:
当调用 updateAsset
时,它采用更改后的类别。但是,当 Hibernate 保存内容时,它会保存用户选择的类别。这对我来说似乎有点奇怪。
所以我想看看是否有任何可能的解决方案或API我可以使用。
此外,我尝试了 onAfterCreate()
、onAfterUpdate()
、onBeforeCreate()
,但运气不好。
我相信我可以挂钩 JournalArticleService
但我希望尽可能使用侦听器来做到这一点。
根据 Tobias 建议更新了代码:
@Override
public void onBeforeUpdate(JournalArticle aModel) throws ModelListenerException {
ServiceContext serviceContext = ServiceContextThreadLocal.getServiceContext();
try {
long[] assetCategoryIds = refactorCategories(anArticle); // this reads the structure key and updates the list of category to the correct one.
if (serviceContext != null) {
serviceContext.setAssetCategoryIds(assetCategoryIds);
}
} catch (PortalException |SystemException ex) {
throw new ModelListenerException("Cannot update the categories for articleId" + anArticle.getArticleId(), ex);
}
}
参见 JournalArticleLocalServiceImpl.addArticle()
updateArticle()
:
journalArticlePersistence.update(article);
...
updateAsset(userId, article, serviceContext.getAssetCategoryIds(),
serviceContext.getAssetTagNames(),
serviceContext.getAssetLinkEntryIds());
第一行 journalArticlePersistence.update(article)
将调用您的侦听器,而 updateAsset
将保存用户提供的类别。在调用您的听众之后。
您可以获取当前服务上下文并从您的侦听器内部更改它:
ServiceContext serviceContext = ServiceContextThreadLocal.getServiceContext();
if (serviceContext != null) {
serviceContext.setAssetCategoryIds(assetCategoryIds);
}
我建议创建一个钩子插件并使用服务包装器来扩展 JournalArticleLocalService
。我找到了一个更适合任务的服务挂钩。根据 Liferay 认证计划,通过服务挂钩执行此操作也是首选方式。
总的来说:
- 我使用模型侦听器在文章属性被持久化之前更新它(例如自定义 url 标题)。
- 我使用服务挂钩更新相关资产条目(例如类别和标签)。
示例扩展服务:
public class MyJournalArticleLocalService extends JournalArticleLocalServiceWrapper {
@Override
public JournalArticle addArticle(..., ServiceContext serviceContext) throws PortalException, SystemException {
// set the right category in the service context, as the service context
// that the original service will work with can be modified here
serviceContext.setAssetCategoryIds(refactorCategories(...));
// delegate to the original implementation
return super.addArticle(..., serviceContext);
}
@Override
public JournalArticle updateArticle(..., , ServiceContext serviceContext) throws PortalException, SystemException {
// set the right category in the service context, as the service context
// that the original service will work with can be modified here
serviceContext.setAssetCategoryIds(refactorCategories(...));
// delegate to the original implementation
return super.updateArticle(..., serviceContext);
}
}
使用服务挂钩,您可以在 之前 或 之后 更新类别 Liferay 完成文章持久化并创建/更新相关资产条目。
您可以在liferay-hook.xml
描述符中注册服务挂钩:
<?xml version="1.0"?>
<!DOCTYPE hook PUBLIC "-//Liferay//DTD Hook 6.2.0//EN" "http://www.liferay.com/dtd/liferay-hook_6_2_0.dtd">
<hook>
<service>
<service-type>com.liferay.portlet.journal.service.JournalArticleLocalService</service-type>
<service-impl>com.test.MyJournalArticleLocalService</service-impl>
</service>
</hook>
我正在根据用户使用的结构链接一个类别。示例:我的结构是 "A" 那么使用此结构创建的任何内容都应具有 "A".
类别我在 JournalArticle
模型上创建了一个扩展 BaseModelListener
的侦听器。我覆盖 onBeforeUpdate()
看起来像:
@Override
public void onBeforeUpdate(JournalArticle aModel) throws ModelListenerException {
try {
long[] assetCategoryIds = refactorCategories(anArticle); // this reads the structure key and updates the list of category to the correct one.
String[] assetTagNames = getTags(anArticle);
long[] assetEntryLinkIds = getEntryLinkIds(anArticle);
JournalArticleLocalServiceUtil.updateAsset(anArticle.getUserId(), anArticle, assetCategoryIds, assetTagNames, assetEntryLinkIds);
} catch (PortalException |SystemException ex) {
throw new ModelListenerException("Cannot update the categories for articleId" + anArticle.getArticleId(), ex);
}
}
我使用一组业务规则更正了 categoryIds
。
以下是两种可能的情况:
没有分配类别:
- 在这种情况下,上面的
onBeforeUpdate()
很有用,并且分配了正确的类别。
- 在这种情况下,上面的
如果用户在调用之前分配了一个类别(可能是错误的):
- 在这种情况下,
onBeforeUpdate()
实施被调用并且我能够看到更新的资产(使用调试验证),但是当完成整个过程时,网络内容没有反映正确的类别。
- 在这种情况下,
我的理解:
当调用 updateAsset
时,它采用更改后的类别。但是,当 Hibernate 保存内容时,它会保存用户选择的类别。这对我来说似乎有点奇怪。
所以我想看看是否有任何可能的解决方案或API我可以使用。
此外,我尝试了 onAfterCreate()
、onAfterUpdate()
、onBeforeCreate()
,但运气不好。
我相信我可以挂钩 JournalArticleService
但我希望尽可能使用侦听器来做到这一点。
根据 Tobias 建议更新了代码:
@Override
public void onBeforeUpdate(JournalArticle aModel) throws ModelListenerException {
ServiceContext serviceContext = ServiceContextThreadLocal.getServiceContext();
try {
long[] assetCategoryIds = refactorCategories(anArticle); // this reads the structure key and updates the list of category to the correct one.
if (serviceContext != null) {
serviceContext.setAssetCategoryIds(assetCategoryIds);
}
} catch (PortalException |SystemException ex) {
throw new ModelListenerException("Cannot update the categories for articleId" + anArticle.getArticleId(), ex);
}
}
参见 JournalArticleLocalServiceImpl.addArticle()
updateArticle()
:
journalArticlePersistence.update(article);
...
updateAsset(userId, article, serviceContext.getAssetCategoryIds(),
serviceContext.getAssetTagNames(),
serviceContext.getAssetLinkEntryIds());
第一行 journalArticlePersistence.update(article)
将调用您的侦听器,而 updateAsset
将保存用户提供的类别。在调用您的听众之后。
您可以获取当前服务上下文并从您的侦听器内部更改它:
ServiceContext serviceContext = ServiceContextThreadLocal.getServiceContext();
if (serviceContext != null) {
serviceContext.setAssetCategoryIds(assetCategoryIds);
}
我建议创建一个钩子插件并使用服务包装器来扩展 JournalArticleLocalService
。我找到了一个更适合任务的服务挂钩。根据 Liferay 认证计划,通过服务挂钩执行此操作也是首选方式。
总的来说:
- 我使用模型侦听器在文章属性被持久化之前更新它(例如自定义 url 标题)。
- 我使用服务挂钩更新相关资产条目(例如类别和标签)。
示例扩展服务:
public class MyJournalArticleLocalService extends JournalArticleLocalServiceWrapper {
@Override
public JournalArticle addArticle(..., ServiceContext serviceContext) throws PortalException, SystemException {
// set the right category in the service context, as the service context
// that the original service will work with can be modified here
serviceContext.setAssetCategoryIds(refactorCategories(...));
// delegate to the original implementation
return super.addArticle(..., serviceContext);
}
@Override
public JournalArticle updateArticle(..., , ServiceContext serviceContext) throws PortalException, SystemException {
// set the right category in the service context, as the service context
// that the original service will work with can be modified here
serviceContext.setAssetCategoryIds(refactorCategories(...));
// delegate to the original implementation
return super.updateArticle(..., serviceContext);
}
}
使用服务挂钩,您可以在 之前 或 之后 更新类别 Liferay 完成文章持久化并创建/更新相关资产条目。
您可以在liferay-hook.xml
描述符中注册服务挂钩:
<?xml version="1.0"?>
<!DOCTYPE hook PUBLIC "-//Liferay//DTD Hook 6.2.0//EN" "http://www.liferay.com/dtd/liferay-hook_6_2_0.dtd">
<hook>
<service>
<service-type>com.liferay.portlet.journal.service.JournalArticleLocalService</service-type>
<service-impl>com.test.MyJournalArticleLocalService</service-impl>
</service>
</hook>