mirror of
https://gitee.com/hhyykk/ipms-sjy.git
synced 2025-09-19 19:42:37 +08:00
多模块重构 4:system 模块的创建,去除 Sys
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.infra.enums;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
|
||||
|
||||
/**
|
||||
* System 错误码枚举类
|
||||
*
|
||||
* system 系统,使用 1-006-000-000 段
|
||||
*/
|
||||
public interface SysErrorCodeConstants {
|
||||
|
||||
// ========= 文件相关 1006001000=================
|
||||
ErrorCode FILE_PATH_EXISTS = new ErrorCode(1006001000, "文件路径已存在");
|
||||
ErrorCode FILE_NOT_EXISTS = new ErrorCode(1006001002, "文件不存在");
|
||||
|
||||
}
|
@@ -1,4 +0,0 @@
|
||||
/**
|
||||
* 占位类,可以无视
|
||||
*/
|
||||
package cn.iocoder.yudao.coreservice.modules.infra.enums;
|
@@ -10,7 +10,7 @@ import org.springframework.stereotype.Service;
|
||||
import javax.annotation.Resource;
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
import static cn.iocoder.yudao.coreservice.modules.system.enums.SysErrorCodeConstants.*;
|
||||
import static cn.iocoder.yudao.coreservice.modules.infra.enums.SysErrorCodeConstants.*;
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
|
||||
/**
|
||||
|
@@ -1,20 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.convert.dict;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.dict.SysDictDataDO;
|
||||
import cn.iocoder.yudao.framework.dict.core.dto.DictDataRespDTO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface SysDictDataCoreConvert {
|
||||
|
||||
SysDictDataCoreConvert INSTANCE = Mappers.getMapper(SysDictDataCoreConvert.class);
|
||||
|
||||
DictDataRespDTO convert02(SysDictDataDO bean);
|
||||
|
||||
List<DictDataRespDTO> convertList03(Collection<SysDictDataDO> list);
|
||||
|
||||
}
|
@@ -1,15 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.convert.logger;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.logger.SysLoginLogDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.service.logger.dto.SysLoginLogCreateReqDTO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
@Mapper
|
||||
public interface SysLoginLogCoreConvert {
|
||||
|
||||
SysLoginLogCoreConvert INSTANCE = Mappers.getMapper(SysLoginLogCoreConvert.class);
|
||||
|
||||
SysLoginLogDO convert(SysLoginLogCreateReqDTO bean);
|
||||
|
||||
}
|
@@ -1,6 +0,0 @@
|
||||
/**
|
||||
* 提供 POJO 类的实体转换
|
||||
*
|
||||
* 目前使用 MapStruct 框架
|
||||
*/
|
||||
package cn.iocoder.yudao.coreservice.modules.system.convert;
|
@@ -1 +0,0 @@
|
||||
<http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao>
|
@@ -1,68 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.auth;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 在线用户表
|
||||
*
|
||||
* 我们已经将 {@link LoginUser} 缓存在 Redis 当中。
|
||||
* 这里额外存储在线用户到 MySQL 中,目的是为了方便管理界面可以灵活查询。
|
||||
* 同时,通过定时轮询 SysUserSessionDO 表,可以主动删除 Redis 的缓存,因为 Redis 的过期删除是延迟的。
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@TableName(value = "sys_user_session", autoResultMap = true)
|
||||
@Data
|
||||
@Builder
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class SysUserSessionDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 会话编号, 即 sessionId
|
||||
*/
|
||||
@TableId(type = IdType.INPUT)
|
||||
private String id;
|
||||
/**
|
||||
* 用户编号
|
||||
*
|
||||
* 关联 SysUserDO.id 或者 MbrUserDO.id
|
||||
*/
|
||||
private Long userId;
|
||||
/**
|
||||
* 用户类型
|
||||
*
|
||||
* 枚举 {@link UserTypeEnum}
|
||||
*/
|
||||
private Integer userType;
|
||||
|
||||
/**
|
||||
* 用户账号
|
||||
*
|
||||
* 冗余,因为账号可以变更
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 用户 IP
|
||||
*/
|
||||
private String userIp;
|
||||
/**
|
||||
* 浏览器 UA
|
||||
*/
|
||||
private String userAgent;
|
||||
/**
|
||||
* 会话超时时间
|
||||
*/
|
||||
private Date sessionTimeout;
|
||||
|
||||
}
|
@@ -1,62 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.dept;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 部门表
|
||||
*
|
||||
* @author ruoyi
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@TableName("sys_dept")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class SysDeptDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 父部门ID
|
||||
*
|
||||
* 关联 {@link #id}
|
||||
*/
|
||||
private Long parentId;
|
||||
/**
|
||||
* 显示顺序
|
||||
*/
|
||||
private Integer sort;
|
||||
/**
|
||||
* 负责人
|
||||
*
|
||||
* 关联 {@link SysUserDO#getId()}
|
||||
*/
|
||||
private Long leaderUserId;
|
||||
/**
|
||||
* 联系电话
|
||||
*/
|
||||
private String phone;
|
||||
/**
|
||||
* 邮箱
|
||||
*/
|
||||
private String email;
|
||||
/**
|
||||
* 部门状态
|
||||
*
|
||||
* 枚举 {@link CommonStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
}
|
@@ -1,48 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.dept;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 岗位表
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@TableName("sys_post")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class SysPostDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 岗位序号
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 岗位名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 岗位编码
|
||||
*/
|
||||
private String code;
|
||||
/**
|
||||
* 岗位排序
|
||||
*/
|
||||
private Integer sort;
|
||||
/**
|
||||
* 状态
|
||||
*
|
||||
* 枚举 {@link CommonStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
@@ -1,54 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.dict;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 字典数据表
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@TableName("sys_dict_data")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class SysDictDataDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 字典数据编号
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 字典排序
|
||||
*/
|
||||
private Integer sort;
|
||||
/**
|
||||
* 字典标签
|
||||
*/
|
||||
private String label;
|
||||
/**
|
||||
* 字典值
|
||||
*/
|
||||
private String value;
|
||||
/**
|
||||
* 字典类型
|
||||
*
|
||||
* 冗余 {@link SysDictDataDO#getDictType()}
|
||||
*/
|
||||
private String dictType;
|
||||
/**
|
||||
* 状态
|
||||
*
|
||||
* 枚举 {@link CommonStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
@@ -1,70 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.logger;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.enums.logger.SysLoginLogTypeEnum;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.enums.logger.SysLoginResultEnum;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* 登录日志表
|
||||
*
|
||||
* 注意,包括登录和登出两种行为
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@TableName("sys_login_log")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class SysLoginLogDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 日志主键
|
||||
*/
|
||||
private Long id;
|
||||
/**
|
||||
* 日志类型
|
||||
*
|
||||
* 枚举 {@link SysLoginLogTypeEnum}
|
||||
*/
|
||||
private Integer logType;
|
||||
/**
|
||||
* 链路追踪编号
|
||||
*/
|
||||
private String traceId;
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
private Long userId;
|
||||
/**
|
||||
* 用户类型
|
||||
*
|
||||
* 枚举 {@link UserTypeEnum}
|
||||
*/
|
||||
private Integer userType;
|
||||
/**
|
||||
* 用户账号
|
||||
*
|
||||
* 冗余,因为账号可以变更
|
||||
*/
|
||||
private String username;
|
||||
/**
|
||||
* 登录结果
|
||||
*
|
||||
* 枚举 {@link SysLoginResultEnum}
|
||||
*/
|
||||
private Integer result;
|
||||
/**
|
||||
* 用户 IP
|
||||
*/
|
||||
private String userIp;
|
||||
/**
|
||||
* 浏览器 UA
|
||||
*/
|
||||
private String userAgent;
|
||||
|
||||
}
|
@@ -1 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.dal.dataobject;
|
@@ -1,75 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.permission;
|
||||
|
||||
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.security.core.enums.DataScopeEnum;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 角色 DO
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@TableName(value = "sys_role", autoResultMap = true)
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class SysRoleDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 角色ID
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 角色名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 角色标识
|
||||
*
|
||||
* 枚举
|
||||
*/
|
||||
private String code;
|
||||
/**
|
||||
* 角色排序
|
||||
*/
|
||||
private Integer sort;
|
||||
/**
|
||||
* 角色状态
|
||||
*
|
||||
* 枚举 {@link CommonStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
/**
|
||||
* 角色类型
|
||||
*
|
||||
* 枚举
|
||||
*/
|
||||
private Integer type;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 数据范围
|
||||
*
|
||||
* 枚举 {@link DataScopeEnum}
|
||||
*/
|
||||
private Integer dataScope;
|
||||
/**
|
||||
* 数据范围(指定部门数组)
|
||||
*
|
||||
* 适用于 {@link #dataScope} 的值为 {@link DataScopeEnum#DEPT_CUSTOM} 时
|
||||
*/
|
||||
@TableField(typeHandler = JsonLongSetTypeHandler.class)
|
||||
private Set<Long> dataScopeDeptIds;
|
||||
|
||||
}
|
@@ -1,33 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.permission;
|
||||
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 用户和角色关联
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@TableName("sys_user_role")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class SysUserRoleDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 自增主键
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 用户 ID
|
||||
*/
|
||||
private Long userId;
|
||||
/**
|
||||
* 角色 ID
|
||||
*/
|
||||
private Long roleId;
|
||||
|
||||
}
|
@@ -1,60 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.sms.core.enums.SmsChannelEnum;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* 短信渠道 DO
|
||||
*
|
||||
* @author zzf
|
||||
* @since 2021-01-25
|
||||
*/
|
||||
@TableName(value = "sys_sms_channel", autoResultMap = true)
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class SysSmsChannelDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 渠道编号
|
||||
*/
|
||||
private Long id;
|
||||
/**
|
||||
* 短信签名
|
||||
*/
|
||||
private String signature;
|
||||
/**
|
||||
* 渠道编码
|
||||
*
|
||||
* 枚举 {@link SmsChannelEnum}
|
||||
*/
|
||||
private String code;
|
||||
/**
|
||||
* 启用状态
|
||||
*
|
||||
* 枚举 {@link CommonStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
/**
|
||||
* 短信 API 的账号
|
||||
*/
|
||||
private String apiKey;
|
||||
/**
|
||||
* 短信 API 的秘钥
|
||||
*/
|
||||
private String apiSecret;
|
||||
/**
|
||||
* 短信发送回调 URL
|
||||
*/
|
||||
private String callbackUrl;
|
||||
|
||||
}
|
@@ -1,173 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.system.enums.sms.SysSmsReceiveStatusEnum;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.enums.sms.SysSmsSendStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||
import lombok.*;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 短信日志 DO
|
||||
*
|
||||
* @author zzf
|
||||
* @since 2021-01-25
|
||||
*/
|
||||
@TableName(value = "sys_sms_log", autoResultMap = true)
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class SysSmsLogDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 自增编号
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
// ========= 渠道相关字段 =========
|
||||
|
||||
/**
|
||||
* 短信渠道编号
|
||||
*
|
||||
* 关联 {@link SysSmsChannelDO#getId()}
|
||||
*/
|
||||
private Long channelId;
|
||||
/**
|
||||
* 短信渠道编码
|
||||
*
|
||||
* 冗余 {@link SysSmsChannelDO#getCode()}
|
||||
*/
|
||||
private String channelCode;
|
||||
|
||||
// ========= 模板相关字段 =========
|
||||
|
||||
/**
|
||||
* 模板编号
|
||||
*
|
||||
* 关联 {@link SysSmsTemplateDO#getId()}
|
||||
*/
|
||||
private Long templateId;
|
||||
/**
|
||||
* 模板编码
|
||||
*
|
||||
* 冗余 {@link SysSmsTemplateDO#getCode()}
|
||||
*/
|
||||
private String templateCode;
|
||||
/**
|
||||
* 短信类型
|
||||
*
|
||||
* 冗余 {@link SysSmsTemplateDO#getType()}
|
||||
*/
|
||||
private Integer templateType;
|
||||
/**
|
||||
* 基于 {@link SysSmsTemplateDO#getContent()} 格式化后的内容
|
||||
*/
|
||||
private String templateContent;
|
||||
/**
|
||||
* 基于 {@link SysSmsTemplateDO#getParams()} 输入后的参数
|
||||
*/
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private Map<String, Object> templateParams;
|
||||
/**
|
||||
* 短信 API 的模板编号
|
||||
*
|
||||
* 冗余 {@link SysSmsTemplateDO#getApiTemplateId()}
|
||||
*/
|
||||
private String apiTemplateId;
|
||||
|
||||
// ========= 手机相关字段 =========
|
||||
|
||||
/**
|
||||
* 手机号
|
||||
*/
|
||||
private String mobile;
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
private Long userId;
|
||||
/**
|
||||
* 用户类型
|
||||
*
|
||||
* 枚举 {@link UserTypeEnum}
|
||||
*/
|
||||
private Integer userType;
|
||||
|
||||
// ========= 发送相关字段 =========
|
||||
|
||||
/**
|
||||
* 发送状态
|
||||
*
|
||||
* 枚举 {@link SysSmsSendStatusEnum}
|
||||
*/
|
||||
private Integer sendStatus;
|
||||
/**
|
||||
* 发送时间
|
||||
*/
|
||||
private Date sendTime;
|
||||
/**
|
||||
* 发送结果的编码
|
||||
*
|
||||
* 枚举 {@link SmsFrameworkErrorCodeConstants}
|
||||
*/
|
||||
private Integer sendCode;
|
||||
/**
|
||||
* 发送结果的提示
|
||||
*
|
||||
* 一般情况下,使用 {@link SmsFrameworkErrorCodeConstants}
|
||||
* 异常情况下,通过格式化 Exception 的提示存储
|
||||
*/
|
||||
private String sendMsg;
|
||||
/**
|
||||
* 短信 API 发送结果的编码
|
||||
*
|
||||
* 由于第三方的错误码可能是字符串,所以使用 String 类型
|
||||
*/
|
||||
private String apiSendCode;
|
||||
/**
|
||||
* 短信 API 发送失败的提示
|
||||
*/
|
||||
private String apiSendMsg;
|
||||
/**
|
||||
* 短信 API 发送返回的唯一请求 ID
|
||||
*
|
||||
* 用于和短信 API 进行定位于排错
|
||||
*/
|
||||
private String apiRequestId;
|
||||
/**
|
||||
* 短信 API 发送返回的序号
|
||||
*
|
||||
* 用于和短信 API 平台的发送记录关联
|
||||
*/
|
||||
private String apiSerialNo;
|
||||
|
||||
// ========= 接收相关字段 =========
|
||||
|
||||
/**
|
||||
* 接收状态
|
||||
*
|
||||
* 枚举 {@link SysSmsReceiveStatusEnum}
|
||||
*/
|
||||
private Integer receiveStatus;
|
||||
/**
|
||||
* 接收时间
|
||||
*/
|
||||
private Date receiveTime;
|
||||
/**
|
||||
* 短信 API 接收结果的编码
|
||||
*/
|
||||
private String apiReceiveCode;
|
||||
/**
|
||||
* 短信 API 接收结果的提示
|
||||
*/
|
||||
private String apiReceiveMsg;
|
||||
|
||||
}
|
@@ -1,89 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.system.enums.sms.SysSmsTemplateTypeEnum;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 短信模板 DO
|
||||
*
|
||||
* @author zzf
|
||||
* @since 2021-01-25
|
||||
*/
|
||||
@TableName(value = "sys_sms_template", autoResultMap = true)
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class SysSmsTemplateDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 自增编号
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
// ========= 模板相关字段 =========
|
||||
|
||||
/**
|
||||
* 短信类型
|
||||
*
|
||||
* 枚举 {@link SysSmsTemplateTypeEnum}
|
||||
*/
|
||||
private Integer type;
|
||||
/**
|
||||
* 启用状态
|
||||
*
|
||||
* 枚举 {@link CommonStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
/**
|
||||
* 模板编码,保证唯一
|
||||
*/
|
||||
private String code;
|
||||
/**
|
||||
* 模板名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 模板内容
|
||||
*
|
||||
* 内容的参数,使用 {} 包括,例如说 {name}
|
||||
*/
|
||||
private String content;
|
||||
/**
|
||||
* 参数数组(自动根据内容生成)
|
||||
*/
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private List<String> params;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
/**
|
||||
* 短信 API 的模板编号
|
||||
*/
|
||||
private String apiTemplateId;
|
||||
|
||||
// ========= 渠道相关字段 =========
|
||||
|
||||
/**
|
||||
* 短信渠道编号
|
||||
*
|
||||
* 关联 {@link SysSmsChannelDO#getId()}
|
||||
*/
|
||||
private Long channelId;
|
||||
/**
|
||||
* 短信渠道编码
|
||||
*
|
||||
* 冗余 {@link SysSmsChannelDO#getCode()}
|
||||
*/
|
||||
private String channelCode;
|
||||
|
||||
}
|
@@ -1,82 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.social;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
|
||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.*;
|
||||
|
||||
/**
|
||||
* 社交用户
|
||||
* 通过 {@link SysSocialUserDO#getUserId()} 关联到对应的 {@link SysUserDO}
|
||||
*
|
||||
* @author weir
|
||||
*/
|
||||
@TableName(value = "sys_social_user", autoResultMap = true)
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SysSocialUserDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 自增主键
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 关联的用户编号
|
||||
*/
|
||||
private Long userId;
|
||||
/**
|
||||
* 用户类型
|
||||
*
|
||||
* 枚举 {@link UserTypeEnum}
|
||||
*/
|
||||
private Integer userType;
|
||||
|
||||
/**
|
||||
* 社交平台的类型
|
||||
*
|
||||
* 枚举 {@link UserTypeEnum}
|
||||
*/
|
||||
private Integer type;
|
||||
|
||||
/**
|
||||
* 社交 openid
|
||||
*/
|
||||
private String openid;
|
||||
/**
|
||||
* 社交 token
|
||||
*/
|
||||
private String token;
|
||||
/**
|
||||
* 社交的全局编号
|
||||
*
|
||||
* 例如说,微信平台的 https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/union-id.html
|
||||
* 如果没有 unionId 的平台,直接使用 openid 作为该字段的值
|
||||
*/
|
||||
private String unionId;
|
||||
/**
|
||||
* 原始 Token 数据,一般是 JSON 格式
|
||||
*/
|
||||
private String rawTokenInfo;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
private String nickname;
|
||||
/**
|
||||
* 用户头像
|
||||
*/
|
||||
private String avatar;
|
||||
/**
|
||||
* 原始用户数据,一般是 JSON 格式
|
||||
*/
|
||||
private String rawUserInfo;
|
||||
|
||||
}
|
||||
|
||||
|
@@ -1,45 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.tenant;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.*;
|
||||
|
||||
/**
|
||||
* 租户 DO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@TableName(value = "sys_tenant", autoResultMap = true)
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class SysTenantDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 租户编号,自增
|
||||
*/
|
||||
private Long id;
|
||||
/**
|
||||
* 租户名,唯一
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 联系人
|
||||
*/
|
||||
private String contactName;
|
||||
/**
|
||||
* 联系手机
|
||||
*/
|
||||
private String contactMobile;
|
||||
/**
|
||||
* 帐号状态
|
||||
*
|
||||
* 枚举 {@link CommonStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
}
|
@@ -1,94 +0,0 @@
|
||||
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.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;
|
||||
import lombok.*;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 管理后台的用户 DO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@TableName(value = "sys_user", autoResultMap = true)
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SysUserDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 用户账号
|
||||
*/
|
||||
private String username;
|
||||
/**
|
||||
* 加密后的密码
|
||||
*
|
||||
* 因为目前使用 {@link BCryptPasswordEncoder} 加密器,所以无需自己处理 salt 盐
|
||||
*/
|
||||
private String password;
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
private String nickname;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
private Long deptId;
|
||||
/**
|
||||
* 岗位编号数组
|
||||
*/
|
||||
@TableField(typeHandler = JsonLongSetTypeHandler.class)
|
||||
private Set<Long> postIds;
|
||||
/**
|
||||
* 用户邮箱
|
||||
*/
|
||||
private String email;
|
||||
/**
|
||||
* 手机号码
|
||||
*/
|
||||
private String mobile;
|
||||
/**
|
||||
* 用户性别
|
||||
*
|
||||
* 枚举类 {@link SysSexEnum}
|
||||
*/
|
||||
private Integer sex;
|
||||
/**
|
||||
* 用户头像
|
||||
*/
|
||||
private String avatar;
|
||||
/**
|
||||
* 帐号状态
|
||||
*
|
||||
* 枚举 {@link CommonStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
/**
|
||||
* 最后登录IP
|
||||
*/
|
||||
private String loginIp;
|
||||
/**
|
||||
* 最后登录时间
|
||||
*/
|
||||
private Date loginDate;
|
||||
|
||||
}
|
@@ -1,10 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.dal.mysql.auth;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.auth.SysUserSessionDO;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface SysUserSessionCoreMapper extends BaseMapperX<SysUserSessionDO> {
|
||||
|
||||
}
|
@@ -1,9 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.dal.mysql.dept;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.dept.SysDeptDO;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface SysDeptCoreMapper extends BaseMapperX<SysDeptDO> {
|
||||
}
|
@@ -1,9 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.dal.mysql.dept;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.dept.SysPostDO;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface SysPostCoreMapper extends BaseMapperX<SysPostDO> {
|
||||
}
|
@@ -1,19 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.dal.mysql.dict;
|
||||
|
||||
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.dict.SysDictDataDO;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Mapper
|
||||
public interface SysDictDataCoreMapper extends BaseMapperX<SysDictDataDO> {
|
||||
|
||||
default boolean selectExistsByUpdateTimeAfter(Date maxUpdateTime) {
|
||||
return selectOne(new QueryWrapper<SysDictDataDO>().select("id")
|
||||
.gt("update_time", maxUpdateTime).last("LIMIT 1")) != null;
|
||||
}
|
||||
|
||||
}
|
@@ -1,10 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.dal.mysql.logger;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.logger.SysLoginLogDO;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface SysLoginLogCoreMapper extends BaseMapperX<SysLoginLogDO> {
|
||||
|
||||
}
|
@@ -1 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.dal.mysql;
|
@@ -1,9 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.dal.mysql.permission;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.permission.SysRoleDO;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface SysRoleCoreMapper extends BaseMapperX<SysRoleDO> {
|
||||
}
|
@@ -1,17 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.dal.mysql.permission;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.permission.SysUserRoleDO;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface SysUserRoleCoreMapper extends BaseMapperX<SysUserRoleDO> {
|
||||
|
||||
default List<SysUserRoleDO> selectListByRoleIds(Collection<Long> roleIds) {
|
||||
return selectList(SysUserRoleDO::getRoleId, roleIds);
|
||||
}
|
||||
|
||||
}
|
@@ -1,13 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.dal.mysql.sms;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms.SysSmsLogDO;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface SysSmsLogCoreMapper extends BaseMapperX<SysSmsLogDO> {
|
||||
}
|
@@ -1,16 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.dal.mysql.sms;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Mapper
|
||||
public interface SysSmsTemplateCoreMapper extends BaseMapperX<SysSmsTemplateDO> {
|
||||
|
||||
@Select("SELECT id FROM sys_sms_template WHERE update_time > #{maxUpdateTime} LIMIT 1")
|
||||
Long selectExistsByUpdateTimeAfter(Date maxUpdateTime);
|
||||
|
||||
}
|
@@ -1,28 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.dal.mysql.social;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.social.SysSocialUserDO;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface SysSocialUserCoreMapper extends BaseMapperX<SysSocialUserDO> {
|
||||
|
||||
default List<SysSocialUserDO> selectListByTypeAndUnionId(Integer userType, Collection<Integer> types, String unionId) {
|
||||
return selectList(new QueryWrapper<SysSocialUserDO>().eq("user_type", userType)
|
||||
.in("type", types).eq("union_id", unionId));
|
||||
}
|
||||
|
||||
default List<SysSocialUserDO> selectListByTypeAndUserId(Integer userType, Collection<Integer> types, Long userId) {
|
||||
return selectList(new QueryWrapper<SysSocialUserDO>().eq("user_type", userType)
|
||||
.in("type", types).eq("user_id", userId));
|
||||
}
|
||||
|
||||
default List<SysSocialUserDO> selectListByUserId(Integer userType, Long userId) {
|
||||
return selectList(new QueryWrapper<SysSocialUserDO>().eq("user_type", userType).eq("user_id", userId));
|
||||
}
|
||||
|
||||
}
|
@@ -1,9 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.dal.mysql.tenant;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.tenant.SysTenantDO;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface SysTenantCoreMapper extends BaseMapperX<SysTenantDO> {
|
||||
}
|
@@ -1,17 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.dal.mysql.user;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface SysUserCoreMapper extends BaseMapperX<SysUserDO> {
|
||||
|
||||
default List<SysUserDO> selectListByDeptIds(Collection<Long> deptIds) {
|
||||
return selectList(SysUserDO::getDeptId, deptIds);
|
||||
}
|
||||
}
|
@@ -1,29 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.dal.redis;
|
||||
|
||||
import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine;
|
||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.STRING;
|
||||
|
||||
/**
|
||||
* System Redis Key 枚举类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface SysRedisKeyCoreConstants {
|
||||
|
||||
RedisKeyDefine LOGIN_USER = new RedisKeyDefine("登录用户的缓存",
|
||||
"login_user:%s", // 参数为 sessionId
|
||||
STRING, LoginUser.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC);
|
||||
|
||||
RedisKeyDefine SOCIAL_AUTH_USER = new RedisKeyDefine("社交登陆的授权用户",
|
||||
"social_auth_user:%d:%s", // 参数为 type,code
|
||||
STRING, AuthUser.class, Duration.ofDays(1));
|
||||
|
||||
RedisKeyDefine SOCIAL_AUTH_STATE = new RedisKeyDefine("社交登陆的 state",
|
||||
"social_auth_state:%s", // 参数为 state
|
||||
STRING, String.class, Duration.ofHours(24)); // 值为 state
|
||||
}
|
@@ -1,47 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.dal.redis.auth;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||
import cn.iocoder.yudao.framework.security.config.SecurityProperties;
|
||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import static cn.iocoder.yudao.coreservice.modules.system.dal.redis.SysRedisKeyCoreConstants.LOGIN_USER;
|
||||
|
||||
/**
|
||||
* {@link LoginUser} 的 RedisDAO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Repository
|
||||
public class SysLoginUserCoreRedisDAO {
|
||||
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
@Resource
|
||||
private SecurityProperties securityProperties;
|
||||
|
||||
public LoginUser get(String sessionId) {
|
||||
String redisKey = formatKey(sessionId);
|
||||
return JsonUtils.parseObject(stringRedisTemplate.opsForValue().get(redisKey), LoginUser.class);
|
||||
}
|
||||
|
||||
public void set(String sessionId, LoginUser loginUser) {
|
||||
String redisKey = formatKey(sessionId);
|
||||
stringRedisTemplate.opsForValue().set(redisKey, JsonUtils.toJsonString(loginUser),
|
||||
securityProperties.getSessionTimeout());
|
||||
}
|
||||
|
||||
public void delete(String sessionId) {
|
||||
String redisKey = formatKey(sessionId);
|
||||
stringRedisTemplate.delete(redisKey);
|
||||
}
|
||||
|
||||
private static String formatKey(String sessionId) {
|
||||
return String.format(LOGIN_USER.getKeyTemplate(), sessionId);
|
||||
}
|
||||
|
||||
}
|
@@ -1,38 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.dal.redis.social;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import static cn.iocoder.yudao.coreservice.modules.system.dal.redis.SysRedisKeyCoreConstants.SOCIAL_AUTH_USER;
|
||||
|
||||
/**
|
||||
* 社交 {@link me.zhyd.oauth.model.AuthUser} 的 RedisDAO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Repository
|
||||
public class SysSocialAuthUserRedisDAO {
|
||||
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
public AuthUser get(Integer type, AuthCallback authCallback) {
|
||||
String redisKey = formatKey(type, authCallback.getCode());
|
||||
return JsonUtils.parseObject(stringRedisTemplate.opsForValue().get(redisKey), AuthUser.class);
|
||||
}
|
||||
|
||||
public void set(Integer type, AuthCallback authCallback, AuthUser authUser) {
|
||||
String redisKey = formatKey(type, authCallback.getCode());
|
||||
stringRedisTemplate.opsForValue().set(redisKey, JsonUtils.toJsonString(authUser), SOCIAL_AUTH_USER.getTimeout());
|
||||
}
|
||||
|
||||
private static String formatKey(Integer type, String code) {
|
||||
return String.format(SOCIAL_AUTH_USER.getKeyTemplate(), type, code);
|
||||
}
|
||||
|
||||
}
|
@@ -1,53 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.enums;
|
||||
|
||||
/**
|
||||
* System 字典类型的枚举类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface SysDictTypeConstants {
|
||||
|
||||
String USER_TYPE = "user_type"; // 用户类型
|
||||
String COMMON_STATUS = "sys_common_status"; // 系统状态
|
||||
|
||||
String USER_SEX = "sys_user_sex"; // 用户性别
|
||||
String OPERATE_TYPE = "sys_operate_type"; // 操作类型
|
||||
String LOGIN_TYPE = "sys_login_type"; // 登录日志的类型
|
||||
String LOGIN_RESULT = "sys_login_result"; // 登录结果
|
||||
String CONFIG_TYPE = "sys_config_type"; // 参数配置类型
|
||||
String BOOLEAN_STRING = "sys_boolean_string"; // Boolean 是否类型
|
||||
|
||||
String SMS_CHANNEL_CODE = "sys_sms_channel_code"; // 短信渠道编码
|
||||
String SMS_TEMPLATE_TYPE = "sys_sms_template_type"; // 短信模板类型
|
||||
String SMS_SEND_STATUS = "sys_sms_send_status"; // 短信发送状态
|
||||
String SMS_RECEIVE_STATUS = "sys_sms_receive_status"; // 短信接收状态
|
||||
|
||||
/**
|
||||
* 支付-订单-订单状态
|
||||
*/
|
||||
String PAY_ORDER_STATUS = "pay_order_status";
|
||||
|
||||
/**
|
||||
* 支付-订单-订单回调商户状态
|
||||
*/
|
||||
String PAY_ORDER_NOTIFY_STATUS = "pay_order_notify_status";
|
||||
|
||||
/**
|
||||
* 支付-订单-订单退款状态
|
||||
*/
|
||||
String PAY_ORDER_REFUND_STATUS = "pay_order_refund_status";
|
||||
|
||||
/**
|
||||
* 支付-退款订单-退款状态
|
||||
*/
|
||||
String PAY_REFUND_ORDER_STATUS = "pay_refund_order_status";
|
||||
|
||||
/**
|
||||
* 支付-退款订单-退款类别
|
||||
*/
|
||||
String PAY_REFUND_ORDER_TYPE = "pay_refund_order_type";
|
||||
|
||||
String BPM_TASK_ASSIGN_RULE_TYPE = "bpm_task_assign_rule_type"; // 任务分配规则类型
|
||||
String BPM_TASK_ASSIGN_SCRIPT = "bpm_task_assign_script"; // 任务分配自定义脚本
|
||||
|
||||
}
|
@@ -1,45 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.enums;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
|
||||
|
||||
/**
|
||||
* System 错误码枚举类
|
||||
*
|
||||
* system 系统,使用 1-006-000-000 段
|
||||
*/
|
||||
public interface SysErrorCodeConstants {
|
||||
|
||||
// ========== 短信发送 1006000000 ==========
|
||||
ErrorCode SMS_SEND_MOBILE_NOT_EXISTS = new ErrorCode(1006000000, "手机号不存在");
|
||||
ErrorCode SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS = new ErrorCode(1006000001, "模板参数({})缺失");
|
||||
ErrorCode SMS_SEND_TEMPLATE_NOT_EXISTS = new ErrorCode(1006000000, "短信模板不存在");
|
||||
|
||||
// ========= 文件相关 1006001000=================
|
||||
ErrorCode FILE_PATH_EXISTS = new ErrorCode(1006001000, "文件路径已存在");
|
||||
ErrorCode FILE_NOT_EXISTS = new ErrorCode(1006001002, "文件不存在");
|
||||
|
||||
// ========== 社交模块 1006002000 ==========
|
||||
ErrorCode SOCIAL_AUTH_FAILURE = new ErrorCode(1006002000, "社交授权失败,原因是:{}");
|
||||
ErrorCode SOCIAL_UNBIND_NOT_SELF = new ErrorCode(1006002001, "社交解绑失败,非当前用户绑定");
|
||||
|
||||
// ========== 用户模块 1006003000 ==========
|
||||
ErrorCode USER_NOT_EXISTS = new ErrorCode(1006003000, "用户不存在");
|
||||
ErrorCode USER_IS_DISABLE = new ErrorCode(1006003001, "名字为【{}】的用户已被禁用");
|
||||
|
||||
// ========== 部门模块 1006004000 ==========
|
||||
ErrorCode DEPT_NOT_FOUND = new ErrorCode(1006004000, "当前部门不存在");
|
||||
ErrorCode DEPT_NOT_ENABLE = new ErrorCode(1006004001, "部门不处于开启状态,不允许选择");
|
||||
|
||||
// ========== 角色模块 1006005000 ==========
|
||||
ErrorCode ROLE_NOT_EXISTS = new ErrorCode(1006005000, "角色不存在");
|
||||
ErrorCode ROLE_IS_DISABLE = new ErrorCode(1006005001, "名字为【{}】的角色已被禁用");
|
||||
|
||||
// ========== 字典类型 1006006000 ==========
|
||||
ErrorCode DICT_DATA_NOT_EXISTS = new ErrorCode(1006006000, "当前字典数据不存在");
|
||||
ErrorCode DICT_DATA_NOT_ENABLE = new ErrorCode(1006006001, "字典数据({})不处于开启状态,不允许选择");
|
||||
|
||||
// ========== 岗位模块 1006007000 ==========
|
||||
ErrorCode POST_NOT_FOUND = new ErrorCode(1006007000, "当前岗位不存在");
|
||||
ErrorCode POST_NOT_ENABLE = new ErrorCode(1006007001, "岗位({}) 不处于开启状态,不允许选择");
|
||||
|
||||
}
|
@@ -1,27 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.enums.common;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 性别的枚举值
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum SysSexEnum {
|
||||
|
||||
/** 男 */
|
||||
MALE(1),
|
||||
/** 女 */
|
||||
FEMALE(2),
|
||||
/* 未知 */
|
||||
UNKNOWN(3);
|
||||
|
||||
/**
|
||||
* 性别
|
||||
*/
|
||||
private final Integer sex;
|
||||
|
||||
}
|
@@ -1,29 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.enums.logger;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 登录日志的类型枚举
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum SysLoginLogTypeEnum {
|
||||
|
||||
LOGIN_USERNAME(100), // 使用账号登录
|
||||
LOGIN_SOCIAL(101), // 使用社交登录
|
||||
LOGIN_MOCK(102), // 使用 Mock 登录
|
||||
LOGIN_MOBILE(103), // 使用手机登陆
|
||||
LOGIN_SMS(104), // 使用短信登陆
|
||||
|
||||
LOGOUT_SELF(200), // 自己主动登出
|
||||
LOGOUT_TIMEOUT(201), // 超时登出
|
||||
LOGOUT_DELETE(202), // 强制退出
|
||||
;
|
||||
|
||||
/**
|
||||
* 日志类型
|
||||
*/
|
||||
private final Integer type;
|
||||
|
||||
}
|
@@ -1,27 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.enums.logger;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 登录结果的枚举类
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum SysLoginResultEnum {
|
||||
|
||||
SUCCESS(0), // 成功
|
||||
BAD_CREDENTIALS(10), // 账号或密码不正确
|
||||
USER_DISABLED(20), // 用户被禁用
|
||||
CAPTCHA_NOT_FOUND(30), // 图片验证码不存在
|
||||
CAPTCHA_CODE_ERROR(31), // 图片验证码不正确
|
||||
|
||||
UNKNOWN_ERROR(100), // 未知异常
|
||||
;
|
||||
|
||||
/**
|
||||
* 结果
|
||||
*/
|
||||
private final Integer result;
|
||||
|
||||
}
|
@@ -1,23 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.enums.sms;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 短信的接收状态枚举
|
||||
*
|
||||
* @author 芋道源码
|
||||
* @date 2021/2/1 13:39
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum SysSmsReceiveStatusEnum {
|
||||
|
||||
INIT(0), // 初始化
|
||||
SUCCESS(10), // 接收成功
|
||||
FAILURE(20), // 接收失败
|
||||
;
|
||||
|
||||
private final int status;
|
||||
|
||||
}
|
@@ -1,24 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.enums.sms;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 短信的发送状态枚举
|
||||
*
|
||||
* @author zzf
|
||||
* @date 2021/2/1 13:39
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum SysSmsSendStatusEnum {
|
||||
|
||||
INIT(0), // 初始化
|
||||
SUCCESS(10), // 发送成功
|
||||
FAILURE(20), // 发送失败
|
||||
IGNORE(30), // 忽略,即不发送
|
||||
;
|
||||
|
||||
private final int status;
|
||||
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.enums.sms;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 短信的模板类型枚举
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum SysSmsTemplateTypeEnum {
|
||||
|
||||
VERIFICATION_CODE(1), // 验证码
|
||||
NOTICE(2), // 通知
|
||||
PROMOTION(3), // 营销
|
||||
;
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private final int type;
|
||||
|
||||
}
|
@@ -1,84 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.enums.social;
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 社交平台的类型枚举
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum SysSocialTypeEnum implements IntArrayValuable {
|
||||
|
||||
/**
|
||||
* Gitee
|
||||
* 文档链接:https://gitee.com/api/v5/oauth_doc#/
|
||||
*/
|
||||
GITEE(10, "GITEE"),
|
||||
/**
|
||||
* 钉钉
|
||||
* 文档链接:https://developers.dingtalk.com/document/app/obtain-identity-credentials
|
||||
*/
|
||||
DINGTALK(20, "DINGTALK"),
|
||||
|
||||
/**
|
||||
* 企业微信
|
||||
* 文档链接:https://xkcoding.com/2019/08/06/use-justauth-integration-wechat-enterprise.html
|
||||
*/
|
||||
WECHAT_ENTERPRISE(30, "WECHAT_ENTERPRISE"),
|
||||
/**
|
||||
* 微信公众平台 - 移动端 H5
|
||||
* 文档链接:https://www.cnblogs.com/juewuzhe/p/11905461.html
|
||||
*/
|
||||
WECHAT_MP(31, "WECHAT_MP"),
|
||||
/**
|
||||
* 微信开放平台 - 网站应用 PC 端扫码授权登录
|
||||
* 文档链接:https://justauth.wiki/guide/oauth/wechat_open/#_2-申请开发者资质认证
|
||||
*/
|
||||
WECHAT_OPEN(32, "WECHAT_OPEN"),
|
||||
/**
|
||||
* 微信小程序
|
||||
* 文档链接:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html
|
||||
*/
|
||||
WECHAT_MINI_PROGRAM(33, "WECHAT_MINI_PROGRAM"),
|
||||
;
|
||||
|
||||
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(SysSocialTypeEnum::getType).toArray();
|
||||
|
||||
public static final List<Integer> WECHAT_ALL = ListUtil.toList(WECHAT_ENTERPRISE.type, WECHAT_MP.type, WECHAT_OPEN.type,
|
||||
WECHAT_MINI_PROGRAM.type);
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private final Integer type;
|
||||
/**
|
||||
* 类型的标识
|
||||
*/
|
||||
private final String source;
|
||||
|
||||
@Override
|
||||
public int[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
|
||||
public static SysSocialTypeEnum valueOfType(Integer type) {
|
||||
return ArrayUtil.firstMatch(o -> o.getType().equals(type), values());
|
||||
}
|
||||
|
||||
public static List<Integer> getRelationTypes(Integer type) {
|
||||
if (WECHAT_ALL.contains(type)) {
|
||||
return WECHAT_ALL;
|
||||
}
|
||||
return ListUtil.toList(type);
|
||||
}
|
||||
|
||||
}
|
@@ -1,4 +0,0 @@
|
||||
/**
|
||||
* 占位
|
||||
*/
|
||||
package cn.iocoder.yudao.coreservice.modules.system.mq.message;
|
@@ -1,50 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.mq.message.sms;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
||||
import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessage;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 短信发送消息
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class SysSmsSendMessage extends AbstractStreamMessage {
|
||||
|
||||
/**
|
||||
* 短信日志编号
|
||||
*/
|
||||
@NotNull(message = "短信日志编号不能为空")
|
||||
private Long logId;
|
||||
/**
|
||||
* 手机号
|
||||
*/
|
||||
@NotNull(message = "手机号不能为空")
|
||||
private String mobile;
|
||||
/**
|
||||
* 短信渠道编号
|
||||
*/
|
||||
@NotNull(message = "短信渠道编号不能为空")
|
||||
private Long channelId;
|
||||
/**
|
||||
* 短信 API 的模板编号
|
||||
*/
|
||||
@NotNull(message = "短信 API 的模板编号不能为空")
|
||||
private String apiTemplateId;
|
||||
/**
|
||||
* 短信模板参数
|
||||
*/
|
||||
private List<KeyValue<String, Object>> templateParams;
|
||||
|
||||
@Override
|
||||
public String getStreamKey() {
|
||||
return "system.sms.send";
|
||||
}
|
||||
|
||||
}
|
@@ -1,4 +0,0 @@
|
||||
/**
|
||||
* 占位
|
||||
*/
|
||||
package cn.iocoder.yudao.coreservice.modules.system.mq.producer;
|
@@ -1,41 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.mq.producer.sms;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.system.mq.message.sms.SysSmsSendMessage;
|
||||
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
||||
import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Sms 短信相关消息的 Core Producer
|
||||
*
|
||||
* @author zzf
|
||||
* @date 2021/3/9 16:35
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class SysSmsCoreProducer {
|
||||
|
||||
@Resource
|
||||
private RedisMQTemplate redisMQTemplate;
|
||||
|
||||
/**
|
||||
* 发送 {@link SysSmsSendMessage} 消息
|
||||
*
|
||||
* @param logId 短信日志编号
|
||||
* @param mobile 手机号
|
||||
* @param channelId 渠道编号
|
||||
* @param apiTemplateId 短信模板编号
|
||||
* @param templateParams 短信模板参数
|
||||
*/
|
||||
public void sendSmsSendMessage(Long logId, String mobile,
|
||||
Long channelId, String apiTemplateId, List<KeyValue<String, Object>> templateParams) {
|
||||
SysSmsSendMessage message = new SysSmsSendMessage().setLogId(logId).setMobile(mobile);
|
||||
message.setChannelId(channelId).setApiTemplateId(apiTemplateId).setTemplateParams(templateParams);
|
||||
redisMQTemplate.send(message);
|
||||
}
|
||||
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
/**
|
||||
* system 包下,我们放通用业务,支撑上层的核心业务。
|
||||
* 例如说:用户、部门、权限、数据字典等等
|
||||
*
|
||||
* 缩写:sys
|
||||
*/
|
||||
package cn.iocoder.yudao.coreservice.modules.system;
|
@@ -1,52 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.auth;
|
||||
|
||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
||||
|
||||
/**
|
||||
* 在线用户 Session Core Service 接口
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface SysUserSessionCoreService {
|
||||
|
||||
/**
|
||||
* 创建在线用户 Session
|
||||
*
|
||||
* @param loginUser 登录用户
|
||||
* @param userIp 用户 IP
|
||||
* @param userAgent 用户 UA
|
||||
* @return Session 编号
|
||||
*/
|
||||
String createUserSession(LoginUser loginUser, String userIp, String userAgent);
|
||||
|
||||
/**
|
||||
* 刷新在线用户 Session 的更新时间
|
||||
*
|
||||
* @param sessionId Session 编号
|
||||
* @param loginUser 登录用户
|
||||
*/
|
||||
void refreshUserSession(String sessionId, LoginUser loginUser);
|
||||
|
||||
/**
|
||||
* 删除在线用户 Session
|
||||
*
|
||||
* @param sessionId Session 编号
|
||||
*/
|
||||
void deleteUserSession(String sessionId);
|
||||
|
||||
/**
|
||||
* 获得 Session 编号对应的在线用户
|
||||
*
|
||||
* @param sessionId Session 编号
|
||||
* @return 在线用户
|
||||
*/
|
||||
LoginUser getLoginUser(String sessionId);
|
||||
|
||||
/**
|
||||
* 获得 Session 超时时间,单位:毫秒
|
||||
*
|
||||
* @return 超时时间
|
||||
*/
|
||||
Long getSessionTimeoutMillis();
|
||||
|
||||
}
|
@@ -1,93 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.auth.impl;
|
||||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.auth.SysUserSessionDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.auth.SysUserSessionCoreMapper;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.redis.auth.SysLoginUserCoreRedisDAO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.service.auth.SysUserSessionCoreService;
|
||||
import cn.iocoder.yudao.framework.security.config.SecurityProperties;
|
||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.Duration;
|
||||
import java.util.Date;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.addTime;
|
||||
|
||||
/**
|
||||
* 在线用户 Session Core Service 实现类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Service
|
||||
public class SysUserSessionCoreServiceImpl implements SysUserSessionCoreService {
|
||||
|
||||
@Resource
|
||||
private SysUserSessionCoreMapper userSessionCoreMapper;
|
||||
|
||||
@Resource
|
||||
private SysLoginUserCoreRedisDAO loginUserCoreRedisDAO;
|
||||
|
||||
@Resource
|
||||
private SecurityProperties securityProperties;
|
||||
|
||||
@Override
|
||||
public String createUserSession(LoginUser loginUser, String userIp, String userAgent) {
|
||||
// 生成 Session 编号
|
||||
String sessionId = generateSessionId();
|
||||
// 写入 Redis 缓存
|
||||
loginUser.setUpdateTime(new Date());
|
||||
loginUserCoreRedisDAO.set(sessionId, loginUser);
|
||||
// 写入 DB 中
|
||||
SysUserSessionDO userSession = SysUserSessionDO.builder().id(sessionId)
|
||||
.userId(loginUser.getId()).userType(loginUser.getUserType())
|
||||
.userIp(userIp).userAgent(userAgent).username(loginUser.getUsername())
|
||||
.sessionTimeout(addTime(Duration.ofMillis(getSessionTimeoutMillis())))
|
||||
.build();
|
||||
userSessionCoreMapper.insert(userSession);
|
||||
// 返回 Session 编号
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshUserSession(String sessionId, LoginUser loginUser) {
|
||||
// 写入 Redis 缓存
|
||||
loginUser.setUpdateTime(new Date());
|
||||
loginUserCoreRedisDAO.set(sessionId, loginUser);
|
||||
// 更新 DB 中
|
||||
SysUserSessionDO updateObj = SysUserSessionDO.builder().id(sessionId).build();
|
||||
updateObj.setUsername(loginUser.getUsername());
|
||||
updateObj.setUpdateTime(new Date());
|
||||
updateObj.setSessionTimeout(addTime(Duration.ofMillis(getSessionTimeoutMillis())));
|
||||
userSessionCoreMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteUserSession(String sessionId) {
|
||||
// 删除 Redis 缓存
|
||||
loginUserCoreRedisDAO.delete(sessionId);
|
||||
// 删除 DB 记录
|
||||
userSessionCoreMapper.deleteById(sessionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoginUser getLoginUser(String sessionId) {
|
||||
return loginUserCoreRedisDAO.get(sessionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getSessionTimeoutMillis() {
|
||||
return securityProperties.getSessionTimeout().toMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 Session 编号,目前采用 UUID 算法
|
||||
*
|
||||
* @return Session 编号
|
||||
*/
|
||||
private static String generateSessionId() {
|
||||
return IdUtil.fastSimpleUUID();
|
||||
}
|
||||
|
||||
}
|
@@ -1,59 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.dept;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.dept.SysDeptDO;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface SysDeptCoreService {
|
||||
/**
|
||||
* 获得部门信息数组
|
||||
*
|
||||
* @param ids 部门编号数组
|
||||
* @return 部门信息数组
|
||||
*/
|
||||
List<SysDeptDO> getDepts(Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* 获得部门信息
|
||||
*
|
||||
* @param id 部门编号
|
||||
* @return 部门信息
|
||||
*/
|
||||
SysDeptDO getDept(Long id);
|
||||
|
||||
/**
|
||||
* 校验部门们是否有效。如下情况,视为无效:
|
||||
* 1. 部门编号不存在
|
||||
* 2. 部门被禁用
|
||||
*
|
||||
* @param ids 角色编号数组
|
||||
*/
|
||||
void validDepts(Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* 获得指定编号的部门列表
|
||||
*
|
||||
* @param ids 部门编号数组
|
||||
* @return 部门列表
|
||||
*/
|
||||
List<SysDeptDO> getSimpleDepts(Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* 获得指定编号的部门 Map
|
||||
*
|
||||
* @param ids 部门编号数组
|
||||
* @return 部门 Map
|
||||
*/
|
||||
default Map<Long, SysDeptDO> getDeptMap(Collection<Long> ids) {
|
||||
if (CollUtil.isEmpty(ids)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
List<SysDeptDO> list = getSimpleDepts(ids);
|
||||
return CollectionUtils.convertMap(list, SysDeptDO::getId);
|
||||
}
|
||||
}
|
@@ -1,19 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.dept;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* 岗位 Core Service 接口
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface SysPostCoreService {
|
||||
/**
|
||||
* 校验岗位们是否有效。如下情况,视为无效:
|
||||
* 1. 岗位编号不存在
|
||||
* 2. 岗位被禁用
|
||||
*
|
||||
* @param ids 岗位编号数组
|
||||
*/
|
||||
void validPosts(Collection<Long> ids);
|
||||
}
|
@@ -1,69 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.dept.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.dept.SysDeptDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.dept.SysDeptCoreMapper;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.service.dept.SysDeptCoreService;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.coreservice.modules.system.enums.SysErrorCodeConstants.DEPT_NOT_ENABLE;
|
||||
import static cn.iocoder.yudao.coreservice.modules.system.enums.SysErrorCodeConstants.DEPT_NOT_FOUND;
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
|
||||
/**
|
||||
* 部门 Core Service 实现类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class SysDeptCoreServiceImpl implements SysDeptCoreService {
|
||||
|
||||
@Resource
|
||||
private SysDeptCoreMapper deptCoreMapper;
|
||||
|
||||
@Override
|
||||
public List<SysDeptDO> getDepts(Collection<Long> ids) {
|
||||
return deptCoreMapper.selectBatchIds(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SysDeptDO getDept(Long id) {
|
||||
return deptCoreMapper.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validDepts(Collection<Long> ids) {
|
||||
if (CollUtil.isEmpty(ids)) {
|
||||
return;
|
||||
}
|
||||
// 获得科室信息
|
||||
List<SysDeptDO> depts = deptCoreMapper.selectBatchIds(ids);
|
||||
Map<Long, SysDeptDO> deptMap = CollectionUtils.convertMap(depts, SysDeptDO::getId);
|
||||
// 校验
|
||||
ids.forEach(id -> {
|
||||
SysDeptDO dept = deptMap.get(id);
|
||||
if (dept == null) {
|
||||
throw exception(DEPT_NOT_FOUND);
|
||||
}
|
||||
if (!CommonStatusEnum.ENABLE.getStatus().equals(dept.getStatus())) {
|
||||
throw exception(DEPT_NOT_ENABLE, dept.getName());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SysDeptDO> getSimpleDepts(Collection<Long> ids) {
|
||||
return deptCoreMapper.selectBatchIds(ids);
|
||||
}
|
||||
|
||||
}
|
@@ -1,50 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.dept.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.dept.SysPostDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.dept.SysPostCoreMapper;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.service.dept.SysPostCoreService;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.coreservice.modules.system.enums.SysErrorCodeConstants.POST_NOT_ENABLE;
|
||||
import static cn.iocoder.yudao.coreservice.modules.system.enums.SysErrorCodeConstants.POST_NOT_FOUND;
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
|
||||
/**
|
||||
* 岗位 Core Service 实现类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Service
|
||||
public class SysPostCoreServiceImpl implements SysPostCoreService {
|
||||
|
||||
@Resource
|
||||
private SysPostCoreMapper sysPostCoreMapper;
|
||||
|
||||
@Override
|
||||
public void validPosts(Collection<Long> ids) {
|
||||
if (CollUtil.isEmpty(ids)) {
|
||||
return;
|
||||
}
|
||||
// 获得岗位信息
|
||||
List<SysPostDO> posts = sysPostCoreMapper.selectBatchIds(ids);
|
||||
Map<Long, SysPostDO> postMap = CollectionUtils.convertMap(posts, SysPostDO::getId);
|
||||
// 校验
|
||||
ids.forEach(id -> {
|
||||
SysPostDO post = postMap.get(id);
|
||||
if (post == null) {
|
||||
throw exception(POST_NOT_FOUND);
|
||||
}
|
||||
if (!CommonStatusEnum.ENABLE.getStatus().equals(post.getStatus())) {
|
||||
throw exception(POST_NOT_ENABLE, post.getName());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@@ -1,29 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.dict;
|
||||
|
||||
import cn.iocoder.yudao.framework.dict.core.service.DictDataFrameworkService;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* 字典数据 Service 接口
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface SysDictDataCoreService extends DictDataFrameworkService {
|
||||
|
||||
/**
|
||||
* 初始化字典数据的本地缓存
|
||||
*/
|
||||
void initLocalCache();
|
||||
|
||||
/**
|
||||
* 校验字典数据们是否有效。如下情况,视为无效:
|
||||
* 1. 字典数据不存在
|
||||
* 2. 字典数据被禁用
|
||||
*
|
||||
* @param dictType 字典类型
|
||||
* @param values 字典数据值的数组
|
||||
*/
|
||||
void validDictDatas(String dictType, Collection<String> values);
|
||||
|
||||
}
|
@@ -1,145 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.dict.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.convert.dict.SysDictDataCoreConvert;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.dict.SysDictDataDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.dict.SysDictDataCoreMapper;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.service.dict.SysDictDataCoreService;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import cn.iocoder.yudao.framework.dict.core.dto.DictDataRespDTO;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableTable;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.Resource;
|
||||
import java.util.*;
|
||||
|
||||
import static cn.iocoder.yudao.coreservice.modules.system.enums.SysErrorCodeConstants.DICT_DATA_NOT_ENABLE;
|
||||
import static cn.iocoder.yudao.coreservice.modules.system.enums.SysErrorCodeConstants.DICT_DATA_NOT_EXISTS;
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
|
||||
/**
|
||||
* 字典数据 Service 实现类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class SysDictDataCoreServiceImpl implements SysDictDataCoreService {
|
||||
|
||||
/**
|
||||
* 定时执行 {@link #schedulePeriodicRefresh()} 的周期
|
||||
* 因为已经通过 Redis Pub/Sub 机制,所以频率不需要高
|
||||
*/
|
||||
private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L;
|
||||
|
||||
/**
|
||||
* 字典数据缓存,第二个 key 使用 label
|
||||
*
|
||||
* key1:字典类型 dictType
|
||||
* key2:字典标签 label
|
||||
*/
|
||||
private ImmutableTable<String, String, SysDictDataDO> labelDictDataCache;
|
||||
/**
|
||||
* 字典数据缓存,第二个 key 使用 value
|
||||
*
|
||||
* key1:字典类型 dictType
|
||||
* key2:字典值 value
|
||||
*/
|
||||
private ImmutableTable<String, String, SysDictDataDO> valueDictDataCache;
|
||||
/**
|
||||
* 缓存字典数据的最大更新时间,用于后续的增量轮询,判断是否有更新
|
||||
*/
|
||||
private volatile Date maxUpdateTime;
|
||||
|
||||
@Resource
|
||||
private SysDictDataCoreMapper dictDataCoreMapper;
|
||||
|
||||
@Override
|
||||
@PostConstruct
|
||||
public synchronized void initLocalCache() {
|
||||
// 获取字典数据列表,如果有更新
|
||||
List<SysDictDataDO> dataList = this.loadDictDataIfUpdate(maxUpdateTime);
|
||||
if (CollUtil.isEmpty(dataList)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 构建缓存
|
||||
ImmutableTable.Builder<String, String, SysDictDataDO> labelDictDataBuilder = ImmutableTable.builder();
|
||||
ImmutableTable.Builder<String, String, SysDictDataDO> valueDictDataBuilder = ImmutableTable.builder();
|
||||
dataList.forEach(dictData -> {
|
||||
labelDictDataBuilder.put(dictData.getDictType(), dictData.getLabel(), dictData);
|
||||
valueDictDataBuilder.put(dictData.getDictType(), dictData.getValue(), dictData);
|
||||
});
|
||||
labelDictDataCache = labelDictDataBuilder.build();
|
||||
valueDictDataCache = valueDictDataBuilder.build();
|
||||
assert dataList.size() > 0; // 断言,避免告警
|
||||
maxUpdateTime = dataList.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime();
|
||||
log.info("[initLocalCache][缓存字典数据,数量为:{}]", dataList.size());
|
||||
}
|
||||
|
||||
@Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
|
||||
public void schedulePeriodicRefresh() {
|
||||
initLocalCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果字典数据发生变化,从数据库中获取最新的全量字典数据。
|
||||
* 如果未发生变化,则返回空
|
||||
*
|
||||
* @param maxUpdateTime 当前字典数据的最大更新时间
|
||||
* @return 字典数据列表
|
||||
*/
|
||||
private List<SysDictDataDO> loadDictDataIfUpdate(Date maxUpdateTime) {
|
||||
// 第一步,判断是否要更新。
|
||||
if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据
|
||||
log.info("[loadDictDataIfUpdate][首次加载全量字典数据]");
|
||||
} else { // 判断数据库中是否有更新的字典数据
|
||||
if (!dictDataCoreMapper.selectExistsByUpdateTimeAfter(maxUpdateTime)) {
|
||||
return null;
|
||||
}
|
||||
log.info("[loadDictDataIfUpdate][增量加载全量字典数据]");
|
||||
}
|
||||
// 第二步,如果有更新,则从数据库加载所有字典数据
|
||||
return dictDataCoreMapper.selectList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DictDataRespDTO getDictDataFromCache(String type, String value) {
|
||||
return SysDictDataCoreConvert.INSTANCE.convert02(valueDictDataCache.get(type, value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DictDataRespDTO parseDictDataFromCache(String type, String label) {
|
||||
return SysDictDataCoreConvert.INSTANCE.convert02(labelDictDataCache.get(type, label));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DictDataRespDTO> listDictDatasFromCache(String type) {
|
||||
return SysDictDataCoreConvert.INSTANCE.convertList03(labelDictDataCache.row(type).values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validDictDatas(String dictType, Collection<String> values) {
|
||||
if (CollUtil.isEmpty(values)) {
|
||||
return;
|
||||
}
|
||||
ImmutableMap<String, SysDictDataDO> dictDataMap = valueDictDataCache.row(dictType);
|
||||
// 校验
|
||||
values.forEach(value -> {
|
||||
SysDictDataDO dictData = dictDataMap.get(value);
|
||||
if (dictData == null) {
|
||||
throw exception(DICT_DATA_NOT_EXISTS);
|
||||
}
|
||||
if (!CommonStatusEnum.ENABLE.getStatus().equals(dictData.getStatus())) {
|
||||
throw exception(DICT_DATA_NOT_ENABLE, dictData.getLabel());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@@ -1,17 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.logger;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.system.service.logger.dto.SysLoginLogCreateReqDTO;
|
||||
|
||||
/**
|
||||
* 登录日志 Core Service 接口
|
||||
*/
|
||||
public interface SysLoginLogCoreService {
|
||||
|
||||
/**
|
||||
* 创建登录日志
|
||||
*
|
||||
* @param reqDTO 日志信息
|
||||
*/
|
||||
void createLoginLog(SysLoginLogCreateReqDTO reqDTO);
|
||||
|
||||
}
|
@@ -1,62 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.logger.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
/**
|
||||
* 登录日志创建 Request DTO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class SysLoginLogCreateReqDTO {
|
||||
|
||||
/**
|
||||
* 日志类型
|
||||
*/
|
||||
@NotNull(message = "日志类型不能为空")
|
||||
private Integer logType;
|
||||
/**
|
||||
* 链路追踪编号
|
||||
*/
|
||||
@NotEmpty(message = "链路追踪编号不能为空")
|
||||
private String traceId;
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
private Long userId;
|
||||
/**
|
||||
* 用户类型
|
||||
*/
|
||||
@NotNull(message = "用户类型不能为空")
|
||||
private Integer userType;
|
||||
/**
|
||||
* 用户账号
|
||||
*/
|
||||
@NotBlank(message = "用户账号不能为空")
|
||||
@Size(max = 30, message = "用户账号长度不能超过30个字符")
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 登录结果
|
||||
*/
|
||||
@NotNull(message = "登录结果不能为空")
|
||||
private Integer result;
|
||||
|
||||
/**
|
||||
* 用户 IP
|
||||
*/
|
||||
@NotEmpty(message = "用户 IP 不能为空")
|
||||
private String userIp;
|
||||
/**
|
||||
* 浏览器 UserAgent
|
||||
*/
|
||||
@NotEmpty(message = "浏览器 UserAgent 不能为空")
|
||||
private String userAgent;
|
||||
|
||||
}
|
@@ -1,30 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.logger.impl;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.system.convert.logger.SysLoginLogCoreConvert;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.logger.SysLoginLogDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.logger.SysLoginLogCoreMapper;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.service.logger.SysLoginLogCoreService;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.service.logger.dto.SysLoginLogCreateReqDTO;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 登录日志 Service Core 实现
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Service
|
||||
public class SysLoginLogCoreServiceImpl implements SysLoginLogCoreService {
|
||||
|
||||
@Resource
|
||||
private SysLoginLogCoreMapper loginLogMapper;
|
||||
|
||||
@Override
|
||||
public void createLoginLog(SysLoginLogCreateReqDTO reqDTO) {
|
||||
SysLoginLogDO loginLog = SysLoginLogCoreConvert.INSTANCE.convert(reqDTO);
|
||||
// 插入
|
||||
loginLogMapper.insert(loginLog);
|
||||
}
|
||||
|
||||
}
|
@@ -1,20 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.permission;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
/**
|
||||
* 权限 Core Service 接口
|
||||
*
|
||||
* 提供用户-角色、角色-菜单、角色-部门的关联权限处理
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface SysPermissionCoreService {
|
||||
/**
|
||||
* 获得拥有多个角色的用户编号集合
|
||||
*
|
||||
* @param roleIds 角色编号集合
|
||||
* @return 用户编号集合
|
||||
*/
|
||||
Set<Long> getUserRoleIdListByRoleIds(Collection<Long> roleIds);
|
||||
}
|
@@ -1,19 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.permission;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* 角色 Core Service 接口
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface SysRoleCoreService {
|
||||
/**
|
||||
* 校验角色们是否有效。如下情况,视为无效:
|
||||
* 1. 角色编号不存在
|
||||
* 2. 角色被禁用
|
||||
*
|
||||
* @param ids 角色编号数组
|
||||
*/
|
||||
void validRoles(Collection<Long> ids);
|
||||
}
|
@@ -1,28 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.permission.impl;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.permission.SysUserRoleDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.permission.SysUserRoleCoreMapper;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.service.permission.SysPermissionCoreService;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
/**
|
||||
* 权限 Core Service 实现类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Service
|
||||
public class SysPermissionCoreServiceImpl implements SysPermissionCoreService {
|
||||
|
||||
@Resource
|
||||
private SysUserRoleCoreMapper userRoleCoreMapper;
|
||||
|
||||
@Override
|
||||
public Set<Long> getUserRoleIdListByRoleIds(Collection<Long> roleIds) {
|
||||
return CollectionUtils.convertSet(userRoleCoreMapper.selectListByRoleIds(roleIds),
|
||||
SysUserRoleDO::getRoleId);
|
||||
}
|
||||
}
|
@@ -1,50 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.permission.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.permission.SysRoleDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.permission.SysRoleCoreMapper;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.service.permission.SysRoleCoreService;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.coreservice.modules.system.enums.SysErrorCodeConstants.ROLE_IS_DISABLE;
|
||||
import static cn.iocoder.yudao.coreservice.modules.system.enums.SysErrorCodeConstants.ROLE_NOT_EXISTS;
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
|
||||
/**
|
||||
* 角色 Core Service 实现类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Service
|
||||
public class SysRoleCoreServiceImpl implements SysRoleCoreService {
|
||||
|
||||
@Resource
|
||||
private SysRoleCoreMapper sysRoleCoreMapper;
|
||||
|
||||
@Override
|
||||
public void validRoles(Collection<Long> ids) {
|
||||
if (CollUtil.isEmpty(ids)) {
|
||||
return;
|
||||
}
|
||||
// 获得角色信息
|
||||
List<SysRoleDO> roles = sysRoleCoreMapper.selectBatchIds(ids);
|
||||
Map<Long, SysRoleDO> roleMap = CollectionUtils.convertMap(roles, SysRoleDO::getId);
|
||||
// 校验
|
||||
ids.forEach(id -> {
|
||||
SysRoleDO role = roleMap.get(id);
|
||||
if (role == null) {
|
||||
throw exception(ROLE_NOT_EXISTS);
|
||||
}
|
||||
if (!CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())) {
|
||||
throw exception(ROLE_IS_DISABLE, role.getName());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@@ -1,63 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.sms;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.system.mq.message.sms.SysSmsSendMessage;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 短信 Service Core 接口
|
||||
*
|
||||
* 接入方,通过调用 send 开头的方法,创建发送短信的任务到 MQ 中
|
||||
* 后续,yudao-admin-server 监听 MQ,执行真正的短信发送逻辑
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface SysSmsCoreService {
|
||||
|
||||
/**
|
||||
* 发送单条短信给后台用户
|
||||
*
|
||||
* 在 mobile 为空时,使用 userId 加载对应管理员的手机号
|
||||
*
|
||||
* @param mobile 手机号
|
||||
* @param userId 用户编号
|
||||
* @param templateCode 短信模板编号
|
||||
* @param templateParams 短信模板参数
|
||||
* @return 发送日志编号
|
||||
*/
|
||||
Long sendSingleSmsToAdmin(String mobile, Long userId,
|
||||
String templateCode, Map<String, Object> templateParams);
|
||||
|
||||
/**
|
||||
* 发送单条短信给前台用户
|
||||
*
|
||||
* 在 mobile 为空时,使用 userId 加载对应会员的手机号
|
||||
*
|
||||
* @param mobile 手机号
|
||||
* @param userId 用户编号
|
||||
* @param templateCode 短信模板编号
|
||||
* @param templateParams 短信模板参数
|
||||
* @return 发送日志编号
|
||||
*/
|
||||
Long sendSingleSmsToMember(String mobile, Long userId,
|
||||
String templateCode, Map<String, Object> templateParams);
|
||||
|
||||
Long sendSingleSms(String mobile, Long userId, Integer userType,
|
||||
String templateCode, Map<String, Object> templateParams);
|
||||
|
||||
void sendBatchSms(List<String> mobiles, List<Long> userIds, Integer userType,
|
||||
String templateCode, Map<String, Object> templateParams);
|
||||
|
||||
void doSendSms(SysSmsSendMessage message);
|
||||
|
||||
/**
|
||||
* 接收短信的接收结果
|
||||
*
|
||||
* @param channelCode 渠道编码
|
||||
* @param text 结果内容
|
||||
* @throws Throwable 处理失败时,抛出异常
|
||||
*/
|
||||
void receiveSmsStatus(String channelCode, String text) throws Throwable;
|
||||
|
||||
}
|
@@ -1,56 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.sms;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 短信日志 Core Service 接口
|
||||
*
|
||||
* @author zzf
|
||||
* @date 13:48 2021/3/2
|
||||
*/
|
||||
public interface SysSmsLogCoreService {
|
||||
|
||||
/**
|
||||
* 创建短信日志
|
||||
*
|
||||
* @param mobile 手机号
|
||||
* @param userId 用户编号
|
||||
* @param userType 用户类型
|
||||
* @param isSend 是否发送
|
||||
* @param template 短信模板
|
||||
* @param templateContent 短信内容
|
||||
* @param templateParams 短信参数
|
||||
* @return 发送日志编号
|
||||
*/
|
||||
Long createSmsLog(String mobile, Long userId, Integer userType, Boolean isSend,
|
||||
SysSmsTemplateDO template, String templateContent, Map<String, Object> templateParams);
|
||||
|
||||
/**
|
||||
* 更新日志的发送结果
|
||||
*
|
||||
* @param id 日志编号
|
||||
* @param sendCode 发送结果的编码
|
||||
* @param sendMsg 发送结果的提示
|
||||
* @param apiSendCode 短信 API 发送结果的编码
|
||||
* @param apiSendMsg 短信 API 发送失败的提示
|
||||
* @param apiRequestId 短信 API 发送返回的唯一请求 ID
|
||||
* @param apiSerialNo 短信 API 发送返回的序号
|
||||
*/
|
||||
void updateSmsSendResult(Long id, Integer sendCode, String sendMsg,
|
||||
String apiSendCode, String apiSendMsg, String apiRequestId, String apiSerialNo);
|
||||
|
||||
/**
|
||||
* 更新日志的接收结果
|
||||
*
|
||||
* @param id 日志编号
|
||||
* @param success 是否接收成功
|
||||
* @param receiveTime 用户接收时间
|
||||
* @param apiReceiveCode API 接收结果的编码
|
||||
* @param apiReceiveMsg API 接收结果的说明
|
||||
*/
|
||||
void updateSmsReceiveResult(Long id, Boolean success, Date receiveTime, String apiReceiveCode, String apiReceiveMsg);
|
||||
|
||||
}
|
@@ -1,36 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.sms;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 短信模板 Core Service 接口
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface SysSmsTemplateCoreService {
|
||||
|
||||
/**
|
||||
* 初始化短信模板的本地缓存
|
||||
*/
|
||||
void initLocalCache();
|
||||
|
||||
/**
|
||||
* 获得短信模板,从缓存中
|
||||
*
|
||||
* @param code 模板编码
|
||||
* @return 短信模板
|
||||
*/
|
||||
SysSmsTemplateDO getSmsTemplateByCodeFromCache(String code);
|
||||
|
||||
/**
|
||||
* 格式化短信内容
|
||||
*
|
||||
* @param content 短信模板的内容
|
||||
* @param params 内容的参数
|
||||
* @return 格式化后的内容
|
||||
*/
|
||||
String formatSmsTemplateContent(String content, Map<String, Object> params);
|
||||
|
||||
}
|
@@ -1,178 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.sms.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.mq.message.sms.SysSmsSendMessage;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.mq.producer.sms.SysSmsCoreProducer;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.service.sms.SysSmsCoreService;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.service.sms.SysSmsLogCoreService;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.service.sms.SysSmsTemplateCoreService;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.service.user.SysUserCoreService;
|
||||
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.framework.sms.core.client.SmsClient;
|
||||
import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory;
|
||||
import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
|
||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
|
||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.yudao.coreservice.modules.system.enums.SysErrorCodeConstants.*;
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
|
||||
/**
|
||||
* 短信 Service Core 实现
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Service
|
||||
public class SysSmsCoreServiceImpl implements SysSmsCoreService {
|
||||
|
||||
@Resource
|
||||
private SysUserCoreService sysUserCoreService;
|
||||
@Resource
|
||||
private SysSmsTemplateCoreService smsTemplateCoreService;
|
||||
@Resource
|
||||
private SysSmsLogCoreService smsLogCoreService;
|
||||
|
||||
@Resource
|
||||
private SmsClientFactory smsClientFactory;
|
||||
|
||||
@Resource
|
||||
private SysSmsCoreProducer smsCoreProducer;
|
||||
|
||||
@Override
|
||||
public Long sendSingleSmsToAdmin(String mobile, Long userId, String templateCode, Map<String, Object> templateParams) {
|
||||
// 如果 mobile 为空,则加载用户编号对应的手机号
|
||||
if (StrUtil.isEmpty(mobile)) {
|
||||
SysUserDO user = sysUserCoreService.getUser(userId);
|
||||
if (user != null) {
|
||||
mobile = user.getMobile();
|
||||
}
|
||||
}
|
||||
// 执行发送
|
||||
return this.sendSingleSms(mobile, userId, UserTypeEnum.ADMIN.getValue(), templateCode, templateParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long sendSingleSmsToMember(String mobile, Long userId, String templateCode, Map<String, Object> templateParams) {
|
||||
// 如果 mobile 为空,则加载用户编号对应的手机号
|
||||
if (StrUtil.isEmpty(mobile)) {
|
||||
// MbrUserDO user = mbrUserCoreService.getUser(userId);
|
||||
// if (user != null) {
|
||||
// mobile = user.getMobile();
|
||||
// }
|
||||
// TODO 芋艿:重构
|
||||
}
|
||||
// 执行发送
|
||||
return this.sendSingleSms(mobile, userId, UserTypeEnum.MEMBER.getValue(), templateCode, templateParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long sendSingleSms(String mobile, Long userId, Integer userType,
|
||||
String templateCode, Map<String, Object> templateParams) {
|
||||
// 校验短信模板是否合法
|
||||
SysSmsTemplateDO template = this.checkSmsTemplateValid(templateCode);
|
||||
// 校验手机号码是否存在
|
||||
mobile = this.checkMobile(mobile);
|
||||
// 构建有序的模板参数。为什么放在这个位置,是提前保证模板参数的正确性,而不是到了插入发送日志
|
||||
List<KeyValue<String, Object>> newTemplateParams = this.buildTemplateParams(template, templateParams);
|
||||
|
||||
// 创建发送日志
|
||||
Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus()); // 如果模板被禁用,则不发送短信,只记录日志
|
||||
String content = smsTemplateCoreService.formatSmsTemplateContent(template.getContent(), templateParams);
|
||||
Long sendLogId = smsLogCoreService.createSmsLog(mobile, userId, userType, isSend, template, content, templateParams);
|
||||
|
||||
// 发送 MQ 消息,异步执行发送短信
|
||||
if (isSend) {
|
||||
smsCoreProducer.sendSmsSendMessage(sendLogId, mobile, template.getChannelId(),
|
||||
template.getApiTemplateId(), newTemplateParams);
|
||||
}
|
||||
return sendLogId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendBatchSms(List<String> mobiles, List<Long> userIds, Integer userType,
|
||||
String templateCode, Map<String, Object> templateParams) {
|
||||
throw new UnsupportedOperationException("暂时不支持该操作,感兴趣可以实现该功能哟!");
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public SysSmsTemplateDO checkSmsTemplateValid(String templateCode) {
|
||||
// 获得短信模板。考虑到效率,从缓存中获取
|
||||
SysSmsTemplateDO template = smsTemplateCoreService.getSmsTemplateByCodeFromCache(templateCode);
|
||||
// 短信模板不存在
|
||||
if (template == null) {
|
||||
throw exception(SMS_SEND_TEMPLATE_NOT_EXISTS);
|
||||
}
|
||||
return template;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将参数模板,处理成有序的 KeyValue 数组
|
||||
*
|
||||
* 原因是,部分短信平台并不是使用 key 作为参数,而是数组下标,例如说腾讯云 https://cloud.tencent.com/document/product/382/39023
|
||||
*
|
||||
* @param template 短信模板
|
||||
* @param templateParams 原始参数
|
||||
* @return 处理后的参数
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public List<KeyValue<String, Object>> buildTemplateParams(SysSmsTemplateDO template, Map<String, Object> templateParams) {
|
||||
return template.getParams().stream().map(key -> {
|
||||
Object value = templateParams.get(key);
|
||||
if (value == null) {
|
||||
throw exception(SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS, key);
|
||||
}
|
||||
return new KeyValue<>(key, value);
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public String checkMobile(String mobile) {
|
||||
if (StrUtil.isEmpty(mobile)) {
|
||||
throw exception(SMS_SEND_MOBILE_NOT_EXISTS);
|
||||
}
|
||||
return mobile;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void doSendSms(SysSmsSendMessage message) {
|
||||
// 获得渠道对应的 SmsClient 客户端
|
||||
SmsClient smsClient = smsClientFactory.getSmsClient(message.getChannelId());
|
||||
Assert.notNull(smsClient, String.format("短信客户端(%d) 不存在", message.getChannelId()));
|
||||
// 发送短信
|
||||
SmsCommonResult<SmsSendRespDTO> sendResult = smsClient.sendSms(message.getLogId(), message.getMobile(),
|
||||
message.getApiTemplateId(), message.getTemplateParams());
|
||||
smsLogCoreService.updateSmsSendResult(message.getLogId(), sendResult.getCode(), sendResult.getMsg(),
|
||||
sendResult.getApiCode(), sendResult.getApiMsg(), sendResult.getApiRequestId(),
|
||||
sendResult.getData() != null ? sendResult.getData().getSerialNo() : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveSmsStatus(String channelCode, String text) throws Throwable {
|
||||
// 获得渠道对应的 SmsClient 客户端
|
||||
SmsClient smsClient = smsClientFactory.getSmsClient(channelCode);
|
||||
Assert.notNull(smsClient, String.format("短信客户端(%s) 不存在", channelCode));
|
||||
// 解析内容
|
||||
List<SmsReceiveRespDTO> receiveResults = smsClient.parseSmsReceiveStatus(text);
|
||||
if (CollUtil.isEmpty(receiveResults)) {
|
||||
return;
|
||||
}
|
||||
// 更新短信日志的接收结果. 因为量一般不大,所以先使用 for 循环更新
|
||||
receiveResults.forEach(result -> smsLogCoreService.updateSmsReceiveResult(result.getLogId(),
|
||||
result.getSuccess(), result.getReceiveTime(), result.getErrorCode(), result.getErrorCode()));
|
||||
}
|
||||
|
||||
}
|
@@ -1,72 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.sms.impl;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms.SysSmsLogDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.sms.SysSmsLogCoreMapper;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.enums.sms.SysSmsReceiveStatusEnum;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.enums.sms.SysSmsSendStatusEnum;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.service.sms.SysSmsLogCoreService;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 短信日志 Core Service 实现类
|
||||
*
|
||||
* @author zzf
|
||||
* @date 2021/1/25 9:25
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class SysSmsLogCoreServiceImpl implements SysSmsLogCoreService {
|
||||
|
||||
@Resource
|
||||
private SysSmsLogCoreMapper smsLogCoreMapper;
|
||||
|
||||
@Override
|
||||
public Long createSmsLog(String mobile, Long userId, Integer userType, Boolean isSend,
|
||||
SysSmsTemplateDO template, String templateContent, Map<String, Object> templateParams) {
|
||||
SysSmsLogDO.SysSmsLogDOBuilder logBuilder = SysSmsLogDO.builder();
|
||||
// 根据是否要发送,设置状态
|
||||
logBuilder.sendStatus(Objects.equals(isSend, true) ? SysSmsSendStatusEnum.INIT.getStatus()
|
||||
: SysSmsSendStatusEnum.IGNORE.getStatus());
|
||||
// 设置手机相关字段
|
||||
logBuilder.mobile(mobile).userId(userId).userType(userType);
|
||||
// 设置模板相关字段
|
||||
logBuilder.templateId(template.getId()).templateCode(template.getCode()).templateType(template.getType());
|
||||
logBuilder.templateContent(templateContent).templateParams(templateParams).apiTemplateId(template.getApiTemplateId());
|
||||
// 设置渠道相关字段
|
||||
logBuilder.channelId(template.getChannelId()).channelCode(template.getChannelCode());
|
||||
// 设置接收相关字段
|
||||
logBuilder.receiveStatus(SysSmsReceiveStatusEnum.INIT.getStatus());
|
||||
|
||||
// 插入数据库
|
||||
SysSmsLogDO logDO = logBuilder.build();
|
||||
smsLogCoreMapper.insert(logDO);
|
||||
return logDO.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSmsSendResult(Long id, Integer sendCode, String sendMsg,
|
||||
String apiSendCode, String apiSendMsg, String apiRequestId, String apiSerialNo) {
|
||||
SysSmsSendStatusEnum sendStatus = CommonResult.isSuccess(sendCode) ? SysSmsSendStatusEnum.SUCCESS
|
||||
: SysSmsSendStatusEnum.FAILURE;
|
||||
smsLogCoreMapper.updateById(SysSmsLogDO.builder().id(id).sendStatus(sendStatus.getStatus()).sendTime(new Date())
|
||||
.sendCode(sendCode).sendMsg(sendMsg).apiSendCode(apiSendCode).apiSendMsg(apiSendMsg)
|
||||
.apiRequestId(apiRequestId).apiSerialNo(apiSerialNo).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSmsReceiveResult(Long id, Boolean success, Date receiveTime, String apiReceiveCode, String apiReceiveMsg) {
|
||||
SysSmsReceiveStatusEnum receiveStatus = Objects.equals(success, true) ? SysSmsReceiveStatusEnum.SUCCESS
|
||||
: SysSmsReceiveStatusEnum.FAILURE;
|
||||
smsLogCoreMapper.updateById(SysSmsLogDO.builder().id(id).receiveStatus(receiveStatus.getStatus()).receiveTime(receiveTime)
|
||||
.apiReceiveCode(apiReceiveCode).apiReceiveMsg(apiReceiveMsg).build());
|
||||
}
|
||||
|
||||
}
|
@@ -1,105 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.sms.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.sms.SysSmsTemplateCoreMapper;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.service.sms.SysSmsTemplateCoreService;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 短信模板 Core Service 接口
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class SysSmsTemplateCoreServiceImpl implements SysSmsTemplateCoreService {
|
||||
|
||||
/**
|
||||
* 定时执行 {@link #schedulePeriodicRefresh()} 的周期
|
||||
* 因为已经通过 Redis Pub/Sub 机制,所以频率不需要高
|
||||
*/
|
||||
private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L;
|
||||
|
||||
/**
|
||||
* 短信模板缓存
|
||||
* key:短信模板编码 {@link SysSmsTemplateDO#getCode()}
|
||||
*
|
||||
* 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向
|
||||
*/
|
||||
private volatile Map<String, SysSmsTemplateDO> smsTemplateCache;
|
||||
/**
|
||||
* 缓存短信模板的最大更新时间,用于后续的增量轮询,判断是否有更新
|
||||
*/
|
||||
private volatile Date maxUpdateTime;
|
||||
|
||||
@Resource
|
||||
private SysSmsTemplateCoreMapper smsTemplateCoreMapper;
|
||||
|
||||
@Override
|
||||
@PostConstruct
|
||||
public void initLocalCache() {
|
||||
// 获取短信模板列表,如果有更新
|
||||
List<SysSmsTemplateDO> smsTemplateList = this.loadSmsTemplateIfUpdate(maxUpdateTime);
|
||||
if (CollUtil.isEmpty(smsTemplateList)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 写入缓存
|
||||
ImmutableMap.Builder<String, SysSmsTemplateDO> builder = ImmutableMap.builder();
|
||||
smsTemplateList.forEach(sysSmsTemplateDO -> builder.put(sysSmsTemplateDO.getCode(), sysSmsTemplateDO));
|
||||
smsTemplateCache = builder.build();
|
||||
assert smsTemplateList.size() > 0; // 断言,避免告警
|
||||
maxUpdateTime = smsTemplateList.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime();
|
||||
log.info("[initLocalCache][初始化 SmsTemplate 数量为 {}]", smsTemplateList.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果短信模板发生变化,从数据库中获取最新的全量短信模板。
|
||||
* 如果未发生变化,则返回空
|
||||
*
|
||||
* @param maxUpdateTime 当前短信模板的最大更新时间
|
||||
* @return 短信模板列表
|
||||
*/
|
||||
private List<SysSmsTemplateDO> loadSmsTemplateIfUpdate(Date maxUpdateTime) {
|
||||
// 第一步,判断是否要更新。
|
||||
if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据
|
||||
log.info("[loadSmsTemplateIfUpdate][首次加载全量短信模板]");
|
||||
} else { // 判断数据库中是否有更新的短信模板
|
||||
if (smsTemplateCoreMapper.selectExistsByUpdateTimeAfter(maxUpdateTime) == null) {
|
||||
return null;
|
||||
}
|
||||
log.info("[loadSmsTemplateIfUpdate][增量加载全量短信模板]");
|
||||
}
|
||||
// 第二步,如果有更新,则从数据库加载所有短信模板
|
||||
return smsTemplateCoreMapper.selectList();
|
||||
}
|
||||
|
||||
@Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
|
||||
public void schedulePeriodicRefresh() {
|
||||
initLocalCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SysSmsTemplateDO getSmsTemplateByCodeFromCache(String code) {
|
||||
return smsTemplateCache.get(code);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String formatSmsTemplateContent(String content, Map<String, Object> params) {
|
||||
return StrUtil.format(content, params);
|
||||
}
|
||||
|
||||
}
|
@@ -1,85 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.social;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.social.SysSocialUserDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.enums.social.SysSocialTypeEnum;
|
||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 社交 Service 接口,例如说社交平台的授权登录
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface SysSocialCoreService {
|
||||
|
||||
/**
|
||||
* 获得社交平台的授权 URL
|
||||
*
|
||||
* @param type 社交平台的类型 {@link SysSocialTypeEnum}
|
||||
* @param redirectUri 重定向 URL
|
||||
* @return 社交平台的授权 URL
|
||||
*/
|
||||
String getAuthorizeUrl(Integer type, String redirectUri);
|
||||
|
||||
/**
|
||||
* 获得授权的用户
|
||||
* 如果授权失败,则会抛出 {@link ServiceException} 异常
|
||||
*
|
||||
* @param type 社交平台的类型 {@link SysSocialTypeEnum}
|
||||
* @param code 授权码
|
||||
* @param state state
|
||||
* @return 授权用户
|
||||
*/
|
||||
@NotNull
|
||||
AuthUser getAuthUser(Integer type, String code, String state);
|
||||
|
||||
default String getAuthUserUnionId(AuthUser authUser) {
|
||||
return StrUtil.blankToDefault(authUser.getToken().getUnionId(), authUser.getUuid());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得 unionId 对应的某个社交平台的“所有”社交用户
|
||||
* 注意,这里的“所有”,指的是类似【微信】平台,包括了小程序、公众号、PC 网站,他们的 unionId 是一致的
|
||||
*
|
||||
* @param type 社交平台的类型 {@link SysSocialTypeEnum}
|
||||
* @param unionId 社交平台的 unionId
|
||||
* @return 社交用户列表
|
||||
* @param userTypeEnum 全局用户类型
|
||||
*/
|
||||
List<SysSocialUserDO> getAllSocialUserList(Integer type, String unionId, UserTypeEnum userTypeEnum);
|
||||
|
||||
/**
|
||||
* 获得指定用户的社交用户列表
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @return 社交用户列表
|
||||
* @param userTypeEnum 全局用户类型
|
||||
*/
|
||||
List<SysSocialUserDO> getSocialUserList(Long userId, UserTypeEnum userTypeEnum);
|
||||
|
||||
/**
|
||||
* 绑定社交用户
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param type 社交平台的类型 {@link SysSocialTypeEnum}
|
||||
* @param authUser 授权用户
|
||||
* @param userTypeEnum 全局用户类型
|
||||
*/
|
||||
void bindSocialUser(Long userId, Integer type, AuthUser authUser, UserTypeEnum userTypeEnum);
|
||||
|
||||
/**
|
||||
* 取消绑定社交用户
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param type 社交平台的类型 {@link SysSocialTypeEnum}
|
||||
* @param unionId 社交平台的 unionId
|
||||
* @param userTypeEnum 全局用户类型
|
||||
*/
|
||||
void unbindSocialUser(Long userId, Integer type, String unionId, UserTypeEnum userTypeEnum);
|
||||
|
||||
}
|
@@ -1,178 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.social.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.social.SysSocialUserDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.social.SysSocialUserCoreMapper;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.redis.social.SysSocialAuthUserRedisDAO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.enums.social.SysSocialTypeEnum;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.service.social.SysSocialCoreService;
|
||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.xkcoding.justauth.AuthRequestFactory;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthResponse;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.request.AuthRequest;
|
||||
import me.zhyd.oauth.utils.AuthStateUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static cn.iocoder.yudao.coreservice.modules.system.enums.SysErrorCodeConstants.SOCIAL_AUTH_FAILURE;
|
||||
import static cn.iocoder.yudao.coreservice.modules.system.enums.SysErrorCodeConstants.SOCIAL_UNBIND_NOT_SELF;
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
|
||||
|
||||
/**
|
||||
* 社交 Service 实现类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
@Slf4j
|
||||
public class SysSocialCoreServiceImpl implements SysSocialCoreService {
|
||||
|
||||
@Resource
|
||||
private AuthRequestFactory authRequestFactory;
|
||||
|
||||
@Resource
|
||||
private SysSocialAuthUserRedisDAO authSocialUserRedisDAO;
|
||||
|
||||
@Resource
|
||||
private SysSocialUserCoreMapper socialUserMapper;
|
||||
|
||||
@Override
|
||||
public String getAuthorizeUrl(Integer type, String redirectUri) {
|
||||
// 获得对应的 AuthRequest 实现
|
||||
AuthRequest authRequest = authRequestFactory.get(SysSocialTypeEnum.valueOfType(type).getSource());
|
||||
// 生成跳转地址
|
||||
String authorizeUri = authRequest.authorize(AuthStateUtils.createState());
|
||||
return HttpUtils.replaceUrlQuery(authorizeUri, "redirect_uri", redirectUri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthUser getAuthUser(Integer type, String code, String state) {
|
||||
AuthCallback authCallback = buildAuthCallback(code, state);
|
||||
// 从缓存中获取
|
||||
AuthUser authUser = authSocialUserRedisDAO.get(type, authCallback);
|
||||
if (authUser != null) {
|
||||
return authUser;
|
||||
}
|
||||
|
||||
// 请求获取
|
||||
authUser = this.getAuthUser0(type, authCallback);
|
||||
// 缓存。原因是 code 有且可以使用一次。在社交登录时,当未绑定 User 时,需要绑定登录,此时需要 code 使用两次
|
||||
authSocialUserRedisDAO.set(type, authCallback, authUser);
|
||||
return authUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SysSocialUserDO> getAllSocialUserList(Integer type, String unionId,UserTypeEnum userTypeEnum) {
|
||||
List<Integer> types = SysSocialTypeEnum.getRelationTypes(type);
|
||||
return socialUserMapper.selectListByTypeAndUnionId(userTypeEnum.getValue(), types, unionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SysSocialUserDO> getSocialUserList(Long userId,UserTypeEnum userTypeEnum) {
|
||||
return socialUserMapper.selectListByUserId(userTypeEnum.getValue(), userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void bindSocialUser(Long userId, Integer type, AuthUser authUser, UserTypeEnum userTypeEnum) {
|
||||
// 获得 unionId 对应的 SysSocialUserDO 列表
|
||||
String unionId = getAuthUserUnionId(authUser);
|
||||
List<SysSocialUserDO> socialUsers = this.getAllSocialUserList(type, unionId, userTypeEnum);
|
||||
|
||||
// 逻辑一:如果 userId 之前绑定过该 type 的其它账号,需要进行解绑
|
||||
this.unbindOldSocialUser(userId, type, unionId, userTypeEnum);
|
||||
|
||||
// 逻辑二:如果 socialUsers 指定的 userId 改变,需要进行更新
|
||||
// 例如说,一个微信 unionId 对应了多个社交账号,结果其中有个关联了新的 userId,则其它也要跟着修改
|
||||
// 考虑到 socialUsers 一般比较少,直接 for 循环更新即可
|
||||
socialUsers.forEach(socialUser -> {
|
||||
if (Objects.equals(socialUser.getUserId(), userId)) {
|
||||
return;
|
||||
}
|
||||
socialUserMapper.updateById(new SysSocialUserDO().setId(socialUser.getId()).setUserId(userId));
|
||||
});
|
||||
|
||||
// 逻辑三:如果 authUser 不存在于 socialUsers 中,则进行新增;否则,进行更新
|
||||
SysSocialUserDO socialUser = CollUtil.findOneByField(socialUsers, "openid", authUser.getUuid());
|
||||
SysSocialUserDO saveSocialUser = SysSocialUserDO.builder() // 新增和更新的通用属性
|
||||
.token(authUser.getToken().getAccessToken()).rawTokenInfo(toJsonString(authUser.getToken()))
|
||||
.nickname(authUser.getNickname()).avatar(authUser.getAvatar()).rawUserInfo(toJsonString(authUser.getRawUserInfo()))
|
||||
.build();
|
||||
if (socialUser == null) {
|
||||
saveSocialUser.setUserId(userId).setUserType(userTypeEnum.getValue())
|
||||
.setType(type).setOpenid(authUser.getUuid()).setUnionId(unionId);
|
||||
socialUserMapper.insert(saveSocialUser);
|
||||
} else {
|
||||
saveSocialUser.setId(socialUser.getId());
|
||||
socialUserMapper.updateById(saveSocialUser);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unbindSocialUser(Long userId, Integer type, String unionId, UserTypeEnum userTypeEnum) {
|
||||
// 获得 unionId 对应的所有 SysSocialUserDO 社交用户
|
||||
List<SysSocialUserDO> socialUsers = this.getAllSocialUserList(type, unionId, userTypeEnum);
|
||||
if (CollUtil.isEmpty(socialUsers)) {
|
||||
return;
|
||||
}
|
||||
// 校验,是否解绑的是非自己的
|
||||
socialUsers.forEach(socialUser -> {
|
||||
if (!Objects.equals(socialUser.getUserId(), userId)) {
|
||||
throw exception(SOCIAL_UNBIND_NOT_SELF);
|
||||
}
|
||||
});
|
||||
|
||||
// 解绑
|
||||
socialUserMapper.deleteBatchIds(CollectionUtils.convertSet(socialUsers, SysSocialUserDO::getId));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void unbindOldSocialUser(Long userId, Integer type, String newUnionId, UserTypeEnum userTypeEnum) {
|
||||
List<Integer> types = SysSocialTypeEnum.getRelationTypes(type);
|
||||
List<SysSocialUserDO> oldSocialUsers = socialUserMapper.selectListByTypeAndUserId(
|
||||
userTypeEnum.getValue(), types, userId);
|
||||
// 如果新老的 unionId 是一致的,说明无需解绑
|
||||
if (CollUtil.isEmpty(oldSocialUsers) || Objects.equals(newUnionId, oldSocialUsers.get(0).getUnionId())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 解绑
|
||||
socialUserMapper.deleteBatchIds(CollectionUtils.convertSet(oldSocialUsers, SysSocialUserDO::getId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求社交平台,获得授权的用户
|
||||
*
|
||||
* @param type 社交平台的类型
|
||||
* @param authCallback 授权回调
|
||||
* @return 授权的用户
|
||||
*/
|
||||
private AuthUser getAuthUser0(Integer type, AuthCallback authCallback) {
|
||||
AuthRequest authRequest = authRequestFactory.get(SysSocialTypeEnum.valueOfType(type).getSource());
|
||||
AuthResponse<?> authResponse = authRequest.login(authCallback);
|
||||
log.info("[getAuthUser0][请求社交平台 type({}) request({}) response({})]", type, toJsonString(authCallback),
|
||||
toJsonString(authResponse));
|
||||
if (!authResponse.ok()) {
|
||||
throw exception(SOCIAL_AUTH_FAILURE, authResponse.getMsg());
|
||||
}
|
||||
return (AuthUser) authResponse.getData();
|
||||
}
|
||||
|
||||
private static AuthCallback buildAuthCallback(String code, String state) {
|
||||
return AuthCallback.builder().code(code).state(state).build();
|
||||
}
|
||||
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.tenant;
|
||||
|
||||
import cn.iocoder.yudao.framework.tenant.core.service.TenantFrameworkService;
|
||||
|
||||
/**
|
||||
* 租户 Service 接口
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface SysTenantCoreService extends TenantFrameworkService {
|
||||
}
|
@@ -1,29 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.tenant.impl;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.tenant.SysTenantDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.tenant.SysTenantCoreMapper;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.service.tenant.SysTenantCoreService;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 租户 Service 实现类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Service
|
||||
public class SysTenantCoreServiceImpl implements SysTenantCoreService {
|
||||
|
||||
@Resource
|
||||
private SysTenantCoreMapper tenantCoreMapper;
|
||||
|
||||
@Override
|
||||
public List<Long> getTenantIds() {
|
||||
List<SysTenantDO> tenants = tenantCoreMapper.selectList();
|
||||
return CollectionUtils.convertList(tenants, SysTenantDO::getId);
|
||||
}
|
||||
|
||||
}
|
@@ -1,70 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.user;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 后台用户 Service Core 接口
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface SysUserCoreService {
|
||||
|
||||
/**
|
||||
* 通过用户 ID 查询用户
|
||||
*
|
||||
* @param id 用户ID
|
||||
* @return 用户对象信息
|
||||
*/
|
||||
SysUserDO getUser(Long id);
|
||||
|
||||
/**
|
||||
* 获得指定部门的用户数组
|
||||
*
|
||||
* @param deptIds 部门数组
|
||||
* @return 用户数组
|
||||
*/
|
||||
List<SysUserDO> getUsersByDeptIds(Collection<Long> deptIds);
|
||||
|
||||
/**
|
||||
* 获得指定岗位的用户数组
|
||||
*
|
||||
* @param postIds 岗位数组
|
||||
* @return 用户数组
|
||||
*/
|
||||
List<SysUserDO> getUsersByPostIds(Collection<Long> postIds);
|
||||
|
||||
/**
|
||||
* 获得用户列表
|
||||
*
|
||||
* @param ids 用户编号数组
|
||||
* @return 用户列表
|
||||
*/
|
||||
List<SysUserDO> getUsers(Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* 校验用户们是否有效。如下情况,视为无效:
|
||||
* 1. 用户编号不存在
|
||||
* 2. 用户被禁用
|
||||
*
|
||||
* @param ids 用户编号数组
|
||||
*/
|
||||
void validUsers(Set<Long> ids);
|
||||
|
||||
/**
|
||||
* 获得用户 Map
|
||||
*
|
||||
* @param ids 用户编号数组
|
||||
* @return 用户 Map
|
||||
*/
|
||||
default Map<Long, SysUserDO> getUserMap(Collection<Long> ids) {
|
||||
if (CollUtil.isEmpty(ids)) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
return CollectionUtils.convertMap(getUsers(ids), SysUserDO::getId);
|
||||
}
|
||||
|
||||
}
|
@@ -1,82 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.user.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.user.SysUserCoreMapper;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.service.user.SysUserCoreService;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.*;
|
||||
|
||||
import static cn.iocoder.yudao.coreservice.modules.system.enums.SysErrorCodeConstants.USER_IS_DISABLE;
|
||||
import static cn.iocoder.yudao.coreservice.modules.system.enums.SysErrorCodeConstants.USER_NOT_EXISTS;
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
|
||||
/**
|
||||
* 后台用户 Service Core 实现
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Service
|
||||
public class SysUserCoreServiceImpl implements SysUserCoreService {
|
||||
|
||||
@Resource
|
||||
private SysUserCoreMapper userCoreMapper;
|
||||
|
||||
@Override
|
||||
public SysUserDO getUser(Long id) {
|
||||
return userCoreMapper.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SysUserDO> getUsersByDeptIds(Collection<Long> deptIds) {
|
||||
if (CollUtil.isEmpty(deptIds)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return userCoreMapper.selectListByDeptIds(deptIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SysUserDO> getUsersByPostIds(Collection<Long> postIds) {
|
||||
if (CollUtil.isEmpty(postIds)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// 过滤不符合条件的
|
||||
// TODO 芋艿:暂时只能内存过滤。解决方案:1、新建一个关联表;2、基于 where + 函数;3、json 字段,适合 mysql 8+ 版本
|
||||
List<SysUserDO> users = userCoreMapper.selectList();
|
||||
users.removeIf(user -> !CollUtil.containsAny(user.getPostIds(), postIds));
|
||||
return users;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SysUserDO> getUsers(Collection<Long> ids) {
|
||||
if (CollUtil.isEmpty(ids)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return userCoreMapper.selectBatchIds(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validUsers(Set<Long> ids) {
|
||||
if (CollUtil.isEmpty(ids)) {
|
||||
return;
|
||||
}
|
||||
// 获得岗位信息
|
||||
List<SysUserDO> users = userCoreMapper.selectBatchIds(ids);
|
||||
Map<Long, SysUserDO> userMap = CollectionUtils.convertMap(users, SysUserDO::getId);
|
||||
// 校验
|
||||
ids.forEach(id -> {
|
||||
SysUserDO user = userMap.get(id);
|
||||
if (user == null) {
|
||||
throw exception(USER_NOT_EXISTS);
|
||||
}
|
||||
if (!CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus())) {
|
||||
throw exception(USER_IS_DISABLE, user.getNickname());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@@ -12,8 +12,7 @@ import org.springframework.context.annotation.Import;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import static cn.iocoder.yudao.coreservice.modules.system.enums.SysErrorCodeConstants.FILE_NOT_EXISTS;
|
||||
import static cn.iocoder.yudao.coreservice.modules.system.enums.SysErrorCodeConstants.FILE_PATH_EXISTS;
|
||||
import static cn.iocoder.yudao.coreservice.modules.infra.enums.SysErrorCodeConstants.*;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
|
||||
|
@@ -1,125 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.auth;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.BaseDbAndRedisUnitTest;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.auth.SysUserSessionDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.auth.SysUserSessionCoreMapper;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.redis.auth.SysLoginUserCoreRedisDAO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.service.auth.impl.SysUserSessionCoreServiceImpl;
|
||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.framework.security.config.SecurityProperties;
|
||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.Duration;
|
||||
import java.util.Date;
|
||||
|
||||
import static cn.hutool.core.util.RandomUtil.randomEle;
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.addTime;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@Import({SysUserSessionCoreServiceImpl.class, SysLoginUserCoreRedisDAO.class})
|
||||
public class SysUserSessionCoreServiceTest extends BaseDbAndRedisUnitTest {
|
||||
|
||||
@Resource
|
||||
private SysUserSessionCoreServiceImpl userSessionCoreService;
|
||||
|
||||
@Resource
|
||||
private SysUserSessionCoreMapper userSessionCoreMapper;
|
||||
@Resource
|
||||
private SysLoginUserCoreRedisDAO loginUserCoreRedisDAO;
|
||||
|
||||
@MockBean
|
||||
private SecurityProperties securityProperties;
|
||||
|
||||
@Test
|
||||
public void testCreateUserSession_success() {
|
||||
// 准备参数
|
||||
String userIp = randomString();
|
||||
String userAgent = randomString();
|
||||
LoginUser loginUser = randomPojo(LoginUser.class, o -> {
|
||||
o.setUserType(randomEle(UserTypeEnum.values()).getValue());
|
||||
o.setTenantId(0L); // 租户设置为 0,因为暂未启用多租户组件
|
||||
});
|
||||
// mock 方法
|
||||
when(securityProperties.getSessionTimeout()).thenReturn(Duration.ofDays(1));
|
||||
|
||||
// 调用
|
||||
String sessionId = userSessionCoreService.createUserSession(loginUser, userIp, userAgent);
|
||||
// 校验 SysUserSessionDO 记录
|
||||
SysUserSessionDO userSessionDO = userSessionCoreMapper.selectById(sessionId);
|
||||
assertPojoEquals(loginUser, userSessionDO, "id", "updateTime");
|
||||
assertEquals(sessionId, userSessionDO.getId());
|
||||
assertEquals(userIp, userSessionDO.getUserIp());
|
||||
assertEquals(userAgent, userSessionDO.getUserAgent());
|
||||
// 校验 LoginUser 缓存
|
||||
LoginUser redisLoginUser = loginUserCoreRedisDAO.get(sessionId);
|
||||
assertPojoEquals(loginUser, redisLoginUser, "username", "password");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateRefreshUserSession_success() {
|
||||
// 准备参数
|
||||
String sessionId = randomString();
|
||||
String userIp = randomString();
|
||||
String userAgent = randomString();
|
||||
long timeLong = randomLongId();
|
||||
String userName = randomString();
|
||||
Date date = randomDate();
|
||||
LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setUserType(randomEle(UserTypeEnum.values()).getValue()));
|
||||
// mock 方法
|
||||
when(securityProperties.getSessionTimeout()).thenReturn(Duration.ofDays(1));
|
||||
// mock 数据
|
||||
loginUser.setUpdateTime(date);
|
||||
loginUserCoreRedisDAO.set(sessionId, loginUser);
|
||||
SysUserSessionDO userSession = SysUserSessionDO.builder().id(sessionId)
|
||||
.userId(loginUser.getId()).userType(loginUser.getUserType())
|
||||
.userIp(userIp).userAgent(userAgent).username(userName)
|
||||
.sessionTimeout(addTime(Duration.ofMillis(timeLong)))
|
||||
.build();
|
||||
userSessionCoreMapper.insert(userSession);
|
||||
|
||||
// 调用
|
||||
userSessionCoreService.refreshUserSession(sessionId, loginUser);
|
||||
// 校验 LoginUser 缓存
|
||||
LoginUser redisLoginUser = loginUserCoreRedisDAO.get(sessionId);
|
||||
assertNotEquals(redisLoginUser.getUpdateTime(), date);
|
||||
// 校验 SysUserSessionDO 记录
|
||||
SysUserSessionDO updateDO = userSessionCoreMapper.selectById(sessionId);
|
||||
assertEquals(updateDO.getUsername(), loginUser.getUsername());
|
||||
assertNotEquals(updateDO.getUpdateTime(), userSession.getUpdateTime());
|
||||
assertNotEquals(updateDO.getSessionTimeout(), addTime(Duration.ofMillis(timeLong)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteUserSession_success() {
|
||||
// 准备参数
|
||||
String sessionId = randomString();
|
||||
String userIp = randomString();
|
||||
String userAgent = randomString();
|
||||
Long timeLong = randomLongId();
|
||||
LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setUserType(randomEle(UserTypeEnum.values()).getValue()));
|
||||
// mock 存入 Redis
|
||||
when(securityProperties.getSessionTimeout()).thenReturn(Duration.ofDays(1));
|
||||
// mock 数据
|
||||
loginUserCoreRedisDAO.set(sessionId, loginUser);
|
||||
SysUserSessionDO userSession = SysUserSessionDO.builder().id(sessionId)
|
||||
.userId(loginUser.getId()).userType(loginUser.getUserType())
|
||||
.userIp(userIp).userAgent(userAgent).username(loginUser.getUsername())
|
||||
.sessionTimeout(addTime(Duration.ofMillis(timeLong)))
|
||||
.build();
|
||||
userSessionCoreMapper.insert(userSession);
|
||||
|
||||
// 调用
|
||||
userSessionCoreService.deleteUserSession(sessionId);
|
||||
// 校验数据不存在了
|
||||
assertNull(loginUserCoreRedisDAO.get(sessionId));
|
||||
assertNull(userSessionCoreMapper.selectById(sessionId));
|
||||
}
|
||||
|
||||
}
|
@@ -1,78 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.dict;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.BaseDbUnitTest;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.dict.SysDictDataDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.dict.SysDictDataCoreMapper;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.service.dict.impl.SysDictDataCoreServiceImpl;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
|
||||
import com.google.common.collect.ImmutableTable;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Date;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static cn.hutool.core.bean.BeanUtil.getFieldValue;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomCommonStatus;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* {@link SysDictDataCoreServiceImpl} 的单元测试类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Import(SysDictDataCoreServiceImpl.class)
|
||||
public class SysDictDataCoreServiceTest extends BaseDbUnitTest {
|
||||
|
||||
@Resource
|
||||
private SysDictDataCoreServiceImpl dictDataCoreService;
|
||||
|
||||
@Resource
|
||||
private SysDictDataCoreMapper dictDataMapper;
|
||||
|
||||
/**
|
||||
* 测试加载到新的字典数据的情况
|
||||
*/
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testInitLocalCache() {
|
||||
// mock 数据
|
||||
SysDictDataDO dictData01 = randomDictDataDO();
|
||||
dictDataMapper.insert(dictData01);
|
||||
SysDictDataDO dictData02 = randomDictDataDO();
|
||||
dictDataMapper.insert(dictData02);
|
||||
|
||||
// 调用
|
||||
dictDataCoreService.initLocalCache();
|
||||
// 断言 labelDictDataCache 缓存
|
||||
ImmutableTable<String, String, SysDictDataDO> labelDictDataCache =
|
||||
(ImmutableTable<String, String, SysDictDataDO>) getFieldValue(dictDataCoreService, "labelDictDataCache");
|
||||
assertEquals(2, labelDictDataCache.size());
|
||||
assertPojoEquals(dictData01, labelDictDataCache.get(dictData01.getDictType(), dictData01.getLabel()));
|
||||
assertPojoEquals(dictData02, labelDictDataCache.get(dictData02.getDictType(), dictData02.getLabel()));
|
||||
// 断言 valueDictDataCache 缓存
|
||||
ImmutableTable<String, String, SysDictDataDO> valueDictDataCache =
|
||||
(ImmutableTable<String, String, SysDictDataDO>) getFieldValue(dictDataCoreService, "valueDictDataCache");
|
||||
assertEquals(2, valueDictDataCache.size());
|
||||
assertPojoEquals(dictData01, valueDictDataCache.get(dictData01.getDictType(), dictData01.getValue()));
|
||||
assertPojoEquals(dictData02, valueDictDataCache.get(dictData02.getDictType(), dictData02.getValue()));
|
||||
// 断言 maxUpdateTime 缓存
|
||||
Date maxUpdateTime = (Date) getFieldValue(dictDataCoreService, "maxUpdateTime");
|
||||
assertEquals(ObjectUtils.max(dictData01.getUpdateTime(), dictData02.getUpdateTime()), maxUpdateTime);
|
||||
}
|
||||
|
||||
// ========== 随机对象 ==========
|
||||
|
||||
@SafeVarargs
|
||||
private static SysDictDataDO randomDictDataDO(Consumer<SysDictDataDO>... consumers) {
|
||||
Consumer<SysDictDataDO> consumer = (o) -> {
|
||||
o.setStatus(randomCommonStatus()); // 保证 status 的范围
|
||||
};
|
||||
return randomPojo(SysDictDataDO.class, ArrayUtils.append(consumer, consumers));
|
||||
}
|
||||
|
||||
}
|
@@ -1,47 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.logger;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.BaseDbUnitTest;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.logger.SysLoginLogDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.logger.SysLoginLogCoreMapper;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.enums.logger.SysLoginLogTypeEnum;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.enums.logger.SysLoginResultEnum;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.service.logger.dto.SysLoginLogCreateReqDTO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.service.logger.impl.SysLoginLogCoreServiceImpl;
|
||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
|
||||
import cn.iocoder.yudao.framework.test.core.util.RandomUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import static cn.hutool.core.util.RandomUtil.randomEle;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
|
||||
|
||||
@Import(SysLoginLogCoreServiceImpl.class)
|
||||
public class SysLoginLogServiceImplTest extends BaseDbUnitTest {
|
||||
|
||||
@Resource
|
||||
private SysLoginLogCoreServiceImpl loginLogCoreService;
|
||||
|
||||
@Resource
|
||||
private SysLoginLogCoreMapper loginLogCoreMapper;
|
||||
|
||||
@Test
|
||||
public void testCreateLoginLog() {
|
||||
SysLoginLogCreateReqDTO reqDTO = RandomUtils.randomPojo(SysLoginLogCreateReqDTO.class, vo -> {
|
||||
// 指定随机的范围,避免超出范围入库失败
|
||||
vo.setUserType(randomEle(UserTypeEnum.values()).getValue());
|
||||
vo.setLogType(randomEle(SysLoginLogTypeEnum.values()).getType());
|
||||
vo.setResult(randomEle(SysLoginResultEnum.values()).getResult());
|
||||
vo.setTraceId(TracerUtils.getTraceId());
|
||||
});
|
||||
|
||||
// 调用
|
||||
loginLogCoreService.createLoginLog(reqDTO);
|
||||
// 断言,忽略基本字段
|
||||
SysLoginLogDO sysLoginLogDO = loginLogCoreMapper.selectOne(null);
|
||||
assertPojoEquals(reqDTO, sysLoginLogDO);
|
||||
}
|
||||
|
||||
}
|
@@ -1 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service;
|
@@ -1,199 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.sms;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.mq.message.sms.SysSmsSendMessage;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.mq.producer.sms.SysSmsCoreProducer;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.service.sms.impl.SysSmsCoreServiceImpl;
|
||||
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.framework.sms.core.client.SmsClient;
|
||||
import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory;
|
||||
import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
|
||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
|
||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
|
||||
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
|
||||
import org.assertj.core.util.Lists;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.hutool.core.util.RandomUtil.randomEle;
|
||||
import static cn.iocoder.yudao.coreservice.modules.system.enums.SysErrorCodeConstants.*;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* {@link SysSmsCoreService} 的单元测试类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class SysSmsCoreServiceTest extends BaseMockitoUnitTest {
|
||||
|
||||
@InjectMocks
|
||||
private SysSmsCoreServiceImpl smsCoreService;
|
||||
|
||||
@Mock
|
||||
private SysSmsTemplateCoreService smsTemplateCoreService;
|
||||
@Mock
|
||||
private SysSmsLogCoreService smsLogCoreService;
|
||||
@Mock
|
||||
private SysSmsCoreProducer smsCoreProducer;
|
||||
@Mock
|
||||
private SmsClientFactory smsClientFactory;
|
||||
|
||||
/**
|
||||
* 发送成功,当短信模板开启时
|
||||
*/
|
||||
@Test
|
||||
public void testSendSingleSms_successWhenSmsTemplateEnable() {
|
||||
// 准备参数
|
||||
String mobile = randomString();
|
||||
Long userId = randomLongId();
|
||||
Integer userType = randomEle(UserTypeEnum.values()).getValue();
|
||||
String templateCode = randomString();
|
||||
Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234")
|
||||
.put("op", "login").build();
|
||||
// mock SmsTemplateService 的方法
|
||||
SysSmsTemplateDO template = randomPojo(SysSmsTemplateDO.class, o -> {
|
||||
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
o.setContent("验证码为{code}, 操作为{op}");
|
||||
o.setParams(Lists.newArrayList("code", "op"));
|
||||
});
|
||||
when(smsTemplateCoreService.getSmsTemplateByCodeFromCache(eq(templateCode))).thenReturn(template);
|
||||
String content = randomString();
|
||||
when(smsTemplateCoreService.formatSmsTemplateContent(eq(template.getContent()), eq(templateParams)))
|
||||
.thenReturn(content);
|
||||
// mock SmsLogService 的方法
|
||||
Long smsLogId = randomLongId();
|
||||
when(smsLogCoreService.createSmsLog(eq(mobile), eq(userId), eq(userType), eq(Boolean.TRUE), eq(template),
|
||||
eq(content), eq(templateParams))).thenReturn(smsLogId);
|
||||
|
||||
// 调用
|
||||
Long resultSmsLogId = smsCoreService.sendSingleSms(mobile, userId, userType, templateCode, templateParams);
|
||||
// 断言
|
||||
assertEquals(smsLogId, resultSmsLogId);
|
||||
// 断言调用
|
||||
verify(smsCoreProducer, times(1)).sendSmsSendMessage(eq(smsLogId), eq(mobile),
|
||||
eq(template.getChannelId()), eq(template.getApiTemplateId()),
|
||||
eq(Lists.newArrayList(new KeyValue<>("code", "1234"), new KeyValue<>("op", "login"))));
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送成功,当短信模板关闭时
|
||||
*/
|
||||
@Test
|
||||
public void testSendSingleSms_successWhenSmsTemplateDisable() {
|
||||
// 准备参数
|
||||
String mobile = randomString();
|
||||
Long userId = randomLongId();
|
||||
Integer userType = randomEle(UserTypeEnum.values()).getValue();
|
||||
String templateCode = randomString();
|
||||
Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234")
|
||||
.put("op", "login").build();
|
||||
// mock SmsTemplateService 的方法
|
||||
SysSmsTemplateDO template = randomPojo(SysSmsTemplateDO.class, o -> {
|
||||
o.setStatus(CommonStatusEnum.DISABLE.getStatus());
|
||||
o.setContent("验证码为{code}, 操作为{op}");
|
||||
o.setParams(Lists.newArrayList("code", "op"));
|
||||
});
|
||||
when(smsTemplateCoreService.getSmsTemplateByCodeFromCache(eq(templateCode))).thenReturn(template);
|
||||
String content = randomString();
|
||||
when(smsTemplateCoreService.formatSmsTemplateContent(eq(template.getContent()), eq(templateParams)))
|
||||
.thenReturn(content);
|
||||
// mock SmsLogService 的方法
|
||||
Long smsLogId = randomLongId();
|
||||
when(smsLogCoreService.createSmsLog(eq(mobile), eq(userId), eq(userType), eq(Boolean.FALSE), eq(template),
|
||||
eq(content), eq(templateParams))).thenReturn(smsLogId);
|
||||
|
||||
// 调用
|
||||
Long resultSmsLogId = smsCoreService.sendSingleSms(mobile, userId, userType, templateCode, templateParams);
|
||||
// 断言
|
||||
assertEquals(smsLogId, resultSmsLogId);
|
||||
// 断言调用
|
||||
verify(smsCoreProducer, times(0)).sendSmsSendMessage(anyLong(), anyString(),
|
||||
anyLong(), any(), anyList());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckSmsTemplateValid_notExists() {
|
||||
// 准备参数
|
||||
String templateCode = randomString();
|
||||
// mock 方法
|
||||
|
||||
// 调用,并断言异常
|
||||
assertServiceException(() -> smsCoreService.checkSmsTemplateValid(templateCode),
|
||||
SMS_SEND_TEMPLATE_NOT_EXISTS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuildTemplateParams_paramMiss() {
|
||||
// 准备参数
|
||||
SysSmsTemplateDO template = randomPojo(SysSmsTemplateDO.class,
|
||||
o -> o.setParams(Lists.newArrayList("code")));
|
||||
Map<String, Object> templateParams = new HashMap<>();
|
||||
// mock 方法
|
||||
|
||||
// 调用,并断言异常
|
||||
assertServiceException(() -> smsCoreService.buildTemplateParams(template, templateParams),
|
||||
SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS, "code");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckMobile_notExists() {
|
||||
// 准备参数
|
||||
// mock 方法
|
||||
|
||||
// 调用,并断言异常
|
||||
assertServiceException(() -> smsCoreService.checkMobile(null),
|
||||
SMS_SEND_MOBILE_NOT_EXISTS);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testDoSendSms() {
|
||||
// 准备参数
|
||||
SysSmsSendMessage message = randomPojo(SysSmsSendMessage.class);
|
||||
// mock SmsClientFactory 的方法
|
||||
SmsClient smsClient = spy(SmsClient.class);
|
||||
when(smsClientFactory.getSmsClient(eq(message.getChannelId()))).thenReturn(smsClient);
|
||||
// mock SmsClient 的方法
|
||||
SmsCommonResult<SmsSendRespDTO> sendResult = randomPojo(SmsCommonResult.class, SmsSendRespDTO.class);
|
||||
when(smsClient.sendSms(eq(message.getLogId()), eq(message.getMobile()), eq(message.getApiTemplateId()),
|
||||
eq(message.getTemplateParams()))).thenReturn(sendResult);
|
||||
|
||||
// 调用
|
||||
smsCoreService.doSendSms(message);
|
||||
// 断言
|
||||
verify(smsLogCoreService, times(1)).updateSmsSendResult(eq(message.getLogId()),
|
||||
eq(sendResult.getCode()), eq(sendResult.getMsg()), eq(sendResult.getApiCode()),
|
||||
eq(sendResult.getApiMsg()), eq(sendResult.getApiRequestId()), eq(sendResult.getData().getSerialNo()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReceiveSmsStatus() throws Throwable {
|
||||
// 准备参数
|
||||
String channelCode = randomString();
|
||||
String text = randomString();
|
||||
// mock SmsClientFactory 的方法
|
||||
SmsClient smsClient = spy(SmsClient.class);
|
||||
when(smsClientFactory.getSmsClient(eq(channelCode))).thenReturn(smsClient);
|
||||
// mock SmsClient 的方法
|
||||
List<SmsReceiveRespDTO> receiveResults = randomPojoList(SmsReceiveRespDTO.class);
|
||||
|
||||
// 调用
|
||||
smsCoreService.receiveSmsStatus(channelCode, text);
|
||||
// 断言
|
||||
receiveResults.forEach(result -> smsLogCoreService.updateSmsReceiveResult(eq(result.getLogId()), eq(result.getSuccess()),
|
||||
eq(result.getReceiveTime()), eq(result.getErrorCode()), eq(result.getErrorCode())));
|
||||
}
|
||||
|
||||
}
|
@@ -1,149 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.sms;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.iocoder.yudao.coreservice.BaseDbUnitTest;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms.SysSmsLogDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.sms.SysSmsLogCoreMapper;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.enums.sms.SysSmsReceiveStatusEnum;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.enums.sms.SysSmsSendStatusEnum;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.enums.sms.SysSmsTemplateTypeEnum;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.service.sms.impl.SysSmsLogCoreServiceImpl;
|
||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static cn.hutool.core.util.RandomUtil.randomBoolean;
|
||||
import static cn.hutool.core.util.RandomUtil.randomEle;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
/**
|
||||
* {@link SysSmsLogCoreServiceImpl} 的单元测试类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Import(SysSmsLogCoreServiceImpl.class)
|
||||
public class SysSmsLogCoreServiceTest extends BaseDbUnitTest {
|
||||
|
||||
@Resource
|
||||
private SysSmsLogCoreServiceImpl smsLogCoreService;
|
||||
|
||||
@Resource
|
||||
private SysSmsLogCoreMapper smsLogCoreMapper;
|
||||
|
||||
@Test
|
||||
public void testCreateSmsLog() {
|
||||
// 准备参数
|
||||
String mobile = randomString();
|
||||
Long userId = randomLongId();
|
||||
Integer userType = randomEle(UserTypeEnum.values()).getValue();
|
||||
Boolean isSend = randomBoolean();
|
||||
SysSmsTemplateDO templateDO = randomPojo(SysSmsTemplateDO.class,
|
||||
o -> o.setType(randomEle(SysSmsTemplateTypeEnum.values()).getType()));
|
||||
String templateContent = randomString();
|
||||
Map<String, Object> templateParams = randomTemplateParams();
|
||||
// mock 方法
|
||||
|
||||
// 调用
|
||||
Long logId = smsLogCoreService.createSmsLog(mobile, userId, userType, isSend,
|
||||
templateDO, templateContent, templateParams);
|
||||
// 断言
|
||||
SysSmsLogDO logDO = smsLogCoreMapper.selectById(logId);
|
||||
assertEquals(isSend ? SysSmsSendStatusEnum.INIT.getStatus() : SysSmsSendStatusEnum.IGNORE.getStatus(),
|
||||
logDO.getSendStatus());
|
||||
assertEquals(mobile, logDO.getMobile());
|
||||
assertEquals(userType, logDO.getUserType());
|
||||
assertEquals(userId, logDO.getUserId());
|
||||
assertEquals(templateDO.getId(), logDO.getTemplateId());
|
||||
assertEquals(templateDO.getCode(), logDO.getTemplateCode());
|
||||
assertEquals(templateDO.getType(), logDO.getTemplateType());
|
||||
assertEquals(templateDO.getChannelId(), logDO.getChannelId());
|
||||
assertEquals(templateDO.getChannelCode(), logDO.getChannelCode());
|
||||
assertEquals(templateContent, logDO.getTemplateContent());
|
||||
assertEquals(templateParams, logDO.getTemplateParams());
|
||||
assertEquals(SysSmsReceiveStatusEnum.INIT.getStatus(), logDO.getReceiveStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateSmsSendResult() {
|
||||
// mock 数据
|
||||
SysSmsLogDO dbSmsLog = randomSmsLogDO(
|
||||
o -> o.setSendStatus(SysSmsSendStatusEnum.IGNORE.getStatus()));
|
||||
smsLogCoreMapper.insert(dbSmsLog);
|
||||
// 准备参数
|
||||
Long id = dbSmsLog.getId();
|
||||
Integer sendCode = randomInteger();
|
||||
String sendMsg = randomString();
|
||||
String apiSendCode = randomString();
|
||||
String apiSendMsg = randomString();
|
||||
String apiRequestId = randomString();
|
||||
String apiSerialNo = randomString();
|
||||
|
||||
// 调用
|
||||
smsLogCoreService.updateSmsSendResult(id, sendCode, sendMsg,
|
||||
apiSendCode, apiSendMsg, apiRequestId, apiSerialNo);
|
||||
// 断言
|
||||
dbSmsLog = smsLogCoreMapper.selectById(id);
|
||||
assertEquals(CommonResult.isSuccess(sendCode) ? SysSmsSendStatusEnum.SUCCESS.getStatus()
|
||||
: SysSmsSendStatusEnum.FAILURE.getStatus(), dbSmsLog.getSendStatus());
|
||||
assertNotNull(dbSmsLog.getSendTime());
|
||||
assertEquals(sendMsg, dbSmsLog.getSendMsg());
|
||||
assertEquals(apiSendCode, dbSmsLog.getApiSendCode());
|
||||
assertEquals(apiSendMsg, dbSmsLog.getApiSendMsg());
|
||||
assertEquals(apiRequestId, dbSmsLog.getApiRequestId());
|
||||
assertEquals(apiSerialNo, dbSmsLog.getApiSerialNo());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateSmsReceiveResult() {
|
||||
// mock 数据
|
||||
SysSmsLogDO dbSmsLog = randomSmsLogDO(
|
||||
o -> o.setReceiveStatus(SysSmsReceiveStatusEnum.INIT.getStatus()));
|
||||
smsLogCoreMapper.insert(dbSmsLog);
|
||||
// 准备参数
|
||||
Long id = dbSmsLog.getId();
|
||||
Boolean success = randomBoolean();
|
||||
Date receiveTime = randomDate();
|
||||
String apiReceiveCode = randomString();
|
||||
String apiReceiveMsg = randomString();
|
||||
|
||||
// 调用
|
||||
smsLogCoreService.updateSmsReceiveResult(id, success, receiveTime, apiReceiveCode, apiReceiveMsg);
|
||||
// 断言
|
||||
dbSmsLog = smsLogCoreMapper.selectById(id);
|
||||
assertEquals(success ? SysSmsReceiveStatusEnum.SUCCESS.getStatus()
|
||||
: SysSmsReceiveStatusEnum.FAILURE.getStatus(), dbSmsLog.getReceiveStatus());
|
||||
assertEquals(receiveTime, dbSmsLog.getReceiveTime());
|
||||
assertEquals(apiReceiveCode, dbSmsLog.getApiReceiveCode());
|
||||
assertEquals(apiReceiveMsg, dbSmsLog.getApiReceiveMsg());
|
||||
}
|
||||
|
||||
// ========== 随机对象 ==========
|
||||
|
||||
@SafeVarargs
|
||||
private static SysSmsLogDO randomSmsLogDO(Consumer<SysSmsLogDO>... consumers) {
|
||||
Consumer<SysSmsLogDO> consumer = (o) -> {
|
||||
o.setTemplateParams(randomTemplateParams());
|
||||
o.setTemplateType(randomEle(SysSmsTemplateTypeEnum.values()).getType()); // 保证 templateType 的范围
|
||||
o.setUserType(randomEle(UserTypeEnum.values()).getValue()); // 保证 userType 的范围
|
||||
o.setSendStatus(randomEle(SysSmsSendStatusEnum.values()).getStatus()); // 保证 sendStatus 的范围
|
||||
o.setReceiveStatus(randomEle(SysSmsReceiveStatusEnum.values()).getStatus()); // 保证 receiveStatus 的范围
|
||||
};
|
||||
return randomPojo(SysSmsLogDO.class, ArrayUtils.append(consumer, consumers));
|
||||
}
|
||||
|
||||
|
||||
private static Map<String, Object> randomTemplateParams() {
|
||||
return MapUtil.<String, Object>builder().put(randomString(), randomString())
|
||||
.put(randomString(), randomString()).build();
|
||||
}
|
||||
}
|
@@ -1,71 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.sms;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.BaseDbUnitTest;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.sms.SysSmsTemplateCoreMapper;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.enums.sms.SysSmsTemplateTypeEnum;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.service.sms.impl.SysSmsTemplateCoreServiceImpl;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static cn.hutool.core.bean.BeanUtil.getFieldValue;
|
||||
import static cn.hutool.core.util.RandomUtil.randomEle;
|
||||
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.max;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* {@link SysSmsTemplateCoreServiceImpl} 的单元测试类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Import(SysSmsTemplateCoreServiceImpl.class)
|
||||
public class SysSmsTemplateServiceTest extends BaseDbUnitTest {
|
||||
|
||||
@Resource
|
||||
private SysSmsTemplateCoreServiceImpl smsTemplateCoreService;
|
||||
|
||||
@Resource
|
||||
private SysSmsTemplateCoreMapper smsTemplateCoreMapper;
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void testInitLocalCache() {
|
||||
// mock 数据
|
||||
SysSmsTemplateDO smsTemplate01 = randomSmsTemplateDO();
|
||||
smsTemplateCoreMapper.insert(smsTemplate01);
|
||||
SysSmsTemplateDO smsTemplate02 = randomSmsTemplateDO();
|
||||
smsTemplateCoreMapper.insert(smsTemplate02);
|
||||
|
||||
// 调用
|
||||
smsTemplateCoreService.initLocalCache();
|
||||
// 断言 deptCache 缓存
|
||||
Map<String, SysSmsTemplateDO> smsTemplateCache = (Map<String, SysSmsTemplateDO>) getFieldValue(smsTemplateCoreService, "smsTemplateCache");
|
||||
assertEquals(2, smsTemplateCache.size());
|
||||
assertPojoEquals(smsTemplate01, smsTemplateCache.get(smsTemplate01.getCode()));
|
||||
assertPojoEquals(smsTemplate02, smsTemplateCache.get(smsTemplate02.getCode()));
|
||||
// 断言 maxUpdateTime 缓存
|
||||
Date maxUpdateTime = (Date) getFieldValue(smsTemplateCoreService, "maxUpdateTime");
|
||||
assertEquals(max(smsTemplate01.getUpdateTime(), smsTemplate02.getUpdateTime()), maxUpdateTime);
|
||||
}
|
||||
|
||||
// ========== 随机对象 ==========
|
||||
|
||||
@SafeVarargs
|
||||
private static SysSmsTemplateDO randomSmsTemplateDO(Consumer<SysSmsTemplateDO>... consumers) {
|
||||
Consumer<SysSmsTemplateDO> consumer = (o) -> {
|
||||
o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
|
||||
o.setType(randomEle(SysSmsTemplateTypeEnum.values()).getType()); // 保证 type 的 范围
|
||||
};
|
||||
return randomPojo(SysSmsTemplateDO.class, ArrayUtils.append(consumer, consumers));
|
||||
}
|
||||
|
||||
}
|
@@ -1,171 +0,0 @@
|
||||
package cn.iocoder.yudao.coreservice.modules.system.service.social;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.BaseDbAndRedisUnitTest;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.social.SysSocialUserDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.social.SysSocialUserCoreMapper;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.redis.social.SysSocialAuthUserRedisDAO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.enums.social.SysSocialTypeEnum;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.service.social.impl.SysSocialCoreServiceImpl;
|
||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import com.xkcoding.justauth.AuthRequestFactory;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.hutool.core.util.RandomUtil.randomEle;
|
||||
import static cn.hutool.core.util.RandomUtil.randomString;
|
||||
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* {@link SysSocialCoreServiceImpl} 的单元测试类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Import({SysSocialCoreServiceImpl.class, SysSocialAuthUserRedisDAO.class})
|
||||
public class SysSocialCoreServiceTest extends BaseDbAndRedisUnitTest {
|
||||
|
||||
@Resource
|
||||
private SysSocialCoreServiceImpl socialService;
|
||||
|
||||
@Resource
|
||||
private SysSocialUserCoreMapper socialUserMapper;
|
||||
|
||||
@MockBean
|
||||
private AuthRequestFactory authRequestFactory;
|
||||
|
||||
/**
|
||||
* 情况一,创建 SysSocialUserDO 的情况
|
||||
*/
|
||||
@Test
|
||||
public void testBindSocialUser_create() {
|
||||
// mock 数据
|
||||
// 准备参数
|
||||
Long userId = randomLongId();
|
||||
Integer type = randomEle(SysSocialTypeEnum.values()).getType();
|
||||
AuthUser authUser = randomPojo(AuthUser.class);
|
||||
// mock 方法
|
||||
|
||||
// 调用
|
||||
socialService.bindSocialUser(userId, type, authUser, UserTypeEnum.ADMIN);
|
||||
// 断言
|
||||
List<SysSocialUserDO> socialUsers = socialUserMapper.selectList("user_id", userId);
|
||||
assertEquals(1, socialUsers.size());
|
||||
assertBindSocialUser(socialUsers.get(0), authUser, userId, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 情况二,更新 SysSocialUserDO 的情况
|
||||
*/
|
||||
@Test
|
||||
public void testBindSocialUser_update() {
|
||||
// mock 数据
|
||||
SysSocialUserDO dbSocialUser = randomPojo(SysSocialUserDO.class, socialUserDO -> {
|
||||
socialUserDO.setUserType(UserTypeEnum.ADMIN.getValue());
|
||||
socialUserDO.setType(randomEle(SysSocialTypeEnum.values()).getType());
|
||||
});
|
||||
socialUserMapper.insert(dbSocialUser);
|
||||
// 准备参数
|
||||
Long userId = dbSocialUser.getUserId();
|
||||
Integer type = dbSocialUser.getType();
|
||||
AuthUser authUser = randomPojo(AuthUser.class);
|
||||
// mock 方法
|
||||
|
||||
// 调用
|
||||
socialService.bindSocialUser(userId, type, authUser, UserTypeEnum.ADMIN);
|
||||
// 断言
|
||||
List<SysSocialUserDO> socialUsers = socialUserMapper.selectList("user_id", userId);
|
||||
assertEquals(1, socialUsers.size());
|
||||
assertBindSocialUser(socialUsers.get(0), authUser, userId, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 情况一和二都存在的,逻辑二的场景
|
||||
*/
|
||||
@Test
|
||||
public void testBindSocialUser_userId() {
|
||||
// mock 数据
|
||||
SysSocialUserDO dbSocialUser = randomPojo(SysSocialUserDO.class, socialUserDO -> {
|
||||
socialUserDO.setUserType(UserTypeEnum.ADMIN.getValue());
|
||||
socialUserDO.setType(randomEle(SysSocialTypeEnum.values()).getType());
|
||||
});
|
||||
socialUserMapper.insert(dbSocialUser);
|
||||
// 准备参数
|
||||
Long userId = randomLongId();
|
||||
Integer type = dbSocialUser.getType();
|
||||
AuthUser authUser = randomPojo(AuthUser.class);
|
||||
// mock 方法
|
||||
|
||||
// 调用
|
||||
socialService.bindSocialUser(userId, type, authUser, UserTypeEnum.ADMIN);
|
||||
// 断言
|
||||
List<SysSocialUserDO> socialUsers = socialUserMapper.selectList("user_id", userId);
|
||||
assertEquals(1, socialUsers.size());
|
||||
}
|
||||
|
||||
private void assertBindSocialUser(SysSocialUserDO socialUser, AuthUser authUser, Long userId,
|
||||
Integer type) {
|
||||
assertEquals(authUser.getToken().getAccessToken(), socialUser.getToken());
|
||||
assertEquals(toJsonString(authUser.getToken()), socialUser.getRawTokenInfo());
|
||||
assertEquals(authUser.getNickname(), socialUser.getNickname());
|
||||
assertEquals(authUser.getAvatar(), socialUser.getAvatar());
|
||||
assertEquals(toJsonString(authUser.getRawUserInfo()), socialUser.getRawUserInfo());
|
||||
assertEquals(userId, socialUser.getUserId());
|
||||
assertEquals(UserTypeEnum.ADMIN.getValue(), socialUser.getUserType());
|
||||
assertEquals(type, socialUser.getType());
|
||||
assertEquals(authUser.getUuid(), socialUser.getOpenid());
|
||||
assertEquals(socialService.getAuthUserUnionId(authUser), socialUser.getUnionId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 情况一,如果新老的 unionId 是一致的,无需解绑
|
||||
*/
|
||||
@Test
|
||||
public void testUnbindOldSocialUser_no() {
|
||||
// mock 数据
|
||||
SysSocialUserDO oldSocialUser = randomPojo(SysSocialUserDO.class, socialUserDO -> {
|
||||
socialUserDO.setUserType(UserTypeEnum.ADMIN.getValue());
|
||||
socialUserDO.setType(randomEle(SysSocialTypeEnum.values()).getType());
|
||||
});
|
||||
socialUserMapper.insert(oldSocialUser);
|
||||
// 准备参数
|
||||
Long userId = oldSocialUser.getUserId();
|
||||
Integer type = oldSocialUser.getType();
|
||||
String newUnionId = oldSocialUser.getUnionId();
|
||||
|
||||
// 调用
|
||||
socialService.unbindOldSocialUser(userId, type, newUnionId, UserTypeEnum.ADMIN);
|
||||
// 断言
|
||||
assertEquals(1L, socialUserMapper.selectCount(null).longValue());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 情况二,如果新老的 unionId 不一致的,需解绑
|
||||
*/
|
||||
@Test
|
||||
public void testUnbindOldSocialUser_yes() {
|
||||
// mock 数据
|
||||
SysSocialUserDO oldSocialUser = randomPojo(SysSocialUserDO.class, socialUserDO -> {
|
||||
socialUserDO.setUserType(UserTypeEnum.ADMIN.getValue());
|
||||
socialUserDO.setType(randomEle(SysSocialTypeEnum.values()).getType());
|
||||
});
|
||||
socialUserMapper.insert(oldSocialUser);
|
||||
// 准备参数
|
||||
Long userId = oldSocialUser.getUserId();
|
||||
Integer type = oldSocialUser.getType();
|
||||
String newUnionId = randomString(10);
|
||||
|
||||
// 调用
|
||||
socialService.unbindOldSocialUser(userId, type, newUnionId, UserTypeEnum.ADMIN);
|
||||
// 断言
|
||||
assertEquals(0L, socialUserMapper.selectCount(null).longValue());
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user