1、框架简介
MVC对于我们来说,已经不陌生了,它起源于20世纪80年代针对smalltalk语言的一种软件设计模式。现在已经被广泛应用。近年来,随着java的盛行,MVC的低耦合性、高重用性、可维护性、软件工程的可管理性等诸多优点使其在java平台很受欢迎,期间,也诞生了许多优秀的MVC框架,如专注于控制层的struts、webwork、struts2、JSF等框架;专注于业务逻辑方面的Spring框架;专注于持久层的Hibernate、iBatis、Castor、JORM等框架。
下面对SSI框架:struts2+spring+iBatis的三个开源的MVC框架进行说明
Struts2主要来源于webwork框架,与Struts1相比:
- 在数据传递方面,Struts2提供了更加强大的OGNL标签功能,使其能够通过action中定义变量来直接与jsp页面中的数据进行相互传值,省去了struts1中的formbean;
- 而在跳转控制方面,Struts2简化了配置文件的信息量,使页面和action之间的交换更加的简洁和直观,便于开发人员的管理。
Spring功能非常的强大:
- 比如它的控制反转IOC/依赖注入SET GET机制,省去了我们自己书写工厂模式的工作,实现类对我们将要用到的控制类Action、业务逻辑类Service、数据访问类domain、以及JNDI或者JDBC数据源Dao进行托管;
- Spring对AOP支持使我们在用户权限控制、事务处理方面节省了很多工作量;
iBatis则是一种轻量级的OR Mapping框架,与Hibernate相比,iBatis提供了半自动化对象关系映射的实现,开发人员需要编写具体的sql语句,为系统设计提供了更大的自由空间,为sql语句优化提供了便利。
2、框架结构
下面这张图就是我们所用到的这三种框架的结合体,下面对其做以简单的介绍。
(1)控制层
在控制层,利用Strtus2标签功能,在Action中直接与jsp页面上的数据进行交互。在调用业务逻辑层应用时,Struts2提供了对Spring的支持。开发人员需要完成对struts.xml的配置工作和各个Action类的编写。
总的struts.xml配置文件:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<package name="struts-init" extends="struts-default">
<action name="index" class="anonymousAction" method="execute">
<result name="success">province_level/shanxi/login.jsp</result>
</action>
<action name="nologinAct" class="nologinAct">
<result name="success">/common/nologin.jsp</result>
</action>
<!-- 插件下载 -->
<action name="downLoadFileLogin" class="anonymousAction" method="getDownLoadFile">
<result name="success" type="stream">
<!--文件类型,当前是所有的类型 -->
<param name="contentType">application/octet-stream</param>
<!--第一个参数是指打开下载框默认是inline浏览器能打开的就不去下载直接打开 -->
<param name="contentDisposition">attachment;fileName="${fileName}"</param>
<param name="inputName">inputStream</param> <!--方法名字 -->
<param name="bufferSize">1024</param> <!--文件大小 -->
</result>
</action>
<interceptors>
<!-- 声明拦截器 -->
<interceptor name="checkPrivilege"
class="com.highland.criminal.business.sysman.Interceptor.CheckAuthorityInterceptor"></interceptor>
<interceptor name="json" class="org.apache.struts2.json.JSONInterceptor" />
<!-- 自定义拦截器 -->
<interceptor name="exceptionInterceptor" class="com.highland.framework.web.interceptor.ExceptionInterceptor"></interceptor>
<!-- 声明一个新的拦截器栈(先检查权限) -->
<interceptor-stack name="myDefaultStack">
<interceptor-ref name="defaultStack" />
<interceptor-ref name="checkPrivilege" />
<interceptor-ref name="exceptionInterceptor" />
<interceptor-ref name="json" />
</interceptor-stack>
</interceptors>
<!-- 默认使用的拦截器(拦截器栈) -->
<default-interceptor-ref name="myDefaultStack" />
<!-- 全局的Result配置 -->
<global-results>
<result name="error">/common/error.jsp</result>
<result name="login" type="redirect">nologinAct.action</result>
<result name="noPrivilegeError">/xtba/common/noPrivilegeError.jsp</result>
</global-results>
<global-exception-mappings>
<exception-mapping result="error"
exception="com.highland.framework.exception.BaseException"></exception-mapping>
</global-exception-mappings>
<!-- 为兼容ecside增加的错误action -->
<action name="errorAction"
class="com.highland.criminal.business.sysman.action.ExceptionAction">
<result>/common/error.jsp</result>
</action>
</package>
<include file="struts/struts-hdzhfx.xml"></include><!-- 综合分析-->
</struts>
由于项目中可能涉及多个功能模块,所以在总的struts.xml中通过<include>标签引入各个功能模块的xml配置。这里以综合分析模块为例,对struts-hdzhfx.xml配置文件进行分析
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<!-- 综合分析报告-->
<package name="hdzhfx" namespace="/" extends="struts-init">
<!-- 这种方式配置返回值链接:返回简单json字符串参数total和rows -->
<action name="glhdfx_new" class="hdzhfxAction" method="glhdfx_new">
<result name="success" type="json">
<param name="includeProperties">
total,rows
</param>
</result>
</action>
<!-- 这种方式配置简单的查询方法链接 -->
<action name="zhfx_thqfx" class="hdzhfxAction" method="thqfx_Query"></action>
<!-- 这种方式配置返回值链接:返回list数据 -->
<action name="listhdkxx" class="hdzhfxAction" method="listhdxx" >
<result name="success">/xzzxyw/hdfx/queryHdxxList.jsp</result>
<result name = "success_hdxx" type = "json">
<param name = "root">
bkxxs
</param>
</result>
</action>
</package>
</struts>
(2)业务逻辑层
在业务逻辑层,利用Spring框架的依赖注入实现对业务逻辑类和Dao类的实例进行托管;
在事务处理方面,利用Spring提供的面向切面的事务处理功能,使对数据的事务控制脱离于数据访问接口实现;
在对象关系映射方面,利用Spring对数据库连接池的托管和对iBatis框架的支持。
开发人员需要完成对数据源的配置、对不同模块所对应的application*.xml文件的配置,以及对业务逻辑接口的定义和业务逻辑实现的编写。
① spring-->ibatis-->applicationContext-ibatis.xml:这里加载数据源配置及事务机制
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<!-- 引入项目的jdbc配置文件 -->
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:/jdbc.properties</value>
</list>
</property>
</bean>
<!-- 配置数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass"><value>${jdbc.driverClassName}</value></property>
<property name="jdbcUrl"><value>${jdbc.url}</value></property>
<property name="user"><value>${jdbc.username}</value></property>
<property name="password"><value>${jdbc.password}</value></property>
<property name="initialPoolSize"><value>50</value></property>
<property name="minPoolSize"><value>50</value></property>
<property name="maxPoolSize"><value>300</value></property>
<property name="checkoutTimeout"><value>5000</value></property>
<property name="maxIdleTime"><value>1800</value></property>
<property name="idleConnectionTestPeriod"><value>3000</value></property>
<property name="acquireIncrement"><value>5</value></property>
<property name="maxStatements" value="0"/>
<property name="testConnectionOnCheckout" value="false"/>
</bean>
<!-- 定义事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource"><ref bean="dataSource"/></property>
</bean>
<!-- Spring的IBatis模板 -->
<!-- 加入对大数据类型操作的支持 -->
<bean id="lobHandler" class="org.springframework.jdbc.support.lob.DefaultLobHandler"/>
<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean" >
<property name="configLocations">
<!-- 重点:这里将spring中的ibatis层与ibatis连接起来了 -->
<value>classpath*:/ibatis/app-sqlmap-config.xml</value>
</property>
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="lobHandler" ref="lobHandler"/> <!-- 加入对大数据类型操作的支持 -->
</bean>
<bean id="sqlMapClientTemplate" class="org.springframework.orm.ibatis.SqlMapClientTemplate">
<property name="sqlMapClient" ref="sqlMapClient"></property>
</bean>
<!--开启事务 -->
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
spring-->ibatis-->app-ibatis-hdzhfx.xml (这个文件与applicationContext-ibatis.xml是通过<ref bean="sqlMapClient">关联到一起的)
这里配置Dao的bean值,是为下一层spring-->service-->app-service-hdzhfx.xml中的bean的返回值<ref bean="tbryhdDao" />做的配置。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="tbryhdDao" class="com.highland.criminal.business.dao.stdao.TbRyHdDao">
<property name="sqlMapClient">
<ref bean="sqlMapClient" />
</property>
</bean>
<bean id="tbryhdtxlbdDao" class="com.highland.criminal.business.dao.stdao.TbRyHdTxlBdDao">
<property name="sqlMapClient">
<ref bean="sqlMapClient" />
</property>
</bean>
</beans>
② spring-->service-->app-service-hdzhfx.xml承上启下的作用。
承上:<ref bean="tbryhdDao" />这里的ref中bean的值对应的是spring-->ibatis-->app-ibatis-hdzhfx.xml中配置的bean的id
启下:这里的bean 的id值zhHdfxService对应的是spring-->struts-->app-struts-hdzhfx.xml中需要的service的名字 <ref bean="zhHdfxService" />。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<!-- 配置bean:注意这里的bean的id对应的是spring中app-struts-hdzhfx.xml中的ref对应的bean值-->
<bean id="zhHdfxService" parent="baseTransactionProxy">
<property name="target">
<bean class="com.highland.criminal.business.xzqbyp.hdfx.service.imp.HdZhfxServiceImpl">
<!-- 这里的ref中bean的值对应的是spring中的ibatis下app-ibatis-hdzhfx.xml中配置的bean的id -->
<property name="tbryhdDao"><ref bean="tbryhdDao" /></property>
<property name="tbRyhdtxlDao"><ref bean="tbryhdtxlbdDao" /></property>
</bean>
</property>
</bean>
</beans>
③ spring -->struts-->app-struts-hdzhfx.xml:
<ref bean="zhHdfxService" />这里的bean的值对应的是spring-->service-->app-service-hdzhfx.xml中配置的bean的id
这里bean的id值hdzhfxAction对应的是配置struts-hdzhfx.xml中需要的action的class类值
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<!-- 配置bean:注意这里的bean的id对应的是spring中struts-hdzhfx.xml中的action的class -->
<bean id="hdzhfxAction" class="com.highland.criminal.business.xzqbyp.hdfx.action.HdZhfxAction" scope="prototype">
<property name="zhHdfxService">
<ref bean="zhHdfxService" /><!-- 注意:这里的bean的值对应的是spring中service中的app-service-hdzhfx.xml中配置的bean的id -->
</property>
</bean>
</beans>
(3) 持久层
在持久层,利用iBatis提供的半自动化对象关系映射实现。开发人员需要编写具体的sql语句,为系统设计提供了更大的自由空间。另外,开发人员需要完成对ibatis的配置文件app-sqlmap-config.xml和*-sqlmap.xml的配置,以及对DAO接口的定义和DAO接口的实现。
app-sqlmap-config.xml:这里配置了多个sql文件的引用
与spring层之间的关联:在spring-->ibatis-->applicationContext-ibatis.xml中配置了这:
<bean id="sqlMapClientTemplate" class="org.springframework.orm.ibatis.SqlMapClientTemplate">
<property name="sqlMapClient" ref="sqlMapClient"></property>
</bean>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN" "sql-map-config-2.dtd">
<sqlMapConfig>
<settings cacheModelsEnabled="false" enhancementEnabled="false"
lazyLoadingEnabled="false" maxRequests="3000" maxSessions="3000"
maxTransactions="3000" useStatementNamespaces="true" />
<sqlMap resource="/ibatis/app/hdzhfx-sqlmap.xml" />
</sqlMapConfig>
hdzhfx-sqlmap.xml:这个文件里写sql语句
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN" "sql-map-2.dtd">
<sqlMap namespace="hdfxnew">
<!-- 映射实体 -->
<typeAlias alias="hdfxxx" type = "com.highland.framework.hdanalysis.domain.hdfxdomain" />
<!-- 根据id查询信息 -->
<select id="queryHdInfo" parameterClass="hdfxxx" resultClass="hdfxxx">
select BJGSD,CTLX,MYZT,THDD,THJZ,JZDQ,JZXQ,IMEI,IMSI,JD,WD,
DFTHDD,DFTHJZ,DFJZDM,DFIMSI,DFGSD,DFIMEI,DFHMJZXM,DFCH,
DFJZQW,DFJD,DFWD,HOLDING_TIME,BJHM,DFHM,CALL_TYPE,
START_TIME,END_TIME from HD_CALL_INFO where 1=1 and scbz=0
<isNotEmpty property="BJHM"> and BJHM= #BJHM#</isNotEmpty>
<isNotEmpty property="DFHM"> and DFHM= #DFHM#</isNotEmpty>
<isNotEmpty property="CALL_TYPE"> and CALL_TYPE= #CALL_TYPE#</isNotEmpty>
<isNotEmpty property="START_TIME"> and to_date(START_TIME,'yyyy-MM-dd hh24miss') >= to_date(#START_TIME#,'yyyy-MM-dd')</isNotEmpty>
<isNotEmpty property="END_TIME"> and to_date(END_TIME,'yyyy-MM-dd hh24miss') <![CDATA[<=]]> to_date(#END_TIME#,'yyyy-MM-dd')</isNotEmpty>
<isNotEmpty property="THDD"> and THDD= #THDD#</isNotEmpty>
</select>
<!-- 新增记录 -->
<insert id="savedrrzdata" parameterClass="hdfxxx">
insert into HD_CALL_LOG (xxzjbh,jzhm,ckrxm,asjbh,ckrsfzh,drzs,drms,drsj)
values (#xxzjbh#,#jzhm#,#ckrxm#,#asjbh#,#ckrsfzh#,#drzs#,#drms#,#drsj#)
<selectKey resultClass="java.lang.String" keyProperty="xxzjbh">
select #xxzjbh# as xxzjbh from dual
</selectKey>
</insert>
<!-- 查询所有的信息 -->
<select id="queryHdlogInfo" parameterClass="hdfxxx" resultClass="hdfxxx">
select xxzjbh,ckrsfzh,jzhm,ckrxm,asjbh,drzs,drms,drsj from HD_CALL_LOG where 1=1 and scbz=0
</select>
</sqlMap>
(4)小结
在各层之间进行交换的过程中,利用数据传输类进行数据的传递和交互。其中数据传输类与数据库表一一对应。
SSI框架能够降低代码的耦合度,增强了代码的健壮性和可重用性,加快了开发速度,但是也有一些不足之处,比如由于三种框架的配置文件较多,也会带来一些不便,特别是对于较小的应用来说更是如此。