当我们使用Spring Boot构建项目,并以Jar方式启动,如果我们自己集成了MyBatis,并设置自动扫描Mapper和xml,这个时候我们项目启动就会报无法初始化DataSource,找不到xml文件;之前一直困扰了好久,后来查找资料发现有两种方式可以解决该问题。
第一种解决方式
手工一个一个在mybatis-config.xml配置文件添加xml文件,并设置domain别名
<?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>
<typeAliases>
<typeAlias type="com.quanteng.ethio.task.database.entity.Order" alias="Order"/>
</typeAliases>
</configuration>
第二种解决方式
查找资料发现Mybatis自己有扫描Mapper和xml的方式,利用VFS来扫描加载
Mybatis源代码:
package org.mybatis.spring.boot.autoconfigure;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import org.apache.ibatis.io.VFS;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
/**
* @author Hans Westerbeek
* @author Eddú Meléndez
* @author Kazuki Shimizu
*/
public class SpringBootVFS extends VFS {
private final ResourcePatternResolver resourceResolver;
public SpringBootVFS() {
this.resourceResolver = new PathMatchingResourcePatternResolver(getClass().getClassLoader());
}
@Override
public boolean isValid() {
return true;
}
@Override
protected List<String> list(URL url, String path) throws IOException {
Resource[] resources = resourceResolver.getResources("classpath*:" + path + "/**/*.class");
List<String> resourcePaths = new ArrayList<String>();
for (Resource resource : resources) {
resourcePaths.add(preserveSubpackageName(resource.getURI(), path));
}
return resourcePaths;
}
private static String preserveSubpackageName(final URI uri, final String rootPath) {
final String uriStr = uri.toString();
final int start = uriStr.indexOf(rootPath);
return uriStr.substring(start);
}
}
所以我们将源代码直接COPY到我们自己工程里面
package com.quanteng.ethio.task.configuration;
import com.google.common.collect.Lists;
import org.apache.ibatis.io.VFS;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.util.List;
/**
* <自定义实现Mybatis扫描xml文件>
*
* @author zping
* @version 2018/12/21 0021
* @see [相关类/方法]
* @since [产品/模块版本]
*/
public class SpringBootVFS extends VFS
{
private final ResourcePatternResolver resourceResolver;
public SpringBootVFS ()
{
this.resourceResolver = new PathMatchingResourcePatternResolver (getClass ().getClassLoader ());
}
@Override
public boolean isValid ()
{
return true;
}
@Override
protected List<String> list (URL url, String path) throws IOException
{
Resource[] resources = resourceResolver.getResources ("classpath*:" + path + "/**/*.class");
List<String> resourcePaths = Lists.newArrayList ();
for (Resource resource : resources)
{
resourcePaths.add (preserveSubpackageName (resource.getURI (), path));
}
return resourcePaths;
}
private static String preserveSubpackageName (final URI uri, final String rootPath)
{
final String uriStr = uri.toString ();
final int start = uriStr.indexOf (rootPath);
return uriStr.substring (start);
}
}
然后在加载扫描Domain实体类的时候添加如下代码
VFS.addImplClass (SpringBootVFS.class);
完整代码如下:
package com.quanteng.ethio.task.configuration;
import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.io.VFS;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
/**
* <一句话功能简述> <功能详细描述>
*
* @author zping
* @version 2018/4/12 0012
* @see [相关类/方法]
* @since [产品/模块版本]
*/
@Configuration
public class RepositoryInitialize
{
/**
* 日志记录器
*/
private static final Logger LOGGER = LoggerFactory.getLogger (RepositoryInitialize.class);
/**
* 实体类包路径
*/
private static final String MODEL_PACKAGE_PATH = "com.quanteng.ethio.task.database.entity";
/**
* mybatis配置文件路径
*/
private static final String MYBATIS_PATH = "classpath:/mybatis-config.xml";
/**
* mybatis映射文件路径
*/
private static final String MAPPER_PATH = "classpath:/mapper/*.xml";
@Autowired
private DruidDataSource druidDataSource;
@Bean (name = "sqlSessionFactory")
public SqlSessionFactory sqlSessionFactory () throws Exception
{
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean ();
sqlSessionFactoryBean.setDataSource (druidDataSource);
VFS.addImplClass (SpringBootVFS.class);
/*扫描DOMAIN包,可以使用别名*/
sqlSessionFactoryBean.setTypeAliasesPackage (MODEL_PACKAGE_PATH);
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver ();
try
{
/*扫描mybatis配置文件*/
sqlSessionFactoryBean.setConfigLocation (resolver.getResource (MYBATIS_PATH));
sqlSessionFactoryBean.setMapperLocations (resolver.getResources (MAPPER_PATH));
return sqlSessionFactoryBean.getObject ();
}
catch (Exception e)
{
LOGGER.error ("init database error.", e);
throw e;
}
}
@Bean
public SqlSessionTemplate sqlSessionTemplate (SqlSessionFactory sqlSessionFactory)
{
return new SqlSessionTemplate (sqlSessionFactory);
}
}
至此已完全解决,项目成功运行!!!