移植多租户,未完全实现
diff --git a/src/main/java/com/supwisdom/dlpay/AppPreparedEvent.java b/src/main/java/com/supwisdom/dlpay/AppPreparedEvent.java
index 304379c..4dead6a 100644
--- a/src/main/java/com/supwisdom/dlpay/AppPreparedEvent.java
+++ b/src/main/java/com/supwisdom/dlpay/AppPreparedEvent.java
@@ -6,7 +6,7 @@
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
-@Configuration
+//@Configuration
public class AppPreparedEvent {
private final DictPool dictPool;
diff --git a/src/main/java/com/supwisdom/dlpay/framework/tenant/HibernateConfig.java b/src/main/java/com/supwisdom/dlpay/framework/tenant/HibernateConfig.java
new file mode 100644
index 0000000..947e0ab
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/framework/tenant/HibernateConfig.java
@@ -0,0 +1,63 @@
+package com.supwisdom.dlpay.framework.tenant;
+
+import org.hibernate.MultiTenancyStrategy;
+import org.hibernate.cfg.Environment;
+import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
+import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties;
+import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
+import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.orm.jpa.JpaVendorAdapter;
+import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
+import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
+
+import javax.persistence.EntityManagerFactory;
+import javax.sql.DataSource;
+import java.util.HashMap;
+import java.util.Map;
+
+@Configuration
+public class HibernateConfig {
+ private final JpaProperties jpaProperties;
+
+ private final HibernateProperties hibernateProperties;
+
+ public HibernateConfig(@Autowired JpaProperties jpaProperties,
+ HibernateProperties hibernateProperties) {
+ this.jpaProperties = jpaProperties;
+ this.hibernateProperties = hibernateProperties;
+ }
+
+ @Bean
+ public JpaVendorAdapter getJpaVendorAdapter() {
+ return new HibernateJpaVendorAdapter();
+ }
+
+ @Bean
+ public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(DataSource dataSource,
+ MultiTenantConnectionProvider multiTenantConnectionProvider,
+ CurrentTenantIdentifierResolver currentTenantIdentifierResolver) {
+ Map<String, Object> properties = new HashMap<>();
+ properties.putAll(hibernateProperties
+ .determineHibernateProperties(jpaProperties.getProperties(),
+ new HibernateSettings()));
+ properties.put(Environment.MULTI_TENANT, MultiTenancyStrategy.SCHEMA);
+ properties.put(Environment.MULTI_TENANT_CONNECTION_PROVIDER, multiTenantConnectionProvider);
+ properties.put(Environment.MULTI_TENANT_IDENTIFIER_RESOLVER, currentTenantIdentifierResolver);
+
+ LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
+ em.setDataSource(dataSource);
+ em.setPackagesToScan("com.supwisdom");
+ em.setJpaPropertyMap(properties);
+ em.setJpaVendorAdapter(getJpaVendorAdapter());
+ return em;
+ }
+
+ @Bean
+ public EntityManagerFactory entityManagerFactoryBean(LocalContainerEntityManagerFactoryBean localBean) {
+ return localBean.getNativeEntityManagerFactory();
+ }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/framework/tenant/MultiTenantConnectionProviderImpl.java b/src/main/java/com/supwisdom/dlpay/framework/tenant/MultiTenantConnectionProviderImpl.java
index 0f1d799..7a0fb8a 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/tenant/MultiTenantConnectionProviderImpl.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/tenant/MultiTenantConnectionProviderImpl.java
@@ -1,20 +1,67 @@
package com.supwisdom.dlpay.framework.tenant;
+import org.hibernate.HibernateException;
import org.hibernate.engine.jdbc.connections.spi.AbstractDataSourceBasedMultiTenantConnectionProviderImpl;
+import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
/**
* Created by shuwei on 2018/12/4.
*/
-public class MultiTenantConnectionProviderImpl extends AbstractDataSourceBasedMultiTenantConnectionProviderImpl {
- @Override
- protected DataSource selectAnyDataSource() {
- return TenantDataSourceProvider.getTenantDataSource("default");
- }
+@Component
+public class MultiTenantConnectionProviderImpl implements MultiTenantConnectionProvider {
+ @Autowired
+ private DataSource dataSource;
- @Override
- protected DataSource selectDataSource(String tenantIdentifier) {
- return TenantDataSourceProvider.getTenantDataSource(TenantThread.getTenantSchema());
+ @Override
+ public Connection getAnyConnection() throws SQLException {
+ return dataSource.getConnection();
+ }
+
+ @Override
+ public void releaseAnyConnection(Connection connection) throws SQLException {
+ connection.close();
+ }
+
+ @Override
+ public Connection getConnection(String ti) throws SQLException {
+ String tenantIdentifier = TenantContext.getTenantSchema();
+ final Connection connection = getAnyConnection();
+ try {
+ if (tenantIdentifier != null) {
+ connection.createStatement().execute("SET search_path = " + tenantIdentifier + ", public");
+ } else {
+ connection.createStatement().execute("SET search_path = public");
+ }
+ } catch (SQLException e) {
+ throw new HibernateException("Problem setting schema to " + tenantIdentifier, e);
}
+ return connection;
+ }
+
+ @Override
+ public void releaseConnection(String tenantIdentifier, Connection connection) throws SQLException {
+ connection.close();
+ }
+
+ @Override
+ public boolean supportsAggressiveRelease() {
+ return false;
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ public boolean isUnwrappableAs(Class unwrapType) {
+ return false;
+ }
+
+ @Override
+ public <T> T unwrap(Class<T> unwrapType) {
+ return null;
+ }
}
diff --git a/src/main/java/com/supwisdom/dlpay/framework/tenant/MultiTenantIdentifierResolver.java b/src/main/java/com/supwisdom/dlpay/framework/tenant/MultiTenantIdentifierResolver.java
index d2dc781..c1dc432 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/tenant/MultiTenantIdentifierResolver.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/tenant/MultiTenantIdentifierResolver.java
@@ -1,21 +1,23 @@
package com.supwisdom.dlpay.framework.tenant;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
+import org.springframework.stereotype.Component;
/**
* Created by shuwei on 2018/12/4.
*/
+@Component
public class MultiTenantIdentifierResolver implements CurrentTenantIdentifierResolver {
- @Override
- public String resolveCurrentTenantIdentifier() {
- if(TenantThread.getTenantSchema()==null){
- return "default";
- }
- return TenantThread.getTenantSchema();
+ @Override
+ public String resolveCurrentTenantIdentifier() {
+ if (TenantContext.getTenantSchema() == null) {
+ return "default";
}
+ return TenantContext.getTenantSchema();
+ }
- @Override
- public boolean validateExistingCurrentSessions() {
- return true;
- }
+ @Override
+ public boolean validateExistingCurrentSessions() {
+ return true;
+ }
}
diff --git a/src/main/java/com/supwisdom/dlpay/framework/tenant/TenantContext.java b/src/main/java/com/supwisdom/dlpay/framework/tenant/TenantContext.java
new file mode 100644
index 0000000..bbee36a
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/framework/tenant/TenantContext.java
@@ -0,0 +1,16 @@
+package com.supwisdom.dlpay.framework.tenant;
+
+/**
+ * Created by shuwei on 2018/11/29.
+ */
+public class TenantContext {
+ private static ThreadLocal<String> currentTenant = new ThreadLocal<>();
+
+ public static void setTenantSchema(String tid) {
+ currentTenant.set(tid);
+ }
+
+ public static String getTenantSchema() {
+ return currentTenant.get();
+ }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/framework/tenant/TenantDataSourceProvider.java b/src/main/java/com/supwisdom/dlpay/framework/tenant/TenantDataSourceProvider.java
deleted file mode 100644
index d93db46..0000000
--- a/src/main/java/com/supwisdom/dlpay/framework/tenant/TenantDataSourceProvider.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package com.supwisdom.dlpay.framework.tenant;
-
-import org.apache.commons.dbcp.BasicDataSource;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.PostConstruct;
-import javax.sql.DataSource;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Created by shuwei on 2018/12/4.
- */
-@Component
-public class TenantDataSourceProvider {
- @Value("${datasource.driverClass}")
- private String driver;
- @Value("${datasource.url}")
- private String url;
- @Value("${datasource.username}")
- private String username;
- @Value("${datasource.password}")
- private String password;
- @Value("${datasource.maxIdle}")
- private int maxIdle;
- @Value("${datasource.maxActive}")
- private int maxActive;
- @Value("${datasource.minIdle}")
- private int minIdle;
- @Value("${datasource.maxWait}")
- private int maxWait;
-
- public static String static_driver;
- public static String static_url;
- public static String static_username;
- public static String static_password;
- public static int static_maxIdle;
- public static int static_maxActive;
- public static int static_minIdle;
- public static int static_maxWait;
-
-
- @PostConstruct
- public void beforeInit() {
- static_driver = driver;
- static_url = url;
- static_username = username;
- static_password = password;
- static_maxIdle = maxIdle;
- static_maxActive = maxActive;
- static_minIdle = minIdle;
- static_maxWait = maxWait;
- }
- // 使用一个map来存储我们租户和对应的数据源,租户和数据源的信息就是从我们的tenant_info表中读出来
- private static Map<String, DataSource> dataSourceMap = new HashMap<>();
-
- /**
- * 静态建立一个数据源,也就是我们的默认数据源,假如我们的访问信息里面没有指定tenantId,就使用默认数据源。
- * 在我这里默认数据源是cloud_config,实际上你可以指向你们的公共信息的库,或者拦截这个操作返回错误。
- */
- // 根据传进来的tenantId决定返回的数据源
- public static DataSource getTenantDataSource(String schemaId) {
- DataSource d = dataSourceMap.get(schemaId);
- if (d == null) {
- String appSchema = schemaId != null ? "'" + schemaId + "','public'" : "'public'";
- String searchPath = "SET search_path = " + appSchema + ";";
- d = createDataSource(schemaId == null, searchPath);
- dataSourceMap.put(schemaId, d);
- }
- return d;
- }
-
- // 初始化的时候用于添加数据源的方法
- public static DataSource createDataSource(boolean rootdatabase, String searchPath) {
- BasicDataSource dataSource = new BasicDataSource();
- dataSource.setDriverClassName(static_driver);
- dataSource.setUrl(static_url);
- dataSource.setUsername(static_username);
- dataSource.setPassword(static_password);
- dataSource.setMaxActive(static_maxActive);
- dataSource.setMaxIdle(static_maxIdle);
- dataSource.setMaxWait(static_maxWait);
- dataSource.setMinIdle(static_minIdle);
- if(static_driver.toLowerCase().contains("oracle")){
- dataSource.setValidationQuery("select 1 from dual");
- }else {
- dataSource.setValidationQuery("select 1 ");
- if(static_driver.toLowerCase().contains("postgresql")) {
- dataSource.setConnectionInitSqls(Collections.singletonList(searchPath));
- }
- }
- return dataSource;
- }
-}
diff --git a/src/main/java/com/supwisdom/dlpay/framework/tenant/TenantInterceptor.java b/src/main/java/com/supwisdom/dlpay/framework/tenant/TenantInterceptor.java
new file mode 100644
index 0000000..73bdbea
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/framework/tenant/TenantInterceptor.java
@@ -0,0 +1,28 @@
+package com.supwisdom.dlpay.framework.tenant;
+
+import com.supwisdom.dlpay.framework.util.Constants;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.ModelAndView;
+import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@Component
+public class TenantInterceptor extends HandlerInterceptorAdapter {
+
+ @Override
+ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
+ throws Exception {
+ String tenantId = request.getHeader(Constants.HEADER_TETANTID);
+ TenantContext.setTenantSchema(tenantId);
+ return true;
+ }
+
+ @Override
+ public void postHandle(HttpServletRequest request, HttpServletResponse response,
+ Object handler, ModelAndView modelAndView)
+ throws Exception {
+ //
+ }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/framework/tenant/TenantThread.java b/src/main/java/com/supwisdom/dlpay/framework/tenant/TenantThread.java
deleted file mode 100644
index 2bfb113..0000000
--- a/src/main/java/com/supwisdom/dlpay/framework/tenant/TenantThread.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.supwisdom.dlpay.framework.tenant;
-
-/**
- * Created by shuwei on 2018/11/29.
- */
-public class TenantThread {
- private static ThreadLocal<String> tenant_schema = new ThreadLocal<>();
-
- public static void setTenantSchema(String tid) {
- tenant_schema.set(tid);
- }
-
- public static String getTenantSchema() {
- return tenant_schema.get();
- }
-}
diff --git a/src/main/java/com/supwisdom/dlpay/framework/util/Constants.java b/src/main/java/com/supwisdom/dlpay/framework/util/Constants.java
index c2e8555..17dd6bc 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/util/Constants.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/util/Constants.java
@@ -2,7 +2,7 @@
public class Constants {
// HTTP HEADER define
- public static final String HEADER_TETANTID = "TENANT-ID";
+ public static final String HEADER_TETANTID = "X-TENANT-ID";
// define
public static final String JWT_CLAIM_TENANTID = "tenantId";
diff --git a/src/main/kotlin/com/supwisdom/dlpay/PayApiApplication.kt b/src/main/kotlin/com/supwisdom/dlpay/PayApiApplication.kt
index 3cfe781..430a8bd 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/PayApiApplication.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/PayApiApplication.kt
@@ -1,15 +1,11 @@
package com.supwisdom.dlpay
-import com.supwisdom.dlpay.system.common.DictPool
import io.lettuce.core.ReadFrom
-import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.autoconfigure.SpringBootApplication
-import org.springframework.boot.context.event.ApplicationPreparedEvent
import org.springframework.boot.runApplication
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
-import org.springframework.context.event.EventListener
import org.springframework.data.redis.connection.RedisConnectionFactory
import org.springframework.data.redis.connection.RedisPassword
import org.springframework.data.redis.connection.RedisStandaloneConfiguration
diff --git a/src/main/kotlin/com/supwisdom/dlpay/framework/controller/security_controller.kt b/src/main/kotlin/com/supwisdom/dlpay/framework/controller/security_controller.kt
index 2304b37..393b5fb 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/framework/controller/security_controller.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/framework/controller/security_controller.kt
@@ -64,7 +64,7 @@
@GetMapping(value = ["/gettoken", "/gettoken/{clientid}"])
fun loginInit(appid: String, @PathVariable clientid: String?,
- @RequestHeader(Constants.HEADER_TETANTID) tetantId: String): ResponseEntity<Any> {
+ @RequestHeader(Constants.HEADER_TETANTID) tetantId: String?): ResponseEntity<Any> {
tetantConfigDao.default?.also {
if (it.tenantId != tetantId) {
diff --git a/src/main/kotlin/com/supwisdom/dlpay/framework/tenant.kt b/src/main/kotlin/com/supwisdom/dlpay/framework/tenant.kt
new file mode 100644
index 0000000..2990f19
--- /dev/null
+++ b/src/main/kotlin/com/supwisdom/dlpay/framework/tenant.kt
@@ -0,0 +1,24 @@
+package com.supwisdom.dlpay.framework
+
+import com.supwisdom.dlpay.framework.util.Constants
+import org.springframework.core.annotation.Order
+import javax.servlet.Filter
+import javax.servlet.FilterChain
+import javax.servlet.ServletRequest
+import javax.servlet.ServletResponse
+import javax.servlet.annotation.WebFilter
+import javax.servlet.http.HttpServletRequest
+
+
+@Order(1)
+@WebFilter(filterName = "multi_tenant_filter", urlPatterns = ["/*"])
+class TenantNameFilter : Filter {
+ override fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain) {
+ if (request is HttpServletRequest) {
+ request.getHeader(Constants.HEADER_TETANTID)?.also {
+ // set tanent datasource
+ }
+ }
+ chain.doFilter(request, response)
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/supwisdom/dlpay/security.kt b/src/main/kotlin/com/supwisdom/dlpay/security.kt
index 8cf8e9f..d898fb7 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/security.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/security.kt
@@ -98,7 +98,7 @@
return
}
val claims = getUtil().verifyToken(jwt)
- if(url.equals("/mobileapi/logout")){
+ if(url == "/mobileapi/logout"){
SecurityContextHolder.clearContext()
apiJwtRepository.deleteById(claims[ReservedClaimNames.JWT_ID].toString())
throw JoseException("JWT has not been register")
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 18ea9d2..4beb006 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -14,6 +14,7 @@
#################### JSP PAGE ####################
#spring.mvc.view.prefix=/pages/
#spring.mvc.view.suffix=.jsp
+server.servlet.context-path=/payapi
#################### thymeleaf ####################
spring.mvc.static-path-pattern=/static/**
spring.thymeleaf.prefix=classpath:/templates/
diff --git a/src/main/resources/import.sql b/src/main/resources/import.sql
index 262c0c1..a1161f6 100644
--- a/src/main/resources/import.sql
+++ b/src/main/resources/import.sql
@@ -1,3 +1,6 @@
+INSERT INTO tb_tenantconfig(cfgid, tenantid, datacenter_id)
+values ('main', '10000110', '01');
+
INSERT INTO tb_operator(operid, closedate, opendate, opercode, opername, operpwd, opertype, status)
VALUES ('LOR2IwRkbOjp+sVG9KR2BpHZbwGKepS4', '20500101', '20190101', 'system', '系统管理员', '$2a$10$Ex9xp11.vCaD8D0a7ahiUOKqDij1TcCUBwRAmrqXeDvAkmzLibn4.', 'oper', 'normal');