设为首页 收藏本站
查看: 1098|回复: 0

[经验分享] spring和mybatis泛型接口的整合(一)

[复制链接]

尚未签到

发表于 2016-11-27 09:21:04 | 显示全部楼层 |阅读模式
1、这次使用spring和mybatis进行整合,使用spring的注解和自动扫描的方式将mybatis装载到程序中去。
2、首先看整个的工程包的截图
DSC0000.png
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());
}
}
}

具体的项目代码见附件!

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-306027-1-1.html 上篇帖子: spring+mybatis 配置文件占位符不能解析的问题 下篇帖子: mybatis insert 时 null值的报错问题
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表