在开发报表中经常用到图型报表,很苦恼每开发一个报表就得写一个xml图形配置,和数据请求结果集处理方法。结合前段时间的开发经历,今天和大家分享一下,ruby调用fusionchart的接口封装。
先看一下需求原型:《实现首页的多种粒度、多种图形的展现》如图:
技术分析:
接口的实现采用rest的设计原理,结合数据库做持久化配置,统一封装了图表展示需求。即不管请求什么类型的图型报表展示,统一由一个方法处理图型类别判断、和图型结果渲染。达到了只用一个XML文件、一个后台请求方法,实现所有类型图例请求的目标。
对fushionchart在ruby中的渲染需要如下几样东西。
1、数据结果集。2、XLM渲染脚本。
一:首先分析一下数据结果集的封装
创建一个数据库表,部分字段如下:(举例:AC图表的4个粒度的图型配置。)
area_gran time_gran action_title chart_style_id chart_atrributes chart_sql parent
地域粒度 时间力度 连接名称 图表类型 图表属性 图表数据集 父节点
province day province_day_ac 1 该图表的配置属性 SQL脚本
province month province_month_ac 1 --- ---
city day city_day_ac 1 --- ---
city month city_month_ac 1 --- ---
现在假设有一个名称为AC的柱状图的图表需要展示:
由于该图表有省天、省月、地市天、地市月等粒度的切换需求所以,设置了地域粒度(area_gran)、时间粒度(time_gran)字段。
action_title:为方法请求响应名称。由“区域力度+时间力度+请求标识”组成。
chart_style_id:用于关联chart_styles图型类别定义表,该表对所有fusionchart图类及相关属性做了定义。
chart_atrributes:为该图表实例,定义的属性配置。(实例化了chart_styles的具体参数数值)
chart_sql:为图表的数据结果集获取SQL脚本。
parent:此字段的设置是为了结果集的公用,即当两图表在同一个sql中能查处所有两表结果集的话,子表图直接采用父表的结果进行渲染。
(此外还有chart_x(主轴),chart_sx(附轴),chart_row(X轴)等字段来定义渲染的列对象。)
准备好数据库配置信息后,页面请求数据结果集就变的很简单了。
1、页面调用AC图列展示请求代码:
<%freed_report_chart("ac",params[:area_gran],params[:time_gran])%>
注释:freed_report_chart是封装的一个方法,包含三个参数,请求标识(随便取一个标识名称、每一个需求取唯一的名称即可)、当前区域粒度、当前时间粒度。
freed_report_chart代码如下:
def freed_report_chart(kpi_style,area_gran,time_gran)
@user_analyses=instance_variable_get("@#{area_gran}_#{time_gran}_#{kpi_style}")
@column=instance_variable_get("@#{area_gran}_#{time_gran}_#{kpi_style}_column")
if @user_analyses.nil?||@user_analyses.empty?
concat "<p>没有数据!</p></div>"
else
con_name="con_"+kpi_style+"_"+area_gran
str_xml = render("first_pages/builder/user_data.builder")
str_xml=CGI.unescapeHTML(str_xml)
render_chart '/FusionCharts/'+@column.chart_style_name,'',str_xml,con_name, 590, 280, false, false do
end
end
end
注释:
@user_analyses为获取的整体数据结果集。
@column为对应定义的图形属性实例对象。
render("first_pages/builder/user_data.builder")为XML渲染模版请求@column和@user_analyses共同对次文件渲染。
@column.chart_style_name为图表类型swf类型文件请求名称(例如2D饼图的时候源文件路径为/FusionCharts/Pie2D.swf)。
con_name为将次chart图渲染值某个DIV的自定义id名称。
2、控制层代码分析:
def area_gran_check
@area_gran=params[:area_gran]
@kpi_style=params[:kpi_style]
@time_gran=params[:time_gran]
combin_name(@kpi_style,@time_gran,@area_gran)
send(@find_combin_name)
end
def combin_name(kpi_style,time_gran,area_gran)
@find_combin_name="#{area_gran}#{time_gran}#{kpi_style}"
end
注释:
combin_name(@kpi_style,@time_gran,@area_gran)用于拼接请求的图例方法。
send(@find_combin_name)为动态请求拼接出来的方法。(比如请求:province_day_ac、province_day_other)。*:other即代表任何需求标签别名。
3、模型层代码分析:
def method_missing(method_name, *args)
@method_name=method_name
@report_source=FreedReport::UltraCompanyChart.find(:first,:conditions=>"action_title='#{@method_name}'")
if @report_source
excute_page_sql(@report_source)
else
super
end
end
注释:页面通过请求province_day_ac在控制层转发了此方法请求到模型层。咱们看到,代码里没有实际的定义province_day_ac、province_day_other这么些方法。按理请求一个没有定义的方法是要报404错误了。这里运用了ruby元编程的动态相应method_missing方法。当所有没有定义的方法请求的时候都会走这个过滤方法,
@method_name对应获取所请求的方法名称,@report_source则通过这个名称巧妙的去刚才定义的数据库表中查找对应action_title字段为该方法的数据库记录。
当然如果查找数据库中,没有定义有该方法的时候会有super发挥404错误页面了,相反,模型层会继续调用excute_page_sql(@report_source)方法来渲染请求的结果集。
def excute_page_sql(exc_object)
@chart_ult_freed_reports=[]
@cullent_attributes=@dbh.execute(content_params(exc_object.chart_sql))
#获取报表展示字段
@columns=@cullent_attributes.column_names
@cullent_attributes.each do |report|
b={}
report.each_with_index do |a , x|
b[@columns[x]]=a.to_s
end
#组装结果集
@chart_ult_freed_reports<<b
end
#图表对象
instance_variable_set("@#{exc_object.action_title}_column", exc_object)
#图表数据源
instance_variable_set("@#{exc_object.action_title}",@chart_ult_freed_reports)
end
注释:def excute_page_sql方法通过method_missing中查找传过来的@report_source对象,获取其中的SQL脚本调用数据库连接执行sql脚本获取数据集结果存放到
instance_variable_set("@#{exc_object.action_title}",@chart_ult_freed_reports)
中供前台响应渲染。其他相印的属性则存放在
instance_variable_set("@#{exc_object.action_title}_column", exc_object)中供xml渲染调用。
数据渲染小结:
我们看到采用rest的设计理念,即你只管请求,我匹配处理,有则回调,无则异常。总共不过50~100行的代码量已经将前台请求到数据封装处理逐一实现了。
不同图型请求,不同图例需求的请求,最终都放到了数据库的直接配置请求中。没有了繁琐的粒度判断,类型判断。
二:XLM渲染脚本封装
由于需求中多次用到图型XML渲染、经过分析,不同图形的XML渲染脚本其实是大同小异的。
XML渲染脚本根据图型的类别需求大致分为如下几样属性:
1:整体图形属性、即图形标题、背景色等的属性参数配置。
2:主轴、附轴的数据获取。
3:X轴列值的获取(其中饼图、只有X轴的列值,不需要柱状图、曲线图一类的主轴、附轴数据集)
我们还记得,页面请求的时候有一个XML渲染文件的调用render("first_pages/builder/user_data.builder")
这个文件通过分别获取后台返回的对象集,分别进行渲染,分别得出所请求的图例。
@user_analyses为获取的整体数据结果集。
@column为对应定义的图形属性实例对象。
XML代码分析:
require "builder"
require "fusioncharts_helper"
xml = Builder::XmlMarkup.new
xml.chart(to_chart_hash(@column.chart_attributes))do
#此部分为X轴列值渲染
if @column.chart_row&&@column.chart_row!=""
xml.categories do
for item in @user_analyses
xml.category(:name=>item["#{@column.chart_row}"])
end
end
end
#注释:此部分为主轴数据渲染
if @column.chart_x&&@column.chart_x!=""
if @column.chart_category=="pie_chart"
#注释:饼图渲染
for columnall in @column.chart_x.split(",")
column=columnall.split("|")
xml.set(:name=>"#{column[0]}" , :value=>@user_analyses[0][column[0]],:color=>"#{column[1]}")
end
else
#注释:柱状图、曲线图类数据渲染
for columnall in @column.chart_x.split(",")
column=columnall.split("|")
xml.dataset(:seriesName=>column[0]) do
for item in @user_analyses
xml.set(:value=>item[column[0]],:color=>"#{column[1]}")
end
end
end
end
end
#注释:此部分为附轴数据渲染
if @column.chart_xs&&@column.chart_xs!=""
for columnall in @column.chart_xs.split(",")
column=columnall.split("|")
xml.dataset(:seriesName=>column[0],:parentYAxis=>"S",:color=>"#{column[1]}") do
for item in @user_analyses
xml.set(:value=>item[column[0]],:color=>"#{column[1]}")
end
end
end
end
end
结尾:基于数据库持久化的图表请求到此结束。目前的需求处理实现了:通过前置配置数据库内容即可定制图表报表的展现,初步实现了预期的效果。如果你也喜欢欢迎交流哇。源码分享请移步:
https://github.com/schooltop/freed_report
分享到:
相关推荐
这个 gem 是用于测量gem 的 Rails 集成。 它提供了 ActiveRecord 适配器,用于保存和检索测量值及其单位和模型验证。 用法 活动记录 列应具有_valueand_unit后缀,并且是DECIMALand VARCHAR,并且接受默认值。支持...
控制器是MVC架构中的C,它连接模型和视图,处理用户输入,调用模型进行业务逻辑处理,并将结果传递给视图进行展示。 3. **ActionView**:视图部分用于生成HTML输出,显示给用户。Rails提供了一套强大的模板系统,...
安装过程中,遵循提示进行,确保选择自定义安装并勾选Rails相关的插件,以便在Aptana中获得对Rails的全面支持。 安装完成后,打开Aptana Studio,创建一个新的Rails项目。在“File”菜单中选择“New”然后点击...
在Rails开发中,为了增强用户体验,常常需要使用JavaScript来处理日期选择和...通过合理地配置和调用,我们可以创建出符合Rails最佳实践的日期选择体验。同时,要注意保持前端代码的整洁和模块化,以便于维护和扩展。
在Rails项目中安装Mongrel通常通过RubyGems进行,这是一个Ruby的包管理器。首先确保RubyGems已经安装,然后在命令行执行以下命令: ```bash gem install mongrel ``` 安装完成后,可以通过`mongrel_rails`命令来...
4. **ActiveRecord**:这是Rails中的ORM(对象关系映射)库,它允许开发者用Ruby代码操作数据库,无需编写SQL。 5. **Scaffolding**:Rails的快速开发工具,能自动生成CRUD(创建、读取、更新、删除)操作的模型、...
这个Rails项目提供了学习和研究Web开发的机会,特别是对于Ruby on Rails新手,可以通过阅读和理解源代码来提升技能,了解实际应用中Rails的用法。同时,对于有经验的开发者,这个项目也可以作为一个起点,进行二次...
- 如何在Rails中实现RESTful接口。 - **案例分析**: - 分析一个典型的RESTful应用示例。 #### 九、练习作业2-在Group里面发表文章-双层RESTFul - **目标**: - 在Group中添加Post功能。 - **实现过程**: - 创建...
- **控制器(Controller)**:处理用户的请求,并控制应用的流程,它调用模型并将数据发送到视图中。 #### 四、Ruby语言基础 - **面向对象编程(OOP)**:Ruby是一种纯面向对象的语言,所有东西都是对象。 - **迭代器与...
在Ruby on Rails中,开发者可以快速构建功能丰富的动态网站,因为它提供了大量的内置功能和库,如数据库连接、ORM(对象关系映射)系统ActiveRecord、模板引擎ActionView以及路由系统ActionController等。...
- **使用**:在视图文件中通过`<%= render component %>`的方式调用组件。 #### 九、安全性 - **重要性**:确保Web应用的安全对于保护用户数据至关重要。 - **措施**:Rails提供了多种内置的安全特性,如防止跨站...
此外,书中还介绍了一些Rails中的高级概念,如Strong Parameters(强参数),它在Rails 4.0版本中引入,用于解决之前版本中的参数篡改问题,从而帮助开发者安全地处理外部提交的数据。 通过一系列的教学内容,包括...
在Ruby on Rails中,`include`和`extend`是用来引入模块到类或对象中的关键语法,它们可以帮助我们更好地组织和重用代码。这两个关键字的主要区别在于它们如何将模块中的方法添加到目标类或对象。 首先,`include`...
RailsGuides中的"blog"程序是一个典型的入门级示例,旨在帮助初学者理解RoR的工作原理和核心概念。 在Rails中,**模型(Model)** 负责处理数据和业务逻辑,通常与数据库交互。在这个"blog"程序中,可能会有一个`...
rails-assets, 在 Rails 中,资产管理的解决 Rails 资产 Bundler 到 Bower 代理本自述文件涉及项目的开发方面。 访问站点了解如何在你的应用程序中使用 Rails 资产。 插件开发设置git clone git@github.com:tenex/r
2. **Active Record**:这是Rails中的ORM(对象关系映射)库,它允许开发者用Ruby代码操作数据库,无需编写SQL语句。 3. **Action Controller**:负责处理HTTP请求并调用模型来执行业务逻辑,然后将结果传递给视图...
在本文中,我们将深入探讨如何使用Rails敏捷开发技术构建一个购物车系统,特别是在参考《rails敏捷开发第四版》中的示例。Rails 3.2.6是本文的基础框架,它是一个强大的Ruby Web应用程序框架,以其MVC(模型-视图-...
在Rails中,我们通常使用ActiveRecord库来创建模型,通过继承`ApplicationRecord`类并定义属性和关系。 2. **View**:视图负责展示用户界面。Rails提供了ERB(Embedded Ruby)模板,允许在HTML中嵌入Ruby代码,实现...
在Rails项目中,我们首先需要了解的是项目的目录结构。一个标准的Rails应用会包含以下关键部分: 1. **app**:应用程序的核心,包括模型(models)、视图(views)和控制器(controllers)。模型负责业务逻辑和数据...