maven/mybatis-plus/spring动态数据源/springmvc/AOP/自定义参数注入/druid/dom4j/generator代码生成器

本文介绍了一种基于Mybatis-Plus的多数据源动态切换方案,可根据租户域名自动选择对应的数据库,支持自定义参数注入、AOP切换数据源等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

mybatis-plus+动态数据源+自定义数据源配置+dom解析+自定义参数注入(注解)+AOP切换数据源+druid

项目需求引入租户概念,每个租户一个域名,由于每个租户的用户量比较大,为方便数据管理和减轻数据库压力,要求使用多数据源,根据租户域名路由到对应租户的数据库。在网上看了好多关于多数据源的文章,感觉都不合适。几乎所有的文章都需要在配置文件中配置多个数据源,如果一个租户即有app,又有web,那相同的租户就要配置2个相同的数据源,配置文件会变的很繁琐。于是想把数据源配置文件独立出来,在项目加载数据源的时候自动解析并注入多数据源。

感谢同事架构师萌琪琪里面一些实现参考了他的多数据源,他用的是AbstractDataSource实现的多数据源路由,不用默认数据源什么的,更接近底层一些。

参考博客:http://icezx.iteye.com/blog/1939586

然后自己整理出一个简单的项目实例,由于还没有实际应用,难免有疏漏或写的不好的地方,欢迎指正。

看下项目结构:


具体的过程我就不多解释了,请参考博客:http://icezx.iteye.com/blog/1939586

项目实例下载地址:点这里!(http://download.youkuaiyun.com/download/kaer_gg/10000306)

简单介绍下实现逻辑和代码吧:

项目启动时通过DynamicDataSource加载数据源,此过程涉及解析自定义的数据库配置文件dataSource.xml。然后controller通过截获请求的url获取用户访问的域名,并通过注解或指定自定义类型对象自动注入到controller参数中,然后通过service切面取得参数做为数据库切换依据进行数据库切换,实现根据不同租户的域名访问项目进行对应租户数据库的访问。

自定义注解:CurrentTenantKey.java

package com.guorucheng.common.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CurrentTenantKey {

}
controller使用自定义注解或指定参数对象注入:CurrentTenantKeyResolver.java
package com.guorucheng.common.annotation.resolver;

import javax.servlet.http.HttpServletRequest;

import org.springframework.core.MethodParameter;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import com.guorucheng.common.annotation.CurrentTenantKey;
import com.guorucheng.common.entity.TenantKey;
import com.guorucheng.common.utils.StringUtil;

/**
 * CurrentTenantKey 注解解析器
 * @author GR·cheng
 *
 */
public class CurrentTenantKeyResolver implements HandlerMethodArgumentResolver {
	
	//private final Pattern PATTERN = Pattern.compile("^http://((\\w+\\.){1,2}guorucheng\\.com)");
	
	/**
	 * 
	 * @Title: resolveArgument
	 * @Description: 将request中的请求参数解析到当前controller参数上
	 * @param parameter 需要被解析的controller参数,此参数必须先传给{@link #supportsParameter}并返回true
	 * @param mavContainer 当前request的ModelAndViewContainer
	 * @param request 当前request
	 * @param binderFactory 生成{@link WebDataBinder}实例的工厂
	 * @return 解析后的controller参数
	 * @throws Exception 
	 * @see org.springframework.web.method.support.HandlerMethodArgumentResolver#resolveArgument(org.springframework.core.MethodParameter, org.springframework.web.method.support.ModelAndViewContainer, org.springframework.web.context.request.NativeWebRequest, org.springframework.web.bind.support.WebDataBinderFactory)
	 * @user GR·cheng
	 * @date 2017年9月6日
	 */
	@Override
	public Object resolveArgument(MethodParameter parameter,
			ModelAndViewContainer mavContainer, NativeWebRequest request,
			WebDataBinderFactory binderFactory) throws Exception {
		TenantKey tenantKey = new TenantKey();
		String url = request.getNativeRequest(HttpServletRequest.class).getServerName().toString();
		if (StringUtil.notEmpty(url)) {
			tenantKey.setTenantKey(url);
		} else {
			tenantKey.setTenantKey("www.guorucheng.com");
		}
		return tenantKey;
	}
	
	/**
	 * 
	 * @Title: supportsParameter
	 * @Description: 指定参数如果被应用@CurrentTenantKey,则使用该注解。
	 * @param parameter 当前使用注解的参数
	 * @return 如果支持当前使用注解的参数,返回true,不支持返回false。如果直接返回true,则表示支持所有参数。
	 * @see org.springframework.web.method.support.HandlerMethodArgumentResolver#supportsParameter(org.springframework.core.MethodParameter)
	 * @user GR·cheng
	 * @date 2017年9月6日
	 */
	@Override
	public boolean supportsParameter(MethodParameter parameter) {
		return parameter.hasParameterAnnotation(CurrentTenantKey.class) || parameter.getParameterType() == TenantKey.class;
	}

}
切面截获切换依据并设置当前线程数据源:TenantKeyAspect.java

package com.guorucheng.common.aspect;

import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;

import com.guorucheng.common.entity.TenantKey;
import com.guorucheng.common.holder.DataSourceHolder;

public class TenantKeyAspect implements MethodBeforeAdvice,AfterReturningAdvice {

	/**
	 * 
	 * @Title: before 执行方法前切换数据源
	 * @Description: 
	 * @param method 方法名
	 * @param parameters 参数组
	 * @param ASP_CLASS 调用的类对象
	 * @throws Throwable 
	 * @see org.springframework.aop.MethodBeforeAdvice#before(java.lang.reflect.Method, java.lang.Object[], java.lang.Object)
	 * @user GR·cheng
	 * @date 2017年9月28日
	 */
	@Override
	public void before(Method method, Object[] parameters, Object ASP_CLASS)
			throws Throwable {
		TenantKey tenantKey = null;
		for (Object object : parameters) {//入参查找租户
			if (object instanceof TenantKey) {
				tenantKey = (TenantKey) object;
				break;
			}
		}
		if (tenantKey == null) {//入参无租户,抛出异常
			throw new RuntimeException("service层切面未获取到tenantKey");
		}
		DataSourceHolder.setDataSourceType(tenantKey.getTenantKey());
	}

	/**
	 * 
	 * @Title: afterReturning 方法执行return前清除线程数据源
	 * @Description: 
	 * @param returnObject 调用方法返回的对象
	 * @param method 方法名
	 * @param parameters 参数组
	 * @param ASP_CLASS 调用的类对象
	 * @throws Throwable 
	 * @see org.springframework.aop.AfterReturningAdvice#afterReturning(java.lang.Object, java.lang.reflect.Method, java.lang.Object[], java.lang.Object)
	 * @user GR·cheng
	 * @date 2017年9月28日
	 */
	@Override
	public void afterReturning(Object returnObject, Method method, Object[] parameters, Object ASP_CLASS) throws Throwable {
		DataSourceHolder.removeDataSourceType();
	}
	
}
多数据源创建、管理、切换类:DynamicDataSource.java

package com.guorucheng.common.dynamicDataSource;

import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.sql.DataSource;

import org.apache.log4j.Logger;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

import com.alibaba.druid.pool.DruidDataSource;
import com.guorucheng.common.entity.DataSourceConfig;
import com.guorucheng.common.entity.TenantKey;
import com.guorucheng.common.holder.DataSourceHolder;
import com.guorucheng.common.utils.StringUtil;
import com.guorucheng.common.xmlConf.XmlConfInitStrategy;

/**
 * 初始化动态数据源,并根据上下文变量切换数据源
 * @author GR·cheng
 *
 */
public class DynamicDataSource extends AbstractRoutingDataSource implements ApplicationContextAware {
	
	private static Logger log = Logger.getLogger(DynamicDataSource.class);
	
	//数据源配置文件名称
	private String configName = "";
	//bean工厂
	private static ApplicationContext context;
	//数据源配置列表
	private List<DataSourceConfig> configs = null;
	//数据源池
	public final ConcurrentHashMap<String, DataSource> dataSourcePool = new ConcurrentHashMap<String, DataSource>();
	
	//初始化多数据源
	@Override
	public void afterPropertiesSet() {
		try {
			initDataSources();
		} catch (Exception e) {
			e.printStackTrace();
		}
		super.afterPropertiesSet();
	}

	//获取bean工厂
	@Override
	public void setApplicationContext(ApplicationContext applicationContext)
			throws BeansException {
		context = applicationContext;
	}
	
	/**
	 * 
	 * 
	 * @Title: initDataSources
	 * @Description: 初始化数据源
	 * @param: 
	 * @return: void
	 * @user: GR·cheng
	 *
	 */
	private void initDataSources() {
		configs = XmlConfInitStrategy.init().getInitConfig(configName);
		DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) context.getAutowireCapableBeanFactory();
		for (DataSourceConfig config : configs) {
			if (!config.checkConfig()) {
				throw new RuntimeException("数据库配置文件缺少关键字段值");
			}
			DataSource dataSource = createDataSource(config);
			List<TenantKey> tenantKeys = config.buildTenantKeyList();
			for (TenantKey tenantKey : tenantKeys) {
				if (dataSourcePool.containsKey(tenantKey)) {
					log.info("数据库连接池中已存在数据源:" + tenantKey.getTenantKey());
				} else {
					beanFactory.registerSingleton(tenantKey.getTenantKey(), dataSource);
					dataSourcePool.put(tenantKey.getTenantKey(), dataSource);
				}
			}
		}
		
		this.setTargetDataSources(dataSourcePool);
		setDefaultTargetDataSource(dataSourcePool.get("www.guorucheng.com"));
		
	}
	
	/**
	 * 
	 * 
	 * @Title: createDataSource
	 * @Description: 创建数据源
	 * @param: @param config
	 * @param: @return
	 * @return: DataSource
	 * @user: GR·cheng
	 *
	 */
	private DataSource createDataSource(DataSourceConfig config) {
		if (config == null) {
			return null;
		}
		DruidDataSource dataSource = new DruidDataSource();
		dataSource.setUrl(config.getUrl());
		dataSource.setUsername(config.getUsername());
		dataSource.setPassword(config.getPassword());
		
		String initialSizeStr = config.getInitialSize();
		if (StringUtil.notEmpty(initialSizeStr)) {
			try {
				Integer initialSize = Integer.parseInt(initialSizeStr);
				dataSource.setInitialSize(initialSize);
			} catch (NumberFormatException e) {
				throw new RuntimeException("xml datasource config initialSize invalid");
			}
		}
		
		String maxActiveStr = config.getMaxActive();
		if (StringUtil.notEmpty(maxActiveStr)) {
			try {
				Integer maxActive = Integer.parseInt(maxActiveStr);
				dataSource.setMaxActive(maxActive);
			} catch (NumberFormatException e) {
				throw new RuntimeException("xml datasource config maxActive invalid");
			}
		}
		
		String minIdleStr = config.getMinIdle();
		if (StringUtil.notEmpty(minIdleStr)) {
			try {
				Integer minIdle = Integer.parseInt(minIdleStr);
				dataSource.setMinIdle(minIdle);
			} catch (NumberFormatException e) {
				throw new RuntimeException("xml datasource config minIdle invalid");
			}
		}
		
		String maxWaitStr = config.getMaxWait();
		if (StringUtil.notEmpty(maxWaitStr)) {
			try {
				Long maxWait = Long.parseLong(maxWaitStr);
				dataSource.setMaxWait(maxWait);
			} catch (NumberFormatException e) {
				throw new RuntimeException("xml datasource config maxWait invalid");
			}
		}
		
		String validationQuery = config.getValidationQuery();
		if (StringUtil.notEmpty(validationQuery)) {
			dataSource.setValidationQuery(validationQuery);
		}
		
		String testOnBorrowStr = config.getTestOnBorrow();
		if (StringUtil.notEmpty(testOnBorrowStr)) {
			Boolean testOnBorrow = Boolean.parseBoolean(testOnBorrowStr);
			dataSource.setTestOnBorrow(testOnBorrow);
		}
		
		String testOnReturnStr = config.getTestOnReturn();
		if (StringUtil.notEmpty(testOnReturnStr)) {
			Boolean testOnReturn = Boolean.parseBoolean(testOnReturnStr);
			dataSource.setTestOnReturn(testOnReturn);
		}
		
		String testWhileIdleStr = config.getTestWhileIdle();
		if (StringUtil.notEmpty(testWhileIdleStr)) {
			Boolean testWhileIdle = Boolean.parseBoolean(testWhileIdleStr);
			dataSource.setTestWhileIdle(testWhileIdle);
		}
		
		String timeBetweenEvictionRunsMillisStr = config.getTimeBetweenEvictionRunsMillis();
		if (StringUtil.notEmpty(timeBetweenEvictionRunsMillisStr)) {
			try {
				Long timeBetweenEvictionRunsMillis = Long.parseLong(timeBetweenEvictionRunsMillisStr);
				dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
			} catch (NumberFormatException e) {
				throw new RuntimeException("xml datasource config timeBetweenEvictionRunsMillis invalid");
			}
		}
		
		String minEvictableIdleTimeMillisStr = config.getMinEvictableIdleTimeMillis();
		if (StringUtil.notEmpty(minEvictableIdleTimeMillisStr)) {
			try {
				Long minEvictableIdleTimeMIllis = Long.parseLong(minEvictableIdleTimeMillisStr);
				dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMIllis);
			} catch (NumberFormatException e) {
				throw new RuntimeException("xml datasource config minEvictableIdleTimeMIllis invalid");
			}
		}
		
		String removeAbandonedStr = config.getRemoveAbandoned();
		if (StringUtil.notEmpty(removeAbandonedStr)) {
			Boolean removeAbandoned = Boolean.parseBoolean(removeAbandonedStr);
			dataSource.setRemoveAbandoned(removeAbandoned);
		}
		
		String removeAbandonedTimeoutStr = config.getRemoveAbandonedTimeout();
		if (StringUtil.notEmpty(removeAbandonedTimeoutStr)) {
			Integer removeAbandonedTimeout = Integer.parseInt(removeAbandonedTimeoutStr);
			dataSource.setRemoveAbandonedTimeout(removeAbandonedTimeout);
		}
		
		String logAbandonedStr = config.getLogAbandoned();
		if (StringUtil.notEmpty(logAbandonedStr)) {
			Boolean logAbandoned = Boolean.parseBoolean(logAbandonedStr);
			dataSource.setLogAbandoned(logAbandoned);
		}
		
		try {
			dataSource.init();
		} catch (SQLException e) {
			throw new RuntimeException("drudDataSource init fail tenant is "+config.getTenantKeyList(),e);
		}
		return dataSource;
	}
	
	//查找当前用户上下文变量中设置的数据源
	@Override
	protected Object determineCurrentLookupKey() {
		return DataSourceHolder.getDataSourceType();
	}
	
	//设置默认数据源
	@Override
	public void setDefaultTargetDataSource(Object defaultTargetDataSource) {
		super.setDefaultTargetDataSource(defaultTargetDataSource);
	}
	
	//设置数据源集合
	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Override
	public void setTargetDataSources(Map targetDataSources){
		super.setTargetDataSources(targetDataSources);
	}

	public String getConfigName() {
		return configName;
	}

	public void setConfigName(String configName) {
		this.configName = configName;
	}
	
}
druid连接池实体类:DataSourceConfig.java

package com.guorucheng.common.entity;

import java.util.ArrayList;
import java.util.List;

import com.guorucheng.common.utils.StringUtil;

public class DataSourceConfig {
	
	/**
	 * 允许接入的租户域名列表
	 */
	private List<String> tenantKeyList;
	/**
	 * 数据库地址
	 */
	private String url;
	/**
	 * 数据库登录名
	 */
	private String username;
	/**
	 * 数据库登录密码
	 */
	private String password;
	/**
	 * 初始化连接池大小
	 */
	private String initialSize;
	/**
	 * 连接池最大使用连接数
	 */
	private String maxActive;
	/**
	 * 连接池最小空闲数
	 */
	private String minIdle;
	/**
	 * 获取连接最大等待时间
	 */
	private String maxWait;
	/**
	 * 用来检测连接是否有效的sql,要求是一个查询语句。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会其作用。
	 */
	private String validationQuery;
	/**
	 * 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
	 */
	private String testOnBorrow;
	/**
	 * 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
	 */
	private String testOnReturn;
	/**
	 * 申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。建议配置为true,不影响性能,并且保证安全性。
	 */
	private String testWhileIdle;
	/**
	 * 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒。
	 */
	private String timeBetweenEvictionRunsMillis;
	/**
	 * 一个连接在连接池中的最小生存时间,单位毫秒。
	 */
	private String minEvictableIdleTimeMillis;
	/**
	 * 对于长时间不使用的连接是否强制关闭
	 */
	private String removeAbandoned;
	/**
	 * 强制关闭长时间不适用的空闲连接的时间
	 */
	private String removeAbandonedTimeout;
	/**
	 * 是否将关闭当前长时间未用的连接记录日志
	 */
	private String logAbandoned;
	
	public List<String> getTenantKeyList() {
		return tenantKeyList;
	}
	public void setTenantKeyList(List<String> tenantKeyList) {
		this.tenantKeyList = tenantKeyList;
	}
	public String getUrl() {
		return url;
	}
	public void setUrl(String url) {
		this.url = url;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getInitialSize() {
		return initialSize;
	}
	public void setInitialSize(String initialSize) {
		this.initialSize = initialSize;
	}
	public String getMaxActive() {
		return maxActive;
	}
	public void setMaxActive(String maxActive) {
		this.maxActive = maxActive;
	}
	public String getMinIdle() {
		return minIdle;
	}
	public void setMinIdle(String minIdle) {
		this.minIdle = minIdle;
	}
	public String getMaxWait() {
		return maxWait;
	}
	public void setMaxWait(String maxWait) {
		this.maxWait = maxWait;
	}
	public String getValidationQuery() {
		return validationQuery;
	}
	public void setValidationQuery(String validationQuery) {
		this.validationQuery = validationQuery;
	}
	public String getTestOnBorrow() {
		return testOnBorrow;
	}
	public void setTestOnBorrow(String testOnBorrow) {
		this.testOnBorrow = testOnBorrow;
	}
	public String getTestOnReturn() {
		return testOnReturn;
	}
	public void setTestOnReturn(String testOnReturn) {
		this.testOnReturn = testOnReturn;
	}
	public String getTestWhileIdle() {
		return testWhileIdle;
	}
	public void setTestWhileIdle(String testWhileIdle) {
		this.testWhileIdle = testWhileIdle;
	}
	public String getTimeBetweenEvictionRunsMillis() {
		return timeBetweenEvictionRunsMillis;
	}
	public void setTimeBetweenEvictionRunsMillis(
			String timeBetweenEvictionRunsMillis) {
		this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
	}
	public String getMinEvictableIdleTimeMillis() {
		return minEvictableIdleTimeMillis;
	}
	public void setMinEvictableIdleTimeMillis(String minEvictableIdleTimeMillis) {
		this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
	}
	public String getRemoveAbandoned() {
		return removeAbandoned;
	}
	public void setRemoveAbandoned(String removeAbandoned) {
		this.removeAbandoned = removeAbandoned;
	}
	public String getRemoveAbandonedTimeout() {
		return removeAbandonedTimeout;
	}
	public void setRemoveAbandonedTimeout(String removeAbandonedTimeout) {
		this.removeAbandonedTimeout = removeAbandonedTimeout;
	}
	public String getLogAbandoned() {
		return logAbandoned;
	}
	public void setLogAbandoned(String logAbandoned) {
		this.logAbandoned = logAbandoned;
	}
	
	public boolean checkConfig() {
		if (tenantKeyList == null || tenantKeyList.size() == 0 || StringUtil.isEmpty(url) || StringUtil.isEmpty(username) || StringUtil.isEmpty(password)) {
			return false;
		}
		return true;
	}
	
	public List<TenantKey> buildTenantKeyList() {
		List<TenantKey> keys = new ArrayList<TenantKey>();
		for (String tenantKey : tenantKeyList) {
			keys.add(new TenantKey(tenantKey));
		}
		return keys;
	}

}
租户实体类:TenantKey.java

package com.guorucheng.common.entity;

public class TenantKey {
	
	private String tenantKey;

	public TenantKey() {
	}

	public TenantKey(String tenantKey) {
		super();
		this.tenantKey = tenantKey;
	}

	public String getTenantKey() {
		return tenantKey;
	}

	public void setTenantKey(String tenantKey) {
		this.tenantKey = tenantKey;
	}

	@Override
	public String toString() {
		return "TenantKey [tenantKey=" + tenantKey + "]";
	}

}

代码生成器:MpGenerator.java

package com.guorucheng.common.generator;

import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.DbType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;

public class MpGenerator {

	public static void main(String[] args) {
		
		AutoGenerator ag = new AutoGenerator();

		//全局配置
		GlobalConfig gc = new GlobalConfig();
		gc.setOutputDir("D://test-Workspace//GuoRuCheng//src//main//java");
		gc.setFileOverride(true);// 是否覆盖文件
		gc.setActiveRecord(true);// 开启activeRecord 模式
		gc.setEnableCache(false);// XML 二级缓存
		gc.setBaseResultMap(true);// XML ResultMap
		gc.setBaseColumnList(true);// XML columList
		gc.setAuthor("GR·cheng");

		// 自定义文件命名,注意 %s 会自动填充表实体属性!
		// .setMapperName("%sDao")
		// .setXmlName("%sDao")
		// .setServiceName("MP%sService")
		// .setServiceImplName("%sServiceDiy")
		// .setControllerName("%sAction")
		
		ag.setGlobalConfig(gc);
		
		//数据源配置
		DataSourceConfig dsc = new DataSourceConfig();
		dsc.setDbType(DbType.MYSQL);
		dsc.setDriverName("com.mysql.jdbc.Driver");
		dsc.setUrl("jdbc:mysql://127.0.0.1:3306/db1?characterEncoding=utf8");
		dsc.setUsername("root");
		dsc.setPassword("root");
		
		ag.setDataSource(dsc);
		
		//生成策略
		StrategyConfig sc = new StrategyConfig();
		sc.containsTablePrefix("");
		sc.setNaming(NamingStrategy.underline_to_camel);//表名生成策略
		
		ag.setStrategy(sc);
		
		PackageConfig pc = new PackageConfig();
		pc.setParent("com.guorucheng");
		pc.setEntity("model");
		pc.setMapper("dao");
		pc.setXml("mapper");
		pc.setService("service");
		pc.setServiceImpl("service.serviceImpl");
		pc.setController("controller");
		
		ag.setPackageInfo(pc);
		
		ag.execute();
	}

}

线程数据源管理器:DataSourceHolder.java

package com.guorucheng.common.holder;

/**
 * 线程数据源管理器
 * @author GR·cheng
 *
 */
public class DataSourceHolder {
	
	private static final ThreadLocal<String> DATA_SOURCE_HOLDER = new ThreadLocal<String>();
	
	public static void setDataSourceType(String dataSourceType) {
		DATA_SOURCE_HOLDER.set(dataSourceType);
	}
	
	public static String getDataSourceType() {
		return DATA_SOURCE_HOLDER.get();
	}
	
	public static void removeDataSourceType() {
		DATA_SOURCE_HOLDER.remove();
	}
	
}

自定义数据库配置文件解析器:XmlConfInitStrategy.java

package com.guorucheng.common.xmlConf;

import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import com.guorucheng.common.entity.DataSourceConfig;
import com.guorucheng.common.utils.StringUtil;

/**
 * 自定义xml解析
 * @author GR·cheng
 *
 */
public class XmlConfInitStrategy {
	
	private final Logger LOG = Logger.getLogger(this.getClass());
	public static XmlConfInitStrategy xmlConfInitStrategy;
	private final String DEFAULT_CONF_FILE = "dataSource-conf.xml";
	
	public static XmlConfInitStrategy init() {
		return xmlConfInitStrategy = new XmlConfInitStrategy();
	}
	
	public List<DataSourceConfig> getInitConfig(String configName) {
		return parseConfigXml(StringUtil.isEmpty(configName)?loadConfig(DEFAULT_CONF_FILE):loadConfig(configName+".xml"));
	}
	
	@SuppressWarnings("unchecked")
	private List<DataSourceConfig> parseConfigXml(InputStream configXml){
		if (configXml == null) {
			return null;
		}
		
		Document document = null;
		SAXReader saxReader = new SAXReader();
		List<DataSourceConfig> dataSourceConfigs = new ArrayList<DataSourceConfig>();
		
		try {
			document = saxReader.read(configXml);
			Element root = document.getRootElement();
			List<Element> nodes = root.elements();
			for (Element node : nodes) {
				DataSourceConfig config = new DataSourceConfig();
				String tenantKeys = node.elementTextTrim("tenantKey");
				String[] tenantKeyArr = tenantKeys.split(";");
				List<String> tenantKeyList = new ArrayList<String>();
				for (String tenantKey : tenantKeyArr) {
					tenantKeyList.add(tenantKey);
				}
				config.setTenantKeyList(tenantKeyList);
				Element dataSource = node.element("dataSource");
				List<Element> dataSources = dataSource.elements();
				for (Element element : dataSources) {
					String propName = element.getName();
					try {
						Field field = config.getClass().getDeclaredField(propName);
						Method setter = config.getClass().getMethod("set"+propName.substring(0,1).toUpperCase()+propName.substring(1), field.getType());
						setter.invoke(config, element.getTextTrim());
					} catch (NoSuchFieldException e) {
						e.printStackTrace();
					} catch (SecurityException e) {
						e.printStackTrace();
					} catch (NoSuchMethodException e) {
						e.printStackTrace();
					} catch (IllegalAccessException e) {
						e.printStackTrace();
					} catch (IllegalArgumentException e) {
						e.printStackTrace();
					} catch (InvocationTargetException e) {
						e.printStackTrace();
					}
				}
				dataSourceConfigs.add(config);
			}
		} catch (DocumentException e) {
			e.printStackTrace();
		}		
		return dataSourceConfigs;
	}
	
	/**
	 * 加载src/main/resources中指定名称的配置文件
	 * @param configPath 文件名称
	 * @return 输入流
	 */
	private InputStream loadConfig(String configName){
		InputStream stream = this.getClass().getClassLoader().getResourceAsStream(configName);
		if (stream==null) {
			LOG.info("dataSource xml is not exist!");
			return null;
		}
		return stream;
	}
	
}

项目中的应用:controller层

/**
	 * 
	 * 
	 * @Title: findSysUsers
	 * @Description: 使用自动识别注参并进行数据源切换查询
	 * @param: @param name
	 * @param: @param tenantKey
	 * @param: @return
	 * @return: List<SysUser>
	 * @user: GR·cheng
	 *
	 */
	@ResponseBody
	@RequestMapping("/findSysUsers")
	public List<SysUser> findSysUsers(TenantKey tenantKey) {
		return userService.findSysUsers(tenantKey);
	}
	
	/**
	 * 
	 * 
	 * @Title: findSysUsers
	 * @Description: 使用注解注参并进行数据源切换查询
	 * @param: @param name
	 * @param: @param tenantKey
	 * @param: @return
	 * @return: List<SysUser>
	 * @user: GR·cheng
	 *
	 */
	@ResponseBody
	@RequestMapping("/findSysUsers1")
	public List<SysUser> findSysUsers1(@CurrentTenantKey TenantKey tenantKey) {
		return userService.findSysUsers(tenantKey);
	}

service层实现时切换数据源,到这里就不用写代码了,切面类自动就切换数据源了,由于使用了mybatis-plus,使用框架自带的通用dao就好了,非常方便,不用自己再写代码了,dao和mapper都不用写。

package com.guorucheng.service.serviceImpl;

import java.util.List;

import com.guorucheng.model.SysUser;
import com.guorucheng.common.entity.TenantKey;
import com.guorucheng.dao.SysUserMapper;
import com.guorucheng.service.ISysUserService;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;

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

/**
 * <p>
 * 系统用户表 服务实现类
 * </p>
 *
 * @author GR·cheng
 * @since 2017-08-31
 */
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {
	
	@Autowired
	private SysUserMapper userDAO;

	@Override
	public List<SysUser> findSysUsers(TenantKey tenantKey) {
		return userDAO.selectList(null);
	}
	
}

dao:

package com.guorucheng.dao;

import com.guorucheng.model.SysUser;
import com.baomidou.mybatisplus.mapper.BaseMapper;

/**
 * <p>
  * 系统用户表 Mapper 接口
 * </p>
 *
 * @author GR·cheng
 * @since 2017-08-31
 */
public interface SysUserMapper extends BaseMapper<SysUser> {

}

mapper:

<?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.guorucheng.dao.SysUserMapper">

	<!-- 通用查询映射结果 -->
	<resultMap id="BaseResultMap" type="com.guorucheng.model.SysUser">
		<id column="id" property="id" />
		<result column="name" property="name" />
		<result column="age" property="age" />
		<result column="ctime" property="ctime" />
	</resultMap>

    <!-- 通用查询结果列 -->
    <sql id="Base_Column_List">
        id, name, age, ctime
    </sql>

</mapper>

接下来是相关配置文件:

spring.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:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

    <!-- Service包(自动注入) -->
    <context:component-scan base-package="com.guorucheng.service"/>

    <import resource="classpath:spring-mybatis.xml"/>
</beans>

spring-mybaties.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:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">
    
    <bean id="dynamicDataSource" class="com.guorucheng.common.dynamicDataSource.DynamicDataSource" >
    	<property name="configName" value="dataSource" /><!-- value值为数据库配置文件xml名称 -->
    </bean>

    <!-- Spring整合Mybatis,更多查看文档:http://mp.baomidou.com -->
    <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean">
        <property name="dataSource" ref="dynamicDataSource"/>
        <!-- 自动扫描Mapping.xml文件 -->
        <property name="mapperLocations" value="classpath:com/guorucheng/mapper/*.xml"/>
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <!-- <property name="typeAliasesPackage" value="com.guorucheng.model"/> -->
        <property name="plugins">
            <array>
                <!-- 分页插件配置 -->
                <bean id="paginationInterceptor" class="com.baomidou.mybatisplus.plugins.PaginationInterceptor">
                </bean>
            </array>
        </property>
	    <!-- 全局配置注入 -->
	    <property name="globalConfig" ref="globalConfig" />
	</bean>
	<bean id="globalConfig" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">
	    <!--
			AUTO->`0`("数据库ID自增")
		 	INPUT->`1`(用户输入ID")
			ID_WORKER->`2`("全局唯一ID")
			UUID->`3`("全局唯一ID")
		-->
	    <property name="idType" value="2" />
		<!--
			MYSQL->`mysql`
			ORACLE->`oracle`
			DB2->`db2`
			H2->`h2`
			HSQL->`hsql`
			SQLITE->`sqlite`
			POSTGRE->`postgresql`
			SQLSERVER2005->`sqlserver2005`
			SQLSERVER->`sqlserver`
		-->
		<!-- Oracle需要添加该项 -->
	    <!-- <property name="dbType" value="oracle" /> -->
	    <!-- 全局表为下划线命名设置 true -->
	    <!-- <property name="dbColumnUnderline" value="true" /> -->
        <!-- <property name="metaObjectHandler">
            <bean class="com.ssm.common.MyMetaObjectHandler" />
        </property> -->
	</bean>

    <!-- MyBatis 动态扫描  -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.guorucheng.dao"/>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
    </bean>

    <!-- 配置事务管理 -->
    <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dynamicDataSource"/>
    </bean>

    <!-- 事务管理 属性 -->
    <tx:advice id="transactionAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="add*" propagation="REQUIRED"/>
            <tx:method name="append*" propagation="REQUIRED"/>
            <tx:method name="save*" propagation="REQUIRED"/>
            <tx:method name="update*" propagation="REQUIRED"/>
            <tx:method name="modify*" propagation="REQUIRED"/>
            <tx:method name="edit*" propagation="REQUIRED"/>
            <tx:method name="insert*" propagation="REQUIRED"/>
            <tx:method name="delete*" propagation="REQUIRED"/>
            <tx:method name="remove*" propagation="REQUIRED"/>
            <tx:method name="repair" propagation="REQUIRED"/>

            <tx:method name="get*" propagation="REQUIRED" read-only="true"/>
            <tx:method name="find*" propagation="REQUIRED" read-only="true"/>
            <tx:method name="load*" propagation="REQUIRED" read-only="true"/>
            <tx:method name="search*" propagation="REQUIRED" read-only="true"/>
            <tx:method name="datagrid*" propagation="REQUIRED" read-only="true"/>

            <tx:method name="*" propagation="REQUIRED" read-only="true"/>
        </tx:attributes>
    </tx:advice>
    
    <bean id="tenantKeyAspect" class="com.guorucheng.common.aspect.TenantKeyAspect" />

    <!-- 配置事务切面和租户切面 -->
    <aop:config>
        <aop:pointcut id="transactionPointcut" expression="execution(* com.guorucheng.service..*.*(..))"/>
        <aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice" order="2"/>
        <aop:advisor pointcut-ref="transactionPointcut" advice-ref="tenantKeyAspect" order="1"/><!-- 数据源切换要在事务之前,否则会导致事务无效 -->
    </aop:config>
    
    

</beans>

spring-mvc.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:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <mvc:default-servlet-handler/>

    <!-- Controller包(自动注入) -->
    <context:component-scan base-package="com.guorucheng.controller"/>

    <mvc:annotation-driven>
	    <!-- 注册自定义参数解析器 -->
	    <mvc:argument-resolvers>
	    	<bean class="com.guorucheng.common.annotation.resolver.CurrentTenantKeyResolver" />
	    </mvc:argument-resolvers>
	    
	    <!-- FastJson注入 -->
        <mvc:message-converters register-defaults="true">
            <!-- 避免IE执行AJAX时,返回JSON出现下载文件 -->
            <!-- FastJson -->
            <bean id="fastJsonHttpMessageConverter"
                  class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
                <property name="supportedMediaTypes">
                    <list>
                        <!-- 这里顺序不能反,一定先写text/html,不然ie下出现下载提示 -->
                        <value>text/html;charset=UTF-8</value>
                        <value>application/json;charset=UTF-8</value>
                    </list>
                </property>
                <property name="features">
                    <array value-type="com.alibaba.fastjson.serializer.SerializerFeature">
                        <!-- 避免循环引用 -->
                        <value>DisableCircularReferenceDetect</value>
                        <!-- 是否输出值为null的字段 -->
                        <value>WriteMapNullValue</value>
                        <!-- 数值字段如果为null,输出为0,而非null -->
                        <value>WriteNullNumberAsZero</value>
                        <!-- 字符类型字段如果为null,输出为"",而非null  -->
                        <value>WriteNullStringAsEmpty</value>
                        <!-- List字段如果为null,输出为[],而非null -->
                        <value>WriteNullListAsEmpty</value>
                        <!-- Boolean字段如果为null,输出为false,而非null -->
                        <value>WriteNullBooleanAsFalse</value>
                    </array>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

    <!-- 静态资源配置 -->
    <mvc:resources mapping="/resources/**" location="/resources/"/>

    <!-- 对模型视图名称的解析,即在模型视图名称添加前后缀 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <!-- 上传限制 -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 上传文件大小限制为31M,31*1024*1024 -->
        <property name="maxUploadSize" value="32505856"/>
    </bean>

</beans>

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD SQL Map Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--
 |   plugins在配置文件中的位置必须符合要求,否则会报错,顺序如下:
 |   properties?, settings?,
 |   typeAliases?, typeHandlers?,
 |   objectFactory?,objectWrapperFactory?,
 |   plugins?,
 |   environments?, databaseIdProvider?, mappers?
 |-->
<configuration>
    <!--
     | 全局配置设置
     |
     | 可配置选项                   默认值,     描述
     |
     | aggressiveLazyLoading       true,     当设置为‘true’的时候,懒加载的对象可能被任何懒属性全部加载。否则,每个属性都按需加载。
     | multipleResultSetsEnabled   true,     允许和不允许单条语句返回多个数据集(取决于驱动需求)
     | useColumnLabel              true,     使用列标签代替列名称。不同的驱动器有不同的作法。参考一下驱动器文档,或者用这两个不同的选项进行测试一下。
     | useGeneratedKeys            false,    允许JDBC 生成主键。需要驱动器支持。如果设为了true,这个设置将强制使用被生成的主键,有一些驱动器不兼容不过仍然可以执行。
     | autoMappingBehavior         PARTIAL,  指定MyBatis 是否并且如何来自动映射数据表字段与对象的属性。PARTIAL将只自动映射简单的,没有嵌套的结果。FULL 将自动映射所有复杂的结果。
     | defaultExecutorType         SIMPLE,   配置和设定执行器,SIMPLE 执行器执行其它语句。REUSE 执行器可能重复使用prepared statements 语句,BATCH执行器可以重复执行语句和批量更新。
     | defaultStatementTimeout     null,     设置一个时限,以决定让驱动器等待数据库回应的多长时间为超时
     | -->
    <settings>
        <!-- 这个配置使全局的映射器启用或禁用缓存 -->
        <setting name="cacheEnabled" value="true"/>
        <!-- 全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载 -->
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="multipleResultSetsEnabled" value="true"/>
        <setting name="useColumnLabel" value="true"/>
        <setting name="defaultExecutorType" value="REUSE"/>
        <setting name="defaultStatementTimeout" value="25000"/>
    </settings>

</configuration>

dataSource.xml

<?xml version="1.0" encoding="UTF-8"?>
<tenants>
	<tenant>
		<!-- 租户,租户域名(项目中必须唯一)-->
		<tenantKey>www.guorucheng.com;app.guorucheng.com</tenantKey>
		<dataSource>
			<url><![CDATA[jdbc:mysql://localhost:3306/db1?useUnicode=true&characterEncoding=utf8&autoReconnect=true]]></url><!-- 必须的 -->
			<username>root</username><!-- 必须的 -->
			<password>root</password><!-- 必须的 -->
			<initialSize>0</initialSize><!-- 初始化连接大小 -->
			<maxActive>5</maxActive><!-- 连接池最大使用连接数量 -->
			<minIdle>0</minIdle><!-- 连接池最小空闲 -->
			<maxWait>60000</maxWait><!-- 获取连接最大等待时间 -->
			<validationQuery>SELECT 1</validationQuery>
			<testOnBorrow>false</testOnBorrow>
			<testOnReturn>false</testOnReturn>
			<testWhileIdle>true</testWhileIdle>
			<timeBetweenEvictionRunsMillis>60000</timeBetweenEvictionRunsMillis><!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
			<minEvictableIdleTimeMillis>25200000</minEvictableIdleTimeMillis><!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
		</dataSource>
	</tenant>
	<tenant>
		<!-- 租户,租户域名(项目中必须唯一) -->
		<tenantKey>beijing.guorucheng.com;app.beijing.guorucheng.com</tenantKey>
		<dataSource>
			<url><![CDATA[jdbc:mysql://localhost:3306/db2?useUnicode=true&characterEncoding=utf8&autoReconnect=true]]></url><!-- 必须的 -->
			<username>root</username><!-- 必须的 -->
			<password>root</password><!-- 必须的 -->
			<initialSize>0</initialSize><!-- 初始化连接大小 -->
			<maxActive>5</maxActive><!-- 连接池最大使用连接数量 -->
			<minIdle>0</minIdle><!-- 连接池最小空闲 -->
			<maxWait>60000</maxWait><!-- 获取连接最大等待时间 -->
			<validationQuery>SELECT 1</validationQuery>
			<testOnBorrow>false</testOnBorrow>
			<testOnReturn>false</testOnReturn>
			<testWhileIdle>true</testWhileIdle>
			<timeBetweenEvictionRunsMillis>60000</timeBetweenEvictionRunsMillis><!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
			<minEvictableIdleTimeMillis>25200000</minEvictableIdleTimeMillis><!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
		</dataSource>
	</tenant>
</tenants>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
	id="WebApp_ID" version="3.0" >
	
	<!-- 加载Spring配置文件 -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:spring.xml</param-value>
	</context-param>
	
	<!-- 字符集 过滤器 -->
	<filter>
		<filter-name>encodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>encodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	
	<!-- Spring监听器 -->
	<listener>
		<description>Spring监听器</description>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	<!-- 防止Spring内存溢出监听器 -->
	<listener>
		<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
	</listener>
	
	<!-- Spring MVC -->
	<servlet>
		<servlet-name>SpringMVC</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<description>SpringMVC</description>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:spring-mvc.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>SpringMVC</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
	
	<!-- Session超时时间 -->
	<session-config>
		<session-timeout>15</session-timeout>
	</session-config>
	
</web-app>

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.guorucheng</groupId>
	<artifactId>DynamicDataSource</artifactId>
	<version>0.0.1-GRC</version>
	<packaging>war</packaging>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<spring.version>4.2.5.RELEASE</spring.version>
		<junit.version>4.12</junit.version>
		<druid.version>1.1.0</druid.version>
		<fastjson.version>1.2.8</fastjson.version>
		<mybaitsplus.version>2.1-gamma</mybaitsplus.version>
		<velocity.version>1.7</velocity.version>
		<mysql.version>5.1.38</mysql.version>
		<log4j.version>1.2.17</log4j.version>
		<slf4j.version>1.7.19</slf4j.version>
		<aspectjweaver.version>1.8.8</aspectjweaver.version>
		<fileupload.version>1.3.1</fileupload.version>
		<jstl.version>1.2</jstl.version>
		<dom4j.version>1.6.1</dom4j.version>
		<freemarker.version>2.3.26-incubating</freemarker.version>
	</properties>

	<dependencies>
		<!-- JUnit -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>${junit.version}</version>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.freemarker</groupId>
			<artifactId>freemarker</artifactId>
			<version>${freemarker.version}</version>
		</dependency>

		<!-- dom4j -->
		<dependency>
			<groupId>dom4j</groupId>
			<artifactId>dom4j</artifactId>
			<version>${dom4j.version}</version>
		</dependency>

		<!-- Spring -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring.version}</version>
			<type>jar</type>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring.version}</version>
			<type>jar</type>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context-support</artifactId>
			<version>${spring.version}</version>
			<type>jar</type>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${spring.version}</version>
			<type>jar</type>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>${spring.version}</version>
			<type>jar</type>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>${spring.version}</version>
			<type>jar</type>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>${spring.version}</version>
			<type>jar</type>
			<scope>compile</scope>
		</dependency>

		<!-- Spring MVC -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${spring.version}</version>
			<type>jar</type>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.version}</version>
			<type>jar</type>
			<scope>compile</scope>
		</dependency>

		<!-- AOP -->
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>${aspectjweaver.version}</version>
		</dependency>

		<!-- FileUpload -->
		<dependency>
			<groupId>commons-fileupload</groupId>
			<artifactId>commons-fileupload</artifactId>
			<version>${fileupload.version}</version>
		</dependency>

		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>${jstl.version}</version>
		</dependency>

		<!-- Mybatis-Plus -->
		<dependency>
			<groupId>com.baomidou</groupId>
			<artifactId>mybatis-plus</artifactId>
			<version>${mybaitsplus.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.velocity</groupId>
			<artifactId>velocity</artifactId>
			<version>${velocity.version}</version>
		</dependency>

		<!-- Mysql -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>${mysql.version}</version>
		</dependency>

		<!-- Druid -->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid</artifactId>
			<version>${druid.version}</version>
		</dependency>

		<!-- FastJson -->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>${fastjson.version}</version>
		</dependency>

		<!-- Log -->
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>${log4j.version}</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>${slf4j.version}</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>${slf4j.version}</version>
		</dependency>
	</dependencies>

	<build>
		<finalName>DynamicDataSource</finalName>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>1.7</source>
					<target>1.7</target>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>


下载项目部署和mybatis-plus简介

# Mybatis-Plus DynamicDataSource

运行方法:

1. 建立数据库,导入SQL(在resources的sql中)。
2. 引入本Maven项目,修改数据库配置文件。
3. 添加Web服务器,运行。
4. 修改localhost解析
	---127.0.0.1 www.guorucheng.com
	---127.0.0.1 app.guorucheng.com
	---127.0.0.1 beijing.guorucheng.com
	---127.0.0.1 app.beijing.guorucheng.com
5.浏览器地址栏访问:
	http://www.guorucheng.com:8080/DynamicDataSource/sysUser/findSysUsers
	http://app.guorucheng.com:8080/DynamicDataSource/sysUser/findSysUsers
	http://beijing.guorucheng.com:8080/DynamicDataSource/sysUser/findSysUsers
	http://app.beijing.guorucheng.com:8080/DynamicDataSource/sysUser/findSysUsers
	查看数据库切换效果。

> 为简化开发工作、提高生产率而生

# 简介 | Intro

Mybatis 增强工具包 - 只做增强不做改变,简化`CRUD`操作

# 优点 | Advantages

- **纯正血统**:完全继承原生 `Mybatis` 的所有特性
- **最少依赖**:仅仅依赖`Mybatis`以及`Mybatis-Spring`
- **性能损耗小**:启动即会自动注入基本CURD ,性能无损耗,直接面向对象操作
- **自动热加载**:Mapper对应的xml可以热加载,大大减少重启Web服务器时间,提升开发效率
- **自动生成代码**:包含自动生成代码类以及Maven插件,通过少量配置,即可快速生成Mybatis对应的xml、mapper、entity、service、serviceimpl层代码,减少开发时间
- **自定义操作**:支持自定义Sql注入,实现个性化操作
- **自定义转义规则**:支持数据库关键词(例如:`order`、`key`等)自动转义,支持自定义关键词
- **多种主键策略**:支持多达4种主键策略,可自由配置,若无将会自动填充,更有充满黑科技的`分布式全局唯一ID生成器`
- **无缝分页插件**:基于Mybatis物理分页,无需关心具体操作,等同于编写基本`selectList`查询
- **性能分析**:自带Sql性能分析插件,开发测试时,能有效解决慢查询
- **全局拦截**:提供全表`delete`、`update`操作智能分析阻断
- **避免Sql注入**:内置Sql注入内容剥离器,预防Sql注入攻击

# 文档 | Documentation

[中文](http://mp.baomidou.com/) | [English](http://mp.baomidou.com/en/)

# 原理 | Principle

[Mybatis-Plus 实践及架构原理](http://git.oschina.net/baomidou/mybatis-plus/attach_files)



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值