您的位置:首页 > 编程语言 > Java开发

springmvc camel mybatis集成实例及分析

2013-03-27 21:10 330 查看
最近在学习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类搞定。

最后附上整个例子的源代码供童鞋们下载交流。项目在我的资源栏目里,当然是免积分的了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: