使用 flex4 开发通用统计系统,发布源代码至github

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 = [email protected];
					var text:String = [email protected];

					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 = [email protected];
					var headerText:String = [email protected];
					var width:String = [email protected];
					//设置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 = [email protected];
					var title:String = [email protected];

					//设置
					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 打开。

时间: 2024-10-12 20:51:54

使用 flex4 开发通用统计系统,发布源代码至github的相关文章

如何开发打点统计系统

最近做了一个打点统计系统,统计系统肯定各个公司都有做过,至于怎么做就不好说了.我见过最多的就是使用php开发一个打点接口,然后在打点接口中做数据点击,这种方法最差的就是每次打点都往数据库中操作,另外一种就是往一个文件中增加数据.对于后一种,我就很奇怪了,你既然php是等于要往日志文件中增加一条记录,那干啥不用web服务器的自身的日志呢?所以我这次就果断使用分析nginx日志的方法来做打点(这个方法也是大多公司统计系统采用的方法吧).至于storm,hadoop啥的,太高大上了.没用 nginx日

Android内核开发:如何统计系统的启动时间

本文是<Android内核开发>系列的第七篇文章,通过上一篇文章<Android内核开发:图解Android系统的启动过程>我们大致了解了Android系统的启动过程,那么本文就从实践的角度,简单介绍一下如何统计Android系统的启动时间. 这里所说的统计系统的启动时间,并不是简单地用秒表和肉眼来统计,而是通过分析系统输出的log信息来统计,这样才显得更加专业. 首先了解2个概念: (1) Android是基于Linux内核的系统,因此Android的启动过程是分为两个阶段的,第

PD003-NET通用后台系统

PD003-NET通用后台系统 开发语言.Net 成品成品 前端技术jquery 数据库sql server .net 通用后台框架 详细信息 基于EF+MVC+Bootstrap构建通用后台管理系统,集成轻量级的缓存模块.日志模块.上传缩略图模块.通用配置及服务调用,提供了OA.CRM.CMS的原型实例,适合快速构建中小型互联网及行业Web系统,也可用来学习. Framework 业务无关的底层通用机制及功能 -Model基类:提供数据传输和底层的最基本的基类及接口 -DAL底层:基于EF c

使用NoSQL实现高并发CRM系统实践(源代码+解析)

又想速度快,又要大数据,又要保证数据不出错,还要拥抱变化,改需求的时候不那么痛苦,特别是字段的调整,按照以前的做法,想想就头疼.使用NoSQL,简直就是随心所欲,再奇葩的数据结构,处理起来也很容易.下面看我如何用NoSQL数据库实现高并发,高可靠的CRM系统. 1.前言 随着facebook.微博等WEB2.0互联网网站的兴起,传统的关系数据库在应付web2.0网站,特别是超大规模和高并发的SNS类型的web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题,而非关系型的数据库则由于其本

【读书笔记-《Android游戏编程之从零开始》】6.Android 游戏开发常用的系统控件(TabHost、ListView)

3.9 TabSpec与TabHost TabHost类官方文档地址:http://developer.android.com/reference/android/widget/TabHost.html Android 实现tab视图有2种方法,一种是在布局页面中定义<tabhost>标签,另一种就是继承tabactivity.但是我比较喜欢第二种方式,应为如果页面比较复杂的话你的XML文件会写得比较庞大,用第二种方式XML页面相对要简洁得多. <?xml version="1

用它来开发“在线Excel”系统,竟如此简单!

最近关注到"知乎"上的一个热门问题:国内有哪些类似 Google Docs 的在线文档编辑软件?大家的回复基本上都是围绕成熟的在线文档编辑软件展开,如石墨文档.腾讯文档.有道云协作等,其中每一款软件都有其最适合的使用场景,有些注重数据存储和数据安全,有些则注重团队管理和文档协作,对于最终用户来说,市面上各类成熟的在线文档编辑软件产品种类繁多,但只有最适合业务需求的那一款才是最好的. 针对不同的业务需求,用户关注的方向也有很大区别: 大型公司更加注重数据安全.协作效率,与原系统文档兼容性

利用JS跨域做一个简单的页面访问统计系统

其实在大部分互联网web产品中,我们通常会用百度统计或者谷歌统计分析系统,通过在程序中引入特定的JS脚本,然后便可以在这些统计系统中看到自己网站页面具体的访问情况.但是有些时候,由于一些特殊情况,我们需要自己来设计统计系统.由于前段时间公司的业务需求,我也是自己尝试了下,本文提供的是一个基本思路,统计系统也比较简单. 几个基本统计需求: 1.统计web每个页面用户访问量 2.统计用户访问者的和IP地址信息 3.页面之间的跳转情况 4.访问高峰时间段 服务器结构: 数据库表设计: 以上只是我简单列

用.NET开发通用Windows App

(此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:随着Windows 10的正式发布,作为.NET开发人员应该开始或多或少了解一下通用(Universal)Windows App的开发了. 所谓Universal Windows App(简称UWP),就是开发一次,可以运行于所有以Windows 10为内核的系统和设备上,包括:桌面设备.移动设备.XBox.HoloLens甚至物联网设备.随着Windows 10在7月29日正式发布,之前没有

开源网站访问统计系统Piwik

http://www.piwik.cn/ http://www.piwik.org/ Piwik 是一套基于 Php+MySQL 技术构建,能够与 Google Analytics 相媲美的开源网站访问统计系统.Piwik 可以给你详细的统计信息,比如网页浏览人数, 访问最多的页面, 搜索引擎关键词等等,并且采用了大量的AJAX/Flash技术,使得在操作上更加便易. Piwik 可以安装在你的服务器上面,数据就保存在你自己的服务器上 面.你可以非常容易的插入统计图表到你的博客或是网站后台的控制