• springmvc camel mybatis集成实例及分析


    最近在学习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跟配置文件里的一些配置项目,尤其是下面这一段:
    <!-- 数据源配置 使用事务控制 -->
        <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"
    		destroy-method="close">
    		<property name="driverClassName" value="com.mysql.jdbc.Driver" />
    		<property name="url" value="jdbc:mysql://localhost:3306/test?characterEncoding=utf-8" />
    		<property name="username" value="root" />
    		<property name="password" value="fanly" />
    		<property name="defaultAutoCommit" value="false" />
    	</bean>
    
        <bean id="transactionManager"
            class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="myDataSource" />
        </bean>
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="myDataSource" />
            <property name="configLocation" value="classpath:SqlMapConfig.xml" />
        </bean>
        <bean id="required" class="org.apache.camel.spring.spi.SpringTransactionPolicy">
            <property name="transactionManager" ref="transactionManager" />
            <property name="propagationBehaviorName" value="PROPAGATION_REQUIRED" />
        </bean>
        <bean id="mybatis" class="org.apache.camel.component.mybatis.MyBatisComponent">
            <property name="sqlSessionFactory" ref="sqlSessionFactory" />
        </bean>
        <!-- 数据源配置结束 -->
    需要注意的是最后一项的配置,通过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文件内容如下所示:
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
    
    <configuration>
    
    	<settings>
    		<setting name="cacheEnabled" value="true" />
    	</settings>
    
    	<mappers>
    		<mapper resource="com/ugarden/mapper/UserMapper.xml" />
    	</mappers>
    	
    </configuration>
    我们再看看UserMapper.xml的内容:
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
    
    <mapper namespace="com.ugarden.repository.UserMapper">
    
    	<resultMap id="UserResult" type="com.ugarden.entity.User">
    		<result property="id" column="id" />
    		<result property="email" column="email" />
    		<result property="realName" column="real_name" />
    		<result property="password" column="password" />
    	</resultMap>
    
    	<sql id="columns">
           <![CDATA[
              id,password,email,show_name,real_name
             ]]>
    	</sql>
    
    	<insert id="batchInsertUsers" parameterType="list" useGeneratedKeys="false">
        <![CDATA[
            INSERT INTO kf_user (
             	id ,
            	password ,
            	email ,
            	real_name
            ) VALUES 
          ]]>
    	<foreach collection="list" item="item" separator=",">
          <![CDATA[
         	  ( 
         	  	#{item.id} ,
            	#{item.password} ,
            	#{item.email} ,
            	#{item.realName} 
              )
       	    ]]>
    	</foreach>
    	</insert>
    
    	<insert id="insert" parameterType="com.ugarden.entity.User" useGeneratedKeys="false" keyProperty="id">
        <![CDATA[
            INSERT INTO kf_user (
            	id ,
            	password ,
            	email ,
            	real_name 
            ) VALUES (
            	#{id} ,
            	#{password} ,
            	#{email} ,
            	#{realName} 
            )
        ]]>
    	</insert>
    
    	<update id="update" parameterType="com.ugarden.entity.User">
        <![CDATA[
            UPDATE kf_user SET
    	        password = #{password} ,
    	        email = #{email} ,
    	        real_name = #{realName} ,
            WHERE 
            	id = #{id}
        ]]>
    	</update>
    
    	<delete id="deleteUsersRolesById" parameterType="string">
    	 <![CDATA[
            DELETE FROM kf_user_role
            WHERE 
              user_id = #{userId}
    	  ]]>
    	</delete>
    
    </mapper>


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

    @Service
    public class UserService {
    	@Autowired
    	private ProducerTemplate producerTemplate;
    	@Autowired
    	private CamelContext camelContext;
    	
    	public void insertUser() throws Exception {
    		
    		//init test user entity
    		User user = new User();
    		user.setEmail("fanly" + System.currentTimeMillis() + "@126.com");
    		user.setPassword("123456");
    		user.setId(String.valueOf(System.currentTimeMillis()));
    		user.setRealName("张双");
    		
    		Exchange in = this.camelContext.getEndpoint("direct:start").createExchange(ExchangePattern.InOut);
    		in.getIn().setBody(user);
    		
    		Exchange out = this.producerTemplate.send("mybatis:insert?statementType=Insert", in);
    		
    		if (null != out.getException()) {
    			throw out.getException();
    		}
    		
    	}
    }


    略懂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根配置文件的如下配置内容:
     <!-- camel context inti -->
     <camelContext id="camel" trace="true" xmlns="http://camel.apache.org/schema/spring">
        	<package>com.ugarden</package>
    </camelContext>
    camelContext就是这样来的,spring一启动的时候他就存在了,如果你有多个camelContext实例的时候,你就要用id来区分注入了。
    那producerTemplate是哪里来的呢?刚开始我也纠结这个问题,最后看了一下camelContext的createProducerTemplate的方法注释,发现它是和camelContext一起初始化的,这样就能解释为什么spring能帮我们注入了。
    那camel如何知道"mybatis:insert?statementType=Insert"中mybatis指的是哪个呢?您还记得这段配置吗?
    <bean id="mybatis" class="org.apache.camel.component.mybatis.MyBatisComponent">
        <property name="sqlSessionFactory" ref="sqlSessionFactory" />
     </bean>
    你看看他的ID,我想如果有多个数据源的时候,我再做如下配置:
    <bean id="mybatis1" class="org.apache.camel.component.mybatis.MyBatisComponent">
        <property name="sqlSessionFactory" ref="sqlSessionFactory" />
     </bean>
    那么我是不是可以通过"mybatis1:insert?statementType=Insert"这样来路由呢?是不是试过才知道,写完我就去试一试,camel官方的uri支持范围里是绝对没有mybatis1这种东西的。

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


  • 相关阅读:
    【UOJ #268】【清华集训2016】数据交互(动态DP)
    【UOJ #267】【清华集训2016】魔法小程序(前缀和)
    【UOJ #266】【清华集训2016】Alice和Bob又在玩游戏(SG函数+01Trie)
    【CSP-S 2019题解】
    【CSP 2019游记】
    【CSP-S 2019模拟题解】
    sql语句: update和sql函数的冲突
    http协议之实践巩固(深度篇一)
    不错的开发工具做下记录
    javascrpt之this指向问题
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/2985704.html
Copyright © 2020-2023  润新知