Struts2整合JSON

 

通过扩展Struts2的ResultType,自定义一个JsonResult使Struts2无缝整合JSON,也使得在Struts2中使用Json的时候变得更加的方便和灵活,更具扩展性。

在Struts2中有个一个StreamResult,这是用于文件的上传和下载的,不知道大家是否用过。我们就先分析一下这个类,然后参照它写出JSONResult。

struts.xml中配置StreamResult的部分如下:

1: <result type="stream"><!-- 使用ognl获取值栈属性值用于配置 -->

2: <param name="contentType">${fileContentType}</param>

3: <param name="inputName">inputStream</param><!-- 默认是inputSteam,可省略,

4: 但是action中需要添加InputStream getInputStream() ,如果这边设置为imageInputStream 则需要添加InputStream getImageInputStream()-->

5: <param name="contentLength">${fileLength}</param>

6: <!-- 设置下载文件名 -->

7: <param name="contentDisposition">filename="${newFileName}"</param>

8: <param name="bufferSize">2048</param>

9: </result>

可以很清楚的看到使用StreamResult的时候,有五个属性参数需要配置,这五个参数都是需要从action中传递过来的!为什么就一定要配置五个参数呢?不能不配置吗?这五个参数是StreamResult中需要使用到的属性,当然也可以不用配置,但是前提是属性值需要符合StreamResult默认的参数。比如这个文件的contentType是image/gif的,而StreamResult中默认的是text/plain,这个能不配置吗?当然不行啦,否则后果是可以设想的,不出错才怪呢?!

接下来我们分析一下StreamResult源文件,要实现一个自定义的ResultType值需要继承StrutsResultSupport,并实现doExecute方法即可

1: import java.io.InputStream;

2: import java.io.OutputStream;

3: import javax.servlet.http.HttpServletResponse;

4: import org.apache.struts2.dispatcher.StrutsResultSupport;

5: import com.opensymphony.xwork2.ActionInvocation;

6: 

7: public class StreamResult extends StrutsResultSupport {

8: 

9: private static final long serialVersionUID = -1468409635999059850L;

10: 

11: public static final String DEFAULT_PARAM = "inputName";

12: 

13: protected String contentType = "text/plain";

14: protected String contentLength;

15: protected String contentDisposition = "inline";

16: protected String inputName = "inputStream";

17: protected InputStream inputStream;

18: protected int bufferSize = 1024;

19: 

20: public StreamResult() {

21: super();

22: }

23: 

24: public StreamResult(InputStream in) {

25: this.inputStream = in;

26: }

27: 

28: //省略一大堆的setter和getter

29: 

30: protected void doExecute(String finalLocation, ActionInvocation invocation)

31: throws Exception {

32: 

33: OutputStream oOutput = null;

34: 

35: try {

36: if (inputStream == null) {

37: // 这里是整个StreamResult的关键(个人观点)

38: // 这里是通过struts.xml中inputName配置的参数值,拿到值栈中与参数值同名的真实对象

39: // 这个对象也就是在action中那个InputStream的对象实例。

40: //通俗的讲,就是将那个参数值转化为与之同名的对象

41: inputStream = (InputStream) invocation.getStack().findValue(

42: conditionalParse(inputName, invocation));

43: }

44: 

45: if (inputStream == null) {

46: String msg = ("Can not find a java.io.InputStream with the name ["

47: + inputName + "] in the invocation stack. " + "Check the <param name=\"inputName\"> tag specified for this action.");

48: throw new IllegalArgumentException(msg);

49: }

50: 

51: // Find the Response in context

52: HttpServletResponse oResponse = (HttpServletResponse) invocation

53: .getInvocationContext().get(HTTP_RESPONSE);

54: 

55: // Set the content type

56: oResponse.setContentType(conditionalParse(contentType, invocation));

57: 

58: // Set the content length

59: if (contentLength != null) {

60: String _contentLength = conditionalParse(contentLength,

61: invocation);

62: int _contentLengthAsInt = -1;

63: try {

64: _contentLengthAsInt = Integer.parseInt(_contentLength);

65: if (_contentLengthAsInt >= 0) {

66: oResponse.setContentLength(_contentLengthAsInt);

67: }

68: } catch (NumberFormatException e) {

69:

70: }

71: }

72: 

73: // Set the content-disposition

74: if (contentDisposition != null) {

75: oResponse.addHeader("Content-disposition", conditionalParse(

76: contentDisposition, invocation));

77: }

78: 

79: // Get the outputstream

80: oOutput = oResponse.getOutputStream();

81: 

82: // Copy input to output

83: byte[] oBuff = new byte[bufferSize];

84: int iSize;

85: while (-1 != (iSize = inputStream.read(oBuff))) {

86: oOutput.write(oBuff, 0, iSize);

87: }

88: 

89: // Flush

90: oOutput.flush();

91: } finally {

92: if (inputStream != null)

93: inputStream.close();

94: if (oOutput != null)

95: oOutput.close();

96: }

97: }

98: 

99: }

我们在web页面中访问服务器中文件对象的时候,服务器都是将那个对象以流的形式输出,浏览器在通过不同的contentType做出不同的响应。比如文件是一个图片,就可以在页面中显示出来;如果是一个rar文件,就会提示是否保存文件了。在以上源码中“转换”出来的inputStream就是那个文件对象的“源”了,代码85-87行就是将那个“源”流到客户端了。这样就可以使用StreanResult达到从服务器端下载一个文件了。

StreamResult的实现方式来实现我们自己的JsonResult。

使用过Json的同学都知道,使用Json的时候有几个重要的类是我们经常使用到的。他们分别是:JSONArray,JSONObject和JsonConfig;

JSONArray:是用于将Java中Array以及Collection转换成Json形式的字符串;

JSONObject:是将Java中的普通对象以及Map转换成Json形式的字符串;

JsonConfig:当我们将Java中的对象要转换成Json的时候,需要防止形成环状(比如在一对一等映射关系中),如果你是使用Hibernate的时候,对于代理对象也是不能转化的,还有就是对于日期的转换也是经常会出错的(如果一定要使用日期,建议使用dwr传输数据)。以上三种情景是在使用Json的时候最容易出错的,幸好JsonConfig帮了我们大忙。使用JsonConfig可以将一个类中包含以上三种类型的属性在将对象转换成Json的时候过滤掉(当然是在客户端不需要那些属性的情况下),同时这样也能减少网络通信的数据量,提升性能。

比如有这么一个Person类:

1: public class Person {

2: 

3: private String id;

4: private String name;

5: private int age;

6: private Date birthday;

7: /**

8: * 身份证,与person是一对一的关系

9: */

10: private IDCard idcard;

我们就可以用以下代码过滤掉某些不需要转换的属性了:

1: public void TransToJson(){

2: JsonConfig config = new JsonConfig();

3: config.setExcludes(new String[]{"birthday","idcard"});

通过以上分析就可以得出JsonResult需要三个属性了:

1: public class JSONResult extends StrutsResultSupport {

2: 

3: private static final long serialVersionUID = 2067467373264270817L;

4: 

5: /**

6: * 配置需要过滤掉的属性

7: */

8: public String excludes;

9: /**

10: * 需要转化为真实的对象,在将此对象转化为Json,通过response响应到客户端

11: */

12: public String objectName;

13: /**

14: * 配置对象类型(Object|Array)

15: */

16: public String objectType;

当我们完成了JsonResult的时候还要在Struts.xml中声明自定义的ResultType

1: <!-- 声明自定义的JsonResults -->

2: <result-types>

3: <result-type name="json" class="ssh.jquery.crud.util.JSONResult"/>

4: </result-types>

5:

6: <action name="person" class="ssh.jquery.crud.action.PersonAction">

7: <result>/WEB-INF/page/default.jsp</result>

8: <!-- 使用名字为json的type -->

9: <result name="json" type="json">

10: <!-- 配置对象类型 -->

11: <param name="objectType">array</param>

12: <!-- 配置对象名,在action需要有一个getPersons()方法 -->

13: <param name="objectName">persons</param>

14: <!-- 配置过滤的属性,当不需要过滤的时候值为null;有多个属性时用","隔开 -->

15: <param name="excludes">null</param>

16: </result>

以下是JsonResult的完整代码:

1: public class JSONResult extends StrutsResultSupport {

2: 

3: private static final long serialVersionUID = 2067467373264270817L;

4: 

5: /**

6: * 配置需要过滤掉的属性

7: */

8: public String excludes;

9: /**

10: * 需要转化为真实的对象,在将此对象转化为Json,通过response响应到客户端

11: */

12: public String objectName;

13: /**

14: * 配置对象类型(Object|Array)

15: */

16: public String objectType;

17: 

18: //省略一堆setter和getter

19: 

20: @Override

21: protected void doExecute(String finalLocation, ActionInvocation invocation)

22: throws Exception {

23: //获得servlet中的response对象

24: HttpServletResponse response = (HttpServletResponse) invocation

25: .getInvocationContext().get(HTTP_RESPONSE);

26: response.setContentType("text/javascript;charset=utf-8");

27: PrintWriter out = response.getWriter();

28: JsonConfig config = new JsonConfig();

29: //设置过滤的属性

30: config.setExcludes(excludes.split(","));

31: //判断对象类型,再进行转换

32: if ("array".equals(objectType.toLowerCase())) {

33: JSONArray jsonArray = JSONArray.fromObject(invocation.getStack()

34: .findValue(conditionalParse(objectName, invocation)),

35: config);

36: out.print(jsonArray.toString());

37: } else if ("object".equals(objectType.toLowerCase())) {

38: JSONObject jsonObject = JSONObject.fromObject(invocation.getStack()

39: .findValue(conditionalParse(objectName, invocation)),

40: config);

41: out.print(jsonObject.toString());

42: }

43: }

你可能感兴趣的:(Struts2整合JSON)