diff --git a/CHANGES.txt b/CHANGES.txt index e424c616e..a06fee9c8 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -313,3 +313,5 @@ 其它valve可以通过pipelineContext.getAttribute("screenResult")来取得该值。 * Bugfix: 对于ClassNameWildcard和PathNameWildcard,当pattern以?开头或结束的时候,错误地匹配了多个字符(?的意思是有且仅有一个字符) + +* 新增 valve,用来将screen所返回的对象转换成json并输出到response。 diff --git a/CHANGES_SINCE_3.1.0.txt b/CHANGES_SINCE_3.1.0.txt index 3dbf36d92..c4a1a4d9d 100644 --- a/CHANGES_SINCE_3.1.0.txt +++ b/CHANGES_SINCE_3.1.0.txt @@ -56,3 +56,5 @@ 其它valve可以通过pipelineContext.getAttribute("screenResult")来取得该值。 * Bugfix: 对于ClassNameWildcard和PathNameWildcard,当pattern以?开头或结束的时候,错误地匹配了多个字符(?的意思是有且仅有一个字符) + +* 新增 valve,用来将screen所返回的对象转换成json并输出到response。 diff --git a/pom.xml b/pom.xml index 3c2b0451e..5aa5029db 100644 --- a/pom.xml +++ b/pom.xml @@ -487,6 +487,11 @@ xml-apis 1.4.01 + + com.alibaba + fastjson + 1.1.23 + diff --git a/webx/turbine/pom.xml b/webx/turbine/pom.xml index 2801079d9..9046416ee 100644 --- a/webx/turbine/pom.xml +++ b/webx/turbine/pom.xml @@ -16,6 +16,10 @@ javax.servlet servlet-api + + com.alibaba + fastjson + ${project.groupId} citrus-webx-framework diff --git a/webx/turbine/src/main/java/com/alibaba/citrus/turbine/pipeline/valve/PerformScreenValve.java b/webx/turbine/src/main/java/com/alibaba/citrus/turbine/pipeline/valve/PerformScreenValve.java index 6bde0aab4..2379c111e 100644 --- a/webx/turbine/src/main/java/com/alibaba/citrus/turbine/pipeline/valve/PerformScreenValve.java +++ b/webx/turbine/src/main/java/com/alibaba/citrus/turbine/pipeline/valve/PerformScreenValve.java @@ -50,7 +50,7 @@ * @author Michael Zhou */ public class PerformScreenValve extends AbstractValve { - private static final String DEFAULT_RESULT_NAME = "screenResult"; + static final String DEFAULT_RESULT_NAME = "screenResult"; @Autowired private ModuleLoaderService moduleLoaderService; diff --git a/webx/turbine/src/main/java/com/alibaba/citrus/turbine/pipeline/valve/RenderResultAsJsonValve.java b/webx/turbine/src/main/java/com/alibaba/citrus/turbine/pipeline/valve/RenderResultAsJsonValve.java new file mode 100644 index 000000000..8c7e15f91 --- /dev/null +++ b/webx/turbine/src/main/java/com/alibaba/citrus/turbine/pipeline/valve/RenderResultAsJsonValve.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2002-2012 Alibaba Group Holding Limited. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.citrus.turbine.pipeline.valve; + +import static com.alibaba.citrus.springext.util.SpringExtUtil.*; +import static com.alibaba.citrus.util.StringUtil.*; + +import java.io.PrintWriter; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.alibaba.citrus.service.pipeline.PipelineContext; +import com.alibaba.citrus.service.pipeline.Valve; +import com.alibaba.citrus.service.pipeline.support.AbstractValveDefinitionParser; +import com.alibaba.fastjson.JSON; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.xml.ParserContext; +import org.w3c.dom.Element; + +/** + * 将screen所返回的结果转换成json格式并输出。 + * + * @author Michael Zhou + */ +public class RenderResultAsJsonValve implements Valve { + private static final String DEFAULT_RESULT_NAME = PerformScreenValve.DEFAULT_RESULT_NAME; + private static final String DEFAULT_CONTENT_TYPE = "application/json"; + private static final String DEFAULT_JAVASCRIPT_VARIABLE = null; + private static final String DEFAULT_JAVASCRIPT_CONTENT_TYPE = "application/javascript"; + + @Autowired + private HttpServletRequest request; + + @Autowired + private HttpServletResponse response; + + private String resultName; + private String contentType; + private String javascriptVariable; + private String javascriptContentType; + + public String getResultName() { + return resultName == null ? DEFAULT_RESULT_NAME : resultName; + } + + public void setResultName(String resultName) { + this.resultName = trimToNull(resultName); + } + + public String getContentType() { + return contentType == null ? DEFAULT_CONTENT_TYPE : contentType; + } + + public void setContentType(String contentType) { + this.contentType = trimToNull(contentType); + } + + public String getJavascriptVariable() { + return javascriptVariable == null ? DEFAULT_JAVASCRIPT_VARIABLE : javascriptVariable; + } + + public void setJavascriptVariable(String javascriptVariable) { + this.javascriptVariable = trimToNull(javascriptVariable); + } + + public String getJavascriptContentType() { + return javascriptContentType == null ? DEFAULT_JAVASCRIPT_CONTENT_TYPE : javascriptContentType; + } + + public void setJavascriptContentType(String javascriptContentType) { + this.javascriptContentType = trimToNull(javascriptContentType); + } + + public void invoke(PipelineContext pipelineContext) throws Exception { + String javascriptVariable = getJavascriptVariable(); + boolean outputAsJson = javascriptVariable == null; + + if (outputAsJson) { + // output as json + response.setContentType(getContentType()); + } else { + // output as javascript + response.setContentType(getJavascriptContentType()); + } + + PrintWriter out = response.getWriter(); + Object resultObject = pipelineContext.getAttribute(getResultName()); + String jsonResult = JSON.toJSONString(resultObject); + + if (outputAsJson) { + out.print(jsonResult); + } else { + out.print("var "); + out.print(javascriptVariable); + out.print(" = "); + out.print(jsonResult); + out.print(";"); + } + } + + public static class DefinitionParser extends AbstractValveDefinitionParser { + @Override + protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { + attributesToProperties(element, builder, "resultName", "contentType", "javascriptVariable", "javascriptContentType"); + } + } +} diff --git a/webx/turbine/src/main/resources/META-INF/services-pipeline-valves.bean-definition-parsers b/webx/turbine/src/main/resources/META-INF/services-pipeline-valves.bean-definition-parsers index 7eb1faa54..c89ab0864 100644 --- a/webx/turbine/src/main/resources/META-INF/services-pipeline-valves.bean-definition-parsers +++ b/webx/turbine/src/main/resources/META-INF/services-pipeline-valves.bean-definition-parsers @@ -12,6 +12,7 @@ performAction=com.alibaba.citrus.turbine.pipeline.valve.PerformActionValve$Defin performTemplateScreen=com.alibaba.citrus.turbine.pipeline.valve.PerformTemplateScreenValve$DefinitionParser performScreen=com.alibaba.citrus.turbine.pipeline.valve.PerformScreenValve$DefinitionParser renderTemplate=com.alibaba.citrus.turbine.pipeline.valve.RenderTemplateValve$DefinitionParser +renderResultAsJson=com.alibaba.citrus.turbine.pipeline.valve.RenderResultAsJsonValve$DefinitionParser exportControl=com.alibaba.citrus.turbine.pipeline.valve.ExportControlValve$DefinitionParser breakUnlessTargetRedirected=com.alibaba.citrus.turbine.pipeline.valve.BreakUnlessTargetRedirectedValve$DefinitionParser diff --git a/webx/turbine/src/main/resources/META-INF/services/pipeline/valves/renderResultAsJson.xsd b/webx/turbine/src/main/resources/META-INF/services/pipeline/valves/renderResultAsJson.xsd new file mode 100644 index 000000000..73432bb1a --- /dev/null +++ b/webx/turbine/src/main/resources/META-INF/services/pipeline/valves/renderResultAsJson.xsd @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/webx/turbine/src/test/config/WEB-INF/webx-app1.xml b/webx/turbine/src/test/config/WEB-INF/webx-app1.xml index 9262c5100..873a618fd 100644 --- a/webx/turbine/src/test/config/WEB-INF/webx-app1.xml +++ b/webx/turbine/src/test/config/WEB-INF/webx-app1.xml @@ -55,6 +55,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/webx/turbine/src/test/java/com/alibaba/citrus/turbine/pipeline/valve/RenderResultAsJsonValveTests.java b/webx/turbine/src/test/java/com/alibaba/citrus/turbine/pipeline/valve/RenderResultAsJsonValveTests.java new file mode 100644 index 000000000..51c740223 --- /dev/null +++ b/webx/turbine/src/test/java/com/alibaba/citrus/turbine/pipeline/valve/RenderResultAsJsonValveTests.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2002-2012 Alibaba Group Holding Limited. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.citrus.turbine.pipeline.valve; + +import static org.junit.Assert.*; + +import com.alibaba.citrus.service.pipeline.impl.PipelineImpl; +import com.meterware.httpunit.WebResponse; +import org.junit.Before; +import org.junit.Test; + +public class RenderResultAsJsonValveTests extends AbstractValveTests { + @Before + public void init() { + pipeline = (PipelineImpl) factory.getBean("renderJson"); + assertNotNull(pipeline); + } + + @Test + public void outputAsJson_noResult() throws Exception { + getInvocationContext("http://localhost/app1/myJsonScreen/noResult"); + initRequestContext(); + pipeline.newInvocation().invoke(); + commitRequestContext(); + + WebResponse webResponse = client.getResponse(invocationContext); + + assertEquals(200, webResponse.getResponseCode()); + assertEquals("application/json", webResponse.getContentType()); + assertEquals("null", webResponse.getText()); + } + + @Test + public void outputAsJson_withResult() throws Exception { + getInvocationContext("http://localhost/app1/myJsonScreen/withResult"); + initRequestContext(); + pipeline.newInvocation().invoke(); + commitRequestContext(); + + WebResponse webResponse = client.getResponse(invocationContext); + + assertEquals(200, webResponse.getResponseCode()); + assertEquals("application/json", webResponse.getContentType()); + assertEquals("{\"age\":100,\"name\":\"michael\"}", webResponse.getText()); + } + + @Test + public void outputAsJson_withResult_specifiedContentType() throws Exception { + pipeline = (PipelineImpl) factory.getBean("renderJson_specifiedContentType"); + getInvocationContext("http://localhost/app1/myJsonScreen/withResult"); + initRequestContext(); + pipeline.newInvocation().invoke(); + commitRequestContext(); + + WebResponse webResponse = client.getResponse(invocationContext); + + assertEquals(200, webResponse.getResponseCode()); + assertEquals("text/plain", webResponse.getContentType()); + assertEquals("{\"age\":100,\"name\":\"michael\"}", webResponse.getText()); + } + + @Test + public void outputAsJs_noResult() throws Exception { + pipeline = (PipelineImpl) factory.getBean("renderJsonAsJs"); + getInvocationContext("http://localhost/app1/myJsonScreen/noResult"); + initRequestContext(); + pipeline.newInvocation().invoke(); + commitRequestContext(); + + WebResponse webResponse = client.getResponse(invocationContext); + + assertEquals(200, webResponse.getResponseCode()); + assertEquals("application/javascript", webResponse.getContentType()); + assertEquals("var myresult = null;", webResponse.getText()); + } + + @Test + public void outputAsJs_withResult() throws Exception { + pipeline = (PipelineImpl) factory.getBean("renderJsonAsJs"); + getInvocationContext("http://localhost/app1/myJsonScreen/withResult"); + initRequestContext(); + pipeline.newInvocation().invoke(); + commitRequestContext(); + + WebResponse webResponse = client.getResponse(invocationContext); + + assertEquals(200, webResponse.getResponseCode()); + assertEquals("application/javascript", webResponse.getContentType()); + assertEquals("var myresult = {\"age\":100,\"name\":\"michael\"};", webResponse.getText()); + } + + @Test + public void outputAsJs_withResult_specifiedContentType() throws Exception { + pipeline = (PipelineImpl) factory.getBean("renderJsonAsJs_specifiedContentType"); + getInvocationContext("http://localhost/app1/myJsonScreen/withResult"); + initRequestContext(); + pipeline.newInvocation().invoke(); + commitRequestContext(); + + WebResponse webResponse = client.getResponse(invocationContext); + + assertEquals(200, webResponse.getResponseCode()); + assertEquals("text/js", webResponse.getContentType()); + assertEquals("var myresult = {\"age\":100,\"name\":\"michael\"};", webResponse.getText()); + } +} diff --git a/webx/turbine/src/test/java/com/alibaba/test/app1/module/screen/MyJsonScreen.java b/webx/turbine/src/test/java/com/alibaba/test/app1/module/screen/MyJsonScreen.java new file mode 100644 index 000000000..852ea73eb --- /dev/null +++ b/webx/turbine/src/test/java/com/alibaba/test/app1/module/screen/MyJsonScreen.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2002-2012 Alibaba Group Holding Limited. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.test.app1.module.screen; + +public class MyJsonScreen { + public void doNoResult() { + } + + public Object doWithResult() throws Exception { + return new MyObject("michael", 100); + } + + public static class MyObject { + private String name; + private int age; + + public MyObject(String name, int age) { + this.name = name; + this.age = age; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + } +}