Просмотр исходного кода

Merge remote-tracking branch 'origin/master'

xgb 3 недель назад
Родитель
Сommit
d8aa9e6b20

+ 97 - 0
fs-admin/src/main/java/com/fs/tenant/TenantInfoController.java

@@ -0,0 +1,97 @@
+package com.fs.tenant;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.tenant.domain.TenantInfo;
+import com.fs.tenant.service.TenantInfoService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 租户基础信息Controller
+ * 
+ * @author fs
+ * @date 2026-01-23
+ */
+@RestController
+@RequestMapping("/tenant/tenant")
+public class TenantInfoController extends BaseController
+{
+    @Autowired
+    private TenantInfoService tenantInfoService;
+
+    /**
+     * 查询租户基础信息列表
+     */
+    @PreAuthorize("@ss.hasPermi('tenant:tenant:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(TenantInfo tenantInfo)
+    {
+        startPage();
+        List<TenantInfo> list = tenantInfoService.selectTenantInfoList(tenantInfo);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出租户基础信息列表
+     */
+    @PreAuthorize("@ss.hasPermi('tenant:tenant:export')")
+    @Log(title = "租户基础信息", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(TenantInfo tenantInfo)
+    {
+        List<TenantInfo> list = tenantInfoService.selectTenantInfoList(tenantInfo);
+        ExcelUtil<TenantInfo> util = new ExcelUtil<TenantInfo>(TenantInfo.class);
+        return util.exportExcel(list, "租户基础信息数据");
+    }
+
+    /**
+     * 获取租户基础信息详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('tenant:tenant:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") String id)
+    {
+        return AjaxResult.success(tenantInfoService.selectTenantInfoById(id));
+    }
+
+    /**
+     * 新增租户基础信息
+     */
+    @PreAuthorize("@ss.hasPermi('tenant:tenant:add')")
+    @Log(title = "租户基础信息", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody TenantInfo tenantInfo)
+    {
+        return toAjax(tenantInfoService.insertTenantInfo(tenantInfo));
+    }
+
+    /**
+     * 修改租户基础信息
+     */
+    @PreAuthorize("@ss.hasPermi('tenant:tenant:edit')")
+    @Log(title = "租户基础信息", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody TenantInfo tenantInfo)
+    {
+        return toAjax(tenantInfoService.updateTenantInfo(tenantInfo));
+    }
+
+    /**
+     * 删除租户基础信息
+     */
+    @PreAuthorize("@ss.hasPermi('tenant:tenant:remove')")
+    @Log(title = "租户基础信息", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable String[] ids)
+    {
+        return toAjax(tenantInfoService.deleteTenantInfoByIds(ids));
+    }
+}

+ 2 - 2
fs-admin/src/main/java/com/fs/web/controller/system/SysLoginController.java

@@ -87,7 +87,7 @@ public class SysLoginController
         AjaxResult ajax = AjaxResult.success();
         // 生成令牌
         String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
-                loginBody.getUuid());
+                loginBody.getUuid(),loginBody.getTenantCode());
         ajax.put(Constants.TOKEN, token);
         return ajax;
     }
@@ -164,7 +164,7 @@ public class SysLoginController
     public boolean checkIsNeedCheck(@RequestBody LoginBody loginBody)
     {
 //        return  false;
-        return loginService.checkIsNeedCheck(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(), loginBody.getUuid());
+        return loginService.checkIsNeedCheck(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(), loginBody.getUuid(), loginBody.getTenantCode());
     }
 
     @PostMapping("/checkCode")

+ 10 - 0
fs-common/src/main/java/com/fs/common/core/domain/model/LoginBody.java

@@ -27,6 +27,16 @@ public class LoginBody
      */
     private String uuid = "";
 
+    public String getTenantCode() {
+        return tenantCode;
+    }
+
+    public void setTenantCode(String tenantCode) {
+        this.tenantCode = tenantCode;
+    }
+
+    private String tenantCode;
+
     public String getUsername()
     {
         return username;

+ 18 - 0
fs-common/src/main/java/com/fs/common/core/domain/model/LoginUser.java

@@ -67,12 +67,30 @@ public class LoginUser implements UserDetails
      */
     private Set<String> permissions;
 
+    public Long getTenantId() {
+        return tenantId;
+    }
+
+    public void setTenantId(Long tenanntId) {
+        this.tenantId = tenanntId;
+    }
+
     /**
      * 用户信息
      */
     private SysUser user;
 
+    private String tenantCode;
 
+    private Long tenantId;
+
+    public String getTenantCode() {
+        return tenantCode;
+    }
+
+    public void setTenantCode(String tenantCode) {
+        this.tenantCode = tenantCode;
+    }
 
     public Long getUserId()
     {

+ 98 - 0
fs-framework/src/main/java/com/fs/framework/datasource/TenantDataSourceManager.java

@@ -0,0 +1,98 @@
+package com.fs.framework.datasource;
+
+import com.alibaba.druid.pool.DruidDataSource;
+import com.fs.tenant.domain.TenantInfo;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import javax.sql.DataSource;
+import java.lang.reflect.Field;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Component
+public class TenantDataSourceManager {
+
+    @Resource
+    private DynamicDataSource dynamicDataSource;
+
+    /**
+     * 租户数据源缓存
+     */
+    private static final Map<String, DataSource> TENANT_DS_CACHE = new ConcurrentHashMap<>();
+
+    /**
+     * 切换到租户数据源(不存在则创建)
+     */
+    public void switchTenant(TenantInfo tenantInfo) {
+
+        // 用租户主键作为唯一标识
+        String tenantKey = buildTenantKey(tenantInfo.getId());
+
+        if (!TENANT_DS_CACHE.containsKey(tenantKey)) {
+            synchronized (this) {
+                if (!TENANT_DS_CACHE.containsKey(tenantKey)) {
+
+                    DataSource tenantDs = createTenantDataSource(tenantInfo);
+                    TENANT_DS_CACHE.put(tenantKey, tenantDs);
+
+                    // 动态追加到已解析的数据源
+                    Map<Object, DataSource> resolvedMap = getResolvedDataSources();
+                    resolvedMap.put(tenantKey, tenantDs);
+                }
+            }
+        }
+
+        // ThreadLocal 切库
+        DynamicDataSourceContextHolder.setDataSourceType(tenantKey);
+    }
+
+    private String buildTenantKey(Long tenantId) {
+        return "tenant:" + tenantId;
+    }
+
+
+
+    /**
+     * 清理 ThreadLocal
+     */
+    public void clear() {
+        DynamicDataSourceContextHolder.clearDataSourceType();
+    }
+
+    /**
+     * 创建租户数据源(MySQL + Druid)
+     */
+    private DataSource createTenantDataSource(TenantInfo tenant) {
+
+        DruidDataSource ds = new DruidDataSource();
+        ds.setUrl(tenant.getDbUrl());
+        ds.setUsername(tenant.getDbAccount());
+        ds.setPassword(tenant.getDbPwd());
+
+        // 统一 MySQL
+        ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
+
+        ds.setInitialSize(5);
+        ds.setMinIdle(10);
+        ds.setMaxActive(20);
+        ds.setMaxWait(60000);
+
+        return ds;
+    }
+
+    /**
+     * 反射获取 AbstractRoutingDataSource.resolvedDataSources
+     */
+    @SuppressWarnings("unchecked")
+    private Map<Object, DataSource> getResolvedDataSources() {
+        try {
+            Field field = org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource
+                    .class.getDeclaredField("resolvedDataSources");
+            field.setAccessible(true);
+            return (Map<Object, DataSource>) field.get(dynamicDataSource);
+        } catch (Exception e) {
+            throw new IllegalStateException("获取 resolvedDataSources 失败", e);
+        }
+    }
+}

+ 35 - 10
fs-framework/src/main/java/com/fs/framework/security/filter/JwtAuthenticationTokenFilter.java

@@ -5,6 +5,12 @@ import javax.servlet.FilterChain;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import javax.sql.DataSource;
+
+import com.alibaba.druid.pool.DruidDataSource;
+import com.fs.common.enums.DataSourceType;
+import com.fs.framework.datasource.DynamicDataSource;
+import com.fs.framework.datasource.DynamicDataSourceContextHolder;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.context.SecurityContextHolder;
@@ -27,18 +33,37 @@ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter
     @Autowired
     private TokenService tokenService;
 
+
     @Override
-    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
-            throws ServletException, IOException
+    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException
     {
-        LoginUser loginUser = tokenService.getLoginUser(request);
-        if (StringUtils.isNotNull(loginUser) && StringUtils.isNull(SecurityUtils.getAuthentication()))
-        {
-            tokenService.verifyToken(loginUser);
-            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
-            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
-            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
+        try {
+            LoginUser loginUser = tokenService.getLoginUser(request);
+
+            if (StringUtils.isNotNull(loginUser)
+                    && StringUtils.isNull(SecurityUtils.getAuthentication()))
+            {
+                // 根据 tenantId 切换数据源
+                Long tenantId = loginUser.getTenantId();
+                if (tenantId != null) {
+                    String tenantKey = "tenant:" + tenantId;
+                    DynamicDataSourceContextHolder.setDataSourceType(tenantKey);
+                } else {
+                    // 没有租户,回主库
+                    DynamicDataSourceContextHolder.setDataSourceType(DataSourceType.MASTER.name());
+                }
+
+                tokenService.verifyToken(loginUser);
+
+                UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
+                authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
+                SecurityContextHolder.getContext().setAuthentication(authenticationToken);
+            }
+            chain.doFilter(request, response);
+        }
+        finally {
+            DynamicDataSourceContextHolder.clearDataSourceType();
         }
-        chain.doFilter(request, response);
     }
+
 }

+ 139 - 63
fs-framework/src/main/java/com/fs/framework/web/service/SysLoginService.java

@@ -2,11 +2,18 @@ package com.fs.framework.web.service;
 
 import javax.annotation.Resource;
 
+import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.util.ObjectUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
+import com.fs.common.enums.DataSourceType;
 import com.fs.common.service.WechatLoginService;
 import com.fs.common.utils.StringUtils;
+import com.fs.framework.datasource.DynamicDataSource;
+import com.fs.framework.datasource.DynamicDataSourceContextHolder;
+import com.fs.framework.datasource.TenantDataSourceManager;
+import com.fs.tenant.domain.TenantInfo;
+import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.security.authentication.AuthenticationManager;
@@ -77,7 +84,7 @@ public class SysLoginService
      * @param uuid 唯一标识
      * @return 结果
      */
-    public String login(String username, String password, String code, String uuid)
+    public String login(String username, String password, String code, String uuid, String tenantCode)
     {
         boolean captchaOnOff = configService.selectCaptchaOnOff();
         // 验证码开关
@@ -85,34 +92,66 @@ public class SysLoginService
         {
             validateCaptcha(username, code, uuid);
         }
-        // 用户验证
-        Authentication authentication = null;
-        try
+
+        TenantInfo tenantInfo = null;
+
+        // 默认使用主库
+        DynamicDataSourceContextHolder.setDataSourceType(DataSourceType.MASTER.name());
+
+        // ===== 只有传了 tenantCode 才查询租户并切库 =====
+        if (StringUtils.isNotBlank(tenantCode))
         {
-            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
-            authentication = authenticationManager
-                    .authenticate(new UsernamePasswordAuthenticationToken(username, password));
+            // 查询租户(主库)
+            tenantInfo = userService.getTenantInfo(tenantCode);
+            if (BeanUtil.isEmpty(tenantInfo)) {
+                throw new ServiceException("企业不存在");
+            }
+
+            if (!tenantInfo.getStatus().equals(1)) {
+                throw new ServiceException("企业已禁用");
+            }
+
+            // 切租户库
+            tenantDataSourceManager.switchTenant(tenantInfo);
         }
-        catch (Exception e)
-        {
-            if (e instanceof BadCredentialsException)
-            {
-                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
-                throw new UserPasswordNotMatchException();
+
+        try {
+            // 用户验证
+            Authentication authentication = null;
+            try {
+                // 该方法会去调用 UserDetailsServiceImpl.loadUserByUsername
+                authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
+            } catch (Exception e) {
+                if (e instanceof BadCredentialsException) {
+                    AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
+                    throw new UserPasswordNotMatchException();
+                } else {
+                    AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
+                    throw new ServiceException(e.getMessage());
+                }
             }
-            else
-            {
-                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
-                throw new ServiceException(e.getMessage());
+
+            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
+
+            LoginUser loginUser = (LoginUser) authentication.getPrincipal();
+
+            // 只有多租户登录才设置 tenantId
+            if (tenantInfo != null) {
+                loginUser.setTenantId(tenantInfo.getId());
             }
+
+            recordLoginInfo(loginUser.getUser());
+
+            // 生成 token
+            return tokenService.createToken(loginUser);
+        } finally {
+            // 防止线程串库(必须)
+            tenantDataSourceManager.clear();
+            DynamicDataSourceContextHolder.setDataSourceType(DataSourceType.MASTER.name());
         }
-        AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
-        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
-        recordLoginInfo(loginUser.getUser());
-        // 生成token
-        return tokenService.createToken(loginUser);
     }
 
+
     /**
      * 校验验证码
      * 
@@ -159,62 +198,99 @@ public class SysLoginService
         userService.updateUserProfile(user);
     }
 
+    @Resource
+    private TenantDataSourceManager tenantDataSourceManager;
 
-    public boolean checkIsNeedCheck(String username, String password, String code, String uuid)
+    public boolean checkIsNeedCheck(String username, String password, String code, String uuid, String tenantCode)
     {
-        String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
-        String captcha = redisCache.getCacheObject(verifyKey);
-        //redisCache.deleteObject(verifyKey);
-        if (captcha == null)
-        {
-            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
-            throw new CaptchaExpireException();
-        }
-        if (!code.equalsIgnoreCase(captcha))
+        TenantInfo tenantInfo = null;
+
+        // 默认使用主库
+        DynamicDataSourceContextHolder.setDataSourceType(DataSourceType.MASTER.name());
+
+        // ===== 只有传了 tenantCode 才走租户逻辑 =====
+        if (StringUtils.isNotBlank(tenantCode))
         {
-            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
-            throw new CaptchaException();
+            // 查询租户(主库)
+            tenantInfo = userService.getTenantInfo(tenantCode);
+            if (BeanUtil.isEmpty(tenantInfo))
+            {
+                throw new ServiceException("企业不存在");
+            }
+            if (!tenantInfo.getStatus().equals(1))
+            {
+                throw new ServiceException("企业已禁用");
+            }
+
+            // 切到租户库
+            tenantDataSourceManager.switchTenant(tenantInfo);
         }
-        // 用户验证
-        Authentication authentication = null;
+
         try
         {
-            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
-            authentication = authenticationManager
-                    .authenticate(new UsernamePasswordAuthenticationToken(username, password));
-        }
-        catch (Exception e)
-        {
-            if (e instanceof BadCredentialsException)
+            String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
+            String captcha = redisCache.getCacheObject(verifyKey);
+            // redisCache.deleteObject(verifyKey);
+
+            if (captcha == null)
             {
-                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
-                throw new UserPasswordNotMatchException();
+                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
+                throw new CaptchaExpireException();
             }
-            else
+
+            if (!code.equalsIgnoreCase(captcha))
             {
-                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
-                throw new ServiceException(e.getMessage());
+                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
+                throw new CaptchaException();
             }
-        }
-        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
-        //查询当前登录用户信息
-        SysUser sysUser = userService.selectUserById(loginUser.getUserId());
-        Long[] userIds = new Long[]{236L, 246L, 247L, 253L,119L};
-        for (Long userId : userIds) {
-            if (userId.equals(sysUser.getUserId())){
+
+            // 用户验证
+            Authentication authentication = null;
+            try {
+                authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
+            } catch (Exception e)
+            {
+                if (e instanceof BadCredentialsException) {
+                    AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
+                    throw new UserPasswordNotMatchException();
+                } else {
+                    AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
+                    throw new ServiceException(e.getMessage());
+                }
+            }
+
+            LoginUser loginUser = (LoginUser) authentication.getPrincipal();
+
+            // 查询当前登录用户信息(在当前数据源下)
+            SysUser sysUser = userService.selectUserById(loginUser.getUserId());
+
+            Long[] userIds = new Long[]{236L, 246L, 247L, 253L, 119L};
+            for (Long userId : userIds)
+            {
+                if (userId.equals(sysUser.getUserId()))
+                {
+                    return false;
+                }
+            }
+
+            // 判断是否开启了扫码配置
+            if (ObjectUtil.isEmpty(isNeedScan) || !isNeedScan)
+            {
                 return false;
             }
-        }
 
-        // 判断是否开启了扫码配置
-        if (ObjectUtil.isEmpty(isNeedScan) || !isNeedScan){
-            return false;
+            // true → 需要短信验证码
+            // false → 直接登录
+            return needCheck(sysUser);
+        }
+        finally
+        {
+            // 防止线程串库
+            tenantDataSourceManager.clear();
+            DynamicDataSourceContextHolder.setDataSourceType(DataSourceType.MASTER.name());
         }
-
-        //true → 要发短信验证码再登录
-        //false → 直接登录
-        return needCheck(sysUser);
     }
+
     public boolean needCheck(SysUser sysUser) {
 
 

+ 3 - 0
fs-service/src/main/java/com/fs/system/mapper/SysUserMapper.java

@@ -3,6 +3,7 @@ package com.fs.system.mapper;
 import java.util.List;
 import java.util.Map;
 
+import com.fs.tenant.domain.TenantInfo;
 import org.apache.ibatis.annotations.Param;
 import com.fs.common.core.domain.entity.SysUser;
 
@@ -132,4 +133,6 @@ public interface SysUserMapper
     public SysUser checkEmailUnique(String email);
 
     List<SysUser> selectUserByPhone(String phone);
+
+    TenantInfo getTenantInfo(String tenantCode);
 }

+ 3 - 0
fs-service/src/main/java/com/fs/system/service/ISysUserService.java

@@ -2,6 +2,7 @@ package com.fs.system.service;
 
 import java.util.List;
 import com.fs.common.core.domain.entity.SysUser;
+import com.fs.tenant.domain.TenantInfo;
 
 /**
  * 用户 业务层
@@ -216,4 +217,6 @@ public interface ISysUserService
     int updateUserInfo(SysUser sysuser);
 
     List<SysUser> selectUserByPhone(String phone);
+
+    TenantInfo getTenantInfo(String tenantCode);
 }

+ 6 - 0
fs-service/src/main/java/com/fs/system/service/impl/SysUserServiceImpl.java

@@ -5,6 +5,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import com.fs.tenant.domain.TenantInfo;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -590,4 +591,9 @@ public class SysUserServiceImpl implements ISysUserService
     public List<SysUser> selectUserByPhone(String phone) {
         return userMapper.selectUserByPhone(phone);
     }
+
+    @Override
+    public TenantInfo getTenantInfo(String tenantCode) {
+        return userMapper.getTenantInfo(tenantCode);
+    }
 }

+ 48 - 0
fs-service/src/main/java/com/fs/tenant/mapper/TenantInfoMapper.java

@@ -3,6 +3,8 @@ package com.fs.tenant.mapper;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.fs.tenant.domain.TenantInfo;
 
+import java.util.List;
+
 /**
 * @author Administrator
 * @description 针对表【tenant_info(租户基础信息表)】的数据库操作Mapper
@@ -10,7 +12,53 @@ import com.fs.tenant.domain.TenantInfo;
 * @Entity generator.domain.TenantInfo
 */
 public interface TenantInfoMapper extends BaseMapper<TenantInfo> {
+    /**
+     * 查询租户基础信息
+     *
+     * @param id 租户基础信息主键
+     * @return 租户基础信息
+     */
+    TenantInfo selectTenantInfoById(String id);
+
+    /**
+     * 查询租户基础信息列表
+     *
+     * @param tenantInfo 租户基础信息
+     * @return 租户基础信息集合
+     */
+    List<TenantInfo> selectTenantInfoList(TenantInfo tenantInfo);
+
+    /**
+     * 新增租户基础信息
+     *
+     * @param tenantInfo 租户基础信息
+     * @return 结果
+     */
+    int insertTenantInfo(TenantInfo tenantInfo);
+
+    /**
+     * 修改租户基础信息
+     *
+     * @param tenantInfo 租户基础信息
+     * @return 结果
+     */
+    int updateTenantInfo(TenantInfo tenantInfo);
+
+    /**
+     * 删除租户基础信息
+     *
+     * @param id 租户基础信息主键
+     * @return 结果
+     */
+    int deleteTenantInfoById(String id);
 
+    /**
+     * 批量删除租户基础信息
+     *
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteTenantInfoByIds(String[] ids);
 }
 
 

+ 48 - 0
fs-service/src/main/java/com/fs/tenant/service/TenantInfoService.java

@@ -3,11 +3,59 @@ package com.fs.tenant.service;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.fs.tenant.domain.TenantInfo;
 
+import java.util.List;
+
 /**
 * @author Administrator
 * @description 针对表【tenant_info(租户基础信息表)】的数据库操作Service
 * @createDate 2026-01-23 09:53:05
 */
 public interface TenantInfoService extends IService<TenantInfo> {
+    /**
+     * 查询租户基础信息
+     *
+     * @param id 租户基础信息主键
+     * @return 租户基础信息
+     */
+    TenantInfo selectTenantInfoById(String id);
+
+    /**
+     * 查询租户基础信息列表
+     *
+     * @param tenantInfo 租户基础信息
+     * @return 租户基础信息集合
+     */
+    List<TenantInfo> selectTenantInfoList(TenantInfo tenantInfo);
+
+    /**
+     * 新增租户基础信息
+     *
+     * @param tenantInfo 租户基础信息
+     * @return 结果
+     */
+    int insertTenantInfo(TenantInfo tenantInfo);
+
+    /**
+     * 修改租户基础信息
+     *
+     * @param tenantInfo 租户基础信息
+     * @return 结果
+     */
+    int updateTenantInfo(TenantInfo tenantInfo);
+
+    /**
+     * 批量删除租户基础信息
+     *
+     * @param ids 需要删除的租户基础信息主键集合
+     * @return 结果
+     */
+    int deleteTenantInfoByIds(String[] ids);
 
+    /**
+     * 删除租户基础信息信息
+     *
+     * @param id 租户基础信息主键
+     * @return 结果
+     */
+    int deleteTenantInfoById(String id);
 }

+ 76 - 2
fs-service/src/main/java/com/fs/tenant/service/impl/TenantInfoServiceImpl.java

@@ -1,20 +1,94 @@
 package com.fs.tenant.service.impl;
 
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.common.utils.DateUtils;
 import com.fs.tenant.domain.TenantInfo;
 import com.fs.tenant.mapper.TenantInfoMapper;
 import com.fs.tenant.service.TenantInfoService;
 import org.springframework.stereotype.Service;
 
+import java.util.List;
+
 /**
 * @author Administrator
 * @description 针对表【tenant_info(租户基础信息表)】的数据库操作Service实现
 * @createDate 2026-01-23 09:53:05
 */
 @Service
-public class TenantInfoServiceImpl extends ServiceImpl<TenantInfoMapper, TenantInfo>
-    implements TenantInfoService {
+public class TenantInfoServiceImpl extends ServiceImpl<TenantInfoMapper, TenantInfo> implements TenantInfoService {
+    /**
+     * 查询租户基础信息
+     *
+     * @param id 租户基础信息主键
+     * @return 租户基础信息
+     */
+    @Override
+    public TenantInfo selectTenantInfoById(String id)
+    {
+        return baseMapper.selectTenantInfoById(id);
+    }
+
+    /**
+     * 查询租户基础信息列表
+     *
+     * @param tenantInfo 租户基础信息
+     * @return 租户基础信息
+     */
+    @Override
+    public List<TenantInfo> selectTenantInfoList(TenantInfo tenantInfo)
+    {
+        return baseMapper.selectTenantInfoList(tenantInfo);
+    }
+
+    /**
+     * 新增租户基础信息
+     *
+     * @param tenantInfo 租户基础信息
+     * @return 结果
+     */
+    @Override
+    public int insertTenantInfo(TenantInfo tenantInfo)
+    {
+        tenantInfo.setCreateTime(DateUtils.getNowDate());
+        return baseMapper.insertTenantInfo(tenantInfo);
+    }
+
+    /**
+     * 修改租户基础信息
+     *
+     * @param tenantInfo 租户基础信息
+     * @return 结果
+     */
+    @Override
+    public int updateTenantInfo(TenantInfo tenantInfo)
+    {
+        tenantInfo.setUpdateTime(DateUtils.getNowDate());
+        return baseMapper.updateTenantInfo(tenantInfo);
+    }
+
+    /**
+     * 批量删除租户基础信息
+     *
+     * @param ids 需要删除的租户基础信息主键
+     * @return 结果
+     */
+    @Override
+    public int deleteTenantInfoByIds(String[] ids)
+    {
+        return baseMapper.deleteTenantInfoByIds(ids);
+    }
 
+    /**
+     * 删除租户基础信息信息
+     *
+     * @param id 租户基础信息主键
+     * @return 结果
+     */
+    @Override
+    public int deleteTenantInfoById(String id)
+    {
+        return baseMapper.deleteTenantInfoById(id);
+    }
 }
 
 

+ 4 - 0
fs-service/src/main/resources/mapper/system/SysUserMapper.xml

@@ -253,6 +253,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 		where u.phonenumber = #{phone}
 	</select>
 
+    <select id="getTenantInfo" resultType="com.fs.tenant.domain.TenantInfo">
+		SELECT * FROM `tenant_info` WHERE tenant_name = #{tenantCode}
+	</select>
+
     <insert id="insertUser" parameterType="SysUser" useGeneratedKeys="true" keyProperty="userId">
  		insert into sys_user(
  			<if test="userId != null and userId != 0">user_id,</if>

+ 94 - 17
fs-service/src/main/resources/mapper/tenant/TenantInfoMapper.xml

@@ -4,24 +4,101 @@
         "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.fs.tenant.mapper.TenantInfoMapper">
 
-    <resultMap id="BaseResultMap" type="com.fs.tenant.domain.TenantInfo">
-            <id property="id" column="id" />
-            <result property="tenantCode" column="tenant_code" />
-            <result property="tenantName" column="tenant_name" />
-            <result property="status" column="status" />
-            <result property="expireTime" column="expire_time" />
-            <result property="dbUrl" column="db_url" />
-            <result property="dbAccount" column="db_account" />
-            <result property="dbPwd" column="db_pwd" />
-            <result property="createTime" column="create_time" />
-            <result property="updateTime" column="update_time" />
-            <result property="contactPhone" column="contact_phone" />
-            <result property="contactName" column="contact_name" />
+    <resultMap type="TenantInfo" id="TenantInfoResult">
+        <result property="id"    column="id"    />
+        <result property="tenantCode"    column="tenant_code"    />
+        <result property="tenantName"    column="tenant_name"    />
+        <result property="status"    column="status"    />
+        <result property="expireTime"    column="expire_time"    />
+        <result property="dbUrl"    column="db_url"    />
+        <result property="dbAccount"    column="db_account"    />
+        <result property="dbPwd"    column="db_pwd"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="updateTime"    column="update_time"    />
+        <result property="contactPhone"    column="contact_phone"    />
+        <result property="contactName"    column="contact_name"    />
     </resultMap>
 
-    <sql id="Base_Column_List">
-        id,tenant_code,tenant_name,status,expire_time,db_url,
-        db_account,db_pwd,create_time,update_time,contact_phone,
-        contact_name
+    <sql id="selectTenantInfoVo">
+        select id, tenant_code, tenant_name, status, expire_time, db_url, db_account, db_pwd, create_time, update_time, contact_phone, contact_name from tenant_info
     </sql>
+
+    <select id="selectTenantInfoList" parameterType="TenantInfo" resultMap="TenantInfoResult">
+        <include refid="selectTenantInfoVo"/>
+        <where>
+            <if test="tenantCode != null  and tenantCode != ''"> and tenant_code = #{tenantCode}</if>
+            <if test="tenantName != null  and tenantName != ''"> and tenant_name like concat('%', #{tenantName}, '%')</if>
+            <if test="status != null "> and status = #{status}</if>
+            <if test="expireTime != null "> and expire_time = #{expireTime}</if>
+            <if test="dbUrl != null  and dbUrl != ''"> and db_url = #{dbUrl}</if>
+            <if test="dbAccount != null  and dbAccount != ''"> and db_account = #{dbAccount}</if>
+            <if test="dbPwd != null  and dbPwd != ''"> and db_pwd = #{dbPwd}</if>
+            <if test="contactPhone != null  and contactPhone != ''"> and contact_phone = #{contactPhone}</if>
+            <if test="contactName != null  and contactName != ''"> and contact_name like concat('%', #{contactName}, '%')</if>
+        </where>
+    </select>
+
+    <select id="selectTenantInfoById" parameterType="String" resultMap="TenantInfoResult">
+        <include refid="selectTenantInfoVo"/>
+        where id = #{id}
+    </select>
+
+    <insert id="insertTenantInfo" parameterType="TenantInfo" useGeneratedKeys="true" keyProperty="id">
+        insert into tenant_info
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="tenantCode != null and tenantCode != ''">tenant_code,</if>
+            <if test="tenantName != null and tenantName != ''">tenant_name,</if>
+            <if test="status != null">status,</if>
+            <if test="expireTime != null">expire_time,</if>
+            <if test="dbUrl != null">db_url,</if>
+            <if test="dbAccount != null">db_account,</if>
+            <if test="dbPwd != null">db_pwd,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="updateTime != null">update_time,</if>
+            <if test="contactPhone != null">contact_phone,</if>
+            <if test="contactName != null">contact_name,</if>
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="tenantCode != null and tenantCode != ''">#{tenantCode},</if>
+            <if test="tenantName != null and tenantName != ''">#{tenantName},</if>
+            <if test="status != null">#{status},</if>
+            <if test="expireTime != null">#{expireTime},</if>
+            <if test="dbUrl != null">#{dbUrl},</if>
+            <if test="dbAccount != null">#{dbAccount},</if>
+            <if test="dbPwd != null">#{dbPwd},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="contactPhone != null">#{contactPhone},</if>
+            <if test="contactName != null">#{contactName},</if>
+        </trim>
+    </insert>
+
+    <update id="updateTenantInfo" parameterType="TenantInfo">
+        update tenant_info
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="tenantCode != null and tenantCode != ''">tenant_code = #{tenantCode},</if>
+            <if test="tenantName != null and tenantName != ''">tenant_name = #{tenantName},</if>
+            <if test="status != null">status = #{status},</if>
+            <if test="expireTime != null">expire_time = #{expireTime},</if>
+            <if test="dbUrl != null">db_url = #{dbUrl},</if>
+            <if test="dbAccount != null">db_account = #{dbAccount},</if>
+            <if test="dbPwd != null">db_pwd = #{dbPwd},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+            <if test="contactPhone != null">contact_phone = #{contactPhone},</if>
+            <if test="contactName != null">contact_name = #{contactName},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteTenantInfoById" parameterType="String">
+        delete from tenant_info where id = #{id}
+    </delete>
+
+    <delete id="deleteTenantInfoByIds" parameterType="String">
+        delete from tenant_info where id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
 </mapper>