基于SaaS的高校财财务数据分析系统设计与实现-项目笔记(一)

 

基于SaaS的高校财财务数据分析系统设计与实现-项目笔记(一)

1第一周

1.1 问题一之开发工具版本冲突

 

问题描述:在搭建开发环境的时候,JDK使用的是JDK1.8高版本的JDK,SpringSources Tools Suite(以下简称STS)使用的是3.0版本,Virgo_Tomcat_Service使用的是3.5版本,启动STS配置好环境变量以及Maven本地仓库后,启动新建的测试项目报错,错误如下:

错误名称

                            详细信息

           版本冲突

The type java.lang.CharSequence cannot be resolved. It is indirectly referenced from required .class files

 

1.2 解决方案

 

该问题是由于STS自带的JDK版本和本机安装的JDK以及Virgo_Tomcat_Service的JDK冲突所致,本机安装的JDK版本过高,高版本的JDK中的一些新特性在低版本的STS中无法解析导致出错。因此,将本机的1.80版本的JDK替换为1.6.0.4版本的JDK,该问题得到解决。

 

1.3问题二之Hibernate原生态SQL查询异常

 

问题描述:在使用Hibernate的原生态SQL对MySQL和Oracle进行查询的时候,对于非关联表进行查询的时候程序没有任何的异常,但是对于关联表的查询,碰到查询char类型的时候始终返回时一个字符,一开始判断是在web端传入的参数有问题,类型转换出错,但是经过反复的调试,排除了这个可能。最后问题的定位还是在Hibernate上,经过单独的实验发现,这个问题主要是Hibernate在查询Mysql数据库的时候,自动将char映射成为character(varchard的子集)类型。

 

1.4改造方案

 

方法一:在程序中将要查询的数据进行封装转换成一个实体Bean,这样就可以解决此问题。

方法二:使用Hibernate中的addScalar(String arg,Type type)来自定义返回的字段类型。

方法三:修改数据关联表的相应字段,把char修改为varchar,当数据库中的表很多时,第三种方法不建议使用。方法二简单方便,因此选择第二种方案进行代码的改造。

备注:(VARCHAR是一种比CHAR更加灵活的数据类型,同样用于表示字符数据,但是VARCHAR可以保存可变长度的字符串。其中M代表该数据类型所允许保存的字符串的最大长度,只要长度小于该最大值的字符串都可以被保存在该数据类型中。因此,对于那些难以估计确切长度的数据对象来说,使用VARCHAR数据类型更加明智。VARCHAR数据类型所支持的最大长度也是255个字符。

 

2第二周

2.1 问题一之工作流建模

 

工作流是一个管理系统必不可少的一部分,工作流能够提高企业的办公效率,更好的引导职工完成相应的工作。现在成熟的工作流第三方框架比较多,但是都是重量级的框架,所以本次的项目自行开发自定义的工作流,在对需求进行分析和数据库建模完成后,接下来的难题是工作流建模,需要用户自定义的把一个流程定义完成,手工向数据库添工作项的各项数据容易造成数据出错,所以需要提供一个UI界面给使用者。

 

2.2 解决方案之Java Swing 开发流程建模工具

 

(1) 处理的节点有:开始节点、结束节点、连接线、同步活动、手工活动。

(2) 处理的事件有:确认、取消、驳回、取回、转办、通过。

(3) 约定:开始节点和结束节点都只能在一次流程中出现一次。

(4) 数据处理:当用户完成流程图的绘制之后、后台自动生成每个工作项的ID(唯一标识),并将得到的数据拼成合乎SQL规范的SQL语句,使用JDBC的数据源对象向数据库写入获取的值、同时更新流程Model表。

 

2.3 问题二之工作流用户同步问题

 

问题描述:该工作流不涉及到权限,在读取每一个工作项对应的用户时,无法区分该用户是否具有操作该工作项的权限。

 

2.4 解决方案 同步管理云用户

 

在登陆该建模工具时,不去读取用户界面,将工作流整合到管理云的时候,将管理云(以下简称平台)中的用户同步到工作流当中。平台中的用户已经有了自己的组织机构和相应的权限,当用户登陆平台的时候,自动将平台中的用户信息通过HTTP请求的方式同步到工作流当中,届时在检查用户的相应权限。因此,在工作流模块中不去读取模块中的用户表,将相应的表字段设为空串(“”)。

 

 

 

 

 

 

3第三周

3.1 问题一之流程建模工作项的前置节点和后置节点设置问题

 

问题描述:在定义流程时,当定义流程中的某一个节点时,由于此时的连接线还没有定义,所以无法获取到该节点的前置节点(FromId)和后置节点(toId),造成了向数据库写入数据时前置节点和后置节点为空。

 

3.2 解决方法之先定义后设置

 

先定义流程中的节点,把定义完成的节点保存在一个临时的Map中,在画连接线的时候,在设置每一个节点的前置节点和后置节点。具体方法是如图:

 

 

除开始节点没有前置节点和结束节点没有后置节点之外,其他的节点都有自己的前置节点和后置节点。

 

3.3 问题二之平台多个模块之间相互交互和通信问题

 

问题描述:基于SaaS模式的系统,往往会整合多个模块,涉及到的功能模块比较多,由此带来的问题就是多个数据库同时访问,多个web模块同时工作。如何切换多个数据源是一个比较困难的问题,还有各个模块之间如何通信。

 

3.4 问题解决之OSGI

 

OSGI框架为Java定义了一个动态的模块化系统,通过使用OSGI,在项目开发中能够较好的控制代码结构,动态的管理代码的生命周期,并且提供了代码协作的松耦合方式。OSGI规范中定义的三个概念层设计:

(1)模块层:关注于打包与代码共享。

(2)生命周期层:关注提供执行时模块管理和对底层OSGI框架的访问。

(3)服务层:关注于模块,特别是模块内的组件间的交互和通信。

将不同的功能模块化,每个模块,在OSGI中将这种模块化的概念称之为Bundle。Bundle是一个包含元数据(关于数据的数据)的JAR文件,由类文件和相关资源文件组成。在服务层中,定义了该bundle所引用的服务和发布的服务。这正好解决了本项目中模块之间相互交互和通信的问题。

 

 

4 第四周

4.1 问题一之系统成熟度模型的选择

 

在开始项目之前,应该分析系统应该采用什么样的成熟度模型,简而言之就是系统应该达到什么样的级别才能符合项目的需求,不能盲目的求高求新。需要对用户的规模进行分析。

 

4.2 解决方案

 

通过查阅相关文档和书籍以及本系统的需求,需要实现如下的几个性能指标:

(1)实现多租户(Multi-Tenant)架构,Multi-Tenant架构师SaaS应用的基本特性;也是实现SaaS规模效应的基本要素。

(2)实现模块的可配置,能够根据用户的需求,进行模块的配置,提高用户的体验。

(3)实现多租户下的高性能,优化系统性能(相比传统的软件模式)提升用户体验以及系统用户规模/容量比。

综合以上的三个要素,所以决定采用SaaS模式下的第三级成熟度模型来设计系统的架构,系统的架构图如下所示

 

 

 

 

 

 

 

 a

 

 

 

 

 

 

 

 

 

 

 

 

4.3 问题二之平台数据库建模

问题描述:在进行数据库建模的时候,涉及到的问题是不同租户之间的数据如何隔离,如何保障用户数据的的安全性。如何区分不同用户的来源,如何实现用户的可配置。

 

4.4 解决方案之建立索引表

 

为用户建立一张用于检索的关联表Tenant(租户表),该表记录着用户所属的租户,对系统中的共享资源(操作模块,访问请求等)按照租户进行划分,当用户登陆时,首先根据用户信息在Tenant表中进行检索,获取用户可用资源。另外,在进行数据库建模的时候,不进行表与表之间的主外键关联,在进行CRUD操作的时候在依次进行检查。

 

 

 

5 第五周

5.1 问题一之Bundle Project 打包相关问题

 

问题描述:在对编写好的Bundle进行打包的时候,位于META-INF目录下的MANIFEST.MF文件无法被打包,在启动时提示无法找到相应的服务和引用

 

 

  

5.2 解决方案

 

没有找到具体的解决方案,手动把项目中的MANIFEST.MF文件拷贝到打包后的JAR文件相应的目录中去,需要注意的是,打包后的JAR文件不能解压出来,用解压缩软件将JAR文件打开,软后将MANIFEST.MF文件拷贝进去,否则JAR文件将无法使用。

 

 

 

5.3 问题二之STS服务器启动失败

 

问题描述:启动Virgo_Tomcat__Service 后访问页面没有响应,后台不报错,连续刷新页面后系统报错,提示org.eclipse.virgo.kernel.shell 相关类没有找到或者不存在。

 

5.4解决方案之调整模块的启动顺序

 

在整个项目中,模块之间存在相互依赖关系,有先后的顺序,存在依赖的bundle必须等待所依赖的bundle正常启动后才能启动,否则将会找不到所依赖的服务,因此在请求相关的操作时,由于定义服务接口的时候默认返回值为void,所以页面没有任何反应。解决这个问方法是:调整服务器中bundle的启动顺序,被依赖的bundle放在最前面。如图所示:

 

 

 

操作步骤:

 

(1)双击STS的服务器按钮,弹出服务器的配置页面。

(2)找到 ArteFact Deployment Order选项,选中需要调整位置的bundle。

(3)根据需要选择Up或者Dow按钮进行调节。

(4)重新将org.eclipse.virgo.kernel.shell-3.0.2.RELEASE.jar文件放入到服务器的仓库中,重新启动服务器,该问题得以解决。

 

 

 

 

 

 

 

 

 

 

 

6 第六周

 

6.1 问题一之单点登录

 

题描述:平台需要对每个来访用户进行身份验证,只有通过验证的用户才可以进行到系统当中,但是平台中有很多的子系统,没有个子系统都需要对用户的身份进行验证,对于传统的做法,将用户信息保存在Session当中的方式对于多系统集成已经失效,不同的模块对应着不同的域名,所以验证将会失效。

 

6.2 解决方案CAS之的SSO单点登录

 

平台是架构在互联网上的,所以需要提供统一的入口进行用户身份的校验,合法的用户进入系统之后,在不关闭浏览器的情况下,多个模块之间的来回切换,不在需要进行多次的身份验证,验证的工作交由CAS框架来实现,这个步骤对于用户来说是透明的,只有当发现用户身份出现异常的时候才跳转到校验窗口进行验证。

 

6.3 CAS的相关协议和原理

 

CAS 包含两个部分: CAS Server 和 CAS Client。CAS Server 需要独立部署,主要负责对用户的认证工作;CAS Client 负责处理对客户端受保护资源的访问请求,需要登录时,重定向到 CAS Server。如图所示是CAS 最基本的协议过程:

 

CAS Client 与受保护的客户端应用部署在一起,以 Filter 方式保护受保护的资源。对于访问受保护资源的每个 Web 请求,CAS Client 会分析该请求的 Http 请求中是否包含 Service Ticket,如果没有,则说明当前用户尚未登录,于是将请求重定向到指定好的 CAS Server 登录地址,并传递 Service (也就是要访问的目的资源地址),以便登录成功过后转回该地址。

 

6.4相关配置

 

 名称

                相关参数

JDK

          1.6.04

服务器

         apache-tomcat-6.0.14

CAS Client

         cas-server-3.4.2

JAR文件

复制modules下面所有jar文件到cas-server的Web-inf/lib下,添加数据库驱动文件

deployerConfigContext.xml

修改验证方式为数据库验证方式:用户名和密码验证机制

取消HTTPS验证机制

<bean class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler"  p:httpClient-ref="httpClient"  p:requireSecure="false"/>

增加参数p:requireSecure="false",是否需要安全验证,即HTTPS,false为不采用。

server\WEB-INF\spring-configuration\ticketGrantingTicketCookieGenerator.xml文件:

class="org.jasig.cas.web.support.CookieRetrievingCookieGenerator"

p:cookieSecure="false"

p:cookieMaxAge="-1"

p:cookieName="CASTGC"

p:cookiePath="/cas" />

</beans>

 

 

 

注:CAS服务端单独部署在tomcat服务上,修改服务器端口为:8090,Virgo_Tomcat_Service 服务器的端口为8080,修改端口号是为了避免端口冲突,因为两个服务器的默认端口号都是8080端口。 

 

 

 

 

 

 

 

 

 

 

 

 

 

6.5 问题二之 CAS如何校验用户

 

要让CAS在项目中起作用,必须在需要进行用户认证的模块中加入CAS的Filter进行相关的过滤。

 

6.6 解决方案

(1) 配置web.xml文件

 

 

 

 

 

(2) 配置config.properties文件

 

config.properties文件位于Virgo_Tomcat_Service服务器下的config目录下,

 

需要配置的参数有:

(1)login:配置了用户进入单点认证的界面所在路径

(2)Logout:配置用户登陆失败时跳转路径

(3)Validate:配置了用于用户校验的Filter模块所在的路径

(4)Servername: 配置了CAS进行服务器端验证成功时需要跳转时回跳路径,即用户进行验证前所请求的路径。

 

 

 

 

 

 

 

 

 

 

7 第七周

 

7.1 问题一之平台与工作流的用户同步

 

问题描述:平台需要将工作流整合到系统当中,但是工作流有自己的数据库,在启动工作流的时候,首先需要读取用户的信息,但是平台中的用户表和工作流的用户表不在一个数据库中,给同步用户带来了不小的麻烦,另外一个需要考虑的问题就是什么时候同步平台中的用户到工作流中。

 

7.2 解决方案

 

同步平台中的用户信息到工作流中,主要的目的是取得用户的已办信息和待办信息,需要拿到用户的唯一标识USERID,现在有如下的两个方案可以选择:

 

(1)方案一:将平台的用户表中的用户信息同步到工作流中的用户表,需要平台中的用户唯一标识USERID与工作流中的用户唯一标识FLOWUSERID对应,其他的数据信息可以忽略,因为用户的验证,权限等都已经在平台中进行了校验,在同步的过程中,实际只需要同步用户的唯一标识USERID。

(2)方案二:专门创建一张关联表。所有的代办和已办信息的USERID都是关联表中的ID,该方案无疑加大了数据库表的维护难度。

 

经过分析,决定采用第一种方案来同步平台中的用户信息到工作流中,同步用户的时间选择在平台创建用户的时候就把用户同步到工作流当中,这样做的优点是:简单方便,如果平台中的用户添加失败,用户信息也不会同步到工作流中,保证了数据的唯一性。缺点是:在创建平台的用户时,必须开启工作流,否则同步失败。

 

 

7.3 问题二之平台与工作流的整合方式

 

问题描述:工作流是单独开发的web模块,没有按照OSGI的规范来定义,如果将工作流改造成符合OSGI的定义规范,难度很大。因此,需要选择合乎项目需求的整合第三方模块的整合模式。

 

 

7.4 解决方案

 

(1)RMI:远程接口调用,RMI是分布式对象软件包,它简化了在多台计算机上的JAVA应用之间的通信。但是它有一个缺点就是无法穿透防火墙,因此该方案不采用。

(2)Web Service:可以实现不同应用程序和在不同系统平台上开发出来的应用程序之间通信,能够穿透防火墙,虽然Web Service 避免了繁琐的协议转换,但是也暴露了它的自身问题,版本管理起来不是一件容易的事情,所以该方案也不采用。

(3)HTTP协议:使用HTTPCLIENT组件来发送HTTP请求,传递参数,将需要传输的数据拼接成字符串,再通过HTTPCLIENT进行传输。使用HTTPCLIENT需要如下的六个步骤:

    1. 创建 HttpClient 的实例

    2. 创建某种连接方法的实例,在这里是 GetMethod。在 GetMethod 的构造函数中传入待连接的地址

    3. 调用第一步中创建好的实例的 execute 方法来执行第二步中创建好的 method 实例

    4. 读 response

    5. 释放连接。无论执行方法是否成功,都必须释放连接

    6. 对得到后的内容进行处理

 

 第三种方案比较好实施,例如现在需要传递一个用户的信息user{id=11111},条件condition{day>3},扩展参数a{b},请求的路径为URL,那么就可以通过如下的方式传递信息:

URL.do?modelid=11111&data=useris11111##dayis3##aisb,其中,is是传输中的关键字,“##”是作为分隔符传入的。每一个键值对都是用##来分隔,每一个键值对中的键和值都是用is来分隔。

 

在对应的服务中,用如下的代码来获取专递过来的数据:

 

 

 

 

 

 

 

8 第八周

8.1 问题之ExtJs异步请求

 

问题描述:ExtJs在平台的主页面第一次加载时无法跨平台请求,需要额外的刷新才能取到对应的树。

 

8.2 问题解决之封装单独的服务

 

在整个项目中,com.tcserver.system.framework.web(以下简称framework)这个bundle依赖于com.tcserver.system.sys.web(以下简称sys) 这个bundle所提供的获取功能点这个服务,在framework中ExtJs无法异步请求到这个服务,因此在framework中重新封装获取功能点这个服务,通过以上方法的改造,解决了这个问题。

改造前:

 

 

直接请求的是sys中提供的queryFunctionTreeByUser服务。

 

改造后:

 

使用的是framework中封装的queryFunctionTreeByUser服务

 

 

对应的实现代码如下:

 

 

 

 

 

 

 

 

 

8.3 问题二之财务数据管理模块

 

问题描述:对于财务模块,其中的很多功能都需要流程来加以控制,因此就需要工作流,如何建立试用与财务管理的工作流模块是一个难题。

 

8.4 解决方案之重构自定义工作流

 

在这一个模块中,不在单独开发财务工作流,而是在STS上重构服务OSGI规范的财务bundle,利用之前的自定义工作流进行重构,共用自定义工作流中的业务表、工作项表、流程实例表以及待办和已办表,添加一张财务模型表(Finance_Data),用来区分具体的业务流程,从而保留了之前的请假模块的Leave模型。

 

 

 

9 第九周

 

9.1 问题一之页面展示

 

问题描述:ExtJs对于处理系统级别的页面展现无疑是一个较好的选择,但是ExtJs是一个重量级的框架,过多的使用导致的问题就是页面加载慢,格式不好控制,不同浏览器之间存在现实上的差异。

 

9.2 解决方案之ECharts

 

ECharts,缩写来自Enterprise Charts,商业级数据图表,一个纯Javascript的图表库,可以流畅的运行在PC和移动设备上,兼容当前绝大部分浏览器(IE6/7/8/9/10/11,chrome,firefox,Safari等),底层依赖轻量级的Canvas类库ZRender,提供直观,生动,可交互,可高度个性化定制的数据可视化图表。创新的拖拽重计算、数据视图、值域漫游等特性大大增强了用户体验,赋予了用户对数据进行挖掘、整合的能力。

 

支持折线图(区域图)、柱状图(条状图)、散点图(气泡图)、K线图、饼图(环形图)、雷达图(填充雷达图)、和弦图、力导向布局图、地图、仪表盘、漏斗图、事件河流图等12类图表,同时提供标题,详情气泡、图例、值域、数据区域、时间轴、工具箱等7个可交互组件,支持多图表、组件的联动和混搭展现。

 

ECharts是一个轻量级的Js插件,同时能够兼容IE6/7/8低版本的IE浏览器,加载速度比ExtJs快,因此页面的展现使用ECharts插件。

 

ECharts所提供的接口如下图所示: