Spring3+Hibernate4+SpringMVC整合Ext:開發Ext界面
前言
Spring3+Hibernate4+SpringMVC整合Ext:項目架構搭建中已經介紹了Spring3、Hibernate4和SpringMVC的整合,下面介紹的是開發一個典型的Ext后臺管理界面:
開發這個界面使用了Ext MVC,好多人都叫我用MVC方法去實現,其實MVC不是每個場景都適合。就我現在這個界面的場景而言并不適合用MVC開發,本來一個js文件就可以處理硬生生的分成了好幾個文件,效果不是很好。代碼是通過MVC實現的,MVC具體怎么樣用大家可以去參考下官方的例子,在這里就不在贅述。下面的代碼通過mvc的方式進行分層展示:
前臺界面
頁面
<%@ page language="java" pageEncoding="UTF-8"%> <% String extLibPath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+"/ext4"; String ctx = request.getContextPath(); pageContext.setAttribute("extLibPath", extLibPath); pageContext.setAttribute("ctx", ctx); %> <html> <head> <title>業務基礎平臺</title> </head> <body> <div id="loading-tip" style="border-radius:3px;position: absolute;z-index: 1;border: solid 1px #ccc;background-color: #fff;padding: 10px;"> <div class="loading-indicator" style="color: #444;font: bold 13px tahoma, arial, helvetica;padding: 10px;height: auto;"> <img src="${ctx}/images/loading32.gif" width="31" height="31" style="margin-right: 8px; float: left; vertical-align: top;" /> 業務基礎平臺V1.0 <br /> <span id="loading-msg" style="font: normal 10px arial, tahoma, sans-serif;">加載樣式和圖片...</span> </div> </div> <script type="text/javascript"> var extLibPath = "${extLibPath}"; var ctx = "${ctx}"; var tip = document.getElementById("loading-tip"); tip.style.top = (document.body.scrollHeight - tip.style.top - 100) / 2; tip.style.left = (document.body.scrollWidth - 200) / 2; </script> <link rel="stylesheet" type="text/css" href="${extLibPath}/resources/css/ext-all.css" /> <link rel="stylesheet" type="text/css" href="icon.css" /> <script type="text/javascript"> document.getElementById("loading-msg").innerHTML = "加載核心組件..."; </script> <script type="text/javascript" src="${extLibPath}/ext-all-debug.js"></script> <script type="text/javascript" src="${extLibPath}/locale/ext-lang-zh_CN.js"></script> <script type="text/javascript" src="app.js"></script> </body> </html>這個是index.jsp頁面,整個界面的代碼就在app.js里面:
Ext.Loader.setConfig({ enabled : true }); Ext.Loader.setPath({ 'Ext.ux' : extLibPath + '/examples/ux', 'Ext.app' : extLibPath + '/examples/app', 'Fes' : 'module' }); Ext.require(['Fes.MsgBox']); Ext.Ajax.on('requestexception', function(conn, response, options) { var msg = '訪問系統資源時發生異常<br/>' + '異常狀態:' + response.status + '(' + response.statusText + ')<br/>' + '異常信息:' + response.responseText Ext.Msg.show({ title : '系統異常', msg : msg, width : 400, icon : Ext.MessageBox.ERROR, buttonText : { ok : ' 提交錯誤報告 ' }, buttons : Ext.MessageBox.OKCANCEL }); }); Ext.get('loading-msg').update('加載系統組件...'); Ext.create('Fes.desktop.Desktop');在app.js的文件中主要是做了一些全局的配置,配置了ext的動態加載和ajax訪問時異常的處理,最后創建“Fes.desktop.Desktop”組件開始初始化界面
控制層
控制層的作用是對界面的行為進行控制、邏輯判斷和事件響應
module/desktop/Desktop.js
Ext.define('Fes.desktop.Desktop', { extend : 'Ext.app.Application', appFolder : 'module/desktop', name : 'Desktop', controllers : ['Desktop'], enableQuickTips : true, autoCreateViewport: true });Fes.desktop.Desktop繼承Ext.app.Application,這個是Ext MVC中規定要繼承的父類。配置了autoCreateViewport為true時Ext會自動創建一個Desktop.view.Viewport的組件,這個規則是appname+view .Viewport。
module/desktop/controller/Desktop.js
Ext.define('Desktop.controller.Desktop', { extend : 'Ext.app.Controller', models : ['Node'], refs : [{ ref : 'navigation', selector : 'navigation' }, { ref : 'container', selector : 'fescontainer' }], init : function() { var me = this; this.control({ 'viewport' : { render : me.onRender }, scope : me }); }, onRender : function() { var me = this; Ext.get('loading-msg').update('正在加載菜單...'); Ext.Ajax.request({ url : 'resource/root',// 獲取面板的地址 method : 'GET', callback : function(options, success, response) { me.createTree(Ext.JSON.decode(response.responseText)); } }); }, createTree : function(datas) { var me = this; Ext.each(datas, function(data) { var tree = Ext.create("Ext.tree.Panel", { title : data.text, iconCls : data.iconCls, useArrows : true, autoScroll : true, rootVisible : false, viewConfig : { loadingText : "正在加載..." }, store : me.createTreeStore(data.id) }); tree.on('itemclick', me.onTreeItemClick, me); me.getNavigation().add(tree); }); Ext.get('loading-msg').update('加載完成.'); Ext.Function.defer(function() { Ext.get('loading-tip').remove(); }, 1000); }, onTreeItemClick : function(view, node) { console.log(node.data.component); var tab = this.getContainer(); if (node.isLeaf()) { // 判斷是否是根節點 if (node.data.type === 'URL') { // 判斷資源類型 var panel = Ext.create('Ext.panel.Panel', { title : node.data.text, closable : true, iconCls : 'icon-activity', html : '<iframe width="100%" height="100%" frameborder="0" src="http://www.baidu.com"></iframe>' }); tab.add(panel); tab.setActiveTab(panel); } else if (node.data.type === 'COMPONENT') { var panel = Ext.create(node.data.component, { title : node.data.text, closable : true, iconCls : 'icon-activity' }); tab.add(panel); tab.setActiveTab(panel); } } }, createTreeStore : function(id) { var me = this; return Ext.create("Ext.data.TreeStore", { defaultRootId : id, // 默認的根節點id model : this.getNodeModel().$className, proxy : { type : 'ajax', // 獲取方式 url : 'resource/child' // 獲取樹節點的地址 }, clearOnLoad : true, nodeParam : 'id'// 設置傳遞給后臺的參數名,值是樹節點的id屬性 }); } });這個是整個界面的控制層,在init的方法中為viewport添加了一個render事件,在整個界面渲染完成后開始加載菜單。在菜單加載完成之后添加菜單的點擊事件。
視圖層
視圖層只頁面的展示,不做任務的邏輯操作和事件處理
module/desktop/view/Viewport.js
Ext.define('Desktop.view.Viewport', { extend : 'Ext.container.Viewport', requires : ['Desktop.view.Container', 'Desktop.view.Header', 'Desktop.view.Navigation'], layout : 'border', initComponent : function() { var me = this; Ext.apply(me, { items : [Ext.create('Desktop.view.Container'), Ext.create('Desktop.view.Header'), Ext.create('Desktop.view.Navigation')] }); this.callParent(arguments); } });
定義Desktop.view.Viewport組件,這個組件會在控制器中被創建。viewport中定義了整個界面的布局,包含了Desktop.view.Container,Desktop.view.HeaderDesktop.view.
Navigation3個組件。
module/desktop/view/Container.js
Ext.define('Desktop.view.Container', { alias: 'widget.fescontainer', extend : 'Ext.tab.Panel', requires : ['Ext.app.Portlet', 'Ext.app.PortalColumn', 'Ext.app.PortalPanel', 'Ext.app.PortalDropZone', 'Ext.ux.TabReorderer','Ext.ux.TabCloseMenu'], activeTab : 0, enableTabScroll : true, animScroll : true, border : true, autoScroll : true, region : 'center', split : true, plugins : [ Ext.create('Ext.ux.TabReorderer'), Ext.create('Ext.ux.TabCloseMenu',{ closeTabText: '關閉面板', closeOthersTabsText: '關閉其他', closeAllTabsText: '關閉所有' }) ], items : [{ iconCls : 'icon-activity', title : '平臺首頁', xtype : 'portalpanel', layout : 'column', items : [{ xtype : 'portalcolumn', columnWidth : 0.7, items : [{ title : '新聞動態', height : 150, iconCls : 'icon-news' }, { title : '最新通知', height : 150, iconCls : 'icon-notice' }, { title : '業績報表', height : 150, iconCls : 'icon-chart' }, { title : '郵件列表', height : 150, iconCls : 'icon-email-list' }] }, { xtype : 'portalcolumn', columnWidth : 0.3, items : [{ title : '功能鏈接', height : 150, iconCls : 'icon-link' }, { title : '待辦事項', height : 150, iconCls : 'icon-note' }, { title : '郵件列表', height : 150, iconCls : 'icon-email-list' }, { title : '郵件列表', height : 150, iconCls : 'icon-email-list' }] }] }] });Desktop.view.Container是一個標簽頁集合的面板,是整個界面的操作區域。
module/desktop/view/Header.js
Ext.define('Desktop.view.Header', { extend : 'Ext.panel.Panel', height : 80, html : '業務基礎平臺', region : 'north', split : true, bbar : [{ iconCls : 'icon-user', text : '管理員' }, '-', { text : Ext.Date.format(new Date(), 'Y年m月d日') }, '->', { text : '退出', iconCls : 'icon-logout' }], bodyStyle : 'backgroud-color:#99bbe8;line-height : 50px;padding-left:20px;' + 'font-size:22px;color:#000000;font-family:黑體;font-weight:bolder;'+ 'background: -webkit-gradient(linear, left top, left bottom, ' + 'color-stop(0%, rgba(153,187, 232, 0.4) ),' + 'color-stop(50%, rgba(153, 187, 232, 0.8) ),' + 'color-stop(0%, rgba(153, 187, 232, 0.4) ) );' , initComponent : function(){ this.callParent(); } });Desktop.view.Header是界面的頭部
module/desktop/view/Navigation.js
Ext.define('Desktop.view.Navigation', { alias: 'widget.navigation', extend : 'Ext.panel.Panel', region : 'west', title : '系統菜單', width : 250, iconCls : "icon-tree", autoScroll : false, layout : 'accordion', collapsible : true, layoutConfig : { animate : true }, id : 'navigation', split : true, initComponent : function(){ this.callParent(); } });Desktop.view.Navigation是界面的導航部分,樹形菜單的展示區域
模型層
模型層主要是定義了前后臺數據交互的模型
module/desktop/model/Node.js
Ext.define('Desktop.model.Node', { extend: 'Ext.data.Model', fields : [{name : "id",type : "string"}, {name : "text",type : "string"}, {name : "iconCls",type : "string"}, {name : "leaf",type : "boolean"}, {name : 'type'}, {name : 'component'}] });Desktop.model.Node定義了菜單數據模型
后臺處理
整個界面的數據交互個入口在module/desktop/controller/Desktop.js文件中的對定義了viewport進行的事件響應:
init : function() { var me = this; this.control({ 'viewport' : { render : me.onRender }, scope : me }); }, onRender : function() { var me = this; Ext.get('loading-msg').update('正在加載菜單...'); Ext.Ajax.request({ url : 'resource/root',// 獲取面板的地址 method : 'GET', callback : function(options, success, response) { me.createTree(Ext.JSON.decode(response.responseText)); } }); }, createTree : function(datas) { var me = this; Ext.each(datas, function(data) { var tree = Ext.create("Ext.tree.Panel", { title : data.text, iconCls : data.iconCls, useArrows : true, autoScroll : true, rootVisible : false, viewConfig : { loadingText : "正在加載..." }, store : me.createTreeStore(data.id) }); tree.on('itemclick', me.onTreeItemClick, me); me.getNavigation().add(tree); }); Ext.get('loading-msg').update('加載完成.'); Ext.Function.defer(function() { Ext.get('loading-tip').remove(); }, 1000); },在viewport渲染完成后發送到resource/root請求獲取菜單的根目錄,后臺java代碼:
ResourceController.java
package com.avicit.fes.system.resource.controller; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import com.avicit.fes.system.resource.service.ResourceService; import com.avicit.fes.system.resource.vo.ResourceNode; @Controller @RequestMapping("/resource") public class ResourceController { @Autowired private ResourceService resourceService; @RequestMapping(value="root",method=RequestMethod.GET) public @ResponseBody List<ResourceNode> root() throws Exception{ return this.resourceService.getRoot(); } @RequestMapping(value="child",method=RequestMethod.GET) public @ResponseBody List<ResourceNode> child(@RequestParam("id") Integer id) throws Exception{ return this.resourceService.getChildren(id); } }在ResourceController類中定義了root方法攔截resource/root請求,在resourceService中獲取菜單的根目錄發送到頁面中,下面看ResourceServiceImpl中的代碼:
package com.avicit.fes.system.resource.service.impl; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.avicit.fes.system.resource.dao.ResourceDAO; import com.avicit.fes.system.resource.entity.Resource; import com.avicit.fes.system.resource.service.ResourceService; import com.avicit.fes.system.resource.vo.ResourceNode; import com.avicit.framework.util.ListUtils; @Service("resourceService") public class ResourceServiceImpl implements ResourceService { protected Log logger = LogFactory.getLog(this.getClass()); @Autowired protected ResourceDAO<Resource, Integer> resourceDAO; @Override public List<ResourceNode> getRoot() throws Exception { return ListUtils.transform(this.resourceDAO.getRootResource(),ResourceNode.class); } public List<ResourceNode> getChildren(Integer id) throws Exception{ return ListUtils.transform(this.resourceDAO.getChildrenByParent(id),ResourceNode.class); } }在ResourceServiceImpl類中getRoot方法中從后臺數據庫中獲取到跟目錄的數據返回給ResourceController,這樣就完成了數據的交互。
在獲取根目錄之后創建樹組件,并通過父節點獲取子節點,從而完成了界面菜單的交互。
來自:http://blog.csdn.net/leecho571/article/details/8043264
本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!