java - 用于包装请求正文的 Sling Filter

标签 java servlets aem sling

用例: 我们正在开发一个 AEM 封闭用户组网站,用户需要在其中提交触发工作流程的表单。由于用户已经过身份验证,因此工作流负载的一部分需要包含发起表单的用户。

我正在考虑为此使用 AEM Forms,它将保存到 /content/user generated/content/forms/af/my-site 下的节点,但有效负载中未提及用户(仅服务使用者)。在本例中,有两个服务用户:运行工作流的工作流服务和处理表单处理和初始保存的 fd-service。例如。从工作流程步骤调用的以下代码报告“fd-service”

workItem.getWorkflowData().getMetaDataMap().get("userId", String.class);

要解决此限制,

Workflow initiated from publish AEM instance: All workflow instances are created using a service user when adaptive forms, interactive communications, or letters are submitted from AEM publish instance. In these cases, the user name of the logged-in user is not captured in the workflow instance data.

我添加了一个过滤器 servlet,以在 AEM Forms servlet 之前使用请求包装器来拦截初始表单提交,以修改添加原始 userID 的请求正文。

就表单、工作流程和启动器而言..这基本上是我的设置 https://helpx.adobe.com/aem-forms/6/aem-workflows-submit-process-form.html

我已查看以下资源:

这是我的包装器的代码

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.wrappers.SlingHttpServletRequestWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.ServletInputStream;
import java.io.*;

public class FormSubmitRequestWrapper extends SlingHttpServletRequestWrapper {
String requestPayload;
private static final Logger log = LoggerFactory.getLogger(FormSubmitRequestWrapper.class);

public FormSubmitRequestWrapper(SlingHttpServletRequest slingRequest) {
    super(slingRequest);

    // read the original payload into the requestPayload variable
    StringBuilder stringBuilder = new StringBuilder();
    BufferedReader bufferedReader = null;
    try {
        // read the payload into the StringBuilder
        InputStream inputStream = slingRequest.getInputStream();
        if (inputStream != null) {
            bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            char[] charBuffer = new char[128];
            int bytesRead = -1;
            while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
                stringBuilder.append(charBuffer, 0, bytesRead);
            }
        } else {
            // make an empty string since there is no payload
            stringBuilder.append("");
        }
    } catch (IOException ex) {
        log.error("Error reading the request payload", ex);
    } finally {
        if (bufferedReader != null) {
            try {
                bufferedReader.close();
            } catch (IOException iox) {
                log.error("Error closing bufferedReader", iox);
            }
        }
    }
    requestPayload = stringBuilder.toString();
}

/**
 * Override of the getInputStream() method which returns an InputStream that reads from the
 * stored requestPayload string instead of from the request's actual InputStream.
 */
@Override
public ServletInputStream getInputStream ()
        throws IOException {

    final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(requestPayload.getBytes());
    ServletInputStream inputStream = new ServletInputStream() {
        public int read ()
                throws IOException {
            return byteArrayInputStream.read();
        }
    };
    return inputStream;
}
}

这是我的过滤器

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.engine.EngineConstants;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import javax.jcr.Session;
import javax.servlet.*;
import java.io.IOException;


@Component(service = Filter.class,
        immediate = true,

        property = {
                Constants.SERVICE_DESCRIPTION + "=Add the CUG userID to any UGC posts",
                EngineConstants.SLING_FILTER_SCOPE + "=" + EngineConstants.FILTER_SCOPE_REQUEST,
                Constants.SERVICE_RANKING + ":Integer=3000",
                EngineConstants.SLING_FILTER_PATTERN + "=/content/forms/af/my-site.*"
        })


public class DecorateUserGeneratedFilter implements Filter {

    private static final Logger log = LoggerFactory.getLogger(DecorateUserGeneratedFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        final SlingHttpServletResponse slingResponse = (SlingHttpServletResponse ) response;
        final SlingHttpServletRequest slingRequest= (SlingHttpServletRequest) request;

        FormSubmitRequestWrapper wrappedRequest = new FormSubmitRequestWrapper(slingRequest);

        log.info("starting ConfirmAlumniStatus workflow");
        log.info(getCurrentUserId(slingRequest));

        chain.doFilter(wrappedRequest, slingResponse);
    }

    @Override
    public void destroy() {

    }

    public String getCurrentUserId(SlingHttpServletRequest request) {
        ResourceResolver resolver = request.getResourceResolver();
        Session session = resolver.adaptTo(Session.class);
        String userId = session.getUserID();

        return userId;

    }

}

当此过滤器处理 POST 提交时,我收到以下错误,指出请求正文已被读取。所以看来过滤器排名可能不够高。

25.06.2018 13:11:13.200 ERROR [0:0:0:0:0:0:0:1 [1529946669719] POST /content/forms/af/my-site/request-access/jcr:content/guideContainer.af.internalsubmit.jsp HTTP/1.1] org.apache.sling.engine.impl.SlingRequestProcessorImpl service: Uncaught Throwable java.lang.IllegalStateException: Request Data has already been read at org.apache.sling.engine.impl.request.RequestData.getInputStream(RequestData.java:669) at org.apache.sling.engine.impl.SlingHttpServletRequestImpl.getInputStream(SlingHttpServletRequestImpl.java:292) at javax.servlet.ServletRequestWrapper.getInputStream(ServletRequestWrapper.java:136) at my.site.servlets.FormSubmitRequestWrapper.(FormSubmitRequestWrapper.java:26) at my.site.servlets.DecorateUserGeneratedFilter.doFilter(DecorateUserGeneratedFilter.java:75) at org.apache.sling.engine.impl.filter.AbstractSlingFilterChain.doFilter(AbstractSlingFilterChain.java:68) at org.apache.sling.engine.impl.filter.AbstractSlingFilterChain.doFilter(AbstractSlingFilterChain.java:73) at org.apache.sling.engine.impl.filter.AbstractSlingFilterChain.doFilter(AbstractSlingFilterChain.java:73) at com.cognifide.cq.includefilter.DynamicIncludeFilter.doFilter(DynamicIncludeFilter.java:82) at org.apache.sling.engine.impl.filter.AbstractSlingFilterChain.doFilter(AbstractSlingFilterChain.java:68) at org.apache.sling.engine.impl.debug.RequestProgressTrackerLogFilter.doFilter(RequestProgressTrackerLogFilter.java:10

我认为服务排名不起作用。当我查看时 http://localhost:4502/system/console/status-slingfilter 我的过滤器如图所示列出。从列出的其他过滤器来看,我认为最左边的数字是过滤器排名。由于某种原因,我的过滤器排名为 0,即使我设置为 service.ranking=700

0 : class my.site.servlets.DecorateUserGeneratedFilter (id: 8402, property: service.ranking=700); called: 0; time: 0ms; time/call: -1µs

更新:我能够修复过滤器等级,使其达到 700 仍然给出 IllegalStateException。设为 3000 后这个问题就消失了。但是当从我的包装器调用 request.getInputStream() 时。它返回 null。

最佳答案

您尝试做的事情可能是简单的方法,但可能无法适应新的 AEM 版本。

您需要完全控制工作流程的触发方式!

  1. 您的表单应有一个字段,其中包含工作流程路径(可能还有该工作流程所需的其他信息)
  2. 创建您的表单将发布到的自定义 servlet。
  3. 在该 servlet 中,处理所有用户发布的值(来自表单)。但尤其要掌握预期的工作流程路径并使用工作流程 API 触发它。

这样您就不必弄乱启动器,并且工作流程由您的用户使用其用户 ID 触发。

希望这有帮助。

关于java - 用于包装请求正文的 Sling Filter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51029340/

相关文章:

java - xml 跳过根元素

Java setBorder 破坏组件填充

java - 在名称为“的 DispatcherServlet 中找不到具有 URI [] 的 HTTP 请求的映射

java - Servlet 3.1 - 部件 - 方法 getParts() 未解决

session - AEM - 获取当前用户ID

java - AEM 6.1 : Enable Rich text editor (RTE) plugins on Touch UI

aem - 当 data-sly-test 计算结果为 false 时保留子元素?

java - 从 AlarmManger 启动的服务获取额外内容时的默认值

java - Java (+- JNA) 有没有办法在 XP+Vista+Windows 7 中可靠地设置主系统卷?

java - SearchServlet 已由较新版本的 Java Runtime 编译