1。上下文
我想实现一个Alfresco-Share Java支持的webscript,就像现有的“I18N资源和消息Web脚本”一样。 主要区别在于我想使用响应输出流(而不是编写器)。
使用的Alfresco-Share版本:4.1.1。
2。用于重现错误的测试代码
- Spring bean:
<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());
}
}
- Webscript desc文件:
<?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输出流响应?
答案 0 :(得分:5)
这是Share Web层上WebScript Runtime的限制。 Share有一个强大的组件框架和可扩展性模型,它包含所有WebScripts - 在JavaScript代码,模板等各个点实现高级自定义。不幸的是将WebScripts视为将其输出合并在一起的组件,这意味着Runtime控制OutputStream和Writer - 您检索的Writer根本不是常用的Servlet Writer,而是包装器。
答案 1 :(得分:0)
在类似的情况下,我已经将org.alfresco.repo.web.scripts.content.StreamContent子类化为AbstractWebScript。
答案 2 :(得分:0)
我遇到了完全相同的问题(使用Spring Sur 1.2.0时,但同样的问题对于最新的Trunk版本仍然有效),
我的解决方案是修补Spring Surf,如以下JIRA问题所述:https://issues.alfresco.com/jira/browse/ALF-21949
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 {
}
正如您所看到的,这只是一个空的&#34;标记类&#34;。
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存储库具有写访问权限的人会提交这些改进,所以其他任何人都可以在将来使用它们。