基础开发平台旨在对业务管理系统进行合理的功能分层,将基础的、通用的、公共的系统功能从业务管理系统中解耦分离出来,并提供灵活快速定制业务的辅助工具,通过沉淀积累,形成业务管理系统的基础开发平台,大大提高基础功能的可复用性,方便升级维护,从而保证大型企业级应用的稳定性,提高应用系统的开发效率,实现快速响应用户需求变化。
当前企业级应用的构建主要有两种主流实现技术可以选择,即J2EE和.NET。图1-2中展示了J2EE体系结构为企业级应用提供了一系列技术支持,包括:关系型数据库(JDBC),目录服务(JNDI),邮件服务(JavaMail),远程调用及CORBA(RMI/IIOP),消息队列(JMS),WEB服务(SOAP),分布式技术(EJB)等。J2EE技术的成熟性,开放性及其易移植等特性,是基础平台选择J2EE技术的主要考量因素。
基础开发平台所采用的技术实现架构充分体现了软件分层的思想,按从前到后业务逻辑的实现部件进行横向划分(如图1-3所示),主要由以下几部分组成:
客户端浏览器:负责html静态页面以及jsp和servlet动态响应结果的界面展示,客户端javascript脚本逻辑的执行,与服务器端展示层servlet/jsp部件的交互。
展示层:主要负责对请求进行动态页面的响应(servlet/jsp), 调用后端业务逻辑部件,负责业务逻辑执行结果的展示工作;采用实现MVC模式的第三方框架struts(为实现异常处理机制的统一处理,略作改造),请求经由ActionServlet调用具体业务的Action实现类,Action实现类调用业务层组件执行业务逻辑,根据执行结果返回需要转向的业务视图。表示层的开发工作量比较大,涉及的技术及角色比较多,通过该模式可以明晰结构,适当分工,通过统一入口ActionServlet可以实现一些功能的统一处理。
业务层:主要负责业务逻辑的实现,考虑适应不同应用规模的要求,业务层采用工厂模式,支持本地和远程分布式计算的不同部署方式,本地javabean和ejb本地代理实现相同的业务逻辑接口,表示层的Action实现类通过调用业务对象工厂来创建配置的业务逻辑部件。
数据访问层:负责数据存储介质的访问,包括:关系型数据库,文件系统,LDAP等数据持久化介质。
基础开发平台的功能结构也充分体现了软件分层的思想,将功能层次按支撑关系进行纵向划分(如图1-4所示),主要由以下几部分组成:
JDK: JDK 是Java开发工具包 (Java Development Kit ) 的缩写,是整个Java的核心,包括了Java运行环境,一堆Java工具和Java基础的类库。JDK是一切java应用程序的基础,所有的java应用程序是构建在JDK之上的。JDK位于基础开发平台的最底层,但不划入到基础开发平台的范畴。
第三方技术实现框架: 在开发Java应用时,为了提高开发效率,缩短开发周期,常常需要集成第三方提供的Java软件,如ORM映射工具Hibernate、MVC框架Struts、日志工具Log4J和Web服务软件Apache AXIS等。第三方技术实现框架是基础开发平台的基础,但不划入到基础开发平台范畴。
SUNRISE:基础开发平台提供的工具类,这些工具类是基础的、常用的、与业务和第三方框架无关的一些功能实现,比如字符串处理类,日期处理类,GUID生成器,MD5算法实现等等。与业务无关的工具类属于基础开发平台的范畴。
技术架构基础层:从技术实现角度对业务逻辑的实现架构进行了横向分层,主要分为表示层,业务逻辑层,数据访问层,每一层定义了对应的基类,抽象类和接口,在纯技术层面形成开发的规范,所有上层功能的开发都必须继承并遵循技术架构的规范要求。技术架构基础层属于基础开发平台的范畴。
系统基础功能层: 基础开发平台对构建一个系统的基本组成要素进行了抽象, 定义了包括模块、视图、视图元素、权限项、数据权限因子、数据存取命令等实体概念,通过对这些元素的抽象,平台提供基本元素的配置功能,从底层就大大加强了构建系统的灵活性。系统基础功能层属于基础开发平台的范畴。
业务基础功能层: 基础开发平台对大多数应用系统都需要的基础的通用的业务功能进行了界定和抽取形成业务基础功能层,其中包括组织配置,用户管理,授权与鉴权,日志管理及消息机制等功能。业务基础功能层属于基础开发平台的范畴。
业务支撑功能层: 基础开发平台将能够为应用系统提供灵活定制业务的设计工具及配套引擎作为平台有效的业务支撑层,主要包括表单定制、查询定制、报表以及其他业务系统需要的、但与业务关联性不强的、公共的辅助功能。业务支撑功能层属于基础开发平台的范畴。
业务功能层:在基础开发平台之上则可以构建具体应用领域中的各种功能模块,业务功能层构建在基础开发平台之上,不划入到基础开发平台的范畴。
在系统分层构建思想的指导下, 可以包装企业产品库的功能目录,客户可以根据自己对某一应用系统功能的理解、定位和边界划分,从产品库的功能目录中选择需要的功能以组合成自己需要的业务应用系统。
一般地,根据技术实现架构的分层定义,各功能模块的后台类的目录结构如下所示:
com.sunrise.packageXXXX ——后台类包结构
|----action ——Action类的文件目录
|----bo ——业务对象BO的文件目录
|----dao ——数据存取对象DAO的文件目录
|----vo ——值对象的文件目录
。。。。。。。。。。 ——其他目录
注:
1)基础平台各子项目的后台类将打包成jar库文件的形式提供给各业务项目使用。
2)业务对象BO基于接口实现。
一般地,功能模块的展现类的目录结构如下所示:
WebRoot ——项目表示层
|----jsp ——基础开发平台的jsp文件目录
|----js ——基础开发平台的jsp文件目录
|----css ——基础开发平台的css文件目录
|----images ——基础开发平台的images文件目录
|----common ——基础开发平台的页面框架目录
|---- 项目XXXX ——项目XXXX1的表示层文件目录
|----jsp ——项目XXXX1的jsp文件目录
|----js ——项目XXXX1的js文件目录
|----css ——项目XXXX1的css文件目录
|----images ——项目XXXX1的images文件目录
。。。。。。。。。。 ——其他目录
注:
为了便于升级基础平台的表示层各个组成部分,发布版本时对基础平台的表示层进行整体替换,建议将基础平台和具体项目的表示层组件在物理上要单独分开。上面的目录结构就是出于升级的考虑提出的。在具体项目的表示层开发中,不要将项目的文件放到下述目录中:
/WebRoot/jsp
/WebRoot/js
/WebRoot/css
/WebRoot/images
/WebRoot/common
而是在WebRoot目录中建立对应项目的表示层目录,如ccatsida,然后再在此目录下建立自己的样式表、脚本、Jsp等文件目录(为了保持界面风格一致,强烈建议各个具体的项目使用业务开发基础平台提供的css,这样将来需要整体变化样式时可以统一由美工调整),以后基础开发平台表示层的变动,将直接覆盖/WebRoot下的jsp,js,css,images,common目录即可。
现阶段基础开发平台将会以一个压缩包,如framework.rar,提供给具体项目的项目组进行基础开发环境的搭建。解开压缩包我们可以看到有两个目录WebRoot跟Base。
在基础平台表示层的\WebRoot\WEB-INF目录中,有多个配置文件,具体项目可能需要更改这些文件的配置内容,查看此目录:
若项目开发中应用到了struts, 则不应该更改这里的struts-config.xml文件,而应该建立一个新的struts配置文件,然后再修改web.xml文件引入此struts配置文件,做到基础平台和具体项目的struts配置文件分离目的。
若项目中用到了webservice则应该会修改server-config.wsdd文件
而项目中如有过滤器等配置也应该会更改web.xml文件
注:web.xml文件跟server-config.wsdd文件会既有基础开发平台的配置,也可能有项目的配置,在这两个文件中应该用注释加以区分,在文件更新时不要用文件覆盖的方法,而应比较该文件与待更新文件的不同之外,手工进行同步操作。
打开Base目录,我们可以看到一系列的配置文件跟jar包。
log4j相关的配置文件是开源日志记录项目log4j的配置文件,我们一般不改动此文件。
若项目开发用到了hibernate,则需要在此修改hibernate.cfg.xml中相关的配置内容。
SystemConfig.properties文件中配置了数据连接池的JNDI名称,这里要根据项目的具体配置做修改。
在具体的业务开发中,有可能并不使用数据连接池这种方式,这时我们可以在ExtraDataSource.xml中进行数据库信息的配置,基础开发平台提供相关的方法进行数据库的访问。
上面的jar包主要是现阶段基础开发平台的后台代码包,我们应该首先将这些包复制到WebRoot\WEB-INF\lib目录中。以后基础开发平台有更新改动后,就是提供这些包给项目进行更新,当然也可能还存在着相关表示层的更新。
在WEB-INF目录下有struts的配置文件struts-config.xml,基础开发平台有关struts的配置都放到struts-config.xml文件中,假若项目开发也用到了struts,这时应该新建一个struts配置文件,如命名为struts-config-xxxproject.xml。如何让系统启动时加载这个struts-config-xxxproject.xml文件呢,我们可以通过修改WEB-INF目录下的web.xml来达到这个目的。查看web.xml关于struts的配置,如下例:
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
<!-- 新增struts配置文件可以通过这种方法来实现,但建议采用第2种 -->
<!-- 方法1,将上面那段配置改为下面的配置,文件间必须以’,’分隔
<param-value>/WEB-INF/struts-config.xml,
/WEB-INF/struts-config-xxxproject.xml</param-value>
-->
</init-param>
<!-- 方法2 -->
<init-param> <!— param-name标签命名必须以’config/’开头-->
<param-name>config/xxxproject</param-name>
<param-value>/WEB-INF/struts-config-xxxproject.xml</param-value>
</init-param>
。。。。。。
<init-param>
<param-name>validate</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
由基础开发框架的技术架构图可以看出,业务层的开发是基于接口编程实现的,表示层通过指定业务对象名称调用业务对象工厂(根据配置信息)创建对应的业务接口实现类的对象实例。业务对象名称和具体的接口实现类的配置资料存储在数据库的物理表中,并按类别加以区分基础开发框架与具体项目的 BO配置,可以避免基础平台的配置和项目的配置混合在同一个配置文件中,有利于平台与项目的独立初始化和升级。
下面我们以图例的方式讲解BO映射的配置。
点击系统功能菜单的“系统管理”模块中的“BO映射配置”,将进行BO配置的列表页面,在此页面可以做“新增”、“编辑”、“修改”及“查询”操作,如下图。
BO映射配置列表
点击“新增”按钮或者在列表选择某条记录后点击“编辑”按钮将进入BO映射配置的维护页面;而在列表中选择一条或多条记录,通过点击“删除”按钮可以将选择的记录删除。在列表页面,还可以输入BO的名称及选择BO的类别来进行查询,查询结果将在列表中显示。
BO映射配置维护页面
上图为新增或修改BO映射配置时的页面,其中BO名称、BO类别及BO的实现类是必填项。BO的类别分为“基础开发框架”及“项目应用”,对于具体项目的BO配置,我们选择“项目应用”。BO的名称是唯一的,系统对新增或修改的BO的名称进行唯一性校验,当新增的BO存在时,系统给予提示。
BO映射的调用一般会在表示层中使用(参照技术加构图),下面以代码的方式简要说明,参照红色字体。
public ActionForward list(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws Exception
{
ActionForward forward = new ActionForward();
int iCurrPage = 1;
int iPageSize = 18;
。。。。。
try
{
IFormTestBO bo = (IFormTestBO) XmlFactory.getObject("FormTestBO");
/*通过XmlFactory的getObject方法实例化BO,getObject方法里的参数为
我们在BO配置中配置的BO名称。*/
PageVO list = bo.query(iPageSize, iCurrPage);
request.setAttribute("list", list);
}
catch (Exception e)
{
throw new Exception("FormTestAction.list(): Exception : fail to execute list", e);
}
forward = mapping.findForward("GRID");
return (forward);
}
业务开发基础平台有一配置文件SystemConfig.properties,我们原来将系统参数,如项目名称、分页数、附件上传路径等参数在此文件中设置,这造成对系统参数的维护不直观,而且也不方便,也容易引起文件内容不一致的情况。现在这个配置文件只保留对数据连接池JNDI的配置项,其他的参数都统一通过系统参数配置模块来完成。
系统参数列表
通过点击系统管理中的“系统参数配置”,我们可以进入系统参数列表页面,在这里将能看到已经配置的系统数的信息,还可以进行“新增”、“编辑”、“删除”及“查询”的操作。
系统参数维护页面
在系统参数维护页面中,我们可以设定参数的名称,参数值等内容。注意:这里的参数即是程序中要引用的参数,上图中的配置类似于我们以前在配置文件中的配置:showError=Y。
系统参数的调用方法很简单,参照下例。
import com.sunrise.framework.base.SystemParameter;
String showError = SystemParameter.getParameterValue("showError");
我们系统的异常处理,将页面统一定位到系统错误页面,如下图。
错误提示页面
上图展现的是错误提示页面,在开发阶段,我们希望能在此页面中还能看到具体的异常信息,这只需要更改相应参数的值即可,在参数定义表sys_parameter_conf中查找字段parameter 值为“showError”的记录,将parvalue字段值定义为“Y”(上述操作可以通过系统参数的配置模块来完成)。在sys_exception表中还会记载系统捕获的异常信息。
对于不可知的异常,我们将采用统一的提示信息在错误页面中展示,对于一些在程序中已经知道的异常,我们可以将错误提示信息以自定义的方式设置并错误页面展现。
下面我们以代码片断来介绍如何在抛出异常时定义我们已知的异常信息:
在action中,我们可以通过request.setAttribute("errorTipMsg ","")的方法将我们定义的异常写入,此种方式优先级最高。
public ActionForward save(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception
{
ActionForward forward = new ActionForward();
try
{
}
catch (Exception e)
{
//在这里写入异常信息
request.setAttribute("errorTipMsg ","保存的记录已经存在!");
throw new Exception("save(): Exception : fail to execute save", e);
}
return (forward);
}
在我们的BOException和DAOException中,我们可以通过如throw new BOException("")的方法自定义异常信息。
public int add(FormTestVO vo) throws BOException
{
int state = 0;
if (vo==null)
{
//抛出自定义异常信息
throw new BOException("保存失败,新增的值对象为空!");
}
try
{
}
catch (Exception e)
{
throw new BOException("FormTestBO.add() : Exception : fail to execute add", e);
}
finally
{
}
return state;
}
对于自定义的异常类,我们必须继承BaseException(异常信息现只针对BaseException类来获取),并定义相关方法,如:
public class WorkflowException extends BaseException
{
public WorkflowException()
{
super();
}
public WorkflowException(String msg)
{
super(msg, "workflow");
}
public WorkflowException(String msg, String from, Throwable nestedThrowable)
{
super(msg, from, nestedThrowable);
}
public WorkflowException(Throwable nestedThrowable)
{
super(nestedThrowable);
}
public WorkflowException(String msg, Throwable nestedThrowable)
{
super(msg,nestedThrowable);
}
BaseException提供了异常嵌套机制,通过该基类可以实现异常从DAO层到BO层再到Action,最后由ActionServlet获取整个异常链并进行记录。
基础开发平台主要采用的是应用服务器提供的数据接连池,这里会涉及到多个文件的配置,下面就以Tomcat5.0为例进行配置说明。
打开%Tomcat%\conf目录中的server.xml文件,在server.xml文件有一个<host></host>标签,我们在这标签中的最后面加入应用服务器的连接池配置内容,参照下面的内容,以蓝色字体标识出我们需要修改的地方,配置时请将下面的中文注释说明内容去掉。
<!-- =============== Data Connection Pool Config =============== -->
<DefaultContext debug="0" privileged="true" reloadable="true" useNaming="true" crossContext="true">
<Resource name="AppDB" auth="Container" type="javax.sql.DataSource">
</Resource> <!--定义连接池资源引用名-->
<ResourceParams name="AppDB">
<parameter>
<name>factory</name>
<value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
</parameter>
<parameter>
<name>username</name>
<value>bdf</value><!--数据库用户名-->
</parameter>
<parameter>
<name>password</name>
<value>password</value><!--数据库用户密码-->
</parameter>
<parameter>
<name>driverClassName</name>
<value>oracle.jdbc.driver.OracleDriver</value><!--数据库驱动-->
</parameter>
<parameter>
<name>url</name>
<!--数据库连接串-->
<value>jdbc:oracle:thin:@127.0.0.1:1521:mydb</value> </parameter>
<parameter>
<name>maxActive</name>
<value>20</value>
</parameter>
<parameter>
<name>maxIdle</name>
<value>5</value>
</parameter>
<parameter>
<name>maxWait</name>
<value>10000</value>
</parameter>
</ResourceParams>
</DefaultContext>
应用服务器的连接池配置好之后,还需要在web.xml中加入连接池的引用声明,具体配置如下:
<resource-ref>
<res-ref-name>AppDB</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
经过上述配置之后,基础开发平台就可以调用Tomcat的连接池了,下面将介绍基础开发平台调用连接池的相关配置及开发中如何取到连接池的数据连接进行操作。
基础开发平台中有一个SystemConfig.properties文件,它定义开发平台从应用服务器获得数据库连接时所使用的参数,如下:
dsJndiName=java:comp/env/AppDB
上面的参数是根据web.xml配置的连接池引用声明来配置的,基础开发平台中有一个封装好的数据连接的类WrappedConnection,它将根据参数dsJndiName的值来获得连接池的连接。
在具体的代码编写中,我们可通过下面的代码示例来取得数据连接进行相关操作。
由于业务开发基础平台采用的是应用服务器提供的数据连接池,这样必然会有一些特殊性,像Websphere不支持线程去连接池取数据连接,Tomcat在启动时加载的一些程序因Tomcat还未完全启动也会导致无法从连接池中取到数据连接,而上述情况Jboss则没问题;针对上述情况,基础开发平台提供了相关的方法进行数据库的配置与访问,ExtraDataSource.xml这个文件中可以定义了一个或多个数据库的数据连接配置,如下面例子中我们就配置了一个标识名为 “FrameWorkDataSource”数据连接池。
对于这种方式,我们上面的示例代码可以改为如下示例:
界面风格统一做法示意图
为了实现界面风格的参数化,方便日后界面风格的统一变换,系统提供-界面风格方案号-系统参数,用户登录系统后,将在session中保存该参数(StyleSolution),在表示层开发中要求jsp使用上图所示的代码,来引用样式文件,各个样式文件中的样式类名称相同,但具体的样式定义可能不同,jsp中的html引用这些样式类名,通过StyleSolution参数可以动态变换样式文件从而实现不修改代码的条件下整体切换界面风格。
在各种业务应用系统中往往存在各种数据管控限制的要求,比如接单部门,区域,专业,局向等授权因子,用户仅能操控一个或多个授权因子特定范围内的数据(如某个用户智能查看某几个局向相关联的工单),在以往系统的实现过程中一般是以固化形式的配置授权并记录在相关的(主体与数据权限要素的)关联表中,考虑到各种业务系统中,授权因子并不局限在上述举例的几种类别内,业务开发基础平台需要考虑授权因子及其数据内容的可配置性,为各类应用系统提供灵活可行的数据权限控制机制
8.1实现思路说明
第一步:定义数据权限控制的因子(比如区域、专业、局向等),这里包括:
定义在SQL命令或存储过程中表示数据权限控制的占位符需要用到的标签名称;
对应权限因子下可授权数据的获取方式(比如区域权限因子,区域信息可能是动态配置的,有哪些区域配置,需要给出获取这些数据的方法,目前暂时考虑先支持通过SQL获取);
授权因子取值的数据类型(决定记录授权记录时是写到哪张表,目前考虑用2个表来记录数据权限授权记录,主要是考虑授权记录表数据量将很大,需要考虑建立索引,为了有效地使用索引,建议针对不同权限因子数据类型分开建立不同的授权记录表,目前只支持int型和string型)
如果授权因子数据是树型关系,需要树型展示,则需要定义父子关系的字段信息
基础开发平台提供了系统参数配置功能,系统参数分成两类,一类是系统级参数,该类型参数在参数配置表中是唯一的,参数的所有者仅为SYSTEM;另一类是客户级参数, 该类型参数在参数配置表中不是唯一的,主要是考虑在ASP(Application Service Provider)应用背景下,不同客户可进行个性化设置,比如全省集中系统,不同的本地网可以定制各自的系统参数,如果某个本地网没有配置某客户级参数,则系统在获取该参数时缺省取名称相同但所有者为省公司的系统参数,如果省公司也没有配置该客户级参数,则缺省取名称相同但所有者为SYSTEM的系统参数。在此,SYSTEM代表系统级别的配置。
目前系统参数的命名暂定如下:
基础开发平台的参数:以‘SYS_’或大模块编码打头
各业务项目的参数:以项目或大模块缩写编码打头
CurrentUser 属性保存当前用户的com.sunrise.framework.org.user.vo.UserVO对象。
11.2StyleSolution属性说明
StyleSolution保存当前用户的界面风格的个性化设置参数值,对象类型为String。
通过用户登陆界面判断用户的合法性,并用分配给该用户相应的权限.
系统主界面
快捷菜单区
主工作区
底部工具栏
系统模块区
功能模块区
可以对组织进行树形显示、新增单位、编辑单位、删除单位、新增岗位等操作。
用户管理
在组织树形显示时,对该单位下的人员进行、新增用户、编辑用户、删除用户、检索等操作
对数据字典进义定义、修改、删除等操作。
对新增、修改数据字典定义
对字典中的内容进行维护。
选中其中的一个对象对其维护。
显示对象中字典内容,可以对字典的内容进行新增、编辑、删除等操作。
字典对象内容编辑、新增界面
可以动态地配置系统中所有模块信息。可以所有功能模块进行新增、编辑、删除等操作。
自定义查询见《查询自定义用户操作手册》