springmvc camel mybatis集成实例及分析

本文介绍如何利用 Camel 框架简化数据库 CRUD 操作,通过配置 spring 和 mybatis,实现通用的 service 层,减少重复代码,提高开发效率。通过 Camel 的 API 调用 mybatis 进行数据交互,实现实体类操作的统一管理。

转自:http://blog.youkuaiyun.com/fanly1987444/article/details/8726329

最近在学习camel,公司之前做过的项目使用到了camel进行了很多工作。就连数据库的操作也是通过camel来完成的。至于用camel来操作数据库有什么优点,目前就我自己的体会来说,利用camel能简化CRUD操作service层的代码。没用camel以前,各个对象的CRUD操作我都会有对应的service去处理。即使这些service很多都只是简单地继承一个CrudServcie然后用泛型限制一下该service处理的实体对象。这样service的接口和实现类看上去很多,但是重复率极高。如果使用了camel,那么我们就可以用camel来写一个通用的service,这样不管你是什么实体类的操作,只要传入类型和要调用的方法名就可以了。由于涉及到公司机密,所以我不会贴出成熟的源代码,但是我可以提供一个自己的列子。我想只要从这个列子出发,稍作改进就能达到上文所提的效果。

例子的架构是这样的:springmvc camel mybatis
依赖由maven来管理,其pom.xml的内容请下载列子源代码查看。
springmvc的配置就不用贴出来了,随处可见。
这里重点讲一下spring跟配置文件里的一些配置项目,尤其是下面这一段:
[html]  view plain copy
  1. <!-- 数据源配置 使用事务控制 -->  
  2.     <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"  
  3.         destroy-method="close">  
  4.         <property name="driverClassName" value="com.mysql.jdbc.Driver" />  
  5.         <property name="url" value="jdbc:mysql://localhost:3306/test?characterEncoding=utf-8" />  
  6.         <property name="username" value="root" />  
  7.         <property name="password" value="fanly" />  
  8.         <property name="defaultAutoCommit" value="false" />  
  9.     </bean>  
  10.   
  11.     <bean id="transactionManager"  
  12.         class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
  13.         <property name="dataSource" ref="myDataSource" />  
  14.     </bean>  
  15.     <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">  
  16.         <property name="dataSource" ref="myDataSource" />  
  17.         <property name="configLocation" value="classpath:SqlMapConfig.xml" />  
  18.     </bean>  
  19.     <bean id="required" class="org.apache.camel.spring.spi.SpringTransactionPolicy">  
  20.         <property name="transactionManager" ref="transactionManager" />  
  21.         <property name="propagationBehaviorName" value="PROPAGATION_REQUIRED" />  
  22.     </bean>  
  23.     <bean id="mybatis" class="org.apache.camel.component.mybatis.MyBatisComponent">  
  24.         <property name="sqlSessionFactory" ref="sqlSessionFactory" />  
  25.     </bean>  
  26.     <!-- 数据源配置结束 -->  
需要注意的是最后一项的配置,通过MyBatisComponent类,camel就知道如何通过用户设置的路由来和mybatis进行交互了。这个MyBatisComponent实现了camel的component接口,至于component接口是用来干什么的,可以参考我的博文或者去查看官方手册。其实你可以把component简单里理解为camelContext和其他系统通信的标准,不同的系统实现了component接口,就可以通过这个接口实现用camel标准API进行通信。
这里需要注意的是,MyBatisComponent有一个configurationUri属性,他的默认值为SqlMapConfig.xml,也就是说在默认情况下MyBatisComponent会去加载类路径下的SqlMapConfig.xml去初始化一些配置和用户编写的mapper文件,你当然可以修改这个默认行为,怎么修改呢?通过property注入你的配置文件位置呗。这里需要指出的是,之前我们单独使用mybatis的时候,一种方式是定义一个mapper接口,然后在对应的mapper.xml中将该mapper问价的namespace设置为mapper接口的全路径,这样在运行时,mybatis会利用mapper.xml生成的代理类来作为mapper接口的实现类为程序提供数据访问层的服务。那么我们使用MyBatisComponent来和数据库交互的时候,还要不要定义mapper接口呢?事实证明,我们不再需要定义mapper接口,我们只需要实现mapper.xml即可,那么MyBatisComponent是如何加载到我们所实现的mapper.xml的呢?我们只要在SqlMapConfig.xml中指定我们的mapper.xml文件即可。本实例代码的SqlMapConfig.xml文件内容如下所示:
[html]  view plain copy
  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">  
  3.   
  4. <configuration>  
  5.   
  6.     <settings>  
  7.         <setting name="cacheEnabled" value="true" />  
  8.     </settings>  
  9.   
  10.     <mappers>  
  11.         <mapper resource="com/ugarden/mapper/UserMapper.xml" />  
  12.     </mappers>  
  13.       
  14. </configuration>  
我们再看看UserMapper.xml的内容:
[html]  view plain copy
  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >  
  3.   
  4. <mapper namespace="com.ugarden.repository.UserMapper">  
  5.   
  6.     <resultMap id="UserResult" type="com.ugarden.entity.User">  
  7.         <result property="id" column="id" />  
  8.         <result property="email" column="email" />  
  9.         <result property="realName" column="real_name" />  
  10.         <result property="password" column="password" />  
  11.     </resultMap>  
  12.   
  13.     <sql id="columns">  
  14.        <![CDATA[ 
  15.           id,password,email,show_name,real_name 
  16.          ]]>  
  17.     </sql>  
  18.   
  19.     <insert id="batchInsertUsers" parameterType="list" useGeneratedKeys="false">  
  20.     <![CDATA[ 
  21.         INSERT INTO kf_user ( 
  22.             id , 
  23.             password , 
  24.             email , 
  25.             real_name 
  26.         ) VALUES  
  27.       ]]>  
  28.     <foreach collection="list" item="item" separator=",">  
  29.       <![CDATA[ 
  30.           (  
  31.             #{item.id} , 
  32.             #{item.password} , 
  33.             #{item.email} , 
  34.             #{item.realName}  
  35.           ) 
  36.         ]]>  
  37.     </foreach>  
  38.     </insert>  
  39.   
  40.     <insert id="insert" parameterType="com.ugarden.entity.User" useGeneratedKeys="false" keyProperty="id">  
  41.     <![CDATA[ 
  42.         INSERT INTO kf_user ( 
  43.             id , 
  44.             password , 
  45.             email , 
  46.             real_name  
  47.         ) VALUES ( 
  48.             #{id} , 
  49.             #{password} , 
  50.             #{email} , 
  51.             #{realName}  
  52.         ) 
  53.     ]]>  
  54.     </insert>  
  55.   
  56.     <update id="update" parameterType="com.ugarden.entity.User">  
  57.     <![CDATA[ 
  58.         UPDATE kf_user SET 
  59.             password = #{password} , 
  60.             email = #{email} , 
  61.             real_name = #{realName} , 
  62.         WHERE  
  63.             id = #{id} 
  64.     ]]>  
  65.     </update>  
  66.   
  67.     <delete id="deleteUsersRolesById" parameterType="string">  
  68.      <![CDATA[ 
  69.         DELETE FROM kf_user_role 
  70.         WHERE  
  71.           user_id = #{userId} 
  72.       ]]>  
  73.     </delete>  
  74.   
  75. </mapper>  


我们在这里也设置了 namespace="com.ugarden.repository.UserMapper",但是我的项目里是没有对应的接口的,这里不设置会不会出问题在写本文的时候还没有试验。写上总是好些,免得让人感到迷茫。
那么我们如何通过camel的API来操作数据库呢?下面是UserServcie.java的内容:

[java]  view plain copy
  1. @Service  
  2. public class UserService {  
  3.     @Autowired  
  4.     private ProducerTemplate producerTemplate;  
  5.     @Autowired  
  6.     private CamelContext camelContext;  
  7.       
  8.     public void insertUser() throws Exception {  
  9.           
  10.         //init test user entity  
  11.         User user = new User();  
  12.         user.setEmail("fanly" + System.currentTimeMillis() + "@126.com");  
  13.         user.setPassword("123456");  
  14.         user.setId(String.valueOf(System.currentTimeMillis()));  
  15.         user.setRealName("张双");  
  16.           
  17.         Exchange in = this.camelContext.getEndpoint("direct:start").createExchange(ExchangePattern.InOut);  
  18.         in.getIn().setBody(user);  
  19.           
  20.         Exchange out = this.producerTemplate.send("mybatis:insert?statementType=Insert", in);  
  21.           
  22.         if (null != out.getException()) {  
  23.             throw out.getException();  
  24.         }  
  25.           
  26.     }  
  27. }  


略懂camel的童鞋们立马就明白了,这里首先通过camelContext获取到一个Endpoint,然后获取到输入过程的Exchange对象,由于数据的来源是我们程序提供的,所以endpoint的uri就设置为direct:start。然后将我们要添加的user对象添加到message对象的body中,再将我们的message对象路由到数据库中,我们是通过producerTemplate对象向camelContext对象发出消息的,路由信息附加在了第一个参数中,即"mybatis:insert?statementType=Insert"如果你不懂这个参数的意思,去camel官方看看camel-mybatis的说明就明白了。这句的意思大概就是告诉camelContext对象,我要通过mybatis这个component对象调用一个名叫insert的方法,该方法的statement类型为Insert类型,将Message对象body里的数据插入到数据库。
你可能会问,你这个service里面的producerTemplate,camelContext是哪里来的,为什么你通过一个"mybatis:insert?statementType=Insert"参数,camelContext就知道要去找那个component来进行路由呢?
莫慌,请看spring根配置文件的如下配置内容:
[html]  view plain copy
  1. <!-- camel context inti -->  
  2. <camelContext id="camel" trace="true" xmlns="http://camel.apache.org/schema/spring">  
  3.     <package>com.ugarden</package>  
  4. lt;/camelContext>  
camelContext就是这样来的,spring一启动的时候他就存在了,如果你有多个camelContext实例的时候,你就要用id来区分注入了。
那producerTemplate是哪里来的呢?刚开始我也纠结这个问题,最后看了一下camelContext的createProducerTemplate的方法注释,发现它是和camelContext一起初始化的,这样就能解释为什么spring能帮我们注入了。
那camel如何知道"mybatis:insert?statementType=Insert"中mybatis指的是哪个呢?您还记得这段配置吗?
[html]  view plain copy
  1. <bean id="mybatis" class="org.apache.camel.component.mybatis.MyBatisComponent">  
  2.     <property name="sqlSessionFactory" ref="sqlSessionFactory" />  
  3.  </bean>  
你看看他的ID,我想如果有多个数据源的时候,我再做如下配置:
[html]  view plain copy
  1. <bean id="mybatis1" class="org.apache.camel.component.mybatis.MyBatisComponent">  
  2.     <property name="sqlSessionFactory" ref="sqlSessionFactory" />  
  3.  </bean>  
那么我是不是可以通过"mybatis1:insert?statementType=Insert"这样来路由呢?是不是试过才知道,写完我就去试一试,camel官方的uri支持范围里是绝对没有mybatis1这种东西的。

现在回到文章开始的问题来,我们如何通过camel来做一个统一的service层呢?很简单,我们只需要将要调用的方法名,body里要路由到数据库的对象,通过参数的方式传递进来不就可以容纳一切变化了吗?从此以后我们只需要通过数据表生成以下mapper.xml,再谢谢特殊的sql就好了。只要是数据库的操作,我们都可以通过camel实现的一个superService类搞定。
最后附上整个例子的源代码供童鞋们下载交流。项目在我的资源栏目里,当然是免积分的了。


资源下载:http://download.youkuaiyun.com/detail/fanly1987444/5187106

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值