1,关于flex4
很老的技术,我居然还再研究使用这个东西,自己想想都不敢相信。
技术存在总是有他的理由的。之所以想用flex4 开发一个通用统计系统,还是有几个有点的:
a,组件比较全,比较全,基本上省去了自己开发
b,在局域网下一次获取大量json数据并解析展示到flex里面速度比html快,图标效果比较好
c,开发系统一个人就够了,浏览器兼容比较好,只要安装flash就行,尤其要做成产品给xp系统的使用那个IE兼容性痛苦啊
当然也有缺点,技术学习成本不低,属于不流行的没落的技术。
但这个不影响做项目,项目的技术选型要合理,维护成本低,综合考虑,而不是所有的全部用新技术,把自己玩死。
存在就有他的意义,不影响做项目,不影响挣钱。
2,系统设计原理
统计系统,设计的不是解决某一个统计问题,而是做一个统计的展示界面,把统计的sql都做xml配置起来。
系统展示界面展示效果:
其中系统的左侧菜单是menu.xml进行控制的
<?xml version="1.0" encoding="utf-8"?>
<!-- 定义左侧菜单: -->
<menus>
<menu label="用户数据统计">
<menu label="用户注册统计" module="/assets/flex/DataGrid.swf" id="stat-demo"/>
<menu label="用户登陆统计" module="/assets/flex/DataGrid.swf" id="stat-user-reg"/>
</menu>
<menu label="系统设置">
<menu label="菜单管理" module="/assets/flex/DataMenu.swf" />
<menu label="数据管理" module="/assets/flex/DataCRUD.swf" />
</menu>
</menus>
通过配置不同的flash文件可以展示不同的配置显示。
通过扩展module可以扩展展示效果。
stat-user-reg.xml配置,显示查询数据
<?xml version="1.0" encoding="UTF-8"?>
<stats>
<!-- 统计数据xml 按照id进行查找。-->
<stat id="stat-demo-1">
<!-- 展示数据 -->
<list>
<column field="id" text="id"/>
<column field="name" text="注册姓名"/>
<column field="sex" text="注册性别"/>
<column field="city" text="注册城市"/>
<column field="phone" text="注册电话"/>
</list>
<sql><![CDATA[
select id,`name`,sex,city,phone,address,qq,email from stat_demo_01 limit 10
]]></sql>
</stat>
</stats>
显示效果如下:
目前已经完成数据显示。但没有数据查询和分页配置,继续开发。
3,服务端代码
服务端,读取xml中的sql语句和配置,拼接成json数据。
/**
* User: freewebsys.com
*/
@Service("statBaseService")
public class StatBaseServiceImpl implements StatBaseService {
@Autowired
private StatBaseDao statBaseDao;
//读取xml文件返回Document。
private Document xmlReader(String confXml) {
try {
SAXReader reader = new SAXReader();
return reader.read(IOUtils.toInputStream(confXml));
} catch (DocumentException e) {
e.printStackTrace();
return null;
}
}
//主函数,负责循环处理节点。
public String findStat(String confXml) {
Document document = xmlReader(confXml);
System.out.println(document);
List<DefaultElement> list = document.selectNodes("/stats/stat");
for (DefaultElement element : list) {
mergeStatElement(element);
}
return document.asXML();
}
private DefaultElement mergeStatElement(DefaultElement element) {
System.out.println(element);
//处理查询出所有列表显示的元素。
List<DefaultElement> columnList = element.selectNodes("list/column");
//找到查询sql。
Node sqlNode = element.selectSingleNode("sql");
String sql = sqlNode.getText();
//获取数据后将节点删除。在客户端不显示。
element.remove(sqlNode);
System.out.println(sql);
List<Map<String, Object>> list = statBaseDao.findStat(sql, null);
JSONArray jsonArray = new JSONArray();
for (Map<String, Object> tmpData : list) {
JSONObject jsonObject = new JSONObject();
for (DefaultElement column : columnList) {
System.out.println(column);
String columnName = column.attributeValue("field");
Object objValue = tmpData.get(columnName);
jsonObject.put(columnName, objValue);
//将一行数据组织成对象,放到数组里面。
}
jsonArray.add(jsonObject);
}
DefaultElement elementData = new DefaultElement("data");
elementData.add(new DefaultCDATA(jsonArray.toJSONString()));
//增加data字段,保存json数据。
element.add(elementData);
return element;
}
//读取配置文件。
public String readConfFile(String configName) {
String basePath = StatBaseServiceImpl.class.getResource("/")
.toString().replace("file:", "");
try {
return FileUtils.readFileToString(new File(basePath + configName), "utf-8");
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
通过读取xml配置文件,将数据返回
<?xml version="1.0" encoding="UTF-8"?>
<stats>
<!-- 统计数据xml 按照id进行查找。-->
<stat id="stat-demo-1">
<!-- 展示数据 -->
<list>
<column field="id" text="id"/>
<column field="name" text="注册姓名"/>
<column field="sex" text="注册性别"/>
<column field="city" text="注册城市"/>
<column field="phone" text="注册电话"/>
</list>
<data><![CDATA[[{"city":"city_222","id":1,"name":"222","phone":"1222","sex":"1"},
{"city":"city_33","id":2,"name":"33","phone":"233","sex":"0"},
{"city":"city_33","id":3,"name":"33","phone":"333","sex":"1"},
{"city":"city_45","id":4,"name":"45","phone":"445","sex":"0"},
{"city":"city_6","id":5,"name":"6","phone":"56","sex":"1"},
{"city":"city_7","id":6,"name":"7","phone":"67","sex":"0"},
{"city":"city_8","id":7,"name":"8","phone":"78","sex":"1"},
{"city":"city_9","id":8,"name":"9","phone":"89","sex":"0"},
{"city":"city_9","id":9,"name":"9","phone":"99","sex":"1"},
{"city":"city_11","id":10,"name":"11","phone":"1011","sex":"0"}]]]></data></stat>
</stats>
数据包括配置的xml和返回的数据。
4,客户端flex4代码
跟新xml返回的数据,动态生成AdvancedDataGridColumn,并添加到 AdvancedDataGrid里面。
<?xml version="1.0" encoding="utf-8"?>
<mx:Module xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="100%" height="100%" initialize="initApp();">
<fx:Style source="./assets/main.css" />
<fx:Declarations>
<mx:HTTPService id="moduleService" method="GET"
resultFormat="e4x" result="resultHandler();"/>
</fx:Declarations>
<fx:Style>
@namespace s "library://ns.adobe.com/flex/spark";
@namespace mx "library://ns.adobe.com/flex/mx";
mx|Text.headLabelStyle{fontSize:20;fontWeight:bold;}
</fx:Style>
<fx:Script>
<![CDATA[
import mx.collections.*;
import mx.controls.*;
import mx.controls.advancedDataGridClasses.*;
import mx.utils.*;
import spark.components.*;
private function initApp():void{
try {
/* 删除问号前面的所有内容,包括问号。 */
var myPattern:RegExp = /.*\?/;
var url:String = this.loaderInfo.url.toString();
//Alert.show(this.loaderInfo.height+","+this.loaderInfo.width);
dataGridGroup.width = this.loaderInfo.width;
//dataGridGroup.height = this.loaderInfo.height;
url = url.replace(myPattern, "");
/* 创建一个形如name=value字符串数组 */
var params:Array = url.split("&");
/* 输出数组中的参数,找到moduleId,这个参数,其他参数类似。 */
var moduleId:String = "";
for (var key:String in params) {
var value:String = String(params[key]);
if(value.indexOf("moduleId=") >= 0){
moduleId = value.replace("moduleId=","");
break;
}
}
//Alert.show(moduleId);
//设置请求地址获取模块参数配置。
moduleService.url = "/stat/module/data.do?moduleId="+moduleId;
moduleService.send();
} catch (e:Error) {
trace(e);
}
/* 显示loaderInfo的一些有用的信息 */
trace("AS version: " + this.loaderInfo.actionScriptVersion);
//trace("App height: " + this.loaderIno.height);
//trace("App width: " + this.loaderInffo.width);
trace("App bytes: " + this.loaderInfo.bytesTotal);
}
private function genWhere(dataXml:XML):HGroup{
var hgroup:HGroup = new HGroup();
//保证居中和左对齐。
hgroup.verticalAlign="middle"
hgroup.horizontalAlign = "left";
//Alert.show(dataXml.where.column);
for each(var objWhere:Object in dataXml.where.column){
var field:String = objWhere.@field;
var text:String = objWhere.@text;
var inputLabel:spark.components.Label = new spark.components.Label();
inputLabel.text = text;
hgroup.addElement(inputLabel);
var input:spark.components.TextInput = new spark.components.TextInput();
input.id = field;
hgroup.addElement(input);
var sp:Spacer = new Spacer();
sp.width = 10;
hgroup.addElement(sp);
}
//如果存在where数据则增加查询按钮。
if(dataXml.where.column.length() > 0){
var search:spark.components.Button = new spark.components.Button();
search.label = "查询";
hgroup.addElement(search);
}
return hgroup;
}
//动态生成 AdvancedDataGrid 数据表单.
private function genAdvancedDataGrid(dataXml:XML):AdvancedDataGrid{
//Alert.show(menuList.source.columns.column);
//Alert.show(menuList.source.data);
//格式化json数据。将数据转换成数组。放到DataGrid里面。
var tmpArray:Array = (JSON.parse(dataXml.data) as Array);
//Alert.show(array.length());
var dataArray:ArrayCollection = new ArrayCollection(tmpArray);
//#######################设置列表显示顶部标题.
var columnArray:Array = new Array();
for each(var objColumn:Object in dataXml.list.column){
var dataField:String = objColumn.@field;
var headerText:String = objColumn.@text;
var width:String = objColumn.@width;
//设置DataGridColun标题,和显示属性。
var adColumn:AdvancedDataGridColumn = new AdvancedDataGridColumn(dataField);
adColumn.headerText = headerText;
if(width){
adColumn.width = Number(width);
}
columnArray.push(adColumn);
}
//adg1.columns();
//adg1.columnCount();
//adg1.columns(columnArray);
var adg:AdvancedDataGrid = new AdvancedDataGrid();
adg.id = "adg-"+id;
adg.dataProvider = dataArray;
adg.columns = columnArray;
adg.rowCount = tmpArray.length + 1;
return adg;
}
//请求数据成功之后处理动态生成表格。
private function resultHandler():void{
for each(var obj:Object in moduleService.lastResult.stat){
var dataXml:XML = obj as XML;
//获得模板id,标题.
var id:String = dataXml.@id;
var title:String = dataXml.@title;
//设置
var vgroup:VGroup = new VGroup();
//设置内边距15。
vgroup.paddingTop = 15;
vgroup.paddingLeft = 15;
vgroup.paddingRight = 15;
vgroup.paddingBottom = 15;
//设置标题。
var titleText:Text = new Text();
titleText.text = title;
titleText.styleName = "headLabelStyle";
vgroup.addElement(titleText);
var hgroup:HGroup = genWhere(dataXml);
vgroup.addElement(hgroup);
//生成高级表格。
var adg:AdvancedDataGrid = genAdvancedDataGrid(dataXml);
vgroup.addElement(adg);
dataGridGroup.addElement(vgroup);
}
}
]]>
</fx:Script>
<!-- 设置如果超过高度滚动. -->
<s:VGroup id="dataGridGroup" height="100%"/>
</mx:Module>
5,后续&代码
这只是最简单的应用,功能还需要完善。
代码已经放到github上面了。 https://github.com/freewebsys/flex4-stat
工程需要使用flahs builder 打开。