`
玉德思密达
  • 浏览: 7545 次
社区版块
存档分类
最新评论

Spring Mvc架构流程

阅读更多

对于一个web项目,根据其大小,在结构上我们也可以有简易复杂之分。故有如下两种方案:

方案一,传统型:

父上下文容器中保存数据源、服务层、DAO层、事务的Bean。

子上下文容器中保存Mvc相关的Action的Bean.

事务控制在服务层。

由于父上下文容器不能访问子上下文容器中内容,事务的Bean在父上下文容器中,无法访问子上下文容器中内容,就无法对子上下文容器中Action进行AOP(事务)。

当然,做为“传统型”方案,也没有必要这要做。

 

方案二,激进型:

Java世界的“面向接口编程”的思想是正确的,但在增删改查为主业务的系统里,Dao层接口,Dao层实现类,Service层接口,Service层实现类,Action父类,Action。再加上众多的O(vo\po\bo)和jsp页面。写一个小功能 7、8个类就写出来了。 开发者说我就是想接点私活儿,和PHP,ASP抢抢饭碗,但我又是Java程序员。最好的结果是大项目能做好,小项目能做快。所以“激进型”方案就出现了-----没有接口、没有Service层、还可以没有众多的O(vo\po\bo)。那没有Service层事务控制在哪一层?只好上升的Action层。

本文不想说这是不是正确的思想,我想说的是Spring不会限制你这样做。

由于有了父子上下文,你将无法实现这一目标。解决方案是只使用子上下文容器,不要父上下文容器 。所以数据源、服务层、DAO层、事务的Bean、Action的Bean都放在子上下文容器中。就可以实现了,事务(注解事务)就正常工作了。这样才够激进。

总结:不使用listener监听器来加载spring的配置文件,只使用DispatcherServlet来加载spring的配置,不要父子上下文,只使用一个DispatcherServlet,事情就简单了,什么麻烦事儿也没有了。

 

 今天就传统型做个规整:

  

demo-web(Mvc相关的Action的Bean):

web层当然要从 web.xml着手分析;

  web.xml(webapp/WEB-INF/web.xml)

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_9" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
 http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> 
<display-name>Struts Blank</display-name>

<resource-ref> 
<description>DB Connection</description> 
<res-ref-name>jdbc/misceooracleds</res-ref-name> 
<res-type>javax.sql.DataSource</res-type> 
<res-auth>Container</res-auth> 
</resource-ref> 

<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:META-INF/spring/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<filter>   
<filter-name>Set Character Encoding</filter-name>   
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>   
<init-param>   
<param-name>encoding</param-name>   
<param-value>utf8</param-value>   
</init-param>   
</filter>   
<filter-mapping>   
<filter-name>Set Character Encoding</filter-name>   
<url-pattern>/*</url-pattern>   
</filter-mapping>


<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<servlet>       
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>

<session-config>
<session-timeout>30</session-timeout>
</session-config>

<mime-mapping>
<extension>xls</extension>
<mime-type>application/msexcel</mime-type>
</mime-mapping>
<mime-mapping>
<extension>zip</extension>
<mime-type>application/zip</mime-type>
</mime-mapping>
<!--
<error-page>
<error-code>500</error-code>
<location>/error.html</location>
</error-page>
<error-page>
<error-code>400</error-code>
<location>/index.html</location>
</error-page>
<error-page>
<error-code>403</error-code>
<location>/403.html</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/404.html</location>
</error-page>
 -->
</web-app>

 

 使用Spring MVC,配置DispatcherServlet是第一步。

DispatcherServlet是一个Servlet,所以可以配置多个DispatcherServlet。

DispatcherServlet是前置控制器,配置在web.xml文件中的。拦截匹配的请求,Servlet拦截匹配规则要自已定义,把拦截下来的请求,依据某某规则分发到目标Controller(我们写的Action)来处理。

 

“某某规则”:是根据你使用了哪个HandlerMapping接口的实现类的不同而不同。

web.xml文件中<context-param>元素的作用

文章分类:Java编程

1.启动一个WEB项目的时候,容器(如:Tomcat)会去读它的配置文件web.xml.读两个节点: <listener></listener> 和 <context-param></context-param>

 

2.紧接着,容器创建一个ServletContext(上下文),这个WEB项目所有部分都将共享这个上下文.

 

3.容器将<context-param></context-param>转化为键值对,并交给ServletContext.

 

4.容器创建<listener></listener>中的类实例,即创建监听.

 

5.在监听中会有contextInitialized(ServletContextEvent args)初始化方法,在这个方法中获得
ServletContext = ServletContextEvent.getServletContext();
context-param的值 = ServletContext.getInitParameter("context-param的键");

 

 

 

6.得到这个context-param的值之后,你就可以做一些操作了.注意,这个时候你的WEB项目还没有完全启动完成.这个动作会比所有的Servlet都要早.
换句话说,这个时候,你对<context-param>中的键值做的操作,将在你的WEB项目完全启动之前被执行.

 

7.举例.你可能想在项目启动之前就打开数据库.
那么这里就可以在<context-param>中设置数据库的连接方式,在监听类中初始化数据库的连接.

 

8.这个监听是自己写的一个类,除了初始化方法,它还有销毁方法.用于关闭应用前释放资源.比如说数据库连接的关闭.

 applicationContext.xml(是spring的一个基本配置文件一般放在spring包下,在web.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:aop="http://www.springframework.org/schema/aop
       xmlns:tx="http://www.springframework.org/schema/tx
    xmlns:context="http://www.springframework.org/schema/context
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
       http://www.springframework.org/schema/tx 
       http://www.springframework.org/schema/tx/spring-tx-3.0.xsd 
    http://www.springframework.org/schema/context 
       http://www.springframework.org/schema/context/spring-context-3.0.xsd 
       http://www.springframework.org/schema/aop 
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> 

<!-- auto register Processor -->
<context:annotation-config/>

<bean id="propertyConfigurer"
  class="com.xxx.common.config.GlobalConfigPropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:/META-INF/spring/jdbc.properties</value>
<value>classpath:/META-INF/spring/common-mis.properties</value>
<value>classpath:/META-INF/spring/config.properties</value>
<value>classpath:/META-INF/spring/cognos.properties</value>
<value>classpath:/META-INF/spring/client.properties</value>
</list>
</property>
</bean>

以下应用模块化设计导入其他模块使得applicationContext更加精简

<import resource="classpath:META-INF/spring/persistence-ceo.xml"/>
<import resource="classpath:META-INF/spring/dal-dao-ceo.xml"/>
<import resource="classpath:META-INF/spring/dal-dao-ceo-batch.xml"/>
<import resource="classpath:META-INF/spring/cache-context-mis.xml"/>

<import resource="classpath:META-INF/spring/services-ceo.xml"/>

<!-- system manager start -->
<import resource="classpath:META-INF/spring/persistence-system.xml"/>
<import resource="classpath:META-INF/spring/dal-dao-system.xml"/>
<import resource="classpath:META-INF/spring/dal-dao-system-batch.xml"/>
<import resource="classpath:META-INF/spring/services-system.xml"/>
<!-- system manager end -->

<!-- engine start -->
<!--
<import resource="classpath:META-INF/spring/persistence-engine-test.xml"/>
<import resource="classpath:META-INF/spring/dal-dao-engine.xml"/>
<import resource="classpath:/META-INF/spring/common-core-engine.xml"/>
<import resource="classpath:/META-INF/spring/common-core-lock.xml"/>
<import resource="classpath:/META-INF/spring/common-core-schedule.xml"/>-->
<!-- engine end -->

<!-- security -->
<import resource="classpath:META-INF/spring/spring-security.xml"/>
<!-- <import resource="classpath:META-INF/spring/spring-pre-security.xml"/>-->
    <!-- remote -->
 <import resource="classpath:META-INF/spring/remote-client.xml"/>
</beans>

在DispatcherServlet的初始化过程中,框架会在web应用的 WEB-INF文件夹下寻找名为[servlet-name]-servlet.xml 的配置文件,生成文件中定义的bean。

 

 springmvc-servlet.xml(路径同web.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"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:mvc="http://www.springframework.org/schema/mvc"
 xsi:schemaLocation="http://www.springframework.org/schema/beans   
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
       http://www.springframework.org/schema/context   
       http://www.springframework.org/schema/context/spring-context-3.0.xsd
       http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
 <!-- 启动Spring MVC的注解功能,完成请求和注解POJO的映射                          注解式方法处理器适配器--> 
 <!-- 开启支持@Controller 和@RequestMapping注解的处理器。-->
    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
  <property name="messageConverters">
   <list>
    <ref bean="mappingJacksonHttpMessageConverter" />  <!-- 处理json数据转换 -->
    <ref bean="mappingTextHttpMessageConverter" />
   </list>
  </property>
 </bean>
 <!-- spring mvc 之返回json数据 -->
 <bean id="mappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>

 <bean id="mappingTextHttpMessageConverter" class = "org.springframework.http.converter.StringHttpMessageConverter">
  <property name = "supportedMediaTypes">
   <list>
    <value>text/plain;charset=UTF-8</value>    <!-- 处理返回的数据 编码   纯文本 字符编码 utf-8-->
   </list>
  </property>
 </bean>   
 
 <mvc:annotation-driven />  <!--  会自动注册DefaultAnnotationHandlerMapping与AnnotationMethodHandlerAdapter 两个bean,是spring MVC为@Controllers分发请求所必须的。
  -->
      
 <!-- 把标记了@Controller注解的类转换为bean  组件扫描--> 
    <context:component-scan base-package="com.....web"/>
    <context:component-scan base-package="com......system.web"/>

    <!-- 启动Spring MVC的注解功能,完成请求和注解POJO的映射 --> 
    <!-- <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" /> --> 
         
 <!-- 对模型视图名称的解析,即在模型视图名称添加前后缀 -->
 <bean
  class="org.springframework.web.servlet.view.InternalResourceViewResolver"
  p:prefix="/" p:suffix=".jsp" />
  
    <!-- 处理Mutipart文件上传的bean --> 
    <bean id="multipartResolver" 
        class="org.springframework.web.multipart.commons.CommonsMultipartResolver" 
        p:defaultEncoding="utf-8" />
   
    <!-- 异常处理 -->
 <bean id="exceptionResolver"
  class="com.xxx.common.resolver.WebExceptionResolver">
  <property name="defaultErrorView">
   <value>/error</value>
  </property>
 </bean>

    <!-- 拦截器配置 -->
    <mvc:interceptors>
        <bean class="com.xxx.security.intercept.PermissionInterceptor" />
    </mvc:interceptors>
  
</beans>

涉及的一些类和接口:

HandlerMapping接口 -- 处理请求的映射

HandlerMapping接口的实现类:

SimpleUrlHandlerMapping  通过配置文件,把一个URL映射到Controller

DefaultAnnotationHandlerMapping  通过注解,把一个URL映射到Controller类上

HandlerAdapter接口 -- 处理请求的映射

AnnotationMethodHandlerAdapter类,通过注解,把一个URL映射到Controller类的方法上

HandlerInterceptor 接口--拦截器

Controller接口 -- 控制器

由于我们使用了@Controller注解,添加了@Controller注解注解的类就可以担任控制器(Action)的职责,

所以我们并没有用到这个接口。

ViewResolver接口的实现类

UrlBasedViewResolver类 通过配置文件,把一个视图名交给到一个View来处理

InternalResourceViewResolver类,
HandlerExceptionResolver接口 --异常处理

SimpleMappingExceptionResolver实现类

ModelAndView类

 

 

 

demo-service(服务层、DAO层):

 

层次结构比较复杂 service---->dao------->框架封装的增删改查方法    映射无处不在(OR-Mapping)

 

Ibatis框架:

       

深入分析 iBATIS 框架之系统架构与映射原理

<!-- LEADSPACE_BODY_END --><!-- SUMMARY_BEGIN -->

iBATIS 通过 SQL Map 将 Java 对象映射成 SQL 语句和将结果集再转化成 Java 对象,与其他 ORM 框架相比,既解决了 Java 对象与输入参数和结果集的映射,又能够让用户方便的手写使用 SQL 语句。本文主要介绍了 iBATIS 框架的体系结构和运行流程,以及 iBATIS 如何完成 SQL 语句的解析与 Java 对象与数据字段映射关系的建立,最后用一个实例说明了 iBATIS 是如何帮我们完成工作的。

 

    

iBATIS 框架主要的类层次结构

总体来说 iBATIS 的系统结构还是比较简单的,它主要完成两件事情:

  1. 根据 JDBC 规范建立与数据库的连接;
  2. 通过反射打通 Java 对象与数据库参数交互之间相互转化关系。

iBATIS 的框架结构也是按照这种思想来组织类层次结构的,其实它是一种典型的交互式框架。先期准备好交互的必要条件,然后构建一个交互的环境,交互环境中还划分成会话,每次的会话也有一个环境。当这些环境都准备好了以后,剩下的就是交换数据了。其实涉及到网络通信,一般都会是类似的处理方式。

图 1 是 iBATIS 框架的主要的类层次结构图:

图 1. iBATIS 框架的主要的类层次结构图

图 1. iBATIS 框架的主要的类层次结构图

上面的类图中左边 SqlMapClient 接口主要定义了客户端的操作行为包括 select、insert、update、delete。而右边主要是定义了当前客户端在当前线程的执行环境。SqlMapSession 可以共享使用,也可以自己创建,如果是自己创建在结束时必须要调用关闭接口关闭。

当使用者持有了 SqlMapClientImpl 对象就可以使用 iBATIS 来工作了。这里还要提到另外一个类 SqlMapExecutorDelegate 这个类从名字就可以看出他是执行代理类。这个类非常重要,重要是因为他耦合了用户端的执行操作行为和执行的环境,他持有执行操作的所需要的数据,同时提供管理着执行操作依赖的环境。所以他是一个强耦合的类,也可以看做是个工具类。


iBATIS 框架的设计策略

iBATIS 主要的设计目的还是为了让我们执行 SQL 时对输入输出的数据管理更加方便,所以如何方便的让我们写出 SQL 和方便的获取 SQL 的执行结果才是 iBATIS 的核心竞争力。那么 iBATIS 是怎么实现它的核心竞争力的呢?

iBATIS 框架的一个重要组成部分就是其 SqlMap 配置文件,SqlMap 配置文件的核心是 Statement 语句包括 CIUD。 iBATIS 通过解析 SqlMap 配置文件得到所有的 Statement 执行语句,同时会形成 ParameterMap、ResultMap 两个对象用于处理参数和经过解析后交给数据库处理的 Sql 对象。这样除去数据库的连接,一条 SQL 的执行条件已经具备了。

图 2 描述了 Statement 有关的类结构图:

图 2. Statement 有关的类结构图

图 2. Statement 有关的类结构图

图 2 给出了围绕 SQL 执行的基本的结构关系,但是还有一个关键的部分就是,如何定义 SQL 语句中的参数与 Java 对象之间的关系,这其中还涉及到 Java 类型到数据库类型的转换等一系列问题。

数据的映射大体的过程是这样的:根据 Statement 中定义的 SQL 语句,解析出其中的参数,按照其出现的顺序保存在 Map 集合中,并按照 Statement 中定义的 ParameterMap 对象类型解析出参数的 Java 数据类型。并根据其数据类型构建 TypeHandler 对象,参数值的复制是通过 DataExchange 对象完成的。

图 3 是参数映射相关的类结构图:

图 3. 参数映射相关的类结构图

图 3. 参数映射相关的类结构图

图 3 是输入参数的映射结构情况,返回结果 ResultMap 的映射情况也是类似的。主要就是要解决 SQL 语句中的参数与返回结果的列名与 Statement 中定义的 parameterClass 和 resultClass 中属性的对应关系。


iBATIS 框架的运行原理

前面大体分析了 iBATIS 框架的主要类的结构,这里主要看一下这些类是如何串联起来、如何工作的。图 4 描述了整个过程的主要执行步骤。

图 4.iBATIS 运行的主要执行步骤

图 4.iBATIS 运行的主要执行步骤

上图中描述的 SqlMapSession 对象的创建和释放根据不同情况会有不同,因为 SqlMapSession 负责创建数据库的连接,包括对事务的管理,iBATIS 对管理事务既可以自己管理也可以由外部管理,iBATIS 自己管理是通过共享 SqlMapSession 对象实现的,多个 Statement 的执行时共享一个 SqlMapSession 实例,而且都是线程安全的。如果是外部程序管理就要自己控制 SqlMapSession 对象的生命周期。

图 5 是通过 Spring 调用 iBATIS 执行一个 Statement 的一个详细的时序图:

图 5. Spring 调用 iBATIS 执行一个 Statement 的时序图

图 5. Spring 调用 iBATIS 执行一个 Statement 的时序图

(查看图 5 的 清晰版本。)

iBATIS 的主要工作连接、交互,所以必须根据不同的交易成本设计不同的交易环境。


示例

下面我们将根据一个具体的实例解析一个 Statement 如何完成映射的,我们用一个典型的查询语句看看 Java 对象中的数据时如何赋给 SQL 中的参数的,再看看 SQL 的查询结果是如何转成 Java 对象的。

先看一下示例的部分代码和配置文件,完整的代码请看附件。

Spring 的 applicationContext 配置文件:

清单 1. applicationContext.xml
<beans>
    <bean id="sqlMapTransactionManager" 
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <bean id="sqlMapTransactionTemplate" 
        class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="sqlMapTransactionManager"/>
    </bean>
    <!--sql map -->
    <bean id="sqlMapClient" 
        class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
        <property name="configLocation" value="com/mydomain/data/sqlmap-ceo.xml"/>
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <bean id="dataSource" name="dataSource" 
        class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
        <property name="url" value="jdbc:oracle:thin:@10.1.5.11:1521:XE"/>
        <property name="username" value="junshan"/>
        <property name="password" value="junshan"/>
        <property name="maxActive" value="20"/>
    </bean>
    <bean id="accountDAO" class="com.mydomain.AccountDAO">
         <!--也可以分离出来 更加模块化 -->

        <property name="sqlMapClient" ref="sqlMapClient"/>
        <property name="sqlMapTransactionTemplate" ref="sqlMapTransactionTemplate"/>
    </bean>
</beans>
  

 

sqlmap-ceo.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN" "http://www.ibatis.com/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
    <settings cacheModelsEnabled="true" enhancementEnabled="false" lazyLoadingEnabled="false" maxRequests="3000" maxSessions="3000" maxTransactions="3000" useStatementNamespaces="false"/>
 
 <sqlMap resource="sqlmap/ceo-common-sqlmap-mapping.xml"/>
 <!--  -->
    <sqlMap resource="sqlmap/AlertConfig-sqlmap-mapping.xml"/>
    <sqlMap resource="sqlmap/Capacity-sqlmap-mapping.xml"/>

</sqlMapConfig>

Capacity-sqlmap-mapping.xml

   <?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN" "http://www.ibatis.com/dtd/sql-map-2.dtd">

<!-- ==========================================================  -->
<!-- Configuration for ibatis sqlmap mapping.                    -->
<sqlMap namespace="mis">
    <!-- ============================================= -->
    <!-- RESULT MAPS                                   -->
    <!-- ============================================= -->

    <!-- result maps for database table T_CAPACITY -->
    <resultMap id="RM-CAPACITY" class="com.cpic.mis.ceo.core.dal.dataobject.CapacityDO">
        <result property="id" column="ID" javaType="int" jdbcType="NUMBER" nullValue="0"/>
        <result property="capName" column="CAP_NAME" javaType="java.lang.String" jdbcType="VARCHAR2"/>
        <result property="description" column="DESCRIPTION" javaType="java.lang.String" jdbcType="VARCHAR2"/>
        <result property="yearBuilt" column="YEAR_BUILT" javaType="java.lang.String" jdbcType="VARCHAR2"/>
        <result property="orgId" column="ORG_ID" javaType="java.lang.String" jdbcType="VARCHAR2"/>
    </resultMap>


    <!-- ============================================= -->
    <!-- mapped statements for IbatisCapacityDAO -->
    <!-- ============================================= -->
    <!-- mapped statement for IbatisCapacityDAO.insert -->
    <insert id="MS-CAPACITY-INSERT">
    <selectKey resultClass="int" keyProperty="id">
    <![CDATA[
        select SEQ_CAPACITY.nextval from dual
    ]]>
    </selectKey>
    <![CDATA[
        insert into T_CAPACITY(ID,DESCRIPTION,CAP_NAME,YEAR_BUILT,ORG_ID) values (#id#, #description#, #capName#, #yearBuilt#, #orgId#)
    ]]>
    </insert>

    <!-- mapped statement for IbatisCapacityDAO.loadById -->
    <select id="MS-CAPACITY-LOAD-BY-ID" resultMap="RM-CAPACITY">
    <![CDATA[
        select ID, DESCRIPTION, CAP_NAME, YEAR_BUILT, ORG_ID from T_CAPACITY where (ID = #value#)
    ]]>
    </select>

    <!-- mapped statement for IbatisCapacityDAO.loadAll -->
    <select id="MS-CAPACITY-LOAD-ALL" resultMap="RM-CAPACITY">
        select * from (select T1.*, rownum linenum from (select ID, DESCRIPTION, CAP_NAME, YEAR_BUILT, ORG_ID from T_CAPACITY t
    <dynamic prepend="where">
     <isNotEmpty prepend="and" property="query.id">
     <![CDATA[
       ID = #query.id#
     ]]>
     </isNotEmpty>
     <isNotEmpty prepend="and" property="query.capName">
     <![CDATA[
       CAP_NAME like '%'||#query.capName#||'%'
     ]]>
     </isNotEmpty>
     <isNotEmpty prepend="and" property="query.yearBuilt">
     <![CDATA[
       YEAR_BUILT = #query.yearBuilt#
     ]]>
     </isNotEmpty>
     <isNotEmpty prepend="and" property="query.orgId">
     <![CDATA[
       ORG_ID = #query.orgId#
     ]]>
     </isNotEmpty>
    </dynamic>
    order by id desc) T1 where rownum &lt;= #endRow#) T2 where linenum &gt;= #startRow#
    </select>

    <!-- mapped statement for IbatisCapacityDAO.loadAll, needed by paging -->
    <select id="MS-CAPACITY-LOAD-ALL-COUNT-FOR-PAGING" resultClass="int">
        select count(*) from T_CAPACITY t
    <dynamic prepend="where">
     <isNotEmpty prepend="and" property="query.id">
     <![CDATA[
       ID = #query.id#
     ]]>
     </isNotEmpty>
     <isNotEmpty prepend="and" property="query.capName">
     <![CDATA[
       CAP_NAME like '%'||#query.capName#||'%'
     ]]>
     </isNotEmpty>
     <isNotEmpty prepend="and" property="query.yearBuilt">
     <![CDATA[
       YEAR_BUILT = #query.yearBuilt#
     ]]>
     </isNotEmpty>
     <isNotEmpty prepend="and" property="query.orgId">
     <![CDATA[
       ORG_ID = #query.orgId#
     ]]>
     </isNotEmpty>
    </dynamic>
    </select>

    <!-- mapped statement for IbatisCapacityDAO.loadAllNoPage -->
    <select id="MS-CAPACITY-LOAD-ALL-NO-PAGE" resultMap="RM-CAPACITY">
        select ID, DESCRIPTION, CAP_NAME, YEAR_BUILT, ORG_ID from T_CAPACITY t
    <dynamic prepend="where">
     <isNotEmpty prepend="and" property="query.id">
     <![CDATA[
       ID = #query.id#
     ]]>
     </isNotEmpty>
     <isNotEmpty prepend="and" property="query.capName">
     <![CDATA[
       CAP_NAME like '%'||#query.capName#||'%'
     ]]>
     </isNotEmpty>
     <isNotEmpty prepend="and" property="query.yearBuilt">
     <![CDATA[
       YEAR_BUILT = #query.yearBuilt#
     ]]>
     </isNotEmpty>
     <isNotEmpty prepend="and" property="query.orgId">
     <![CDATA[
       ORG_ID = #query.orgId#
     ]]>
     </isNotEmpty>
    </dynamic>
    </select>

    <!-- mapped statement for IbatisCapacityDAO.update -->
    <update id="MS-CAPACITY-UPDATE">
    <![CDATA[
        update T_CAPACITY set DESCRIPTION=#description#, CAP_NAME=#capName#, YEAR_BUILT=#yearBuilt#, ORG_ID=#orgId# where (ID = #id#)
    ]]>
    </update>

    <!-- mapped statement for IbatisCapacityDAO.deleteById -->
    <delete id="MS-CAPACITY-DELETE-BY-ID">
    <![CDATA[
        delete from T_CAPACITY where (ID = #value#)
    ]]>
    </delete>

    <!-- mapped statement for IbatisCapacityDAO.deleteByIds -->
    <delete id="MS-CAPACITY-DELETE-BY-IDS">
        delete T_CAPACITY where ID in
    <iterate open="(" close=")" conjunction=",">
    #[]#
    </iterate>
    </delete>

</sqlMap>

 

 

 

下面是 Account.xml 的一个 Statement:

清单 2. Account.xml 中一个 Statement
<select id="selectAccount" parameterClass="Account" resultClass="Account">
    select
      ACC_ID,
      ACC_FIRST_NAME as firstName,
      ACC_LAST_NAME as lastName,
      ACC_EMAIL as emailAddress,
      ACC_DATE
    from ACCOUNT
    where ACC_ID = #id:INTEGER# and ACC_FIRST_NAME = #firstName#
</select>

下面是 Java 的测试类:

清单 3. SimpleTest
public class SimpleTest {
    public static void main(String[] args) {
        ApplicationContext factory = 
        new ClassPathXmlApplicationContext("/com/mydomain/data/applicationContext.xml");
        final AccountDAO accountDAO = (AccountDAO) factory.getBean("accountDAO");
        final Account account = new Account();
        account.setId(1);
        account.setFirstName("tao");
        account.setLastName("bao");
        account.setEmailAddress("junshan@taobao.com");
        account.setDate(new Date());
        try {
            accountDAO.getSqlMapTransactionTemplate().execute(new TransactionCallback(){
                    public Object doInTransaction(TransactionStatus status){
                        try{
                            accountDAO.deleteAccount(account.getId());
                            accountDAO.insertAccount(account);
                            //account.setLastName("bobo");
                            //accountDAO.updateAccount(account);
                            Account result = accountDAO.selectAccount(account);
                            System.out.println(result);
                            return null;
                        } catch (Exception e) {
                            status.setRollbackOnly();
                            return false;
                        }
                    }
                });
            //accountDAO.getSqlMapClient().commitTransaction();
         } catch (Exception e) {
             e.printStackTrace();
         }
     }
}

iBATIS 对 SQL 语句的解析

这里所说的 SQL 解析只是针对 iBATIS 配置文件中所定义的 SQL 语句,如前一节中清单 2 中所示的查询语句。和标准的 SQL 语句不同的是,参数的赋值是“#“包裹的变量名。如何解析这个变量就是 iBATIS 要完成的工作。当然 SQL 的表达形式还有很多其他的形式如动态 SQL 等。

现在我们关心的是当我们执行:

清单 4. 执行查询方法
accountDAO.selectAccountById(account)

iBATIS 将会选择清单 2 这条 Statement 来解析,最终会把它解析成一个标准的 SQL 提交给数据库执行,并且会设置两个选择条件参数。这个过程中参数映射的细节是什么样子呢?

在前面的第二小节中已经说明了,iBATIS 会把 SqlMap 配置文件解析成一个个 Statement,其中包括 ParameterMap、ResultMap,以及解析后的 SQL。当 iBATIS 构建好 RequestScope 执行环境后,要做的工作就是把传过来的对象数据结合 ParameterMap 中信息提取出一个参数数组,这个数组的顺序就是对应于 SQL 中参数的顺序,然后会调用 preparedStatement.setXXX(i, parameter) 提交参数。

在清单 3 中,我们给 account 对象的 id 属性和 firstName 属性分别赋值为 1 和“tao“,当执行清单 4 中的这段代码时,iBATIS 必须把这两个属性值传给清单 2 中 SQL 语句中对象的参数。这个是怎么做到的,其实很简单,在图 3 中描述了与 ParameterMap 相关的类的关系,这些类中都保存了在 SqlMap 配置文件初始化是解析清单 2 中 Statement 的所有必要的信息,具体的信息是这样的:

最终的 SQL 语句是:

清单 5. 解析后的 SQL
select
    ACC_ID,
    ACC_FIRST_NAME as firstName,
    ACC_LAST_NAME as lastName,
    ACC_EMAIL as emailAddress,
    ACC_DATE
from ACCOUNT
where ACC_ID = ? and ACC_FIRST_NAME = ?

#id:INTEGER# 将被解析成 JDBC 类型是 INTEGER,参数值取 Account 对象的 id 属性。#firstName# 同样被解析成 Account 对象的 firstName 属性,而 parameterClass="Account"指明了 Account 的类类型。注意到清单 5 中 #id:INTEGER# 和 #firstName# 都被替换成“?”,iBATIS 如何保证它们的顺序?在解析清单 2 过程中,iBATIS 会根据“#”分隔符取出合法的变量名构建参数对象数组,数组的顺序就是 SQL 中变量出现的顺序。接着 iBATIS 会根据这些变量和 parameterClass 指定的类型创建合适的 dataExchange 和 parameterPlan 对象。parameterPlan 对象中按照前面的顺序保存了变量的 setter 和 getter 方法列表。

所以 parameter 的赋值就是根据 parameterPlan 中保存的 getter 方法列表以及传进来的 account 对象利用反射机制得到清单 5 对应的参数值数组,再将这个数组按照指定的 JDBC 类型提交给数据库。以上这些过程可以用图 6 的时序图清楚的描述:

图 6. 映射参数值到数据库过程时序图

图 6. 映射参数值到数据库过程时序图

上图 4 中在 8 步骤中如果 value 值为空时会设置 preparedStatement.setNull(i , jdbcType) 如果在清单 2 中的变量没有设置 jdbcType 类型时有可能会出错。


数据库字段映射到 Java 对象

数据库执行完 SQL 后会返回执行结果,在第 4 小节的例子中满足 id 为 1、firstName 为“tao”的信息有两条,iBATIS 如何将这两条记录设置到 account 对象中呢?

和 ParameterMap 类似,填充返回信息需要的资源都已经包含在 ResultMap 中。当有了保存返回结果的 ResultSet 对象后,就是要把列名映射到 account 对象的对应属性中。这个过程大体如下:

根据 ResultMap 中定义的 ResultClass 创建返回对象,这里就是 account 对象。获取这个对象的所有可写的也就是 setter 方法的属性数组,接着根据返回 ResultSet 中的列名去匹配前面的属性数组,把匹配结果构造成一个集合(resultMappingList),后面是选择 DataExchange 类型、AccessPlan 类型为后面的真正的数据交换提供支持。根据 resultMappingList 集合从 ResultSet 中取出列对应的值,构成值数组(columnValues),这个数组的顺序就是 SQL 中对应列名的顺序。最后把 columnValues 值调用 account 对象的属性的 setter 方法设置到对象中。这个过程可以用下面的时序图来表示:

图 7. 映射返回对象时序图

图 7. 映射返回对象时序图


示例运行的结果

前两个小节主要描述了输入参数和输出结果的映射原理,这里再结合第 4 小节的示例分析一下执行清单 3 代码的结果。

执行清单 3 所示代码打印的结果为:

清单 6. 示例程序的运行结果
Account{id=0, firstName='tao', lastName='bobo', emailAddress='junshan@taobao.com'}

上面的结果和我们预想的结果似乎有所不同,看代码我们插入数据库的 account 对象各属性值分别为 {1,“tao”,“bao”,“junshan@taobao.com”,“时间”},后面调用清单 2 的查询,返回应该是一样的结果才对。id 的结果不对、date 属性值丢失。再仔细看看清单 2 这个 Statement 可以发现,返回结果的列名分别是 {ACC_ID,firstName,lastName,emailAddress,ACC_DATE} 其中 id 和 date 并不能映射到 Account 类的属性中。id 被赋了默认数字 0,而 date 没有被赋值。

还有一个值得注意的地方是变量 id 后面跟上 JDBC 类型,这个 JDBC 类型有没有用?通常情况下都没有用,因此你可以不设,iBATIS 会自动选择默认的类型。但是如果你要这个这个值可能为空时如果没有指定 JDBC 类型可能就有问题了,在 Oracle 中虽然能正常工作但是会引起 Oracle 这当前这个 SQL 有多次编译现象,因此会影响数据库的性能。还有当同一个 Java 类型如果对应多个 JDBC 类型(如 Date 对应 JDBC 类型有 java.sql.Date、java.sql.Timestamp)就可以通过指定 JDBC 类型保存不同的值到数据库。


总结

如果用最简洁的话来总结 iBATIS 主要完成那些功能时,我想下面几个代码足够概括。

清单 7. 典型的 Java 操作数据库代码
Class.forName("oracle.jdbc.driver.OracleDriver"); 
Connection conn= DriverManager.getConnection(url,user,password);
java.sql.PreparedStatement  st = conn.prepareStatement(sql);
st.setInt(0,1);
st.execute();
java.sql.ResultSet rs =  st.getResultSet();
while(rs.next()){
    String result = rs.getString(colname);
}

iBATIS 就是将上面这几行代码分解包装,但是最终执行的仍然是这几行代码。前两行是对数据库的数据源的管理包括事务管理,3、4 两行 iBATIS 通过配置文件来管理 SQL 以及输入参数的映射,6、7、8 行是 iBATIS 获取返回结果到 Java 对象的映射,他也是通过配置文件管理。

配置文件对应到相应代码如图所示:

图 8. 配置文件与相应代码对应关系

图 8. 配置文件与相应代码对应关系

iBATIS 要达到目的就是把用户关心的和容易变化的数据放到配置文件中配置,方便用户管理。而把流程性的、固定不变的交给 iBATIS 来实现。这样是用户操作数据库简单、方便,这也是 iBATIS 的价值所在。

<!--CMA ID: 576855--><!--Site ID: 10--><!--XSLT stylesheet used to transform this file: dw-document-html-7.0.xsl-->

Hibernate框架:

         –update()方法:更新数据库中的Java对象。 

         –delete()方法:把Java对象从数据库中删除。 

          –get()方法:从数据库中加载Java对象。  

 然后在编写用session处理数据类DAO类,先编写有关接口然后编写实现类,这个类主要用session处理数据执行事务的类: 示例代码:  //调用工具类获得

session  Session session = factory.openSession(); 

Transaction tx;  try {  

//开始一个事务   tx = session.beginTransaction(); 

//执行事务  ... 

 //提交事务  tx.commit(); 

}   catch (Exception e)

         {  //如果出现异常,就撤销事务 

 if (tx!=null) tx.rollback(); 

         throw e;  }  finally {  

 

//不管事务执行成功与否,最后都关闭Session  session.close();  }  

 然后编写逻辑处理类(服务类):先写有关接口然后写实现类这个类主要用于处理一些逻辑处理,在这个地方主要用于调用数据处理类DAO进行数据处理

public class PersonServiceImpl implements PersonService

       { public void savePerson(Person person) { 

 PersonDAO personDAO = new PersonDAOImpl();

 personDAO.savePerson(person); } } 

然后直接在action里面写出PersonServiceImpl 实例进行调用其方法进行就可以了。Action里面主要处理方法代码示例:  public String execute() throws Exception

{  Person person = new Person();

     person.setUsername(username);

    person.setPassword(password);

    person.setAge(age); 

   java.sql.Date registerDate = new java.sql.Date(new java.util.Date().getTime());

   System.out.println("222222");

   person.setRegisterDate(registerDate); 

   PersonServiceImpl personService = new PersonServiceImpl();

   personService.savePerson(person); return SUCCESS; }  写到这,一个hibernate主要的逻辑层就差不多了,现在就主要看怎样写配置文件了:先配置hibernate.cfg.xml.主要配置示例: 

 <?xml version='1.0' encoding='UTF-8'?>

<!DOCTYPE hibernate-configuration PUBLIC            "-//Hibernate/Hibernate Configuration DTD 3.0//EN"            "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">  

 <hibernate-configuration>  

<session-factory>   

<property name="connection.url">jdbc:sqlserver://localhost:1433;  DatabaseName=Hibernate</property>     

 <property name="connection.username">sa</property>   

  <property name="connection.password">123456</property>    

 <property  name="connection.driver_class">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>     

<property name="dialect">org.hibernate.dialect.SQLServerDialect</property>    

<property name="show_sql">true</property>     

<mapping resource="Person.hbm.xml"/>//映射到具体person表的配置文件   </session-factory>    </hibernate-configuration>  注:  Hibernate的描述文件中存放数据库连接驱动程序类,登陆数据库的用户名/密码,映射实体类配置文件的位置等信息。  •将该配置文件存放在src目录下  最后一步:  对持久化(实体)类Person.java文件创建一个Hibernate映射文件Person.hbm.xml  Java的实体类是通过配置文件与数据表中的字段相关联。Hibernate在运行时解析配置文件,根据其中的字段名生成相应的SQL语句  •将该文件存放在src目录下  具体代码示例: 

 <?xml version="1.0"?>  <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  

 <hibernate-mapping>     

 <class name="com.csh.model.Person" table="person">       

 <id name="id" column="id"  type="int">          

<generator class="increment"></generator>          </id>      

 <property name="username" column="username" type="string"></property>     

 <property name="password" column="password" type="string"></property>     

<property name="age" column="age" type="int"></property>      

<property name="registerDate" column="registerDate" type="date"></property>    

</class> 

</hibernate-mapping>  注:id元素对应的一定是数据库的主键列;class="increment"意为自增 <property>元素映射值类型属性  •name属性:指定持久化类的属性的名字。   •type属性:指定Hibernate或Java映射类型。Hibernate映射类型是Java类型与SQL类型的桥梁。   •column属性:指定与类的属性映射的表的字段名。   

 

  

 

分享到:
评论

相关推荐

    SpringMVC框架架构介绍

    三、spring mvc 核心流程图 四、spring mvc DispatcherServlet说明 五、spring mvc 双亲上下文的说明 六、springMVC-mvc.xml 配置文件片段讲解 七、spring mvc 如何访问到静态的文件,如jpg,js,css? 八、spring ...

    Spring MVC+MyBatis开发从入门到项目实战

    第3篇是Spring MVC技术入门,包括Spring MVC的背景介绍、架构整体剖析、环境搭建、处理器与映射器的讲解、前端控制器的源码分析、多种视图解析器的介绍、请求映射与参数绑定的介绍、Validation校验与异常处理和拦截...

    基于jpa+hibernate+spring+spring mvc注解方式项目

    基于jpa+hibernate+spring+spring mvc注解方式项目案例带整体架构及一个页面操作小流程适合新手

    全面掌握Spring MVC:从基础到高级的实践指南

    本文通过分析Spring MVC的核心组件和执行流程,提供了一个全面的学习指南。 Spring MVC基于Model-View-Controller(MVC)架构模式,优化了Web应用程序的设计和开发。在Spring MVC中,DispatcherServlet作为前端控制...

    21道Java Spring MVC综合面试题详解含答案(值得珍藏)

    基于MVC架构模式,有助于将web层进行职责解耦。 容易理解上手快,使用简单。Spring MVC支持注解,可以简化开发。 作为Spring的一部分,能够使用Spring框架的IOC容器和Aop编程。 方便整合Struts、MyBatis、Hibernate...

    SSM框架原理 spring-mvc执行流程

    SSM框架是spring MVC ,spring和mybatis框架的整合,是标准的MVC模式,将整个系统划分为controller层,service层,mapper层三层,通常称为三层架构 使用spring MVC负责请求的转发和视图管理 spring实现业务对象管理...

    深入解析Spring+MVC与Web+Flow.pdf

    Yalcs是.J2EE主架构师,Donald是SpringWeb Flow负责人,Hartop是Spring与Tomcat成产品负责人。“《深入解析Spring MVCgn Web Flow》为Spring社区弥补了一大空白。” ——Lasse Koskela.JavaRanch版主,Test Driven...

    spring+spring mvc+mybatis+mysql+dubbo整合开发任务流程后台管理系统.zip

    spring+spring mvc+mybatis+mysql+dubbo整合开发任务流程后台管理系统.zip

    基于Web的线上外卖订餐(JAVA+JSP+MYSQL+Spring MVC+Hibernate+Spring+文档).zip

    本系统基于B/S架构,采用Spring MVC+Hibernate+Spring作为开发框架,以MySQL为数据库,Tomcat为服务器,实现了订餐消费者、商家和管理员三类用户的各种功能。经测试,该系统不仅令消费者订餐更为便捷、选择更为丰富...

    图解springMVC执行流程及原理.docx

    使用 Spring 可插入的 MVC架构,从而在使用Spring进行WEB开发时,可以选择使用Spring的Spring MVC框架或集成其他MVC开发框架。 SpringMVC执行流程概括 SpringMVC框架固然强大,但是其执行流程更是妙不可言。所以我们...

    SpringMVC常见知识点.md

    MVC是一种设计模式,遵循 模型(Model),视图(View) 和 控制器(Controller)的架构设计。 MVC的优点很明显: 应用层次分明,职责分明,使得系统的耦合性降低,并有利于系统的维护。 什么是 Spring MVC? Spring MVC是一...

    民宿网站管理系统java+spring.7z,架构是SSM

    Spring MVC 内置了 Requestmapping、HandlerMapping 和 ViewResolver 等组件,可以简化开发流程。MyBatis 作为持久层框架,负责处理数据库操作。 在安全性方面,该网站采用了 SSL 证书进行加密传输,并实现了用户...

    图书管理系统( Spring+Spring MVC+JdbcTemplate).zip

    计算机硬件系统: 计算机硬件...综上所述,计算机领域的“系统”概念广泛涉及硬件架构、软件层次、信息管理、网络通信、分布式计算以及安全保障等多个方面,它们相互交织,共同构成了现代计算机技术的复杂生态系统。

    Spring Boot与Feign:微服务架构下的优雅通信

    通过本文,读者将能够轻松掌握Feign在Spring Boot微服务架构中的应用。 Feign是一个声明式的Web Service客户端,它使得编写HTTP客户端变得更简单。使用Feign,只需要创建一个接口并注解,它具有可插拔的注解特性,...

    SSM图书管理系统(高分毕设).zip

    它采用MVC(Model-View-Controller,模型-视图-控制器)的架构模式,将应用程序分为模型层、视图层和控制器层,提供了处理请求、渲染视图和管理流程的功能。 MyBatis框架:MyBatis是一个持久层框架,

    基于SpringBoot微服务架构下的MVC模型研究_张雷.pdf

    微服务概念改变着软件开发领域,传统的开源框架结构开发,由于其繁琐的配置流程,复杂的设置行为,为项目的开发增加了繁重的工作量,微服务致力于解决除业务逻辑以外的开发工作量的精简与废除,集约化的改善开发环境和开发...

    基于ssm的网上求职招聘管理系统(95分以上课程大作业).zip

    它采用MVC(Model-View-Controller,模型-视图-控制器)的架构模式,将应用程序分为模型层、视图层和控制器层,提供了处理请求、渲染视图和管理流程的功能。 MyBatis框架:MyBatis是一个持久层框架,用于与数据库...

    基于SSM框架的高校考研资讯网(高分毕设).zip

    它采用MVC(Model-View-Controller,模型-视图-控制器)的架构模式,将应用程序分为模型层、视图层和控制器层,提供了处理请求、渲染视图和管理流程的功能。 MyBatis框架:MyBatis是一个持久层框架,用于与数据库...

    基于SSM的商城购物系统(95分以上课程大作业).zip

    它采用MVC(Model-View-Controller,模型-视图-控制器)的架构模式,将应用程序分为模型层、视图层和控制器层,提供了处理请求、渲染视图和管理流程的功能。 MyBatis框架:MyBatis是一个持久层框架,用于与数据库...

Global site tag (gtag.js) - Google Analytics