如何限制 CQ5/自定义组件每页仅添加一次。?当作者第二次将相同的组件添加到同一页面中时,我想限制组件的拖放到页面中。
6 回答
一种选择是将组件直接包含在模板的 JSP 中,并将其从 Sidekick 中的可用组件列表中排除。为此,请将组件直接添加到您的 JSP(本示例中为基础轮播):
<cq:include path="carousel" resourceType="foundation/components/carousel" />
要从 Sidekick 隐藏组件,请设置:
componentGroup: .hidden
或使用设计模式将其从“允许的组件”列表中排除。
如果您需要允许用户在没有此组件的情况下创建页面,您可以提供第二个模板并cq:include
省略。
感谢猖獗,我已按照您的方法和链接说明。 再次发布链接:请关注此博客 这真的很有帮助。无论我做了什么,我都会发布实现。它对我来说很好。绝对可以提高代码质量,这是原始代码,仅供参考。
1.Servlet过滤器
请记住,如果任何资源被引用,此过滤器将执行。因此,您需要在最后过滤内容以进行进一步处理。PS chain.doFilter(request,response); 是必须的。否则 cq 将被挂起并且不会显示任何内容。
@SlingFilter(generateComponent = false, generateService = true, order = -700,
scope = SlingFilterScope.REQUEST)
@Component(immediate = true, metatype = false)
public class ComponentRestrictorFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {}
@Reference
private ResourceResolverFactory resolverFactory;
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
WCMMode mode = WCMMode.fromRequest(request);
if (mode == WCMMode.EDIT) {
SlingHttpServletRequest slingRequest = (SlingHttpServletRequest) request;
PageManager pageManager = slingRequest.getResource().getResourceResolver().adaptTo(PageManager.class);
Page currentPage = pageManager.getContainingPage(slingRequest.getResource());
logger.error("***mode" + mode);
if (currentPage != null )) {
ComponentRestrictor restrictor = new ComponentRestrictor(currentPage.getPath(), RESTRICTED_COMPONENT);
restrictor.removeDuplicateEntry(resolverFactory,pageManager);
}
chain.doFilter(request, response);
}
}
public void destroy() {}
}
2.ComponentRestrictor类
public class ComponentRestrictor {
private String targetPage;
private String component;
private Pattern pattern;
private Set<Resource> duplicateResource = new HashSet<Resource>();
private Logger logger = LoggerFactory.getLogger(ComponentRestrictor.class);
private Resource resource = null;
private ResourceResolver resourceResolver = null;
private ComponentRestrictorHelper helper = new ComponentRestrictorHelper();
public ComponentRestrictor(String targetPage_, String component_){
targetPage = targetPage_ + "/jcr:content";
component = component_;
}
public void removeDuplicateEntry(ResourceResolverFactory resolverFactory, PageManager pageManager) {
pattern = Pattern.compile("([\"']|^)(" + component + ")(\\S|$)");
findReference(resolverFactory, pageManager);
}
private void findReference(ResourceResolverFactory resolverFactory, PageManager pageManager) {
try {
resourceResolver = resolverFactory.getAdministrativeResourceResolver(null);
resource = resourceResolver.getResource(this.targetPage);
if (resource == null)
return;
search(resource);
helper.removeDuplicateResource(pageManager,duplicateResource);
} catch (LoginException e) {
logger.error("Exception while getting the ResourceResolver " + e.getMessage());
}
resourceResolver.close();
}
private void search(Resource parentResource) {
searchReferencesInContent(parentResource);
for (Iterator<Resource> iter = parentResource.listChildren(); iter.hasNext();) {
Resource child = iter.next();
search(child);
}
}
private void searchReferencesInContent(Resource resource) {
ValueMap map = ResourceUtil.getValueMap(resource);
for (String key : map.keySet()) {
if (!helper.checkKey(key)) {
continue;
}
String[] values = map.get(key, new String[0]);
for (String value : values) {
if (pattern.matcher(value).find()) {
logger.error("resource**" + resource.getPath());
duplicateResource.add(resource);
}
}
}
}
}
3.删除节点/资源无论你想删除/删除哪个资源,只需使用PageManager api
pageManeger.delete(resource,false);
而已 !!!你已准备好出发。
没有一个选项看起来很容易实现。我发现最好的方法是使用 ACS Commons Implementation,它非常简单,可以用于任何项目。
这是链接以及如何配置它: https ://github.com/Adobe-Consulting-Services/acs-aem-commons/pull/639
享受编码!
听起来需要澄清需求(并理解为什么)。
如果可以培训作者,让他们通过创作和审查工作流程来管理组件的限制。
如果组件只能出现 1 个固定位置,则页面组件应包含内容组件,并让组件具有“启用”切换属性以确定它是否应该呈现任何内容。组件的组应该是 .hidden 以防止从 Sidekick 拖动。
如果组件有一组固定的位置,则页面组件可以具有位置列表的下拉列表(包括“无”)。然后页面呈现组件将有条件地将组件包含在正确的位置。再次,防止从 Sidekick 拖动组件。
在“难以想象”的情况下,组件可以出现在页面上的任何位置,由作者添加,但仅限于 1 个实例 - 使用包装器组件来管理包括(不可拖动的)组件。让作者在页面上拖动包装器任意多次,但包装器应该查询页面的资源并确定它是否是第一个实例,如果是,则包含结束组件。否则,包装器什么也不做。
根据我们的经验(在 CQ 上超过 2 年),通过代码实现这种类型的业务规则会创建一个脆弱的解决方案。此外,需求有变化的习惯。如果通过代码强制执行,则需要进行开发工作,而不是让作者更快、更优雅地进行更改。
这些选项都不是那么好。如果你真的想要一个强大的解决方案来解决这个问题(限制页面上的项目数量而不使用硬编码位置),那么最好的方法是使用 servlet 过滤器链 OSGI 服务,您可以在其中管理实例数量,然后使用资源解析器删除有问题的实例。
基本要点是:
- 刷新页面编辑使用
cq:editConfig
- 创建一个
javax.servlet.Filter
封装您的业务规则的 OSGI 服务实现。 - 使用过滤器根据业务规则去除多余的组件
- 继续页面处理。
有关更多详细信息,请参见此处: 使用 servlet 过滤器来限制每页或 parsys 组件的实例数
这种方法可以让您管理每页或每页的项目数量,parsys
并以其他提供的解决方案根本无法实现的方式应用其他可能复杂的业务规则。
如果不对 ui 代码进行一些大规模的修改,你就无法阻止这种情况,即使那样,你也只能从 ui 的一个方面阻止它。还有crxde,然后是发布内容的能力。
如果这确实是一项要求,那么最好的方法可能如下:
- 让组件检查 pageContext 对象中的特殊值(使用 REQUEST_SCOPE)
- 如果未找到值,则渲染组件并设置值
- 否则,打印出组件只能使用一次的消息
请注意,您不能阻止显示对话框,但至少作者表明该特定组件只能使用一次。