太难了

This commit is contained in:
Wang Chen Chen
2022-12-13 18:08:52 +08:00
parent 42ae525be2
commit 743d7c46b8
173 changed files with 1295 additions and 1452 deletions

2
.gitignore vendored
View File

@@ -1,4 +1,4 @@
README.md
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/

27
README.md Normal file
View File

@@ -0,0 +1,27 @@
# Getting Started
### Reference Documentation
For further reference, please consider the following sections:
* [Official Apache Maven documentation](https://maven.apache.org/guides/index.html)
* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/3.0.0/maven-plugin/reference/html/)
* [Create an OCI image](https://docs.spring.io/spring-boot/docs/3.0.0/maven-plugin/reference/html/#build-image)
* [Spring Configuration Processor](https://docs.spring.io/spring-boot/docs/3.0.0/reference/htmlsingle/#appendix.configuration-metadata.annotation-processor)
* [Spring Web](https://docs.spring.io/spring-boot/docs/3.0.0/reference/htmlsingle/#web)
* [Validation](https://docs.spring.io/spring-boot/docs/3.0.0/reference/htmlsingle/#io.validation)
* [Spring Data Redis (Access+Driver)](https://docs.spring.io/spring-boot/docs/3.0.0/reference/htmlsingle/#data.nosql.redis)
* [Spring Boot DevTools](https://docs.spring.io/spring-boot/docs/3.0.0/reference/htmlsingle/#using.devtools)
* [Spring Boot Actuator](https://docs.spring.io/spring-boot/docs/3.0.0/reference/htmlsingle/#actuator)
### Guides
The following guides illustrate how to use some features concretely:
* [Building a RESTful Web Service](https://spring.io/guides/gs/rest-service/)
* [Serving Web Content with Spring MVC](https://spring.io/guides/gs/serving-web-content/)
* [Building REST services with Spring](https://spring.io/guides/tutorials/rest/)
* [Validation](https://spring.io/guides/gs/validating-form-input/)
* [Messaging with Redis](https://spring.io/guides/gs/messaging-redis/)
* [Building a RESTful Web Service with Spring Boot Actuator](https://spring.io/guides/gs/actuator-service/)

View File

@@ -0,0 +1,24 @@
### 获取全局配置列表
GET {{baseUrl}}/sys/config/query
Content-Type: application/json
#x-tenant-id: {{tenantId}}
x-tenant-id: google
Authorization: Bearer {{tokenValue}}
### 获取用户列表
GET {{baseUrl}}/pms/user
Content-Type: application/json
#x-tenant-id: {{tenantId}}
x-tenant-id: apple
Authorization: Bearer {{tokenValue}}
### 获取局配置数据
GET {{baseUrl}}/pms/role
Content-Type: application/json
# x-tenant-id: {{tenantId}}
x-tenant-id: google
Authorization: Bearer {{tokenValue}}

View File

@@ -10,9 +10,30 @@ Authorization: Bearer {{tokenValue}}
"name": "apple",
"email": "apple@gmail.com",
"linkman": "乔布斯",
"contactNumber": "1521332423",
"contactNumber": "15999999999",
"areaCode": "123123221311",
"address": "美国硅谷"
"address": "美国硅谷",
"templateIds": [
1
]
}
### 创建租户
POST {{baseUrl}}/sys/tenant
Content-Type: application/json
x-tenant-id: {{tenantId}}
Authorization: Bearer {{tokenValue}}
{
"tenantId": "google",
"logo": "https://google.com/google.png",
"name": "google",
"email": "google@gmail.com",
"linkman": "拉里·佩奇",
"contactNumber": "1521332466",
"areaCode": "123123221311",
"address": "美国加利福尼亚州圣克拉拉县山景市"
}
@@ -34,6 +55,16 @@ Authorization: Bearer {{tokenValue}}
}
### 获取租户列表
GET {{baseUrl}}/sys/tenant/query
Content-Type: application/json
#x-tenant-id: {{tenantId}}
x-tenant-id: apple
Authorization: Bearer {{tokenValue}}
### 获取租户详情
GET {{baseUrl}}/sys/tenant/apple
Content-Type: application/json

View File

@@ -16,7 +16,7 @@ User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:86.0) Gecko/20100101 Fi
"username": "admin",
"password": "123456",
"codeKey": "5jXzuwcoUzbtnHNh",
"codeText": "tj2yf"
"codeText": "ry2oo"
}
> {%
@@ -46,18 +46,3 @@ x-tenant-id: {{tenantId}}
Authorization: Bearer {{tokenValue}}
### 获取用户列表
GET {{baseUrl}}/pms/user
Content-Type: application/json
x-tenant-id: {{tenantId}}
#x-tenant-id: apple
Authorization: Bearer {{tokenValue}}
### 获取用户列表
GET {{baseUrl}}/sys/config/query
Content-Type: application/json
x-tenant-id: {{tenantId}}
# x-tenant-id: apple
Authorization: Bearer {{tokenValue}}

View File

@@ -1,65 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>
<parent>
<artifactId>molly-multi-tenant</artifactId>
<groupId>com.xaaef.molly</groupId>
<version>1.0.1</version>
<relativePath>../pom.xml</relativePath>
</parent>
<packaging>jar</packaging>
<artifactId>molly-admin</artifactId>
<name>molly-admin</name>
<description>
后台管理
</description>
<dependencies>
<dependency>
<groupId>com.xaaef.molly</groupId>
<artifactId>molly-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.xaaef.molly</groupId>
<artifactId>molly-perms</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.xaaef.molly</groupId>
<artifactId>molly-system</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,38 +0,0 @@
package com.xaaef.molly.controller;
import com.xaaef.molly.common.util.JsonResult;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>
* 中国行政地区 Controller
* </p>
*
* @author Wang Chen Chen
* @version 1.0
* @date 2021/7/5 16:37
*/
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/china/area")
public class ChinaAreaController {
@GetMapping()
public JsonResult<String> findById() {
return JsonResult.success();
}
@GetMapping("/hello")
public JsonResult<String> hello() {
return JsonResult.success();
}
}

View File

@@ -1,26 +0,0 @@
package com.xaaef.molly.common;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
/**
* <p>
* 测试类
* </p>
*
* @author WangChenChen
* @version 1.1
* @date 2022/12/9 10:26
*/
@Slf4j
public class CommonTest {
@Test
public void test1() {
}
}

View File

@@ -1,88 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>
<parent>
<artifactId>molly-multi-tenant</artifactId>
<groupId>com.xaaef.molly</groupId>
<version>1.0.1</version>
<relativePath>../pom.xml</relativePath>
</parent>
<packaging>jar</packaging>
<artifactId>molly-common</artifactId>
<name>molly-common</name>
<description>
通用模块,核心工具,函数
</description>
<dependencies>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-http</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-jwt</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-captcha</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
</dependency>
<dependency>
<groupId>org.msgpack</groupId>
<artifactId>msgpack-core</artifactId>
<version>${msgpack.version}</version>
</dependency>
<dependency>
<groupId>org.msgpack</groupId>
<artifactId>jackson-dataformat-msgpack</artifactId>
<version>${msgpack.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,87 +0,0 @@
package com.xaaef.molly.common.consts;
/**
* <p>
* 全局配置文件 key
* </p>
*
* @author Wang Chen Chen
* @version 1.0.1
* @date 2021/7/16 15:15
*/
public class ConfigName {
/**
* 用户默认密码
*/
public static final String REDIS_CACHE_KEY = "sys_config_cache";
/**
* 用户默认密码
*/
public static final String USER_DEFAULT_PASSWORD = "user_default_password";
/**
* 租户默认logo
*/
public static final String TENANT_DEFAULT_LOGO = "tenant_default_logo";
/**
* 租户默认角色名称
*/
public static final String TENANT_DEFAULT_ROLE_NAME = "tenant_default_role_name";
/**
* [旧的] 获取法定节假日的接口
*/
public static final String LEGAL_HOLIDAY_URL = "legal_holiday_url";
/**
* 获取法定节假日的接口
*/
public static final String GET_HOLIDAY_URL = "get_holiday_url";
/**
* 顶级 租户ID
*/
public static final String SYS_TENANT_ID = "root_tenant_id";
/**
* 引导灯RGB初始化配置
*/
public static final String GUIDE_LIGHT_RGB = "guide_light_rgb";
/**
* 日期模式 初始化配置
*/
public static final String INIT_DATE_MODE = "init_date_mode";
/**
* 区域 点位最大数量
*/
public static final String AREA_POINT_MAX_NUMBER = "area_point_max_number";
/**
* 产品制造商
*/
public static final String MANUFACTURER = "manufacturer";
/**
* 碳排放的 默认 0.785
*/
public static final String CARBON_EMISSION = "carbon_emission";
}

View File

@@ -1,142 +0,0 @@
package com.xaaef.molly.common.util;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.extern.slf4j.Slf4j;
import org.msgpack.jackson.dataformat.MessagePackFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* <p>
* jackson Json 工具类
* </p>
*
* @author Wang Chen Chen <932560435@qq.com>
* @version 2.0
* @date 2019/4/18 11:45
*/
@Slf4j
public class MsgpackUtils {
private static final ObjectMapper MAPPER = new ObjectMapper(new MessagePackFactory())
.registerModules(new Jdk8Module(), new JavaTimeModule())
.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true)
.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.setSerializationInclusion(JsonInclude.Include.NON_NULL);
public static ObjectMapper getMapper() {
return MAPPER;
}
/**
* 将 对象 转换成 二进制
*
* @param data
* @return java.util.List<T>
* @author Wang Chen Chen <932560435@qq.com>
* @date 2019/4/18 15:26
*/
public static byte[] toBytes(Object data) {
try {
return MAPPER.writeValueAsBytes(data);
} catch (JsonProcessingException e) {
log.error(e.getMessage());
}
return new byte[0];
}
/**
* 将 二进制 结果集转化为对象
*
* @param data
* @param beanType
* @return java.util.List<T>
* @author Wang Chen Chen <932560435@qq.com>
* @date 2019/4/18 15:26
*/
public static <T> T toPojo(byte[] data, Class<T> beanType) {
try {
return MAPPER.readValue(data, 0, data.length, beanType);
} catch (Exception e) {
log.error(e.getMessage());
}
return null;
}
/**
* 将 二进制 数据转换成 pojo 对象 list
*
* @param data
* @param beanType
* @return java.util.List<T>
* @author Wang Chen Chen <932560435@qq.com>
* @date 2019/4/18 15:26
*/
public static <T> List<T> toListPojo(byte[] data, Class<T> beanType) {
try {
return MAPPER.readValue(data, MAPPER.getTypeFactory().constructCollectionType(ArrayList.class, beanType));
} catch (Exception e) {
log.error(e.getMessage());
}
return null;
}
/**
* 将 二进制 数据转换成 Map
*
* @param data
* @param keyType
* @param valueType
* @return java.util.List<T>
* @author Wang Chen Chen <932560435@qq.com>
* @date 2019/4/18 15:26
*/
public static <K, V> Map<K, V> toMap(byte[] data, Class<K> keyType, Class<V> valueType) {
try {
return MAPPER.readValue(data, MAPPER.getTypeFactory().constructMapType(HashMap.class, keyType, valueType));
} catch (Exception e) {
log.error(e.getMessage());
}
return null;
}
/**
* 将二进制数据转换成 pojo对象list
*
* @param data
* @param keyType
* @param valueType
* @return java.util.List<T>
* @author Wang Chen Chen <932560435@qq.com>
* @date 2019/4/18 15:26
*/
public static <K, V> List<Map<K, V>> toListMap(byte[] data, Class<K> keyType, Class<V> valueType) {
try {
return MAPPER.readValue(
data,
MAPPER.getTypeFactory().constructCollectionType(ArrayList.class,
MAPPER.getTypeFactory().constructMapType(HashMap.class, keyType, valueType)
)
);
} catch (Exception e) {
log.error(e.getMessage());
}
return null;
}
}

View File

@@ -1,79 +0,0 @@
package com.xaaef.molly.common;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import com.xaaef.molly.common.domain.RectPoint;
import com.xaaef.molly.common.util.RectRangeUtils;
import com.xaaef.molly.common.util.ServletUtils;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.Objects;
/**
* <p>
* 测试类
* </p>
*
* @author WangChenChen
* @version 1.1
* @date 2022/12/9 10:26
*/
@Slf4j
public class CommonTest {
@Test
public void test1() {
var ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:108.0) Gecko/20100101 Firefox/108.0";
var userAgent = ServletUtils.getUserAgent(ua);
var browser = StrUtil.format("{} {}", userAgent.getBrowser(), userAgent.getVersion());
System.out.println(browser);
var os = StrUtil.format("{} {}", userAgent.getPlatform(), Objects.requireNonNullElse(userAgent.getOsVersion(), ""));
System.out.println(os);
}
@Test
public void test2() {
// 需要检测的点位
var points = List.of(
new RectPoint<>(618.33D, 334.99D, 1L),
new RectPoint<>(265D, 653D, 2L),
new RectPoint<>(406.25D, 501.25D, 2L)
);
var topLeft = new RectPoint<Long>(289D, 209D);
var bottomRight = new RectPoint<Long>(1029D, 549D);
points.forEach(target -> {
boolean a = RectRangeUtils.isIn(target, topLeft, bottomRight);
System.out.printf("%s => %b\r\n", target.getId(), a);
});
}
@Test
public void test3() {
int i = (19 / 100) + 1;
System.out.println(i);
}
@Test
public void test4() {
var jwt = JWTUtil.parseToken("654wq1e45qw");
var loginId = jwt.getPayloads().getStr(JWT.SUBJECT);
System.out.println(loginId);
}
}

View File

@@ -1,93 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>
<parent>
<artifactId>molly-multi-tenant</artifactId>
<groupId>com.xaaef.molly</groupId>
<version>1.0.1</version>
<relativePath>../pom.xml</relativePath>
</parent>
<packaging>jar</packaging>
<artifactId>molly-core</artifactId>
<name>molly-core</name>
<description>
核心模块
</description>
<dependencies>
<dependency>
<groupId>com.xaaef.molly</groupId>
<artifactId>molly-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,126 +0,0 @@
package com.xaaef.molly.core.tenant;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.CallbackException;
import org.hibernate.Interceptor;
import org.hibernate.metamodel.RepresentationMode;
import org.hibernate.metamodel.spi.EntityRepresentationStrategy;
import org.hibernate.type.Type;
import org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer;
import org.springframework.stereotype.Component;
import java.util.Iterator;
import java.util.Map;
import static org.hibernate.cfg.AvailableSettings.INTERCEPTOR;
/**
* <p>
* </p>
*
* @author WangChenChen
* @version 1.1
* @date 2022/12/12 18:25
*/
@Slf4j
@Component
public class CustomInterceptor implements Interceptor, HibernatePropertiesCustomizer, java.io.Serializable {
@Override
public boolean onLoad(Object entity, Object id, Object[] state, String[] propertyNames, Type[] types) throws CallbackException {
log.info("onLoad...");
return Interceptor.super.onLoad(entity, id, state, propertyNames, types);
}
@Override
public boolean onFlushDirty(Object entity, Object id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) throws CallbackException {
log.info("onFlushDirty...");
return Interceptor.super.onFlushDirty(entity, id, currentState, previousState, propertyNames, types);
}
@Override
public boolean onSave(Object entity, Object id, Object[] state, String[] propertyNames, Type[] types) throws CallbackException {
log.info("onSave...");
return Interceptor.super.onSave(entity, id, state, propertyNames, types);
}
@Override
public void onDelete(Object entity, Object id, Object[] state, String[] propertyNames, Type[] types) throws CallbackException {
log.info("onDelete...");
Interceptor.super.onDelete(entity, id, state, propertyNames, types);
}
@Override
public void onCollectionRecreate(Object collection, Object key) throws CallbackException {
log.info("onCollectionRecreate...");
Interceptor.super.onCollectionRecreate(collection, key);
}
@Override
public void onCollectionRemove(Object collection, Object key) throws CallbackException {
log.info("onCollectionRemove...");
Interceptor.super.onCollectionRemove(collection, key);
}
@Override
public void onCollectionUpdate(Object collection, Object key) throws CallbackException {
log.info("onCollectionUpdate...");
Interceptor.super.onCollectionUpdate(collection, key);
}
@Override
public void preFlush(Iterator<Object> entities) throws CallbackException {
log.info("preFlush...");
Interceptor.super.preFlush(entities);
}
@Override
public void postFlush(Iterator<Object> entities) throws CallbackException {
log.info("postFlush...");
Interceptor.super.postFlush(entities);
}
@Override
public Boolean isTransient(Object entity) {
log.info("isTransient...");
return Interceptor.super.isTransient(entity);
}
@Override
public int[] findDirty(Object entity, Object id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) {
log.info("findDirty...");
return Interceptor.super.findDirty(entity, id, currentState, previousState, propertyNames, types);
}
@Override
public Object instantiate(String entityName, EntityRepresentationStrategy representationStrategy, Object id) throws CallbackException {
log.info("instantiate...");
return Interceptor.super.instantiate(entityName, representationStrategy, id);
}
@Override
public Object instantiate(String entityName, RepresentationMode representationMode, Object id) throws CallbackException {
log.info("instantiate...");
return Interceptor.super.instantiate(entityName, representationMode, id);
}
@Override
public String getEntityName(Object object) throws CallbackException {
log.info("getEntityName...");
return Interceptor.super.getEntityName(object);
}
@Override
public Object getEntity(String entityName, Object id) throws CallbackException {
log.info("getEntity...");
return Interceptor.super.getEntity(entityName, id);
}
@Override
public void customize(Map<String, Object> hibernateProperties) {
hibernateProperties.put(INTERCEPTOR, this);
}
}

View File

@@ -1,39 +0,0 @@
package com.xaaef.molly.core;
import com.xaaef.molly.core.auth.jwt.JwtSecurityUtils;
import com.xaaef.molly.core.tenant.enums.DbStyle;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
/**
* <p>
* 测试类
* </p>
*
* @author WangChenChen
* @version 1.1
* @date 2022/12/9 10:26
*/
@Slf4j
public class CoreTest {
@Test
public void test1() {
String admin = JwtSecurityUtils.encryptPassword("admin");
System.out.println(admin);
String apple = JwtSecurityUtils.encryptPassword("apple");
System.out.println(apple);
}
@Test
public void test2() {
int i = 2 % 100;
System.out.println(i);
}
}

View File

@@ -1,53 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>
<parent>
<artifactId>molly-multi-tenant</artifactId>
<groupId>com.xaaef.molly</groupId>
<version>1.0.1</version>
<relativePath>../pom.xml</relativePath>
</parent>
<packaging>jar</packaging>
<artifactId>molly-perms</artifactId>
<name>molly-perms</name>
<description>
权限管理模块
</description>
<dependencies>
<dependency>
<groupId>com.xaaef.molly</groupId>
<artifactId>molly-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.xaaef.molly</groupId>
<artifactId>molly-core</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,7 +0,0 @@
package com.xaaef.molly.perms.repository;
import com.xaaef.molly.perms.entity.SysUser;
import org.springframework.data.jpa.repository.JpaRepository;
public interface SysUserRepository extends JpaRepository<SysUser, Long> {
}

View File

@@ -1,8 +0,0 @@
package com.xaaef.molly.perms.repository;
import com.xaaef.molly.perms.entity.SysUserSocial;
import org.springframework.data.jpa.repository.JpaRepository;
public interface SysUserSocialRepository extends JpaRepository<SysUserSocial, Long> {
}

View File

@@ -1,26 +0,0 @@
package com.xaaef.molly.common;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
/**
* <p>
* 测试类
* </p>
*
* @author WangChenChen
* @version 1.1
* @date 2022/12/9 10:26
*/
@Slf4j
public class CommonTest {
@Test
public void test1() {
}
}

View File

@@ -1,41 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>
<parent>
<artifactId>molly-multi-tenant</artifactId>
<groupId>com.xaaef.molly</groupId>
<version>1.0.1</version>
<relativePath>../pom.xml</relativePath>
</parent>
<packaging>jar</packaging>
<artifactId>molly-quartz</artifactId>
<name>molly-quartz</name>
<description>
quartz 定时任务
</description>
<dependencies>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,26 +0,0 @@
package com.xaaef.molly.common;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
/**
* <p>
* 测试类
* </p>
*
* @author WangChenChen
* @version 1.1
* @date 2022/12/9 10:26
*/
@Slf4j
public class CommonTest {
@Test
public void test1() {
}
}

View File

@@ -1,53 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>
<parent>
<artifactId>molly-multi-tenant</artifactId>
<groupId>com.xaaef.molly</groupId>
<version>1.0.1</version>
<relativePath>../pom.xml</relativePath>
</parent>
<packaging>jar</packaging>
<artifactId>molly-system</artifactId>
<name>molly-system</name>
<description>
系统模块
</description>
<dependencies>
<dependency>
<groupId>com.xaaef.molly</groupId>
<artifactId>molly-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.xaaef.molly</groupId>
<artifactId>molly-core</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,54 +0,0 @@
package com.xaaef.molly.system.controller;
import com.xaaef.molly.common.util.JsonResult;
import com.xaaef.molly.system.entity.SysTenant;
import com.xaaef.molly.system.service.SysTenantService;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
@AllArgsConstructor
@RestController
@RequestMapping("/sys/tenant")
public class TenantController {
public final SysTenantService baseService;
@GetMapping("/{id}")
public JsonResult<SysTenant> findById(@PathVariable("id") String id) {
return JsonResult.success(baseService.getById(id));
}
@GetMapping("/exist/{id}")
public JsonResult<Boolean> existById(@PathVariable("id") String id) {
return JsonResult.success(baseService.existsById(id));
}
@PostMapping
public JsonResult<SysTenant> save(@RequestBody SysTenant tenant) {
return JsonResult.success(
baseService.save(tenant)
);
}
@PutMapping
public JsonResult<SysTenant> updateById(@RequestBody SysTenant tenant) {
return JsonResult.success(
baseService.updateById(tenant)
);
}
@DeleteMapping("/{id}")
public JsonResult<String> deleteById(@PathVariable("id") String id) {
baseService.deleteById(id);
return JsonResult.success();
}
}

View File

@@ -1,10 +0,0 @@
package com.xaaef.molly.system.repository;
import com.xaaef.molly.system.entity.ChinaArea;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ChinaAreaRepository extends JpaRepository<ChinaArea, Long> {
}

View File

@@ -1,11 +0,0 @@
package com.xaaef.molly.system.repository;
import com.xaaef.molly.system.entity.SysDictData;
import org.springframework.data.jpa.repository.JpaRepository;
public interface SysDictDataRepository extends JpaRepository<SysDictData, Long> {
}

View File

@@ -1,13 +0,0 @@
package com.xaaef.molly.system.repository;
import com.xaaef.molly.system.entity.SysDictType;
import org.springframework.data.jpa.repository.JpaRepository;
public interface SysDictTypeRepository extends JpaRepository<SysDictType, Long> {
}

View File

@@ -1,12 +0,0 @@
package com.xaaef.molly.system.repository;
import com.xaaef.molly.system.entity.SysMenu;
import org.springframework.data.jpa.repository.JpaRepository;
public interface SysMenuRepository extends JpaRepository<SysMenu, Long> {
}

View File

@@ -1,32 +0,0 @@
package com.xaaef.molly.system.service;
import com.xaaef.molly.system.entity.ChinaArea;
import java.util.Collection;
import java.util.Optional;
public interface ChinaAreaService {
Optional<ChinaArea> findById(Long id);
ChinaArea save(ChinaArea entity);
Collection<ChinaArea> saveBatch(Collection<ChinaArea> entity);
ChinaArea updateById(ChinaArea entity);
Collection<ChinaArea> updateByIdBatch(Collection<ChinaArea> arr);
void deleteById(Long id);
void deleteAllById(Collection<Long> ids);
}

View File

@@ -1,106 +0,0 @@
package com.xaaef.molly.system.service.impl;
import cn.hutool.core.util.IdUtil;
import com.xaaef.molly.core.tenant.DataSourceManager;
import com.xaaef.molly.core.tenant.base.service.impl.BaseServiceImpl;
import com.xaaef.molly.core.tenant.service.MultiTenantManager;
import com.xaaef.molly.system.entity.SysTenant;
import com.xaaef.molly.system.repository.SysTenantRepository;
import com.xaaef.molly.system.service.SysConfigService;
import com.xaaef.molly.system.service.SysTenantService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.Optional;
import static com.xaaef.molly.common.consts.ConfigName.TENANT_DEFAULT_LOGO;
import static com.xaaef.molly.core.auth.jwt.JwtSecurityUtils.isAdminUser;
import static com.xaaef.molly.core.auth.jwt.JwtSecurityUtils.isMasterUser;
/**
* <p>
* </p>
*
* @author WangChenChen
* @version 1.1
* @date 2022/12/9 15:36
*/
@Slf4j
@Service
@AllArgsConstructor
public class SysTenantServiceImpl extends BaseServiceImpl<SysTenantRepository, SysTenant, String>
implements SysTenantService {
private final MultiTenantManager tenantManager;
private final DataSourceManager dataSourceManager;
private final SysConfigService configService;
/**
* uuid
*/
public static String getUUIDSuffix() {
return IdUtil.fastUUID().split("-")[4];
}
@Transactional(rollbackFor = Exception.class)
@Override
public SysTenant save(SysTenant entity) {
if (!isMasterUser()) {
throw new RuntimeException("只有系统用户,才能创建租户!");
}
if (StringUtils.isBlank(entity.getTenantId())) {
do {
entity.setTenantId(getUUIDSuffix());
}
while (tenantManager.existById(entity.getTenantId()));
} else {
if (tenantManager.existById(entity.getTenantId())) {
throw new RuntimeException(String.format("租户ID %s 已经存在了!", entity.getTenantId()));
}
}
if (entity.getExpired() == null) {
entity.setExpired(LocalDateTime.now().plusYears(10));
}
if (entity.getStatus() == null) {
entity.setStatus((byte) 0);
}
if (entity.getLogo() == null) {
var defaultLogoPath = configService.findValueByKey(TENANT_DEFAULT_LOGO);
entity.setLogo(defaultLogoPath);
}
var save = super.save(entity);
// 将 新创建的 租户ID 保存到 redis 中
tenantManager.addTenantId(entity.getTenantId());
// 新创建的 租户 创建表结构
dataSourceManager.createTable(entity.getTenantId());
return save;
}
@Transactional(rollbackFor = Exception.class)
@Override
public void deleteById(String id) {
if (isMasterUser() && isAdminUser()) {
if (!existsById(id)) {
return;
}
super.deleteById(id);
tenantManager.removeTenantId(id);
dataSourceManager.deleteTable(id);
} else {
throw new RuntimeException("非系统管理员,无法删除租户!");
}
}
}

View File

@@ -1,28 +0,0 @@
package com.xaaef.molly.system;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
/**
* <p>
* 测试类
* </p>
*
* @author WangChenChen
* @version 1.1
* @date 2022/12/9 10:26
*/
@Slf4j
@SpringBootTest
public class SystemTest {
@Test
public void test1() {
}
}

102
pom.xml
View File

@@ -2,7 +2,7 @@
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<packaging>jar</packaging>
<groupId>com.xaaef.molly</groupId>
<artifactId>molly-multi-tenant</artifactId>
<version>1.0.1</version>
@@ -12,15 +12,6 @@
molly jpa multi tenant sass platform
</description>
<modules>
<module>molly-common</module>
<module>molly-core</module>
<module>molly-perms</module>
<module>molly-quartz</module>
<module>molly-system</module>
<module>molly-admin</module>
</modules>
<properties>
<java.version>17</java.version>
<maven.compiler.source>17</maven.compiler.source>
@@ -30,6 +21,7 @@
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<hutool.version>5.8.10</hutool.version>
<knife4j.version>3.0.3</knife4j.version>
<msgpack.version>0.9.2</msgpack.version>
<spring-boot.version>3.0.0</spring-boot.version>
@@ -43,11 +35,89 @@
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-http</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-jwt</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-captcha</artifactId>
</dependency>
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
</dependency>
<!--引入Knife4j的官方start包,Swagger2基于Springfox2.10.5项目-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>${knife4j.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
@@ -108,6 +178,18 @@
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>

View File

@@ -2,24 +2,29 @@ package com.xaaef.molly;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
* <p>
* spring boot jpa 多租户 启动类
* </p>
*
* @author WangChenChen
* @version 1.1
* @date 2022/12/9 10:49
* @version 1.0.1
* @date 2021/10/14 14:24
*/
@EnableAsync
@EnableCaching
@EnableScheduling
@SpringBootApplication
public class MollyAdminApplication {
public class MollyApplication {
public static void main(String[] args) {
SpringApplication.run(MollyAdminApplication.class, args);
SpringApplication.run(MollyApplication.class, args);
}
}

View File

@@ -0,0 +1,46 @@
package com.xaaef.molly.common.consts;
/**
* <p>
* 全局配置文件 key
* </p>
*
* @author Wang Chen Chen
* @version 1.0.1
* @date 2021/7/16 15:15
*/
public class ConfigName {
/**
* 系统配置
*/
public static final String REDIS_CACHE_KEY = "sys_config_cache";
/**
* 用户默认密码
*/
public static final String USER_DEFAULT_PASSWORD = "user_default_password";
/**
* 租户默认logo
*/
public static final String TENANT_DEFAULT_LOGO = "default_tenant_logo";
/**
* 租户默认角色名称
*/
public static final String TENANT_DEFAULT_ROLE_NAME = "default_role_name";
/**
* 获取法定节假日的接口
*/
public static final String GET_HOLIDAY_URL = "get_holiday_url";
}

View File

@@ -20,19 +20,19 @@ import lombok.ToString;
@ToString
public enum GenderType {
FEMALE(0, ""),
FEMALE((byte) 0, ""),
MALE(1, ""),
MALE((byte) 1, ""),
UNKNOWN(2, "未知");
UNKNOWN((byte) 2, "未知");
GenderType(int code, String description) {
GenderType(byte code, String description) {
this.code = code;
this.description = description;
}
@JsonCreator
public static GenderType get(int code) {
public static GenderType get(byte code) {
if (FEMALE.code == code) {
return FEMALE;
} else if (MALE.code == code) {
@@ -43,7 +43,7 @@ public enum GenderType {
}
@JsonValue
private final int code;
private final byte code;
private final String description;

View File

@@ -1,5 +1,6 @@
package com.xaaef.molly.core.tenant;
import cn.hutool.core.util.StrUtil;
import com.xaaef.molly.core.auth.jwt.JwtSecurityUtils;
import com.xaaef.molly.core.tenant.props.MultiTenantProperties;
import com.xaaef.molly.core.tenant.util.TenantUtils;
@@ -37,7 +38,7 @@ public class CustomTenantResolver implements CurrentTenantIdentifierResolver,
@Override
public String resolveCurrentTenantIdentifier() {
log.info("resolveCurrentTenantIdentifier {} ................", TenantUtils.getTenantId());
log.debug("2.CustomTenantResolver.resolveCurrentTenantIdentifier(): {} ", TenantUtils.getTenantId());
// 如果当前是 master 直接放过任何用户都可以进入 master 读取一些公共的数据: 全局配置权限菜单
if (StringUtils.equals(props.getDefaultTenantId(), TenantUtils.getTenantId())) {
return TenantUtils.getTenantId();

View File

@@ -0,0 +1,66 @@
package com.xaaef.molly.core.tenant;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties;
import org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* <p>
* 所有租户的 EntityManager
* 比如: 全局配置,字典集合,之类的表,使用的是公有的数据库
* </p>
*
* @author WangChenChen
* @version 1.1
* @date 2022/12/13 11:37
*/
@Slf4j
@Configuration
@AllArgsConstructor
public class DataSourceConfig {
private final DataSourceProperties dataSourceProperties;
@Primary
@Bean(name = "multiTenantDataSource")
public DataSource multiTenantDataSource() {
return dataSourceProperties.initializeDataSourceBuilder().build();
}
@Bean(name = "commonTenantDataSource")
public DataSource commonTenantDataSource() {
return dataSourceProperties.initializeDataSourceBuilder().build();
}
}

View File

@@ -4,7 +4,7 @@ import com.xaaef.molly.core.tenant.props.MultiTenantProperties;
import javax.sql.DataSource;
public interface DataSourceManager {
public interface DatabaseManager {
default String getOldDbName(String url) {
var startInx = url.lastIndexOf("?");

View File

@@ -0,0 +1,110 @@
package com.xaaef.molly.core.tenant;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties;
import org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* <p>
* 所有租户的 EntityManager
* 比如: 全局配置,字典集合,之类的表,使用的是公有的数据库
* </p>
*
* @author WangChenChen
* @version 1.1
* @date 2022/12/13 11:37
*/
@Slf4j
@Configuration
@AllArgsConstructor
@EnableTransactionManagement
@EnableJpaRepositories(
basePackages = {
"com.xaaef.molly.system.repository",
},
entityManagerFactoryRef = "commonTenantEntityManagerFactory",
transactionManagerRef = "commonTenantTransactionManager")
public class JpaCommonTenantConfig {
private final JpaProperties jpaProperties;
private final HibernateProperties hibernateProperties;
private final List<HibernatePropertiesCustomizer> customizers;
private Map<String, Object> getVendorProperties() {
// 公共的库,是不需要做租户拦截的
customizers.removeIf(r -> r instanceof CurrentTenantIdentifierResolver);
customizers.removeIf(r -> r instanceof MultiTenantConnectionProvider);
var hibernateSettings = new HibernateSettings();
if (customizers.size() > 0) {
hibernateSettings.hibernatePropertiesCustomizers(this.customizers);
}
log.info("JpaCommonTenantConfig............");
return new LinkedHashMap<>(
this.hibernateProperties
.determineHibernateProperties(
jpaProperties.getProperties(),
hibernateSettings
)
);
}
@Bean(name = "commonTenantEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean commonTenantEntityManagerFactory(
@Qualifier("commonTenantDataSource") DataSource dataSource, EntityManagerFactoryBuilder builder) {
return builder
// 设置数据源
.dataSource(dataSource)
// 设置jpa配置
.properties(getVendorProperties())
// 设置实体包名
.packages(
"com.xaaef.molly.system.entity"
)
// 设置持久化单元名,用于@PersistenceContext注解获取EntityManager时指定数据源
.persistenceUnit("commonTenantPersistenceUnit")
.build();
}
@Bean(name = "commonTenantEntityManager")
public EntityManager commonTenantEntityManager(
@Qualifier("commonTenantEntityManagerFactory") EntityManagerFactory factory) {
return factory.createEntityManager();
}
@Bean(name = "commonTenantTransactionManager")
public PlatformTransactionManager commonTenantTransactionManager(
@Qualifier("commonTenantEntityManagerFactory") EntityManagerFactory factory) {
return new JpaTransactionManager(factory);
}
}

View File

@@ -0,0 +1,111 @@
package com.xaaef.molly.core.tenant;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties;
import org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* <p>
* 多租户的 EntityManager
* 比如: 用户,角色,部门。等. 每个租户独有的数据
* </p>
*
* @author WangChenChen
* @version 1.1
* @date 2022/12/13 11:37
*/
@Slf4j
@Configuration
@AllArgsConstructor
@EnableTransactionManagement
@EnableJpaRepositories(
basePackages = {
"com.xaaef.molly.perms.repository",
},
entityManagerFactoryRef = "multiTenantEntityManagerFactory",
transactionManagerRef = "multiTenantTransactionManager")
public class JpaMultiTenantConfig {
private final JpaProperties jpaProperties;
private final HibernateProperties hibernateProperties;
private final List<HibernatePropertiesCustomizer> customizers;
private Map<String, Object> getVendorProperties() {
var hibernateSettings = new HibernateSettings();
if (customizers.size() > 0) {
hibernateSettings.hibernatePropertiesCustomizers(this.customizers);
}
log.info("JpaMultiTenantConfig............");
return new LinkedHashMap<>(
this.hibernateProperties
.determineHibernateProperties(
jpaProperties.getProperties(),
hibernateSettings
)
);
}
@Primary
@Bean(name = "multiTenantEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean multiTenantEntityManagerFactory(
@Qualifier("multiTenantDataSource") DataSource dataSource, EntityManagerFactoryBuilder builder) {
return builder
// 设置数据源
.dataSource(dataSource)
// 设置jpa配置
.properties(getVendorProperties())
// 设置实体包名
.packages(
"com.xaaef.molly.perms.entity"
)
// 设置持久化单元名,用于@PersistenceContext注解获取EntityManager时指定数据源
.persistenceUnit("multiTenantPersistenceUnit")
.build();
}
@Primary
@Bean(name = "multiTenantEntityManager")
public EntityManager multiTenantEntityManager(
@Qualifier("multiTenantEntityManagerFactory") EntityManagerFactory factory) {
return factory.createEntityManager();
}
@Primary
@Bean(name = "multiTenantTransactionManager")
public PlatformTransactionManager multiTenantTransactionManager(
@Qualifier("multiTenantEntityManagerFactory") EntityManagerFactory factory) {
return new JpaTransactionManager(factory);
}
}

View File

@@ -61,6 +61,7 @@ public class MultiTenantTenantIdInterceptor implements HandlerInterceptor {
return false;
}
TenantUtils.setTenantId(tenantId);
log.debug("1.MultiTenantTenantIdInterceptor.preHandle(): {} ", tenantId);
return HandlerInterceptor.super.preHandle(request, response, handler);
}

View File

@@ -4,6 +4,7 @@ import jakarta.persistence.Column;
import jakarta.persistence.MappedSuperclass;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
@@ -23,6 +24,7 @@ import java.time.LocalDateTime;
@Getter
@Setter
@Accessors(chain = true)
@MappedSuperclass
public class BaseEntity implements java.io.Serializable {

View File

@@ -36,7 +36,7 @@ public class BaseServiceImpl<R extends JpaRepository<T, ID>, T extends BaseEntit
/**
* 插入时 填写
*/
protected void saveFill(T entity) {
protected <F extends BaseEntity> void saveFill(F entity) {
var userId = JwtSecurityUtils.getLoginUser().getUserId();
if (null == entity.getCreateUser() && userId != null) {
entity.setCreateUser(userId);

View File

@@ -1,6 +1,6 @@
package com.xaaef.molly.core.tenant.database;
import com.xaaef.molly.core.tenant.DataSourceManager;
import com.xaaef.molly.core.tenant.DatabaseManager;
import com.xaaef.molly.core.tenant.props.MultiTenantProperties;
import jakarta.annotation.PreDestroy;
import liquibase.Liquibase;
@@ -15,7 +15,6 @@ import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.io.Closeable;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -35,7 +34,7 @@ import static org.springframework.util.ResourceUtils.CLASSPATH_URL_PREFIX;
@Slf4j
@Component
@ConditionalOnProperty(prefix = "multi.tenant", name = "db-style", havingValue = "DataBase")
public class DatabaseDataSourceManager implements DataSourceManager {
public class DatabaseDataSourceManager implements DatabaseManager {
private static final Map<String, DataSource> DATA_SOURCE_MAP = new ConcurrentHashMap<>();

View File

@@ -1,12 +1,11 @@
package com.xaaef.molly.core.tenant.database;
import com.xaaef.molly.core.tenant.DataSourceManager;
import com.xaaef.molly.core.tenant.DatabaseManager;
import jakarta.annotation.PostConstruct;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.engine.jdbc.connections.spi.AbstractDataSourceBasedMultiTenantConnectionProviderImpl;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer;
import org.springframework.stereotype.Component;
@@ -39,19 +38,19 @@ public class DatabaseTenantProvider extends AbstractDataSourceBasedMultiTenantCo
log.info("multi tenant use DataBase .....");
}
private final DataSourceManager dataSourceManager;
private final DatabaseManager databaseManager;
@Override
protected DataSource selectAnyDataSource() {
return dataSourceManager.getDefaultDataSource();
return databaseManager.getDefaultDataSource();
}
@Override
protected DataSource selectDataSource(String tenantId) {
if (StringUtils.isNotBlank(tenantId)) {
return dataSourceManager.getDataSource(tenantId);
return databaseManager.getDataSource(tenantId);
} else {
return this.selectAnyDataSource();
}

View File

@@ -1,25 +1,19 @@
package com.xaaef.molly.core.tenant.schema;
import com.xaaef.molly.core.tenant.DataSourceManager;
import com.xaaef.molly.core.tenant.DatabaseManager;
import com.xaaef.molly.core.tenant.props.MultiTenantProperties;
import jakarta.annotation.PostConstruct;
import liquibase.Liquibase;
import liquibase.database.jvm.JdbcConnection;
import liquibase.resource.ClassLoaderResourceAccessor;
import liquibase.resource.DirectoryResourceAccessor;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.io.Closeable;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import static org.springframework.util.ResourceUtils.CLASSPATH_URL_PREFIX;
@@ -38,7 +32,7 @@ import static org.springframework.util.ResourceUtils.CLASSPATH_URL_PREFIX;
@Component
@AllArgsConstructor
@ConditionalOnProperty(prefix = "multi.tenant", name = "db-style", havingValue = "Schema")
public class SchemaDataSourceManager implements DataSourceManager {
public class SchemaDataSourceManager implements DatabaseManager {
// 默认租户的数据源
private final DataSource dataSource;

Some files were not shown because too many files have changed in this diff Show More