3

1. 背景

我想实现一个 Alfresco-Share Java 支持的 webscript,比如现有的“I18N 资源和消息 Web 脚本”。主要区别在于我想使用响应输出流(而不是编写器)。

使用的 Alfresco-Share 版本:4.1.1。

2. 用于重现错误的测试代码

- 春豆:

<bean id="webscript.test.content.get" parent="webscript" class="test.TestWebscript" />

- Java代码:

package test;

import java.io.IOException;

import org.springframework.extensions.webscripts.AbstractWebScript;
import org.springframework.extensions.webscripts.WebScriptRequest;
import org.springframework.extensions.webscripts.WebScriptResponse;

public final class TestWebscript extends AbstractWebScript
{
    @Override
    public void execute(final WebScriptRequest request, final WebScriptResponse response) throws IOException
    {
        response.getOutputStream().write("test".getBytes());
    }
}

- 网页脚本描述文件:

<?xml version="1.0" encoding="UTF-8"?>

<webscript>
  <shortname>Test webscript</shortname>
  <description>A webscript using the response outputstream</description>
  <url>/test/content</url>
  <format default="">extension</format>
  <lifecycle>draft_public_api</lifecycle>
  <authentication>guest</authentication>
  <transaction>required</transaction>
  <family>Tests</family>
</webscript>

3. 结果

我有以下例外:

java.lang.IllegalStateException: getOutputStream() has already been called for this response
    at org.apache.catalina.connector.Response.getWriter(Response.java:611)
    at org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:198)
    at org.springframework.extensions.webscripts.servlet.WebScriptServletResponse.getWriter(WebScriptServletResponse.java:198)
    at org.springframework.extensions.webscripts.LocalWebScriptRuntimeContainer.executeScript(LocalWebScriptRuntimeContainer.java:241)
    at org.springframework.extensions.webscripts.AbstractRuntime.executeScript(AbstractRuntime.java:377)
    at org.springframework.extensions.webscripts.AbstractRuntime.executeScript(AbstractRuntime.java:209)
    at org.springframework.extensions.webscripts.servlet.mvc.WebScriptView.renderMergedOutputModel(WebScriptView.java:104)
    at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:250)
    at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1047)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:817)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:549)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.alfresco.web.site.servlet.MTAuthenticationFilter.doFilter(MTAuthenticationFilter.java:74)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.alfresco.web.site.servlet.SSOAuthenticationFilter.doFilter(SSOAuthenticationFilter.java:355)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
    at org.apache.coyote.http11.Http11NioProcessor.process(Http11NioProcessor.java:886)
    at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:721)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:2256)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)

4. 问题

有没有办法使用 webscript 输出流响应?

4

3 回答 3

5

这是共享 Web 层上 WebScript 运行时的限制。Share 有一个强大的组件框架和可扩展性模型,可以封装所有 WebScript——在 JavaScript 代码、模板等的各个点启用高级定制。不幸的是,将 WebScript 视为将它们的输出合并到一个页面上的组件意味着运行时控​​制OutputStream 和 Writer - 您检索的 Writer 根本不是通常的 Servlet Writer,而是一个包装器。

于 2013-01-14T17:33:46.580 回答
0

在类似情况下,我将 org.alfresco.repo.web.scripts.content.StreamContent 子类化为 AbstractWebScript 而不是。

于 2013-01-11T12:40:28.263 回答
0

我遇到了完全相同的问题(使用 Spring Sur 1.2.0 时,同样的问题对于最新的 Trunk 版本仍然有效),

我的解决方案是修补 Spring Surf,如以下 JIRA 问题中所述:https ://issues.alfresco.com/jira/browse/ALF-21949

并在以下论坛主题中:https ://community.alfresco.com/thread/202736-webscript-to-export-nodes-to-excel-cannot-call-getwriter-after-getoutputstream


1)我在 spring-webscripts-1.2.0.jar 中创建了一个新类:

package org.springframework.extensions.webscripts;

/**
 * Represents a type of {@link WebScript} which directly streams the content (such as a binary file) to the {@link WebScriptResponse#getOutputStream()}.
 * <p>
 * If you want to implement the streaming of the content directly to the OutputStream obtained from the {@link WebScriptResponse},
 * then subclass this abstract class and override the method {@link AbstractWebScript#execute(WebScriptRequest, WebScriptResponse)}.
 */
public abstract class OutputStreamWebScript extends AbstractWebScript {
}

.

如您所见,这只是一个空的“标记类”。

2)我在 spring-surf-1.2.0.jar 中修改了以下类: org.springframework.extensions.webscripts.LocalWebScriptRuntimeContainer (导致异常的那个):

2a) 我在executeScript(WebScriptRequest scriptReq, WebScriptResponse scriptRes, Authenticator auth)之后添加了一个新方法:

 private void executeScriptWithExtensibilityModel(WebScriptRequest scriptReq, WebScriptResponse scriptRes, Authenticator auth) throws IOException
 {
      WebScript script = scriptReq.getServiceMatch().getWebScript();

      if (script instanceof OutputStreamWebScript)
      {
           // This type of WebScript streams directly the content to the OutputStream of the WebScriptResponse,
           // so we must not apply any extensibility model, but call through to the parent container to perform the WebScript processing
           super.executeScript(scriptReq, scriptRes, auth);
      }
      else
      {
           // For all the other types of WebScripts, apply the extensibility model as needed
           ExtensibilityModel extModel = openExtensibilityModel();
           super.executeScript(scriptReq, scriptRes, auth);
           closeExtensibilityModel(extModel, scriptRes.getWriter());
      }
 }

.

2b) 我executeScript(WebScriptRequest scriptReq, WebScriptResponse scriptRes, Authenticator auth) 中替换了以下几行:

        try
        {
            // call through to the parent container to perform the WebScript processing
            ExtensibilityModel extModel = openExtensibilityModel();
            super.executeScript(scriptReq, scriptRes, auth);
            closeExtensibilityModel(extModel, scriptRes.getWriter());
        }

这些行:

           try
           {
                // call through to the parent container to perform the WebScript processing, applying any ExtensibilityModel
                executeScriptWithExtensibilityModel(scriptReq, scriptRes, auth);
           }

.

也许对 spring-surf 和 spring-webscripts 存储库具有写访问权限的人会提交这些改进,以便其他任何人将来都可以使用它们。

于 2018-01-19T13:37:19.630 回答