Skyform-Cmp项目ui
本文对sf-ui框架的背景、需求说明和实现的思路进行简单描述,供开发人员进行参考。相关人员可以参考本文档使用该框架或进行二次开发。
sf-ui框架最初是为项目skyform-cmp编写的UI框架,只负责页面展现部分,所有数据操作都交由后台进行。随着后期开发过程中地不断完善,这个框架由定制开发演变成了通用开发,稍作修改后即可应用于多个项目。
skyform-cmp项目中模块具有高度相似性,因此这里抽象出模块的共性进行说明。模块的功能点分为查询、创建、删除、详情展示四部分。模块中大部分是资源模块,还有一部分是告警和日志模块,每个模块独有的操作这里不再赘述。
2.1.1. 创建
创建是每个资源开始的第一步。创建成功之后,才可以在列表展示和详情展示中看到相关信息,实现资源信息的查询、删除等功能。创建结束后,如果成功,则将新资源展示在列表中,如果失败,则在右上角给出提示,说明错误原因。值得一提的是,创建成功并不代表该资源可用,还需要关注资源的可用状态或连接状态,默认资源的可用状态是可用状态,资源的大部分操作都要在可用状态下进行。
2.1.2. 删除
删除某个资源时,要求资源的状态满足一定的要求。例如删除虚拟机时要求虚拟机的状态是停止方可,非停止状态的虚拟机选中后,“更多操作”下拉框中的“删除”项将不会显示。删除之前,要求用户在弹出框中确认方可执行删除操作。
2.1.3. 查询
查询模块信息,支持模糊查询、精确查询和分页查询,可同时实现多条件查询,并由统一界面实现。
2.1.4. 详情展示
模块的详情包括模块的详细信息、日志操作等。虚拟机详情中还包括虚拟机的监控信息展示,由granafa提供。granafa允许对存储在不同地方的数据进行查询、可视化和监控起变化等,提供了一种数据驱动文化。这里采用granafa可以简化监控展示的开发,设置号展示参数然后嵌套即可。
2.2. 资源监控
包含逻辑视图和业务视图两类监控。
逻辑视图中包含了资源按逻辑划分的逐级监控情况,从上到下依次为:资源池、区域、集群、主机、虚拟机。资源池、区域、集群选中时展示该资源池或所属资源池的资源使用情况、告警情况,主机选中时展示该主机中的资源使用情况,虚拟机选中时展示虚拟机的详细信息、网卡信息、监控信息(granafa提供)。
业务视图中包含了资源按业务划分的逐级监控情况,从上到下依次为:资源池、业务、虚拟机。资源池选中时显示如逻辑视图中的资源池监控情况,业务选中时展示业务的基本信息和资源统计情况,虚拟机选中时展示如逻辑视图中的虚拟机监控情况。
sf-ui与外部系统的交互如下图所示:
核心交互过程:
1. sf-ui通过cas进行单点登录。
2. sf-ui通过nginx进行负载均衡的配置,进而同各个api服务进行数据交互。
3. sf-ui通过浏览器调用与granafa进行交互。
3.1.1. 与cas服务的交互
为保证多系统间用户认证的统一,引入了cas实现单点登录。cas服务配置在web.xml中,如下(请注意参看注释):
<!--========================单点登录开始 ======================== -->
<!-- 用于单点退出,该过滤器用于实现单点登出功能,可选配置-->
<listener>
<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
</listener>
<filter>
<filter-name>singleSignOutFilter</filter-name>
<filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>singleSignOutFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>CASFilter</filter-name>
<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
<init-param>
<param-name>casServerLoginUrl</param-name>
<!-- 根据真实地址填写,cas服务的登录地址 -->
<param-value>http:// cas服务的登录地址/cas/login</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<!--根据真实地址填写,sf-ui的访问地址-->
<param-value>http:// sf-ui的访问地址</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CASFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 该过滤器负责对Ticket的校验工作,必须启用它 -->
<filter>
<filter-name>CASValidation Filter</filter-name>
<filter-class>
org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class>
<init-param>
<param-name>casServerUrlPrefix</param-name>
<!-- 根据真实地址填写,cas服务地址 -->
<param-value>http:// cas服务地址/cas</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<!-- 根据真实地址填写,sf-ui服务地址 -->
<param-value>http:// sf-ui服务地址</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CASValidation Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--
该过滤器负责实现HttpServletRequest请求的包裹,比如允许开发者通过HttpServletRequest的getRemoteUser()方法获得SSO登录用户的登录名,可选配置。
-->
<filter>
<filter-name>CASHttpServletRequest Wrapper Filter</filter-name>
<filter-class>
org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CASHttpServletRequest Wrapper Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--
该过滤器使得开发者可以通过org.jasig.cas.client.util.AssertionHolder来获取用户的登录名。比如AssertionHolder.getAssertion().getPrincipal().getName()。
-->
<filter>
<filter-name>CASAssertion Thread Local Filter</filter-name>
<filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CASAssertion Thread Local Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- ========================单点登录结束======================== -->
<!-- 获取登录用户servletbegin -->
<servlet>
<servlet-name>getUserInfo</servlet-name>
<servlet-class>com.skycloud.cas.SkyCasClient</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>getUserInfo</servlet-name>
<url-pattern>/getUserInfo</url-pattern>
</servlet-mapping>
<!-- 获取登录用户servlet end-->
3.1.2. 与api服务的交互
api服务包含cmdb、zconf、system、zvm、vol、network、alarm、granafa、aggregate等服务,随着业务的变更,服务个数和内容也会随之改变。每个服务各司其职,除了granafa服务外,sf-ui通过Restful API与这些服务进行交互。下面以sf-ui的自定义模块虚拟机调用api模块zvm服务为例,讲述sf-ui与api服务的交互。
1、 封装ajax调用过程,对请求的发送和接收做统一处理。
编写apiZstack服务,服务中对请求发送时所需的参数和header设置做统一处理,封装get和post两种类型的请求方法,具体请参见js/api.js文件。
2、 在虚拟机模块的页面中将需要调用的api接口进行封装,方便反复调用。
app.service('vmService',vmService);
function vmService(apiZstack,$cookieStore, SERVICE_CONFIG, commonService) {
var self= this;
//获取模块的名称
self.ModuleName=SERVICE_CONFIG.module_vm.name;
//获取模块中所需后台api服务的访问地址
var VMServiceURL= SERVICE_CONFIG.vmServiceURL;
//配置模块所需接口的名称
self.ResourceCMD= {
'vm_create' : VMServiceURL+ '/CreateVmInstance',
'vm_delete' : VMServiceURL+ '/DestroyVmInstance'
//省略N行
};
//模块实际需要调用的function
self.vm_create= function(params){
return apiZstack.send(self.ResourceCMD.vm_create,params);
};
self.vm_delete= function(params){
return apiZstack.send(self.ResourceCMD.vm_delete,params);
};
//省略N行
}
3、 调用。
在实际使用中,只需要引入vmService服务,然后调用服务中对应的function即可,如下所示,调用删除虚拟机的接口:
vmService.vm_delete({"uuid": deletingItemUuid}).then(function(response){
if(response.status||response.errorCode==0){
//返回结果显示为“成功”后的操作
} else{
//返回结果显示为“失败”后的操作
}
});
}, function () {
$log.info('Modal dismissed at: '+ newDate());
});
其中,源码仅在开发中使用。对应的项目文件结构及说明如下:
其中组件提供者指的是引入使用某个组件时所需要的全部文件的集合。
源码文件仅在开发过程中使用,开发完成后由gulp编译压缩后生成新文件并在index.html中引用生效。
4. 实现设计HLD
4.1. 整体设计
4.1.1. 技术选型
运行容器:ApacheTomcat
框架:Angular JS1.3.2
类库:jQuery、Bootstrap
第三方组件库:echarts、highcharts等
后台转发/负载均衡:nginx。
4.2. 使用说明
4.2.1. 启动说明
sf-ui是一个静态web项目,它依赖cas进行用户信息管理、依赖后台api提供数据,因此在启动sf-ui之前需要保证cas和后台api能正常使用。cas和后台api的配置及启动不在本文档的说明范围内,这里不再赘述。
为了实现动静分离,方便管理后台相关信息的配置,这里使用了config.js配置对应路径、nginx进行转发的方法。首先,在config.js文件中配置后台api的路径,如下所示:
var app =
angular.module('app')
.constant('SERVICE_CONFIG', {
queryFrequency: 2000, //毫秒
zconfServiceURL :'/services/zconf',
systemServiceURL : '/services/sys',
cmdbServiceURL : '/services/cmdb',
vmServiceURL : '/services/zvm',
vmConsoleServiceURL : '/vm',
volumeServiceURL :'/services/zvol',
networkServiceURL : '/services/znet',
aggregateServiceURL :'/services/agrg'
//省略n行
})
这里将路径统一在了常量SERVICECONFIG中,方便后续开发中调用。然后,修改nginx.conf文件实现nginx转发。注意,转发路径要和config.js中的路径名称一致,同时分配好nginx和tomcat的监听端口(这里nginx的监听端口为8080,tomat的监听端口为8088)。
后台api调用路径和nginx转发配置完成后,将sf-ui中静态文件和对应的lib包放到tomcat中,启动tomcat后首先看到的是cas登录页面,登录后即可看到skyform-cmp的ui界面,如下图所示:
4.2.2. 编码说明
由于项目采用了Angular JS 1.3.2作为框架,并引入了jQuery、Bootstrap等类库,因此首先将第三方的文件引入文件夹vendor中,作为组件提供者集合,后续开发中需要新加的组件也放到vendor文件夹中,注意各个版本之间的兼容性。
编码主要分为了三大部分:样式、通用指令服务等和展示页面,下面将对它们的编码分别讲述。
1、 样式
文件夹css中存放了需要引入启动文件index.html的样式文件,包括bootstrap.min.css、animate.css、font-awesome.min.css等第三方文件和自定义样式文件app.min.css。样式的资源文件分别位于fonts和img文件夹中。
自定义样式文件app.min.css的源码文件位于sources/style文件夹中,以less进行编写,通过gulp编译压缩后生成。源码中将页面元素拆开进行样式的编写,包含app.buttons.less、app.nav.less、app.widgets.less等,同时统一了页面颜色(app.colors.less)和变量(app.variable.less),方便进行样式的统一调整,减轻了美工人员调整页面的工作量。
2、 通用指令服务等
整个项目中大量使用了grid、breadcrumb等,且查询、资源状态等拥有统一的展现形式,因此将这些通用部分编写成合适的指令或服务,方便页面调用和代码管理。
第三方指令通过gulp压缩生成了directives.min.js,组件ui.grid在页面大量使用,因此将它写了一个单独的指令sfUiGrid存放在sf-ui-grid.js文件中,其余指令或过滤器较小,放在了sf-console.js文件中,包括状态指令sfState、面包屑指令sfBreadcrumb、验证ip地址格式指令checkIpFormat、资源类型过滤器resourceTypeFilter等等。指令编写完成后需要在index.html中引用以生效。
3、 展示页面
展示页面部分包含了如header、footer、nav等通用页面和自定义模块页面两大部分。前者位于tpl文件夹中,这里不再详述,依要求完成即可。后者位于views文件夹中,每个模块自成一个子文件夹,方便管理,里面包含了模块的页面、逻辑、路由等。
4.2.3. 自定义模块的添加流程
这里以主机Host为例进行说明,该模块包含的功能有:grid列表(包括前端分页、排序)、多条件查询、新建主机、删除、选中列表中某一个主机进入该主机的详情页面。
考虑到自定义模块的相似性,这里编写了一个自动代码生成项目,以减少重复编码工作、减轻开发压力。自动代码生成使用了Apache的项目Velocity,它是一个基于java编写的模板引擎,使用十分方便。自动代码生成的页面包含了grid列表(包括前端分页、排序)、多条件查询、新建(仅包含名称和描述)、删除、详情页面。如果有后续功能需要修改和补充的,不在自动生成里,请自行修改代码实现。下面讲述自动生成的实现过程。
首先下载代码自动生成项目,修改src/java/cn/sw/generate/service/VelocityService.java其中的自定义模块部分,配置自定义模块的代码、中文描述、路由中的路径、弹出框对象、自定义模块的数据模型、生成文件的路径等,配置完成后,执行该文件中的main函数即可看到output文件夹中生成了新的自定义模块的初始文件,如下图所示:
文件host.html、host.js、host.service.js、host_create.html、host_detail.html直接拷贝到sf-ui项目的views/host文件夹下,文件host_other.js需要做一写处理。以下是host_other.js文件的内容及修改说明:
启动sf-ui项目,访问app.resources.host所指的路径即可看到主机页面。
结束语
至此skyform-cmp项目的ui框架的介绍和使用已说明完毕,有任何问题可以联系我们公司的技术邮箱skyform_support@chinaskycloud.com,以后机会继续和大家进行分享。