欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

spring和mybatis泛型接口的整合(一)

程序员文章站 2024-01-24 22:20:34
...
1、这次使用spring和mybatis进行整合,使用spring的注解和自动扫描的方式将mybatis装载到程序中去。
2、首先看整个的工程包的截图
spring和mybatis泛型接口的整合(一)
            
    
    博客分类: SSH+i/mbatis spring mybatis 泛型接口编程 
3、先来分析spring.mybatis.orm包下的类
1)、SqlMapl类属于数据库标识接口,用于spring中的配置使用。
package spring.mybatis.orm;
/**
 * 数据库访问标识接口
 *@author TonyJ
 *@time 2015-1-31 下午03:41:17
 *@email tanglongjia@126.com
 */
public interface SqlMap {
}

2)、BaseSqlMap类,操作数据库的通用方法接口
package spring.mybatis.orm;
/**
 *@author TonyJ
 *@time 2015-1-31 下午03:45:52
 *@email tanglongjia@126.com
 */
public interface BaseSqlMap<T extends BaseEntity> extends SqlMap {

	/**
	 * 保存
	 */
	public static final String SQL_INSERT=".insert";
	
	/**
	 * 删除
	 */
	public static final String SQL_DELETE=".delete";
	
	/**
	 * 更新
	 */
	public static final String SQL_UPDATE=".update";
	
	/**
	 * 根据Id查询
	 */
	public static final String SQL_SELECT_SINGLE = ".selectSingle";
	
	/**
	 * 查询单个
	 * @param param
	 * @return
	 */
	T selectSingle(Object param);
	
	/**
	 * 保存
	 * @param entity
	 * @return
	 */
	T insert(T entity);
	
	/**
	 * 更新
	 * @param entity
	 * @return
	 */
	boolean update(T entity);
	
	/**
	 * 删除一个
	 * @param param
	 * @return
	 */
	boolean delete(Object param);
	
}

3)、BaseEntity类,通用的实体类定义一些通用的属性
package spring.mybatis.orm;

import java.io.Serializable;
import java.util.Date;

/**
 *@author TonyJ
 *@time 2015-1-31 下午03:37:46
 *@email tanglongjia@126.com
 */
public class BaseEntity implements Serializable,Cloneable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 2413960745071474764L;
	
	/**
	 *标识Id 
	 */
	private long id;
	
	/**
	 * 用户名
	 */
	private String userName;
	
	/**
	 * 创建时间
	 */
	private Date createTime;
	
	/**
	 * 更新时间
	 */
	private Date updateTime;

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public Date getCreateTime() {
		return createTime;
	}

	public void setCreateTime(Date createTime) {
		this.createTime = createTime;
	}

	public Date getUpdateTime() {
		return updateTime;
	}

	public void setUpdateTime(Date updateTime) {
		this.updateTime = updateTime;
	}
	
}

4)、MyBatisDao类,通用方法的实现类
package spring.mybatis.orm;

import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;

import spring.mybatis.utils.ReflectHelper;


/**
 *@author TonyJ
 *@time 2015-1-31 04:43:08
 *@email tanglongjia@126.com
 */
public class MyBatisDao<T extends BaseEntity>  implements BaseSqlMap<T> {

	private static final Logger logger = Logger.getLogger(MyBatisDao.class);
    
	protected Class<T> entityClass;
	
	@Autowired
	protected SqlSessionTemplate sqlSession;
	
	@SuppressWarnings("unchecked")
	public MyBatisDao(){
		this.entityClass = ReflectHelper.getSuperClassGenericType(getClass(), 0);
	}
	
	public SqlSession getSqlSession(){
		return sqlSession;
	}
	
	
	public void setSqlSession(SqlSessionTemplate sqlSession) {
		this.sqlSession = sqlSession;
	}
	
	@Override
	public T selectSingle(Object param) {
		if(null == param){
            logger.error("非法参数:param为空!");
            throw new IllegalArgumentException("非法参数:param为空!");
        }
        T result = null;
        try{
            result = getSqlSession().selectOne(entityClass.getName()+SQL_SELECT_SINGLE, param);
        }catch(Throwable e){
            logger.error(e);
        }
        return result;
	}

	@Override
	public T insert(T entity) {
		if(null == entity){
            logger.error("参数对象为null!");
            throw new IllegalArgumentException("参数不可为null!");
        }
	    try{
            getSqlSession().insert(entityClass.getName()+SQL_INSERT, entity);
        }catch(Throwable e){
            logger.error(e);
            return null;
        }
		
		return entity;
	}

	@Override
	public boolean update(T entity) {
		if(null == entity){
            throw new IllegalArgumentException("参数不可为null!");
        }
        try{
            getSqlSession().update(entityClass.getName()+SQL_UPDATE, entity);
        }
        catch (Exception e) {
           logger.error("更新数据异常:", e);
           return false;
        }
        return true;
	}

	@Override
	public boolean delete(Object param) {
		try{
	        getSqlSession().delete(entityClass.getName()+SQL_DELETE, param);
	    }catch (Exception e) {
	        logger.error("删除数据异常:",e);
            return false;
        }
	    return true;
	}

}

5)、ReflectHelper类,工具类,通过java反射,获得定义类时声明的基类(父类)的泛型参数的类型.
package spring.mybatis.utils;

/*
 * 文件名:ReflectHelper.java
 *
 * �? 能: 利用java反射机制,提供访问类的详细信息和类对象的工具方法�?
 * �? 名: ReflectHelper
 *
 **/

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import org.apache.log4j.Logger;

/**
 * 
 * <b>本类�?利用java反射机制,提供访问类的详细信息和类对象的工具类�?
 * </b><br><br>
 * <em>
 * <b>功能�?/b>利用java反射机制,提供访问类的详细信息和类对象的工具方法�?
 * 
 * </em>
 *
 */
public class ReflectHelper {  
	
	private static final Logger log = Logger.getLogger(ReflectHelper.class);
	
    /** 
     * 获取obj对象fieldName的Field 
     * @param obj 
     * @param fieldName 
     * @return 
     */  
    public static Field getFieldByFieldName(Object obj, String fieldName) {  
        for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass  
                .getSuperclass()) {  
            try {  
                return superClass.getDeclaredField(fieldName);  
            } catch (NoSuchFieldException e) {  
            }  
        }  
        return null;  
    }  
  
    /** 
     * 获取obj对象fieldName的属性�? 
     * @param obj 
     * @param fieldName 
     * @return 
     * @throws SecurityException 
     * @throws NoSuchFieldException 
     * @throws IllegalArgumentException 
     * @throws IllegalAccessException 
     */  
    public static Object getValueByFieldName(Object obj, String fieldName)  
            throws SecurityException, NoSuchFieldException,  
            IllegalArgumentException, IllegalAccessException {  
        Field field = getFieldByFieldName(obj, fieldName);  
        Object value = null;  
        if(field!=null){  
            if (field.isAccessible()) {  
                value = field.get(obj);  
            } else {  
                field.setAccessible(true);  
                value = field.get(obj);  
                field.setAccessible(false);  
            }  
        }  
        return value;  
    }  
  
    /** 
     * 设置obj对象fieldName的属性�? 
     * @param obj 
     * @param fieldName 
     * @param value 
     * @throws SecurityException 
     * @throws NoSuchFieldException 
     * @throws IllegalArgumentException 
     * @throws IllegalAccessException 
     */  
    public static void setValueByFieldName(Object obj, String fieldName,  
            Object value) throws SecurityException, NoSuchFieldException,  
            IllegalArgumentException, IllegalAccessException {  
        Field field = obj.getClass().getDeclaredField(fieldName);  
        if (field.isAccessible()) {  
            field.set(obj, value);  
        } else {  
            field.setAccessible(true);  
            field.set(obj, value);  
            field.setAccessible(false);  
        }  
    }  
    /**
	 * 通过java反射,获得定义类时声明的基类(父类)的泛型参数的类型.
	 * 如类声明:public UserDao extends HibernateDao &lt;com.mass.demo.User&gt; ...,�?
	 * 调用本方法语句getSuperClassGenericType(UserDao.class,0)返回User.class.
	 * 
	 * @param clazz - 子类Class
	 * @param index - 基类层级
	 * @return 基类(父类)的泛型参数的类型
	 */
    @SuppressWarnings("unchecked")
	public static Class getSuperClassGenericType(final Class clazz, final int index){
    	Type genericType = clazz.getGenericSuperclass();
    	if(!(genericType instanceof ParameterizedType)){
    		return Object.class;
    	}
    	Type[] params = ((ParameterizedType) genericType).getActualTypeArguments();
    	
    	
    	if(index>=params.length || index < 0){
    		log.warn("Index:"+index+",size of "+clazz.getSimpleName()+"'s Parameterize Type:"+params.length);
    		return Object.class;
    	}
    	if(!(params[index] instanceof Class)){
    		return Object.class;
    	}
    	return (Class)params[index]; 
    }
}  



接下来通过具体的实例来分析整合过程,使用一个用户表ad_user包含字段id、username、password。

4、根据表建立实体bean和mybatis的sql.xml文件配置
User类需要继承BaseEntity
package spring.mybatis.bean;

import spring.mybatis.orm.BaseEntity;

/**
 *@author TonyJ
 *@time 2015-1-31 下午04:57:54
 *@email tanglongjia@126.com
 */
public class User extends BaseEntity {

	/**
	 * 
	 */
	private static final long serialVersionUID = 6305819764075546164L;

	/**
	 * 密码
	 */
	private String password;

	public void setPassword(String password) {
		this.password = password;
	}

	public String getPassword() {
		return password;
	}
}


user.sqlMap.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="spring.mybatis.bean.User">
	
	<resultMap type="spring.mybatis.bean.User" id="userResult">
		<result property="id" column="id" jdbcType="INTEGER" javaType="java.lang.Integer" />
		<result property="userName" column="username" />
		<result property="password" column="password" />
	</resultMap>

	<select id="selectSingle" parameterType="int" resultMap="userResult">
		select username,password,id
		from ad_user where id=#{id}
 	</select>
 	
 	<select id="getAll"  resultMap="userResult">
		select username,password,id
		from ad_user 
 	</select>

	<insert id="insert" parameterType="user">
		<selectKey keyProperty="id" resultType="int" order="BEFORE">
			select _nextval('ad_user_seq')
		</selectKey>
	 <![CDATA[
		insert into
		ad_user(id,username,password) values(#{id},#{userName},#{password})
		]]>
 	</insert>

	<update id="update" parameterType="user">
		update ad_user set
		username=#{userName},password=#{password} where id=#{id}
 	</update>
 	
	<delete id="delete" parameterType="int">
		delete from ad_user where
		id=#{id}
	</delete>

</mapper>

UserDao的实现,需要继承MyBatisDao,在UserDao中可以扩展自己的方法,@Repository注解表示该层为存储层。
package spring.mybatis.dao;

import java.util.List;

import org.springframework.stereotype.Repository;

import spring.mybatis.bean.User;
import spring.mybatis.orm.MyBatisDao;

/**
 *@author TonyJ
 *@time 2015-2-2 下午08:53:40
 *@email tanglongjia@126.com
 */
@Repository
public class UserDao extends MyBatisDao<User> {

	public List<User> getAll(){
		return this.getSqlSession().selectList("getAll");
	}
}


UserService类业务层类,@Service表示该层为服务层,@Transactional放在类上表示每个公有方法都受事物管理,具体的管理方式在spring的配置文件中提现。
package spring.mybatis.service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import spring.mybatis.bean.User;
import spring.mybatis.dao.UserDao;

/**
 *@author TonyJ
 *@time 2015-2-2 下午08:55:04
 *@email tanglongjia@126.com
 */

@Service
@Transactional
public class UserService {
	
	@Autowired
	private UserDao userDao;
	
	public User getUserById(Long id){
		Map<String,Long> param = new HashMap<String,Long>();
		param.put("id", id);
		return userDao.selectSingle(param);
	}
	
	public List<User> getAll(){
		return userDao.getAll();
	}
	
}


5、配置文件的分析
最主要的配置文件是applicationContext.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/aop 
           http://www.springframework.org/schema/aop/spring-aop-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">
	
	<!-- 数据库配置文件位置 -->
	<context:property-placeholder location="classpath:db.properties" />
	
	<!-- 配置dbcp数据源 -->
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
		<property name="driverClassName" value="${jdbc.driverClassName}" />
		<property name="url" value="${jdbc.url}" />
		<property name="username" value="${jdbc.username}" />
		<property name="password" value="${jdbc.password}" />
		<!-- 队列中的最小等待数 -->
		<property name="minIdle" value="${jdbc.minIdle}"></property>
		<!-- 队列中的最大等待数 -->
		<property name="maxIdle" value="${jdbc.maxIdle}"></property>
		<!-- 最长等待时间,单位毫秒 -->
		<property name="maxWait" value="${jdbc.maxWait}"></property>
		<!-- 最大活跃数 -->
		<property name="maxActive" value="${jdbc.maxActive}"></property>
		<property name="initialSize" value="${jdbc.initialSize}"></property>
	</bean>

	<!-- 配置SqlSessionFactoryBean -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource"/>
		<property name="configLocation" value="classpath:mybatis-config.xml"/>
		<!-- mapper和resultmap配置路径 --> 
		<property name="mapperLocations">
			<list>
				<!-- 表示在spring.mybatis.bean包或以下所有目录中,以sqlMap.xml结尾所有文件 --> 
				<value>classpath:spring/mybatis/bean/*sqlMap.xml</value>
			</list>
		</property>
	</bean>
	<!-- 配置事务的传播特性-->
	<bean id="baseTransactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true">
		<property name="transactionManager" ref="transactionManager" />
		<property name="transactionAttributes">
			<props>
				<prop key="add*">PROPAGATION_REQUIRED</prop>
				<prop key="edit*">PROPAGATION_REQUIRED</prop>
				<prop key="remove*">PROPAGATION_REQUIRED</prop>
				<prop key="insert*">PROPAGATION_REQUIRED</prop>
				<prop key="update*">PROPAGATION_REQUIRED</prop>
				<prop key="del*">PROPAGATION_REQUIRED</prop>
				<prop key="*">readOnly</prop>
			</props>
		</property>
	</bean>
	 
	<!-- 通过扫描的模式,扫描目录在spring/mybatis/目录下,所有的mapper都继承SqlMapper接口的接口, 这样一个bean就可以了 	-->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="spring.mybatis"/>
		<property name="markerInterface" value="spring.mybatis.orm.SqlMap"/>
	</bean>
	
	<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
	    <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory" />
	</bean>
	
	<!-- 采用注释的方式配置bean -->
	<context:annotation-config />
	<!-- 配置要扫描的包 -->
	<context:component-scan base-package="spring.mybatis"></context:component-scan>
	<!--proxy-target-class="true"强制使用cglib代理   如果为false则spring会自动选择-->
	<aop:aspectj-autoproxy  proxy-target-class="true"/>
	<!-- 使用annotation注解方式配置事务 -->
	<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

db.properties文件用于配置数据库连接信息
dialect=MYSQL
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc\:mysql\://localhost\:3306/cmsp
jdbc.username=test
jdbc.password=test
jdbc.maxActive = 2
jdbc.maxIdle =5
jdbc.minIdle=1
jdbc.initialSize =3
jdbc.maxWait =3000

ehcache-application.xml用于配置缓存信息
<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
	<diskStore path="java.io.tmpdir" />
	<cacheManagerEventListenerFactory class="" properties=""/>
	<!-- DefaultCache setting. -->
	<defaultCache maxElementsInMemory="100000"
            eternal="true"
            overflowToDisk="true"
            diskSpoolBufferSizeMB="30"
            maxElementsOnDisk="10000000"
            timeToIdleSeconds="130" timeToLiveSeconds="140" 
            memoryStoreEvictionPolicy="LRU" />
</ehcache>

log4j.properties用于配置日志信息
log4j.rootLogger=debug,stdout,fout
log4j.logger.org.apache.ibatis=ERROR
log4j.logger.java.sql=debug,stdout


log4j.logger.com.jsmass=DEBUG
# SqlMap logging configuration...
#log4j.logger.com.mybatis=DEBUG
#log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=DEBUG
#log4j.logger.com.ibatis.common.jdbc.ScriptRunner=DEBUG
#log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG
#log4j.logger.org.apache.commons=ERROR
#log4j.logger.java.sql.Connection=DEBUG
#log4j.logger.java.sql.Statement=DEBUG
#log4j.logger.java.sql.PreparedStatement=DEBUG
#log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.com.ibatis=DEBUG
log4j.logger.org.apache.ibais.jdbc.ScriptRunner=DEBUG
#log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
#log4j.logger.com.jsmass=DEBUG
#log4j.logger.cn.jsmass=DEBUG
#log4j.logger.cn.com.jsmass=DEBUG

# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss},%6.6r]%-5p[%t]%x(%F:%L) - %m%n


#File output
log4j.appender.fout=org.apache.log4j.DailyRollingFileAppender  
log4j.appender.fout.file=C:/log/log4j.log
log4j.appender.fout.layout=org.apache.log4j.PatternLayout  
log4j.appender.fout.layout.ConversionPattern=[%d{yyyy-MM-dd HH\:mm\:ss},%6.6r]%-5p[%t]%x(%F\:%L) - %m%n 

mybaits.sqlMap.xml无实际作用,这个里面的配置信息都在spring配置文件中进行配置了
<?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">   <!-- dtd约束,一定要拷过去啊。下面的根据具体应用,改改就可以了 -->
<configuration>
	<!--  指定与数据库相关的配置资源文件名,若下面的dataSource所需要的url等直接配置编码在此文件,那么此properties也可以去掉 -->
	<properties resource="db.properties"/>  
	<!-- 给指定的类定义别名,这样在后面的Mapping映射文件中,可以直接写别名,可以不用写完整限定类名了 -->
	<typeAliases>
		<typeAlias alias="user" type="spring.mybatis.bean.User" />
	</typeAliases>
	
	<environments default="default">
		<environment id="default">
			<transactionManager type="JDBC" />	<!-- JDBC事务管理 -->
			<dataSource type="POOLED">  <!-- 数据源 连接池相关 所需要数据库连接的相关配置信息,在db.properties有指定 -->
				<property name="driver" value="${driver}" />
				<property name="url" value="${url}" />
				<property name="username" value="${username}" />
				<property name="password" value="${password}" />
			</dataSource>
		</environment>
	</environments>
	<!-- 映射文件 将sql、POJO、dao层映射连接在一起,以可配置的方式来组织。从此SQL的写法与dao层无关了。 -->
	<mappers>
	</mappers>
</configuration>


6、测试的类TestMain
package spring.mybatis.test;

import java.util.List;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import spring.mybatis.bean.User;
import spring.mybatis.dao.UserDao;

/**
 *@author TonyJ
 *@time 2015-2-2 下午08:57:56
 *@email tanglongjia@126.com
 */
public class TestMain {
	@Test
    public void userServiceTest(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao dao = context.getAutowireCapableBeanFactory().getBean("userDao", UserDao.class);
       /* Map<String, Long> param = new HashMap<String, Long>();
        param.put("id", new Long(12));
        User user = dao.selectSingle(param);
        System.out.println(user.getUserName());*/
        List<User> userList = dao.getAll();
        for (User user : userList) {
			System.out.println("id : " + user.getId() + ",userName : " + user.getUserName() + 
					",password : " + user.getPassword());
		}
	}
}

具体的项目代码见附件!
  • spring和mybatis泛型接口的整合(一)
            
    
    博客分类: SSH+i/mbatis spring mybatis 泛型接口编程 
  • 大小: 12.2 KB