Liferay 7.1自定义搜索结果与facets 过滤无layoutId内容方案咨询
你当前在JSP Fragment中实现过滤的方式确实不符合Liferay开发规范,属于展示层后置过滤,会导致搜索分页计数错误、Facets统计不准等问题。你提到的通过Action Command Hook修改对应Java Action类的思路虽然可实现需求,但属于侵入性修改,后续版本升级兼容性风险极高,也不是最优解。
推荐实现方案
Liferay提供了原生的搜索扩展点,可以无侵入实现你的过滤需求,按优先度推荐以下两种方案:
方案1:索引字段增强+查询过滤器(性能最优,推荐)
该方案在索引阶段就把Web内容关联的布局信息存入搜索索引,查询时直接通过过滤条件筛选,性能损耗最小,不会影响分页和统计功能的准确性。
操作步骤:
- 实现
IndexerPostProcessor接口,重写postProcessDocument方法,在Web内容(JournalArticle)索引生成时,将关联的layoutId列表写入索引文档,核心代码如下:
@Component( immediate = true, property = "indexer.class.name=com.liferay.journal.model.JournalArticle", service = IndexerPostProcessor.class ) public class JournalArticleLayoutIndexerPostProcessor implements IndexerPostProcessor { @Reference private JournalContentSearchLocalService journalContentSearchLocalService; @Override public void postProcessDocument(Document document, Object object) throws Exception { JournalArticle article = (JournalArticle) object; // 仅处理最新版本的文章 if (article.isLatestVersion()) { long[] layoutIds = journalContentSearchLocalService.getLayoutIds( article.getGroupId(), false, article.getArticleId() ); // 把关联布局ID列表作为关键字段存入索引 document.addKeyword("webcontent_related_layout_ids", layoutIds); // 额外存入是否存在关联布局的标识字段,方便后续过滤 document.addKeyword("webcontent_has_related_layout", layoutIds != null && layoutIds.length > 0); } } // 其余接口方法默认实现即可 @Override public void postProcessSearchQuery(BooleanQuery searchQuery, BooleanFilter booleanFilter, Indexer<?> indexer, SearchContext searchContext) throws Exception {} @Override public void postProcessSummary(Summary summary, Document document, Locale locale, String snippet) throws Exception {} }
- 实现
IndexerQueryContributor接口,在搜索查询执行前添加过滤条件,仅返回存在关联布局的Web内容:
@Component( immediate = true, service = IndexerQueryContributor.class ) public class JournalArticleLayoutQueryContributor implements IndexerQueryContributor { @Override public void contribute(BooleanQuery booleanQuery, Indexer<?> indexer, SearchContext searchContext) throws Exception { // 仅对Web内容的搜索请求添加过滤条件 if (JournalArticle.class.getName().equals(indexer.getClassName())) { booleanQuery.addRequiredTerm("webcontent_has_related_layout", true); } } }
- 部署模块后,重新索引所有Web内容即可生效。
方案2:搜索结果后置处理器(轻量实现,无需重建索引)
如果你不想改动索引结构,可选择在搜索查询执行完成后、结果返回前端前做过滤,适合小流量场景使用,注意需要同步修正结果总计数避免分页异常。
核心实现为实现SearchResultsProcessor接口:
@Component( immediate = true, service = SearchResultsProcessor.class ) public class JournalArticleLayoutResultProcessor implements SearchResultsProcessor { @Reference private JournalContentSearchLocalService journalContentSearchLocalService; @Override public void process(SearchContext searchContext, SearchResults searchResults) throws SearchException { List<Document> filteredDocuments = new ArrayList<>(); for (Document document : searchResults.getDocuments()) { // 判断是否为Web内容类型的结果 String entryClassName = document.get(Field.ENTRY_CLASS_NAME); if (!JournalArticle.class.getName().equals(entryClassName)) { filteredDocuments.add(document); continue; } // 校验是否有关联布局 long groupId = GetterUtil.getLong(document.get(Field.GROUP_ID)); String articleId = document.get("articleId"); long[] layoutIds = journalContentSearchLocalService.getLayoutIds(groupId, false, articleId); if (layoutIds != null && layoutIds.length > 0) { filteredDocuments.add(document); } } // 更新过滤后的结果和总计数 searchResults.setDocuments(filteredDocuments); searchResults.setTotalHits(filteredDocuments.size()); } }
参考截图

内容的提问来源于stack exchange,提问作者Rafael Bravo
相关产品推荐
相关产品推荐

