最近也終于使用ext做了一個小的web項目。第一次使用ext做項目畢竟經驗不足,僅記下一些開發思路和需要注意的地方。
Ext Js 2.2+Spring 2.5,沒有使用struts,hibernate
1)目錄結構
a)js部分
根目錄下建立/js/ext/目錄,存放所有和ext相關的js文件。/js/ext/目錄下可建立ext相關子目錄
/js/ext/adapter/ — 存放適配器jquery,prototype,yui。。。
/js/ext/experimental/ — 存放ext一些未正式推出的組件,可參考ext開發包examples例子部分。
/js/ext/plugins/ — 存放ext擴展組件,例如ext的patch文件,ext主題,擴展組建等等。
/js/ext/resources/ — 不用說了,ext開發包中的resources目錄直接拷貝。
/js/ — 目錄下可以放一些最常用 的js文件。
/js/ext/ — 目錄下放置ext-all.js,ext-base.js,ext-lang-zh_CN.js,ext核心文件;
b)模塊部分
根目錄下建立/module/文件夾,每個模塊在/module/目錄下新建文件夾,例如:
/module/comment/ — 評論模塊
/module/stat/ — 統計模塊
每個模塊目錄下新建js目錄存放當前模塊需要引用的js文件,例如/module/comment/js/comment.js
為簡化開發不使用struts,直接使用jsp代替struts;每個模塊下新建action.jsp替代structs接受
ext ajax請求,action.jsp不負責頁面的顯示。只負責service層方法調用及請求跳轉。
c)權限部分
根目錄下直接建一個security目錄完事。
2)基本布局及權限
border布局,center區域使用TabPanel組建增加新的iframe窗口裝載系統不同模塊。
暫不在意iframe的效率問題,盡可能做到每個系統模塊+UI部分的獨立。
初始化布局時TabPanel組件中添加默認的歡迎登錄頁面,解決TabPanel組件添加新窗口時高度增加的bug。
權限系統設計參考spring security建議的數據庫設計,項目后期可與spring security整合。
3)用戶訪問超時
解決兩種情況下的用戶訪問超時。
a)普通http請求的session超時。
b)異步http請求的session超時,使用ext后大部分的界面刷新都是異步的ajax請求。
不管是那種類型的http請求總是可以由一個過濾器來捕捉。
分類:普通http請求的header參數中沒有x-requested-with:XMLHttpRequest頭信息,而異步的有。
其實對于常見的ajax框架,header中還有標示自己身份的header信息。
對于普通的http請求,發現session超時后直接重定向到一個超時頁面,顯示訪問超時。
對于異步http請求,發現session超時后則向請求的response中寫入特定的超時頭信息,客戶端ajax對象檢測
頭信息,發現有超時狀態標志后調用顯示超時信息的javascript方法,提示用戶訪問超時。
服務器端session超時后在過濾器中為response添加新的頭信息,標記該請求超時:
- if(r.getHeader("x-requested-with")!=null
- && r.getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest")){
- response.setHeader("sessionstatus","timeout");
- }
if(r.getHeader("x-requested-with")!=null
&& r.getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest")){
response.setHeader("sessionstatus","timeout");
}
使用Ext.Ajaxt對象完成異步請求的交互,Ext.Ajax是單實例對象(非常重要,全局單一Ext.Ajax實例!)。
注冊Ext.Ajax的requestcomplete事件,每個ajax請求成功后首先響應該事件。在該事件的回調函數里面判斷
訪問請求是否超時。使用Ext.Ajax對象的好處是,只需要引入一個包含了幾行超時處理代碼的js文件,就可以
為當前應用增加超時處理功能,原有代碼不需要做任何修改。
使用Ext.Ajaxt對象完成異步請求交互,假如checkUserSessionStatus是你的回調方法,每個頁面引用:
- Ext.Ajax.on('requestcomplete',checkUserSessionStatus, this);
- function checkUserSessionStatus(conn,response,options){
-
- if(typeof response.getResponseHeader.sessionstatus != 'undefined'){
-
- }
- }
Ext.Ajax.on('requestcomplete',checkUserSessionStatus, this);
function checkUserSessionStatus(conn,response,options){
//Ext重新封裝了response對象
if(typeof response.getResponseHeader.sessionstatus != 'undefined'){
//發現請求超時,退出處理代碼...
}
}
可以利用的幾個特性:
a)所有的ajax請求均帶有x-requested-with:XMLHttpRequest頭信息
b)Ext.Ajax是單實例對象(非常重要,全局單一Ext.Ajax實例!)
c)注冊Ext.Ajax的requestcomplete事件,每個ajax請求成功后首先響應該事件(概念類似spring的aop攔截)。
對于其他的ajax框架,解決用戶訪問請求超時這個問題的思路是類似的。
在這里推薦一個很實用的Js方法:
- function getRootWin(){
- var win = window;
- while (win != win.parent){
- win = win.parent;
- }
- return win;
- }
function getRootWin(){
var win = window;
while (win != win.parent){
win = win.parent;
}
return win;
}
通過該方法,可以在一個任意深度的iframe中調用父iframe中的方法。具體到這里就是無論哪一個iframe中的用戶訪
問請求超時,都可以通過該方法調用最外層iframe中的退出方法,這樣便為用戶提供了一個統一的訪問超時退出的UI
呈現。
4)系統異常處理
將實際業務代碼中的各種異常封裝成IOException, ServletException異常,指定過濾器捕獲。其余處理思路同
用戶訪問超時處理。
5)添加jquery支持
使用jquery順手的且希望在Ext項目中同時使用某些jquery插件的時候,添加jquery支持。
頁面head中直接添加:
- <link rel="stylesheet" type="text/css" href="/js/ext/resources/css/ext-all.css" />
-
- <script type="text/javascript" src="/js/ext/adapter/jquery/jquery.js"></script>
- <script type="text/javascript" src="/js/jquery.cookie.js"></script>
- <script type="text/javascript" src="/js/ext/adapter/jquery/ext-jquery-adapter.js"></script>
-
- <script type="text/javascript" src="/js/ext/ext-base.js"></script>
- <script type="text/javascript" src="/js/ext/ext-all.js"></script>
- <script type="text/javascript" src="/js/ext/ext-lang-zh_CN.js"></script>
<link rel="stylesheet" type="text/css" href="/js/ext/resources/css/ext-all.css" />
<script type="text/javascript" src="/js/ext/adapter/jquery/jquery.js"></script>
<script type="text/javascript" src="/js/jquery.cookie.js"></script>
<script type="text/javascript" src="/js/ext/adapter/jquery/ext-jquery-adapter.js"></script>
<script type="text/javascript" src="/js/ext/ext-base.js"></script>
<script type="text/javascript" src="/js/ext/ext-all.js"></script>
<script type="text/javascript" src="/js/ext/ext-lang-zh_CN.js"></script>
6)修改布局
常見的布局一般是:header,center,footer,以及一個位于頁面左側的tree menu。其實對于Ext的UI實現來說,
去掉header,footer也不錯,因為Ext的UI本來就做得挺好看再加上去掉header及footer后可以為center增加不
少可視區面積,一個頁面還可以顯示更多的內容。
應該可以支持這兩種布局方式的切換,交給用戶選擇。
試了幾次,在border布局初始化完畢之后再想去掉header,footer區域好像比較麻煩,ext的官方論壇上也說設
計border布局的本意就是應付靜態呈現。
但是好像已經有javaeye上的同志實現了動態的border布局呵呵。可以參考一下 EXT2的動態BorderLayout組件 。
7)更換主題
去ext的官網上下載各種主題皮膚 Themes for Ext 2.0
主題皮膚文件拷貝至本地/js/ext/plugins/theme/css/,/js/ext/plugins/theme/images/ 目錄
最好將用戶選擇的主題配置保存在cookie中,這樣用戶每次登陸都可以使用相同的界面主題。
Ext主題切換:
- if($.cookie('ext.theme') != null && $.cookie('ext.theme') != 'default'){
- Ext.util.CSS.swapStyleSheet("theme","/js/ext/plugins/theme/css/"+$.cookie('ext.theme'));
- }
if($.cookie('ext.theme') != null && $.cookie('ext.theme') != 'default'){
Ext.util.CSS.swapStyleSheet("theme","/js/ext/plugins/theme/css/"+$.cookie('ext.theme'));
}
8)添加自定義的toolbar圖標
直接參考javaeye上的這邊文章 共享一些Ext的圖標 即可,作者提供的圖標很好看,使用也非常簡單。
9)生成Excel文檔
最先參考的資料是extjs論壇上面的這篇文章:GridPanel directly to Excel.
作者思路不錯,就是利用javascript直接讀取GridPanel的store數據,然后生成一個描述excel文檔的xml數據,最后
再通過一個包含了該xml數據的"data" URL下載該excel。
該方法的好處是通用性比較強,生成的excel文檔也不難看,并且是不需要服務器端參與處理的一種純客戶端解決方案。
但是最大的缺點是目前IE7不支持(This needs a browser that supports data URLs. FF, Opera and IE8 will support this.)。
而后發現dojochina網站上的一個用戶整理和修改了這個生成excel文檔的實現方法。
引用
以下的幾個問題我都已經整理和修改:
1、沒有考慮到含有序號和選擇框的grid,
2、utf8轉換bug.
3、寬度的bug
4、不支持ie6、ie7和Safari
原文地址:官方Grid導出到Excel修正版 (作者給出的代碼有些小問題,需要略微進行些調整)
如果是IE瀏覽器,客戶端將以multipart/form-data方式向服務器端提交該xml數據。
原文給出了后臺由php實現時的exportexcel.php代碼。
如果后臺由java實現,exportexcel.jsp
- <%@page import="java.util.Date"%>
- <%@page import="org.apache.commons.lang.time.DateFormatUtils"%>
- <%@page import="com.oreilly.servlet.multipart.*"%>
- <%
- response.setContentType("application/vnd.ms-excel");
- response.setHeader("Content-disposition","attachment;filename="+
- (DateFormatUtils.format(new Date(),"yyyyMMddHHmmss"))+".xls" );
-
- MultipartParser parse = new MultipartParser(request,1000000000);
- Part part = null;
- int maxcount = 0;
- ParamPart param = null;
-
- while(true){
- part = parse.readNextPart();
- if(part == null || maxcount>1000)
- break;
- if(part.isParam() && part.getName().equalsIgnoreCase("exportContent")){
- param = (ParamPart)part;
- break;
- }
- maxcount++;
- }
-
- if(param!=null){
- response.getWriter().println(param.getStringValue());
- }else{
- ;
- }
- %>
<%@page import="java.util.Date"%>
<%@page import="org.apache.commons.lang.time.DateFormatUtils"%>
<%@page import="com.oreilly.servlet.multipart.*"%>
<%
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-disposition","attachment;filename="+
(DateFormatUtils.format(new Date(),"yyyyMMddHHmmss"))+".xls" );
MultipartParser parse = new MultipartParser(request,1000000000);
Part part = null;
int maxcount = 0;
ParamPart param = null;
while(true){
part = parse.readNextPart();
if(part == null || maxcount>1000)
break;
if(part.isParam() && part.getName().equalsIgnoreCase("exportContent")){
param = (ParamPart)part;
break;
}
maxcount++;
}
if(param!=null){
response.getWriter().println(param.getStringValue());
}else{
;
}
%>
這里使用 com.oreilly.servlet 解析multipart/form-data類型數據。com.oreilly.servlet 很適合文件,表單混合提
交、多文件上傳的數據解析。
10)js文件管理
凡是這種基于javascript的富客戶端解決方案一大問題就是js文件太多。每個頁面不僅要導入Ext的css,js文件,
還要導入每個頁面應用需要的一些js文件,這樣管理起來很麻煩。
原來的情況,至少要導入:
- <link rel="stylesheet" type="text/css" href="/js/ext/resources/css/ext-all.css" />
-
- <script type="text/javascript" src="/js/ext/adapter/jquery/jquery.js"></script>
- <script type="text/javascript" src="/js/jquery.cookie.js"></script>
- <script type="text/javascript" src="/js/ext/adapter/jquery/ext-jquery-adapter.js"></script>
-
- <script type="text/javascript" src="/js/ext/ext-base.js"></script>
- <script type="text/javascript" src="/js/ext/ext-all.js"></script>
- <script type="text/javascript" src="/js/ext/ext-lang-zh_CN.js"></script>
- <script type="text/javascript" src="/js/extajax.js"></script>
- <script type="text/javascript" src="/js/exttheme.js"></script>
<link rel="stylesheet" type="text/css" href="/js/ext/resources/css/ext-all.css" />
<script type="text/javascript" src="/js/ext/adapter/jquery/jquery.js"></script>
<script type="text/javascript" src="/js/jquery.cookie.js"></script>
<script type="text/javascript" src="/js/ext/adapter/jquery/ext-jquery-adapter.js"></script>
<script type="text/javascript" src="/js/ext/ext-base.js"></script>
<script type="text/javascript" src="/js/ext/ext-all.js"></script>
<script type="text/javascript" src="/js/ext/ext-lang-zh_CN.js"></script>
<script type="text/javascript" src="/js/extajax.js"></script>
<script type="text/javascript" src="/js/exttheme.js"></script>
推薦使用 JSLoader 管理眾多的js,css文件
1,編寫一個js文件統一管理支持所有公用css,js文件的動態導入
-
- JSLoader.loadJavaScript("/js/ext/adapter/jquery/jquery.js");
- JSLoader.loadJavaScript("/js/jquery.cookie.js");
- JSLoader.loadJavaScript("/js/ext/adapter/jquery/ext-jquery-adapter.js");
-
- JSLoader.loadStyleSheet("/js/ext/resources/css/ext-all.css");
- JSLoader.loadJavaScript("/js/ext/ext-base.js");
- JSLoader.loadJavaScript("/js/ext/ext-all.js");
- JSLoader.loadJavaScript("/js/ext/ext-lang-zh_CN.js");
-
- JSLoader.loadStyleSheet("/js/ext/plugins/icon/css/ext-extend.css");
-
- JSLoader.loadJavaScript("/js/extajax.js");
-
- JSLoader.loadJavaScript("/js/exttheme.js");
-
- JSLoader.loadJavaScript("/js/ext.excel.js");
//添加jquery支持
JSLoader.loadJavaScript("/js/ext/adapter/jquery/jquery.js");
JSLoader.loadJavaScript("/js/jquery.cookie.js");
JSLoader.loadJavaScript("/js/ext/adapter/jquery/ext-jquery-adapter.js");
//Ext支持
JSLoader.loadStyleSheet("/js/ext/resources/css/ext-all.css");
JSLoader.loadJavaScript("/js/ext/ext-base.js");
JSLoader.loadJavaScript("/js/ext/ext-all.js");
JSLoader.loadJavaScript("/js/ext/ext-lang-zh_CN.js");
//加載自定義toolbar圖標css樣式
JSLoader.loadStyleSheet("/js/ext/plugins/icon/css/ext-extend.css");
//加載用戶超時,異常處理
JSLoader.loadJavaScript("/js/extajax.js");
//主題管理
JSLoader.loadJavaScript("/js/exttheme.js");
//Excel導出支持
JSLoader.loadJavaScript("/js/ext.excel.js");
2,每個頁面只需要引入:
- <script type="text/javascript" src="/js/jsloader.js"></script>
- <script type="text/javascript" src="/js/assets.js"></script>
http://www.javaeye.com/topic/320633