Browse Source

【新增】更新core和system模块,增加多租户的基础类

fengshuonan 4 years ago
parent
commit
65855eaa14
16 changed files with 484 additions and 8 deletions
  1. 10 0
      guns-base-support/guns-core/src/main/java/cn/stylefeng/guns/core/consts/AopSortConstant.java
  2. 43 0
      guns-base-support/guns-core/src/main/java/cn/stylefeng/guns/core/dbs/CurrentDataSourceContext.java
  3. 1 1
      guns-base-support/guns-core/src/main/java/cn/stylefeng/guns/core/pojo/login/SysLoginUser.java
  4. 31 0
      guns-base-support/guns-core/src/main/java/cn/stylefeng/guns/core/tenant/consts/TenantConstants.java
  5. 21 0
      guns-base-support/guns-core/src/main/java/cn/stylefeng/guns/core/tenant/consts/TenantExpEnumConstant.java
  6. 24 0
      guns-base-support/guns-core/src/main/java/cn/stylefeng/guns/core/tenant/context/TenantCodeHolder.java
  7. 24 0
      guns-base-support/guns-core/src/main/java/cn/stylefeng/guns/core/tenant/context/TenantDbNameHolder.java
  8. 71 0
      guns-base-support/guns-core/src/main/java/cn/stylefeng/guns/core/tenant/entity/TenantInfo.java
  9. 18 0
      guns-base-support/guns-core/src/main/java/cn/stylefeng/guns/core/tenant/exception/TenantException.java
  10. 56 0
      guns-base-support/guns-core/src/main/java/cn/stylefeng/guns/core/tenant/exception/enums/TenantExceptionEnum.java
  11. 44 0
      guns-base-support/guns-core/src/main/java/cn/stylefeng/guns/core/tenant/params/TenantInfoParam.java
  12. 56 0
      guns-base-support/guns-core/src/main/java/cn/stylefeng/guns/core/tenant/service/TenantInfoService.java
  13. 8 0
      guns-base-support/guns-system/src/main/java/cn/stylefeng/guns/sys/modular/auth/controller/SysLoginController.java
  14. 26 6
      guns-base-support/guns-system/src/main/java/cn/stylefeng/guns/sys/modular/auth/factory/LoginUserFactory.java
  15. 10 1
      guns-base-support/guns-system/src/main/java/cn/stylefeng/guns/sys/modular/auth/service/AuthService.java
  16. 41 0
      guns-base-support/guns-system/src/main/java/cn/stylefeng/guns/sys/modular/auth/service/impl/AuthServiceImpl.java

+ 10 - 0
guns-base-support/guns-core/src/main/java/cn/stylefeng/guns/core/consts/AopSortConstant.java

@ -54,6 +54,16 @@ public interface AopSortConstant {
     */
    int DATA_SCOPE_AOP = -50;
    /**
     * 多租户的aop
     */
    int TENANT_EXCHANGE_AOP = -10;
    /**
     * 多数据源切换的aop
     */
    int MULTI_DATA_SOURCE_AOP = 1;
    /**
     * 业务日志的AOP
     */

+ 43 - 0
guns-base-support/guns-core/src/main/java/cn/stylefeng/guns/core/dbs/CurrentDataSourceContext.java

@ -0,0 +1,43 @@
package cn.stylefeng.guns.core.dbs;
/**
 * datasource的上下文
 *
 * @author fengshuonan
 * @date 2020/8/24
 */
public class CurrentDataSourceContext {
    private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
    /**
     * 设置数据源类型
     *
     * @param dataSourceType 数据库类型
     * @date 2020/8/24
     */
    public static void setDataSourceType(String dataSourceType) {
        CONTEXT_HOLDER.set(dataSourceType);
    }
    /**
     * 获取数据源类型
     *
     * @author fengshuonan
     * @date 2020/8/24
     */
    public static String getDataSourceType() {
        return CONTEXT_HOLDER.get();
    }
    /**
     * 清除数据源类型
     *
     * @author fengshuonan
     * @date 2020/8/24
     */
    public static void clearDataSourceType() {
        CONTEXT_HOLDER.remove();
    }
}

+ 1 - 1
guns-base-support/guns-core/src/main/java/cn/stylefeng/guns/core/pojo/login/SysLoginUser.java

@ -163,7 +163,7 @@ public class SysLoginUser implements UserDetails, Serializable {
    /**
     * 租户信息
     */
    private List<Dict> tenants;
    private Dict tenants;
    /**
     * 角色名称集合

+ 31 - 0
guns-base-support/guns-core/src/main/java/cn/stylefeng/guns/core/tenant/consts/TenantConstants.java

@ -0,0 +1,31 @@
package cn.stylefeng.guns.core.tenant.consts;
/**
 * 租户的常量
 *
 * @author fengshuonan
 * @date 2019-06-18-16:24
 */
public interface TenantConstants {
    /**
     * 租户数据源标识前缀
     */
    String TENANT_DB_PREFIX = "guns_tenant_db_";
    /**
     * 初始化租户的sql文件名称
     */
    String INIT_SQL_FILE_NAME = "tenant_init.sql";
    /**
     * 租户编码的字段名称
     */
    String TENANT_CODE = "tenantCode";
    /**
     * 租户对应的数据库编码字段名称
     */
    String TENANT_DB_NAME = "tenantDbName";
}

+ 21 - 0
guns-base-support/guns-core/src/main/java/cn/stylefeng/guns/core/tenant/consts/TenantExpEnumConstant.java

@ -0,0 +1,21 @@
package cn.stylefeng.guns.core.tenant.consts;
/**
 * 多租户的异常编码规范
 *
 * @author fengshuonan
 * @date 2020/9/3
 */
public interface TenantExpEnumConstant {
    /**
     * 模块分类编码(2位)
     */
    int TENANT_MODULE_EXP_CODE = 60;
    /**
     * 租户操作相关分类编码(4位)
     */
    int TENANT_EXCEPTION_ENUM = 1100;
}

+ 24 - 0
guns-base-support/guns-core/src/main/java/cn/stylefeng/guns/core/tenant/context/TenantCodeHolder.java

@ -0,0 +1,24 @@
package cn.stylefeng.guns.core.tenant.context;
/**
 * 租户编码的临时存放
 *
 * @author fengshuonan
 * @date 2019-06-19-14:08
 */
public class TenantCodeHolder {
    private static final ThreadLocal<String> TENANT_CODE_HOLDER = new ThreadLocal<>();
    public static void put(String value) {
        TENANT_CODE_HOLDER.set(value);
    }
    public static String get() {
        return TENANT_CODE_HOLDER.get();
    }
    public static void remove() {
        TENANT_CODE_HOLDER.remove();
    }
}

+ 24 - 0
guns-base-support/guns-core/src/main/java/cn/stylefeng/guns/core/tenant/context/TenantDbNameHolder.java

@ -0,0 +1,24 @@
package cn.stylefeng.guns.core.tenant.context;
/**
 * 租户对应的数据库的临时存放
 *
 * @author fengshuonan
 * @date 2019-06-19-14:08
 */
public class TenantDbNameHolder {
    private static final ThreadLocal<String> DB_NAME_HOLDER = new ThreadLocal<>();
    public static void put(String value) {
        DB_NAME_HOLDER.set(value);
    }
    public static String get() {
        return DB_NAME_HOLDER.get();
    }
    public static void remove() {
        DB_NAME_HOLDER.remove();
    }
}

+ 71 - 0
guns-base-support/guns-core/src/main/java/cn/stylefeng/guns/core/tenant/entity/TenantInfo.java

@ -0,0 +1,71 @@
package cn.stylefeng.guns.core.tenant.entity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
 * <p>
 * 租户表
 * </p>
 *
 * @author stylefeng
 * @since 2019-06-16
 */
@TableName("tenant_info")
@Data
public class TenantInfo implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 主键id
     */
    @TableId(value = "tenant_id", type = IdType.ASSIGN_ID)
    private Long tenantId;
    /**
     * 租户名称
     */
    @TableField("name")
    private String name;
    /**
     * 租户的编码
     */
    @TableField("code")
    private String code;
    /**
     * 关联的数据库名称
     */
    @TableField("db_name")
    private String dbName;
    /**
     * 创建时间
     */
    @TableField(value = "create_time", fill = FieldFill.INSERT)
    private Date createTime;
    /**
     * 创建人
     */
    @TableField(value = "create_user", fill = FieldFill.INSERT)
    private Long createUser;
    /**
     * 更新时间
     */
    @TableField(value = "update_time", fill = FieldFill.UPDATE)
    private Date updateTime;
    /**
     * 更新人
     */
    @TableField(value = "update_user", fill = FieldFill.UPDATE)
    private Long updateUser;
}

+ 18 - 0
guns-base-support/guns-core/src/main/java/cn/stylefeng/guns/core/tenant/exception/TenantException.java

@ -0,0 +1,18 @@
package cn.stylefeng.guns.core.tenant.exception;
import cn.stylefeng.guns.core.exception.ServiceException;
import cn.stylefeng.guns.core.exception.enums.abs.AbstractBaseExceptionEnum;
/**
 * 多租户的异常
 *
 * @author fengshuonan
 * @date 2020/9/3
 */
public class TenantException extends ServiceException {
    public TenantException(AbstractBaseExceptionEnum exception) {
        super(exception);
    }
}

+ 56 - 0
guns-base-support/guns-core/src/main/java/cn/stylefeng/guns/core/tenant/exception/enums/TenantExceptionEnum.java

@ -0,0 +1,56 @@
package cn.stylefeng.guns.core.tenant.exception.enums;
import cn.stylefeng.guns.core.annotion.ExpEnumType;
import cn.stylefeng.guns.core.exception.enums.abs.AbstractBaseExceptionEnum;
import cn.stylefeng.guns.core.factory.ExpEnumCodeFactory;
import cn.stylefeng.guns.core.tenant.consts.TenantExpEnumConstant;
/**
 * 多租户异常枚举
 *
 * @author fengshuonan
 * @date 2020/8/24
 */
@ExpEnumType(module = TenantExpEnumConstant.TENANT_MODULE_EXP_CODE, kind = TenantExpEnumConstant.TENANT_EXCEPTION_ENUM)
public enum TenantExceptionEnum implements AbstractBaseExceptionEnum {
    /**
     * 更新租户的密码错误
     */
    UPDATE_TENANT_PASSWORD_ERROR(1, "更新租户的密码错误"),
    /**
     * 多数据源模块未启用,找不到DatabaseInfoService
     */
    DBS_MODULAR_NOT_ENABLE_ERROR(2, "多数据源模块未启用,找不到DatabaseInfoService"),
    /**
     * 找不到该租户信息
     */
    CNAT_FIND_TENANT_ERROR(3, "找不到该租户信息"),
    /**
     * 多租户模块未启用,找不到TenantInfoService
     */
    TENANT_MODULE_NOT_ENABLE_ERROR(4, "多租户模块未启用,找不到TenantInfoService");
    TenantExceptionEnum(int code, String message) {
        this.code = code;
        this.message = message;
    }
    private final Integer code;
    private final String message;
    @Override
    public Integer getCode() {
        return ExpEnumCodeFactory.getExpEnumCode(this.getClass(), code);
    }
    @Override
    public String getMessage() {
        return message;
    }
}

+ 44 - 0
guns-base-support/guns-core/src/main/java/cn/stylefeng/guns/core/tenant/params/TenantInfoParam.java

@ -0,0 +1,44 @@
package cn.stylefeng.guns.core.tenant.params;
import cn.stylefeng.guns.core.pojo.base.param.BaseParam;
import lombok.Data;
/**
 * <p>
 * 租户表
 * </p>
 *
 * @author stylefeng
 * @since 2019-06-16
 */
@Data
public class TenantInfoParam extends BaseParam {
    private static final long serialVersionUID = 1L;
    /**
     * 主键id
     */
    private Long tenantId;
    /**
     * 租户名称
     */
    private String name;
    /**
     * 租户的编码
     */
    private String code;
    /**
     * 租户管理员账号
     */
    private String adminUsername;
    /**
     * 租户管理员密码
     */
    private String adminPassword;
}

+ 56 - 0
guns-base-support/guns-core/src/main/java/cn/stylefeng/guns/core/tenant/service/TenantInfoService.java

@ -0,0 +1,56 @@
package cn.stylefeng.guns.core.tenant.service;
import cn.stylefeng.guns.core.pojo.page.PageResult;
import cn.stylefeng.guns.core.tenant.entity.TenantInfo;
import cn.stylefeng.guns.core.tenant.params.TenantInfoParam;
import com.baomidou.mybatisplus.extension.service.IService;
/**
 * 租户表 服务类
 *
 * @author stylefeng
 * @since 2019-06-16
 */
public interface TenantInfoService extends IService<TenantInfo> {
    /**
     * 新增租户
     *
     * @author stylefeng
     * @date 2019-06-16
     */
    void add(TenantInfoParam param);
    /**
     * 删除租户
     *
     * @author stylefeng
     * @date 2019-06-16
     */
    void delete(TenantInfoParam param);
    /**
     * 更新租户
     *
     * @author stylefeng
     * @date 2019-06-16
     */
    void update(TenantInfoParam param);
    /**
     * 分页查询租户列表
     *
     * @author fengshuonan
     * @date 2020/9/3
     */
    PageResult<TenantInfo> page(TenantInfoParam param);
    /**
     * 获取租户信息,通过租户编码
     *
     * @author fengshuonan
     * @date 2019-06-19 14:17
     */
    TenantInfo getByCode(String code);
}

+ 8 - 0
guns-base-support/guns-system/src/main/java/cn/stylefeng/guns/sys/modular/auth/controller/SysLoginController.java

@ -25,6 +25,7 @@ Guns采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意
package cn.stylefeng.guns.sys.modular.auth.controller;
import cn.hutool.core.lang.Dict;
import cn.stylefeng.guns.core.context.constant.ConstantContextHolder;
import cn.stylefeng.guns.core.context.login.LoginContextHolder;
import cn.stylefeng.guns.core.pojo.response.ResponseData;
import cn.stylefeng.guns.core.pojo.response.SuccessResponseData;
@ -58,6 +59,13 @@ public class SysLoginController {
    public ResponseData login(@RequestBody Dict dict) {
        String account = dict.getStr("account");
        String password = dict.getStr("password");
        String tenantCode = dict.getStr("tenantCode");
        //如果系统开启了多租户开关,则添加租户的临时缓存
        if (ConstantContextHolder.getTenantOpenFlag()) {
            authService.cacheTenantInfo(tenantCode);
        }
        String token = authService.login(account, password);
        return new SuccessResponseData(token);
    }

+ 26 - 6
guns-base-support/guns-system/src/main/java/cn/stylefeng/guns/sys/modular/auth/factory/LoginUserFactory.java

@ -28,12 +28,17 @@ import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.stylefeng.guns.core.consts.CommonConstant;
import cn.stylefeng.guns.core.context.constant.ConstantContextHolder;
import cn.stylefeng.guns.core.exception.ServiceException;
import cn.stylefeng.guns.core.exception.enums.ServerExceptionEnum;
import cn.stylefeng.guns.core.pojo.login.LoginEmpInfo;
import cn.stylefeng.guns.core.pojo.login.SysLoginUser;
import cn.stylefeng.guns.core.tenant.consts.TenantConstants;
import cn.stylefeng.guns.core.tenant.context.TenantCodeHolder;
import cn.stylefeng.guns.core.tenant.context.TenantDbNameHolder;
import cn.stylefeng.guns.core.util.HttpServletUtil;
import cn.stylefeng.guns.core.util.IpAddressUtil;
import cn.stylefeng.guns.core.util.UaUtil;
@ -80,27 +85,27 @@ public class LoginUserFactory {
            sysLoginUser.setLastLoginOs(UaUtil.getOs(request));
            Long userId = sysLoginUser.getId();
            //员工信息
            // 员工信息
            LoginEmpInfo loginEmpInfo = sysEmpService.getLoginEmpInfo(userId);
            sysLoginUser.setLoginEmpInfo(loginEmpInfo);
            //角色信息
            // 角色信息
            List<Dict> roles = sysRoleService.getLoginRoles(userId);
            sysLoginUser.setRoles(roles);
            //权限信息
            // 权限信息
            List<String> permissions = sysMenuService.getLoginPermissions(userId);
            sysLoginUser.setPermissions(permissions);
            //数据范围信息
            // 数据范围信息
            List<Long> dataScopes = sysUserService.getUserDataScopeIdList(userId, loginEmpInfo.getOrgId());
            sysLoginUser.setDataScopes(dataScopes);
            //具备应用信息(多系统,默认激活一个,可根据系统切换菜单),返回的结果中第一个为激活的系统
            // 具备应用信息(多系统,默认激活一个,可根据系统切换菜单),返回的结果中第一个为激活的系统
            List<Dict> apps = sysAppService.getLoginApps(userId);
            sysLoginUser.setApps(apps);
            //如果根本没有应用信息,则没有菜单信息
            // 如果根本没有应用信息,则没有菜单信息
            if (ObjectUtil.isEmpty(apps)) {
                sysLoginUser.setMenus(CollectionUtil.newArrayList());
            } else {
@ -108,6 +113,21 @@ public class LoginUserFactory {
                String defaultActiveAppCode = apps.get(0).getStr(CommonConstant.CODE);
                sysLoginUser.setMenus(sysMenuService.getLoginMenusAntDesign(userId, defaultActiveAppCode));
            }
            //如果开启了多租户功能,则设置当前登录用户的租户标识
            if (ConstantContextHolder.getTenantOpenFlag()) {
                String tenantCode = TenantCodeHolder.get();
                String dataBaseName = TenantDbNameHolder.get();
                if (StrUtil.isNotBlank(tenantCode) && StrUtil.isNotBlank(dataBaseName)) {
                    Dict tenantInfo = Dict.create();
                    tenantInfo.set(TenantConstants.TENANT_CODE, tenantCode);
                    tenantInfo.set(TenantConstants.TENANT_DB_NAME, dataBaseName);
                }
                //注意,这里remove不代表所有情况,在aop remove
                TenantCodeHolder.remove();
                TenantDbNameHolder.remove();
            }
        } else {
            throw new ServiceException(ServerExceptionEnum.REQUEST_EMPTY);
        }

+ 10 - 1
guns-base-support/guns-system/src/main/java/cn/stylefeng/guns/sys/modular/auth/service/AuthService.java

@ -40,7 +40,7 @@ public interface AuthService {
    /**
     * 账号密码登录
     *
     * @param account 账号
     * @param account  账号
     * @param password 密码
     * @return token
     * @author xuyuxiang
@ -102,4 +102,13 @@ public interface AuthService {
     * @date 2020/5/28 9:57
     */
    void checkToken(String token);
    /**
     * 临时缓存租户信息
     *
     * @param tenantCode 多租户编码
     * @author fengshuonan
     * @date 2020/9/3 21:22
     */
    void cacheTenantInfo(String tenantCode);
}

+ 41 - 0
guns-base-support/guns-system/src/main/java/cn/stylefeng/guns/sys/modular/auth/service/impl/AuthServiceImpl.java

@ -27,14 +27,23 @@ package cn.stylefeng.guns.sys.modular.auth.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.stylefeng.guns.core.consts.CommonConstant;
import cn.stylefeng.guns.core.context.constant.ConstantContextHolder;
import cn.stylefeng.guns.core.dbs.CurrentDataSourceContext;
import cn.stylefeng.guns.core.enums.CommonStatusEnum;
import cn.stylefeng.guns.core.exception.AuthException;
import cn.stylefeng.guns.core.exception.ServiceException;
import cn.stylefeng.guns.core.exception.enums.AuthExceptionEnum;
import cn.stylefeng.guns.core.exception.enums.ServerExceptionEnum;
import cn.stylefeng.guns.core.pojo.login.SysLoginUser;
import cn.stylefeng.guns.core.tenant.context.TenantCodeHolder;
import cn.stylefeng.guns.core.tenant.context.TenantDbNameHolder;
import cn.stylefeng.guns.core.tenant.entity.TenantInfo;
import cn.stylefeng.guns.core.tenant.exception.TenantException;
import cn.stylefeng.guns.core.tenant.exception.enums.TenantExceptionEnum;
import cn.stylefeng.guns.core.tenant.service.TenantInfoService;
import cn.stylefeng.guns.core.util.HttpServletUtil;
import cn.stylefeng.guns.core.util.IpAddressUtil;
import cn.stylefeng.guns.sys.core.cache.UserCache;
@ -207,6 +216,38 @@ public class AuthServiceImpl implements AuthService, UserDetailsService {
        }
    }
    @Override
    public void cacheTenantInfo(String tenantCode) {
        if (StrUtil.isBlank(tenantCode)) {
            return;
        }
        // 从spring容器中获取service,如果没开多租户功能,没引入相关包,这里会报错
        TenantInfoService tenantInfoService = null;
        try {
            tenantInfoService = SpringUtil.getBean(TenantInfoService.class);
        } catch (Exception e) {
            throw new TenantException(TenantExceptionEnum.TENANT_MODULE_NOT_ENABLE_ERROR);
        }
        // 获取租户信息
        TenantInfo tenantInfo = tenantInfoService.getByCode(tenantCode);
        if (tenantInfo != null) {
            String dbName = tenantInfo.getDbName();
            // 租户编码的临时存放
            TenantCodeHolder.put(tenantCode);
            // 租户的数据库名称临时缓存
            TenantDbNameHolder.put(dbName);
            // 数据源信息临时缓存
            CurrentDataSourceContext.setDataSourceType(dbName);
        } else {
            throw new TenantException(TenantExceptionEnum.CNAT_FIND_TENANT_ERROR);
        }
    }
    @Override
    public SysLoginUser loadUserByUsername(String account) throws UsernameNotFoundException {
        SysLoginUser sysLoginUser = new SysLoginUser();