diff --git a/yudao-admin-server/pom.xml b/yudao-admin-server/pom.xml
index 4314e0fed9..f3b91ac0f7 100644
--- a/yudao-admin-server/pom.xml
+++ b/yudao-admin-server/pom.xml
@@ -117,6 +117,11 @@
yudao-spring-boot-starter-excel
+
+ cn.iocoder.boot
+ yudao-spring-boot-starter-tenant
+
+
org.apache.velocity
velocity-engine-core
diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/auth/SysAuthController.http b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/auth/SysAuthController.http
index 125a368469..580b897f88 100644
--- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/auth/SysAuthController.http
+++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/auth/SysAuthController.http
@@ -1,11 +1,12 @@
### 请求 /login 接口 => 成功
POST {{baseUrl}}/login
Content-Type: application/json
+tenant-id: 0
{
"username": "admin",
"password": "admin123",
- "uuid": "9b2ffbc1-7425-4155-9894-9d5c08541d62",
+ "uuid": "3acd87a09a4f48fb9118333780e94883",
"code": "1024"
}
diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/framework/captcha/config/CaptchaProperties.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/framework/captcha/config/CaptchaProperties.java
index 6eadd4d121..73939df754 100644
--- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/framework/captcha/config/CaptchaProperties.java
+++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/framework/captcha/config/CaptchaProperties.java
@@ -12,6 +12,13 @@ import java.time.Duration;
@Data
public class CaptchaProperties {
+ private static final Boolean ENABLE_DEFAULT = true;
+
+ /**
+ * 是否开启
+ * 注意,这里仅仅是后端 Server 是否校验,暂时不控制前端的逻辑
+ */
+ private Boolean enable = ENABLE_DEFAULT;
/**
* 验证码的过期时间
*/
diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/impl/SysAuthServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/impl/SysAuthServiceImpl.java
index 762649d9d2..2804b28139 100644
--- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/impl/SysAuthServiceImpl.java
+++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/impl/SysAuthServiceImpl.java
@@ -133,9 +133,13 @@ public class SysAuthServiceImpl implements SysAuthService {
}
private void verifyCaptcha(String username, String captchaUUID, String captchaCode) {
+ // 如果验证码关闭,则不进行校验
+ if (!captchaService.isCaptchaEnable()) {
+ return;
+ }
+ // 验证码不存在
final SysLoginLogTypeEnum logTypeEnum = SysLoginLogTypeEnum.LOGIN_USERNAME;
String code = captchaService.getCaptchaCode(captchaUUID);
- // 验证码不存在
if (code == null) {
// 创建登录失败日志(验证码不存在)
this.createLoginLog(username, logTypeEnum, SysLoginResultEnum.CAPTCHA_NOT_FOUND);
diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/common/SysCaptchaService.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/common/SysCaptchaService.java
index 286a5ef1f8..32aff5b06a 100644
--- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/common/SysCaptchaService.java
+++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/common/SysCaptchaService.java
@@ -14,6 +14,13 @@ public interface SysCaptchaService {
*/
SysCaptchaImageRespVO getCaptchaImage();
+ /**
+ * 是否开启图片验证码
+ *
+ * @return 是否
+ */
+ Boolean isCaptchaEnable();
+
/**
* 获得 uuid 对应的验证码
*
diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/common/impl/SysCaptchaServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/common/impl/SysCaptchaServiceImpl.java
index 44d291ffd7..daefc007f4 100644
--- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/common/impl/SysCaptchaServiceImpl.java
+++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/common/impl/SysCaptchaServiceImpl.java
@@ -35,6 +35,11 @@ public class SysCaptchaServiceImpl implements SysCaptchaService {
return SysCaptchaConvert.INSTANCE.convert(uuid, captcha);
}
+ @Override
+ public Boolean isCaptchaEnable() {
+ return captchaProperties.getEnable();
+ }
+
@Override
public String getCaptchaCode(String uuid) {
return captchaRedisDAO.get(uuid);
diff --git a/yudao-admin-server/src/main/resources/application-local.yaml b/yudao-admin-server/src/main/resources/application-local.yaml
index d7880547fd..79fdb300c7 100644
--- a/yudao-admin-server/src/main/resources/application-local.yaml
+++ b/yudao-admin-server/src/main/resources/application-local.yaml
@@ -166,6 +166,8 @@ logging:
# 芋道配置项,设置当前项目所有自定义的配置
yudao:
+ captcha:
+ enable: false # 本地环境,暂时关闭图片验证码,方便登录等接口的测试
security:
token-header: Authorization
token-secret: abcdefghijklmnopqrstuvwxyz
diff --git a/yudao-admin-server/src/main/resources/application.yaml b/yudao-admin-server/src/main/resources/application.yaml
index 8674452cfa..f71a66fc67 100644
--- a/yudao-admin-server/src/main/resources/application.yaml
+++ b/yudao-admin-server/src/main/resources/application.yaml
@@ -73,5 +73,7 @@ yudao:
constants-class-list:
- cn.iocoder.yudao.adminserver.modules.infra.enums.InfErrorCodeConstants
- cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants
+ tenant:
+ tables: sys_user
debug: false
diff --git a/yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/SysAuthServiceImplTest.java b/yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/SysAuthServiceImplTest.java
index 59be978091..492128e6bc 100644
--- a/yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/SysAuthServiceImplTest.java
+++ b/yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/SysAuthServiceImplTest.java
@@ -17,6 +17,7 @@ import cn.iocoder.yudao.coreservice.modules.system.service.user.SysUserCoreServi
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.test.core.util.AssertUtils;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
@@ -71,6 +72,11 @@ public class SysAuthServiceImplTest extends BaseDbUnitTest {
@MockBean
private SysPostService postService;
+ @BeforeEach
+ public void setUp() {
+ when(captchaService.isCaptchaEnable()).thenReturn(true);
+ }
+
@Test
public void testLoadUserByUsername_success() {
// 准备参数
diff --git a/yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/system/service/user/SysUserServiceImplTest.java b/yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/system/service/user/SysUserServiceImplTest.java
index 70751eeacc..cd1faa5928 100644
--- a/yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/system/service/user/SysUserServiceImplTest.java
+++ b/yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/system/service/user/SysUserServiceImplTest.java
@@ -21,6 +21,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
+import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import org.junit.jupiter.api.Test;
import org.mockito.stubbing.Answer;
import org.springframework.boot.test.mock.mockito.MockBean;
diff --git a/yudao-admin-server/src/test/resources/sql/create_tables.sql b/yudao-admin-server/src/test/resources/sql/create_tables.sql
index db67cad23f..96157b3d98 100644
--- a/yudao-admin-server/src/test/resources/sql/create_tables.sql
+++ b/yudao-admin-server/src/test/resources/sql/create_tables.sql
@@ -287,6 +287,7 @@ CREATE TABLE IF NOT EXISTS "sys_user" (
"updater" varchar(64) default '',
"update_time" timestamp not null default current_timestamp,
"deleted" bit not null default false,
+ "tenant_id" bigint not null default '0',
primary key ("id")
) comment '用户信息表';
diff --git a/yudao-core-service/pom.xml b/yudao-core-service/pom.xml
index 4fd85c0aac..4be7e2e30c 100644
--- a/yudao-core-service/pom.xml
+++ b/yudao-core-service/pom.xml
@@ -91,6 +91,11 @@
+
+ cn.iocoder.boot
+ yudao-spring-boot-starter-tenant
+
+
com.google.guava
guava
diff --git a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/dal/dataobject/user/SysUserDO.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/dal/dataobject/user/SysUserDO.java
index ef33f8d2a5..bb5e6854ce 100644
--- a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/dal/dataobject/user/SysUserDO.java
+++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/dal/dataobject/user/SysUserDO.java
@@ -2,8 +2,8 @@ package cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user;
import cn.iocoder.yudao.coreservice.modules.system.enums.common.SysSexEnum;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
-import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler;
+import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
@@ -24,7 +24,7 @@ import java.util.Set;
@Builder
@NoArgsConstructor
@AllArgsConstructor
-public class SysUserDO extends BaseDO {
+public class SysUserDO extends TenantBaseDO {
/**
* 用户ID
diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml
index cd5efec940..8d94d04c89 100644
--- a/yudao-dependencies/pom.xml
+++ b/yudao-dependencies/pom.xml
@@ -48,6 +48,7 @@
2.2
1.0.5
30.1.1-jre
+ 2.12.2
4.5.25
2.1.0
@@ -350,6 +351,12 @@
${revision}
+
+ cn.iocoder.boot
+ yudao-spring-boot-starter-tenant
+ ${revision}
+
+
org.projectlombok
lombok
@@ -402,6 +409,12 @@
${guava.version}
+
+ com.alibaba
+ transmittable-thread-local
+ ${transmittable-thread-local.version}
+
+
diff --git a/yudao-framework/pom.xml b/yudao-framework/pom.xml
index 136ac30733..63fc2c33c3 100644
--- a/yudao-framework/pom.xml
+++ b/yudao-framework/pom.xml
@@ -32,6 +32,7 @@
yudao-spring-boot-starter-biz-pay
yudao-spring-boot-starter-biz-weixin
yudao-spring-boot-starter-extension
+ yudao-spring-boot-starter-tenant
yudao-framework
diff --git a/yudao-framework/yudao-common/pom.xml b/yudao-framework/yudao-common/pom.xml
index ad84d6a24e..2681c8914a 100644
--- a/yudao-framework/yudao-common/pom.xml
+++ b/yudao-framework/yudao-common/pom.xml
@@ -122,6 +122,17 @@
jakarta.validation-api
provided
+
+
+ cn.hutool
+ hutool-all
+
+
+
+ com.alibaba
+ transmittable-thread-local
+
+
diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/WebFilterOrderEnum.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/WebFilterOrderEnum.java
index 6ad94a3698..1d8cc4034a 100644
--- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/WebFilterOrderEnum.java
+++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/WebFilterOrderEnum.java
@@ -17,9 +17,11 @@ public interface WebFilterOrderEnum {
// OrderedRequestContextFilter 默认为 -105,用于国际化上下文等等
- int API_ACCESS_LOG_FILTER = -104; // 需要保证在 RequestBodyCacheFilter 后面
+ int TENANT_FILTER = - 100; // 需要保证在 ApiAccessLogFilter 前面
- int XSS_FILTER = -103; // 需要保证在 RequestBodyCacheFilter 后面
+ int API_ACCESS_LOG_FILTER = -90; // 需要保证在 RequestBodyCacheFilter 后面
+
+ int XSS_FILTER = -80; // 需要保证在 RequestBodyCacheFilter 后面
// Spring Security Filter 默认为 -100,可见 SecurityProperties 配置属性类
diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/dataobject/BaseDO.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/dataobject/BaseDO.java
index 15d99a3d83..f63f054de6 100644
--- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/dataobject/BaseDO.java
+++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/dataobject/BaseDO.java
@@ -10,9 +10,11 @@ import java.util.Date;
/**
* 基础实体对象
+ *
+ * @author 芋道源码
*/
@Data
-public class BaseDO implements Serializable {
+public abstract class BaseDO implements Serializable {
/**
* 创建时间
diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java
index 3c455e8935..8789ea5742 100644
--- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java
+++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java
@@ -4,9 +4,13 @@ import cn.hutool.core.collection.CollectionUtil;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.SortingField;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
+import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.List;
import java.util.stream.Collectors;
/**
@@ -30,4 +34,17 @@ public class MyBatisUtils {
return page;
}
+ /**
+ * 将拦截器添加到链中
+ * 由于 MybatisPlusInterceptor 不支持添加拦截器,所以只能全量设置
+ *
+ * @param interceptor 链
+ * @param inner 拦截器
+ */
+ public static void addInterceptor(MybatisPlusInterceptor interceptor, InnerInterceptor inner) {
+ List inners = new ArrayList<>(interceptor.getInterceptors());
+ inners.add(0, inner);
+ interceptor.setInterceptors(inners);
+ }
+
}
diff --git a/yudao-framework/yudao-spring-boot-starter-tenant/pom.xml b/yudao-framework/yudao-spring-boot-starter-tenant/pom.xml
new file mode 100644
index 0000000000..854db0bbf0
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-tenant/pom.xml
@@ -0,0 +1,37 @@
+
+
+
+ yudao-framework
+ cn.iocoder.boot
+ ${revision}
+
+ 4.0.0
+ yudao-spring-boot-starter-tenant
+ jar
+
+ ${artifactId}
+ 多租户
+ https://github.com/YunaiV/ruoyi-vue-pro
+
+
+
+ cn.iocoder.boot
+ yudao-common
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+
+ cn.iocoder.boot
+ yudao-spring-boot-starter-mybatis
+
+
+
+
diff --git a/yudao-framework/yudao-spring-boot-starter-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/TenantProperties.java b/yudao-framework/yudao-spring-boot-starter-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/TenantProperties.java
new file mode 100644
index 0000000000..5b97b22f66
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/TenantProperties.java
@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.framework.tenant.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import java.util.Set;
+
+/**
+ * 多租户配置
+ *
+ * @author 芋道源码
+ */
+@ConfigurationProperties(prefix = "yudao.tenant")
+@Data
+public class TenantProperties {
+
+ /**
+ * 需要多租户的表
+ *
+ * 由于多租户并不作为 yudao 项目的重点功能,更多是扩展性的功能,所以采用正向配置需要多租户的表。
+ * 如果需要,你可以改成 ignoreTables 来取消部分不需要的表
+ */
+ private Set tables;
+
+}
diff --git a/yudao-framework/yudao-spring-boot-starter-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantDatabaseAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantDatabaseAutoConfiguration.java
new file mode 100644
index 0000000000..7149e39a28
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantDatabaseAutoConfiguration.java
@@ -0,0 +1,43 @@
+package cn.iocoder.yudao.framework.tenant.config;
+
+import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
+import cn.iocoder.yudao.framework.tenant.core.db.TenantDatabaseInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+
+/**
+ * 多租户针对 DB 的自动配置
+ *
+ * @author 芋道源码
+ */
+@EnableConfigurationProperties(TenantProperties.class)
+public class YudaoTenantDatabaseAutoConfiguration {
+
+ @Bean
+ public TenantLineInnerInterceptor tenantLineInnerInterceptor(TenantProperties properties) {
+ return new TenantLineInnerInterceptor(new TenantDatabaseInterceptor(properties));
+ }
+
+ @Bean
+ public BeanPostProcessor mybatisPlusInterceptorBeanPostProcessor(TenantLineInnerInterceptor tenantLineInnerInterceptor) {
+ return new BeanPostProcessor() {
+
+ @Override
+ public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
+ if (!(bean instanceof MybatisPlusInterceptor)) {
+ return bean;
+ }
+ // 将 TenantDatabaseInterceptor 添加到最前面
+ MybatisPlusInterceptor interceptor = (MybatisPlusInterceptor) bean;
+ MyBatisUtils.addInterceptor(interceptor, tenantLineInnerInterceptor);
+ return bean;
+ }
+
+ };
+ }
+
+}
diff --git a/yudao-framework/yudao-spring-boot-starter-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantWebAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantWebAutoConfiguration.java
new file mode 100644
index 0000000000..7b2e1aaf5f
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantWebAutoConfiguration.java
@@ -0,0 +1,23 @@
+package cn.iocoder.yudao.framework.tenant.config;
+
+import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum;
+import cn.iocoder.yudao.framework.tenant.core.web.TenantWebFilter;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+
+/**
+ * 多租户针对 Web 的自动配置
+ *
+ * @author 芋道源码
+ */
+public class YudaoTenantWebAutoConfiguration {
+
+ @Bean
+ public FilterRegistrationBean tenantWebFilter() {
+ FilterRegistrationBean registrationBean = new FilterRegistrationBean<>();
+ registrationBean.setFilter(new TenantWebFilter());
+ registrationBean.setOrder(WebFilterOrderEnum.TENANT_FILTER);
+ return registrationBean;
+ }
+
+}
diff --git a/yudao-framework/yudao-spring-boot-starter-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/context/TenantContextHolder.java b/yudao-framework/yudao-spring-boot-starter-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/context/TenantContextHolder.java
new file mode 100644
index 0000000000..92dbff0027
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/context/TenantContextHolder.java
@@ -0,0 +1,26 @@
+package cn.iocoder.yudao.framework.tenant.core.context;
+
+import com.alibaba.ttl.TransmittableThreadLocal;
+
+/**
+ * 多租户上下文 Holder
+ *
+ * @author 芋道源码
+ */
+public class TenantContextHolder {
+
+ private static final ThreadLocal TENANT_ID = new TransmittableThreadLocal<>();
+
+ public static Long getTenantId() {
+ return TENANT_ID.get();
+ }
+
+ public static void setTenantId(Long tenantId) {
+ TENANT_ID.set(tenantId);
+ }
+
+ public static void clear() {
+ TENANT_ID.remove();
+ }
+
+}
diff --git a/yudao-framework/yudao-spring-boot-starter-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantBaseDO.java b/yudao-framework/yudao-spring-boot-starter-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantBaseDO.java
new file mode 100644
index 0000000000..f4f0ea50ac
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantBaseDO.java
@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.framework.tenant.core.db;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 拓展多租户的 BaseDO 基类
+ *
+ * @author 芋道源码
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public abstract class TenantBaseDO extends BaseDO {
+
+ /**
+ * 多租户编号
+ */
+ private Long tenantId;
+
+}
diff --git a/yudao-framework/yudao-spring-boot-starter-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java b/yudao-framework/yudao-spring-boot-starter-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java
new file mode 100644
index 0000000000..dfcd8a4a4e
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java
@@ -0,0 +1,33 @@
+package cn.iocoder.yudao.framework.tenant.core.db;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.tenant.config.TenantProperties;
+import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
+import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
+import lombok.AllArgsConstructor;
+import net.sf.jsqlparser.expression.Expression;
+import net.sf.jsqlparser.expression.StringValue;
+
+/**
+ * 基于 MyBatis Plus 多租户的功能,实现 DB 层面的多租户的功能
+ *
+ * @author 芋道源码
+ */
+@AllArgsConstructor
+public class TenantDatabaseInterceptor implements TenantLineHandler {
+
+ private final TenantProperties properties;
+
+ @Override
+ public Expression getTenantId() {
+ // TODO 芋艿:暂时不考虑获取不到的情况。此时,会存在 NPE 的报错
+ return new StringValue(TenantContextHolder.getTenantId().toString());
+ }
+
+ @Override
+ public boolean ignoreTable(String tableName) {
+ // 不包含,说明要过滤
+ return !CollUtil.contains(properties.getTables(), tableName);
+ }
+
+}
diff --git a/yudao-framework/yudao-spring-boot-starter-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/web/TenantWebFilter.java b/yudao-framework/yudao-spring-boot-starter-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/web/TenantWebFilter.java
new file mode 100644
index 0000000000..0276564769
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/web/TenantWebFilter.java
@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.framework.tenant.core.web;
+
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * 多租户 Web 过滤器
+ * 将请求 Header 中的 tenant-id 解析出来,添加到 {@link TenantContextHolder} 中,这样后续的 DB 等操作,可以获得到租户编号
+ *
+ * @author 芋道源码
+ */
+public class TenantWebFilter extends OncePerRequestFilter {
+
+ private static final String HEADER_TENANT_ID = "tenant-id";
+
+ @Override
+ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
+ throws ServletException, IOException {
+ // 设置
+ String tenantId = request.getHeader(HEADER_TENANT_ID);
+ if (StrUtil.isNotEmpty(tenantId)) {
+ TenantContextHolder.setTenantId(Long.valueOf(tenantId));
+ }
+ try {
+ chain.doFilter(request, response);
+ } finally {
+ // 清理
+ TenantContextHolder.clear();
+ }
+ }
+
+}
diff --git a/yudao-framework/yudao-spring-boot-starter-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/package-info.java b/yudao-framework/yudao-spring-boot-starter-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/package-info.java
new file mode 100644
index 0000000000..1f39db41fc
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/package-info.java
@@ -0,0 +1,8 @@
+/**
+ * 多租户,支持如下层面:
+ * 1. DB:基于 MyBatis Plus 多租户的功能实现
+ * 2. Job:TODO
+ * 3. MQ:TODO
+ * 4. Web:TODO
+ */
+package cn.iocoder.yudao.framework.tenant;
diff --git a/yudao-framework/yudao-spring-boot-starter-tenant/src/main/resources/META-INF/spring.factories b/yudao-framework/yudao-spring-boot-starter-tenant/src/main/resources/META-INF/spring.factories
new file mode 100644
index 0000000000..6f0a6f12b6
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-tenant/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,3 @@
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+ cn.iocoder.yudao.framework.tenant.config.YudaoTenantDatabaseAutoConfiguration,\
+ cn.iocoder.yudao.framework.tenant.config.YudaoTenantWebAutoConfiguration
diff --git a/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/controller/user/SysUserProfileController.java b/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/controller/user/SysUserProfileController.java
index 93149e7934..c0778184af 100644
--- a/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/controller/user/SysUserProfileController.java
+++ b/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/controller/user/SysUserProfileController.java
@@ -41,8 +41,8 @@ public class SysUserProfileController {
@PutMapping("/update-nickname")
@ApiOperation("修改用户昵称")
@PreAuthenticated
- public CommonResult updateNickname(@RequestParam("nickName") String nickName) {
- userService.updateNickname(getLoginUserId(), nickName);
+ public CommonResult updateNickname(@RequestParam("nickname") String nickname) {
+ userService.updateNickname(getLoginUserId(), nickname);
return success(true);
}
diff --git a/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/service/user/MbrUserService.java b/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/service/user/MbrUserService.java
index fc5a8564da..e33978bfe2 100644
--- a/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/service/user/MbrUserService.java
+++ b/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/service/user/MbrUserService.java
@@ -51,9 +51,9 @@ public interface MbrUserService {
/**
* 修改用户昵称
* @param userId 用户id
- * @param nickName 用户新昵称
+ * @param nickname 用户新昵称
*/
- void updateNickname(Long userId, String nickName);
+ void updateNickname(Long userId, String nickname);
/**
* 修改用户头像
diff --git a/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/service/user/impl/MbrUserServiceImpl.java b/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/service/user/impl/MbrUserServiceImpl.java
index 40b7b862b8..442da41470 100644
--- a/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/service/user/impl/MbrUserServiceImpl.java
+++ b/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/service/user/impl/MbrUserServiceImpl.java
@@ -86,15 +86,15 @@ public class MbrUserServiceImpl implements MbrUserService {
}
@Override
- public void updateNickname(Long userId, String nickName) {
+ public void updateNickname(Long userId, String nickname) {
MbrUserDO user = this.checkUserExists(userId);
// 仅当新昵称不等于旧昵称时进行修改
- if (nickName.equals(user.getNickname())){
+ if (nickname.equals(user.getNickname())){
return;
}
MbrUserDO userDO = new MbrUserDO();
userDO.setId(user.getId());
- userDO.setNickname(nickName);
+ userDO.setNickname(nickname);
userMapper.updateById(userDO);
}
diff --git a/yudao-vue-ui/api/member/userProfile.js b/yudao-vue-ui/api/member/userProfile.js
index 3c3d52e713..2effa1eb72 100644
--- a/yudao-vue-ui/api/member/userProfile.js
+++ b/yudao-vue-ui/api/member/userProfile.js
@@ -6,4 +6,18 @@ export function getUserInfo() {
url: 'member/user/profile/get',
method: 'get'
})
+}
+
+// 修改
+export function updateNickname(nickname) {
+ return request({
+ url: 'member/user/profile/update-nickname',
+ method: 'post',
+ header: {
+ "Content-Type": "application/x-www-form-urlencoded"
+ },
+ data: {
+ nickname
+ }
+ })
}
\ No newline at end of file
diff --git a/yudao-vue-ui/common/js/request.js b/yudao-vue-ui/common/js/request.js
index 7f3d04baec..d78866e4e9 100644
--- a/yudao-vue-ui/common/js/request.js
+++ b/yudao-vue-ui/common/js/request.js
@@ -12,6 +12,7 @@ export const request = (options) => {
method: options.method || 'GET',
data: options.data || {},
header: {
+ ...options.header,
'Authorization': authToken ? `Bearer ${authToken}` : ''
}
}).then(res => {
diff --git a/yudao-vue-ui/pages/set/userInfo.vue b/yudao-vue-ui/pages/set/userInfo.vue
index 07eae7e2fe..4d46ed8a8c 100644
--- a/yudao-vue-ui/pages/set/userInfo.vue
+++ b/yudao-vue-ui/pages/set/userInfo.vue
@@ -20,8 +20,20 @@
昵称
+
+
+
+
+
+
+
+
+
+
+
+
+
-
@@ -32,6 +44,16 @@
uploadProgress: 100, //头像上传进度
tempAvatar: '',
userInfo: {},
+ nicknameOpen: false,
+ nicknameForm: {
+ nickname: ''
+ },
+ nicknameRules: {
+ nickname: [{
+ required: true,
+ message: '请输入昵称'
+ }]
+ }
}
},
computed: {
@@ -50,6 +72,30 @@
this.userInfo = {avatar, nickname, gender};
},
methods: {
+ nicknameClick() {
+ this.nicknameOpen = true;
+ this.nicknameForm.nickname = this.userInfo.nickname;
+ },
+ nicknameCancel() {
+ this.nicknameOpen = false;
+ },
+ nicknameSubmit() {
+ this.$refs.nicknameForm.validate().then(() => {
+ this.loading = true;
+ // 执行登陆
+ const { mobile, code, password} = this.form;
+ const loginPromise = this.loginType == 'password' ? login(mobile, password) :
+ smsLogin(mobile, code);
+ loginPromise.then(data => {
+ // 登陆成功
+ this.loginSuccessCallBack(data);
+ }).catch(errors => {
+ }).finally(() => {
+ this.loading = false;
+ })
+ }).catch(errors => {
+ });
+ },
// 提交修改
async confirm() {
// 校验信息是否变化