<feat>接入MyBatis Plus,优化多租户登录代码逻辑。

This commit is contained in:
Yean 2025-02-22 23:56:15 +08:00
parent e3476ad90d
commit 1904d7b9d8
16 changed files with 641 additions and 30 deletions

28
pom.xml
View File

@ -18,13 +18,15 @@
<properties>
<java.version>17</java.version>
<magic-api.version>2.1.1</magic-api.version>
<druid.version>1.2.20</druid.version>
<hutool-all.version>5.8.15</hutool-all.version>
<sa-token.version>1.35.0.RC</sa-token.version>
<druid.version>1.2.23</druid.version>
<hutool-all.version>5.8.36</hutool-all.version>
<sa-token.version>1.40.0</sa-token.version>
<poi.version>4.1.2</poi.version>
<mysql.connector.version>8.0.32</mysql.connector.version>
<aliyun-core.version>4.6.0</aliyun-core.version>
<camunda.spring-boot.version>7.21.0</camunda.spring-boot.version>
<mybatis-plus.version>3.5.10.1</mybatis-plus.version>
<lombok.version>1.18.36</lombok.version>
</properties>
<dependencies>
<dependency>
@ -35,6 +37,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.ssssssss</groupId>
<artifactId>magic-api-spring-boot-starter</artifactId>
@ -60,6 +66,11 @@
<artifactId>sa-token-spring-boot3-starter</artifactId>
<version>${sa-token.version}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redis-jackson</artifactId>
<version>${sa-token.version}</version>
</dependency>
<dependency>
<groupId>org.ssssssss</groupId>
<artifactId>magic-api-plugin-task</artifactId>
@ -90,6 +101,17 @@
<artifactId>camunda-bpm-spring-boot-starter-rest</artifactId>
<version>${camunda.spring-boot.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>

View File

@ -1,9 +1,11 @@
package org.ssssssss.magicboot;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("org.ssssssss.magicboot.data.mapper")
public class MagicBootApplication {
public static void main(String[] args) {

View File

@ -0,0 +1,178 @@
package org.ssssssss.magicboot.data.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.util.Date;
import lombok.Data;
/**
* 租户表
* @TableName sys_tenant
*/
@TableName(value ="sys_tenant")
@Data
public class SysTenant {
/**
* 租户ID
*/
@TableId(value = "id")
private String id;
/**
* 租户编码
*/
@TableField(value = "code")
private String code;
/**
* 租户名称
*/
@TableField(value = "name")
private String name;
/**
* 租户Logo
*/
@TableField(value = "logo")
private String logo;
/**
* 网站图标
*/
@TableField(value = "favicon")
private String favicon;
/**
* 登录页背景图
*/
@TableField(value = "login_background")
private String loginBackground;
/**
* 系统名称
*/
@TableField(value = "system_name")
private String systemName;
/**
* 版权信息
*/
@TableField(value = "copyright")
private String copyright;
/**
* 状态0禁用1启用
*/
@TableField(value = "status")
private Integer status;
/**
* 到期时间
*/
@TableField(value = "expire_time")
private Date expireTime;
/**
* 最大用户数
*/
@TableField(value = "max_user")
private Integer maxUser;
/**
* 联系人姓名
*/
@TableField(value = "contact_name")
private String contactName;
/**
* 联系人电话
*/
@TableField(value = "contact_phone")
private String contactPhone;
/**
* 联系人邮箱
*/
@TableField(value = "contact_email")
private String contactEmail;
/**
* 备注信息
*/
@TableField(value = "remark")
private String remark;
/**
* 创建时间
*/
@TableField(value = "create_date")
private Date createDate;
/**
* 更新时间
*/
@TableField(value = "update_date")
private Date updateDate;
/**
* 删除标识
*/
@TableField(value = "is_del")
private Integer isDel;
/**
* 创建人ID
*/
@TableField(value = "create_by")
private String createBy;
/**
* 更新人ID
*/
@TableField(value = "update_by")
private String updateBy;
/**
* 数据库类型(MYSQL/MARIADB/SQLSERVER/ORACLE)
*/
@TableField(value = "db_type")
private String dbType;
/**
* 租户JDBC连接字符串
*/
@TableField(value = "db_jdbc_url")
private String dbJdbcUrl;
/**
* 数据库IP
*/
@TableField(value = "db_host")
private String dbHost;
/**
* 数据库端口号
*/
@TableField(value = "db_port")
private Integer dbPort;
/**
* 数据库用户名
*/
@TableField(value = "db_user")
private String dbUser;
/**
* 数据库密码
*/
@TableField(value = "db_password")
private String dbPassword;
/**
* 数据库名称
*/
@TableField(value = "db_name")
private String dbName;
}

View File

@ -0,0 +1,82 @@
package org.ssssssss.magicboot.data.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.util.Date;
import lombok.Data;
/**
* 租户接入配置表
* @TableName sys_tenant_platform
*/
@TableName(value ="sys_tenant_platform")
@Data
public class SysTenantPlatform {
/**
* 主键
*/
@TableId(value = "id")
private String id;
/**
* 租户ID
*/
@TableField(value = "tenant_id")
private String tenantId;
/**
* 平台类型DOMAIN域名,PATH路径,WX_MINI微信小程序,WX_MP微信公众号,WX_WORK企业微信,DINGTALK钉钉,FEISHU飞书
*/
@TableField(value = "platform_type")
private String platformType;
/**
* 标识符(域名/路径/AppID)
*/
@TableField(value = "identifier")
private String identifier;
/**
* 应用密钥
*/
@TableField(value = "app_secret")
private String appSecret;
/**
* 是否默认(用于域名)
*/
@TableField(value = "is_default")
private Integer isDefault;
/**
* 其他配置JSON
*/
@TableField(value = "other_config")
private String otherConfig;
/**
* 状态0禁用1启用
*/
@TableField(value = "status")
private Integer status;
/**
* 备注
*/
@TableField(value = "remark")
private String remark;
/**
* 创建时间
*/
@TableField(value = "create_date")
private Date createDate;
/**
* 更新时间
*/
@TableField(value = "update_date")
private Date updateDate;
}

View File

@ -0,0 +1,24 @@
package org.ssssssss.magicboot.data.mapper;
import org.apache.ibatis.annotations.Param;
import org.ssssssss.magicboot.data.entity.SysTenant;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @author yean
* @description 针对表sys_tenant(租户表)的数据库操作Mapper
* @Entity org.ssssssss.magicboot.data.entity.SysTenant
*/
public interface SysTenantMapper extends BaseMapper<SysTenant> {
/**
* 根据域名查询租户信息
* @param domain
* @return
*/
SysTenant getTenantByDomain(@Param("domain") String domain);
}

View File

@ -0,0 +1,18 @@
package org.ssssssss.magicboot.data.mapper;
import org.ssssssss.magicboot.data.entity.SysTenantPlatform;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @author yean
* @description 针对表sys_tenant_platform(租户接入配置表)的数据库操作Mapper
* @createDate 2025-02-22 17:40:22
* @Entity org.ssssssss.magicboot.data.entity.SysTenantPlatform
*/
public interface SysTenantPlatformMapper extends BaseMapper<SysTenantPlatform> {
}

View File

@ -0,0 +1,13 @@
package org.ssssssss.magicboot.data.service;
import org.ssssssss.magicboot.data.entity.SysTenantPlatform;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @author yean
* @description 针对表sys_tenant_platform(租户接入配置表)的数据库操作Service
* @createDate 2025-02-22 17:40:22
*/
public interface SysTenantPlatformService extends IService<SysTenantPlatform> {
}

View File

@ -0,0 +1,19 @@
package org.ssssssss.magicboot.data.service;
import org.ssssssss.magicboot.data.entity.SysTenant;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @author yean
* @description 针对表sys_tenant(租户表)的数据库操作Service
* @createDate 2025-02-22 17:37:23
*/
public interface SysTenantService extends IService<SysTenant> {
/**
* 根据域名获取租户信息
* @param domain
* @return
*/
SysTenant getTenantByDomain(String domain);
}

View File

@ -0,0 +1,22 @@
package org.ssssssss.magicboot.data.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.ssssssss.magicboot.data.entity.SysTenantPlatform;
import org.ssssssss.magicboot.data.service.SysTenantPlatformService;
import org.ssssssss.magicboot.data.mapper.SysTenantPlatformMapper;
import org.springframework.stereotype.Service;
/**
* @author yean
* @description 针对表sys_tenant_platform(租户接入配置表)的数据库操作Service实现
* @createDate 2025-02-22 17:40:22
*/
@Service
public class SysTenantPlatformServiceImpl extends ServiceImpl<SysTenantPlatformMapper, SysTenantPlatform>
implements SysTenantPlatformService{
}

View File

@ -0,0 +1,26 @@
package org.ssssssss.magicboot.data.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.ssssssss.magicboot.data.entity.SysTenant;
import org.ssssssss.magicboot.data.service.SysTenantService;
import org.ssssssss.magicboot.data.mapper.SysTenantMapper;
import org.springframework.stereotype.Service;
/**
* @author yean
* @description 针对表sys_tenant(租户表)的数据库操作Service实现
* @createDate 2025-02-22 17:37:23
*/
@Service
public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant>
implements SysTenantService{
@Override
public SysTenant getTenantByDomain(String domain) {
return getBaseMapper().getTenantByDomain(domain);
}
}

View File

@ -0,0 +1,28 @@
package org.ssssssss.magicboot.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
@AllArgsConstructor
public enum TenantStatus {
NORMAL(1,"启用"),
EXPIRED(0,"禁用"),
;
/**
* 状态码
*/
@Getter
private final Integer code;
/**
* 状态名称
*/
@Getter
private final String name;
}

View File

@ -3,8 +3,8 @@ package org.ssssssss.magicboot.interceptor;
import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.druid.pool.DruidDataSource;
import com.mysql.cj.jdbc.JdbcConnection;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.jdbc.core.JdbcTemplate;
@ -12,7 +12,11 @@ import org.springframework.stereotype.Component;
import org.ssssssss.magicapi.core.context.MagicUser;
import org.ssssssss.magicapi.core.exception.MagicLoginException;
import org.ssssssss.magicapi.core.interceptor.AuthorizationInterceptor;
import org.ssssssss.magicboot.data.entity.SysTenant;
import org.ssssssss.magicboot.data.service.SysTenantService;
import org.ssssssss.magicboot.enums.TenantDbType;
import org.ssssssss.magicboot.enums.TenantStatus;
import org.ssssssss.magicboot.utils.DruidTenantDataSourceUtil;
import java.util.Map;
@ -31,6 +35,12 @@ public class MagicApiAuthorizationInterceptor implements AuthorizationIntercepto
@Resource
private JdbcTemplate jdbcTemplate;
@Resource
private SysTenantService sysTenantService;
@Resource
private DruidTenantDataSourceUtil druidTenantDataSourceUtil;
@Override
public boolean requireLogin() {
return true;
@ -39,25 +49,21 @@ public class MagicApiAuthorizationInterceptor implements AuthorizationIntercepto
@Override
public MagicUser login(String username, String password) throws MagicLoginException {
// 根据当前域名查询租户
Map<String, Object> tenantInfo = jdbcTemplate.queryForMap("""
select st.*
from sys_tenant_platform stp
left join sys_tenant st on (st.id = stp.tenant_id)
where stp.identifier = ? limit 1
""", httpServletRequest.getServerName());
SysTenant tenantInfo = sysTenantService.getTenantByDomain(httpServletRequest.getServerName());
if (MapUtil.isEmpty(tenantInfo)) {
if (ObjectUtil.isEmpty(tenantInfo)) {
throw new MagicLoginException("很抱歉,租户不存在,请检查当前域名是否正确");
} else {
if (TenantStatus.EXPIRED.getCode().equals(tenantInfo.getStatus())) {
throw new MagicLoginException("很抱歉,租户已禁用");
}
return handleTenantLogin(tenantInfo, username, password);
}
}
@Override
public MagicUser getUserByToken(String token) throws MagicLoginException {
String loginId = (String) StpUtil.getLoginIdByToken(token);
if (StpUtil.isLogin(loginId)) {
return new MagicUser(loginId, loginId, token);
} else {
@ -77,33 +83,43 @@ public class MagicApiAuthorizationInterceptor implements AuthorizationIntercepto
* @param tenantInfo
* @return
*/
public MagicUser handleTenantLogin(Map<String, Object> tenantInfo, String username, String password) {
TenantDbType dbType = TenantDbType.valueOf(tenantInfo.get("db_type").toString());
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl((String) tenantInfo.get("db_jdbc_url"));
dataSource.setUsername((String) tenantInfo.get("db_user"));
dataSource.setPassword((String) tenantInfo.get("db_password"));
dataSource.setDriverClassName(dbType.getDriverClassName());
JdbcTemplate template = new JdbcTemplate(dataSource);
public MagicUser handleTenantLogin(SysTenant tenantInfo, String username, String password) throws MagicLoginException {
TenantDbType dbType = TenantDbType.valueOf(tenantInfo.getDbType());
DruidDataSource tenantDataSource = null;
try {
Map<String, Object> userInfo = template.queryForMap("""
select * from sys_user where username = ? and password = ? limit 1;
""", username, SaSecureUtil.sha256(password));
// 使用工具类创建数据源
tenantDataSource = druidTenantDataSourceUtil.createTenantDataSource(
dbType.getDriverClassName(),
tenantInfo.getDbJdbcUrl(),
tenantInfo.getDbUser(),
tenantInfo.getDbPassword()
);
// 使用临时JdbcTemplate查询用户
JdbcTemplate tenantJdbcTemplate = new JdbcTemplate(tenantDataSource);
Map<String, Object> userInfo = tenantJdbcTemplate.queryForMap(
"select * from sys_user where username = ? and password = ? and is_del = 0 limit 1",
username,
SaSecureUtil.sha256(password)
);
if (MapUtil.isNotEmpty(userInfo)) {
StpUtil.login(tenantInfo.get("id") + ":" + userInfo.get("id"));
StpUtil.login(tenantInfo.getId() + ":" + userInfo.get("id"));
MagicUser user = new MagicUser();
user.setToken(StpUtil.getTokenValue());
user.setUsername(tenantInfo.get("id") + ":" + username);
user.setId(tenantInfo.get("id") + "_" + userInfo.get("id").toString());
user.setUsername(tenantInfo.getId() + ":" + username);
user.setId(tenantInfo.getId() + "_" + userInfo.get("id").toString());
return user;
} else {
throw new MagicLoginException("很抱歉,用户名或密码错误");
}
} catch (Exception e) {
e.printStackTrace();
throw new MagicLoginException("登录失败: " + e.getMessage());
} finally {
// 使用工具类关闭数据源
druidTenantDataSourceUtil.closeDataSource(tenantDataSource);
}
return null;
}
}

View File

@ -0,0 +1,74 @@
package org.ssssssss.magicboot.utils;
import com.alibaba.druid.pool.DruidDataSource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class DruidTenantDataSourceUtil {
/**
* 创建租户数据源
*
* @param driverClassName 数据库驱动类名
* @param url 数据库连接URL
* @param username 用户名
* @param password 密码
* @return DruidDataSource实例
*/
public DruidDataSource createTenantDataSource(String driverClassName, String url, String username, String password) throws Exception {
DruidDataSource tenantDataSource = new DruidDataSource();
// 设置基本连接信息
tenantDataSource.setDriverClassName(driverClassName);
tenantDataSource.setUrl(url);
tenantDataSource.setUsername(username);
tenantDataSource.setPassword(password);
// 设置连接池配置
tenantDataSource.setInitialSize(1);
tenantDataSource.setMinIdle(1);
tenantDataSource.setMaxActive(20);
tenantDataSource.setMaxWait(60000);
tenantDataSource.setTimeBetweenEvictionRunsMillis(60000);
tenantDataSource.setMinEvictableIdleTimeMillis(300000);
tenantDataSource.setValidationQuery("SELECT 1");
tenantDataSource.setTestWhileIdle(true);
tenantDataSource.setTestOnBorrow(false);
tenantDataSource.setTestOnReturn(false);
tenantDataSource.setPoolPreparedStatements(true);
tenantDataSource.setMaxPoolPreparedStatementPerConnectionSize(20);
// 初始化数据源
tenantDataSource.init();
return tenantDataSource;
}
/**
* 创建租户JdbcTemplate
*
* @param driverClassName 数据库驱动类名
* @param url 数据库连接URL
* @param username 用户名
* @param password 密码
* @return JdbcTemplate实例
*/
public JdbcTemplate createTenantJdbcTemplate(String driverClassName, String url, String username, String password) throws Exception {
DruidDataSource dataSource = createTenantDataSource(driverClassName, url, username, password);
return new JdbcTemplate(dataSource);
}
/**
* 安全关闭数据源
*
* @param dataSource 要关闭的数据源
*/
public void closeDataSource(DruidDataSource dataSource) {
if (dataSource != null && !dataSource.isClosed()) {
dataSource.close();
}
}
}

View File

@ -0,0 +1,6 @@
███╗ ███╗ █████╗ ██████╗ ██╗ ██████╗ ██████╗ ██████╗ ██████╗ ████████╗
████╗ ████║██╔══██╗██╔════╝ ██║██╔════╝ ██╔══██╗██╔═══██╗██╔═══██╗╚══██╔══╝
██╔████╔██║███████║██║ ███╗██║██║ ██████╔╝██║ ██║██║ ██║ ██║
██║╚██╔╝██║██╔══██║██║ ██║██║██║ ██╔══██╗██║ ██║██║ ██║ ██║
██║ ╚═╝ ██║██║ ██║╚██████╔╝██║╚██████╗ ██████╔╝╚██████╔╝╚██████╔╝ ██║
╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝

View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.ssssssss.magicboot.data.mapper.SysTenantMapper">
<resultMap id="BaseResultMap" type="org.ssssssss.magicboot.data.entity.SysTenant">
<id property="id" column="id" jdbcType="VARCHAR"/>
<result property="code" column="code" jdbcType="VARCHAR"/>
<result property="name" column="name" jdbcType="VARCHAR"/>
<result property="logo" column="logo" jdbcType="VARCHAR"/>
<result property="favicon" column="favicon" jdbcType="VARCHAR"/>
<result property="loginBackground" column="login_background" jdbcType="VARCHAR"/>
<result property="systemName" column="system_name" jdbcType="VARCHAR"/>
<result property="copyright" column="copyright" jdbcType="VARCHAR"/>
<result property="status" column="status" jdbcType="INTEGER"/>
<result property="expireTime" column="expire_time" jdbcType="TIMESTAMP"/>
<result property="maxUser" column="max_user" jdbcType="INTEGER"/>
<result property="contactName" column="contact_name" jdbcType="VARCHAR"/>
<result property="contactPhone" column="contact_phone" jdbcType="VARCHAR"/>
<result property="contactEmail" column="contact_email" jdbcType="VARCHAR"/>
<result property="remark" column="remark" jdbcType="VARCHAR"/>
<result property="createDate" column="create_date" jdbcType="TIMESTAMP"/>
<result property="updateDate" column="update_date" jdbcType="TIMESTAMP"/>
<result property="isDel" column="is_del" jdbcType="INTEGER"/>
<result property="createBy" column="create_by" jdbcType="VARCHAR"/>
<result property="updateBy" column="update_by" jdbcType="VARCHAR"/>
<result property="dbType" column="db_type" jdbcType="VARCHAR"/>
<result property="dbJdbcUrl" column="db_jdbc_url" jdbcType="VARCHAR"/>
<result property="dbHost" column="db_host" jdbcType="VARCHAR"/>
<result property="dbPort" column="db_port" jdbcType="INTEGER"/>
<result property="dbUser" column="db_user" jdbcType="VARCHAR"/>
<result property="dbPassword" column="db_password" jdbcType="VARCHAR"/>
<result property="dbName" column="db_name" jdbcType="VARCHAR"/>
</resultMap>
<sql id="Base_Column_List">
id,code,name,
logo,favicon,login_background,
system_name,copyright,status,
expire_time,max_user,contact_name,
contact_phone,contact_email,remark,
create_date,update_date,is_del,
create_by,update_by,db_type,
db_jdbc_url,db_host,db_port,
db_user,db_password,db_name
</sql>
<select id="getTenantByDomain" resultType="org.ssssssss.magicboot.data.entity.SysTenant">
select st.*
from sys_tenant_platform stp
left join sys_tenant st on (st.id = stp.tenant_id)
where stp.identifier = #{domain} limit 1
</select>
</mapper>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.ssssssss.magicboot.data.mapper.SysTenantPlatformMapper">
<resultMap id="BaseResultMap" type="org.ssssssss.magicboot.data.entity.SysTenantPlatform">
<id property="id" column="id" jdbcType="VARCHAR"/>
<result property="tenantId" column="tenant_id" jdbcType="VARCHAR"/>
<result property="platformType" column="platform_type" jdbcType="VARCHAR"/>
<result property="identifier" column="identifier" jdbcType="VARCHAR"/>
<result property="appSecret" column="app_secret" jdbcType="VARCHAR"/>
<result property="isDefault" column="is_default" jdbcType="INTEGER"/>
<result property="otherConfig" column="other_config" jdbcType="VARCHAR"/>
<result property="status" column="status" jdbcType="INTEGER"/>
<result property="remark" column="remark" jdbcType="VARCHAR"/>
<result property="createDate" column="create_date" jdbcType="TIMESTAMP"/>
<result property="updateDate" column="update_date" jdbcType="TIMESTAMP"/>
</resultMap>
<sql id="Base_Column_List">
id,tenant_id,platform_type,
identifier,app_secret,is_default,
other_config,status,remark,
create_date,update_date
</sql>
</mapper>