!58 新增多租户、数据权限

Merge pull request !58 from 芋道源码/feature/user-register
This commit is contained in:
芋道源码 2021-12-14 14:57:47 +00:00 committed by Gitee
commit ac1ced7459
673 changed files with 57741 additions and 460 deletions

View File

@ -33,6 +33,7 @@
| | 菜单管理 | 配置系统菜单,操作权限,按钮权限标识等 |
| | 部门管理 | 配置系统组织机构(公司、部门、小组),树结构展现支持数据权限 |
| | 岗位管理 | 配置系统用户所属担任职务 |
| | 租户管理 | 配置系统租户,支持 SaaS 场景下的多租户功能 |
| | 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护 |
| 🚀 | 短信管理 | 短信渠道、短息模板、短信日志,对接阿里云、云片等主流短信平台 |
| 🚀 | 操作日志 | 系统正常操作日志记录和查询,集成 Swagger 生成日志内容 |

BIN
img.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

View File

@ -117,7 +117,15 @@
<artifactId>yudao-spring-boot-starter-excel</artifactId>
</dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-tenant</artifactId>
</dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-data-permission</artifactId>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>

View File

@ -1,9 +0,0 @@
package cn.iocoder.yudao.adminserver.framework.async.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
@Configuration
@EnableAsync
public class AsyncConfiguration {
}

View File

@ -1,4 +0,0 @@
/**
* 异步执行基于 Spring @Async 实现
*/
package cn.iocoder.yudao.adminserver.framework.async;

View File

@ -22,9 +22,11 @@ public class SecurityConfiguration {
@Bean
public Customizer<ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry> authorizeRequestsCustomizer() {
return registry -> {
// 通用的接口可匿名访问 TODO 芋艿需要抽象出去
// 验证码的接口
registry.antMatchers(api("/system/captcha/**")).anonymous();
// Spring Boot Admin Server 的安全配置 TODO 芋艿需要抽象出去
// 获得租户编号的接口
registry.antMatchers(api("/system/tenant/get-id-by-name")).anonymous();
// Spring Boot Admin Server 的安全配置
registry.antMatchers(adminSeverContextPath).anonymous()
.antMatchers(adminSeverContextPath + "/**").anonymous();
// 短信回调 API

View File

@ -1,13 +1,13 @@
package cn.iocoder.yudao.adminserver.modules.infra.mq.message.config;
import cn.iocoder.yudao.framework.mq.core.pubsub.ChannelMessage;
import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;
import lombok.Data;
/**
* 配置数据刷新 Message
*/
@Data
public class InfConfigRefreshMessage implements ChannelMessage {
public class InfConfigRefreshMessage extends AbstractChannelMessage {
@Override
public String getChannel() {

View File

@ -1,8 +1,7 @@
package cn.iocoder.yudao.adminserver.modules.infra.mq.producer.config;
import cn.iocoder.yudao.adminserver.modules.infra.mq.message.config.InfConfigRefreshMessage;
import cn.iocoder.yudao.framework.mq.core.util.RedisMessageUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@ -14,14 +13,14 @@ import javax.annotation.Resource;
public class InfConfigProducer {
@Resource
private StringRedisTemplate stringRedisTemplate;
private RedisMQTemplate redisMQTemplate;
/**
* 发送 {@link InfConfigRefreshMessage} 消息
*/
public void sendConfigRefreshMessage() {
InfConfigRefreshMessage message = new InfConfigRefreshMessage();
RedisMessageUtils.sendChannelMessage(stringRedisTemplate, message);
redisMQTemplate.send(message);
}
}

View File

@ -1,21 +1,25 @@
### 请求 /login 接口 => 成功
POST {{baseUrl}}/login
Content-Type: application/json
tenant-id: 1
{
"username": "admin",
"password": "admin123",
"uuid": "9b2ffbc1-7425-4155-9894-9d5c08541d62",
"uuid": "3acd87a09a4f48fb9118333780e94883",
"code": "1024"
}
### 请求 /get-permission-info 接口 => 成功
GET {{baseUrl}}/get-permission-info
Authorization: Bearer {{token}}
tenant-id: 1
### 请求 /list-menus 接口 => 成功
GET {{baseUrl}}/list-menus
Authorization: Bearer {{token}}
#Authorization: Bearer a6aa7714a2e44c95aaa8a2c5adc2a67a
tenant-id: 1
### 请求 /druid/xxx 接口 => 失败 TODO 临时测试
GET http://127.0.0.1:8080/druid/123

View File

@ -0,0 +1,106 @@
package cn.iocoder.yudao.adminserver.modules.system.controller.tenant;
import cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo.*;
import cn.iocoder.yudao.adminserver.modules.system.convert.tenant.SysTenantConvert;
import cn.iocoder.yudao.adminserver.modules.system.service.tenant.SysTenantService;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.tenant.SysTenantDO;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
@Api(tags = "租户")
@RestController
@RequestMapping("/system/tenant")
public class SysTenantController {
@Resource
private SysTenantService tenantService;
@GetMapping("/get-id-by-name")
@ApiOperation(value = "使用租户名,获得租户编号", notes = "登录界面,根据用户的租户名,获得租户编号")
@ApiImplicitParam(name = "name", value = "租户名", required = true, example = "芋道源码", dataTypeClass = Long.class)
public CommonResult<Long> getTenantIdByName(@RequestParam("name") String name) {
SysTenantDO tenantDO = tenantService.getTenantByName(name);
return success(tenantDO != null ? tenantDO.getId() : null);
}
@PostMapping("/create")
@ApiOperation("创建租户")
@PreAuthorize("@ss.hasPermission('system:tenant:create')")
public CommonResult<Long> createTenant(@Valid @RequestBody SysTenantCreateReqVO createReqVO) {
return success(tenantService.createTenant(createReqVO));
}
@PutMapping("/update")
@ApiOperation("更新租户")
@PreAuthorize("@ss.hasPermission('system:tenant:update')")
public CommonResult<Boolean> updateTenant(@Valid @RequestBody SysTenantUpdateReqVO updateReqVO) {
tenantService.updateTenant(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@ApiOperation("删除租户")
@ApiImplicitParam(name = "id", value = "编号", required = true)
@PreAuthorize("@ss.hasPermission('system:tenant:delete')")
public CommonResult<Boolean> deleteTenant(@RequestParam("id") Long id) {
tenantService.deleteTenant(id);
return success(true);
}
@GetMapping("/get")
@ApiOperation("获得租户")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('system:tenant:query')")
public CommonResult<SysTenantRespVO> getTenant(@RequestParam("id") Long id) {
SysTenantDO tenant = tenantService.getTenant(id);
return success(SysTenantConvert.INSTANCE.convert(tenant));
}
@GetMapping("/list")
@ApiOperation("获得租户列表")
@ApiImplicitParam(name = "ids", value = "编号列表", required = true, example = "1024,2048", dataTypeClass = List.class)
@PreAuthorize("@ss.hasPermission('system:tenant:query')")
public CommonResult<List<SysTenantRespVO>> getTenantList(@RequestParam("ids") Collection<Long> ids) {
List<SysTenantDO> list = tenantService.getTenantList(ids);
return success(SysTenantConvert.INSTANCE.convertList(list));
}
@GetMapping("/page")
@ApiOperation("获得租户分页")
@PreAuthorize("@ss.hasPermission('system:tenant:query')")
public CommonResult<PageResult<SysTenantRespVO>> getTenantPage(@Valid SysTenantPageReqVO pageVO) {
PageResult<SysTenantDO> pageResult = tenantService.getTenantPage(pageVO);
return success(SysTenantConvert.INSTANCE.convertPage(pageResult));
}
@GetMapping("/export-excel")
@ApiOperation("导出租户 Excel")
@PreAuthorize("@ss.hasPermission('system:tenant:export')")
@OperateLog(type = EXPORT)
public void exportTenantExcel(@Valid SysTenantExportReqVO exportReqVO,
HttpServletResponse response) throws IOException {
List<SysTenantDO> list = tenantService.getTenantList(exportReqVO);
// 导出 Excel
List<SysTenantExcelVO> datas = SysTenantConvert.INSTANCE.convertList02(list);
ExcelUtils.write(response, "租户.xls", "数据", SysTenantExcelVO.class, datas);
}
}

View File

@ -0,0 +1,30 @@
package cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import javax.validation.constraints.*;
/**
* 租户 Base VO提供给添加修改详细的子 VO 使用
* 如果子 VO 存在差异的字段请不要添加到这里影响 Swagger 文档生成
*/
@Data
public class SysTenantBaseVO {
@ApiModelProperty(value = "租户名", required = true, example = "芋道")
@NotNull(message = "租户名不能为空")
private String name;
@ApiModelProperty(value = "联系人", required = true, example = "芋艿")
@NotNull(message = "联系人不能为空")
private String contactName;
@ApiModelProperty(value = "联系手机", example = "15601691300")
private String contactMobile;
@ApiModelProperty(value = "租户状态0正常 1停用", required = true, example = "1")
@NotNull(message = "租户状态0正常 1停用不能为空")
private Integer status;
}

View File

@ -0,0 +1,14 @@
package cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import javax.validation.constraints.*;
@ApiModel("租户创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class SysTenantCreateReqVO extends SysTenantBaseVO {
}

View File

@ -0,0 +1,39 @@
package cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import com.alibaba.excel.annotation.ExcelProperty;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
/**
* 租户 Excel VO
*
* @author 芋道源码
*/
@Data
public class SysTenantExcelVO {
@ExcelProperty("租户编号")
private Long id;
@ExcelProperty("租户名")
private String name;
@ExcelProperty("联系人")
private String contactName;
@ExcelProperty("联系手机")
private String contactMobile;
@ExcelProperty(value = "租户状态0正常 1停用", converter = DictConvert.class)
@DictFormat("sys_common_status") // TODO 代码优化建议设置到对应的 XXXDictTypeConstants 枚举类中
private Integer status;
@ExcelProperty("创建时间")
private Date createTime;
}

View File

@ -0,0 +1,36 @@
package cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel(value = "租户 Excel 导出 Request VO", description = "参数和 SysTenantPageReqVO 是一致的")
@Data
public class SysTenantExportReqVO {
@ApiModelProperty(value = "租户名", example = "芋道")
private String name;
@ApiModelProperty(value = "联系人", example = "芋艿")
private String contactName;
@ApiModelProperty(value = "联系手机", example = "15601691300")
private String contactMobile;
@ApiModelProperty(value = "租户状态0正常 1停用", example = "1")
private Integer status;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "开始创建时间")
private Date beginCreateTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "结束创建时间")
private Date endCreateTime;
}

View File

@ -0,0 +1,41 @@
package cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel("租户分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class SysTenantPageReqVO extends PageParam {
@ApiModelProperty(value = "租户名", example = "芋道")
private String name;
@ApiModelProperty(value = "联系人", example = "芋艿")
private String contactName;
@ApiModelProperty(value = "联系手机", example = "15601691300")
private String contactMobile;
@ApiModelProperty(value = "租户状态0正常 1停用", example = "1")
private Integer status;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "开始创建时间")
private Date beginCreateTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "结束创建时间")
private Date endCreateTime;
}

View File

@ -0,0 +1,19 @@
package cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
@ApiModel("租户 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class SysTenantRespVO extends SysTenantBaseVO {
@ApiModelProperty(value = "租户编号", required = true, example = "1024")
private Long id;
@ApiModelProperty(value = "创建时间", required = true)
private Date createTime;
}

View File

@ -0,0 +1,18 @@
package cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import javax.validation.constraints.*;
@ApiModel("租户更新 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class SysTenantUpdateReqVO extends SysTenantBaseVO {
@ApiModelProperty(value = "租户编号", required = true, example = "1024")
@NotNull(message = "租户编号不能为空")
private Long id;
}

View File

@ -1,3 +1,4 @@
### 请求 /system/user/page 接口 => 没有权限
GET {{baseUrl}}/system/user/page?pageNo=1&pageSize=10
Authorization: Bearer test104 # 使用测试账号
Authorization: Bearer test1 # 使用测试账号
tenant-id: 1

View File

@ -0,0 +1,36 @@
package cn.iocoder.yudao.adminserver.modules.system.convert.tenant;
import cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo.SysTenantCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo.SysTenantExcelVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo.SysTenantRespVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo.SysTenantUpdateReqVO;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.tenant.SysTenantDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
/**
* 租户 Convert
*
* @author 芋道源码
*/
@Mapper
public interface SysTenantConvert {
SysTenantConvert INSTANCE = Mappers.getMapper(SysTenantConvert.class);
SysTenantDO convert(SysTenantCreateReqVO bean);
SysTenantDO convert(SysTenantUpdateReqVO bean);
SysTenantRespVO convert(SysTenantDO bean);
List<SysTenantRespVO> convertList(List<SysTenantDO> list);
PageResult<SysTenantRespVO> convertPage(PageResult<SysTenantDO> page);
List<SysTenantExcelVO> convertList02(List<SysTenantDO> list);
}

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@ -15,7 +15,7 @@ import lombok.EqualsAndHashCode;
@TableName("sys_dept")
@Data
@EqualsAndHashCode(callSuper = true)
public class SysDeptDO extends BaseDO {
public class SysDeptDO extends TenantBaseDO {
/**
* 部门ID

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@ -15,14 +15,13 @@ import lombok.EqualsAndHashCode;
@TableName("sys_post")
@Data
@EqualsAndHashCode(callSuper = true)
public class SysPostDO extends BaseDO {
public class SysPostDO extends TenantBaseDO {
/**
* 岗位序号
*/
@TableId
private Long id;
/**
* 岗位名称
*/

View File

@ -3,7 +3,7 @@ package cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.logger;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
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;
@ -22,7 +22,7 @@ import java.util.Map;
@TableName(value = "sys_operate_log", autoResultMap = true)
@Data
@EqualsAndHashCode(callSuper = true)
public class SysOperateLogDO extends BaseDO {
public class SysOperateLogDO extends TenantBaseDO {
/**
* {@link #javaMethodArgs} 的最大长度

View File

@ -1,8 +1,8 @@
package cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.notice;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.adminserver.modules.system.enums.notice.SysNoticeTypeEnum;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@ -16,7 +16,7 @@ import lombok.EqualsAndHashCode;
@TableName("sys_notice")
@Data
@EqualsAndHashCode(callSuper = true)
public class SysNoticeDO extends BaseDO {
public class SysNoticeDO extends TenantBaseDO {
/**
* 公告ID

View File

@ -24,7 +24,7 @@ public interface SysDeptMapper extends BaseMapperX<SysDeptDO> {
}
default Integer selectCountByParentId(Long parentId) {
return selectCount(new QueryWrapper<SysDeptDO>().eq("parent_id", parentId));
return selectCount("parent_id", parentId);
}
default boolean selectExistsByUpdateTimeAfter(Date maxUpdateTime) {

View File

@ -19,7 +19,7 @@ public interface SysMenuMapper extends BaseMapperX<SysMenuDO> {
}
default Integer selectCountByParentId(Long parentId) {
return selectCount(new QueryWrapper<SysMenuDO>().eq("parent_id", parentId));
return selectCount("parent_id", parentId);
}
default List<SysMenuDO> selectList(SysMenuListReqVO reqVO) {

View File

@ -0,0 +1,44 @@
package cn.iocoder.yudao.adminserver.modules.system.dal.mysql.tenant;
import cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo.SysTenantExportReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo.SysTenantPageReqVO;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.tenant.SysTenantDO;
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
*
* @author 芋道源码
*/
@Mapper
public interface SysTenantMapper extends BaseMapperX<SysTenantDO> {
default PageResult<SysTenantDO> selectPage(SysTenantPageReqVO reqVO) {
return selectPage(reqVO, new QueryWrapperX<SysTenantDO>()
.likeIfPresent("name", reqVO.getName())
.likeIfPresent("contact_name", reqVO.getContactName())
.likeIfPresent("contact_mobile", reqVO.getContactMobile())
.eqIfPresent("status", reqVO.getStatus())
.betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
.orderByDesc("id"));
}
default List<SysTenantDO> selectList(SysTenantExportReqVO reqVO) {
return selectList(new QueryWrapperX<SysTenantDO>()
.likeIfPresent("name", reqVO.getName())
.likeIfPresent("contact_name", reqVO.getContactName())
.likeIfPresent("contact_mobile", reqVO.getContactMobile())
.eqIfPresent("status", reqVO.getStatus())
.betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
.orderByDesc("id"));
}
default SysTenantDO selectByName(String name) {
return selectOne("name", name);
}
}

View File

@ -85,10 +85,12 @@ public interface SysErrorCodeConstants {
ErrorCode SMS_TEMPLATE_NOT_EXISTS = new ErrorCode(1002011000, "短信模板不存在");
ErrorCode SMS_TEMPLATE_CODE_DUPLICATE = new ErrorCode(1002011001, "已经存在编码为【{}】的短信模板");
// ========== 租户模块 1002012000 ==========
ErrorCode TENANT_NOT_EXISTS = new ErrorCode(1002012000, "租户不存在");
// ========== 错误码模块 1002013000 ==========
ErrorCode ERROR_CODE_NOT_EXISTS = new ErrorCode(1002013000, "错误码不存在");
ErrorCode ERROR_CODE_DUPLICATE = new ErrorCode(1002013001, "已经存在编码为【{}】的错误码");
}

View File

@ -12,6 +12,13 @@ import java.time.Duration;
@Data
public class CaptchaProperties {
private static final Boolean ENABLE_DEFAULT = true;
/**
* 是否开启
* 注意这里仅仅是后端 Server 是否校验暂时不控制前端的逻辑
*/
private Boolean enable = ENABLE_DEFAULT;
/**
* 验证码的过期时间
*/

View File

@ -0,0 +1,25 @@
package cn.iocoder.yudao.adminserver.modules.system.framework.datapermission.config;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept.SysDeptDO;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
import cn.iocoder.yudao.framework.datapermission.core.dept.rule.DeptDataPermissionRuleCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* system 模块的数据权限 Configuration
*
* @author 芋道源码
*/
@Configuration
public class SysDataPermissionConfiguration {
@Bean
public DeptDataPermissionRuleCustomizer sysDeptDataPermissionRuleCustomizer() {
return rule -> {
rule.addDeptColumn(SysUserDO.class);
rule.addDeptColumn(SysDeptDO.class, "id");
};
}
}

View File

@ -0,0 +1,4 @@
/**
* system 模块的数据权限配置
*/
package cn.iocoder.yudao.adminserver.modules.system.framework.datapermission;

View File

@ -2,6 +2,7 @@ package cn.iocoder.yudao.adminserver.modules.system.job.auth;
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
import cn.iocoder.yudao.adminserver.modules.system.service.auth.SysUserSessionService;
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@ -13,6 +14,7 @@ import javax.annotation.Resource;
* @author
*/
@Component
@TenantJob
@Slf4j
public class SysUserSessionTimeoutJob implements JobHandler {

View File

@ -1,13 +1,17 @@
package cn.iocoder.yudao.adminserver.modules.system.mq.message.dept;
import cn.iocoder.yudao.framework.mq.core.pubsub.ChannelMessage;
import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 部门数据刷新 Message
*
* @author 芋道源码
*/
@Data
public class SysDeptRefreshMessage implements ChannelMessage {
@EqualsAndHashCode(callSuper = true)
public class SysDeptRefreshMessage extends AbstractChannelMessage {
@Override
public String getChannel() {

View File

@ -1,13 +1,15 @@
package cn.iocoder.yudao.adminserver.modules.system.mq.message.dict;
import cn.iocoder.yudao.framework.mq.core.pubsub.ChannelMessage;
import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 字典数据数据刷新 Message
*/
@Data
public class SysDictDataRefreshMessage implements ChannelMessage {
@EqualsAndHashCode(callSuper = true)
public class SysDictDataRefreshMessage extends AbstractChannelMessage {
@Override
public String getChannel() {

View File

@ -1,7 +1,8 @@
package cn.iocoder.yudao.adminserver.modules.system.mq.message.mail;
import cn.iocoder.yudao.framework.mq.core.stream.StreamMessage;
import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessage;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotNull;
import java.util.Map;
@ -12,7 +13,8 @@ import java.util.Map;
* @author 芋道源码
*/
@Data
public class SysMailSendMessage implements StreamMessage {
@EqualsAndHashCode(callSuper = true)
public class SysMailSendMessage extends AbstractStreamMessage {
/**
* 邮箱地址

View File

@ -1,13 +1,17 @@
package cn.iocoder.yudao.adminserver.modules.system.mq.message.permission;
import cn.iocoder.yudao.framework.mq.core.pubsub.ChannelMessage;
import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 菜单数据刷新 Message
*
* @author 芋道源码
*/
@Data
public class SysMenuRefreshMessage implements ChannelMessage {
@EqualsAndHashCode(callSuper = true)
public class SysMenuRefreshMessage extends AbstractChannelMessage {
@Override
public String getChannel() {

View File

@ -1,13 +1,17 @@
package cn.iocoder.yudao.adminserver.modules.system.mq.message.permission;
import cn.iocoder.yudao.framework.mq.core.pubsub.ChannelMessage;
import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 角色与菜单数据刷新 Message
*
* @author 芋道源码
*/
@Data
public class SysRoleMenuRefreshMessage implements ChannelMessage {
@EqualsAndHashCode(callSuper = true)
public class SysRoleMenuRefreshMessage extends AbstractChannelMessage {
@Override
public String getChannel() {

View File

@ -1,13 +1,17 @@
package cn.iocoder.yudao.adminserver.modules.system.mq.message.permission;
import cn.iocoder.yudao.framework.mq.core.pubsub.ChannelMessage;
import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 角色数据刷新 Message
*
* @author 芋道源码
*/
@Data
public class SysRoleRefreshMessage implements ChannelMessage {
@EqualsAndHashCode(callSuper = true)
public class SysRoleRefreshMessage extends AbstractChannelMessage {
@Override
public String getChannel() {

View File

@ -1,13 +1,17 @@
package cn.iocoder.yudao.adminserver.modules.system.mq.message.sms;
import cn.iocoder.yudao.framework.mq.core.pubsub.ChannelMessage;
import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 短信渠道的数据刷新 Message
*
* @author 芋道源码
*/
@Data
public class SysSmsChannelRefreshMessage implements ChannelMessage {
@EqualsAndHashCode(callSuper = true)
public class SysSmsChannelRefreshMessage extends AbstractChannelMessage {
@Override
public String getChannel() {

View File

@ -1,13 +1,17 @@
package cn.iocoder.yudao.adminserver.modules.system.mq.message.sms;
import cn.iocoder.yudao.framework.mq.core.pubsub.ChannelMessage;
import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 短信模板的数据刷新 Message
*
* @author 芋道源码
*/
@Data
public class SysSmsTemplateRefreshMessage implements ChannelMessage {
@EqualsAndHashCode(callSuper = true)
public class SysSmsTemplateRefreshMessage extends AbstractChannelMessage {
@Override
public String getChannel() {

View File

@ -1,8 +1,7 @@
package cn.iocoder.yudao.adminserver.modules.system.mq.producer.dept;
import cn.iocoder.yudao.framework.mq.core.util.RedisMessageUtils;
import cn.iocoder.yudao.adminserver.modules.system.mq.message.dept.SysDeptRefreshMessage;
import org.springframework.data.redis.core.StringRedisTemplate;
import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@ -14,14 +13,14 @@ import javax.annotation.Resource;
public class SysDeptProducer {
@Resource
private StringRedisTemplate stringRedisTemplate;
private RedisMQTemplate redisMQTemplate;
/**
* 发送 {@link SysDeptRefreshMessage} 消息
*/
public void sendDeptRefreshMessage() {
SysDeptRefreshMessage message = new SysDeptRefreshMessage();
RedisMessageUtils.sendChannelMessage(stringRedisTemplate, message);
redisMQTemplate.send(message);
}
}

View File

@ -1,8 +1,7 @@
package cn.iocoder.yudao.adminserver.modules.system.mq.producer.dict;
import cn.iocoder.yudao.framework.mq.core.util.RedisMessageUtils;
import cn.iocoder.yudao.adminserver.modules.system.mq.message.dict.SysDictDataRefreshMessage;
import org.springframework.data.redis.core.StringRedisTemplate;
import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@ -14,14 +13,14 @@ import javax.annotation.Resource;
public class SysDictDataProducer {
@Resource
private StringRedisTemplate stringRedisTemplate;
private RedisMQTemplate redisMQTemplate;
/**
* 发送 {@link SysDictDataRefreshMessage} 消息
*/
public void sendDictDataRefreshMessage() {
SysDictDataRefreshMessage message = new SysDictDataRefreshMessage();
RedisMessageUtils.sendChannelMessage(stringRedisTemplate, message);
redisMQTemplate.send(message);
}
}

View File

@ -1,8 +1,7 @@
package cn.iocoder.yudao.adminserver.modules.system.mq.producer.permission;
import cn.iocoder.yudao.framework.mq.core.util.RedisMessageUtils;
import cn.iocoder.yudao.adminserver.modules.system.mq.message.permission.SysMenuRefreshMessage;
import org.springframework.data.redis.core.StringRedisTemplate;
import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@ -14,14 +13,14 @@ import javax.annotation.Resource;
public class SysMenuProducer {
@Resource
private StringRedisTemplate stringRedisTemplate;
private RedisMQTemplate redisMQTemplate;
/**
* 发送 {@link SysMenuRefreshMessage} 消息
*/
public void sendMenuRefreshMessage() {
SysMenuRefreshMessage message = new SysMenuRefreshMessage();
RedisMessageUtils.sendChannelMessage(stringRedisTemplate, message);
redisMQTemplate.send(message);
}
}

View File

@ -1,8 +1,7 @@
package cn.iocoder.yudao.adminserver.modules.system.mq.producer.permission;
import cn.iocoder.yudao.framework.mq.core.util.RedisMessageUtils;
import cn.iocoder.yudao.adminserver.modules.system.mq.message.permission.SysRoleMenuRefreshMessage;
import org.springframework.data.redis.core.StringRedisTemplate;
import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@ -14,14 +13,14 @@ import javax.annotation.Resource;
public class SysPermissionProducer {
@Resource
private StringRedisTemplate stringRedisTemplate;
private RedisMQTemplate redisMQTemplate;
/**
* 发送 {@link SysRoleMenuRefreshMessage} 消息
*/
public void sendRoleMenuRefreshMessage() {
SysRoleMenuRefreshMessage message = new SysRoleMenuRefreshMessage();
RedisMessageUtils.sendChannelMessage(stringRedisTemplate, message);
redisMQTemplate.send(message);
}
}

View File

@ -1,8 +1,7 @@
package cn.iocoder.yudao.adminserver.modules.system.mq.producer.permission;
import cn.iocoder.yudao.framework.mq.core.util.RedisMessageUtils;
import cn.iocoder.yudao.adminserver.modules.system.mq.message.permission.SysRoleRefreshMessage;
import org.springframework.data.redis.core.StringRedisTemplate;
import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@ -16,14 +15,14 @@ import javax.annotation.Resource;
public class SysRoleProducer {
@Resource
private StringRedisTemplate stringRedisTemplate;
private RedisMQTemplate redisMQTemplate;
/**
* 发送 {@link SysRoleRefreshMessage} 消息
*/
public void sendRoleRefreshMessage() {
SysRoleRefreshMessage message = new SysRoleRefreshMessage();
RedisMessageUtils.sendChannelMessage(stringRedisTemplate, message);
redisMQTemplate.send(message);
}
}

View File

@ -1,15 +1,12 @@
package cn.iocoder.yudao.adminserver.modules.system.mq.producer.sms;
import cn.iocoder.yudao.framework.common.core.KeyValue;
import cn.iocoder.yudao.framework.mq.core.util.RedisMessageUtils;
import cn.iocoder.yudao.adminserver.modules.system.mq.message.sms.SysSmsChannelRefreshMessage;
import cn.iocoder.yudao.adminserver.modules.system.mq.message.sms.SysSmsTemplateRefreshMessage;
import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
/**
* Sms 短信相关消息的 Producer
@ -22,14 +19,14 @@ import java.util.List;
public class SysSmsProducer {
@Resource
private StringRedisTemplate stringRedisTemplate;
private RedisMQTemplate redisMQTemplate;
/**
* 发送 {@link SysSmsChannelRefreshMessage} 消息
*/
public void sendSmsChannelRefreshMessage() {
SysSmsChannelRefreshMessage message = new SysSmsChannelRefreshMessage();
RedisMessageUtils.sendChannelMessage(stringRedisTemplate, message);
redisMQTemplate.send(message);
}
/**
@ -37,7 +34,7 @@ public class SysSmsProducer {
*/
public void sendSmsTemplateRefreshMessage() {
SysSmsTemplateRefreshMessage message = new SysSmsTemplateRefreshMessage();
RedisMessageUtils.sendChannelMessage(stringRedisTemplate, message);
redisMQTemplate.send(message);
}
}

View File

@ -92,9 +92,7 @@ public class SysAuthServiceImpl implements SysAuthService {
throw new UsernameNotFoundException(username);
}
// 创建 LoginUser 对象
LoginUser loginUser = SysAuthConvert.INSTANCE.convert(user);
loginUser.setPostIds(user.getPostIds());
return loginUser;
return this.buildLoginUser(user);
}
@Override
@ -107,9 +105,7 @@ public class SysAuthServiceImpl implements SysAuthService {
this.createLoginLog(user.getUsername(), SysLoginLogTypeEnum.LOGIN_MOCK, SysLoginResultEnum.SUCCESS);
// 创建 LoginUser 对象
LoginUser loginUser = SysAuthConvert.INSTANCE.convert(user);
loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId())); // 获取用户角色列表
return loginUser;
return this.buildLoginUser(user);
}
@Override
@ -117,10 +113,9 @@ public class SysAuthServiceImpl implements SysAuthService {
// 判断验证码是否正确
this.verifyCaptcha(reqVO.getUsername(), reqVO.getUuid(), reqVO.getCode());
// 使用账号密码进行登录
// 使用账号密码进行登录
LoginUser loginUser = this.login0(reqVO.getUsername(), reqVO.getPassword());
loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId())); // 获取用户角色列表
loginUser.setGroups(this.getUserPosts(loginUser.getPostIds()));
// 缓存登陆用户到 Redis 返回 sessionId 编号
return userSessionCoreService.createUserSession(loginUser, userIp, userAgent);
}
@ -133,9 +128,13 @@ public class SysAuthServiceImpl implements SysAuthService {
}
private void verifyCaptcha(String username, String captchaUUID, String captchaCode) {
// 如果验证码关闭则不进行校验
if (!captchaService.isCaptchaEnable()) {
return;
}
// 验证码不存在
final SysLoginLogTypeEnum logTypeEnum = SysLoginLogTypeEnum.LOGIN_USERNAME;
String code = captchaService.getCaptchaCode(captchaUUID);
// 验证码不存在
if (code == null) {
// 创建登录失败日志验证码不存在
this.createLoginLog(username, logTypeEnum, SysLoginResultEnum.CAPTCHA_NOT_FOUND);
@ -230,8 +229,7 @@ public class SysAuthServiceImpl implements SysAuthService {
this.createLoginLog(user.getUsername(), SysLoginLogTypeEnum.LOGIN_SOCIAL, SysLoginResultEnum.SUCCESS);
// 创建 LoginUser 对象
LoginUser loginUser = SysAuthConvert.INSTANCE.convert(user);
loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId())); // 获取用户角色列表
LoginUser loginUser = this.buildLoginUser(user);
// 绑定社交用户更新
socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, userTypeEnum);
@ -248,7 +246,6 @@ public class SysAuthServiceImpl implements SysAuthService {
// 使用账号密码进行登录
LoginUser loginUser = this.login0(reqVO.getUsername(), reqVO.getPassword());
loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId())); // 获取用户角色列表
// 绑定社交用户新增
socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, userTypeEnum);
@ -301,15 +298,14 @@ public class SysAuthServiceImpl implements SysAuthService {
return null;
}
// 刷新 LoginUser 缓存
this.refreshLoginUserCache(token, loginUser);
return loginUser;
return this.refreshLoginUserCache(token, loginUser);
}
private void refreshLoginUserCache(String token, LoginUser loginUser) {
private LoginUser refreshLoginUserCache(String token, LoginUser loginUser) {
// 1/3 Session 超时时间刷新 LoginUser 缓存
if (System.currentTimeMillis() - loginUser.getUpdateTime().getTime() <
userSessionCoreService.getSessionTimeoutMillis() / 3) {
return;
return loginUser;
}
// 重新加载 SysUserDO 信息
@ -319,9 +315,18 @@ public class SysAuthServiceImpl implements SysAuthService {
}
// 刷新 LoginUser 缓存
LoginUser newLoginUser= this.buildLoginUser(user);
userSessionCoreService.refreshUserSession(token, newLoginUser);
return newLoginUser;
}
private LoginUser buildLoginUser(SysUserDO user) {
LoginUser loginUser = SysAuthConvert.INSTANCE.convert(user);
// 补全字段
loginUser.setDeptId(user.getDeptId());
loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId()));
userSessionCoreService.refreshUserSession(token, loginUser);
loginUser.setGroups(this.getUserPosts(user.getPostIds()));
return loginUser;
}
}

View File

@ -14,6 +14,13 @@ public interface SysCaptchaService {
*/
SysCaptchaImageRespVO getCaptchaImage();
/**
* 是否开启图片验证码
*
* @return 是否
*/
Boolean isCaptchaEnable();
/**
* 获得 uuid 对应的验证码
*

View File

@ -35,6 +35,11 @@ public class SysCaptchaServiceImpl implements SysCaptchaService {
return SysCaptchaConvert.INSTANCE.convert(uuid, captcha);
}
@Override
public Boolean isCaptchaEnable() {
return captchaProperties.getEnable();
}
@Override
public String getCaptchaCode(String uuid) {
return captchaRedisDAO.get(uuid);

View File

@ -169,9 +169,12 @@ public class SysDeptServiceImpl implements SysDeptService {
@Override
public List<SysDeptDO> getDeptsByParentIdFromCache(Long parentId, boolean recursive) {
List<SysDeptDO> result = new ArrayList<>();
if (parentId == null) {
return Collections.emptyList();
}
List<SysDeptDO> result = new ArrayList<>(); // TODO 芋艿待优化新增缓存避免每次遍历的计算
// 递归简单粗暴
this.listDeptsByParentIdFromCache(result, parentId,
this.getDeptsByParentIdFromCache(result, parentId,
recursive ? Integer.MAX_VALUE : 1, // 如果递归获取则无限否则只递归 1
parentDeptCache);
return result;
@ -185,8 +188,8 @@ public class SysDeptServiceImpl implements SysDeptService {
* @param recursiveCount 递归次数
* @param parentDeptMap 父部门 Map使用缓存避免变化
*/
private void listDeptsByParentIdFromCache(List<SysDeptDO> result, Long parentId, int recursiveCount,
Multimap<Long, SysDeptDO> parentDeptMap) {
private void getDeptsByParentIdFromCache(List<SysDeptDO> result, Long parentId, int recursiveCount,
Multimap<Long, SysDeptDO> parentDeptMap) {
// 递归次数为 0结束
if (recursiveCount == 0) {
return;
@ -198,7 +201,7 @@ public class SysDeptServiceImpl implements SysDeptService {
}
result.addAll(depts);
// 继续递归
depts.forEach(dept -> listDeptsByParentIdFromCache(result, dept.getId(),
depts.forEach(dept -> getDeptsByParentIdFromCache(result, dept.getId(),
recursiveCount - 1, parentDeptMap));
}

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.adminserver.modules.system.service.permission;
import cn.iocoder.yudao.framework.datapermission.core.dept.service.DeptDataPermissionFrameworkService;
import cn.iocoder.yudao.framework.security.core.service.SecurityPermissionFrameworkService;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysMenuDO;
import org.springframework.lang.Nullable;
@ -15,7 +16,7 @@ import java.util.Set;
*
* @author 芋道源码
*/
public interface SysPermissionService extends SecurityPermissionFrameworkService {
public interface SysPermissionService extends SecurityPermissionFrameworkService, DeptDataPermissionFrameworkService {
/**
* 初始化权限的本地缓存

View File

@ -3,19 +3,25 @@ package cn.iocoder.yudao.adminserver.modules.system.service.permission.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.permission.SysRoleMenuMapper;
import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.permission.SysUserRoleMapper;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept.SysDeptDO;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysMenuDO;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysRoleDO;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysRoleMenuDO;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysUserRoleDO;
import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.permission.SysRoleMenuMapper;
import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.permission.SysUserRoleMapper;
import cn.iocoder.yudao.adminserver.modules.system.mq.producer.permission.SysPermissionProducer;
import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysDeptService;
import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysMenuService;
import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermissionService;
import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysRoleService;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.enums.DataScopeEnum;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
@ -39,6 +45,11 @@ import java.util.*;
@Slf4j
public class SysPermissionServiceImpl implements SysPermissionService {
/**
* LoginUser Context 缓存 Key
*/
public static final String CONTEXT_KEY = SysPermissionServiceImpl.class.getSimpleName();
/**
* 定时执行 {@link #schedulePeriodicRefresh()} 的周期
* 因为已经通过 Redis Pub/Sub 机制所以频率不需要高
@ -75,6 +86,8 @@ public class SysPermissionServiceImpl implements SysPermissionService {
private SysRoleService roleService;
@Resource
private SysMenuService menuService;
@Resource
private SysDeptService deptService;
@Resource
private SysPermissionProducer permissionProducer;
@ -329,4 +342,58 @@ public class SysPermissionServiceImpl implements SysPermissionService {
return CollUtil.containsAny(userRoles, Sets.newHashSet(roles));
}
@Override
public DeptDataPermissionRespDTO getDeptDataPermission(LoginUser loginUser) {
// 判断是否 context 已经缓存
DeptDataPermissionRespDTO result = loginUser.getContext(CONTEXT_KEY, DeptDataPermissionRespDTO.class);
if (result != null) {
return result;
}
// 创建 DeptDataPermissionRespDTO 对象
result = new DeptDataPermissionRespDTO();
List<SysRoleDO> roles = roleService.getRolesFromCache(loginUser.getRoleIds());
for (SysRoleDO role : roles) {
// 为空时跳过
if (role.getDataScope() == null) {
continue;
}
// 情况一ALL
if (Objects.equals(role.getDataScope(), DataScopeEnum.ALL.getScope())) {
result.setAll(true);
continue;
}
// 情况二DEPT_CUSTOM
if (Objects.equals(role.getDataScope(), DataScopeEnum.DEPT_CUSTOM.getScope())) {
CollUtil.addAll(result.getDeptIds(), role.getDataScopeDeptIds());
// 自定义可见部门时保证可以看到自己所在的部门否则一些场景下可能会有问题
// 例如说登录时基于 t_user username 查询会可能被 dept_id 过滤掉
CollUtil.addAll(result.getDeptIds(), loginUser.getDeptId());
continue;
}
// 情况三DEPT_ONLY
if (Objects.equals(role.getDataScope(), DataScopeEnum.DEPT_ONLY.getScope())) {
CollectionUtils.addIfNotNull(result.getDeptIds(), loginUser.getDeptId());
continue;
}
// 情况四DEPT_DEPT_AND_CHILD
if (Objects.equals(role.getDataScope(), DataScopeEnum.DEPT_AND_CHILD.getScope())) {
List<SysDeptDO> depts = deptService.getDeptsByParentIdFromCache(loginUser.getDeptId(), true);
CollUtil.addAll(result.getDeptIds(), CollectionUtils.convertList(depts, SysDeptDO::getId));
continue;
}
// 情况五SELF
if (Objects.equals(role.getDataScope(), DataScopeEnum.SELF.getScope())) {
result.setSelf(true);
continue;
}
// 未知情况error log 即可
log.error("[getDeptDataPermission][LoginUser({}) role({}) 无法处理]", loginUser.getId(), JsonUtils.toJsonString(result));
}
// 添加到缓存并返回
loginUser.setContext(CONTEXT_KEY, result);
return result;
}
}

View File

@ -18,6 +18,7 @@ import cn.iocoder.yudao.adminserver.modules.system.enums.permission.SysRoleTypeE
import cn.iocoder.yudao.adminserver.modules.system.mq.producer.permission.SysRoleProducer;
import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermissionService;
import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysRoleService;
import cn.iocoder.yudao.framework.security.core.enums.DataScopeEnum;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap;
import lombok.extern.slf4j.Slf4j;
@ -127,6 +128,7 @@ public class SysRoleServiceImpl implements SysRoleService {
SysRoleDO role = SysRoleConvert.INSTANCE.convert(reqVO);
role.setType(SysRoleTypeEnum.CUSTOM.getType());
role.setStatus(CommonStatusEnum.ENABLE.getStatus());
role.setDataScope(DataScopeEnum.ALL.getScope()); // 默认可查看所有数据原因是可能一些项目不需要项目权限
roleMapper.insert(role);
// 发送刷新消息
roleProducer.sendRoleRefreshMessage();

View File

@ -0,0 +1,83 @@
package cn.iocoder.yudao.adminserver.modules.system.service.tenant;
import cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo.SysTenantCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo.SysTenantExportReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo.SysTenantPageReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo.SysTenantUpdateReqVO;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.tenant.SysTenantDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import javax.validation.Valid;
import java.util.Collection;
import java.util.List;
/**
* 租户 Service 接口
*
* @author 芋道源码
*/
public interface SysTenantService {
/**
* 创建租户
*
* @param createReqVO 创建信息
* @return 编号
*/
Long createTenant(@Valid SysTenantCreateReqVO createReqVO);
/**
* 更新租户
*
* @param updateReqVO 更新信息
*/
void updateTenant(@Valid SysTenantUpdateReqVO updateReqVO);
/**
* 删除租户
*
* @param id 编号
*/
void deleteTenant(Long id);
/**
* 获得租户
*
* @param id 编号
* @return 租户
*/
SysTenantDO getTenant(Long id);
/**
* 获得租户列表
*
* @param ids 编号
* @return 租户列表
*/
List<SysTenantDO> getTenantList(Collection<Long> ids);
/**
* 获得租户分页
*
* @param pageReqVO 分页查询
* @return 租户分页
*/
PageResult<SysTenantDO> getTenantPage(SysTenantPageReqVO pageReqVO);
/**
* 获得租户列表, 用于 Excel 导出
*
* @param exportReqVO 查询条件
* @return 租户列表
*/
List<SysTenantDO> getTenantList(SysTenantExportReqVO exportReqVO);
/**
* 获得名字对应的租户
*
* @param name 组户名
* @return 租户
*/
SysTenantDO getTenantByName(String name);
}

View File

@ -0,0 +1,91 @@
package cn.iocoder.yudao.adminserver.modules.system.service.tenant.impl;
import cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo.SysTenantCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo.SysTenantExportReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo.SysTenantPageReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo.SysTenantUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.convert.tenant.SysTenantConvert;
import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.tenant.SysTenantMapper;
import cn.iocoder.yudao.adminserver.modules.system.service.tenant.SysTenantService;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.tenant.SysTenantDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
import static cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants.TENANT_NOT_EXISTS;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
/**
* 租户 Service 实现类
*
* @author 芋道源码
*/
@Service
@Validated
public class SysTenantServiceImpl implements SysTenantService {
@Resource
private SysTenantMapper tenantMapper;
@Override
public Long createTenant(SysTenantCreateReqVO createReqVO) {
// 插入
SysTenantDO tenant = SysTenantConvert.INSTANCE.convert(createReqVO);
tenantMapper.insert(tenant);
// 返回
return tenant.getId();
}
@Override
public void updateTenant(SysTenantUpdateReqVO updateReqVO) {
// 校验存在
this.validateTenantExists(updateReqVO.getId());
// 更新
SysTenantDO updateObj = SysTenantConvert.INSTANCE.convert(updateReqVO);
tenantMapper.updateById(updateObj);
}
@Override
public void deleteTenant(Long id) {
// 校验存在
this.validateTenantExists(id);
// 删除
tenantMapper.deleteById(id);
}
private void validateTenantExists(Long id) {
if (tenantMapper.selectById(id) == null) {
throw exception(TENANT_NOT_EXISTS);
}
}
@Override
public SysTenantDO getTenant(Long id) {
return tenantMapper.selectById(id);
}
@Override
public List<SysTenantDO> getTenantList(Collection<Long> ids) {
return tenantMapper.selectBatchIds(ids);
}
@Override
public PageResult<SysTenantDO> getTenantPage(SysTenantPageReqVO pageReqVO) {
return tenantMapper.selectPage(pageReqVO);
}
@Override
public List<SysTenantDO> getTenantList(SysTenantExportReqVO exportReqVO) {
return tenantMapper.selectList(exportReqVO);
}
@Override
public SysTenantDO getTenantByName(String name) {
return tenantMapper.selectByName(name);
}
}

View File

@ -10,6 +10,7 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.adminserver.modules.system.framework.codegen.config.CodegenProperties;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
@ -119,6 +120,8 @@ public class ToolCodegenEngine {
private void initGlobalBindingMap() {
// 全局配置
globalBindingMap.put("basePackage", codegenProperties.getBasePackage());
globalBindingMap.put("baseFrameworkPackage", StrUtil.subBefore(codegenProperties.getBasePackage(),
'.', true) + '.' + "framework");
// 全局 Java Bean
globalBindingMap.put("CommonResultClassName", CommonResult.class.getName());
globalBindingMap.put("PageResultClassName", PageResult.class.getName());
@ -134,6 +137,7 @@ public class ToolCodegenEngine {
globalBindingMap.put("ServiceExceptionUtilClassName", ServiceExceptionUtil.class.getName());
globalBindingMap.put("DateUtilsClassName", DateUtils.class.getName());
globalBindingMap.put("ExcelUtilsClassName", ExcelUtils.class.getName());
globalBindingMap.put("ObjectUtilsClassName", ObjectUtils.class.getName());
globalBindingMap.put("DictConvertClassName", DictConvert.class.getName());
globalBindingMap.put("OperateLogClassName", OperateLog.class.getName());
globalBindingMap.put("OperateTypeEnumClassName", OperateTypeEnum.class.getName());

View File

@ -66,6 +66,7 @@ spring:
# Quartz 配置项,对应 QuartzProperties 配置类
spring:
quartz:
auto-startup: true # 测试环境,需要开启 Job
scheduler-name: schedulerName # Scheduler 名字。默认为 schedulerName
job-store-type: jdbc # Job 存储器类型。默认为 memory 表示内存,可选 jdbc 使用数据库。
wait-for-jobs-to-complete-on-shutdown: true # 应用关闭时,是否等待定时任务执行完成。默认为 false ,建议设置为 true

View File

@ -80,6 +80,7 @@ spring:
# Quartz 配置项,对应 QuartzProperties 配置类
spring:
quartz:
auto-startup: false # 本地开发环境,尽量不要开启 Job
scheduler-name: schedulerName # Scheduler 名字。默认为 schedulerName
job-store-type: jdbc # Job 存储器类型。默认为 memory 表示内存,可选 jdbc 使用数据库。
wait-for-jobs-to-complete-on-shutdown: true # 应用关闭时,是否等待定时任务执行完成。默认为 false ,建议设置为 true
@ -166,6 +167,8 @@ logging:
# 芋道配置项,设置当前项目所有自定义的配置
yudao:
captcha:
enable: false # 本地环境,暂时关闭图片验证码,方便登录等接口的测试
security:
token-header: Authorization
token-secret: abcdefghijklmnopqrstuvwxyz

View File

@ -22,7 +22,7 @@ spring:
# MyBatis Plus 的配置项
mybatis-plus:
# 在 mybatis-config/mybatis-config.xml 中设置
# 在 mybatis-config/mybatis-config.xml 中设置 TODO jason看看有没其它解决方案
# configuration:
# map-underscore-to-camel-case: true # 虽然默认为 true ,但是还是显示去指定下。
# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印日志
@ -73,5 +73,7 @@ yudao:
constants-class-list:
- cn.iocoder.yudao.adminserver.modules.infra.enums.InfErrorCodeConstants
- cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants
tenant: # 多租户相关配置项
tables: # 配置需要开启多租户的表;如果实体已经继承 TenantBaseDO 类,则无需重复配置
debug: false

View File

@ -10,7 +10,6 @@ import ${basePackage}.modules.${table.moduleName}.service.${table.businessName}.
import ${basePackage}.modules.${table.moduleName}.controller.${table.businessName}.vo.*;
import ${basePackage}.modules.${table.moduleName}.dal.dataobject.${table.businessName}.${table.className}DO;
import ${basePackage}.modules.${table.moduleName}.dal.mysql.${table.businessName}.${table.className}Mapper;
import ${basePackage}.util.object.ObjectUtils;
import ${PageResultClassName};
import javax.annotation.Resource;
@ -19,9 +18,10 @@ import java.util.*;
import static cn.hutool.core.util.RandomUtil.*;
import static ${basePackage}.modules.${table.moduleName}.enums.${simpleModuleName_upperFirst}ErrorCodeConstants.*;
import static ${basePackage}.util.AssertUtils.*;
import static ${basePackage}.util.RandomUtils.*;
import static ${basePackage}.util.date.DateUtils.*;
import static ${baseFrameworkPackage}.test.core.util.AssertUtils.*;
import static ${baseFrameworkPackage}.test.core.util.RandomUtils.*;
import static ${ObjectUtilsClassName}.*;
import static ${DateUtilsClassName}.*;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
@ -41,7 +41,7 @@ import static org.mockito.Mockito.*;
#if (${column.listOperation})
#set ($JavaField = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})##首字母大写
// 测试 ${column.javaField} 不匹配
${classNameVar}Mapper.insert(ObjectUtils.clone(db${simpleClassName}, o -> o.set$JavaField(null)));
${classNameVar}Mapper.insert(cloneIgnoreId(db${simpleClassName}, o -> o.set$JavaField(null)));
#end
#end
// 准备参数

View File

@ -6,6 +6,7 @@
<settings>
<setting name="lazyLoadingEnabled" value="false" />
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="logImpl" value="org.apache.ibatis.logging.stdout.StdOutImpl"/> <!-- 如果不想打 SQL 日志,可以注释掉 -->
</settings>
<typeAliases>
<typeAlias type="org.activiti.engine.impl.persistence.ByteArrayRefTypeHandler" alias="ByteArrayRefTypeHandler"/>

View File

@ -172,13 +172,13 @@ public class InfConfigServiceTest extends BaseDbUnitTest {
});
configMapper.insert(dbConfig);
// 测试 name 不匹配
configMapper.insert(ObjectUtils.clone(dbConfig, o -> o.setName("土豆")));
configMapper.insert(ObjectUtils.cloneIgnoreId(dbConfig, o -> o.setName("土豆")));
// 测试 key 不匹配
configMapper.insert(ObjectUtils.clone(dbConfig, o -> o.setKey("tudou")));
configMapper.insert(ObjectUtils.cloneIgnoreId(dbConfig, o -> o.setKey("tudou")));
// 测试 type 不匹配
configMapper.insert(ObjectUtils.clone(dbConfig, o -> o.setType(InfConfigTypeEnum.CUSTOM.getType())));
configMapper.insert(ObjectUtils.cloneIgnoreId(dbConfig, o -> o.setType(InfConfigTypeEnum.CUSTOM.getType())));
// 测试 createTime 不匹配
configMapper.insert(ObjectUtils.clone(dbConfig, o -> o.setCreateTime(buildTime(2021, 1, 1))));
configMapper.insert(ObjectUtils.cloneIgnoreId(dbConfig, o -> o.setCreateTime(buildTime(2021, 1, 1))));
// 准备参数
InfConfigPageReqVO reqVO = new InfConfigPageReqVO();
reqVO.setName("");
@ -206,13 +206,13 @@ public class InfConfigServiceTest extends BaseDbUnitTest {
});
configMapper.insert(dbConfig);
// 测试 name 不匹配
configMapper.insert(ObjectUtils.clone(dbConfig, o -> o.setName("土豆")));
configMapper.insert(ObjectUtils.cloneIgnoreId(dbConfig, o -> o.setName("土豆")));
// 测试 key 不匹配
configMapper.insert(ObjectUtils.clone(dbConfig, o -> o.setKey("tudou")));
configMapper.insert(ObjectUtils.cloneIgnoreId(dbConfig, o -> o.setKey("tudou")));
// 测试 type 不匹配
configMapper.insert(ObjectUtils.clone(dbConfig, o -> o.setType(InfConfigTypeEnum.CUSTOM.getType())));
configMapper.insert(ObjectUtils.cloneIgnoreId(dbConfig, o -> o.setType(InfConfigTypeEnum.CUSTOM.getType())));
// 测试 createTime 不匹配
configMapper.insert(ObjectUtils.clone(dbConfig, o -> o.setCreateTime(buildTime(2021, 1, 1))));
configMapper.insert(ObjectUtils.cloneIgnoreId(dbConfig, o -> o.setCreateTime(buildTime(2021, 1, 1))));
// 准备参数
InfConfigExportReqVO reqVO = new InfConfigExportReqVO();
reqVO.setName("");

View File

@ -41,14 +41,14 @@ public class InfFileServiceTest extends BaseDbUnitTest {
});
fileMapper.insert(dbFile);
// 测试 id 不匹配
fileMapper.insert(ObjectUtils.clone(dbFile, o -> o.setId("tudou")));
fileMapper.insert(ObjectUtils.cloneIgnoreId(dbFile, o -> o.setId("tudou")));
// 测试 type 不匹配
fileMapper.insert(ObjectUtils.clone(dbFile, o -> {
fileMapper.insert(ObjectUtils.cloneIgnoreId(dbFile, o -> {
o.setId("yudao02");
o.setType("png");
}));
// 测试 createTime 不匹配
fileMapper.insert(ObjectUtils.clone(dbFile, o -> {
fileMapper.insert(ObjectUtils.cloneIgnoreId(dbFile, o -> {
o.setId("yudao03");
o.setCreateTime(buildTime(2020, 1, 15));
}));

View File

@ -84,7 +84,7 @@ public class InfJobLogServiceTest extends BaseDbUnitTest {
o.setExecuteIndex(1);
o.setStatus(randomEle(InfJobLogStatusEnum.values()).getStatus()); // 保证 status 的范围
});
InfJobLogDO cloneJobLog = ObjectUtils.clone(dbJobLog, o -> o.setHandlerName(randomString()));
InfJobLogDO cloneJobLog = ObjectUtils.cloneIgnoreId(dbJobLog, o -> o.setHandlerName(randomString()));
jobLogMapper.insert(dbJobLog);
// 测试 handlerName 不匹配
jobLogMapper.insert(cloneJobLog);
@ -111,15 +111,15 @@ public class InfJobLogServiceTest extends BaseDbUnitTest {
});
jobLogMapper.insert(dbJobLog);
// 测试 jobId 不匹配
jobLogMapper.insert(ObjectUtils.clone(dbJobLog, o -> o.setJobId(randomLongId())));
jobLogMapper.insert(ObjectUtils.cloneIgnoreId(dbJobLog, o -> o.setJobId(randomLongId())));
// 测试 handlerName 不匹配
jobLogMapper.insert(ObjectUtils.clone(dbJobLog, o -> o.setHandlerName(randomString())));
jobLogMapper.insert(ObjectUtils.cloneIgnoreId(dbJobLog, o -> o.setHandlerName(randomString())));
// 测试 beginTime 不匹配
jobLogMapper.insert(ObjectUtils.clone(dbJobLog, o -> o.setBeginTime(buildTime(2021, 1, 7))));
jobLogMapper.insert(ObjectUtils.cloneIgnoreId(dbJobLog, o -> o.setBeginTime(buildTime(2021, 1, 7))));
// 测试 endTime 不匹配
jobLogMapper.insert(ObjectUtils.clone(dbJobLog, o -> o.setEndTime(buildTime(2021, 1, 9))));
jobLogMapper.insert(ObjectUtils.cloneIgnoreId(dbJobLog, o -> o.setEndTime(buildTime(2021, 1, 9))));
// 测试 status 不匹配
jobLogMapper.insert(ObjectUtils.clone(dbJobLog, o -> o.setStatus(InfJobLogStatusEnum.FAILURE.getStatus())));
jobLogMapper.insert(ObjectUtils.cloneIgnoreId(dbJobLog, o -> o.setStatus(InfJobLogStatusEnum.FAILURE.getStatus())));
// 准备参数
InfJobLogPageReqVO reqVo = new InfJobLogPageReqVO();
reqVo.setJobId(dbJobLog.getJobId());
@ -147,15 +147,15 @@ public class InfJobLogServiceTest extends BaseDbUnitTest {
});
jobLogMapper.insert(dbJobLog);
// 测试 jobId 不匹配
jobLogMapper.insert(ObjectUtils.clone(dbJobLog, o -> o.setJobId(randomLongId())));
jobLogMapper.insert(ObjectUtils.cloneIgnoreId(dbJobLog, o -> o.setJobId(randomLongId())));
// 测试 handlerName 不匹配
jobLogMapper.insert(ObjectUtils.clone(dbJobLog, o -> o.setHandlerName(randomString())));
jobLogMapper.insert(ObjectUtils.cloneIgnoreId(dbJobLog, o -> o.setHandlerName(randomString())));
// 测试 beginTime 不匹配
jobLogMapper.insert(ObjectUtils.clone(dbJobLog, o -> o.setBeginTime(buildTime(2021, 1, 7))));
jobLogMapper.insert(ObjectUtils.cloneIgnoreId(dbJobLog, o -> o.setBeginTime(buildTime(2021, 1, 7))));
// 测试 endTime 不匹配
jobLogMapper.insert(ObjectUtils.clone(dbJobLog, o -> o.setEndTime(buildTime(2021, 1, 9))));
jobLogMapper.insert(ObjectUtils.cloneIgnoreId(dbJobLog, o -> o.setEndTime(buildTime(2021, 1, 9))));
// 测试 status 不匹配
jobLogMapper.insert(ObjectUtils.clone(dbJobLog, o -> o.setStatus(InfJobLogStatusEnum.FAILURE.getStatus())));
jobLogMapper.insert(ObjectUtils.cloneIgnoreId(dbJobLog, o -> o.setStatus(InfJobLogStatusEnum.FAILURE.getStatus())));
// 准备参数
InfJobLogExportReqVO reqVo = new InfJobLogExportReqVO();
reqVo.setJobId(dbJobLog.getJobId());

View File

@ -230,7 +230,7 @@ public class InfJobServiceTest extends BaseDbUnitTest {
InfJobDO dbJob = randomPojo(InfJobDO.class, o -> {
o.setStatus(randomEle(InfJobStatusEnum.values()).getStatus()); // 保证 status 的范围
});
InfJobDO cloneJob = ObjectUtils.clone(dbJob, o -> o.setHandlerName(randomString()));
InfJobDO cloneJob = ObjectUtils.cloneIgnoreId(dbJob, o -> o.setHandlerName(randomString()));
jobMapper.insert(dbJob);
// 测试 handlerName 不匹配
jobMapper.insert(cloneJob);
@ -255,11 +255,11 @@ public class InfJobServiceTest extends BaseDbUnitTest {
});
jobMapper.insert(dbJob);
// 测试 name 不匹配
jobMapper.insert(ObjectUtils.clone(dbJob, o -> o.setName("土豆")));
jobMapper.insert(ObjectUtils.cloneIgnoreId(dbJob, o -> o.setName("土豆")));
// 测试 status 不匹配
jobMapper.insert(ObjectUtils.clone(dbJob, o -> o.setStatus(InfJobStatusEnum.NORMAL.getStatus())));
jobMapper.insert(ObjectUtils.cloneIgnoreId(dbJob, o -> o.setStatus(InfJobStatusEnum.NORMAL.getStatus())));
// 测试 handlerName 不匹配
jobMapper.insert(ObjectUtils.clone(dbJob, o -> o.setHandlerName(randomString())));
jobMapper.insert(ObjectUtils.cloneIgnoreId(dbJob, o -> o.setHandlerName(randomString())));
// 准备参数
InfJobPageReqVO reqVo = new InfJobPageReqVO();
reqVo.setName("定时");
@ -283,11 +283,11 @@ public class InfJobServiceTest extends BaseDbUnitTest {
});
jobMapper.insert(dbJob);
// 测试 name 不匹配
jobMapper.insert(ObjectUtils.clone(dbJob, o -> o.setName("土豆")));
jobMapper.insert(ObjectUtils.cloneIgnoreId(dbJob, o -> o.setName("土豆")));
// 测试 status 不匹配
jobMapper.insert(ObjectUtils.clone(dbJob, o -> o.setStatus(InfJobStatusEnum.NORMAL.getStatus())));
jobMapper.insert(ObjectUtils.cloneIgnoreId(dbJob, o -> o.setStatus(InfJobStatusEnum.NORMAL.getStatus())));
// 测试 handlerName 不匹配
jobMapper.insert(ObjectUtils.clone(dbJob, o -> o.setHandlerName(randomString())));
jobMapper.insert(ObjectUtils.cloneIgnoreId(dbJob, o -> o.setHandlerName(randomString())));
// 准备参数
InfJobExportReqVO reqVo = new InfJobExportReqVO();
reqVo.setName("定时");

View File

@ -59,19 +59,19 @@ public class InfApiAccessLogServiceImplTest extends BaseDbUnitTest {
// 下面几个都是不匹配的数据
// userId 不同的
infApiAccessLogMapper.insert(ObjectUtils.clone(infApiAccessLogDO, logDO -> logDO.setUserId(3344L)));
infApiAccessLogMapper.insert(ObjectUtils.cloneIgnoreId(infApiAccessLogDO, logDO -> logDO.setUserId(3344L)));
// userType
infApiAccessLogMapper.insert(ObjectUtils.clone(infApiAccessLogDO, logDO -> logDO.setUserType(UserTypeEnum.MEMBER.getValue())));
infApiAccessLogMapper.insert(ObjectUtils.cloneIgnoreId(infApiAccessLogDO, logDO -> logDO.setUserType(UserTypeEnum.MEMBER.getValue())));
// applicationName 不同的
infApiAccessLogMapper.insert(ObjectUtils.clone(infApiAccessLogDO, logDO -> logDO.setApplicationName("test")));
infApiAccessLogMapper.insert(ObjectUtils.cloneIgnoreId(infApiAccessLogDO, logDO -> logDO.setApplicationName("test")));
// requestUrl 不同的
infApiAccessLogMapper.insert(ObjectUtils.clone(infApiAccessLogDO, logDO -> logDO.setRequestUrl("bar")));
infApiAccessLogMapper.insert(ObjectUtils.cloneIgnoreId(infApiAccessLogDO, logDO -> logDO.setRequestUrl("bar")));
// 构造一个早期时间 2021-02-06 00:00:00
infApiAccessLogMapper.insert(ObjectUtils.clone(infApiAccessLogDO, logDO -> logDO.setBeginTime(buildTime(2021, 2, 6))));
infApiAccessLogMapper.insert(ObjectUtils.cloneIgnoreId(infApiAccessLogDO, logDO -> logDO.setBeginTime(buildTime(2021, 2, 6))));
// duration 不同的
infApiAccessLogMapper.insert(ObjectUtils.clone(infApiAccessLogDO, logDO -> logDO.setDuration(100)));
infApiAccessLogMapper.insert(ObjectUtils.cloneIgnoreId(infApiAccessLogDO, logDO -> logDO.setDuration(100)));
// resultCode 不同的
infApiAccessLogMapper.insert(ObjectUtils.clone(infApiAccessLogDO, logDO -> logDO.setResultCode(2)));
infApiAccessLogMapper.insert(ObjectUtils.cloneIgnoreId(infApiAccessLogDO, logDO -> logDO.setResultCode(2)));
// 构造调用参数
InfApiAccessLogPageReqVO reqVO = new InfApiAccessLogPageReqVO();
@ -117,19 +117,19 @@ public class InfApiAccessLogServiceImplTest extends BaseDbUnitTest {
// 下面几个都是不匹配的数据
// userId 不同的
infApiAccessLogMapper.insert(ObjectUtils.clone(infApiAccessLogDO, logDO -> logDO.setUserId(3344L)));
infApiAccessLogMapper.insert(ObjectUtils.cloneIgnoreId(infApiAccessLogDO, logDO -> logDO.setUserId(3344L)));
// userType
infApiAccessLogMapper.insert(ObjectUtils.clone(infApiAccessLogDO, logDO -> logDO.setUserType(UserTypeEnum.MEMBER.getValue())));
infApiAccessLogMapper.insert(ObjectUtils.cloneIgnoreId(infApiAccessLogDO, logDO -> logDO.setUserType(UserTypeEnum.MEMBER.getValue())));
// applicationName 不同的
infApiAccessLogMapper.insert(ObjectUtils.clone(infApiAccessLogDO, logDO -> logDO.setApplicationName("test")));
infApiAccessLogMapper.insert(ObjectUtils.cloneIgnoreId(infApiAccessLogDO, logDO -> logDO.setApplicationName("test")));
// requestUrl 不同的
infApiAccessLogMapper.insert(ObjectUtils.clone(infApiAccessLogDO, logDO -> logDO.setRequestUrl("bar")));
infApiAccessLogMapper.insert(ObjectUtils.cloneIgnoreId(infApiAccessLogDO, logDO -> logDO.setRequestUrl("bar")));
// 构造一个早期时间 2021-02-06 00:00:00
infApiAccessLogMapper.insert(ObjectUtils.clone(infApiAccessLogDO, logDO -> logDO.setBeginTime(buildTime(2021, 2, 6))));
infApiAccessLogMapper.insert(ObjectUtils.cloneIgnoreId(infApiAccessLogDO, logDO -> logDO.setBeginTime(buildTime(2021, 2, 6))));
// duration 不同的
infApiAccessLogMapper.insert(ObjectUtils.clone(infApiAccessLogDO, logDO -> logDO.setDuration(100)));
infApiAccessLogMapper.insert(ObjectUtils.cloneIgnoreId(infApiAccessLogDO, logDO -> logDO.setDuration(100)));
// resultCode 不同的
infApiAccessLogMapper.insert(ObjectUtils.clone(infApiAccessLogDO, logDO -> logDO.setResultCode(2)));
infApiAccessLogMapper.insert(ObjectUtils.cloneIgnoreId(infApiAccessLogDO, logDO -> logDO.setResultCode(2)));
// 构造调用参数
InfApiAccessLogExportReqVO reqVO = new InfApiAccessLogExportReqVO();

View File

@ -1,16 +1,16 @@
package cn.iocoder.yudao.adminserver.modules.infra.service.logger;
import cn.iocoder.yudao.adminserver.BaseDbUnitTest;
import cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.logger.InfApiErrorLogDO;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.adminserver.modules.infra.controller.logger.vo.apierrorlog.InfApiErrorLogExportReqVO;
import cn.iocoder.yudao.adminserver.modules.infra.controller.logger.vo.apierrorlog.InfApiErrorLogPageReqVO;
import cn.iocoder.yudao.adminserver.modules.infra.dal.mysql.logger.InfApiErrorLogMapper;
import cn.iocoder.yudao.adminserver.modules.infra.enums.logger.InfApiErrorLogProcessStatusEnum;
import cn.iocoder.yudao.adminserver.modules.infra.service.logger.impl.InfApiErrorLogServiceImpl;
import cn.iocoder.yudao.framework.test.core.util.RandomUtils;
import cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.logger.InfApiErrorLogDO;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.framework.test.core.util.RandomUtils;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;
@ -20,11 +20,10 @@ import java.util.List;
import static cn.iocoder.yudao.adminserver.modules.infra.enums.InfErrorCodeConstants.API_ERROR_LOG_NOT_FOUND;
import static cn.iocoder.yudao.adminserver.modules.infra.enums.InfErrorCodeConstants.API_ERROR_LOG_PROCESSED;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
/**
* {@link InfApiErrorLogServiceImpl} 单元测试
@ -60,17 +59,17 @@ public class InfApiErrorLogServiceImplTest extends BaseDbUnitTest {
// 下面几个都是不匹配的数据
// userId 不同的
infApiErrorLogMapper.insert(ObjectUtils.clone(infApiErrorLogDO, logDO -> logDO.setUserId(3344L)));
infApiErrorLogMapper.insert(ObjectUtils.cloneIgnoreId(infApiErrorLogDO, logDO -> logDO.setUserId(3344L)));
// userType
infApiErrorLogMapper.insert(ObjectUtils.clone(infApiErrorLogDO, logDO -> logDO.setUserType(UserTypeEnum.MEMBER.getValue())));
infApiErrorLogMapper.insert(ObjectUtils.cloneIgnoreId(infApiErrorLogDO, logDO -> logDO.setUserType(UserTypeEnum.MEMBER.getValue())));
// applicationName 不同的
infApiErrorLogMapper.insert(ObjectUtils.clone(infApiErrorLogDO, logDO -> logDO.setApplicationName("test")));
infApiErrorLogMapper.insert(ObjectUtils.cloneIgnoreId(infApiErrorLogDO, logDO -> logDO.setApplicationName("test")));
// requestUrl 不同的
infApiErrorLogMapper.insert(ObjectUtils.clone(infApiErrorLogDO, logDO -> logDO.setRequestUrl("bar")));
infApiErrorLogMapper.insert(ObjectUtils.cloneIgnoreId(infApiErrorLogDO, logDO -> logDO.setRequestUrl("bar")));
// 构造一个早期时间 2021-02-06 00:00:00
infApiErrorLogMapper.insert(ObjectUtils.clone(infApiErrorLogDO, logDO -> logDO.setExceptionTime(buildTime(2021, 2, 6))));
infApiErrorLogMapper.insert(ObjectUtils.cloneIgnoreId(infApiErrorLogDO, logDO -> logDO.setExceptionTime(buildTime(2021, 2, 6))));
// progressStatus 不同的
infApiErrorLogMapper.insert(ObjectUtils.clone(infApiErrorLogDO, logDO -> logDO.setProcessStatus(InfApiErrorLogProcessStatusEnum.DONE.getStatus())));
infApiErrorLogMapper.insert(ObjectUtils.cloneIgnoreId(infApiErrorLogDO, logDO -> logDO.setProcessStatus(InfApiErrorLogProcessStatusEnum.DONE.getStatus())));
// 构造调用参数
InfApiErrorLogPageReqVO reqVO = new InfApiErrorLogPageReqVO();
@ -113,17 +112,17 @@ public class InfApiErrorLogServiceImplTest extends BaseDbUnitTest {
// 下面几个都是不匹配的数据
// userId 不同的
infApiErrorLogMapper.insert(ObjectUtils.clone(infApiErrorLogDO, logDO -> logDO.setUserId(3344L)));
infApiErrorLogMapper.insert(ObjectUtils.cloneIgnoreId(infApiErrorLogDO, logDO -> logDO.setUserId(3344L)));
// userType
infApiErrorLogMapper.insert(ObjectUtils.clone(infApiErrorLogDO, logDO -> logDO.setUserType(UserTypeEnum.MEMBER.getValue())));
infApiErrorLogMapper.insert(ObjectUtils.cloneIgnoreId(infApiErrorLogDO, logDO -> logDO.setUserType(UserTypeEnum.MEMBER.getValue())));
// applicationName 不同的
infApiErrorLogMapper.insert(ObjectUtils.clone(infApiErrorLogDO, logDO -> logDO.setApplicationName("test")));
infApiErrorLogMapper.insert(ObjectUtils.cloneIgnoreId(infApiErrorLogDO, logDO -> logDO.setApplicationName("test")));
// requestUrl 不同的
infApiErrorLogMapper.insert(ObjectUtils.clone(infApiErrorLogDO, logDO -> logDO.setRequestUrl("bar")));
infApiErrorLogMapper.insert(ObjectUtils.cloneIgnoreId(infApiErrorLogDO, logDO -> logDO.setRequestUrl("bar")));
// 构造一个早期时间 2021-02-06 00:00:00
infApiErrorLogMapper.insert(ObjectUtils.clone(infApiErrorLogDO, logDO -> logDO.setExceptionTime(buildTime(2021, 2, 6))));
infApiErrorLogMapper.insert(ObjectUtils.cloneIgnoreId(infApiErrorLogDO, logDO -> logDO.setExceptionTime(buildTime(2021, 2, 6))));
// progressStatus 不同的
infApiErrorLogMapper.insert(ObjectUtils.clone(infApiErrorLogDO, logDO -> logDO.setProcessStatus(InfApiErrorLogProcessStatusEnum.DONE.getStatus())));
infApiErrorLogMapper.insert(ObjectUtils.cloneIgnoreId(infApiErrorLogDO, logDO -> logDO.setProcessStatus(InfApiErrorLogProcessStatusEnum.DONE.getStatus())));
// 构造调用参数
InfApiErrorLogExportReqVO reqVO = new InfApiErrorLogExportReqVO();

View File

@ -17,6 +17,7 @@ import cn.iocoder.yudao.coreservice.modules.system.service.user.SysUserCoreServi
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.test.core.util.AssertUtils;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
@ -71,6 +72,11 @@ public class SysAuthServiceImplTest extends BaseDbUnitTest {
@MockBean
private SysPostService postService;
@BeforeEach
public void setUp() {
when(captchaService.isCaptchaEnable()).thenReturn(true);
}
@Test
public void testLoadUserByUsername_success() {
// 准备参数
@ -83,7 +89,6 @@ public class SysAuthServiceImplTest extends BaseDbUnitTest {
LoginUser loginUser = (LoginUser) authService.loadUserByUsername(username);
// 校验
AssertUtils.assertPojoEquals(user, loginUser, "updateTime");
assertNull(loginUser.getRoleIds()); // 此时不会加载角色所以是空的
}
@Test

View File

@ -73,12 +73,12 @@ public class SysUserSessionServiceImplTest extends BaseDbAndRedisUnitTest {
});
userSessionMapper.insert(dbSession);
// 测试 username 不匹配
userSessionMapper.insert(ObjectUtils.clone(dbSession, o -> {
userSessionMapper.insert(ObjectUtils.cloneIgnoreId(dbSession, o -> {
o.setId(randomString());
o.setUserId(123456L);
}));
// 测试 userIp 不匹配
userSessionMapper.insert(ObjectUtils.clone(dbSession, o -> {
userSessionMapper.insert(ObjectUtils.cloneIgnoreId(dbSession, o -> {
o.setId(randomString());
o.setUserIp("testUserIp");
}));

View File

@ -83,9 +83,9 @@ class SysDeptServiceTest extends BaseDbUnitTest {
});
deptMapper.insert(dept);
// 测试 name 不匹配
deptMapper.insert(ObjectUtils.clone(dept, o -> o.setName("")));
deptMapper.insert(ObjectUtils.cloneIgnoreId(dept, o -> o.setName("")));
// 测试 status 不匹配
deptMapper.insert(ObjectUtils.clone(dept, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
deptMapper.insert(ObjectUtils.cloneIgnoreId(dept, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
// 准备参数
SysDeptListReqVO reqVO = new SysDeptListReqVO();
reqVO.setName("");

View File

@ -49,9 +49,9 @@ class SysPostServiceTest extends BaseDbUnitTest {
});
postMapper.insert(postDO);
// 测试 name 不匹配
postMapper.insert(ObjectUtils.clone(postDO, o -> o.setName("程序员")));
postMapper.insert(ObjectUtils.cloneIgnoreId(postDO, o -> o.setName("程序员")));
// 测试 status 不匹配
postMapper.insert(ObjectUtils.clone(postDO, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
postMapper.insert(ObjectUtils.cloneIgnoreId(postDO, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
// 准备参数
SysPostPageReqVO reqVO = new SysPostPageReqVO();
@ -76,9 +76,9 @@ class SysPostServiceTest extends BaseDbUnitTest {
});
postMapper.insert(postDO);
// 测试 name 不匹配
postMapper.insert(ObjectUtils.clone(postDO, o -> o.setName("程序员")));
postMapper.insert(ObjectUtils.cloneIgnoreId(postDO, o -> o.setName("程序员")));
// 测试 status 不匹配
postMapper.insert(ObjectUtils.clone(postDO, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
postMapper.insert(ObjectUtils.cloneIgnoreId(postDO, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
// 准备参数
SysPostExportReqVO reqVO = new SysPostExportReqVO();
reqVO.setName("");

View File

@ -14,17 +14,14 @@ import cn.iocoder.yudao.adminserver.modules.system.mq.producer.dict.SysDictDataP
import cn.iocoder.yudao.adminserver.modules.system.service.dict.impl.SysDictDataServiceImpl;
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.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.function.Consumer;
import static cn.hutool.core.bean.BeanUtil.getFieldValue;
import static cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants.*;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
@ -61,11 +58,11 @@ public class SysDictDataServiceTest extends BaseDbUnitTest {
});
dictDataMapper.insert(dbDictData);
// 测试 label 不匹配
dictDataMapper.insert(ObjectUtils.clone(dbDictData, o -> o.setLabel("")));
dictDataMapper.insert(ObjectUtils.cloneIgnoreId(dbDictData, o -> o.setLabel("")));
// 测试 dictType 不匹配
dictDataMapper.insert(ObjectUtils.clone(dbDictData, o -> o.setDictType("nai")));
dictDataMapper.insert(ObjectUtils.cloneIgnoreId(dbDictData, o -> o.setDictType("nai")));
// 测试 status 不匹配
dictDataMapper.insert(ObjectUtils.clone(dbDictData, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
dictDataMapper.insert(ObjectUtils.cloneIgnoreId(dbDictData, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
// 准备参数
SysDictDataPageReqVO reqVO = new SysDictDataPageReqVO();
reqVO.setLabel("");
@ -90,11 +87,11 @@ public class SysDictDataServiceTest extends BaseDbUnitTest {
});
dictDataMapper.insert(dbDictData);
// 测试 label 不匹配
dictDataMapper.insert(ObjectUtils.clone(dbDictData, o -> o.setLabel("")));
dictDataMapper.insert(ObjectUtils.cloneIgnoreId(dbDictData, o -> o.setLabel("")));
// 测试 dictType 不匹配
dictDataMapper.insert(ObjectUtils.clone(dbDictData, o -> o.setDictType("nai")));
dictDataMapper.insert(ObjectUtils.cloneIgnoreId(dbDictData, o -> o.setDictType("nai")));
// 测试 status 不匹配
dictDataMapper.insert(ObjectUtils.clone(dbDictData, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
dictDataMapper.insert(ObjectUtils.cloneIgnoreId(dbDictData, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
// 准备参数
SysDictDataExportReqVO reqVO = new SysDictDataExportReqVO();
reqVO.setLabel("");

View File

@ -57,13 +57,13 @@ public class SysDictTypeServiceTest extends BaseDbUnitTest {
});
dictTypeMapper.insert(dbDictType);
// 测试 name 不匹配
dictTypeMapper.insert(ObjectUtils.clone(dbDictType, o -> o.setName("tudou")));
dictTypeMapper.insert(ObjectUtils.cloneIgnoreId(dbDictType, o -> o.setName("tudou")));
// 测试 type 不匹配
dictTypeMapper.insert(ObjectUtils.clone(dbDictType, o -> o.setType("土豆")));
dictTypeMapper.insert(ObjectUtils.cloneIgnoreId(dbDictType, o -> o.setType("土豆")));
// 测试 status 不匹配
dictTypeMapper.insert(ObjectUtils.clone(dbDictType, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
dictTypeMapper.insert(ObjectUtils.cloneIgnoreId(dbDictType, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
// 测试 createTime 不匹配
dictTypeMapper.insert(ObjectUtils.clone(dbDictType, o -> o.setCreateTime(buildTime(2021, 1, 1))));
dictTypeMapper.insert(ObjectUtils.cloneIgnoreId(dbDictType, o -> o.setCreateTime(buildTime(2021, 1, 1))));
// 准备参数
SysDictTypePageReqVO reqVO = new SysDictTypePageReqVO();
reqVO.setName("nai");
@ -91,13 +91,13 @@ public class SysDictTypeServiceTest extends BaseDbUnitTest {
});
dictTypeMapper.insert(dbDictType);
// 测试 name 不匹配
dictTypeMapper.insert(ObjectUtils.clone(dbDictType, o -> o.setName("tudou")));
dictTypeMapper.insert(ObjectUtils.cloneIgnoreId(dbDictType, o -> o.setName("tudou")));
// 测试 type 不匹配
dictTypeMapper.insert(ObjectUtils.clone(dbDictType, o -> o.setType("土豆")));
dictTypeMapper.insert(ObjectUtils.cloneIgnoreId(dbDictType, o -> o.setType("土豆")));
// 测试 status 不匹配
dictTypeMapper.insert(ObjectUtils.clone(dbDictType, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
dictTypeMapper.insert(ObjectUtils.cloneIgnoreId(dbDictType, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
// 测试 createTime 不匹配
dictTypeMapper.insert(ObjectUtils.clone(dbDictType, o -> o.setCreateTime(buildTime(2021, 1, 1))));
dictTypeMapper.insert(ObjectUtils.cloneIgnoreId(dbDictType, o -> o.setCreateTime(buildTime(2021, 1, 1))));
// 准备参数
SysDictTypeExportReqVO reqVO = new SysDictTypeExportReqVO();
reqVO.setName("nai");

View File

@ -131,15 +131,15 @@ public class SysErrorCodeServiceTest extends BaseDbUnitTest {
});
errorCodeMapper.insert(dbErrorCode);
// 测试 type 不匹配
errorCodeMapper.insert(ObjectUtils.clone(dbErrorCode, o -> o.setType(SysErrorCodeTypeEnum.MANUAL_OPERATION.getType())));
errorCodeMapper.insert(ObjectUtils.cloneIgnoreId(dbErrorCode, o -> o.setType(SysErrorCodeTypeEnum.MANUAL_OPERATION.getType())));
// 测试 applicationName 不匹配
errorCodeMapper.insert(ObjectUtils.clone(dbErrorCode, o -> o.setApplicationName("yunai")));
errorCodeMapper.insert(ObjectUtils.cloneIgnoreId(dbErrorCode, o -> o.setApplicationName("yunai")));
// 测试 code 不匹配
errorCodeMapper.insert(ObjectUtils.clone(dbErrorCode, o -> o.setCode(2)));
errorCodeMapper.insert(ObjectUtils.cloneIgnoreId(dbErrorCode, o -> o.setCode(2)));
// 测试 message 不匹配
errorCodeMapper.insert(ObjectUtils.clone(dbErrorCode, o -> o.setMessage("nai")));
errorCodeMapper.insert(ObjectUtils.cloneIgnoreId(dbErrorCode, o -> o.setMessage("nai")));
// 测试 createTime 不匹配
errorCodeMapper.insert(ObjectUtils.clone(dbErrorCode, o -> o.setCreateTime(buildTime(2020, 12, 12))));
errorCodeMapper.insert(ObjectUtils.cloneIgnoreId(dbErrorCode, o -> o.setCreateTime(buildTime(2020, 12, 12))));
return dbErrorCode;
}

View File

@ -51,13 +51,13 @@ public class SysLoginLogServiceImplTest extends BaseDbUnitTest {
// 下面几个都是不匹配的数据
// 登录失败的
loginLogMapper.insert(ObjectUtils.clone(loginLogDO, logDO -> logDO.setResult(SysLoginResultEnum.CAPTCHA_CODE_ERROR.getResult())));
loginLogMapper.insert(ObjectUtils.cloneIgnoreId(loginLogDO, logDO -> logDO.setResult(SysLoginResultEnum.CAPTCHA_CODE_ERROR.getResult())));
// 不同ip段的
loginLogMapper.insert(ObjectUtils.clone(loginLogDO, logDO -> logDO.setUserIp("192.168.128.18")));
loginLogMapper.insert(ObjectUtils.cloneIgnoreId(loginLogDO, logDO -> logDO.setUserIp("192.168.128.18")));
// 不同username
loginLogMapper.insert(ObjectUtils.clone(loginLogDO, logDO -> logDO.setUsername("yunai")));
loginLogMapper.insert(ObjectUtils.cloneIgnoreId(loginLogDO, logDO -> logDO.setUsername("yunai")));
// 构造一个早期时间 2021-02-06 00:00:00
loginLogMapper.insert(ObjectUtils.clone(loginLogDO, logDO -> logDO.setCreateTime(buildTime(2021, 2, 6))));
loginLogMapper.insert(ObjectUtils.cloneIgnoreId(loginLogDO, logDO -> logDO.setCreateTime(buildTime(2021, 2, 6))));
// 构造调用参数
@ -96,13 +96,13 @@ public class SysLoginLogServiceImplTest extends BaseDbUnitTest {
// 下面几个都是不匹配的数据
// 登录失败的
loginLogMapper.insert(ObjectUtils.clone(loginLogDO, logDO -> logDO.setResult(SysLoginResultEnum.CAPTCHA_CODE_ERROR.getResult())));
loginLogMapper.insert(ObjectUtils.cloneIgnoreId(loginLogDO, logDO -> logDO.setResult(SysLoginResultEnum.CAPTCHA_CODE_ERROR.getResult())));
// 不同ip段的
loginLogMapper.insert(ObjectUtils.clone(loginLogDO, logDO -> logDO.setUserIp("192.168.128.18")));
loginLogMapper.insert(ObjectUtils.cloneIgnoreId(loginLogDO, logDO -> logDO.setUserIp("192.168.128.18")));
// 不同username
loginLogMapper.insert(ObjectUtils.clone(loginLogDO, logDO -> logDO.setUsername("yunai")));
loginLogMapper.insert(ObjectUtils.cloneIgnoreId(loginLogDO, logDO -> logDO.setUsername("yunai")));
// 构造一个早期时间 2021-02-06 00:00:00
loginLogMapper.insert(ObjectUtils.clone(loginLogDO, logDO -> logDO.setCreateTime(buildTime(2021, 2, 6))));
loginLogMapper.insert(ObjectUtils.cloneIgnoreId(loginLogDO, logDO -> logDO.setCreateTime(buildTime(2021, 2, 6))));
// 构造调用参数

View File

@ -87,15 +87,15 @@ public class SysOperateLogServiceImplTest extends BaseDbUnitTest {
// 下面几个是不匹配的数据
// 随机 userId
operateLogMapper.insert(ObjectUtils.clone(sysOperateLogDO, logDO -> logDO.setUserId(userId + 1)));
operateLogMapper.insert(ObjectUtils.cloneIgnoreId(sysOperateLogDO, logDO -> logDO.setUserId(userId + 1)));
// module 不同
operateLogMapper.insert(ObjectUtils.clone(sysOperateLogDO, logDO -> logDO.setModule("user")));
operateLogMapper.insert(ObjectUtils.cloneIgnoreId(sysOperateLogDO, logDO -> logDO.setModule("user")));
// type 不同
operateLogMapper.insert(ObjectUtils.clone(sysOperateLogDO, logDO -> logDO.setType(OperateTypeEnum.IMPORT.getType())));
operateLogMapper.insert(ObjectUtils.cloneIgnoreId(sysOperateLogDO, logDO -> logDO.setType(OperateTypeEnum.IMPORT.getType())));
// createTime 不同
operateLogMapper.insert(ObjectUtils.clone(sysOperateLogDO, logDO -> logDO.setStartTime(buildTime(2021, 2, 6))));
operateLogMapper.insert(ObjectUtils.cloneIgnoreId(sysOperateLogDO, logDO -> logDO.setStartTime(buildTime(2021, 2, 6))));
// resultCode 不同
operateLogMapper.insert(ObjectUtils.clone(sysOperateLogDO, logDO -> logDO.setResultCode(GlobalErrorCodeConstants.BAD_REQUEST.getCode())));
operateLogMapper.insert(ObjectUtils.cloneIgnoreId(sysOperateLogDO, logDO -> logDO.setResultCode(GlobalErrorCodeConstants.BAD_REQUEST.getCode())));
// 构造调用参数
SysOperateLogPageReqVO reqVO = new SysOperateLogPageReqVO();
@ -138,15 +138,15 @@ public class SysOperateLogServiceImplTest extends BaseDbUnitTest {
// 下面几个是不匹配的数据
// 随机 userId
operateLogMapper.insert(ObjectUtils.clone(sysOperateLogDO, logDO -> logDO.setUserId(userId + 1)));
operateLogMapper.insert(ObjectUtils.cloneIgnoreId(sysOperateLogDO, logDO -> logDO.setUserId(userId + 1)));
// module 不同
operateLogMapper.insert(ObjectUtils.clone(sysOperateLogDO, logDO -> logDO.setModule("user")));
operateLogMapper.insert(ObjectUtils.cloneIgnoreId(sysOperateLogDO, logDO -> logDO.setModule("user")));
// type 不同
operateLogMapper.insert(ObjectUtils.clone(sysOperateLogDO, logDO -> logDO.setType(OperateTypeEnum.IMPORT.getType())));
operateLogMapper.insert(ObjectUtils.cloneIgnoreId(sysOperateLogDO, logDO -> logDO.setType(OperateTypeEnum.IMPORT.getType())));
// createTime 不同
operateLogMapper.insert(ObjectUtils.clone(sysOperateLogDO, logDO -> logDO.setStartTime(buildTime(2021, 2, 6))));
operateLogMapper.insert(ObjectUtils.cloneIgnoreId(sysOperateLogDO, logDO -> logDO.setStartTime(buildTime(2021, 2, 6))));
// resultCode 不同
operateLogMapper.insert(ObjectUtils.clone(sysOperateLogDO, logDO -> logDO.setResultCode(GlobalErrorCodeConstants.BAD_REQUEST.getCode())));
operateLogMapper.insert(ObjectUtils.cloneIgnoreId(sysOperateLogDO, logDO -> logDO.setResultCode(GlobalErrorCodeConstants.BAD_REQUEST.getCode())));
// 构造调用参数
SysOperateLogExportReqVO reqVO = new SysOperateLogExportReqVO();

View File

@ -46,9 +46,9 @@ class SysNoticeServiceImplTest extends BaseDbUnitTest {
sysNoticeMapper.insert(dbNotice);
// 测试 title 不匹配
sysNoticeMapper.insert(ObjectUtils.clone(dbNotice, o -> o.setTitle("尼古拉斯凯奇也来啦!")));
sysNoticeMapper.insert(ObjectUtils.cloneIgnoreId(dbNotice, o -> o.setTitle("尼古拉斯凯奇也来啦!")));
// 测试 status 不匹配
sysNoticeMapper.insert(ObjectUtils.clone(dbNotice, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
sysNoticeMapper.insert(ObjectUtils.cloneIgnoreId(dbNotice, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
// 查询

View File

@ -1,12 +1,19 @@
package cn.iocoder.yudao.adminserver.modules.system.service.permission;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.adminserver.BaseDbUnitTest;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept.SysDeptDO;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysRoleDO;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysRoleMenuDO;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysUserRoleDO;
import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.permission.SysRoleMenuMapper;
import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.permission.SysUserRoleMapper;
import cn.iocoder.yudao.adminserver.modules.system.mq.producer.permission.SysPermissionProducer;
import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysDeptService;
import cn.iocoder.yudao.adminserver.modules.system.service.permission.impl.SysPermissionServiceImpl;
import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.enums.DataScopeEnum;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
@ -17,8 +24,12 @@ import java.util.List;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
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;
import static java.util.Collections.singletonList;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@Import(SysPermissionServiceImpl.class)
public class SysPermissionServiceTest extends BaseDbUnitTest {
@ -35,6 +46,8 @@ public class SysPermissionServiceTest extends BaseDbUnitTest {
private SysRoleService roleService;
@MockBean
private SysMenuService menuService;
@MockBean
private SysDeptService deptService;
@MockBean
private SysPermissionProducer permissionProducer;
@ -106,4 +119,111 @@ public class SysPermissionServiceTest extends BaseDbUnitTest {
assertPojoEquals(dbUserRoles.get(0), userRoleDO02);
}
@Test // 测试从 context 获取的场景
public void testGetDeptDataPermission_fromContext() {
// 准备参数
LoginUser loginUser = randomPojo(LoginUser.class);
// mock 方法
DeptDataPermissionRespDTO respDTO = new DeptDataPermissionRespDTO();
loginUser.setContext(SysPermissionServiceImpl.CONTEXT_KEY, respDTO);
// 调用
DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(loginUser);
// 断言
assertSame(respDTO, result);
}
@Test
public void testGetDeptDataPermission_All() {
// 准备参数
LoginUser loginUser = randomPojo(LoginUser.class);
// mock 方法
SysRoleDO roleDO = randomPojo(SysRoleDO.class, o -> o.setDataScope(DataScopeEnum.ALL.getScope()));
when(roleService.getRolesFromCache(same(loginUser.getRoleIds()))).thenReturn(singletonList(roleDO));
// 调用
DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(loginUser);
// 断言
assertTrue(result.getAll());
assertFalse(result.getSelf());
assertTrue(CollUtil.isEmpty(result.getDeptIds()));
assertSame(result, loginUser.getContext(SysPermissionServiceImpl.CONTEXT_KEY, DeptDataPermissionRespDTO.class));
}
@Test
public void testGetDeptDataPermission_DeptCustom() {
// 准备参数
LoginUser loginUser = randomPojo(LoginUser.class);
// mock 方法
SysRoleDO roleDO = randomPojo(SysRoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_CUSTOM.getScope()));
when(roleService.getRolesFromCache(same(loginUser.getRoleIds()))).thenReturn(singletonList(roleDO));
// 调用
DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(loginUser);
// 断言
assertFalse(result.getAll());
assertFalse(result.getSelf());
assertEquals(roleDO.getDataScopeDeptIds().size() + 1, result.getDeptIds().size());
assertTrue(CollUtil.containsAll(result.getDeptIds(), roleDO.getDataScopeDeptIds()));
assertTrue(CollUtil.contains(result.getDeptIds(), loginUser.getDeptId()));
assertSame(result, loginUser.getContext(SysPermissionServiceImpl.CONTEXT_KEY, DeptDataPermissionRespDTO.class));
}
@Test
public void testGetDeptDataPermission_DeptOnly() {
// 准备参数
LoginUser loginUser = randomPojo(LoginUser.class);
// mock 方法
SysRoleDO roleDO = randomPojo(SysRoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_ONLY.getScope()));
when(roleService.getRolesFromCache(same(loginUser.getRoleIds()))).thenReturn(singletonList(roleDO));
// 调用
DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(loginUser);
// 断言
assertFalse(result.getAll());
assertFalse(result.getSelf());
assertEquals(1, result.getDeptIds().size());
assertTrue(CollUtil.contains(result.getDeptIds(), loginUser.getDeptId()));
assertSame(result, loginUser.getContext(SysPermissionServiceImpl.CONTEXT_KEY, DeptDataPermissionRespDTO.class));
}
@Test
public void testGetDeptDataPermission_DeptAndChild() {
// 准备参数
LoginUser loginUser = randomPojo(LoginUser.class);
// mock 方法角色
SysRoleDO roleDO = randomPojo(SysRoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_AND_CHILD.getScope()));
when(roleService.getRolesFromCache(same(loginUser.getRoleIds()))).thenReturn(singletonList(roleDO));
// mock 方法部门
SysDeptDO deptDO = randomPojo(SysDeptDO.class);
when(deptService.getDeptsByParentIdFromCache(eq(loginUser.getDeptId()), eq(true)))
.thenReturn(singletonList(deptDO));
// 调用
DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(loginUser);
// 断言
assertFalse(result.getAll());
assertFalse(result.getSelf());
assertEquals(1, result.getDeptIds().size());
assertTrue(CollUtil.contains(result.getDeptIds(), deptDO.getId()));
assertSame(result, loginUser.getContext(SysPermissionServiceImpl.CONTEXT_KEY, DeptDataPermissionRespDTO.class));
}
@Test
public void testGetDeptDataPermission_Self() {
// 准备参数
LoginUser loginUser = randomPojo(LoginUser.class);
// mock 方法
SysRoleDO roleDO = randomPojo(SysRoleDO.class, o -> o.setDataScope(DataScopeEnum.SELF.getScope()));
when(roleService.getRolesFromCache(same(loginUser.getRoleIds()))).thenReturn(singletonList(roleDO));
// 调用
DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(loginUser);
// 断言
assertFalse(result.getAll());
assertTrue(result.getSelf());
assertTrue(CollUtil.isEmpty(result.getDeptIds()));
assertSame(result, loginUser.getContext(SysPermissionServiceImpl.CONTEXT_KEY, DeptDataPermissionRespDTO.class));
}
}

View File

@ -133,11 +133,11 @@ public class SysRoleServiceTest extends BaseDbUnitTest {
//调用
Set<Long> deptIdSet = Arrays.asList(1L, 2L, 3L, 4L, 5L).stream().collect(Collectors.toSet());
sysRoleService.updateRoleDataScope(roleId, DataScopeEnum.DEPT_CUSTOM.getScore(), deptIdSet);
sysRoleService.updateRoleDataScope(roleId, DataScopeEnum.DEPT_CUSTOM.getScope(), deptIdSet);
//断言
SysRoleDO newRoleDO = roleMapper.selectById(roleId);
assertEquals(DataScopeEnum.DEPT_CUSTOM.getScore(), newRoleDO.getDataScope());
assertEquals(DataScopeEnum.DEPT_CUSTOM.getScope(), newRoleDO.getDataScope());
Set<Long> newDeptIdSet = newRoleDO.getDataScopeDeptIds();
assertTrue(deptIdSet.size() == newDeptIdSet.size());
@ -242,7 +242,7 @@ public class SysRoleServiceTest extends BaseDbUnitTest {
o.setCode("code");
o.setType(SysRoleTypeEnum.CUSTOM.getType());
o.setStatus(1);
o.setDataScope(DataScopeEnum.ALL.getScore());
o.setDataScope(DataScopeEnum.ALL.getScope());
});
roleMapper.insert(roleDO);
@ -293,7 +293,7 @@ public class SysRoleServiceTest extends BaseDbUnitTest {
o.setName(name);
o.setType(typeEnum.getType());
o.setStatus(status);
o.setDataScope(scopeEnum.getScore());
o.setDataScope(scopeEnum.getScope());
o.setCode(code);
});
return roleDO;

View File

@ -169,11 +169,11 @@ public class SysSmsChannelServiceTest extends BaseDbUnitTest {
});
smsChannelMapper.insert(dbSmsChannel);
// 测试 signature 不匹配
smsChannelMapper.insert(ObjectUtils.clone(dbSmsChannel, o -> o.setSignature("源码")));
smsChannelMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsChannel, o -> o.setSignature("源码")));
// 测试 status 不匹配
smsChannelMapper.insert(ObjectUtils.clone(dbSmsChannel, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
smsChannelMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsChannel, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
// 测试 createTime 不匹配
smsChannelMapper.insert(ObjectUtils.clone(dbSmsChannel, o -> o.setCreateTime(buildTime(2020, 11, 11))));
smsChannelMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsChannel, o -> o.setCreateTime(buildTime(2020, 11, 11))));
// 准备参数
SysSmsChannelPageReqVO reqVO = new SysSmsChannelPageReqVO();
reqVO.setSignature("芋道");

View File

@ -57,19 +57,19 @@ public class SysSmsLogServiceTest extends BaseDbUnitTest {
});
smsLogMapper.insert(dbSmsLog);
// 测试 channelId 不匹配
smsLogMapper.insert(ObjectUtils.clone(dbSmsLog, o -> o.setChannelId(2L)));
smsLogMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsLog, o -> o.setChannelId(2L)));
// 测试 templateId 不匹配
smsLogMapper.insert(ObjectUtils.clone(dbSmsLog, o -> o.setTemplateId(20L)));
smsLogMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsLog, o -> o.setTemplateId(20L)));
// 测试 mobile 不匹配
smsLogMapper.insert(ObjectUtils.clone(dbSmsLog, o -> o.setMobile("18818260999")));
smsLogMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsLog, o -> o.setMobile("18818260999")));
// 测试 sendStatus 不匹配
smsLogMapper.insert(ObjectUtils.clone(dbSmsLog, o -> o.setSendStatus(SysSmsSendStatusEnum.IGNORE.getStatus())));
smsLogMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsLog, o -> o.setSendStatus(SysSmsSendStatusEnum.IGNORE.getStatus())));
// 测试 sendTime 不匹配
smsLogMapper.insert(ObjectUtils.clone(dbSmsLog, o -> o.setSendTime(buildTime(2020, 12, 12))));
smsLogMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsLog, o -> o.setSendTime(buildTime(2020, 12, 12))));
// 测试 receiveStatus 不匹配
smsLogMapper.insert(ObjectUtils.clone(dbSmsLog, o -> o.setReceiveStatus(SysSmsReceiveStatusEnum.SUCCESS.getStatus())));
smsLogMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsLog, o -> o.setReceiveStatus(SysSmsReceiveStatusEnum.SUCCESS.getStatus())));
// 测试 receiveTime 不匹配
smsLogMapper.insert(ObjectUtils.clone(dbSmsLog, o -> o.setReceiveTime(buildTime(2021, 12, 12))));
smsLogMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsLog, o -> o.setReceiveTime(buildTime(2021, 12, 12))));
// 准备参数
SysSmsLogPageReqVO reqVO = new SysSmsLogPageReqVO();
reqVO.setChannelId(1L);
@ -104,19 +104,19 @@ public class SysSmsLogServiceTest extends BaseDbUnitTest {
});
smsLogMapper.insert(dbSmsLog);
// 测试 channelId 不匹配
smsLogMapper.insert(ObjectUtils.clone(dbSmsLog, o -> o.setChannelId(2L)));
smsLogMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsLog, o -> o.setChannelId(2L)));
// 测试 templateId 不匹配
smsLogMapper.insert(ObjectUtils.clone(dbSmsLog, o -> o.setTemplateId(20L)));
smsLogMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsLog, o -> o.setTemplateId(20L)));
// 测试 mobile 不匹配
smsLogMapper.insert(ObjectUtils.clone(dbSmsLog, o -> o.setMobile("18818260999")));
smsLogMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsLog, o -> o.setMobile("18818260999")));
// 测试 sendStatus 不匹配
smsLogMapper.insert(ObjectUtils.clone(dbSmsLog, o -> o.setSendStatus(SysSmsSendStatusEnum.IGNORE.getStatus())));
smsLogMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsLog, o -> o.setSendStatus(SysSmsSendStatusEnum.IGNORE.getStatus())));
// 测试 sendTime 不匹配
smsLogMapper.insert(ObjectUtils.clone(dbSmsLog, o -> o.setSendTime(buildTime(2020, 12, 12))));
smsLogMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsLog, o -> o.setSendTime(buildTime(2020, 12, 12))));
// 测试 receiveStatus 不匹配
smsLogMapper.insert(ObjectUtils.clone(dbSmsLog, o -> o.setReceiveStatus(SysSmsReceiveStatusEnum.SUCCESS.getStatus())));
smsLogMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsLog, o -> o.setReceiveStatus(SysSmsReceiveStatusEnum.SUCCESS.getStatus())));
// 测试 receiveTime 不匹配
smsLogMapper.insert(ObjectUtils.clone(dbSmsLog, o -> o.setReceiveTime(buildTime(2021, 12, 12))));
smsLogMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsLog, o -> o.setReceiveTime(buildTime(2021, 12, 12))));
// 准备参数
SysSmsLogExportReqVO reqVO = new SysSmsLogExportReqVO();
reqVO.setChannelId(1L);

View File

@ -190,19 +190,19 @@ public class SysSmsTemplateServiceTest extends BaseDbUnitTest {
});
smsTemplateMapper.insert(dbSmsTemplate);
// 测试 type 不匹配
smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setType(SysSmsTemplateTypeEnum.VERIFICATION_CODE.getType())));
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setType(SysSmsTemplateTypeEnum.VERIFICATION_CODE.getType())));
// 测试 status 不匹配
smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
// 测试 code 不匹配
smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setCode("yuanma")));
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setCode("yuanma")));
// 测试 content 不匹配
smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setContent("源码")));
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setContent("源码")));
// 测试 apiTemplateId 不匹配
smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setApiTemplateId("nai")));
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setApiTemplateId("nai")));
// 测试 channelId 不匹配
smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setChannelId(2L)));
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setChannelId(2L)));
// 测试 createTime 不匹配
smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setCreateTime(buildTime(2021, 12, 12))));
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setCreateTime(buildTime(2021, 12, 12))));
// 准备参数
SysSmsTemplatePageReqVO reqVO = new SysSmsTemplatePageReqVO();
reqVO.setType(SysSmsTemplateTypeEnum.PROMOTION.getType());
@ -236,19 +236,19 @@ public class SysSmsTemplateServiceTest extends BaseDbUnitTest {
});
smsTemplateMapper.insert(dbSmsTemplate);
// 测试 type 不匹配
smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setType(SysSmsTemplateTypeEnum.VERIFICATION_CODE.getType())));
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setType(SysSmsTemplateTypeEnum.VERIFICATION_CODE.getType())));
// 测试 status 不匹配
smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
// 测试 code 不匹配
smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setCode("yuanma")));
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setCode("yuanma")));
// 测试 content 不匹配
smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setContent("源码")));
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setContent("源码")));
// 测试 apiTemplateId 不匹配
smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setApiTemplateId("nai")));
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setApiTemplateId("nai")));
// 测试 channelId 不匹配
smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setChannelId(2L)));
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setChannelId(2L)));
// 测试 createTime 不匹配
smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setCreateTime(buildTime(2021, 12, 12))));
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setCreateTime(buildTime(2021, 12, 12))));
// 准备参数
SysSmsTemplateExportReqVO reqVO = new SysSmsTemplateExportReqVO();
reqVO.setType(SysSmsTemplateTypeEnum.PROMOTION.getType());

View File

@ -0,0 +1,181 @@
package cn.iocoder.yudao.adminserver.modules.system.service.tenant;
import cn.iocoder.yudao.adminserver.BaseDbUnitTest;
import cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo.SysTenantCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo.SysTenantExportReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo.SysTenantPageReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.tenant.vo.SysTenantUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.tenant.SysTenantMapper;
import cn.iocoder.yudao.adminserver.modules.system.service.tenant.impl.SysTenantServiceImpl;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.tenant.SysTenantDO;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;
import javax.annotation.Resource;
import java.util.List;
import static cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants.TENANT_NOT_EXISTS;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime;
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
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.*;
/**
* {@link SysTenantServiceImpl} 的单元测试类
*
* @author 芋道源码
*/
@Import(SysTenantServiceImpl.class)
public class SysTenantServiceTest extends BaseDbUnitTest {
@Resource
private SysTenantServiceImpl tenantService;
@Resource
private SysTenantMapper tenantMapper;
@Test
public void testCreateTenant_success() {
// 准备参数
SysTenantCreateReqVO reqVO = randomPojo(SysTenantCreateReqVO.class, o -> o.setStatus(randomCommonStatus()));
// 调用
Long tenantId = tenantService.createTenant(reqVO);
// 断言
assertNotNull(tenantId);
// 校验记录的属性是否正确
SysTenantDO tenant = tenantMapper.selectById(tenantId);
assertPojoEquals(reqVO, tenant);
}
@Test
public void testUpdateTenant_success() {
// mock 数据
SysTenantDO dbTenant = randomPojo(SysTenantDO.class, o -> o.setStatus(randomCommonStatus()));
tenantMapper.insert(dbTenant);// @Sql: 先插入出一条存在的数据
// 准备参数
SysTenantUpdateReqVO reqVO = randomPojo(SysTenantUpdateReqVO.class, o -> {
o.setId(dbTenant.getId()); // 设置更新的 ID
o.setStatus(randomCommonStatus());
});
// 调用
tenantService.updateTenant(reqVO);
// 校验是否更新正确
SysTenantDO tenant = tenantMapper.selectById(reqVO.getId()); // 获取最新的
assertPojoEquals(reqVO, tenant);
}
@Test
public void testUpdateTenant_notExists() {
// 准备参数
SysTenantUpdateReqVO reqVO = randomPojo(SysTenantUpdateReqVO.class);
// 调用, 并断言异常
assertServiceException(() -> tenantService.updateTenant(reqVO), TENANT_NOT_EXISTS);
}
@Test
public void testDeleteTenant_success() {
// mock 数据
SysTenantDO dbTenant = randomPojo(SysTenantDO.class,
o -> o.setStatus(randomCommonStatus()));
tenantMapper.insert(dbTenant);// @Sql: 先插入出一条存在的数据
// 准备参数
Long id = dbTenant.getId();
// 调用
tenantService.deleteTenant(id);
// 校验数据不存在了
assertNull(tenantMapper.selectById(id));
}
@Test
public void testDeleteTenant_notExists() {
// 准备参数
Long id = randomLongId();
// 调用, 并断言异常
assertServiceException(() -> tenantService.deleteTenant(id), TENANT_NOT_EXISTS);
}
@Test
public void testGetTenantPage() {
// mock 数据
SysTenantDO dbTenant = randomPojo(SysTenantDO.class, o -> { // 等会查询到
o.setName("芋道源码");
o.setContactName("芋艿");
o.setContactMobile("15601691300");
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
o.setCreateTime(buildTime(2020, 12, 12));
});
tenantMapper.insert(dbTenant);
// 测试 name 不匹配
tenantMapper.insert(cloneIgnoreId(dbTenant, o -> o.setName(randomString())));
// 测试 contactName 不匹配
tenantMapper.insert(cloneIgnoreId(dbTenant, o -> o.setContactName(randomString())));
// 测试 contactMobile 不匹配
tenantMapper.insert(cloneIgnoreId(dbTenant, o -> o.setContactMobile(randomString())));
// 测试 status 不匹配
tenantMapper.insert(cloneIgnoreId(dbTenant, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
// 测试 createTime 不匹配
tenantMapper.insert(cloneIgnoreId(dbTenant, o -> o.setCreateTime(buildTime(2021, 12, 12))));
// 准备参数
SysTenantPageReqVO reqVO = new SysTenantPageReqVO();
reqVO.setName("芋道");
reqVO.setContactName("");
reqVO.setContactMobile("1560");
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
reqVO.setBeginCreateTime(buildTime(2020, 12, 1));
reqVO.setEndCreateTime(buildTime(2020, 12, 24));
// 调用
PageResult<SysTenantDO> pageResult = tenantService.getTenantPage(reqVO);
// 断言
assertEquals(1, pageResult.getTotal());
assertEquals(1, pageResult.getList().size());
assertPojoEquals(dbTenant, pageResult.getList().get(0));
}
@Test
public void testGetTenantList() {
// mock 数据
SysTenantDO dbTenant = randomPojo(SysTenantDO.class, o -> { // 等会查询到
o.setName("芋道源码");
o.setContactName("芋艿");
o.setContactMobile("15601691300");
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
o.setCreateTime(buildTime(2020, 12, 12));
});
tenantMapper.insert(dbTenant);
// 测试 name 不匹配
tenantMapper.insert(cloneIgnoreId(dbTenant, o -> o.setName(randomString())));
// 测试 contactName 不匹配
tenantMapper.insert(cloneIgnoreId(dbTenant, o -> o.setContactName(randomString())));
// 测试 contactMobile 不匹配
tenantMapper.insert(cloneIgnoreId(dbTenant, o -> o.setContactMobile(randomString())));
// 测试 status 不匹配
tenantMapper.insert(cloneIgnoreId(dbTenant, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
// 测试 createTime 不匹配
tenantMapper.insert(cloneIgnoreId(dbTenant, o -> o.setCreateTime(buildTime(2021, 12, 12))));
// 准备参数
SysTenantExportReqVO reqVO = new SysTenantExportReqVO();
reqVO.setName("芋道");
reqVO.setContactName("");
reqVO.setContactMobile("1560");
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
reqVO.setBeginCreateTime(buildTime(2020, 12, 1));
reqVO.setEndCreateTime(buildTime(2020, 12, 24));
// 调用
List<SysTenantDO> list = tenantService.getTenantList(reqVO);
// 断言
assertEquals(1, list.size());
assertPojoEquals(dbTenant, list.get(0));
}
}

View File

@ -309,15 +309,15 @@ public class SysUserServiceImplTest extends BaseDbUnitTest {
});
userMapper.insert(dbUser);
// 测试 username 不匹配
userMapper.insert(ObjectUtils.clone(dbUser, o -> o.setUsername("yuanma")));
userMapper.insert(ObjectUtils.cloneIgnoreId(dbUser, o -> o.setUsername("yuanma")));
// 测试 mobile 不匹配
userMapper.insert(ObjectUtils.clone(dbUser, o -> o.setMobile("18818260888")));
userMapper.insert(ObjectUtils.cloneIgnoreId(dbUser, o -> o.setMobile("18818260888")));
// 测试 status 不匹配
userMapper.insert(ObjectUtils.clone(dbUser, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
userMapper.insert(ObjectUtils.cloneIgnoreId(dbUser, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
// 测试 createTime 不匹配
userMapper.insert(ObjectUtils.clone(dbUser, o -> o.setCreateTime(buildTime(2020, 11, 11))));
userMapper.insert(ObjectUtils.cloneIgnoreId(dbUser, o -> o.setCreateTime(buildTime(2020, 11, 11))));
// 测试 dept 不匹配
userMapper.insert(ObjectUtils.clone(dbUser, o -> o.setDeptId(0L)));
userMapper.insert(ObjectUtils.cloneIgnoreId(dbUser, o -> o.setDeptId(0L)));
return dbUser;
}

View File

@ -24,3 +24,4 @@ DELETE FROM "sys_sms_template";
DELETE FROM "sys_sms_log";
DELETE FROM "sys_error_code";
DELETE FROM "sys_social_user";
DELETE FROM "sys_tenant";

View File

@ -1,7 +1,7 @@
-- inf 开头的 DB
CREATE TABLE IF NOT EXISTS "inf_config" (
"id" int NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"id" bigint(20) NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"group" varchar(50) NOT NULL,
"type" tinyint NOT NULL,
"name" varchar(100) NOT NULL DEFAULT '',
@ -26,6 +26,7 @@ CREATE TABLE IF NOT EXISTS "inf_file" (
"updater" varchar(64) DEFAULT '',
"update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
"tenant_id" bigint not null default '0',
PRIMARY KEY ("id")
) COMMENT '文件表';
@ -82,6 +83,7 @@ CREATE TABLE IF NOT EXISTS "sys_dept" (
"updater" varchar(64) DEFAULT '',
"update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
"tenant_id" bigint not null default '0',
PRIMARY KEY ("id")
) COMMENT '部门表';
@ -189,6 +191,7 @@ CREATE TABLE IF NOT EXISTS `sys_user_session` (
`updater` varchar(64) DEFAULT '' ,
"update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
"tenant_id" bigint not null default '0',
PRIMARY KEY (`id`)
) COMMENT '用户在线 Session';
@ -204,6 +207,7 @@ CREATE TABLE IF NOT EXISTS "sys_post" (
"updater" varchar(64) DEFAULT '',
"update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
"tenant_id" bigint not null default '0',
PRIMARY KEY ("id")
) COMMENT '岗位信息表';
@ -218,7 +222,8 @@ CREATE TABLE IF NOT EXISTS "sys_notice" (
"updater" varchar(64) DEFAULT '' COMMENT '更新者',
"update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
"deleted" bit NOT NULL DEFAULT 0 COMMENT '是否删除',
PRIMARY KEY("id")
"tenant_id" bigint not null default '0',
PRIMARY KEY("id")
) COMMENT '通知公告表';
CREATE TABLE IF NOT EXISTS `sys_login_log` (
@ -264,6 +269,7 @@ CREATE TABLE IF NOT EXISTS `sys_operate_log` (
`updater` varchar(64) DEFAULT '',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`deleted` bit(1) NOT NULL DEFAULT '0',
"tenant_id" bigint not null default '0',
PRIMARY KEY (`id`)
) COMMENT ='操作日志记录';
@ -287,6 +293,7 @@ CREATE TABLE IF NOT EXISTS "sys_user" (
"updater" varchar(64) default '',
"update_time" timestamp not null default current_timestamp,
"deleted" bit not null default false,
"tenant_id" bigint not null default '0',
primary key ("id")
) comment '用户信息表';
@ -311,11 +318,12 @@ CREATE TABLE IF NOT EXISTS "inf_api_access_log" (
"updater" varchar(64) default '',
"update_time" timestamp not null default current_timestamp,
"deleted" bit not null default false,
"tenant_id" bigint not null default '0',
primary key ("id")
) COMMENT 'API 访问日志表';
CREATE TABLE IF NOT EXISTS "inf_api_error_log" (
"id" integer not null GENERATED BY DEFAULT AS IDENTITY,
"id" bigint not null GENERATED BY DEFAULT AS IDENTITY,
"trace_id" varchar(64) not null,
"user_id" bigint not null default '0',
"user_type" tinyint not null default '0',
@ -342,6 +350,7 @@ CREATE TABLE IF NOT EXISTS "inf_api_error_log" (
"updater" varchar(64) default '',
"update_time" timestamp not null default current_timestamp,
"deleted" bit not null default false,
"tenant_id" bigint not null default '0',
primary key ("id")
) COMMENT '系统异常日志';
@ -449,3 +458,17 @@ CREATE TABLE IF NOT EXISTS "sys_social_user" (
"deleted" bit NOT NULL DEFAULT FALSE,
PRIMARY KEY ("id")
) COMMENT '社交用户';
CREATE TABLE IF NOT EXISTS "sys_tenant" (
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"name" varchar(63) NOT NULL,
"contact_name" varchar(255) NOT NULL,
"contact_mobile" varchar(255),
"status" tinyint NOT NULL,
"creator" varchar(64) DEFAULT '',
"create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updater" varchar(64) DEFAULT '',
"update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
PRIMARY KEY ("id")
) COMMENT '租户';

View File

@ -0,0 +1,54 @@
import request from '@/utils/request'
// 创建租户
export function createTenant(data) {
return request({
url: '/system/tenant/create',
method: 'post',
data: data
})
}
// 更新租户
export function updateTenant(data) {
return request({
url: '/system/tenant/update',
method: 'put',
data: data
})
}
// 删除租户
export function deleteTenant(id) {
return request({
url: '/system/tenant/delete?id=' + id,
method: 'delete'
})
}
// 获得租户
export function getTenant(id) {
return request({
url: '/system/tenant/get?id=' + id,
method: 'get'
})
}
// 获得租户分页
export function getTenantPage(query) {
return request({
url: '/system/tenant/page',
method: 'get',
params: query
})
}
// 导出租户 Excel
export function exportTenantExcel(query) {
return request({
url: '/system/tenant/export-excel',
method: 'get',
params: query,
responseType: 'blob'
})
}

View File

@ -3,6 +3,7 @@ import { Notification, MessageBox, Message } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'
import errorCode from '@/utils/errorCode'
import Cookies from "js-cookie";
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
// 创建axios实例
@ -19,6 +20,11 @@ service.interceptors.request.use(config => {
if (getToken() && !isToken) {
config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
}
// 设置租户
const tenantId = Cookies.get('tenantId');
if (tenantId) {
config.headers['tenant-id'] = tenantId;
}
// get请求映射params参数
if (config.method === 'get' && config.params) {
let url = config.url + '?';

View File

@ -2,6 +2,11 @@
<div class="login">
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
<h3 class="title">芋道后台管理系统</h3>
<el-form-item prop="tenantName">
<el-input v-model="loginForm.tenantName" type="text" auto-complete="off" placeholder='租户'>
<svg-icon slot="prefix" icon-class="tree" class="el-input__icon input-icon" />
</el-input>
</el-form-item>
<el-form-item prop="username">
<el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号">
<svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
@ -46,6 +51,7 @@
<script>
import { getCodeImg,socialAuthRedirect } from "@/api/login";
import { getTenantIdByName } from "@/api/system/tenant";
import Cookies from "js-cookie";
import { encrypt, decrypt } from '@/utils/jsencrypt'
import {InfApiErrorLogProcessStatusEnum, SysUserSocialTypeEnum} from "@/utils/constants";
@ -60,9 +66,29 @@ export default {
password: "admin123",
rememberMe: false,
code: "",
uuid: ""
uuid: "",
tenantName: "芋道源码",
},
loginRules: {
tenantName: [
{ required: true, trigger: "blur", message: "租户不能为空" },
{
validator: (rule, value, callback) => {
// debugger
getTenantIdByName(value).then(res => {
const tenantId = res.data;
if (tenantId >= 0) {
//
Cookies.set("tenantId", tenantId);
callback();
} else {
callback('租户不存在');
}
});
},
trigger: 'blur'
}
],
username: [
{ required: true, trigger: "blur", message: "用户名不能为空" }
],
@ -103,25 +129,31 @@ export default {
const username = Cookies.get("username");
const password = Cookies.get("password");
const rememberMe = Cookies.get('rememberMe')
const tenantName = Cookies.get('tenantName');
this.loginForm = {
username: username === undefined ? this.loginForm.username : username,
password: password === undefined ? this.loginForm.password : decrypt(password),
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe),
tenantName: tenantName === undefined ? this.loginForm.tenantName : tenantName,
};
},
handleLogin() {
this.$refs.loginForm.validate(valid => {
if (valid) {
this.loading = true;
// Cookie
if (this.loginForm.rememberMe) {
Cookies.set("username", this.loginForm.username, { expires: 30 });
Cookies.set("password", encrypt(this.loginForm.password), { expires: 30 });
Cookies.set('rememberMe', this.loginForm.rememberMe, { expires: 30 });
Cookies.set('tenantName', this.loginForm.tenantName, { expires: 30 });
} else {
Cookies.remove("username");
Cookies.remove("password");
Cookies.remove('rememberMe');
Cookies.remove('tenantName');
}
//
this.$store.dispatch("Login", this.loginForm).then(() => {
this.$router.push({ path: this.redirect || "/" }).catch(()=>{});
}).catch(() => {
@ -167,7 +199,7 @@ export default {
.login-form {
border-radius: 6px;
background: #ffffff;
width: 400px;
width: 500px;
padding: 25px 25px 5px 25px;
.el-input {
height: 38px;

View File

@ -0,0 +1,259 @@
<template>
<div class="app-container">
<!-- 搜索工作栏 -->
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="租户名" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入租户名" clearable size="small" @keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="联系人" prop="contactName">
<el-input v-model="queryParams.contactName" placeholder="请输入联系人" clearable size="small" @keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="联系手机" prop="contactMobile">
<el-input v-model="queryParams.contactMobile" placeholder="请输入联系手机" clearable size="small" @keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="租户状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择租户状态" clearable size="small">
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.SYS_COMMON_STATUS)"
:key="dict.value" :label="dict.label" :value="dict.value"/>
</el-select>
</el-form-item>
<el-form-item label="创建时间">
<el-date-picker v-model="dateRangeCreateTime" size="small" style="width: 240px" value-format="yyyy-MM-dd"
type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 操作工具栏 -->
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
v-hasPermi="['system:tenant:create']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport"
v-hasPermi="['system:tenant:export']">导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<!-- 列表 -->
<el-table v-loading="loading" :data="list">
<el-table-column label="租户编号" align="center" prop="id" />
<el-table-column label="租户名" align="center" prop="name" />
<el-table-column label="联系人" align="center" prop="contactName" />
<el-table-column label="联系手机" align="center" prop="contactMobile" />
<el-table-column label="租户状态" align="center" prop="status">
<template slot-scope="scope">
<span>{{ getDictDataLabel(DICT_TYPE.SYS_COMMON_STATUS, scope.row.status) }}</span>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
v-hasPermi="['system:tenant:update']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['system:tenant:delete']">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
@pagination="getList"/>
<!-- 对话框(添加 / 修改) -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="租户名" prop="name">
<el-input v-model="form.name" placeholder="请输入租户名" />
</el-form-item>
<el-form-item label="联系人" prop="contactName">
<el-input v-model="form.contactName" placeholder="请输入联系人" />
</el-form-item>
<el-form-item label="联系手机" prop="contactMobile">
<el-input v-model="form.contactMobile" placeholder="请输入联系手机" />
</el-form-item>
<el-form-item label="租户状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio v-for="dict in this.getDictDatas(DICT_TYPE.SYS_COMMON_STATUS)"
:key="dict.value" :label="parseInt(dict.value)">{{dict.label}}</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { createTenant, updateTenant, deleteTenant, getTenant, getTenantPage, exportTenantExcel } from "@/api/system/tenant";
import { SysCommonStatusEnum } from '@/utils/constants'
export default {
name: "Tenant",
components: {
},
data() {
return {
//
loading: true,
//
showSearch: true,
//
total: 0,
//
list: [],
//
title: "",
//
open: false,
dateRangeCreateTime: [],
//
queryParams: {
pageNo: 1,
pageSize: 10,
name: null,
contactName: null,
contactMobile: null,
status: undefined,
},
//
form: {},
//
rules: {
name: [{ required: true, message: "租户名不能为空", trigger: "blur" }],
contactName: [{ required: true, message: "联系人不能为空", trigger: "blur" }],
status: [{ required: true, message: "租户状态0正常 1停用不能为空", trigger: "blur" }],
}
};
},
created() {
this.getList();
},
methods: {
/** 查询列表 */
getList() {
this.loading = true;
//
let params = {...this.queryParams};
this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
//
getTenantPage(params).then(response => {
this.list = response.data.list;
this.total = response.data.total;
this.loading = false;
});
},
/** 取消按钮 */
cancel() {
this.open = false;
this.reset();
},
/** 表单重置 */
reset() {
this.form = {
id: undefined,
name: undefined,
contactName: undefined,
contactMobile: undefined,
status: SysCommonStatusEnum.ENABLE,
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNo = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.dateRangeCreateTime = [];
this.resetForm("queryForm");
this.handleQuery();
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加租户";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const id = row.id;
getTenant(id).then(response => {
this.form = response.data;
this.open = true;
this.title = "修改租户";
});
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (!valid) {
return;
}
//
if (this.form.id != null) {
updateTenant(this.form).then(response => {
this.msgSuccess("修改成功");
this.open = false;
this.getList();
});
return;
}
//
createTenant(this.form).then(response => {
this.msgSuccess("新增成功");
this.open = false;
this.getList();
});
});
},
/** 删除按钮操作 */
handleDelete(row) {
const id = row.id;
this.$confirm('是否确认删除租户编号为"' + id + '"的数据项?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(function() {
return deleteTenant(id);
}).then(() => {
this.getList();
this.msgSuccess("删除成功");
})
},
/** 导出按钮操作 */
handleExport() {
//
let params = {...this.queryParams};
params.pageNo = undefined;
params.pageSize = undefined;
this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
//
this.$confirm('是否确认导出所有租户数据项?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(function() {
return exportTenantExcel(params);
}).then(response => {
this.downloadExcel(response, '租户.xls');
})
}
}
};
</script>

View File

@ -91,6 +91,11 @@
</dependency>
<!-- 工具类相关 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-tenant</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.file;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
@ -21,7 +22,7 @@ import java.io.InputStream;
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class InfFileDO extends BaseDO {
public class InfFileDO extends TenantBaseDO {
/**
* 文件路径

View File

@ -2,7 +2,7 @@ package cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.logger;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
@ -21,7 +21,7 @@ import java.util.Date;
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class InfApiAccessLogDO extends BaseDO {
public class InfApiAccessLogDO extends TenantBaseDO {
/**
* 编号

View File

@ -1,8 +1,8 @@
package cn.iocoder.yudao.coreservice.modules.infra.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.infra.enums.logger.InfApiErrorLogProcessStatusEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
@ -21,7 +21,7 @@ import java.util.Date;
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class InfApiErrorLogDO extends BaseDO {
public class InfApiErrorLogDO extends TenantBaseDO {
/**
* 编号

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
@ -22,7 +22,7 @@ import java.util.Date;
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class MbrUserDO extends BaseDO {
public class MbrUserDO extends TenantBaseDO {
/**
* 用户ID

View File

@ -1,8 +1,8 @@
package cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.auth;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
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;
@ -25,7 +25,7 @@ import java.util.Date;
@Data
@Builder
@EqualsAndHashCode(callSuper = true)
public class SysUserSessionDO extends BaseDO {
public class SysUserSessionDO extends TenantBaseDO {
/**
* 会话编号, sessionId

View File

@ -0,0 +1,45 @@
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;
}

View File

@ -2,8 +2,8 @@ package cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user;
import cn.iocoder.yudao.coreservice.modules.system.enums.common.SysSexEnum;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
@ -24,7 +24,7 @@ import java.util.Set;
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SysUserDO extends BaseDO {
public class SysUserDO extends TenantBaseDO {
/**
* 用户ID

View File

@ -0,0 +1,9 @@
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> {
}

View File

@ -1,8 +1,9 @@
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.StreamMessage;
import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessage;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotNull;
import java.util.List;
@ -13,7 +14,8 @@ import java.util.List;
* @author 芋道源码
*/
@Data
public class SysSmsSendMessage implements StreamMessage {
@EqualsAndHashCode(callSuper = true)
public class SysSmsSendMessage extends AbstractStreamMessage {
/**
* 短信日志编号

View File

@ -2,9 +2,8 @@ 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.util.RedisMessageUtils;
import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@ -21,7 +20,7 @@ import java.util.List;
public class SysSmsCoreProducer {
@Resource
private StringRedisTemplate stringRedisTemplate;
private RedisMQTemplate redisMQTemplate;
/**
* 发送 {@link SysSmsSendMessage} 消息
@ -36,7 +35,7 @@ public class SysSmsCoreProducer {
Long channelId, String apiTemplateId, List<KeyValue<String, Object>> templateParams) {
SysSmsSendMessage message = new SysSmsSendMessage().setLogId(logId).setMobile(mobile);
message.setChannelId(channelId).setApiTemplateId(apiTemplateId).setTemplateParams(templateParams);
RedisMessageUtils.sendStreamMessage(stringRedisTemplate, message);
redisMQTemplate.send(message);
}
}

Some files were not shown because too many files have changed in this diff Show More