WebWork开发JSON接口最佳实践
WebWork开发JSON接口最佳实践
背景
在以前开发中使用webwork开发的应用大多是jsp页面,随着web2.0概念的深入人心,在页面中使用了大量的ajax调用,在实践中发现服务器端和客户端交互的最好协议是使用json数据格式,因为json的数据格式在javascript中可以很好地处理,并不用做任何额外的处理就能直接被客户端javascript处理。
笔者在本文中着重要关心的是如何通过webwork来开发出优雅,且有重用性的JSON接口程序。
欠优雅的解决方案的思考
假设现在有一个需求,给一个用户id,返回json格式的数据流给客户端。当接收到这个需求我们会想些什么?
大部分人会想:
1. 恩?json数据格式是啥呀?
2. 有没有什么map工具呀能够帮我自动将java对象转换成json数据?
3. 需要改造原先写jsp的那个流程吗?
面对上面这三个问题,稍微有点开发经验的程序员都会自问自答:
1. 问题一:json数据格式,这个有什么难的去google上找找。一看便知。
2. 问题二:这个也到google上去找找,找到一个json-java.jar的包,里面有两个类JSONObject和JSONArray这两个类可以很好地解决javabean对象转换成Json文本。
3. 问题三:既然能够将java对象转换成一个json的数据流,也就是一个String值,那简单了,要只要最后把这个String值在jsp页面上输出就行了
于是我们会把这个需求用一下的方式来实现:
1. 写一个UserAction.java
public class UserAction extends ActionSupport { private String jsonValue; private int userId; private UserService userService; public String execute() throws Exception { User user = userService.getUser(this.getUserId()); JSONObject j = new JSONObject(user); // 解析之后的字符串 this.jsonValue = j.toString(); return SUCCESS; }
2. Xwork配置文件
<action name="useraction" class="com.opensymphony.webwork.example.UserAction"> <result>/json_result.jsp</result> </action>
3. 写json_result.jsp
<%@ page pageEncoding="GBK"%><%@ taglib prefix="ww" uri="/webwork" %> <ww:property value="jsonValue" /> |
现在我就基本实现了返回用户Json数据流的需求。
反复看这个解决方法,在我内心深处始终有一种说不出的感觉,让我浑身不舒服,让我不安,暂时说不出是什么,毕竟已经实现了所有要实现的需求。之后,我又思索良久,终于想出了几条,不知道你同不同意我的想法。
问题:
1. 如果有一天前段工程师告诉我,他们不想用ajax方式来调用用户信息,这时我怎么办?势必要把 private String jsonValue这个成员变量从UserAction中去除掉。这样的改动会不会引起其他问题?现在说不好。按照面向对象的开闭原则来说,对修改应该是封闭的。如果要把jsonValue去掉的话显然对修改是不封闭的。
2. json_result.jsp 这个页面的功能仅仅只是通过它将action中的一个属性输出,暂时不讨论这个jsp能否实现共用,就这个jsp来说我觉得完全是没有必要的存在的,是一个累赘。如果要在输出流中输出一些信息的话,完全可以在action中拿到outputStream,然后往这个流里面写一些东西。
那么,应该如何来解决这些问题呢?我又开始了思考。。。。。。
想了一会儿,眼前又出现了那张刚开始学MVC设计模式时候的概念图。
这张图中有三个角色View、Controller、Model,相信大家和我一样对这三个角色的意义应该非常明白了,让我们简单地来回顾一下:
1. View:展现业务对象模型的实现层,在这里可以具体定义业务对象如何展现。
2. Controller:可以控制如何调用业务逻辑模型,选择哪个视图(view)展现给终端客户端。
3. Model:这个不用多说了,是业务逻辑模型,它只关心业务逻辑之间的具体业务逻辑,至于是应用在C2C呢还是B2B的应用场景它都不关心。
结合上面的例子,来分析一下吧,UserAction这个类就应该是一个标准的controller,json_result.jsp这个页面就应该是一个View(视图)。按照mvc模式的要求view和Controller是解耦的各自应该是可以独立地变化,但是我们发现如果要把json的数据格式改变成xml或者其他的数据格式的话,必须改动Controller(UserAction)了,再查查为啥必须改动controller呢?原来将定义模型如何展示规则的业务逻辑放到了action中,对了就是那段代码:
。。。。。 JSONObject j = new JSONObject(user); // 解析之后的字符串 this.jsonValue = j.toString(); 。。。。。。。。。
就是因为这段代码把Controller和View耦合在了一起,而且是紧紧地耦合在了一起,使得他们不能各自独立地变化。
所以现在的设计是违反mvc设计模式的。
优化、重构
知道了原因,我们就可以来着手改造了,改造的主要内容就是解耦,将controller和View解耦。
1. 首先,将JSONObject从action中移出去,将UserAction改造成如下:
public class UserAction extends ActionSupport { private int userId; private UserService userService; public String execute() throws Exception { User user = userService.getUser(this.getUserId()); this.setUser(user); return SUCCESS; } 。。。。。。 |
2. 新添加一个webwork的Result类型
添加一个新的MyJsonResult继承于JSONResult(webwork2.2.7中新添加的一个类),在新的MyJsonResult中覆写父类中的方法getJSONObject();主要代码如下:
public class JsonArrayResult extends JSONResult { @Override protected JSONObject getJSONObject(ActionInvocation invocation) throws JSONException { ActionContext actionContext = invocation.getInvocationContext(); Object obj = actionContext.getValueStack().findValue( this.getJSONObjectProperty()); 。。。。。。。。。。。。。。 JSONObject jo = new JavaScriptJSONObject(); jo.put("result", obj); return jo; } 。。。。。。。。。。。。。。。。。。。。
将这个新的Result配置在xwork.xml中
<package name="store" extends="default" namespace="/store"> <result-types> <result-type name="jsonArrayResult" class="com.koubei.store.action.json.JsonArrayResult" /> </result-types> </package>
3. 改造action配置
<action name="useraction" class="com.opensymphony.webwork.example.UserAction"> <result name="success" type="jsonArrayResult"> <param name="jSONObjectProperty">user</param> </result> </action>
好了,改造完成了。这里最主要的一个东西,就是添加了一个自定义Result将json展示的业务逻辑封装到了这个Result中。改造之后符合了MVC模式的要求,Controller和View可以各自独立地变化。可以省去一个累赘的jsp文件。
结束语
促使笔者写这篇文章的原因是笔者参加口碑的一个活动页面开发过程中,有一个返回给客户端Json数据的需求,在查看了其他同事编写的代码(本文档的未优化前的解决方案),基本上都是这样写的,结合自己以往学习MVC模式的经验,觉得有可以重构之处。
老实说这样的代码改动来说的确很小,而且对系统运行的性能也没有多大帮助,但是笔者总相信,再好的架构,再好的系统也是从一个个微小的细节组合起来的。只有将每一个细小的细节,每一个流程都处理好,都和谐地运行。才能在更高层次上做优化,正所谓聚沙成塔,就是这个道理。