ExtJs通過JSON與后臺通信
Posted on | 二月 22, 2010 | No Comments
引言
EXT技術對提升用戶體驗有著先天的優勢,很多機構和個人都開始學習EXT技術,截止今天EXT CORE 3.0 也已經發布,EXTJS 3.0 指日可待。雖然性能越來越讓人擔憂。。。
無論用多么驚天地泣鬼神的前臺技術,與后臺的通信總是必須的。本文就目前手頭上有的資料和經驗來大概闡述一下EXTJS和后臺通信這點事。
為什么要用JSON?
選中JSON不是一拍腦門子的事。EXTJS也不是只支持JSON。目前常用的不外乎下面幾種通信方式:
1. 動態語言文件周轉,如JSP
用JSP一類的動態語言文件中轉數據無疑是傳遞數據比較簡單的一種,但是不好傳遞對象。隨便舉個用Session傳遞數據的例子。例如:
varUserName= <%=session.getAttribute(“user”)%>;
if(UserName==null){
location.href = ‘login.jsp’;
}
缺點就是不能方便的傳遞對象。不那么舒服,EXT的不徹底。還在混雜使用JSP這種相比與EXT來說老掉牙的東西。 當然,如果項目條件不允許,或者不需要做成徹底的AJAX OnePage應用。這種方式還是可以解決很多迫在眉睫的問題的。(我是徹底的One Page 狂熱者^.^)
2. JSON
JSON是和JavaScript門當戶對的數據傳輸方式,所以用起來會很舒服。而且他可以很方便的傳遞對象,EXT也對JSON支持的很全面。所有的數據傳遞需求他都可以勝任?,F在第三方的JSON框架也很成熟。
3. XML
EXTJS本身是提供對XML類型數據的解析功能的,和JSON一樣。 官方的示例程序也有專門演示XML數據通信的。個人感覺和JSON是同一個級別的,也是比較推薦的方式。
4. 文本
異步調用返回的東西是文本,說白了AJAX就是靠文本傳輸數據的,無論JSON還是XML,他都是文本。所以文本很牛的。如果弄好了,自己定義一個傳輸格式也不是不可以。一般不復雜的東西,比如傳個標記,傳個string什么的。沒必要用JSON,用文本就很好用。
缺點已經說了,就是無法勝任稍復雜的通信需求。
所以目前看來就在JSON和XML中選擇一個了。XML以后再表,我們現在主要表JSON。
通信過程
從后臺到前臺
看一下通信過程中的圖,其中對象我們已經有了,也就是你想要傳遞的東西。剩下的,就是后臺如何把對象轉換成JSON,以及前臺如何把JSON再解析為對象了。我們先來看后臺如何把對象轉換成JSON。
首先要隆重登場的是我自己改寫的一個根據LIST生成JSON的類。其實這類簡單的要死。所以他只能勝任把LIST轉成JSON的工作。而且還有一個局限,至于是什么局限,我們慢慢說。
先看代碼:
//yueue修改的輕量級JSON類
package Extest;
import java.util.ArrayList;
public class Json {
public static void main(String[] args) {
}
public String singleInfo=”";
public Integer total=0;
protected boolean _success=true;
protected String _error=”";
protected ArrayList arrData=new ArrayList();
protected ArrayList dataItem=new ArrayList();
public String getError() {
return _error;
}
public void setError(String error) {
if(!error.equals(“”))this._success=false;
this._error = error;
}
public boolean getSuccess() {
return _success;
}
public void setSuccess(boolean success) {
if(success) this._error=”";
this._success = success;
}
public Json()
{
}
public void reSet()
{
arrData.clear();
dataItem.clear();
}
public void addItem(String name,String _value)
{
dataItem.add(name);
dataItem.add(_value);
}
//一個數組添加完畢,一個新的數組開始
public void addItemOk()
{
arrData.add(dataItem);
dataItem=new ArrayList();
}
public String ToString()
{
StringBuilder sb=new StringBuilder();
sb.append(“{“);
sb.append(“\”total\”:”);
sb.append(total.toString()+”,”);
sb.append(“\”datas\”:”);
sb.append(“[");
int ad=arrData.size();
for(int i=0;i<ad;i++)
{
ArrayList arr=(ArrayList)(arrData.get(i));
sb.append("{");
int t=arr.size();
for(int j=0;j<t;j+=2)
{
if(j==t) break;
sb.append("\"");
sb.append(arr.get(j).toString());
sb.append("\"");
sb.append(":");
sb.append("\"");
sb.append(arr.get(j+1).toString());
sb.append("\"");
if(j<t-2) sb.append(",");
}
sb.append("}");
if(i<ad-1) sb.append(",");
}
sb.append("]“);
sb.append(“}”);
return sb.toString();
}
}
代碼不長。下面我們看看怎么用這個東西把一個LIST轉成JSON
Json js = new Json();
while (rs.next())
{
js.addItem(“ID”, rs.getString(“ID”));
js.addItem(“Code”, rs.getString(“Sheet_Code”));
js.addItem(“Consignee”, rs.getString(“Sheet_Consignee”));
js.addItem(“Tone”, rs.getString(“Sheet_Tone”));
js.addItem(“Date”, rs.getString(“Sheet_Date”));
js.addItem(“Cash”, rs.getString(“Sheet_Cash”));
js.addItem(“Station”, rs.getString(“Sheet_Station”));
js.addItem(“Class”, rs.getString(“Sheet_Class”));
js.addItemOk();
}
System.out.print(js.outputString());
其中rs是一個ResultSet ,里面放的是從數據庫里讀取的數據。
其中每次 addItem() 都向JSON提交了一個字段(屬性),當字段提交完畢,執行addItemOk()方法,就會創建條完整的記錄(對象) , 當你循環執行這個流程,就提交了多條記錄(對象),最后的最后, outputString() 方法將你前面提交的所有記錄(對象)轉化為JSON并打印出來。你可以對比代碼看看最后輸出來的JSON到底是個什么樣子。有助于你理解JSON。
上面的這個類看起來似乎不錯。實際上這個類幾乎沒有大的用途。因為他只能處理簡單的對象,他遇到任何對象都會調用其toString 方法試圖獲得代表這個對象的字符串,然后儲存并轉化。當然,如果是String , Integer , Double ,等類型自然沒有問題,因為這些對象可以不失真的轉化為String。而遇到一個復雜對象,比如一個由Hibernate生成的對象,他就無能為力了。他不能自動遍歷對象下面的所有屬性,并一一轉換。
那么怎么解決呢? 答案是用強大的第3方類庫,比如JSON-Lib 或者 org.json包
JSON-lib 是一個封裝了常用的JSON業務的第3方類庫,很強,很大。
使用JSON-lib 還需要很多特定版本的包來支持(很煩)。
具體的安裝,還有需要什么支持包,去jsonlib網站上看吧。
下面看一個項目中常用的JSON-Lib使用例子。(在ACTION中的代碼)
try{
PrintWriter out = response.getWriter();
UserInfo userInfo = (UserInfo)request.getSession().getAttribute(“userinfo”); //從session中得到用戶信息對象
String tempStr = “{\”Datas\”:”+JSONSerializer.toJSON(theList,config).toString()+”}”;
out.print(tmpStr);
return null;
}catch(Exception ex){
ex.printStackTrace();
return null;
}
很簡單,使用JSON-Lib轉化的工作就在String tempStr = “{\”Datas\”:”+JSONSerializer.toJSON(theList,config).toString()+”}”;
這行搞定了。然后輸出就可以了。
但是,這里有3個問題:
1. 會有可能出現亂碼
2. 會出現環,比如,對象A中包含B,而對象B中又再次包含A,于是出現了無限循環的環路。這個時候JSON-LIB會報一個net.sf.json.JSONException: There is a cycle in the hierarchy的錯誤。
3. 會出現日期問題,因為JAVA中日期屬于一個復雜對象,JSON-Lib會把他當做一個復雜對象去解析,得到的結果就不是你要的 2009-01-01 這樣的字符串了
解決方法:
1. 請參見我的BLOG : 《Extjs Ajax 亂碼問題解決方案》
2. 請參見我的BLOG: 《json-lib出現There is a cycle in the hierarchy解決辦法》
3. 對JSON-LIB進行設置 config.registerJsonValueProcessor(Date.class,new DateJsonValueProcessor(“yyyy-MM-dd”)); //date processor register
所以,最后,這段轉換對象的代碼最后變成
response.setContentType(“text/html”);
response.setCharacterEncoding(“utf-8″);
try{
PrintWriter out = response.getWriter();
UserInfo userInfo = (UserInfo)request.getSession().getAttribute(“userinfo”); //從session中得到用戶信息對象
JsonConfig config = new JsonConfig();
config.setIgnoreDefaultExcludes(false);
config.setCycleDetectionStrategy(CycleDetectionStrategy.LENIENT);
config.registerJsonValueProcessor(Date.class,new DateJsonValueProcessor(“yyyy-MM-dd”)); //date processor register
String tempStr = “{\”Datas\”:”+JSONSerializer.toJSON(theList,config).toString()+”}”;
out.print(tmpStr);
return null;
}catch(Exception ex){
ex.printStackTrace();
return null;
}
可以訪問一下ACTION或者SERVLET, 看看結果了
現在把對象轉化為JSON沒問題了。剩下的是前臺如何把JSON轉化成對象了。
其實這部分工作EXT基本全都做了。EXT主要的數據接收和儲存靠Store 。 EXT提供有JSONStroe 用來處理json 。 這部分的工作基本不直接接觸JSON ,而是使用EXT。
如
//Grid Store from servlet
var store = new Ext.data.JsonStore({
url:’/ctams/plan/monthTransportPlan.do?method=findMonthTransportPlan’,
root:’Datas’,
totalProperty: ‘TotalRecords’,
fields:["mtpId",
"mtpDate",
"mtpAcceptnum",
"mtpPlannum",
"mtpCarriagenum",
"mtpTunnage",
"mtpTrainnum",
"mtpFormernum",
"mtpFormertunnage",
"mtpFormertrainnum",
"mtpSwapload",
"mtpEndharbor",
"mtpAlreadyuse",
"mtpFlag",
"mtpRemark",
{name:'mpId',mapping:'monthPlan.mpId'}
],
baseParams:{
planDate:txtSearchText.getValue(),
planType:’42′,
conName:”
}
});
從前臺到后臺
目前我接觸到系統往前臺發送數據主要通過HTTP參數發送。
更高級一些的就是打包成json,再發回服務器