四、EXTJS应用举例
序:在开发电信报表时,局方提出这样的需求,形式化描述为:在web前台展示电信的数据A,由工作人员输入相应其它运营上的数据B,然后,根据既定的计算公式,生成所需数据C,最后,生成xls格式报表。因为之前我们已经完成了xls报表的生成与展示,所以,我们所面临的问题就是如何完成web前台电信数据的展示、相应运营商数据的输入及传输到后台产生最终的报表,为此,我在此的示例程序是Extjs的EditGrid。
1、下载Extjs
其下载地址http://extjs.com/download,目前最新版本为2.0.2.
2、搭建使用extjs环境
搭建方式有多种,可以根据你的需求,登陆http://extjs.com/download/build ,在线定制自己的需求,为方便记,你也不妨采用我下面的方式,搭建一个简易的测试环境:
图 4
如上图4,创建一个web工程extjsApp,将我们下载的ext-2.0.2.zip解压缩后,把其整个内容拷贝到WebRoot/extjs目录下,部署该工程,启动tomcat服务,我们便可以访问该工程下的examples示例及docs文档,如下图5、6:
图 5
图 6
当我们输入http://localhost:10000/extjsApp/extjs/examples/grid/totals.html,便可以得到下图7所示的示例程序:
图 7
该程序将是我们的研究对象,它涉及到三个文件:
totals.js、totals.html及GroupSummary.js,其中,GroupSummary.js主要是完成数据汇总,显示在图7每个分组的最后一行,它定义了一个继承于Ext.util.Observable类的子类Ext.grid.GroupSummary,在该类中,我们目前仅需关注它的Ext.grid.GroupSummary.Calculations方法的应用就够了,totals.js完成图7页面数据的静态加载,当我们改变Estimate、Rate时,相应的统计值会发生变化。
但是,上面的示例程序尚不能完全满足我们的需求,我们还要为其加入如下功能:1、加入button,提交参数到server之后展示数据;2、数据应从server端动态获取;3、能够获取展示的grid数据并传送到server端。为此,我们需要做如下几个工作:
A. 改写totals.js
A. 改写totals.js
Ext.onReady(function(){
//定义函数变量datesubmitfunc,为button点击做相应准备
var datesubmitfunc = function() {
//改写默认的背景图片,否则Ext会到http://www.extjs.com获取该图片
Ext.BLANK_IMAGE_URL = '/extjsApp/extjs/resources/images/default/s.gif';
Ext.QuickTips.init();
// Ext.get('btnsubmitdate').on('click',function(){alert('click me~~')});
var xg = Ext.grid;
/*
var reader = new Ext.data.JsonReader({
idProperty:'taskId', //idProperty:'taskId' 可以更换为 id:'taskId'
fields: [
{name: 'projectId', type: 'int'},
{name: 'project', type: 'string'},
{name: 'taskId', type: 'int'},
{name: 'description', type: 'string'},
{name: 'estimate', type: 'float'},
{name: 'rate', type: 'float'},
{name: 'cost', type: 'float'},
{name: 'due', type: 'date', dateFormat:'m/d/Y'}
]
});
*/
/*
以下是替换上面的代码的 var reader = new Ext.data.JsonReader -twolf
*/
var contentNode = new Ext.data.Record.create([
{name: 'projectId', type: 'int'},
{name: 'project', type: 'string'},
{name: 'taskId', type: 'int'},
{name: 'description', type: 'string'},
{name: 'estimate', type: 'float'},
{name: 'rate', type: 'float'},
{name: 'cost', type: 'float'},
{name: 'due', type: 'date', dateFormat:'m/d/Y'}
]);
var reader = new Ext.data.JsonReader({root:'data',id:'taskId'},contentNode);
/*
替换结束-twolf
*/
// define a custom summary function,so u can do sth. for yourself’s requirements like this
Ext.grid.GroupSummary.Calculations['totalCost'] = function(v, record, field){
return v + (record.data.estimate * record.data.rate);
}
var summary = new Ext.grid.GroupSummary();
//定义变量获取totals.html输入框id标记为date的值,测试client数据传输到server
var params = Ext.get('date').getValue(false);
/*
定义按钮及其点击事件处理
*/
var btntest = new Ext.Button({
id: 'btn-one',
text: 'bnt4test',
handler: function(){alert('test')}
});
var btn = new Ext.Button({
id:'_btn',
text:'btn'
});
btn.on('click',function(){
//alert(myGrid.getStore().getCount());
//获取grid中数据,编写成json格式,然后上传到server
var upInfo='[';
var dataStore = myGrid.getStore();
var record;
for(var i=0;i<dataStore.getCount();i++) {
record = dataStore.getAt(i);
upInfo = upInfo + '{estimate:' + record.get('estimate') + ',rate:' + record.get('rate') + '},';
}
upInfo = upInfo.substring(0,upInfo.length-1) + ']';
alert(upInfo);
//利用Ajax技术,将我们的upInfo信息传递到server,以备后台程序处理
Ext.Ajax.request({
url:'/extjsApp/updata',
params:{upInfo:upInfo},
success:function(response,options){
alert('success!');
}
});
});
var myGrid = new xg.EditorGridPanel({
//ds 即为 store
ds: new Ext.data.GroupingStore({
autoLoad: true,
loadMask:{msg:'Loading ...'},
reader: reader,
//修改data来源,要求来自server端
//data: xg.dummyData,
proxy: new Ext.data.HttpProxy(
new Ext.data.Connection(
{
extraParams:{test:params,suc:'suc'},
url:'/extjsApp/getdata'
}
)
),
//url:'/extjsApp/getdata?test=test',这种形式可以替代上面的proxy,因为它可以自动帮我们创建一个HttpProxy
sortInfo:{field: 'due', direction: "ASC"},
groupField:'project'
}),
/*
以下的summaryType、summaryRenderer工作都是由GroupSummary.js完成
*/
columns: [
{
id: 'description',
header: "Task",
width: 80,
sortable: true,
dataIndex: 'description',
summaryType: 'count',
hideable: false,
summaryRenderer: function(v, params, data){
return ((v === 0 || v > 1) ? '(' + v +' Tasks)' : '(1 Task)');
},
editor: new Ext.form.TextField({
allowBlank: false
})
},{
header: "Project",
width: 20,
sortable: true,
dataIndex: 'project'
},{
header: "Due Date",
width: 25,
sortable: true,
dataIndex: 'due',
summaryType:'max',
renderer: Ext.util.Format.dateRenderer('m/d/Y'),
editor: new Ext.form.DateField({
format: 'm/d/Y'
})
},{
header: "Estimate",
width: 20,
sortable: true,
dataIndex: 'estimate',
summaryType:'sum',
renderer : function(v){
return v +' hours';
},
editor: new Ext.form.NumberField({
allowBlank: false,
allowNegative: false,
style: 'text-align:left'
})
},{
header: "Rate",
width: 20,
sortable: true,
renderer: Ext.util.Format.usMoney,
dataIndex: 'rate',
summaryType:'average',
editor: new Ext.form.NumberField({
allowBlank: false,
allowNegative: false,
style: 'text-align:left'
})
},{
id: 'cost',
header: "Cost",
width: 20,
sortable: false,
groupable: false,
renderer: function(v, params, record){
return Ext.util.Format.usMoney(record.data.estimate * record.data.rate);
},
dataIndex: 'cost',
summaryType:'totalCost',
summaryRenderer: Ext.util.Format.usMoney
}
],
buttons: [btntest,btn],
view: new Ext.grid.GroupingView({
forceFit:true,
showGroupName: false,
enableNoGroups:false, // REQUIRED!
hideGroupedColumn: true
}),
plugins: summary,
frame:true,
width: 800,
height: 450,
clicksToEdit: 1,
collapsible: true,
animCollapse: false,
trackMouseOver: false,
//enableColumnMove: false,
title: 'Sponsored Projects',
iconCls: 'icon-grid',
renderTo: document.body
});
};
Ext.get('btnsubmitdate').on('click',datesubmitfunc);
//获取totals.html中id为btnsubmitdate的button对象并添加click点击事件
});
B、在上面A中,我们用到了两个请求:url:'/extjsApp/getdata'从server获取数据和url:'/extjsApp/updata'传送数据到server端,为此,我们添加以下内容到web.xml配置文件中:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<servlet>
<servlet-name>getdata</servlet-name>
<servlet-class>twolf.dataserv.GetData</servlet-class>
</servlet>
<servlet>
<servlet-name>updata</servlet-name>
<servlet-class>twolf.dataserv.Updata</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>getdata</servlet-name>
<url-pattern>/getdata</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>updata</servlet-name>
<url-pattern>/updata</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
C、 定义上面B用到的两个测试类
package twolf.dataserv;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class GetData extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// TODO Auto-generated method stub
//super.doGet(req, resp);
resp.setContentType("application/x-json;charset=utf-8");
PrintWriter out = resp.getWriter();
System.out.println("param:"+req.getParameter("test"));
String info = "{data:["
+ "{projectId: 100, project: 'Ext Forms: Field Anchoring', taskId: 112, description: 'Integrate 2.0 Forms with 2.0 Layouts', estimate: 6, rate: 150,cost:101, due:'06/24/2007'}"
+","
+"{projectId: 100, project: 'Ext Forms: Field Anchoring', taskId: 113, description: 'Implement AnchorLayout', estimate: 4, rate: 150,cost:102, due:'06/25/2007'}"
+","
+"{projectId: 102, project: 'Ext Grid: Summary Rows X', taskId: 111, description: 'Testing and debugging', estimate: 8, rate: 125,cost:103, due:'07/15/2007'}"
+"]}";
out.println(info);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// TODO Auto-generated method stub
//super.doPost(req, resp);
doGet(req,resp);
}
}
.................................................................
package twolf.dataserv;
import java.io.IOException;
import java.util.Iterator;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
public class Updata extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// TODO Auto-generated method stub
//super.doGet(req, resp);
String upInfo = req.getParameter("upInfo");
System.out.println(upInfo);
JSONArray jsonArr = JSONArray.fromObject(upInfo);
JSONObject jsonObj;
Iterator<Object> itr = jsonArr.iterator();
while(itr.hasNext()) {
jsonObj = JSONObject.fromObject(itr.next());
System.out.println(jsonObj);
}
System.out.println("...........................");
for(Object obj : jsonArr){
jsonObj = JSONObject.fromObject(obj);
System.out.println(jsonObj);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// TODO Auto-generated method stub
//super.doPost(req, resp);
doGet(req,resp);
}
}
至此,我们重新部署一下,就可以运行它了,效果如下:
启动
提交
点击btn
操作后client、server数据往来信息
到此为止,改造后的EditGrid理论上已经可以满足我们的需求了。
你是否已经注意到这样两个问题:1、类Updata使用了json对象;2、用到了firefox的javascript调试工具firebug...