Commit 9a898a81fd19cc28de2a4b57ea0791b1a0acbbe5

Authored by 芋道源码
Committed by Gitee
2 parents 319c73fe c69fbe54

!783 ✅ 增加 system 和 infra 的代码覆盖率,提升稳定性

Merge pull request !783 from 芋道源码/feature/vo-optimize
Showing 53 changed files with 1767 additions and 447 deletions
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/CodegenController.java
@@ -4,6 +4,7 @@ import cn.hutool.core.io.IoUtil; @@ -4,6 +4,7 @@ import cn.hutool.core.io.IoUtil;
4 import cn.hutool.core.util.ZipUtil; 4 import cn.hutool.core.util.ZipUtil;
5 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 5 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
6 import cn.iocoder.yudao.framework.common.pojo.PageResult; 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  7 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
7 import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; 8 import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
8 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenCreateListReqVO; 9 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenCreateListReqVO;
9 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenDetailRespVO; 10 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenDetailRespVO;
@@ -66,7 +67,7 @@ public class CodegenController { @@ -66,7 +67,7 @@ public class CodegenController {
66 @PreAuthorize("@ss.hasPermission('infra:codegen:query')") 67 @PreAuthorize("@ss.hasPermission('infra:codegen:query')")
67 public CommonResult<List<CodegenTableRespVO>> getCodegenTableList(@RequestParam(value = "dataSourceConfigId") Long dataSourceConfigId) { 68 public CommonResult<List<CodegenTableRespVO>> getCodegenTableList(@RequestParam(value = "dataSourceConfigId") Long dataSourceConfigId) {
68 List<CodegenTableDO> list = codegenService.getCodegenTableList(dataSourceConfigId); 69 List<CodegenTableDO> list = codegenService.getCodegenTableList(dataSourceConfigId);
69 - return success(CodegenConvert.INSTANCE.convertList05(list)); 70 + return success(BeanUtils.toBean(list, CodegenTableRespVO.class));
70 } 71 }
71 72
72 @GetMapping("/table/page") 73 @GetMapping("/table/page")
@@ -74,7 +75,7 @@ public class CodegenController { @@ -74,7 +75,7 @@ public class CodegenController {
74 @PreAuthorize("@ss.hasPermission('infra:codegen:query')") 75 @PreAuthorize("@ss.hasPermission('infra:codegen:query')")
75 public CommonResult<PageResult<CodegenTableRespVO>> getCodegenTablePage(@Valid CodegenTablePageReqVO pageReqVO) { 76 public CommonResult<PageResult<CodegenTableRespVO>> getCodegenTablePage(@Valid CodegenTablePageReqVO pageReqVO) {
76 PageResult<CodegenTableDO> pageResult = codegenService.getCodegenTablePage(pageReqVO); 77 PageResult<CodegenTableDO> pageResult = codegenService.getCodegenTablePage(pageReqVO);
77 - return success(CodegenConvert.INSTANCE.convertPage(pageResult)); 78 + return success(BeanUtils.toBean(pageResult, CodegenTableRespVO.class));
78 } 79 }
79 80
80 @GetMapping("/detail") 81 @GetMapping("/detail")
@@ -82,7 +83,7 @@ public class CodegenController { @@ -82,7 +83,7 @@ public class CodegenController {
82 @Parameter(name = "tableId", description = "表编号", required = true, example = "1024") 83 @Parameter(name = "tableId", description = "表编号", required = true, example = "1024")
83 @PreAuthorize("@ss.hasPermission('infra:codegen:query')") 84 @PreAuthorize("@ss.hasPermission('infra:codegen:query')")
84 public CommonResult<CodegenDetailRespVO> getCodegenDetail(@RequestParam("tableId") Long tableId) { 85 public CommonResult<CodegenDetailRespVO> getCodegenDetail(@RequestParam("tableId") Long tableId) {
85 - CodegenTableDO table = codegenService.getCodegenTablePage(tableId); 86 + CodegenTableDO table = codegenService.getCodegenTable(tableId);
86 List<CodegenColumnDO> columns = codegenService.getCodegenColumnListByTableId(tableId); 87 List<CodegenColumnDO> columns = codegenService.getCodegenColumnListByTableId(tableId);
87 // 拼装返回 88 // 拼装返回
88 return success(CodegenConvert.INSTANCE.convert(table, columns)); 89 return success(CodegenConvert.INSTANCE.convert(table, columns));
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/CodegenUpdateReqVO.java
1 package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo; 1 package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo;
2 2
3 -import cn.hutool.core.util.ObjectUtil;  
4 -import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column.CodegenColumnBaseVO;  
5 -import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTableBaseVO;  
6 -import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum;  
7 -import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;  
8 -import com.fasterxml.jackson.annotation.JsonIgnore; 3 +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column.CodegenColumnSaveReqVO;
  4 +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTableSaveReqVO;
9 import io.swagger.v3.oas.annotations.media.Schema; 5 import io.swagger.v3.oas.annotations.media.Schema;
10 import lombok.Data; 6 import lombok.Data;
11 -import lombok.EqualsAndHashCode;  
12 -import lombok.ToString;  
13 7
14 import javax.validation.Valid; 8 import javax.validation.Valid;
15 -import javax.validation.constraints.AssertTrue;  
16 import javax.validation.constraints.NotNull; 9 import javax.validation.constraints.NotNull;
17 import java.util.List; 10 import java.util.List;
18 11
@@ -22,55 +15,10 @@ public class CodegenUpdateReqVO { @@ -22,55 +15,10 @@ public class CodegenUpdateReqVO {
22 15
23 @Valid // 校验内嵌的字段 16 @Valid // 校验内嵌的字段
24 @NotNull(message = "表定义不能为空") 17 @NotNull(message = "表定义不能为空")
25 - private Table table; 18 + private CodegenTableSaveReqVO table;
26 19
27 @Valid // 校验内嵌的字段 20 @Valid // 校验内嵌的字段
28 @NotNull(message = "字段定义不能为空") 21 @NotNull(message = "字段定义不能为空")
29 - private List<Column> columns;  
30 -  
31 - @Schema(description = "更新表定义")  
32 - @Data  
33 - @EqualsAndHashCode(callSuper = true)  
34 - @ToString(callSuper = true)  
35 - @Valid  
36 - public static class Table extends CodegenTableBaseVO {  
37 -  
38 - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")  
39 - private Long id;  
40 -  
41 - @AssertTrue(message = "上级菜单不能为空,请前往 [修改生成配置 -> 生成信息] 界面,设置“上级菜单”字段")  
42 - @JsonIgnore  
43 - public boolean isParentMenuIdValid() {  
44 - // 生成场景为管理后台时,必须设置上级菜单,不然生成的菜单 SQL 是无父级菜单的  
45 - return ObjectUtil.notEqual(getScene(), CodegenSceneEnum.ADMIN.getScene())  
46 - || getParentMenuId() != null;  
47 - }  
48 -  
49 - @AssertTrue(message = "关联的父表信息不全")  
50 - @JsonIgnore  
51 - public boolean isSubValid() {  
52 - return ObjectUtil.notEqual(getTemplateType(), CodegenTemplateTypeEnum.SUB)  
53 - || (ObjectUtil.isAllNotEmpty(getMasterTableId(), getSubJoinColumnId(), getSubJoinMany()));  
54 - }  
55 -  
56 - @AssertTrue(message = "关联的树表信息不全")  
57 - @JsonIgnore  
58 - public boolean isTreeValid() {  
59 - return ObjectUtil.notEqual(getTemplateType(), CodegenTemplateTypeEnum.TREE)  
60 - || (ObjectUtil.isAllNotEmpty(getTreeParentColumnId(), getTreeNameColumnId()));  
61 - }  
62 -  
63 - }  
64 -  
65 - @Schema(description = "更新表定义")  
66 - @Data  
67 - @EqualsAndHashCode(callSuper = true)  
68 - @ToString(callSuper = true)  
69 - public static class Column extends CodegenColumnBaseVO {  
70 -  
71 - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")  
72 - private Long id;  
73 -  
74 - } 22 + private List<CodegenColumnSaveReqVO> columns;
75 23
76 } 24 }
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/column/CodegenColumnRespVO.java
@@ -2,20 +2,70 @@ package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column; @@ -2,20 +2,70 @@ package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column;
2 2
3 import io.swagger.v3.oas.annotations.media.Schema; 3 import io.swagger.v3.oas.annotations.media.Schema;
4 import lombok.Data; 4 import lombok.Data;
5 -import lombok.EqualsAndHashCode;  
6 -import lombok.ToString;  
7 5
8 import java.time.LocalDateTime; 6 import java.time.LocalDateTime;
9 7
10 @Schema(description = "管理后台 - 代码生成字段定义 Response VO") 8 @Schema(description = "管理后台 - 代码生成字段定义 Response VO")
11 @Data 9 @Data
12 -@EqualsAndHashCode(callSuper = true)  
13 -@ToString(callSuper = true)  
14 -public class CodegenColumnRespVO extends CodegenColumnBaseVO { 10 +public class CodegenColumnRespVO {
15 11
16 @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 12 @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
17 private Long id; 13 private Long id;
18 14
  15 + @Schema(description = "表编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  16 + private Long tableId;
  17 +
  18 + @Schema(description = "字段名", requiredMode = Schema.RequiredMode.REQUIRED, example = "user_age")
  19 + private String columnName;
  20 +
  21 + @Schema(description = "字段类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "int(11)")
  22 + private String dataType;
  23 +
  24 + @Schema(description = "字段描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "年龄")
  25 + private String columnComment;
  26 +
  27 + @Schema(description = "是否允许为空", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  28 + private Boolean nullable;
  29 +
  30 + @Schema(description = "是否主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
  31 + private Boolean primaryKey;
  32 +
  33 + @Schema(description = "是否自增", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  34 + private Boolean autoIncrement;
  35 +
  36 + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
  37 + private Integer ordinalPosition;
  38 +
  39 + @Schema(description = "Java 属性类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "userAge")
  40 + private String javaType;
  41 +
  42 + @Schema(description = "Java 属性名", requiredMode = Schema.RequiredMode.REQUIRED, example = "Integer")
  43 + private String javaField;
  44 +
  45 + @Schema(description = "字典类型", example = "sys_gender")
  46 + private String dictType;
  47 +
  48 + @Schema(description = "数据示例", example = "1024")
  49 + private String example;
  50 +
  51 + @Schema(description = "是否为 Create 创建操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  52 + private Boolean createOperation;
  53 +
  54 + @Schema(description = "是否为 Update 更新操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
  55 + private Boolean updateOperation;
  56 +
  57 + @Schema(description = "是否为 List 查询操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  58 + private Boolean listOperation;
  59 +
  60 + @Schema(description = "List 查询操作的条件类型,参见 CodegenColumnListConditionEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "LIKE")
  61 + private String listOperationCondition;
  62 +
  63 + @Schema(description = "是否为 List 查询操作的返回字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  64 + private Boolean listOperationResult;
  65 +
  66 + @Schema(description = "显示类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "input")
  67 + private String htmlType;
  68 +
19 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) 69 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
20 private LocalDateTime createTime; 70 private LocalDateTime createTime;
21 71
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/column/CodegenColumnBaseVO.java renamed to yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/column/CodegenColumnSaveReqVO.java
@@ -5,12 +5,12 @@ import lombok.Data; @@ -5,12 +5,12 @@ import lombok.Data;
5 5
6 import javax.validation.constraints.NotNull; 6 import javax.validation.constraints.NotNull;
7 7
8 -/**  
9 -* 代码生成字段定义 Base VO,提供给添加、修改、详细的子 VO 使用  
10 -* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成  
11 -*/ 8 +@Schema(description = "管理后台 - 代码生成字段定义创建/修改 Request VO")
12 @Data 9 @Data
13 -public class CodegenColumnBaseVO { 10 +public class CodegenColumnSaveReqVO {
  11 +
  12 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  13 + private Long id;
14 14
15 @Schema(description = "表编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 15 @Schema(description = "表编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
16 @NotNull(message = "表编号不能为空") 16 @NotNull(message = "表编号不能为空")
@@ -38,7 +38,7 @@ public class CodegenColumnBaseVO { @@ -38,7 +38,7 @@ public class CodegenColumnBaseVO {
38 38
39 @Schema(description = "是否自增", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") 39 @Schema(description = "是否自增", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
40 @NotNull(message = "是否自增不能为空") 40 @NotNull(message = "是否自增不能为空")
41 - private String autoIncrement; 41 + private Boolean autoIncrement;
42 42
43 @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") 43 @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
44 @NotNull(message = "排序不能为空") 44 @NotNull(message = "排序不能为空")
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/CodegenTableRespVO.java
@@ -2,20 +2,64 @@ package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table; @@ -2,20 +2,64 @@ package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table;
2 2
3 import io.swagger.v3.oas.annotations.media.Schema; 3 import io.swagger.v3.oas.annotations.media.Schema;
4 import lombok.Data; 4 import lombok.Data;
5 -import lombok.EqualsAndHashCode;  
6 -import lombok.ToString;  
7 5
8 import java.time.LocalDateTime; 6 import java.time.LocalDateTime;
9 7
10 @Schema(description = "管理后台 - 代码生成表定义 Response VO") 8 @Schema(description = "管理后台 - 代码生成表定义 Response VO")
11 @Data 9 @Data
12 -@EqualsAndHashCode(callSuper = true)  
13 -@ToString(callSuper = true)  
14 -public class CodegenTableRespVO extends CodegenTableBaseVO { 10 +public class CodegenTableRespVO {
15 11
16 @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 12 @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
17 private Long id; 13 private Long id;
18 14
  15 + @Schema(description = "生成场景,参见 CodegenSceneEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  16 + private Integer scene;
  17 +
  18 + @Schema(description = "表名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao")
  19 + private String tableName;
  20 +
  21 + @Schema(description = "表描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道")
  22 + private String tableComment;
  23 +
  24 + @Schema(description = "备注", example = "我是备注")
  25 + private String remark;
  26 +
  27 + @Schema(description = "模块名", requiredMode = Schema.RequiredMode.REQUIRED, example = "system")
  28 + private String moduleName;
  29 +
  30 + @Schema(description = "业务名", requiredMode = Schema.RequiredMode.REQUIRED, example = "codegen")
  31 + private String businessName;
  32 +
  33 + @Schema(description = "类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "CodegenTable")
  34 + private String className;
  35 +
  36 + @Schema(description = "类描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "代码生成器的表定义")
  37 + private String classComment;
  38 +
  39 + @Schema(description = "作者", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码")
  40 + private String author;
  41 +
  42 + @Schema(description = "模板类型,参见 CodegenTemplateTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  43 + private Integer templateType;
  44 +
  45 + @Schema(description = "前端类型,参见 CodegenFrontTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
  46 + private Integer frontType;
  47 +
  48 + @Schema(description = "父菜单编号", example = "1024")
  49 + private Long parentMenuId;
  50 +
  51 + @Schema(description = "主表的编号", example = "2048")
  52 + private Long masterTableId;
  53 + @Schema(description = "子表关联主表的字段编号", example = "4096")
  54 + private Long subJoinColumnId;
  55 + @Schema(description = "主表与子表是否一对多", example = "4096")
  56 + private Boolean subJoinMany;
  57 +
  58 + @Schema(description = "树表的父字段编号", example = "8192")
  59 + private Long treeParentColumnId;
  60 + @Schema(description = "树表的名字字段编号", example = "16384")
  61 + private Long treeNameColumnId;
  62 +
19 @Schema(description = "主键编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") 63 @Schema(description = "主键编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
20 private Integer dataSourceConfigId; 64 private Integer dataSourceConfigId;
21 65
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/CodegenTableBaseVO.java renamed to yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/CodegenTableSaveReqVO.java
1 package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table; 1 package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table;
2 2
  3 +import cn.hutool.core.util.ObjectUtil;
  4 +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum;
  5 +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
  6 +import com.fasterxml.jackson.annotation.JsonIgnore;
3 import io.swagger.v3.oas.annotations.media.Schema; 7 import io.swagger.v3.oas.annotations.media.Schema;
4 import lombok.Data; 8 import lombok.Data;
5 9
  10 +import javax.validation.constraints.AssertTrue;
6 import javax.validation.constraints.NotNull; 11 import javax.validation.constraints.NotNull;
7 12
8 -/**  
9 - * 代码生成 Base VO,提供给添加、修改、详细的子 VO 使用  
10 - * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成  
11 - */ 13 +@Schema(description = "管理后台 - 代码生成表定义创建/修改 Response VO")
12 @Data 14 @Data
13 -public class CodegenTableBaseVO { 15 +public class CodegenTableSaveReqVO {
  16 +
  17 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  18 + private Long id;
14 19
15 @Schema(description = "生成场景,参见 CodegenSceneEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 20 @Schema(description = "生成场景,参见 CodegenSceneEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
16 @NotNull(message = "导入类型不能为空") 21 @NotNull(message = "导入类型不能为空")
@@ -70,4 +75,26 @@ public class CodegenTableBaseVO { @@ -70,4 +75,26 @@ public class CodegenTableBaseVO {
70 @Schema(description = "树表的名字字段编号", example = "16384") 75 @Schema(description = "树表的名字字段编号", example = "16384")
71 private Long treeNameColumnId; 76 private Long treeNameColumnId;
72 77
  78 + @AssertTrue(message = "上级菜单不能为空,请前往 [修改生成配置 -> 生成信息] 界面,设置“上级菜单”字段")
  79 + @JsonIgnore
  80 + public boolean isParentMenuIdValid() {
  81 + // 生成场景为管理后台时,必须设置上级菜单,不然生成的菜单 SQL 是无父级菜单的
  82 + return ObjectUtil.notEqual(getScene(), CodegenSceneEnum.ADMIN.getScene())
  83 + || getParentMenuId() != null;
  84 + }
  85 +
  86 + @AssertTrue(message = "关联的父表信息不全")
  87 + @JsonIgnore
  88 + public boolean isSubValid() {
  89 + return ObjectUtil.notEqual(getTemplateType(), CodegenTemplateTypeEnum.SUB)
  90 + || (ObjectUtil.isAllNotEmpty(masterTableId, subJoinColumnId, subJoinMany));
  91 + }
  92 +
  93 + @AssertTrue(message = "关联的树表信息不全")
  94 + @JsonIgnore
  95 + public boolean isTreeValid() {
  96 + return ObjectUtil.notEqual(templateType, CodegenTemplateTypeEnum.TREE)
  97 + || (ObjectUtil.isAllNotEmpty(treeParentColumnId, treeNameColumnId));
  98 + }
  99 +
73 } 100 }
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/codegen/CodegenConvert.java
1 package cn.iocoder.yudao.module.infra.convert.codegen; 1 package cn.iocoder.yudao.module.infra.convert.codegen;
2 2
3 -import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  4 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
4 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenDetailRespVO; 5 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenDetailRespVO;
5 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenPreviewRespVO; 6 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenPreviewRespVO;
6 -import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenUpdateReqVO;  
7 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column.CodegenColumnRespVO; 7 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column.CodegenColumnRespVO;
8 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTableRespVO; 8 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTableRespVO;
9 -import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.DatabaseTableRespVO;  
10 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO; 9 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
11 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; 10 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
12 import com.baomidou.mybatisplus.generator.config.po.TableField; 11 import com.baomidou.mybatisplus.generator.config.po.TableField;
@@ -20,7 +19,6 @@ import org.mapstruct.factory.Mappers; @@ -20,7 +19,6 @@ import org.mapstruct.factory.Mappers;
20 19
21 import java.util.List; 20 import java.util.List;
22 import java.util.Map; 21 import java.util.Map;
23 -import java.util.stream.Collectors;  
24 22
25 @Mapper 23 @Mapper
26 public interface CodegenConvert { 24 public interface CodegenConvert {
@@ -54,40 +52,18 @@ public interface CodegenConvert { @@ -54,40 +52,18 @@ public interface CodegenConvert {
54 return jdbcType.name(); 52 return jdbcType.name();
55 } 53 }
56 54
57 - // ========== CodegenTableDO 相关 ==========  
58 -  
59 - List<CodegenTableRespVO> convertList05(List<CodegenTableDO> list);  
60 -  
61 - CodegenTableRespVO convert(CodegenTableDO bean);  
62 -  
63 - PageResult<CodegenTableRespVO> convertPage(PageResult<CodegenTableDO> page);  
64 -  
65 - // ========== CodegenTableDO 相关 ==========  
66 -  
67 - List<CodegenColumnRespVO> convertList02(List<CodegenColumnDO> list);  
68 -  
69 - CodegenTableDO convert(CodegenUpdateReqVO.Table bean);  
70 -  
71 - List<CodegenColumnDO> convertList03(List<CodegenUpdateReqVO.Column> columns);  
72 -  
73 - List<DatabaseTableRespVO> convertList04(List<TableInfo> list);  
74 -  
75 // ========== 其它 ========== 55 // ========== 其它 ==========
76 56
77 default CodegenDetailRespVO convert(CodegenTableDO table, List<CodegenColumnDO> columns) { 57 default CodegenDetailRespVO convert(CodegenTableDO table, List<CodegenColumnDO> columns) {
78 CodegenDetailRespVO respVO = new CodegenDetailRespVO(); 58 CodegenDetailRespVO respVO = new CodegenDetailRespVO();
79 - respVO.setTable(convert(table));  
80 - respVO.setColumns(convertList02(columns)); 59 + respVO.setTable(BeanUtils.toBean(table, CodegenTableRespVO.class));
  60 + respVO.setColumns(BeanUtils.toBean(columns, CodegenColumnRespVO.class));
81 return respVO; 61 return respVO;
82 } 62 }
83 63
84 default List<CodegenPreviewRespVO> convert(Map<String, String> codes) { 64 default List<CodegenPreviewRespVO> convert(Map<String, String> codes) {
85 - return codes.entrySet().stream().map(entry -> {  
86 - CodegenPreviewRespVO respVO = new CodegenPreviewRespVO();  
87 - respVO.setFilePath(entry.getKey());  
88 - respVO.setCode(entry.getValue());  
89 - return respVO;  
90 - }).collect(Collectors.toList()); 65 + return CollectionUtils.convertList(codes.entrySet(),
  66 + entry -> new CodegenPreviewRespVO().setFilePath(entry.getKey()).setCode(entry.getValue()));
91 } 67 }
92 68
93 } 69 }
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenService.java
@@ -70,7 +70,7 @@ public interface CodegenService { @@ -70,7 +70,7 @@ public interface CodegenService {
70 * @param id 表编号 70 * @param id 表编号
71 * @return 表定义 71 * @return 表定义
72 */ 72 */
73 - CodegenTableDO getCodegenTablePage(Long id); 73 + CodegenTableDO getCodegenTable(Long id);
74 74
75 /** 75 /**
76 * 获得指定表的字段定义数组 76 * 获得指定表的字段定义数组
@@ -91,7 +91,6 @@ public interface CodegenService { @@ -91,7 +91,6 @@ public interface CodegenService {
91 /** 91 /**
92 * 获得数据库自带的表定义列表 92 * 获得数据库自带的表定义列表
93 * 93 *
94 - *  
95 * @param dataSourceConfigId 数据源的配置编号 94 * @param dataSourceConfigId 数据源的配置编号
96 * @param name 表名称 95 * @param name 表名称
97 * @param comment 表描述 96 * @param comment 表描述
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenServiceImpl.java
@@ -3,12 +3,11 @@ package cn.iocoder.yudao.module.infra.service.codegen; @@ -3,12 +3,11 @@ package cn.iocoder.yudao.module.infra.service.codegen;
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.util.StrUtil; 4 import cn.hutool.core.util.StrUtil;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 6 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
7 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenCreateListReqVO; 7 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenCreateListReqVO;
8 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenUpdateReqVO; 8 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenUpdateReqVO;
9 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTablePageReqVO; 9 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTablePageReqVO;
10 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.DatabaseTableRespVO; 10 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.DatabaseTableRespVO;
11 -import cn.iocoder.yudao.module.infra.convert.codegen.CodegenConvert;  
12 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO; 11 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
13 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; 12 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
14 import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenColumnMapper; 13 import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenColumnMapper;
@@ -22,6 +21,7 @@ import cn.iocoder.yudao.module.infra.service.db.DatabaseTableService; @@ -22,6 +21,7 @@ import cn.iocoder.yudao.module.infra.service.db.DatabaseTableService;
22 import cn.iocoder.yudao.module.system.api.user.AdminUserApi; 21 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
23 import com.baomidou.mybatisplus.generator.config.po.TableField; 22 import com.baomidou.mybatisplus.generator.config.po.TableField;
24 import com.baomidou.mybatisplus.generator.config.po.TableInfo; 23 import com.baomidou.mybatisplus.generator.config.po.TableInfo;
  24 +import com.google.common.annotations.VisibleForTesting;
25 import org.springframework.stereotype.Service; 25 import org.springframework.stereotype.Service;
26 import org.springframework.transaction.annotation.Transactional; 26 import org.springframework.transaction.annotation.Transactional;
27 27
@@ -31,6 +31,8 @@ import java.util.function.BiPredicate; @@ -31,6 +31,8 @@ import java.util.function.BiPredicate;
31 import java.util.stream.Collectors; 31 import java.util.stream.Collectors;
32 32
33 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 33 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  34 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
  35 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
34 import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; 36 import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
35 37
36 /** 38 /**
@@ -69,7 +71,7 @@ public class CodegenServiceImpl implements CodegenService { @@ -69,7 +71,7 @@ public class CodegenServiceImpl implements CodegenService {
69 return ids; 71 return ids;
70 } 72 }
71 73
72 - public Long createCodegen(Long userId, Long dataSourceConfigId, String tableName) { 74 + private Long createCodegen(Long userId, Long dataSourceConfigId, String tableName) {
73 // 从数据库中,获得数据库表结构 75 // 从数据库中,获得数据库表结构
74 TableInfo tableInfo = databaseTableService.getTable(dataSourceConfigId, tableName); 76 TableInfo tableInfo = databaseTableService.getTable(dataSourceConfigId, tableName);
75 // 导入 77 // 导入
@@ -103,7 +105,8 @@ public class CodegenServiceImpl implements CodegenService { @@ -103,7 +105,8 @@ public class CodegenServiceImpl implements CodegenService {
103 return table.getId(); 105 return table.getId();
104 } 106 }
105 107
106 - private void validateTableInfo(TableInfo tableInfo) { 108 + @VisibleForTesting
  109 + void validateTableInfo(TableInfo tableInfo) {
107 if (tableInfo == null) { 110 if (tableInfo == null) {
108 throw exception(CODEGEN_IMPORT_TABLE_NULL); 111 throw exception(CODEGEN_IMPORT_TABLE_NULL);
109 } 112 }
@@ -139,10 +142,10 @@ public class CodegenServiceImpl implements CodegenService { @@ -139,10 +142,10 @@ public class CodegenServiceImpl implements CodegenService {
139 } 142 }
140 143
141 // 更新 table 表定义 144 // 更新 table 表定义
142 - CodegenTableDO updateTableObj = CodegenConvert.INSTANCE.convert(updateReqVO.getTable()); 145 + CodegenTableDO updateTableObj = BeanUtils.toBean(updateReqVO.getTable(), CodegenTableDO.class);
143 codegenTableMapper.updateById(updateTableObj); 146 codegenTableMapper.updateById(updateTableObj);
144 // 更新 column 字段定义 147 // 更新 column 字段定义
145 - List<CodegenColumnDO> updateColumnObjs = CodegenConvert.INSTANCE.convertList03(updateReqVO.getColumns()); 148 + List<CodegenColumnDO> updateColumnObjs = BeanUtils.toBean(updateReqVO.getColumns(), CodegenColumnDO.class);
146 updateColumnObjs.forEach(updateColumnObj -> codegenColumnMapper.updateById(updateColumnObj)); 149 updateColumnObjs.forEach(updateColumnObj -> codegenColumnMapper.updateById(updateColumnObj));
147 } 150 }
148 151
@@ -161,29 +164,28 @@ public class CodegenServiceImpl implements CodegenService { @@ -161,29 +164,28 @@ public class CodegenServiceImpl implements CodegenService {
161 } 164 }
162 165
163 private void syncCodegen0(Long tableId, TableInfo tableInfo) { 166 private void syncCodegen0(Long tableId, TableInfo tableInfo) {
164 - // 校验导入的表和字段非空 167 + // 1. 校验导入的表和字段非空
165 validateTableInfo(tableInfo); 168 validateTableInfo(tableInfo);
166 List<TableField> tableFields = tableInfo.getFields(); 169 List<TableField> tableFields = tableInfo.getFields();
167 170
168 - // 构建 CodegenColumnDO 数组,只同步新增的字段 171 + // 2. 构建 CodegenColumnDO 数组,只同步新增的字段
169 List<CodegenColumnDO> codegenColumns = codegenColumnMapper.selectListByTableId(tableId); 172 List<CodegenColumnDO> codegenColumns = codegenColumnMapper.selectListByTableId(tableId);
170 - Set<String> codegenColumnNames = CollectionUtils.convertSet(codegenColumns, CodegenColumnDO::getColumnName); 173 + Set<String> codegenColumnNames = convertSet(codegenColumns, CodegenColumnDO::getColumnName);
171 174
172 - //计算需要修改的字段,插入时重新插入,删除时将原来的删除  
173 - BiPredicate<TableField, CodegenColumnDO> pr = 175 + // 3.1 计算需要【修改】的字段,插入时重新插入,删除时将原来的删除
  176 + Map<String, CodegenColumnDO> codegenColumnDOMap = convertMap(codegenColumns, CodegenColumnDO::getColumnName);
  177 + BiPredicate<TableField, CodegenColumnDO> primaryKeyPredicate =
174 (tableField, codegenColumn) -> tableField.getMetaInfo().getJdbcType().name().equals(codegenColumn.getDataType()) 178 (tableField, codegenColumn) -> tableField.getMetaInfo().getJdbcType().name().equals(codegenColumn.getDataType())
175 && tableField.getMetaInfo().isNullable() == codegenColumn.getNullable() 179 && tableField.getMetaInfo().isNullable() == codegenColumn.getNullable()
176 && tableField.isKeyFlag() == codegenColumn.getPrimaryKey() 180 && tableField.isKeyFlag() == codegenColumn.getPrimaryKey()
177 && tableField.getComment().equals(codegenColumn.getColumnComment()); 181 && tableField.getComment().equals(codegenColumn.getColumnComment());
178 - Map<String, CodegenColumnDO> codegenColumnDOMap = CollectionUtils.convertMap(codegenColumns, CodegenColumnDO::getColumnName);  
179 - //需要修改的字段  
180 Set<String> modifyFieldNames = tableFields.stream() 182 Set<String> modifyFieldNames = tableFields.stream()
181 .filter(tableField -> codegenColumnDOMap.get(tableField.getColumnName()) != null 183 .filter(tableField -> codegenColumnDOMap.get(tableField.getColumnName()) != null
182 - && !pr.test(tableField, codegenColumnDOMap.get(tableField.getColumnName()))) 184 + && !primaryKeyPredicate.test(tableField, codegenColumnDOMap.get(tableField.getColumnName())))
183 .map(TableField::getColumnName) 185 .map(TableField::getColumnName)
184 .collect(Collectors.toSet()); 186 .collect(Collectors.toSet());
185 - // 计算需要删除的字段  
186 - Set<String> tableFieldNames = CollectionUtils.convertSet(tableFields, TableField::getName); 187 + // 3.2 计算需要【删除】的字段
  188 + Set<String> tableFieldNames = convertSet(tableFields, TableField::getName);
187 Set<Long> deleteColumnIds = codegenColumns.stream() 189 Set<Long> deleteColumnIds = codegenColumns.stream()
188 .filter(column -> (!tableFieldNames.contains(column.getColumnName())) || modifyFieldNames.contains(column.getColumnName())) 190 .filter(column -> (!tableFieldNames.contains(column.getColumnName())) || modifyFieldNames.contains(column.getColumnName()))
189 .map(CodegenColumnDO::getId).collect(Collectors.toSet()); 191 .map(CodegenColumnDO::getId).collect(Collectors.toSet());
@@ -193,10 +195,10 @@ public class CodegenServiceImpl implements CodegenService { @@ -193,10 +195,10 @@ public class CodegenServiceImpl implements CodegenService {
193 throw exception(CODEGEN_SYNC_NONE_CHANGE); 195 throw exception(CODEGEN_SYNC_NONE_CHANGE);
194 } 196 }
195 197
196 - // 插入新增的字段 198 + // 4.1 插入新增的字段
197 List<CodegenColumnDO> columns = codegenBuilder.buildColumns(tableId, tableFields); 199 List<CodegenColumnDO> columns = codegenBuilder.buildColumns(tableId, tableFields);
198 codegenColumnMapper.insertBatch(columns); 200 codegenColumnMapper.insertBatch(columns);
199 - // 删除不存在的字段 201 + // 4.2 删除不存在的字段
200 if (CollUtil.isNotEmpty(deleteColumnIds)) { 202 if (CollUtil.isNotEmpty(deleteColumnIds)) {
201 codegenColumnMapper.deleteBatchIds(deleteColumnIds); 203 codegenColumnMapper.deleteBatchIds(deleteColumnIds);
202 } 204 }
@@ -227,7 +229,7 @@ public class CodegenServiceImpl implements CodegenService { @@ -227,7 +229,7 @@ public class CodegenServiceImpl implements CodegenService {
227 } 229 }
228 230
229 @Override 231 @Override
230 - public CodegenTableDO getCodegenTablePage(Long id) { 232 + public CodegenTableDO getCodegenTable(Long id) {
231 return codegenTableMapper.selectById(id); 233 return codegenTableMapper.selectById(id);
232 } 234 }
233 235
@@ -277,10 +279,10 @@ public class CodegenServiceImpl implements CodegenService { @@ -277,10 +279,10 @@ public class CodegenServiceImpl implements CodegenService {
277 public List<DatabaseTableRespVO> getDatabaseTableList(Long dataSourceConfigId, String name, String comment) { 279 public List<DatabaseTableRespVO> getDatabaseTableList(Long dataSourceConfigId, String name, String comment) {
278 List<TableInfo> tables = databaseTableService.getTableList(dataSourceConfigId, name, comment); 280 List<TableInfo> tables = databaseTableService.getTableList(dataSourceConfigId, name, comment);
279 // 移除在 Codegen 中,已经存在的 281 // 移除在 Codegen 中,已经存在的
280 - Set<String> existsTables = CollectionUtils.convertSet( 282 + Set<String> existsTables = convertSet(
281 codegenTableMapper.selectListByDataSourceConfigId(dataSourceConfigId), CodegenTableDO::getTableName); 283 codegenTableMapper.selectListByDataSourceConfigId(dataSourceConfigId), CodegenTableDO::getTableName);
282 tables.removeIf(table -> existsTables.contains(table.getName())); 284 tables.removeIf(table -> existsTables.contains(table.getName()));
283 - return CodegenConvert.INSTANCE.convertList04(tables); 285 + return BeanUtils.toBean(tables, DatabaseTableRespVO.class);
284 } 286 }
285 287
286 } 288 }
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/job/JobService.java
@@ -7,8 +7,6 @@ import cn.iocoder.yudao.module.infra.dal.dataobject.job.JobDO; @@ -7,8 +7,6 @@ import cn.iocoder.yudao.module.infra.dal.dataobject.job.JobDO;
7 import org.quartz.SchedulerException; 7 import org.quartz.SchedulerException;
8 8
9 import javax.validation.Valid; 9 import javax.validation.Valid;
10 -import java.util.Collection;  
11 -import java.util.List;  
12 10
13 /** 11 /**
14 * 定时任务 Service 接口 12 * 定时任务 Service 接口
@@ -63,14 +61,6 @@ public interface JobService { @@ -63,14 +61,6 @@ public interface JobService {
63 JobDO getJob(Long id); 61 JobDO getJob(Long id);
64 62
65 /** 63 /**
66 - * 获得定时任务列表  
67 - *  
68 - * @param ids 编号  
69 - * @return 定时任务列表  
70 - */  
71 - List<JobDO> getJobList(Collection<Long> ids);  
72 -  
73 - /**  
74 * 获得定时任务分页 64 * 获得定时任务分页
75 * 65 *
76 * @param pageReqVO 分页查询 66 * @param pageReqVO 分页查询
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/job/JobServiceImpl.java
@@ -148,11 +148,6 @@ public class JobServiceImpl implements JobService { @@ -148,11 +148,6 @@ public class JobServiceImpl implements JobService {
148 } 148 }
149 149
150 @Override 150 @Override
151 - public List<JobDO> getJobList(Collection<Long> ids) {  
152 - return jobMapper.selectBatchIds(ids);  
153 - }  
154 -  
155 - @Override  
156 public PageResult<JobDO> getJobPage(JobPageReqVO pageReqVO) { 151 public PageResult<JobDO> getJobPage(JobPageReqVO pageReqVO) {
157 return jobMapper.selectPage(pageReqVO); 152 return jobMapper.selectPage(pageReqVO);
158 } 153 }
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/index.vue.vm
@@ -269,7 +269,7 @@ const queryParams = reactive({ @@ -269,7 +269,7 @@ const queryParams = reactive({
269 #foreach ($column in $columns) 269 #foreach ($column in $columns)
270 #if ($column.listOperation) 270 #if ($column.listOperation)
271 #if ($column.listOperationCondition != 'BETWEEN') 271 #if ($column.listOperationCondition != 'BETWEEN')
272 - $column.javaField: null, 272 + $column.javaField: undefined,
273 #end 273 #end
274 #if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN") 274 #if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN")
275 $column.javaField: [], 275 $column.javaField: [],
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenServiceImplTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.codegen;
  2 +
  3 +import cn.hutool.core.collection.ListUtil;
  4 +import cn.hutool.core.map.MapUtil;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  7 +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenCreateListReqVO;
  8 +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenUpdateReqVO;
  9 +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column.CodegenColumnSaveReqVO;
  10 +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTablePageReqVO;
  11 +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.DatabaseTableRespVO;
  12 +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
  13 +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
  14 +import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenColumnMapper;
  15 +import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenTableMapper;
  16 +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum;
  17 +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum;
  18 +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
  19 +import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties;
  20 +import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenBuilder;
  21 +import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenEngine;
  22 +import cn.iocoder.yudao.module.infra.service.db.DatabaseTableService;
  23 +import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
  24 +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
  25 +import com.baomidou.mybatisplus.generator.config.po.TableField;
  26 +import com.baomidou.mybatisplus.generator.config.po.TableInfo;
  27 +import org.junit.jupiter.api.Test;
  28 +import org.springframework.boot.test.mock.mockito.MockBean;
  29 +import org.springframework.context.annotation.Import;
  30 +
  31 +import javax.annotation.Resource;
  32 +import java.util.Arrays;
  33 +import java.util.Collections;
  34 +import java.util.List;
  35 +import java.util.Map;
  36 +
  37 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
  38 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
  39 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
  40 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
  41 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
  42 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
  43 +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
  44 +import static org.junit.jupiter.api.Assertions.*;
  45 +import static org.mockito.ArgumentMatchers.*;
  46 +import static org.mockito.Mockito.mock;
  47 +import static org.mockito.Mockito.when;
  48 +
  49 +/**
  50 + * {@link CodegenServiceImpl} 的单元测试类
  51 + *
  52 + * @author 芋道源码
  53 + */
  54 +@Import(CodegenServiceImpl.class)
  55 +public class CodegenServiceImplTest extends BaseDbUnitTest {
  56 +
  57 + @Resource
  58 + private CodegenServiceImpl codegenService;
  59 +
  60 + @Resource
  61 + private CodegenTableMapper codegenTableMapper;
  62 + @Resource
  63 + private CodegenColumnMapper codegenColumnMapper;
  64 +
  65 + @MockBean
  66 + private DatabaseTableService databaseTableService;
  67 +
  68 + @MockBean
  69 + private AdminUserApi userApi;
  70 +
  71 + @MockBean
  72 + private CodegenBuilder codegenBuilder;
  73 + @MockBean
  74 + private CodegenEngine codegenEngine;
  75 +
  76 + @MockBean
  77 + private CodegenProperties codegenProperties;
  78 +
  79 + @Test
  80 + public void testCreateCodegenList() {
  81 + // 准备参数
  82 + Long userId = randomLongId();
  83 + CodegenCreateListReqVO reqVO = randomPojo(CodegenCreateListReqVO.class,
  84 + o -> o.setDataSourceConfigId(1L).setTableNames(Collections.singletonList("t_yunai")));
  85 + // mock 方法(TableInfo)
  86 + TableInfo tableInfo = mock(TableInfo.class);
  87 + when(databaseTableService.getTable(eq(1L), eq("t_yunai")))
  88 + .thenReturn(tableInfo);
  89 + when(tableInfo.getComment()).thenReturn("芋艿");
  90 + // mock 方法(TableInfo fields)
  91 + TableField field01 = mock(TableField.class);
  92 + when(field01.getComment()).thenReturn("主键");
  93 + TableField field02 = mock(TableField.class);
  94 + when(field02.getComment()).thenReturn("名字");
  95 + List<TableField> fields = Arrays.asList(field01, field02);
  96 + when(tableInfo.getFields()).thenReturn(fields);
  97 + // mock 方法(CodegenTableDO)
  98 + CodegenTableDO table = randomPojo(CodegenTableDO.class);
  99 + when(codegenBuilder.buildTable(same(tableInfo))).thenReturn(table);
  100 + // mock 方法(AdminUserRespDTO)
  101 + AdminUserRespDTO user = randomPojo(AdminUserRespDTO.class, o -> o.setNickname("芋头"));
  102 + when(userApi.getUser(eq(userId))).thenReturn(user);
  103 + // mock 方法(CodegenColumnDO)
  104 + List<CodegenColumnDO> columns = randomPojoList(CodegenColumnDO.class);
  105 + when(codegenBuilder.buildColumns(eq(table.getId()), same(fields)))
  106 + .thenReturn(columns);
  107 + // mock 方法(CodegenProperties)
  108 + when(codegenProperties.getFrontType()).thenReturn(CodegenFrontTypeEnum.VUE3.getType());
  109 +
  110 + // 调用
  111 + List<Long> result = codegenService.createCodegenList(userId, reqVO);
  112 + // 断言
  113 + assertEquals(1, result.size());
  114 + // 断言(CodegenTableDO)
  115 + CodegenTableDO dbTable = codegenTableMapper.selectList().get(0);
  116 + assertPojoEquals(table, dbTable);
  117 + assertEquals(1L, dbTable.getDataSourceConfigId());
  118 + assertEquals(CodegenSceneEnum.ADMIN.getScene(), dbTable.getScene());
  119 + assertEquals(CodegenFrontTypeEnum.VUE3.getType(), dbTable.getFrontType());
  120 + assertEquals("芋头", dbTable.getAuthor());
  121 + // 断言(CodegenColumnDO)
  122 + List<CodegenColumnDO> dbColumns = codegenColumnMapper.selectList();
  123 + assertEquals(columns.size(), dbColumns.size());
  124 + assertTrue(dbColumns.get(0).getPrimaryKey());
  125 + for (int i = 0; i < dbColumns.size(); i++) {
  126 + assertPojoEquals(columns.get(i), dbColumns.get(i));
  127 + }
  128 + }
  129 +
  130 + @Test
  131 + public void testValidateTableInfo() {
  132 + // 情况一
  133 + assertServiceException(() -> codegenService.validateTableInfo(null),
  134 + CODEGEN_IMPORT_TABLE_NULL);
  135 + // 情况二
  136 + TableInfo tableInfo = mock(TableInfo.class);
  137 + assertServiceException(() -> codegenService.validateTableInfo(tableInfo),
  138 + CODEGEN_TABLE_INFO_TABLE_COMMENT_IS_NULL);
  139 + // 情况三
  140 + when(tableInfo.getComment()).thenReturn("芋艿");
  141 + assertServiceException(() -> codegenService.validateTableInfo(tableInfo),
  142 + CODEGEN_IMPORT_COLUMNS_NULL);
  143 + // 情况四
  144 + TableField field = mock(TableField.class);
  145 + when(field.getName()).thenReturn("name");
  146 + when(tableInfo.getFields()).thenReturn(Collections.singletonList(field));
  147 + assertServiceException(() -> codegenService.validateTableInfo(tableInfo),
  148 + CODEGEN_TABLE_INFO_COLUMN_COMMENT_IS_NULL, field.getName());
  149 + }
  150 +
  151 + @Test
  152 + public void testUpdateCodegen_notExists() {
  153 + // 准备参数
  154 + CodegenUpdateReqVO updateReqVO = randomPojo(CodegenUpdateReqVO.class);
  155 + // mock 方法
  156 +
  157 + // 调用,并断言
  158 + assertServiceException(() -> codegenService.updateCodegen(updateReqVO),
  159 + CODEGEN_TABLE_NOT_EXISTS);
  160 + }
  161 +
  162 + @Test
  163 + public void testUpdateCodegen_sub_masterNotExists() {
  164 + // mock 数据
  165 + CodegenTableDO table = randomPojo(CodegenTableDO.class,
  166 + o -> o.setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
  167 + .setScene(CodegenSceneEnum.ADMIN.getScene()));
  168 + codegenTableMapper.insert(table);
  169 + // 准备参数
  170 + CodegenUpdateReqVO updateReqVO = randomPojo(CodegenUpdateReqVO.class,
  171 + o -> o.getTable().setId(table.getId())
  172 + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType()));
  173 +
  174 + // 调用,并断言
  175 + assertServiceException(() -> codegenService.updateCodegen(updateReqVO),
  176 + CODEGEN_MASTER_TABLE_NOT_EXISTS, updateReqVO.getTable().getMasterTableId());
  177 + }
  178 +
  179 + @Test
  180 + public void testUpdateCodegen_sub_columnNotExists() {
  181 + // mock 数据
  182 + CodegenTableDO subTable = randomPojo(CodegenTableDO.class,
  183 + o -> o.setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
  184 + .setScene(CodegenSceneEnum.ADMIN.getScene()));
  185 + codegenTableMapper.insert(subTable);
  186 + // mock 数据(master)
  187 + CodegenTableDO masterTable = randomPojo(CodegenTableDO.class,
  188 + o -> o.setTemplateType(CodegenTemplateTypeEnum.MASTER_ERP.getType())
  189 + .setScene(CodegenSceneEnum.ADMIN.getScene()));
  190 + codegenTableMapper.insert(masterTable);
  191 + // 准备参数
  192 + CodegenUpdateReqVO updateReqVO = randomPojo(CodegenUpdateReqVO.class,
  193 + o -> o.getTable().setId(subTable.getId())
  194 + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
  195 + .setMasterTableId(masterTable.getId()));
  196 +
  197 + // 调用,并断言
  198 + assertServiceException(() -> codegenService.updateCodegen(updateReqVO),
  199 + CODEGEN_SUB_COLUMN_NOT_EXISTS, updateReqVO.getTable().getSubJoinColumnId());
  200 + }
  201 +
  202 + @Test
  203 + public void testUpdateCodegen_success() {
  204 + // mock 数据
  205 + CodegenTableDO table = randomPojo(CodegenTableDO.class,
  206 + o -> o.setTemplateType(CodegenTemplateTypeEnum.ONE.getType())
  207 + .setScene(CodegenSceneEnum.ADMIN.getScene()));
  208 + codegenTableMapper.insert(table);
  209 + CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
  210 + codegenColumnMapper.insert(column01);
  211 + CodegenColumnDO column02 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
  212 + codegenColumnMapper.insert(column02);
  213 + // 准备参数
  214 + CodegenUpdateReqVO updateReqVO = randomPojo(CodegenUpdateReqVO.class,
  215 + o -> o.getTable().setId(table.getId())
  216 + .setTemplateType(CodegenTemplateTypeEnum.ONE.getType())
  217 + .setScene(CodegenSceneEnum.ADMIN.getScene()));
  218 + CodegenColumnSaveReqVO columnVO01 = randomPojo(CodegenColumnSaveReqVO.class,
  219 + o -> o.setId(column01.getId()).setTableId(table.getId()));
  220 + CodegenColumnSaveReqVO columnVO02 = randomPojo(CodegenColumnSaveReqVO.class,
  221 + o -> o.setId(column02.getId()).setTableId(table.getId()));
  222 + updateReqVO.setColumns(Arrays.asList(columnVO01, columnVO02));
  223 +
  224 + // 调用
  225 + codegenService.updateCodegen(updateReqVO);
  226 + // 断言
  227 + CodegenTableDO dbTable = codegenTableMapper.selectById(table.getId());
  228 + assertPojoEquals(updateReqVO.getTable(), dbTable);
  229 + List<CodegenColumnDO> dbColumns = codegenColumnMapper.selectList();
  230 + assertEquals(2, dbColumns.size());
  231 + assertPojoEquals(columnVO01, dbColumns.get(0));
  232 + assertPojoEquals(columnVO02, dbColumns.get(1));
  233 + }
  234 +
  235 + @Test
  236 + public void testSyncCodegenFromDB() {
  237 + // mock 数据(CodegenTableDO)
  238 + CodegenTableDO table = randomPojo(CodegenTableDO.class, o -> o.setTableName("t_yunai")
  239 + .setDataSourceConfigId(1L).setScene(CodegenSceneEnum.ADMIN.getScene()));
  240 + codegenTableMapper.insert(table);
  241 + CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId())
  242 + .setColumnName("id"));
  243 + codegenColumnMapper.insert(column01);
  244 + CodegenColumnDO column02 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId())
  245 + .setColumnName("name"));
  246 + codegenColumnMapper.insert(column02);
  247 + // 准备参数
  248 + Long tableId = table.getId();
  249 + // mock 方法(TableInfo)
  250 + TableInfo tableInfo = mock(TableInfo.class);
  251 + when(databaseTableService.getTable(eq(1L), eq("t_yunai")))
  252 + .thenReturn(tableInfo);
  253 + when(tableInfo.getComment()).thenReturn("芋艿");
  254 + // mock 方法(TableInfo fields)
  255 + TableField field01 = mock(TableField.class);
  256 + when(field01.getComment()).thenReturn("主键");
  257 + TableField field03 = mock(TableField.class);
  258 + when(field03.getComment()).thenReturn("分类");
  259 + List<TableField> fields = Arrays.asList(field01, field03);
  260 + when(tableInfo.getFields()).thenReturn(fields);
  261 + when(databaseTableService.getTable(eq(1L), eq("t_yunai")))
  262 + .thenReturn(tableInfo);
  263 + // mock 方法(CodegenTableDO)
  264 + List<CodegenColumnDO> newColumns = randomPojoList(CodegenColumnDO.class);
  265 + when(codegenBuilder.buildColumns(eq(table.getId()), argThat(tableFields -> {
  266 + assertEquals(2, tableFields.size());
  267 + assertSame(tableInfo.getFields(), tableFields);
  268 + return true;
  269 + }))).thenReturn(newColumns);
  270 +
  271 + // 调用
  272 + codegenService.syncCodegenFromDB(tableId);
  273 + // 断言
  274 + List<CodegenColumnDO> dbColumns = codegenColumnMapper.selectList();
  275 + assertEquals(newColumns.size(), dbColumns.size());
  276 + assertPojoEquals(newColumns.get(0), dbColumns.get(0));
  277 + assertPojoEquals(newColumns.get(1), dbColumns.get(1));
  278 + }
  279 +
  280 + @Test
  281 + public void testDeleteCodegen_notExists() {
  282 + assertServiceException(() -> codegenService.deleteCodegen(randomLongId()),
  283 + CODEGEN_TABLE_NOT_EXISTS);
  284 + }
  285 +
  286 + @Test
  287 + public void testDeleteCodegen_success() {
  288 + // mock 数据
  289 + CodegenTableDO table = randomPojo(CodegenTableDO.class,
  290 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene()));
  291 + codegenTableMapper.insert(table);
  292 + CodegenColumnDO column = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
  293 + codegenColumnMapper.insert(column);
  294 + // 准备参数
  295 + Long tableId = table.getId();
  296 +
  297 + // 调用
  298 + codegenService.deleteCodegen(tableId);
  299 + // 断言
  300 + assertNull(codegenTableMapper.selectById(tableId));
  301 + assertEquals(0, codegenColumnMapper.selectList().size());
  302 + }
  303 +
  304 + @Test
  305 + public void testGetCodegenTableList() {
  306 + // mock 数据
  307 + CodegenTableDO table01 = randomPojo(CodegenTableDO.class,
  308 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene()));
  309 + codegenTableMapper.insert(table01);
  310 + CodegenTableDO table02 = randomPojo(CodegenTableDO.class,
  311 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene()));
  312 + codegenTableMapper.insert(table02);
  313 + // 准备参数
  314 + Long dataSourceConfigId = table01.getDataSourceConfigId();
  315 +
  316 + // 调用
  317 + List<CodegenTableDO> result = codegenService.getCodegenTableList(dataSourceConfigId);
  318 + // 断言
  319 + assertEquals(1, result.size());
  320 + assertPojoEquals(table01, result.get(0));
  321 + }
  322 +
  323 + @Test
  324 + public void testGetCodegenTablePage() {
  325 + // mock 数据
  326 + CodegenTableDO tableDO = randomPojo(CodegenTableDO.class, o -> {
  327 + o.setTableName("t_yunai");
  328 + o.setTableComment("芋艿");
  329 + o.setClassName("SystemYunai");
  330 + o.setCreateTime(buildTime(2021, 3, 10));
  331 + }).setScene(CodegenSceneEnum.ADMIN.getScene());
  332 + codegenTableMapper.insert(tableDO);
  333 + // 测试 tableName 不匹配
  334 + codegenTableMapper.insert(cloneIgnoreId(tableDO, o -> o.setTableName(randomString())));
  335 + // 测试 tableComment 不匹配
  336 + codegenTableMapper.insert(cloneIgnoreId(tableDO, o -> o.setTableComment(randomString())));
  337 + // 测试 className 不匹配
  338 + codegenTableMapper.insert(cloneIgnoreId(tableDO, o -> o.setClassName(randomString())));
  339 + // 测试 createTime 不匹配
  340 + codegenTableMapper.insert(cloneIgnoreId(tableDO, logDO -> logDO.setCreateTime(buildTime(2021, 4, 10))));
  341 + // 准备参数
  342 + CodegenTablePageReqVO reqVO = new CodegenTablePageReqVO();
  343 + reqVO.setTableName("yunai");
  344 + reqVO.setTableComment("芋");
  345 + reqVO.setClassName("Yunai");
  346 + reqVO.setCreateTime(buildBetweenTime(2021, 3, 1, 2021, 3, 31));
  347 +
  348 + // 调用
  349 + PageResult<CodegenTableDO> pageResult = codegenService.getCodegenTablePage(reqVO);
  350 + // 断言,只查到了一条符合条件的
  351 + assertEquals(1, pageResult.getTotal());
  352 + assertEquals(1, pageResult.getList().size());
  353 + assertPojoEquals(tableDO, pageResult.getList().get(0));
  354 + }
  355 +
  356 + @Test
  357 + public void testGetCodegenTable() {
  358 + // mock 数据
  359 + CodegenTableDO tableDO = randomPojo(CodegenTableDO.class, o -> o.setScene(CodegenSceneEnum.ADMIN.getScene()));
  360 + codegenTableMapper.insert(tableDO);
  361 + // 准备参数
  362 + Long id = tableDO.getId();
  363 +
  364 + // 调用
  365 + CodegenTableDO result = codegenService.getCodegenTable(id);
  366 + // 断言
  367 + assertPojoEquals(tableDO, result);
  368 + }
  369 +
  370 + @Test
  371 + public void testGetCodegenColumnListByTableId() {
  372 + // mock 数据
  373 + CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class);
  374 + codegenColumnMapper.insert(column01);
  375 + CodegenColumnDO column02 = randomPojo(CodegenColumnDO.class);
  376 + codegenColumnMapper.insert(column02);
  377 + // 准备参数
  378 + Long tableId = column01.getTableId();
  379 +
  380 + // 调用
  381 + List<CodegenColumnDO> result = codegenService.getCodegenColumnListByTableId(tableId);
  382 + // 断言
  383 + assertEquals(1, result.size());
  384 + assertPojoEquals(column01, result.get(0));
  385 + }
  386 +
  387 + @Test
  388 + public void testGenerationCodes_tableNotExists() {
  389 + assertServiceException(() -> codegenService.generationCodes(randomLongId()),
  390 + CODEGEN_TABLE_NOT_EXISTS);
  391 + }
  392 +
  393 + @Test
  394 + public void testGenerationCodes_columnNotExists() {
  395 + // mock 数据(CodegenTableDO)
  396 + CodegenTableDO table = randomPojo(CodegenTableDO.class,
  397 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())
  398 + .setTemplateType(CodegenTemplateTypeEnum.MASTER_NORMAL.getType()));
  399 + codegenTableMapper.insert(table);
  400 + // 准备参数
  401 + Long tableId = table.getId();
  402 +
  403 + // 调用,并断言
  404 + assertServiceException(() -> codegenService.generationCodes(tableId),
  405 + CODEGEN_COLUMN_NOT_EXISTS);
  406 + }
  407 +
  408 + @Test
  409 + public void testGenerationCodes_sub_tableNotExists() {
  410 + // mock 数据(CodegenTableDO)
  411 + CodegenTableDO table = randomPojo(CodegenTableDO.class,
  412 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())
  413 + .setTemplateType(CodegenTemplateTypeEnum.MASTER_NORMAL.getType()));
  414 + codegenTableMapper.insert(table);
  415 + // mock 数据(CodegenColumnDO)
  416 + CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
  417 + codegenColumnMapper.insert(column01);
  418 + // 准备参数
  419 + Long tableId = table.getId();
  420 +
  421 + // 调用,并断言
  422 + assertServiceException(() -> codegenService.generationCodes(tableId),
  423 + CODEGEN_MASTER_GENERATION_FAIL_NO_SUB_TABLE);
  424 + }
  425 +
  426 + @Test
  427 + public void testGenerationCodes_sub_columnNotExists() {
  428 + // mock 数据(CodegenTableDO)
  429 + CodegenTableDO table = randomPojo(CodegenTableDO.class,
  430 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())
  431 + .setTemplateType(CodegenTemplateTypeEnum.MASTER_NORMAL.getType()));
  432 + codegenTableMapper.insert(table);
  433 + // mock 数据(CodegenColumnDO)
  434 + CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
  435 + codegenColumnMapper.insert(column01);
  436 + // mock 数据(sub CodegenTableDO)
  437 + CodegenTableDO subTable = randomPojo(CodegenTableDO.class,
  438 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())
  439 + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
  440 + .setMasterTableId(table.getId()));
  441 + codegenTableMapper.insert(subTable);
  442 + // 准备参数
  443 + Long tableId = table.getId();
  444 +
  445 + // 调用,并断言
  446 + assertServiceException(() -> codegenService.generationCodes(tableId),
  447 + CODEGEN_SUB_COLUMN_NOT_EXISTS, subTable.getId());
  448 + }
  449 +
  450 + @Test
  451 + public void testGenerationCodes_one_success() {
  452 + // mock 数据(CodegenTableDO)
  453 + CodegenTableDO table = randomPojo(CodegenTableDO.class,
  454 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())
  455 + .setTemplateType(CodegenTemplateTypeEnum.ONE.getType()));
  456 + codegenTableMapper.insert(table);
  457 + // mock 数据(CodegenColumnDO)
  458 + CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
  459 + codegenColumnMapper.insert(column01);
  460 + CodegenColumnDO column02 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
  461 + codegenColumnMapper.insert(column02);
  462 + // mock 执行生成
  463 + Map<String, String> codes = MapUtil.of(randomString(), randomString());
  464 + when(codegenEngine.execute(eq(table), argThat(columns -> {
  465 + assertEquals(2, columns.size());
  466 + assertEquals(column01, columns.get(0));
  467 + assertEquals(column02, columns.get(1));
  468 + return true;
  469 + }), isNull(), isNull())).thenReturn(codes);
  470 + // 准备参数
  471 + Long tableId = table.getId();
  472 +
  473 + // 调用
  474 + Map<String, String> result = codegenService.generationCodes(tableId);
  475 + // 断言
  476 + assertSame(codes, result);
  477 + }
  478 +
  479 + @Test
  480 + public void testGenerationCodes_master_success() {
  481 + // mock 数据(CodegenTableDO)
  482 + CodegenTableDO table = randomPojo(CodegenTableDO.class,
  483 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())
  484 + .setTemplateType(CodegenTemplateTypeEnum.MASTER_NORMAL.getType()));
  485 + codegenTableMapper.insert(table);
  486 + // mock 数据(CodegenColumnDO)
  487 + CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
  488 + codegenColumnMapper.insert(column01);
  489 + CodegenColumnDO column02 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
  490 + codegenColumnMapper.insert(column02);
  491 + // mock 数据(sub CodegenTableDO)
  492 + CodegenTableDO subTable = randomPojo(CodegenTableDO.class,
  493 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())
  494 + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
  495 + .setMasterTableId(table.getId())
  496 + .setSubJoinColumnId(1024L));
  497 + codegenTableMapper.insert(subTable);
  498 + // mock 数据(sub CodegenColumnDO)
  499 + CodegenColumnDO subColumn01 = randomPojo(CodegenColumnDO.class, o -> o.setId(1024L).setTableId(subTable.getId()));
  500 + codegenColumnMapper.insert(subColumn01);
  501 + // mock 执行生成
  502 + Map<String, String> codes = MapUtil.of(randomString(), randomString());
  503 + when(codegenEngine.execute(eq(table), argThat(columns -> {
  504 + assertEquals(2, columns.size());
  505 + assertEquals(column01, columns.get(0));
  506 + assertEquals(column02, columns.get(1));
  507 + return true;
  508 + }), argThat(tables -> {
  509 + assertEquals(1, tables.size());
  510 + assertPojoEquals(subTable, tables.get(0));
  511 + return true;
  512 + }), argThat(columns -> {
  513 + assertEquals(1, columns.size());
  514 + assertPojoEquals(subColumn01, columns.size());
  515 + return true;
  516 + }))).thenReturn(codes);
  517 + // 准备参数
  518 + Long tableId = table.getId();
  519 +
  520 + // 调用
  521 + Map<String, String> result = codegenService.generationCodes(tableId);
  522 + // 断言
  523 + assertSame(codes, result);
  524 + }
  525 +
  526 + @Test
  527 + public void testGetDatabaseTableList() {
  528 + // 准备参数
  529 + Long dataSourceConfigId = randomLongId();
  530 + String name = randomString();
  531 + String comment = randomString();
  532 + // mock 方法
  533 + TableInfo tableInfo01 = mock(TableInfo.class);
  534 + when(tableInfo01.getName()).thenReturn("t_yunai");
  535 + when(tableInfo01.getComment()).thenReturn("芋艿");
  536 + TableInfo tableInfo02 = mock(TableInfo.class);
  537 + when(tableInfo02.getName()).thenReturn("t_yunai_02");
  538 + when(tableInfo02.getComment()).thenReturn("芋艿_02");
  539 + when(databaseTableService.getTableList(eq(dataSourceConfigId), eq(name), eq(comment)))
  540 + .thenReturn(ListUtil.toList(tableInfo01, tableInfo02));
  541 + // mock 数据
  542 + CodegenTableDO tableDO = randomPojo(CodegenTableDO.class,
  543 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())
  544 + .setTableName("t_yunai_02")
  545 + .setDataSourceConfigId(dataSourceConfigId));
  546 + codegenTableMapper.insert(tableDO);
  547 +
  548 + // 调用
  549 + List<DatabaseTableRespVO> result = codegenService.getDatabaseTableList(dataSourceConfigId, name, comment);
  550 + // 断言
  551 + assertEquals(1, result.size());
  552 + assertEquals("t_yunai", result.get(0).getName());
  553 + assertEquals("芋艿", result.get(0).getComment());
  554 + }
  555 +
  556 +}
0 \ No newline at end of file 557 \ No newline at end of file
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenBuilderTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.codegen.inner;
  2 +
  3 +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
  4 +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
  5 +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
  6 +import com.baomidou.mybatisplus.generator.config.po.TableField;
  7 +import com.baomidou.mybatisplus.generator.config.po.TableInfo;
  8 +import com.baomidou.mybatisplus.generator.config.rules.IColumnType;
  9 +import org.apache.ibatis.type.JdbcType;
  10 +import org.junit.jupiter.api.Test;
  11 +import org.mockito.InjectMocks;
  12 +
  13 +import java.util.Collections;
  14 +import java.util.List;
  15 +
  16 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
  17 +import static org.junit.jupiter.api.Assertions.*;
  18 +import static org.mockito.Mockito.mock;
  19 +import static org.mockito.Mockito.when;
  20 +
  21 +public class CodegenBuilderTest extends BaseMockitoUnitTest {
  22 +
  23 + @InjectMocks
  24 + private CodegenBuilder codegenBuilder;
  25 +
  26 + @Test
  27 + public void testBuildTable() {
  28 + // 准备参数
  29 + TableInfo tableInfo = mock(TableInfo.class);
  30 + // mock 方法
  31 + when(tableInfo.getName()).thenReturn("system_user");
  32 + when(tableInfo.getComment()).thenReturn("用户");
  33 +
  34 + // 调用
  35 + CodegenTableDO table = codegenBuilder.buildTable(tableInfo);
  36 + // 断言
  37 + assertEquals("system_user", table.getTableName());
  38 + assertEquals("用户", table.getTableComment());
  39 + assertEquals("system", table.getModuleName());
  40 + assertEquals("user", table.getBusinessName());
  41 + assertEquals("User", table.getClassName());
  42 + assertEquals("用户", table.getClassComment());
  43 + }
  44 +
  45 + @Test
  46 + public void testBuildColumns() {
  47 + // 准备参数
  48 + Long tableId = randomLongId();
  49 + TableField tableField = mock(TableField.class);
  50 + List<TableField> tableFields = Collections.singletonList(tableField);
  51 + // mock 方法
  52 + TableField.MetaInfo metaInfo = mock(TableField.MetaInfo.class);
  53 + when(tableField.getMetaInfo()).thenReturn(metaInfo);
  54 + when(metaInfo.getJdbcType()).thenReturn(JdbcType.BIGINT);
  55 + when(tableField.getComment()).thenReturn("编号");
  56 + when(tableField.isKeyFlag()).thenReturn(true);
  57 + when(tableField.isKeyIdentityFlag()).thenReturn(true);
  58 + IColumnType columnType = mock(IColumnType.class);
  59 + when(tableField.getColumnType()).thenReturn(columnType);
  60 + when(columnType.getType()).thenReturn("Long");
  61 + when(tableField.getName()).thenReturn("id2");
  62 + when(tableField.getPropertyName()).thenReturn("id");
  63 +
  64 + // 调用
  65 + List<CodegenColumnDO> columns = codegenBuilder.buildColumns(tableId, tableFields);
  66 + // 断言
  67 + assertEquals(1, columns.size());
  68 + CodegenColumnDO column = columns.get(0);
  69 + assertEquals(tableId, column.getTableId());
  70 + assertEquals("id2", column.getColumnName());
  71 + assertEquals("BIGINT", column.getDataType());
  72 + assertEquals("编号", column.getColumnComment());
  73 + assertFalse(column.getNullable());
  74 + assertTrue(column.getPrimaryKey());
  75 + assertTrue(column.getAutoIncrement());
  76 + assertEquals(1, column.getOrdinalPosition());
  77 + assertEquals("Long", column.getJavaType());
  78 + assertEquals("id", column.getJavaField());
  79 + assertNull(column.getDictType());
  80 + assertNotNull(column.getExample());
  81 + assertFalse(column.getCreateOperation());
  82 + assertTrue(column.getUpdateOperation());
  83 + assertFalse(column.getListOperation());
  84 + assertEquals("=", column.getListOperationCondition());
  85 + assertTrue(column.getListOperationResult());
  86 + assertEquals("input", column.getHtmlType());
  87 + }
  88 +
  89 +}
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/package-info.java deleted
1 -/**  
2 - * 占位,无其它作用  
3 - */  
4 -package cn.iocoder.yudao.module.infra.service.codegen;  
5 \ No newline at end of file 0 \ No newline at end of file
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/job/JobLogServiceImplTest.java
@@ -10,8 +10,11 @@ import org.junit.jupiter.api.Test; @@ -10,8 +10,11 @@ import org.junit.jupiter.api.Test;
10 import org.springframework.context.annotation.Import; 10 import org.springframework.context.annotation.Import;
11 11
12 import javax.annotation.Resource; 12 import javax.annotation.Resource;
  13 +import java.time.Duration;
13 import java.time.LocalDateTime; 14 import java.time.LocalDateTime;
  15 +import java.util.List;
14 16
  17 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime;
15 import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; 18 import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
16 import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; 19 import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
17 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; 20 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
@@ -93,6 +96,28 @@ public class JobLogServiceImplTest extends BaseDbUnitTest { @@ -93,6 +96,28 @@ public class JobLogServiceImplTest extends BaseDbUnitTest {
93 } 96 }
94 97
95 @Test 98 @Test
  99 + public void testCleanJobLog() {
  100 + // mock 数据
  101 + JobLogDO log01 = randomPojo(JobLogDO.class, o -> o.setCreateTime(addTime(Duration.ofDays(-3))))
  102 + .setExecuteIndex(1);
  103 + jobLogMapper.insert(log01);
  104 + JobLogDO log02 = randomPojo(JobLogDO.class, o -> o.setCreateTime(addTime(Duration.ofDays(-1))))
  105 + .setExecuteIndex(1);
  106 + jobLogMapper.insert(log02);
  107 + // 准备参数
  108 + Integer exceedDay = 2;
  109 + Integer deleteLimit = 1;
  110 +
  111 + // 调用
  112 + Integer count = jobLogService.cleanJobLog(exceedDay, deleteLimit);
  113 + // 断言
  114 + assertEquals(1, count);
  115 + List<JobLogDO> logs = jobLogMapper.selectList();
  116 + assertEquals(1, logs.size());
  117 + assertEquals(log02, logs.get(0));
  118 + }
  119 +
  120 + @Test
96 public void testGetJobLog() { 121 public void testGetJobLog() {
97 // mock 数据 122 // mock 数据
98 JobLogDO dbJobLog = randomPojo(JobLogDO.class, o -> o.setExecuteIndex(1)); 123 JobLogDO dbJobLog = randomPojo(JobLogDO.class, o -> o.setExecuteIndex(1));
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/logger/ApiAccessLogServiceImplTest.java
@@ -12,9 +12,10 @@ import org.junit.jupiter.api.Test; @@ -12,9 +12,10 @@ import org.junit.jupiter.api.Test;
12 import org.springframework.context.annotation.Import; 12 import org.springframework.context.annotation.Import;
13 13
14 import javax.annotation.Resource; 14 import javax.annotation.Resource;
  15 +import java.time.Duration;
  16 +import java.util.List;
15 17
16 -import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;  
17 -import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; 18 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
18 import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; 19 import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
19 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; 20 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
20 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; 21 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
@@ -74,6 +75,26 @@ public class ApiAccessLogServiceImplTest extends BaseDbUnitTest { @@ -74,6 +75,26 @@ public class ApiAccessLogServiceImplTest extends BaseDbUnitTest {
74 } 75 }
75 76
76 @Test 77 @Test
  78 + public void testCleanJobLog() {
  79 + // mock 数据
  80 + ApiAccessLogDO log01 = randomPojo(ApiAccessLogDO.class, o -> o.setCreateTime(addTime(Duration.ofDays(-3))));
  81 + apiAccessLogMapper.insert(log01);
  82 + ApiAccessLogDO log02 = randomPojo(ApiAccessLogDO.class, o -> o.setCreateTime(addTime(Duration.ofDays(-1))));
  83 + apiAccessLogMapper.insert(log02);
  84 + // 准备参数
  85 + Integer exceedDay = 2;
  86 + Integer deleteLimit = 1;
  87 +
  88 + // 调用
  89 + Integer count = apiAccessLogService.cleanAccessLog(exceedDay, deleteLimit);
  90 + // 断言
  91 + assertEquals(1, count);
  92 + List<ApiAccessLogDO> logs = apiAccessLogMapper.selectList();
  93 + assertEquals(1, logs.size());
  94 + assertEquals(log02, logs.get(0));
  95 + }
  96 +
  97 + @Test
77 public void testCreateApiAccessLog() { 98 public void testCreateApiAccessLog() {
78 // 准备参数 99 // 准备参数
79 ApiAccessLogCreateReqDTO createDTO = randomPojo(ApiAccessLogCreateReqDTO.class); 100 ApiAccessLogCreateReqDTO createDTO = randomPojo(ApiAccessLogCreateReqDTO.class);
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/logger/ApiErrorLogServiceImplTest.java
@@ -12,10 +12,11 @@ import org.junit.jupiter.api.Test; @@ -12,10 +12,11 @@ import org.junit.jupiter.api.Test;
12 import org.springframework.context.annotation.Import; 12 import org.springframework.context.annotation.Import;
13 13
14 import javax.annotation.Resource; 14 import javax.annotation.Resource;
  15 +import java.time.Duration;
  16 +import java.util.List;
15 17
16 import static cn.hutool.core.util.RandomUtil.randomEle; 18 import static cn.hutool.core.util.RandomUtil.randomEle;
17 -import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;  
18 -import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; 19 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
19 import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; 20 import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
20 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; 21 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
21 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; 22 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
@@ -50,13 +51,13 @@ public class ApiErrorLogServiceImplTest extends BaseDbUnitTest { @@ -50,13 +51,13 @@ public class ApiErrorLogServiceImplTest extends BaseDbUnitTest {
50 // 测试 userId 不匹配 51 // 测试 userId 不匹配
51 apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, o -> o.setUserId(3344L))); 52 apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, o -> o.setUserId(3344L)));
52 // 测试 userType 不匹配 53 // 测试 userType 不匹配
53 - apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, logDO -> logDO.setUserType(UserTypeEnum.MEMBER.getValue()))); 54 + apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, o -> o.setUserType(UserTypeEnum.MEMBER.getValue())));
54 // 测试 applicationName 不匹配 55 // 测试 applicationName 不匹配
55 - apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, logDO -> logDO.setApplicationName("test"))); 56 + apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, o -> o.setApplicationName("test")));
56 // 测试 requestUrl 不匹配 57 // 测试 requestUrl 不匹配
57 - apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, logDO -> logDO.setRequestUrl("bar"))); 58 + apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, o -> o.setRequestUrl("bar")));
58 // 测试 exceptionTime 不匹配:构造一个早期时间 2021-02-06 00:00:00 59 // 测试 exceptionTime 不匹配:构造一个早期时间 2021-02-06 00:00:00
59 - apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, logDO -> logDO.setExceptionTime(buildTime(2021, 2, 6)))); 60 + apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, o -> o.setExceptionTime(buildTime(2021, 2, 6))));
60 // 测试 progressStatus 不匹配 61 // 测试 progressStatus 不匹配
61 apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, logDO -> logDO.setProcessStatus(ApiErrorLogProcessStatusEnum.DONE.getStatus()))); 62 apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, logDO -> logDO.setProcessStatus(ApiErrorLogProcessStatusEnum.DONE.getStatus())));
62 // 准备参数 63 // 准备参数
@@ -139,4 +140,24 @@ public class ApiErrorLogServiceImplTest extends BaseDbUnitTest { @@ -139,4 +140,24 @@ public class ApiErrorLogServiceImplTest extends BaseDbUnitTest {
139 API_ERROR_LOG_NOT_FOUND); 140 API_ERROR_LOG_NOT_FOUND);
140 } 141 }
141 142
  143 + @Test
  144 + public void testCleanJobLog() {
  145 + // mock 数据
  146 + ApiErrorLogDO log01 = randomPojo(ApiErrorLogDO.class, o -> o.setCreateTime(addTime(Duration.ofDays(-3))));
  147 + apiErrorLogMapper.insert(log01);
  148 + ApiErrorLogDO log02 = randomPojo(ApiErrorLogDO.class, o -> o.setCreateTime(addTime(Duration.ofDays(-1))));
  149 + apiErrorLogMapper.insert(log02);
  150 + // 准备参数
  151 + Integer exceedDay = 2;
  152 + Integer deleteLimit = 1;
  153 +
  154 + // 调用
  155 + Integer count = apiErrorLogService.cleanErrorLog(exceedDay, deleteLimit);
  156 + // 断言
  157 + assertEquals(1, count);
  158 + List<ApiErrorLogDO> logs = apiErrorLogMapper.selectList();
  159 + assertEquals(1, logs.size());
  160 + assertEquals(log02, logs.get(0));
  161 + }
  162 +
142 } 163 }
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_erp/vue/index
@@ -197,11 +197,11 @@ const total = ref(0) // 列表的总页数 @@ -197,11 +197,11 @@ const total = ref(0) // 列表的总页数
197 const queryParams = reactive({ 197 const queryParams = reactive({
198 pageNo: 1, 198 pageNo: 1,
199 pageSize: 10, 199 pageSize: 10,
200 - name: null,  
201 - birthday: null, 200 + name: undefined,
  201 + birthday: undefined,
202 birthday: [], 202 birthday: [],
203 - sex: null,  
204 - enabled: null, 203 + sex: undefined,
  204 + enabled: undefined,
205 createTime: [] 205 createTime: []
206 }) 206 })
207 const queryFormRef = ref() // 搜索的表单 207 const queryFormRef = ref() // 搜索的表单
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_inner/vue/index
@@ -192,11 +192,11 @@ const total = ref(0) // 列表的总页数 @@ -192,11 +192,11 @@ const total = ref(0) // 列表的总页数
192 const queryParams = reactive({ 192 const queryParams = reactive({
193 pageNo: 1, 193 pageNo: 1,
194 pageSize: 10, 194 pageSize: 10,
195 - name: null,  
196 - birthday: null, 195 + name: undefined,
  196 + birthday: undefined,
197 birthday: [], 197 birthday: [],
198 - sex: null,  
199 - enabled: null, 198 + sex: undefined,
  199 + enabled: undefined,
200 createTime: [] 200 createTime: []
201 }) 201 })
202 const queryFormRef = ref() // 搜索的表单 202 const queryFormRef = ref() // 搜索的表单
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_normal/vue/index
@@ -177,11 +177,11 @@ const total = ref(0) // 列表的总页数 @@ -177,11 +177,11 @@ const total = ref(0) // 列表的总页数
177 const queryParams = reactive({ 177 const queryParams = reactive({
178 pageNo: 1, 178 pageNo: 1,
179 pageSize: 10, 179 pageSize: 10,
180 - name: null,  
181 - birthday: null, 180 + name: undefined,
  181 + birthday: undefined,
182 birthday: [], 182 birthday: [],
183 - sex: null,  
184 - enabled: null, 183 + sex: undefined,
  184 + enabled: undefined,
185 createTime: [] 185 createTime: []
186 }) 186 })
187 const queryFormRef = ref() // 搜索的表单 187 const queryFormRef = ref() // 搜索的表单
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_one/vue/index
@@ -177,11 +177,11 @@ const total = ref(0) // 列表的总页数 @@ -177,11 +177,11 @@ const total = ref(0) // 列表的总页数
177 const queryParams = reactive({ 177 const queryParams = reactive({
178 pageNo: 1, 178 pageNo: 1,
179 pageSize: 10, 179 pageSize: 10,
180 - name: null,  
181 - birthday: null, 180 + name: undefined,
  181 + birthday: undefined,
182 birthday: [], 182 birthday: [],
183 - sex: null,  
184 - enabled: null, 183 + sex: undefined,
  184 + enabled: undefined,
185 createTime: [] 185 createTime: []
186 }) 186 })
187 const queryFormRef = ref() // 搜索的表单 187 const queryFormRef = ref() // 搜索的表单
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_tree/vue/index
@@ -106,7 +106,7 @@ const { t } = useI18n() // 国际化 @@ -106,7 +106,7 @@ const { t } = useI18n() // 国际化
106 const loading = ref(true) // 列表的加载中 106 const loading = ref(true) // 列表的加载中
107 const list = ref([]) // 列表的数据 107 const list = ref([]) // 列表的数据
108 const queryParams = reactive({ 108 const queryParams = reactive({
109 - name: null 109 + name: undefined
110 }) 110 })
111 const queryFormRef = ref() // 搜索的表单 111 const queryFormRef = ref() // 搜索的表单
112 const exportLoading = ref(false) // 导出的加载中 112 const exportLoading = ref(false) // 导出的加载中
yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/clean.sql
@@ -8,3 +8,5 @@ DELETE FROM &quot;infra_api_error_log&quot;; @@ -8,3 +8,5 @@ DELETE FROM &quot;infra_api_error_log&quot;;
8 DELETE FROM "infra_file_config"; 8 DELETE FROM "infra_file_config";
9 DELETE FROM "infra_test_demo"; 9 DELETE FROM "infra_test_demo";
10 DELETE FROM "infra_data_source_config"; 10 DELETE FROM "infra_data_source_config";
  11 +DELETE FROM "infra_codegen_table";
  12 +DELETE FROM "infra_codegen_column";
yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/create_tables.sql
@@ -170,3 +170,59 @@ CREATE TABLE IF NOT EXISTS &quot;infra_data_source_config&quot; ( @@ -170,3 +170,59 @@ CREATE TABLE IF NOT EXISTS &quot;infra_data_source_config&quot; (
170 "deleted" bit NOT NULL DEFAULT FALSE, 170 "deleted" bit NOT NULL DEFAULT FALSE,
171 PRIMARY KEY ("id") 171 PRIMARY KEY ("id")
172 ) COMMENT '数据源配置表'; 172 ) COMMENT '数据源配置表';
  173 +
  174 +CREATE TABLE IF NOT EXISTS "infra_codegen_table" (
  175 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  176 + "data_source_config_id" bigint not null,
  177 + "scene" tinyint not null DEFAULT 1,
  178 + "table_name" varchar(200) NOT NULL,
  179 + "table_comment" varchar(500) NOT NULL,
  180 + "remark" varchar(500) NOT NULL,
  181 + "module_name" varchar(30) NOT NULL,
  182 + "business_name" varchar(30) NOT NULL,
  183 + "class_name" varchar(100) NOT NULL,
  184 + "class_comment" varchar(50) NOT NULL,
  185 + "author" varchar(50) NOT NULL,
  186 + "template_type" tinyint not null DEFAULT 1,
  187 + "front_type" tinyint not null,
  188 + "parent_menu_id" bigint not null,
  189 + "master_table_id" bigint not null,
  190 + "sub_join_column_id" bigint not null,
  191 + "sub_join_many" bit not null,
  192 + "tree_parent_column_id" bigint not null,
  193 + "tree_name_column_id" bigint not null,
  194 + "creator" varchar(64) DEFAULT '',
  195 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  196 + "updater" varchar(64) DEFAULT '',
  197 + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  198 + "deleted" bit NOT NULL DEFAULT FALSE,
  199 + PRIMARY KEY ("id")
  200 +) COMMENT '代码生成表定义表';
  201 +
  202 +CREATE TABLE IF NOT EXISTS "infra_codegen_column" (
  203 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  204 + "table_id" bigint not null,
  205 + "column_name" varchar(200) NOT NULL,
  206 + "data_type" varchar(100) NOT NULL,
  207 + "column_comment" varchar(500) NOT NULL,
  208 + "nullable" tinyint not null,
  209 + "primary_key" tinyint not null,
  210 + "auto_increment" varchar(5) not null,
  211 + "ordinal_position" int not null,
  212 + "java_type" varchar(32) NOT NULL,
  213 + "java_field" varchar(64) NOT NULL,
  214 + "dict_type" varchar(200) NOT NULL,
  215 + "example" varchar(64) NOT NULL,
  216 + "create_operation" bit not null,
  217 + "update_operation" bit not null,
  218 + "list_operation" bit not null,
  219 + "list_operation_condition" varchar(32) not null,
  220 + "list_operation_result" bit not null,
  221 + "html_type" varchar(32) NOT NULL,
  222 + "creator" varchar(64) DEFAULT '',
  223 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  224 + "updater" varchar(64) DEFAULT '',
  225 + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  226 + "deleted" bit NOT NULL DEFAULT FALSE,
  227 + PRIMARY KEY ("id")
  228 +) COMMENT '代码生成表字段定义表';
173 \ No newline at end of file 229 \ No newline at end of file
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dict/DictDataController.java
1 package cn.iocoder.yudao.module.system.controller.admin.dict; 1 package cn.iocoder.yudao.module.system.controller.admin.dict;
2 2
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
3 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 import cn.iocoder.yudao.framework.common.pojo.PageParam; 5 import cn.iocoder.yudao.framework.common.pojo.PageParam;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
@@ -66,7 +67,8 @@ public class DictDataController { @@ -66,7 +67,8 @@ public class DictDataController {
66 @Operation(summary = "获得全部字典数据列表", description = "一般用于管理后台缓存字典数据在本地") 67 @Operation(summary = "获得全部字典数据列表", description = "一般用于管理后台缓存字典数据在本地")
67 // 无需添加权限认证,因为前端全局都需要 68 // 无需添加权限认证,因为前端全局都需要
68 public CommonResult<List<DictDataSimpleRespVO>> getSimpleDictDataList() { 69 public CommonResult<List<DictDataSimpleRespVO>> getSimpleDictDataList() {
69 - List<DictDataDO> list = dictDataService.getDictDataList(); 70 + List<DictDataDO> list = dictDataService.getDictDataList(
  71 + CommonStatusEnum.ENABLE.getStatus(), null);
70 return success(BeanUtils.toBean(list, DictDataSimpleRespVO.class)); 72 return success(BeanUtils.toBean(list, DictDataSimpleRespVO.class));
71 } 73 }
72 74
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/vo/user/SocialUserPageReqVO.java
@@ -23,7 +23,7 @@ public class SocialUserPageReqVO extends PageParam { @@ -23,7 +23,7 @@ public class SocialUserPageReqVO extends PageParam {
23 @Schema(description = "用户昵称", example = "李四") 23 @Schema(description = "用户昵称", example = "李四")
24 private String nickname; 24 private String nickname;
25 25
26 - @Schema(description = "社交 openid", example = "oz-Jdt0kd_jdhUxJHQdBJMlOFN7w\n") 26 + @Schema(description = "社交 openid", example = "oz-Jdt0kd_jdhUxJHQdBJMlOFN7w")
27 private String openid; 27 private String openid;
28 28
29 @Schema(description = "创建时间") 29 @Schema(description = "创建时间")
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserSaveReqVO.java
@@ -14,8 +14,7 @@ import java.util.Set; @@ -14,8 +14,7 @@ import java.util.Set;
14 @Data 14 @Data
15 public class UserSaveReqVO { 15 public class UserSaveReqVO {
16 16
17 - @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")  
18 - @NotNull(message = "用户编号不能为空") 17 + @Schema(description = "用户编号", example = "1024")
19 private Long id; 18 private Long id;
20 19
21 @Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") 20 @Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao")
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/dict/AppDictDataController.java
1 package cn.iocoder.yudao.module.system.controller.app.dict; 1 package cn.iocoder.yudao.module.system.controller.app.dict;
2 2
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
3 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
5 import cn.iocoder.yudao.module.system.controller.app.dict.vo.AppDictDataRespVO; 6 import cn.iocoder.yudao.module.system.controller.app.dict.vo.AppDictDataRespVO;
@@ -32,7 +33,8 @@ public class AppDictDataController { @@ -32,7 +33,8 @@ public class AppDictDataController {
32 @Operation(summary = "根据字典类型查询字典数据信息") 33 @Operation(summary = "根据字典类型查询字典数据信息")
33 @Parameter(name = "type", description = "字典类型", required = true, example = "common_status") 34 @Parameter(name = "type", description = "字典类型", required = true, example = "common_status")
34 public CommonResult<List<AppDictDataRespVO>> getDictDataListByType(@RequestParam("type") String type) { 35 public CommonResult<List<AppDictDataRespVO>> getDictDataListByType(@RequestParam("type") String type) {
35 - List<DictDataDO> list = dictDataService.getEnabledDictDataListByType(type); 36 + List<DictDataDO> list = dictDataService.getDictDataList(
  37 + CommonStatusEnum.ENABLE.getStatus(), type);
36 return success(BeanUtils.toBean(list, AppDictDataRespVO.class)); 38 return success(BeanUtils.toBean(list, AppDictDataRespVO.class));
37 } 39 }
38 40
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dict/DictDataMapper.java
@@ -40,10 +40,10 @@ public interface DictDataMapper extends BaseMapperX&lt;DictDataDO&gt; { @@ -40,10 +40,10 @@ public interface DictDataMapper extends BaseMapperX&lt;DictDataDO&gt; {
40 .orderByDesc(Arrays.asList(DictDataDO::getDictType, DictDataDO::getSort))); 40 .orderByDesc(Arrays.asList(DictDataDO::getDictType, DictDataDO::getSort)));
41 } 41 }
42 42
43 - default List<DictDataDO> selectListByTypeAndStatus(String dictType, Integer status) {  
44 - return selectList(new LambdaQueryWrapper<DictDataDO>()  
45 - .eq(DictDataDO::getDictType, dictType)  
46 - .eq(DictDataDO::getStatus, status)); 43 + default List<DictDataDO> selectListByStatusAndDictType(Integer status, String dictType) {
  44 + return selectList(new LambdaQueryWrapperX<DictDataDO>()
  45 + .eqIfPresent(DictDataDO::getStatus, status)
  46 + .eqIfPresent(DictDataDO::getDictType, dictType));
47 } 47 }
48 48
49 } 49 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/PostService.java
1 package cn.iocoder.yudao.module.system.service.dept; 1 package cn.iocoder.yudao.module.system.service.dept;
2 2
3 -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;  
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostPageReqVO; 4 import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostPageReqVO;
6 import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostSaveReqVO; 5 import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostSaveReqVO;
@@ -10,8 +9,6 @@ import org.springframework.lang.Nullable; @@ -10,8 +9,6 @@ import org.springframework.lang.Nullable;
10 import java.util.Collection; 9 import java.util.Collection;
11 import java.util.List; 10 import java.util.List;
12 11
13 -import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;  
14 -  
15 /** 12 /**
16 * 岗位 Service 接口 13 * 岗位 Service 接口
17 * 14 *
@@ -44,12 +41,10 @@ public interface PostService { @@ -44,12 +41,10 @@ public interface PostService {
44 /** 41 /**
45 * 获得岗位列表 42 * 获得岗位列表
46 * 43 *
47 - * @param ids 岗位编号数组。如果为空,不进行筛选 44 + * @param ids 岗位编号数组
48 * @return 部门列表 45 * @return 部门列表
49 */ 46 */
50 - default List<PostDO> getPostList(@Nullable Collection<Long> ids) {  
51 - return getPostList(ids, asSet(CommonStatusEnum.ENABLE.getStatus(), CommonStatusEnum.DISABLE.getStatus()));  
52 - } 47 + List<PostDO> getPostList(@Nullable Collection<Long> ids);
53 48
54 /** 49 /**
55 * 获得符合条件的岗位列表 50 * 获得符合条件的岗位列表
@@ -58,7 +53,8 @@ public interface PostService { @@ -58,7 +53,8 @@ public interface PostService {
58 * @param statuses 状态数组。如果为空,不进行筛选 53 * @param statuses 状态数组。如果为空,不进行筛选
59 * @return 部门列表 54 * @return 部门列表
60 */ 55 */
61 - List<PostDO> getPostList(@Nullable Collection<Long> ids, @Nullable Collection<Integer> statuses); 56 + List<PostDO> getPostList(@Nullable Collection<Long> ids,
  57 + @Nullable Collection<Integer> statuses);
62 58
63 /** 59 /**
64 * 获得岗位分页列表 60 * 获得岗位分页列表
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/PostServiceImpl.java
@@ -13,6 +13,7 @@ import org.springframework.validation.annotation.Validated; @@ -13,6 +13,7 @@ import org.springframework.validation.annotation.Validated;
13 13
14 import javax.annotation.Resource; 14 import javax.annotation.Resource;
15 import java.util.Collection; 15 import java.util.Collection;
  16 +import java.util.Collections;
16 import java.util.List; 17 import java.util.List;
17 import java.util.Map; 18 import java.util.Map;
18 19
@@ -108,6 +109,14 @@ public class PostServiceImpl implements PostService { @@ -108,6 +109,14 @@ public class PostServiceImpl implements PostService {
108 } 109 }
109 110
110 @Override 111 @Override
  112 + public List<PostDO> getPostList(Collection<Long> ids) {
  113 + if (CollUtil.isEmpty(ids)) {
  114 + return Collections.emptyList();
  115 + }
  116 + return postMapper.selectBatchIds(ids);
  117 + }
  118 +
  119 + @Override
111 public List<PostDO> getPostList(Collection<Long> ids, Collection<Integer> statuses) { 120 public List<PostDO> getPostList(Collection<Long> ids, Collection<Integer> statuses) {
112 return postMapper.selectList(ids, statuses); 121 return postMapper.selectList(ids, statuses);
113 } 122 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictDataService.java
@@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataPageReqVO; 4 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataPageReqVO;
5 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataSaveReqVO; 5 import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataSaveReqVO;
6 import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO; 6 import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
  7 +import org.springframework.lang.Nullable;
7 8
8 import java.util.Collection; 9 import java.util.Collection;
9 import java.util.List; 10 import java.util.List;
@@ -40,9 +41,11 @@ public interface DictDataService { @@ -40,9 +41,11 @@ public interface DictDataService {
40 /** 41 /**
41 * 获得字典数据列表 42 * 获得字典数据列表
42 * 43 *
  44 + * @param status 状态
  45 + * @param dictType 字典类型
43 * @return 字典数据全列表 46 * @return 字典数据全列表
44 */ 47 */
45 - List<DictDataDO> getDictDataList(); 48 + List<DictDataDO> getDictDataList(@Nullable Integer status, @Nullable String dictType);
46 49
47 /** 50 /**
48 * 获得字典数据分页列表 51 * 获得字典数据分页列表
@@ -53,14 +56,6 @@ public interface DictDataService { @@ -53,14 +56,6 @@ public interface DictDataService {
53 PageResult<DictDataDO> getDictDataPage(DictDataPageReqVO pageReqVO); 56 PageResult<DictDataDO> getDictDataPage(DictDataPageReqVO pageReqVO);
54 57
55 /** 58 /**
56 - * 获得字典数据列表  
57 - *  
58 - * @param dictType 字典类型  
59 - * @return 字典数据列表  
60 - */  
61 - List<DictDataDO> getEnabledDictDataListByType(String dictType);  
62 -  
63 - /**  
64 * 获得字典数据详情 59 * 获得字典数据详情
65 * 60 *
66 * @param id 字典数据编号 61 * @param id 字典数据编号
@@ -74,7 +69,7 @@ public interface DictDataService { @@ -74,7 +69,7 @@ public interface DictDataService {
74 * @param dictType 字典类型 69 * @param dictType 字典类型
75 * @return 数据数量 70 * @return 数据数量
76 */ 71 */
77 - long countByDictType(String dictType); 72 + long getDictDataCountByDictType(String dictType);
78 73
79 /** 74 /**
80 * 校验字典数据们是否有效。如下情况,视为无效: 75 * 校验字典数据们是否有效。如下情况,视为无效:
@@ -103,4 +98,5 @@ public interface DictDataService { @@ -103,4 +98,5 @@ public interface DictDataService {
103 * @return 字典数据 98 * @return 字典数据
104 */ 99 */
105 DictDataDO parseDictData(String dictType, String label); 100 DictDataDO parseDictData(String dictType, String label);
  101 +
106 } 102 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictDataServiceImpl.java
@@ -46,8 +46,8 @@ public class DictDataServiceImpl implements DictDataService { @@ -46,8 +46,8 @@ public class DictDataServiceImpl implements DictDataService {
46 private DictDataMapper dictDataMapper; 46 private DictDataMapper dictDataMapper;
47 47
48 @Override 48 @Override
49 - public List<DictDataDO> getDictDataList() {  
50 - List<DictDataDO> list = dictDataMapper.selectList(DictDataDO::getStatus, CommonStatusEnum.ENABLE.getStatus()); 49 + public List<DictDataDO> getDictDataList(Integer status, String dictType) {
  50 + List<DictDataDO> list = dictDataMapper.selectListByStatusAndDictType(status, dictType);
51 list.sort(COMPARATOR_TYPE_AND_SORT); 51 list.sort(COMPARATOR_TYPE_AND_SORT);
52 return list; 52 return list;
53 } 53 }
@@ -58,13 +58,6 @@ public class DictDataServiceImpl implements DictDataService { @@ -58,13 +58,6 @@ public class DictDataServiceImpl implements DictDataService {
58 } 58 }
59 59
60 @Override 60 @Override
61 - public List<DictDataDO> getEnabledDictDataListByType(String dictType) {  
62 - List<DictDataDO> list = dictDataMapper.selectListByTypeAndStatus(dictType, CommonStatusEnum.ENABLE.getStatus());  
63 - list.sort(COMPARATOR_TYPE_AND_SORT);  
64 - return list;  
65 - }  
66 -  
67 - @Override  
68 public DictDataDO getDictData(Long id) { 61 public DictDataDO getDictData(Long id) {
69 return dictDataMapper.selectById(id); 62 return dictDataMapper.selectById(id);
70 } 63 }
@@ -106,7 +99,7 @@ public class DictDataServiceImpl implements DictDataService { @@ -106,7 +99,7 @@ public class DictDataServiceImpl implements DictDataService {
106 } 99 }
107 100
108 @Override 101 @Override
109 - public long countByDictType(String dictType) { 102 + public long getDictDataCountByDictType(String dictType) {
110 return dictDataMapper.selectCountByDictType(dictType); 103 return dictDataMapper.selectCountByDictType(dictType);
111 } 104 }
112 105
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dict/DictTypeServiceImpl.java
@@ -80,7 +80,7 @@ public class DictTypeServiceImpl implements DictTypeService { @@ -80,7 +80,7 @@ public class DictTypeServiceImpl implements DictTypeService {
80 // 校验是否存在 80 // 校验是否存在
81 DictTypeDO dictType = validateDictTypeExists(id); 81 DictTypeDO dictType = validateDictTypeExists(id);
82 // 校验是否有字典数据 82 // 校验是否有字典数据
83 - if (dictDataService.countByDictType(dictType.getType()) > 0) { 83 + if (dictDataService.getDictDataCountByDictType(dictType.getType()) > 0) {
84 throw exception(DICT_TYPE_HAS_CHILDREN); 84 throw exception(DICT_TYPE_HAS_CHILDREN);
85 } 85 }
86 // 删除字典类型 86 // 删除字典类型
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/notify/NotifySendService.java
@@ -48,7 +48,7 @@ public interface NotifySendService { @@ -48,7 +48,7 @@ public interface NotifySendService {
48 String templateCode, Map<String, Object> templateParams); 48 String templateCode, Map<String, Object> templateParams);
49 49
50 default void sendBatchNotify(List<String> mobiles, List<Long> userIds, Integer userType, 50 default void sendBatchNotify(List<String> mobiles, List<Long> userIds, Integer userType,
51 - String templateCode, Map<String, Object> templateParams) { 51 + String templateCode, Map<String, Object> templateParams) {
52 throw new UnsupportedOperationException("暂时不支持该操作,感兴趣可以实现该功能哟!"); 52 throw new UnsupportedOperationException("暂时不支持该操作,感兴趣可以实现该功能哟!");
53 } 53 }
54 54
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceImpl.java
@@ -6,6 +6,7 @@ import cn.hutool.core.util.ObjectUtil; @@ -6,6 +6,7 @@ import cn.hutool.core.util.ObjectUtil;
6 import cn.hutool.extra.spring.SpringUtil; 6 import cn.hutool.extra.spring.SpringUtil;
7 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 7 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
8 import cn.iocoder.yudao.framework.common.pojo.PageResult; 8 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  9 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
9 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 10 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
10 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RolePageReqVO; 11 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RolePageReqVO;
11 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleSaveReqVO; 12 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleSaveReqVO;
@@ -27,7 +28,6 @@ import javax.annotation.Resource; @@ -27,7 +28,6 @@ import javax.annotation.Resource;
27 import java.util.*; 28 import java.util.*;
28 29
29 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 30 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
30 -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;  
31 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; 31 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
32 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; 32 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
33 33
@@ -198,7 +198,7 @@ public class RoleServiceImpl implements RoleService { @@ -198,7 +198,7 @@ public class RoleServiceImpl implements RoleService {
198 } 198 }
199 // 这里采用 for 循环从缓存中获取,主要考虑 Spring CacheManager 无法批量操作的问题 199 // 这里采用 for 循环从缓存中获取,主要考虑 Spring CacheManager 无法批量操作的问题
200 RoleServiceImpl self = getSelf(); 200 RoleServiceImpl self = getSelf();
201 - return convertList(ids, self::getRoleFromCache); 201 + return CollectionUtils.convertList(ids, self::getRoleFromCache);
202 } 202 }
203 203
204 @Override 204 @Override
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/bo/RoleCreateReqBO.java deleted
1 -package cn.iocoder.yudao.module.system.service.permission.bo;  
2 -  
3 -import lombok.Data;  
4 -  
5 -import javax.validation.constraints.NotBlank;  
6 -import javax.validation.constraints.NotNull;  
7 -import javax.validation.constraints.Size;  
8 -  
9 -/**  
10 - * 角色创建 Request BO  
11 - *  
12 - * @author 芋道源码  
13 - */  
14 -@Data  
15 -public class RoleCreateReqBO {  
16 -  
17 - /**  
18 - * 租户编号  
19 - */  
20 - @NotNull(message = "租户编号不能为空")  
21 - private Long tenantId;  
22 -  
23 - /**  
24 - * 角色名称  
25 - */  
26 - @NotBlank(message = "角色名称不能为空")  
27 - @Size(max = 30, message = "角色名称长度不能超过30个字符")  
28 - private String name;  
29 -  
30 - /**  
31 - * 角色标志  
32 - */  
33 - @NotBlank(message = "角色标志不能为空")  
34 - @Size(max = 100, message = "角色标志长度不能超过100个字符")  
35 - private String code;  
36 -  
37 - /**  
38 - * 显示顺序  
39 - */  
40 - @NotNull(message = "显示顺序不能为空")  
41 - private Integer sort;  
42 -  
43 - /**  
44 - * 角色类型  
45 - */  
46 - @NotNull(message = "角色类型不能为空")  
47 - private Integer type;  
48 -  
49 -}  
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java
@@ -142,7 +142,8 @@ public class SocialClientServiceImpl implements SocialClientService { @@ -142,7 +142,8 @@ public class SocialClientServiceImpl implements SocialClientService {
142 * @param userType 用户类型 142 * @param userType 用户类型
143 * @return AuthRequest 对象 143 * @return AuthRequest 对象
144 */ 144 */
145 - private AuthRequest buildAuthRequest(Integer socialType, Integer userType) { 145 + @VisibleForTesting
  146 + AuthRequest buildAuthRequest(Integer socialType, Integer userType) {
146 // 1. 先查找默认的配置项,从 application-*.yaml 中读取 147 // 1. 先查找默认的配置项,从 application-*.yaml 中读取
147 AuthRequest request = authRequestFactory.get(SocialTypeEnum.valueOfType(socialType).getSource()); 148 AuthRequest request = authRequestFactory.get(SocialTypeEnum.valueOfType(socialType).getSource());
148 Assert.notNull(request, String.format("社交平台(%d) 不存在", socialType)); 149 Assert.notNull(request, String.format("社交平台(%d) 不存在", socialType));
@@ -180,7 +181,8 @@ public class SocialClientServiceImpl implements SocialClientService { @@ -180,7 +181,8 @@ public class SocialClientServiceImpl implements SocialClientService {
180 * @param userType 用户类型 181 * @param userType 用户类型
181 * @return WxMpService 对象 182 * @return WxMpService 对象
182 */ 183 */
183 - private WxMpService getWxMpService(Integer userType) { 184 + @VisibleForTesting
  185 + WxMpService getWxMpService(Integer userType) {
184 // 第一步,查询 DB 的配置项,获得对应的 WxMpService 对象 186 // 第一步,查询 DB 的配置项,获得对应的 WxMpService 对象
185 SocialClientDO client = socialClientMapper.selectBySocialTypeAndUserType( 187 SocialClientDO client = socialClientMapper.selectBySocialTypeAndUserType(
186 SocialTypeEnum.WECHAT_MP.getType(), userType); 188 SocialTypeEnum.WECHAT_MP.getType(), userType);
@@ -198,7 +200,7 @@ public class SocialClientServiceImpl implements SocialClientService { @@ -198,7 +200,7 @@ public class SocialClientServiceImpl implements SocialClientService {
198 * @param clientSecret 微信公众号 secret 200 * @param clientSecret 微信公众号 secret
199 * @return WxMpService 对象 201 * @return WxMpService 对象
200 */ 202 */
201 - private WxMpService buildWxMpService(String clientId, String clientSecret) { 203 + public WxMpService buildWxMpService(String clientId, String clientSecret) {
202 // 第一步,创建 WxMpRedisConfigImpl 对象 204 // 第一步,创建 WxMpRedisConfigImpl 对象
203 WxMpRedisConfigImpl configStorage = new WxMpRedisConfigImpl( 205 WxMpRedisConfigImpl configStorage = new WxMpRedisConfigImpl(
204 new RedisTemplateWxRedisOps(stringRedisTemplate), 206 new RedisTemplateWxRedisOps(stringRedisTemplate),
@@ -231,7 +233,8 @@ public class SocialClientServiceImpl implements SocialClientService { @@ -231,7 +233,8 @@ public class SocialClientServiceImpl implements SocialClientService {
231 * @param userType 用户类型 233 * @param userType 用户类型
232 * @return WxMpService 对象 234 * @return WxMpService 对象
233 */ 235 */
234 - private WxMaService getWxMaService(Integer userType) { 236 + @VisibleForTesting
  237 + WxMaService getWxMaService(Integer userType) {
235 // 第一步,查询 DB 的配置项,获得对应的 WxMaService 对象 238 // 第一步,查询 DB 的配置项,获得对应的 WxMaService 对象
236 SocialClientDO client = socialClientMapper.selectBySocialTypeAndUserType( 239 SocialClientDO client = socialClientMapper.selectBySocialTypeAndUserType(
237 SocialTypeEnum.WECHAT_MINI_APP.getType(), userType); 240 SocialTypeEnum.WECHAT_MINI_APP.getType(), userType);
@@ -311,7 +314,6 @@ public class SocialClientServiceImpl implements SocialClientService { @@ -311,7 +314,6 @@ public class SocialClientServiceImpl implements SocialClientService {
311 * @param userType 用户类型 314 * @param userType 用户类型
312 * @param socialType 社交类型 315 * @param socialType 社交类型
313 */ 316 */
314 - @VisibleForTesting  
315 private void validateSocialClientUnique(Long id, Integer userType, Integer socialType) { 317 private void validateSocialClientUnique(Long id, Integer userType, Integer socialType) {
316 SocialClientDO client = socialClientMapper.selectBySocialTypeAndUserType( 318 SocialClientDO client = socialClientMapper.selectBySocialTypeAndUserType(
317 socialType, userType); 319 socialType, userType);
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialUserServiceImpl.java
1 package cn.iocoder.yudao.module.system.service.social; 1 package cn.iocoder.yudao.module.system.service.social;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 -import cn.hutool.core.collection.ListUtil;  
5 import cn.hutool.core.lang.Assert; 4 import cn.hutool.core.lang.Assert;
6 import cn.iocoder.yudao.framework.common.exception.ServiceException; 5 import cn.iocoder.yudao.framework.common.exception.ServiceException;
7 import cn.iocoder.yudao.framework.common.pojo.PageResult; 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
8 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; 7 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
9 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; 8 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
10 import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO; 9 import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO;
11 -import cn.iocoder.yudao.module.system.convert.social.SocialUserConvert;  
12 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserBindDO; 10 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserBindDO;
13 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO; 11 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO;
14 import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserBindMapper; 12 import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserBindMapper;
@@ -22,14 +20,14 @@ import org.springframework.validation.annotation.Validated; @@ -22,14 +20,14 @@ import org.springframework.validation.annotation.Validated;
22 20
23 import javax.annotation.Resource; 21 import javax.annotation.Resource;
24 import javax.validation.constraints.NotNull; 22 import javax.validation.constraints.NotNull;
25 -import java.util.Collection;  
26 import java.util.Collections; 23 import java.util.Collections;
27 import java.util.List; 24 import java.util.List;
28 25
29 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 26 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
30 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; 27 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
31 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; 28 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
32 -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; 29 +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.AUTH_THIRD_LOGIN_NOT_BIND;
  30 +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_USER_NOT_FOUND;
33 31
34 /** 32 /**
35 * 社交用户 Service 实现类 33 * 社交用户 Service 实现类
@@ -61,7 +59,7 @@ public class SocialUserServiceImpl implements SocialUserService { @@ -61,7 +59,7 @@ public class SocialUserServiceImpl implements SocialUserService {
61 } 59 }
62 60
63 @Override 61 @Override
64 - @Transactional 62 + @Transactional(rollbackFor = Exception.class)
65 public String bindSocialUser(SocialUserBindReqDTO reqDTO) { 63 public String bindSocialUser(SocialUserBindReqDTO reqDTO) {
66 // 获得社交用户 64 // 获得社交用户
67 SocialUserDO socialUser = authSocialUser(reqDTO.getSocialType(), reqDTO.getUserType(), 65 SocialUserDO socialUser = authSocialUser(reqDTO.getSocialType(), reqDTO.getUserType(),
@@ -110,7 +108,6 @@ public class SocialUserServiceImpl implements SocialUserService { @@ -110,7 +108,6 @@ public class SocialUserServiceImpl implements SocialUserService {
110 return new SocialUserRespDTO(socialUser.getOpenid(), socialUserBind.getUserId()); 108 return new SocialUserRespDTO(socialUser.getOpenid(), socialUserBind.getUserId());
111 } 109 }
112 110
113 - // TODO 芋艿:调整下单测  
114 /** 111 /**
115 * 授权获得对应的社交用户 112 * 授权获得对应的社交用户
116 * 如果授权失败,则会抛出 {@link ServiceException} 异常 113 * 如果授权失败,则会抛出 {@link ServiceException} 异常
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/dept/PostServiceImplTest.java
@@ -156,6 +156,24 @@ public class PostServiceImplTest extends BaseDbUnitTest { @@ -156,6 +156,24 @@ public class PostServiceImplTest extends BaseDbUnitTest {
156 @Test 156 @Test
157 public void testGetPostList() { 157 public void testGetPostList() {
158 // mock 数据 158 // mock 数据
  159 + PostDO postDO01 = randomPojo(PostDO.class);
  160 + postMapper.insert(postDO01);
  161 + // 测试 id 不匹配
  162 + PostDO postDO02 = randomPojo(PostDO.class);
  163 + postMapper.insert(postDO02);
  164 + // 准备参数
  165 + List<Long> ids = singletonList(postDO01.getId());
  166 +
  167 + // 调用
  168 + List<PostDO> list = postService.getPostList(ids);
  169 + // 断言
  170 + assertEquals(1, list.size());
  171 + assertPojoEquals(postDO01, list.get(0));
  172 + }
  173 +
  174 + @Test
  175 + public void testGetPostList_idsAndStatus() {
  176 + // mock 数据
159 PostDO postDO01 = randomPojo(PostDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())); 177 PostDO postDO01 = randomPojo(PostDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()));
160 postMapper.insert(postDO01); 178 postMapper.insert(postDO01);
161 // 测试 status 不匹配 179 // 测试 status 不匹配
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/dict/DictDataServiceImplTest.java
@@ -50,10 +50,15 @@ public class DictDataServiceImplTest extends BaseDbUnitTest { @@ -50,10 +50,15 @@ public class DictDataServiceImplTest extends BaseDbUnitTest {
50 DictDataDO dictDataDO03 = randomDictDataDO().setDictType("yunai").setSort(3) 50 DictDataDO dictDataDO03 = randomDictDataDO().setDictType("yunai").setSort(3)
51 .setStatus(CommonStatusEnum.DISABLE.getStatus()); 51 .setStatus(CommonStatusEnum.DISABLE.getStatus());
52 dictDataMapper.insert(dictDataDO03); 52 dictDataMapper.insert(dictDataDO03);
  53 + DictDataDO dictDataDO04 = randomDictDataDO().setDictType("yunai2").setSort(3)
  54 + .setStatus(CommonStatusEnum.DISABLE.getStatus());
  55 + dictDataMapper.insert(dictDataDO04);
53 // 准备参数 56 // 准备参数
  57 + Integer status = CommonStatusEnum.ENABLE.getStatus();
  58 + String dictType = "yunai";
54 59
55 // 调用 60 // 调用
56 - List<DictDataDO> dictDataDOList = dictDataService.getDictDataList(); 61 + List<DictDataDO> dictDataDOList = dictDataService.getDictDataList(status, dictType);
57 // 断言 62 // 断言
58 assertEquals(2, dictDataDOList.size()); 63 assertEquals(2, dictDataDOList.size());
59 assertPojoEquals(dictDataDO02, dictDataDOList.get(0)); 64 assertPojoEquals(dictDataDO02, dictDataDOList.get(0));
@@ -236,7 +241,7 @@ public class DictDataServiceImplTest extends BaseDbUnitTest { @@ -236,7 +241,7 @@ public class DictDataServiceImplTest extends BaseDbUnitTest {
236 } 241 }
237 242
238 @Test 243 @Test
239 - public void testCountByDictType() { 244 + public void testGetDictDataCountByDictType() {
240 // mock 数据 245 // mock 数据
241 dictDataMapper.insert(randomDictDataDO(o -> o.setDictType("yunai"))); 246 dictDataMapper.insert(randomDictDataDO(o -> o.setDictType("yunai")));
242 dictDataMapper.insert(randomDictDataDO(o -> o.setDictType("tudou"))); 247 dictDataMapper.insert(randomDictDataDO(o -> o.setDictType("tudou")));
@@ -245,7 +250,7 @@ public class DictDataServiceImplTest extends BaseDbUnitTest { @@ -245,7 +250,7 @@ public class DictDataServiceImplTest extends BaseDbUnitTest {
245 String dictType = "yunai"; 250 String dictType = "yunai";
246 251
247 // 调用 252 // 调用
248 - long count = dictDataService.countByDictType(dictType); 253 + long count = dictDataService.getDictDataCountByDictType(dictType);
249 // 校验 254 // 校验
250 assertEquals(2L, count); 255 assertEquals(2L, count);
251 } 256 }
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/dict/DictTypeServiceImplTest.java
@@ -158,7 +158,7 @@ public class DictTypeServiceImplTest extends BaseDbUnitTest { @@ -158,7 +158,7 @@ public class DictTypeServiceImplTest extends BaseDbUnitTest {
158 // 准备参数 158 // 准备参数
159 Long id = dbDictType.getId(); 159 Long id = dbDictType.getId();
160 // mock 方法 160 // mock 方法
161 - when(dictDataService.countByDictType(eq(dbDictType.getType()))).thenReturn(1L); 161 + when(dictDataService.getDictDataCountByDictType(eq(dbDictType.getType()))).thenReturn(1L);
162 162
163 // 调用, 并断言异常 163 // 调用, 并断言异常
164 assertServiceException(() -> dictTypeService.deleteDictType(id), DICT_TYPE_HAS_CHILDREN); 164 assertServiceException(() -> dictTypeService.deleteDictType(id), DICT_TYPE_HAS_CHILDREN);
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/notify/NotifySendServiceImplTest.java
@@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; @@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
6 import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; 6 import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
7 import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO; 7 import cn.iocoder.yudao.module.system.dal.dataobject.notify.NotifyTemplateDO;
8 import org.assertj.core.util.Lists; 8 import org.assertj.core.util.Lists;
  9 +import org.junit.jupiter.api.Assertions;
9 import org.junit.jupiter.api.Test; 10 import org.junit.jupiter.api.Test;
10 import org.mockito.InjectMocks; 11 import org.mockito.InjectMocks;
11 import org.mockito.Mock; 12 import org.mockito.Mock;
@@ -172,5 +173,18 @@ class NotifySendServiceImplTest extends BaseMockitoUnitTest { @@ -172,5 +173,18 @@ class NotifySendServiceImplTest extends BaseMockitoUnitTest {
172 NOTIFY_SEND_TEMPLATE_PARAM_MISS, "code"); 173 NOTIFY_SEND_TEMPLATE_PARAM_MISS, "code");
173 } 174 }
174 175
  176 + @Test
  177 + public void testSendBatchNotify() {
  178 + // 准备参数
  179 + // mock 方法
  180 +
  181 + // 调用
  182 + UnsupportedOperationException exception = Assertions.assertThrows(
  183 + UnsupportedOperationException.class,
  184 + () -> notifySendService.sendBatchNotify(null, null, null, null, null)
  185 + );
  186 + // 断言
  187 + assertEquals("暂时不支持该操作,感兴趣可以实现该功能哟!", exception.getMessage());
  188 + }
175 189
176 } 190 }
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/MenuServiceImplTest.java
@@ -13,6 +13,8 @@ import org.springframework.boot.test.mock.mockito.MockBean; @@ -13,6 +13,8 @@ import org.springframework.boot.test.mock.mockito.MockBean;
13 import org.springframework.context.annotation.Import; 13 import org.springframework.context.annotation.Import;
14 14
15 import javax.annotation.Resource; 15 import javax.annotation.Resource;
  16 +import java.util.Collection;
  17 +import java.util.Collections;
16 import java.util.List; 18 import java.util.List;
17 import java.util.Set; 19 import java.util.Set;
18 20
@@ -186,6 +188,40 @@ public class MenuServiceImplTest extends BaseDbUnitTest { @@ -186,6 +188,40 @@ public class MenuServiceImplTest extends BaseDbUnitTest {
186 } 188 }
187 189
188 @Test 190 @Test
  191 + public void testGetMenuIdListByPermissionFromCache() {
  192 + // mock 数据
  193 + MenuDO menu100 = randomPojo(MenuDO.class);
  194 + menuMapper.insert(menu100);
  195 + MenuDO menu101 = randomPojo(MenuDO.class);
  196 + menuMapper.insert(menu101);
  197 + // 准备参数
  198 + String permission = menu100.getPermission();
  199 +
  200 + // 调用
  201 + List<Long> ids = menuService.getMenuIdListByPermissionFromCache(permission);
  202 + // 断言
  203 + assertEquals(1, ids.size());
  204 + assertEquals(menu100.getId(), ids.get(0));
  205 + }
  206 +
  207 + @Test
  208 + public void testGetMenuList_ids() {
  209 + // mock 数据
  210 + MenuDO menu100 = randomPojo(MenuDO.class);
  211 + menuMapper.insert(menu100);
  212 + MenuDO menu101 = randomPojo(MenuDO.class);
  213 + menuMapper.insert(menu101);
  214 + // 准备参数
  215 + Collection<Long> ids = Collections.singleton(menu100.getId());
  216 +
  217 + // 调用
  218 + List<MenuDO> list = menuService.getMenuList(ids);
  219 + // 断言
  220 + assertEquals(1, list.size());
  221 + assertPojoEquals(menu100, list.get(0));
  222 + }
  223 +
  224 + @Test
189 public void testGetMenu() { 225 public void testGetMenu() {
190 // mock 数据 226 // mock 数据
191 MenuDO menu = randomPojo(MenuDO.class); 227 MenuDO menu = randomPojo(MenuDO.class);
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceImplTest.java
@@ -234,6 +234,39 @@ public class RoleServiceImplTest extends BaseDbUnitTest { @@ -234,6 +234,39 @@ public class RoleServiceImplTest extends BaseDbUnitTest {
234 } 234 }
235 235
236 @Test 236 @Test
  237 + public void testGetRoleList() {
  238 + // mock 数据
  239 + RoleDO dbRole01 = randomPojo(RoleDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()));
  240 + roleMapper.insert(dbRole01);
  241 + RoleDO dbRole02 = randomPojo(RoleDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()));
  242 + roleMapper.insert(dbRole02);
  243 +
  244 + // 调用
  245 + List<RoleDO> list = roleService.getRoleList();
  246 + // 断言
  247 + assertEquals(2, list.size());
  248 + assertPojoEquals(dbRole01, list.get(0));
  249 + assertPojoEquals(dbRole02, list.get(1));
  250 + }
  251 +
  252 + @Test
  253 + public void testGetRoleList_ids() {
  254 + // mock 数据
  255 + RoleDO dbRole01 = randomPojo(RoleDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()));
  256 + roleMapper.insert(dbRole01);
  257 + RoleDO dbRole02 = randomPojo(RoleDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()));
  258 + roleMapper.insert(dbRole02);
  259 + // 准备参数
  260 + Collection<Long> ids = singleton(dbRole01.getId());
  261 +
  262 + // 调用
  263 + List<RoleDO> list = roleService.getRoleList(ids);
  264 + // 断言
  265 + assertEquals(1, list.size());
  266 + assertPojoEquals(dbRole01, list.get(0));
  267 + }
  268 +
  269 + @Test
237 public void testGetRoleListFromCache() { 270 public void testGetRoleListFromCache() {
238 try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) { 271 try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
239 springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(RoleServiceImpl.class))) 272 springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(RoleServiceImpl.class)))
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sensitiveword/SensitiveWordServiceImplTest.java
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.service.sensitiveword; @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.service.sensitiveword;
3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.framework.common.util.collection.SetUtils; 5 import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
  6 +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
6 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; 7 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
7 import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordPageReqVO; 8 import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordPageReqVO;
8 import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordSaveVO; 9 import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordSaveVO;
@@ -13,6 +14,8 @@ import org.junit.jupiter.api.Test; @@ -13,6 +14,8 @@ import org.junit.jupiter.api.Test;
13 import org.springframework.context.annotation.Import; 14 import org.springframework.context.annotation.Import;
14 15
15 import javax.annotation.Resource; 16 import javax.annotation.Resource;
  17 +import java.time.Duration;
  18 +import java.time.LocalDateTime;
16 import java.util.Arrays; 19 import java.util.Arrays;
17 import java.util.List; 20 import java.util.List;
18 21
@@ -79,6 +82,35 @@ public class SensitiveWordServiceImplTest extends BaseDbUnitTest { @@ -79,6 +82,35 @@ public class SensitiveWordServiceImplTest extends BaseDbUnitTest {
79 } 82 }
80 83
81 @Test 84 @Test
  85 + public void testRefreshLocalCache() {
  86 + // mock 数据
  87 + SensitiveWordDO wordDO1 = randomPojo(SensitiveWordDO.class, o -> o.setName("傻瓜")
  88 + .setTags(singletonList("论坛")).setStatus(CommonStatusEnum.ENABLE.getStatus()));
  89 + wordDO1.setUpdateTime(LocalDateTime.now());
  90 + sensitiveWordMapper.insert(wordDO1);
  91 + sensitiveWordService.initLocalCache();
  92 + // mock 数据 ②
  93 + SensitiveWordDO wordDO2 = randomPojo(SensitiveWordDO.class, o -> o.setName("笨蛋")
  94 + .setTags(singletonList("蔬菜")).setStatus(CommonStatusEnum.ENABLE.getStatus()));
  95 + wordDO2.setUpdateTime(LocalDateTimeUtils.addTime(Duration.ofMinutes(1))); // 避免时间相同
  96 + sensitiveWordMapper.insert(wordDO2);
  97 +
  98 + // 调用
  99 + sensitiveWordService.refreshLocalCache();
  100 + // 断言 sensitiveWordTagsCache 缓存
  101 + assertEquals(SetUtils.asSet("论坛", "蔬菜"), sensitiveWordService.getSensitiveWordTagSet());
  102 + // 断言 sensitiveWordCache
  103 + assertEquals(2, sensitiveWordService.getSensitiveWordCache().size());
  104 + assertPojoEquals(wordDO1, sensitiveWordService.getSensitiveWordCache().get(0));
  105 + assertPojoEquals(wordDO2, sensitiveWordService.getSensitiveWordCache().get(1));
  106 + // 断言 tagSensitiveWordTries 缓存
  107 + assertNotNull(sensitiveWordService.getDefaultSensitiveWordTrie());
  108 + assertEquals(2, sensitiveWordService.getTagSensitiveWordTries().size());
  109 + assertNotNull(sensitiveWordService.getTagSensitiveWordTries().get("论坛"));
  110 + assertNotNull(sensitiveWordService.getTagSensitiveWordTries().get("蔬菜"));
  111 + }
  112 +
  113 + @Test
82 public void testCreateSensitiveWord_success() { 114 public void testCreateSensitiveWord_success() {
83 // 准备参数 115 // 准备参数
84 SensitiveWordSaveVO reqVO = randomPojo(SensitiveWordSaveVO.class) 116 SensitiveWordSaveVO reqVO = randomPojo(SensitiveWordSaveVO.class)
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsSendServiceImplTest.java
@@ -16,6 +16,7 @@ import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer; @@ -16,6 +16,7 @@ import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer;
16 import cn.iocoder.yudao.module.system.service.member.MemberService; 16 import cn.iocoder.yudao.module.system.service.member.MemberService;
17 import cn.iocoder.yudao.module.system.service.user.AdminUserService; 17 import cn.iocoder.yudao.module.system.service.user.AdminUserService;
18 import org.assertj.core.util.Lists; 18 import org.assertj.core.util.Lists;
  19 +import org.junit.jupiter.api.Assertions;
19 import org.junit.jupiter.api.Test; 20 import org.junit.jupiter.api.Test;
20 import org.mockito.InjectMocks; 21 import org.mockito.InjectMocks;
21 import org.mockito.Mock; 22 import org.mockito.Mock;
@@ -35,7 +36,7 @@ import static org.mockito.Mockito.*; @@ -35,7 +36,7 @@ import static org.mockito.Mockito.*;
35 public class SmsSendServiceImplTest extends BaseMockitoUnitTest { 36 public class SmsSendServiceImplTest extends BaseMockitoUnitTest {
36 37
37 @InjectMocks 38 @InjectMocks
38 - private SmsSendServiceImpl smsService; 39 + private SmsSendServiceImpl smsSendService;
39 40
40 @Mock 41 @Mock
41 private AdminUserService adminUserService; 42 private AdminUserService adminUserService;
@@ -80,7 +81,7 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest { @@ -80,7 +81,7 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest {
80 eq(content), eq(templateParams))).thenReturn(smsLogId); 81 eq(content), eq(templateParams))).thenReturn(smsLogId);
81 82
82 // 调用 83 // 调用
83 - Long resultSmsLogId = smsService.sendSingleSmsToAdmin(null, userId, templateCode, templateParams); 84 + Long resultSmsLogId = smsSendService.sendSingleSmsToAdmin(null, userId, templateCode, templateParams);
84 // 断言 85 // 断言
85 assertEquals(smsLogId, resultSmsLogId); 86 assertEquals(smsLogId, resultSmsLogId);
86 // 断言调用 87 // 断言调用
@@ -119,7 +120,7 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest { @@ -119,7 +120,7 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest {
119 eq(content), eq(templateParams))).thenReturn(smsLogId); 120 eq(content), eq(templateParams))).thenReturn(smsLogId);
120 121
121 // 调用 122 // 调用
122 - Long resultSmsLogId = smsService.sendSingleSmsToMember(null, userId, templateCode, templateParams); 123 + Long resultSmsLogId = smsSendService.sendSingleSmsToMember(null, userId, templateCode, templateParams);
123 // 断言 124 // 断言
124 assertEquals(smsLogId, resultSmsLogId); 125 assertEquals(smsLogId, resultSmsLogId);
125 // 断言调用 126 // 断言调用
@@ -159,7 +160,7 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest { @@ -159,7 +160,7 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest {
159 eq(content), eq(templateParams))).thenReturn(smsLogId); 160 eq(content), eq(templateParams))).thenReturn(smsLogId);
160 161
161 // 调用 162 // 调用
162 - Long resultSmsLogId = smsService.sendSingleSms(mobile, userId, userType, templateCode, templateParams); 163 + Long resultSmsLogId = smsSendService.sendSingleSms(mobile, userId, userType, templateCode, templateParams);
163 // 断言 164 // 断言
164 assertEquals(smsLogId, resultSmsLogId); 165 assertEquals(smsLogId, resultSmsLogId);
165 // 断言调用 166 // 断言调用
@@ -199,7 +200,7 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest { @@ -199,7 +200,7 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest {
199 eq(content), eq(templateParams))).thenReturn(smsLogId); 200 eq(content), eq(templateParams))).thenReturn(smsLogId);
200 201
201 // 调用 202 // 调用
202 - Long resultSmsLogId = smsService.sendSingleSms(mobile, userId, userType, templateCode, templateParams); 203 + Long resultSmsLogId = smsSendService.sendSingleSms(mobile, userId, userType, templateCode, templateParams);
203 // 断言 204 // 断言
204 assertEquals(smsLogId, resultSmsLogId); 205 assertEquals(smsLogId, resultSmsLogId);
205 // 断言调用 206 // 断言调用
@@ -214,7 +215,7 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest { @@ -214,7 +215,7 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest {
214 // mock 方法 215 // mock 方法
215 216
216 // 调用,并断言异常 217 // 调用,并断言异常
217 - assertServiceException(() -> smsService.validateSmsTemplate(templateCode), 218 + assertServiceException(() -> smsSendService.validateSmsTemplate(templateCode),
218 SMS_SEND_TEMPLATE_NOT_EXISTS); 219 SMS_SEND_TEMPLATE_NOT_EXISTS);
219 } 220 }
220 221
@@ -227,7 +228,7 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest { @@ -227,7 +228,7 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest {
227 // mock 方法 228 // mock 方法
228 229
229 // 调用,并断言异常 230 // 调用,并断言异常
230 - assertServiceException(() -> smsService.buildTemplateParams(template, templateParams), 231 + assertServiceException(() -> smsSendService.buildTemplateParams(template, templateParams),
231 SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS, "code"); 232 SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS, "code");
232 } 233 }
233 234
@@ -237,11 +238,25 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest { @@ -237,11 +238,25 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest {
237 // mock 方法 238 // mock 方法
238 239
239 // 调用,并断言异常 240 // 调用,并断言异常
240 - assertServiceException(() -> smsService.validateMobile(null), 241 + assertServiceException(() -> smsSendService.validateMobile(null),
241 SMS_SEND_MOBILE_NOT_EXISTS); 242 SMS_SEND_MOBILE_NOT_EXISTS);
242 } 243 }
243 244
244 @Test 245 @Test
  246 + public void testSendBatchNotify() {
  247 + // 准备参数
  248 + // mock 方法
  249 +
  250 + // 调用
  251 + UnsupportedOperationException exception = Assertions.assertThrows(
  252 + UnsupportedOperationException.class,
  253 + () -> smsSendService.sendBatchSms(null, null, null, null, null)
  254 + );
  255 + // 断言
  256 + assertEquals("暂时不支持该操作,感兴趣可以实现该功能哟!", exception.getMessage());
  257 + }
  258 +
  259 + @Test
245 @SuppressWarnings("unchecked") 260 @SuppressWarnings("unchecked")
246 public void testDoSendSms() throws Throwable { 261 public void testDoSendSms() throws Throwable {
247 // 准备参数 262 // 准备参数
@@ -255,7 +270,7 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest { @@ -255,7 +270,7 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest {
255 eq(message.getTemplateParams()))).thenReturn(sendResult); 270 eq(message.getTemplateParams()))).thenReturn(sendResult);
256 271
257 // 调用 272 // 调用
258 - smsService.doSendSms(message); 273 + smsSendService.doSendSms(message);
259 // 断言 274 // 断言
260 verify(smsLogService).updateSmsSendResult(eq(message.getLogId()), 275 verify(smsLogService).updateSmsSendResult(eq(message.getLogId()),
261 eq(sendResult.getSuccess()), eq(sendResult.getApiCode()), 276 eq(sendResult.getSuccess()), eq(sendResult.getApiCode()),
@@ -274,7 +289,7 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest { @@ -274,7 +289,7 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest {
274 List<SmsReceiveRespDTO> receiveResults = randomPojoList(SmsReceiveRespDTO.class); 289 List<SmsReceiveRespDTO> receiveResults = randomPojoList(SmsReceiveRespDTO.class);
275 290
276 // 调用 291 // 调用
277 - smsService.receiveSmsStatus(channelCode, text); 292 + smsSendService.receiveSmsStatus(channelCode, text);
278 // 断言 293 // 断言
279 receiveResults.forEach(result -> smsLogService.updateSmsReceiveResult(eq(result.getLogId()), eq(result.getSuccess()), 294 receiveResults.forEach(result -> smsLogService.updateSmsReceiveResult(eq(result.getLogId()), eq(result.getSuccess()),
280 eq(result.getReceiveTime()), eq(result.getErrorCode()), eq(result.getErrorCode()))); 295 eq(result.getReceiveTime()), eq(result.getErrorCode()), eq(result.getErrorCode())));
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImplTest.java
1 package cn.iocoder.yudao.module.system.service.sms; 1 package cn.iocoder.yudao.module.system.service.sms;
2 2
  3 +import cn.hutool.core.map.MapUtil;
3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; 6 import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
@@ -8,8 +9,8 @@ import cn.iocoder.yudao.framework.sms.core.client.SmsClient; @@ -8,8 +9,8 @@ import cn.iocoder.yudao.framework.sms.core.client.SmsClient;
8 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO; 9 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
9 import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum; 10 import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
10 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; 11 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
11 -import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateSaveReqVO;  
12 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplatePageReqVO; 12 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplatePageReqVO;
  13 +import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateSaveReqVO;
13 import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO; 14 import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO;
14 import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO; 15 import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO;
15 import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsTemplateMapper; 16 import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsTemplateMapper;
@@ -21,6 +22,7 @@ import org.springframework.context.annotation.Import; @@ -21,6 +22,7 @@ import org.springframework.context.annotation.Import;
21 22
22 import javax.annotation.Resource; 23 import javax.annotation.Resource;
23 import java.util.List; 24 import java.util.List;
  25 +import java.util.Map;
24 import java.util.function.Consumer; 26 import java.util.function.Consumer;
25 27
26 import static cn.hutool.core.util.RandomUtil.randomEle; 28 import static cn.hutool.core.util.RandomUtil.randomEle;
@@ -49,6 +51,19 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest { @@ -49,6 +51,19 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest {
49 private SmsClient smsClient; 51 private SmsClient smsClient;
50 52
51 @Test 53 @Test
  54 + public void testFormatSmsTemplateContent() {
  55 + // 准备参数
  56 + String content = "正在进行登录操作{operation},您的验证码是{code}";
  57 + Map<String, Object> params = MapUtil.<String, Object>builder("operation", "登录")
  58 + .put("code", "1234").build();
  59 +
  60 + // 调用
  61 + String result = smsTemplateService.formatSmsTemplateContent(content, params);
  62 + // 断言
  63 + assertEquals("正在进行登录操作登录,您的验证码是1234", result);
  64 + }
  65 +
  66 + @Test
52 public void testParseTemplateContentParams() { 67 public void testParseTemplateContentParams() {
53 // 准备参数 68 // 准备参数
54 String content = "正在进行登录操作{operation},您的验证码是{code}"; 69 String content = "正在进行登录操作{operation},您的验证码是{code}";
@@ -157,6 +172,34 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest { @@ -157,6 +172,34 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest {
157 } 172 }
158 173
159 @Test 174 @Test
  175 + public void testGetSmsTemplate() {
  176 + // mock 数据
  177 + SmsTemplateDO dbSmsTemplate = randomSmsTemplateDO();
  178 + smsTemplateMapper.insert(dbSmsTemplate);// @Sql: 先插入出一条存在的数据
  179 + // 准备参数
  180 + Long id = dbSmsTemplate.getId();
  181 +
  182 + // 调用
  183 + SmsTemplateDO smsTemplate = smsTemplateService.getSmsTemplate(id);
  184 + // 校验
  185 + assertPojoEquals(dbSmsTemplate, smsTemplate);
  186 + }
  187 +
  188 + @Test
  189 + public void testGetSmsTemplateByCodeFromCache() {
  190 + // mock 数据
  191 + SmsTemplateDO dbSmsTemplate = randomSmsTemplateDO();
  192 + smsTemplateMapper.insert(dbSmsTemplate);// @Sql: 先插入出一条存在的数据
  193 + // 准备参数
  194 + String code = dbSmsTemplate.getCode();
  195 +
  196 + // 调用
  197 + SmsTemplateDO smsTemplate = smsTemplateService.getSmsTemplateByCodeFromCache(code);
  198 + // 校验
  199 + assertPojoEquals(dbSmsTemplate, smsTemplate);
  200 + }
  201 +
  202 + @Test
160 public void testGetSmsTemplatePage() { 203 public void testGetSmsTemplatePage() {
161 // mock 数据 204 // mock 数据
162 SmsTemplateDO dbSmsTemplate = randomPojo(SmsTemplateDO.class, o -> { // 等会查询到 205 SmsTemplateDO dbSmsTemplate = randomPojo(SmsTemplateDO.class, o -> { // 等会查询到
@@ -202,6 +245,22 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest { @@ -202,6 +245,22 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest {
202 } 245 }
203 246
204 @Test 247 @Test
  248 + public void testGetSmsTemplateCountByChannelId() {
  249 + // mock 数据
  250 + SmsTemplateDO dbSmsTemplate = randomPojo(SmsTemplateDO.class, o -> o.setChannelId(1L));
  251 + smsTemplateMapper.insert(dbSmsTemplate);
  252 + // 测试 channelId 不匹配
  253 + smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setChannelId(2L)));
  254 + // 准备参数
  255 + Long channelId = 1L;
  256 +
  257 + // 调用
  258 + Long count = smsTemplateService.getSmsTemplateCountByChannelId(channelId);
  259 + // 断言
  260 + assertEquals(1, count);
  261 + }
  262 +
  263 + @Test
205 public void testValidateSmsChannel_success() { 264 public void testValidateSmsChannel_success() {
206 // 准备参数 265 // 准备参数
207 Long channelId = randomLongId(); 266 Long channelId = randomLongId();
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImplTest.java
1 package cn.iocoder.yudao.module.system.service.social; 1 package cn.iocoder.yudao.module.system.service.social;
2 2
  3 +import cn.binarywang.wx.miniapp.api.WxMaService;
  4 +import cn.binarywang.wx.miniapp.api.WxMaUserService;
  5 +import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
  6 +import cn.hutool.core.util.ReflectUtil;
  7 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  8 +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 9 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; 10 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
5 import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO; 11 import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO;
6 import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientSaveReqVO; 12 import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientSaveReqVO;
7 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO; 13 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO;
8 import cn.iocoder.yudao.module.system.dal.mysql.social.SocialClientMapper; 14 import cn.iocoder.yudao.module.system.dal.mysql.social.SocialClientMapper;
9 -import org.junit.jupiter.api.Disabled; 15 +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
  16 +import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaProperties;
  17 +import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties;
  18 +import com.xingyuv.jushauth.config.AuthConfig;
  19 +import com.xingyuv.jushauth.model.AuthResponse;
  20 +import com.xingyuv.jushauth.model.AuthUser;
  21 +import com.xingyuv.jushauth.request.AuthDefaultRequest;
  22 +import com.xingyuv.jushauth.request.AuthRequest;
  23 +import com.xingyuv.jushauth.utils.AuthStateUtils;
  24 +import com.xingyuv.justauth.AuthRequestFactory;
  25 +import me.chanjar.weixin.common.bean.WxJsapiSignature;
  26 +import me.chanjar.weixin.common.error.WxErrorException;
  27 +import me.chanjar.weixin.mp.api.WxMpService;
10 import org.junit.jupiter.api.Test; 28 import org.junit.jupiter.api.Test;
  29 +import org.mockito.MockedStatic;
  30 +import org.springframework.boot.test.mock.mockito.MockBean;
11 import org.springframework.context.annotation.Import; 31 import org.springframework.context.annotation.Import;
  32 +import org.springframework.data.redis.core.StringRedisTemplate;
12 33
13 import javax.annotation.Resource; 34 import javax.annotation.Resource;
14 35
  36 +import static cn.hutool.core.util.RandomUtil.randomEle;
15 import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; 37 import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
16 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; 38 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
17 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; 39 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
18 -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;  
19 -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;  
20 -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_CLIENT_NOT_EXISTS; 40 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
  41 +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
21 import static org.junit.jupiter.api.Assertions.*; 42 import static org.junit.jupiter.api.Assertions.*;
  43 +import static org.mockito.Mockito.*;
22 44
23 -// TODO 芋艿:单测后续补充下;  
24 /** 45 /**
25 * {@link SocialClientServiceImpl} 的单元测试类 46 * {@link SocialClientServiceImpl} 的单元测试类
26 * 47 *
27 * @author 芋道源码 48 * @author 芋道源码
28 */ 49 */
29 @Import(SocialClientServiceImpl.class) 50 @Import(SocialClientServiceImpl.class)
30 -@Disabled  
31 public class SocialClientServiceImplTest extends BaseDbUnitTest { 51 public class SocialClientServiceImplTest extends BaseDbUnitTest {
32 52
33 @Resource 53 @Resource
@@ -36,10 +56,305 @@ public class SocialClientServiceImplTest extends BaseDbUnitTest { @@ -36,10 +56,305 @@ public class SocialClientServiceImplTest extends BaseDbUnitTest {
36 @Resource 56 @Resource
37 private SocialClientMapper socialClientMapper; 57 private SocialClientMapper socialClientMapper;
38 58
  59 + @MockBean
  60 + private AuthRequestFactory authRequestFactory;
  61 +
  62 + @MockBean
  63 + private WxMpService wxMpService;
  64 + @MockBean
  65 + private WxMpProperties wxMpProperties;
  66 + @MockBean
  67 + private StringRedisTemplate stringRedisTemplate;
  68 + @MockBean
  69 + private WxMaService wxMaService;
  70 + @MockBean
  71 + private WxMaProperties wxMaProperties;
  72 +
  73 + @Test
  74 + public void testGetAuthorizeUrl() {
  75 + try (MockedStatic<AuthStateUtils> authStateUtilsMock = mockStatic(AuthStateUtils.class)) {
  76 + // 准备参数
  77 + Integer socialType = SocialTypeEnum.WECHAT_MP.getType();
  78 + Integer userType = randomPojo(UserTypeEnum.class).getValue();
  79 + String redirectUri = "sss";
  80 + // mock 获得对应的 AuthRequest 实现
  81 + AuthRequest authRequest = mock(AuthRequest.class);
  82 + when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest);
  83 + // mock 方法
  84 + authStateUtilsMock.when(AuthStateUtils::createState).thenReturn("aoteman");
  85 + when(authRequest.authorize(eq("aoteman"))).thenReturn("https://www.iocoder.cn?redirect_uri=yyy");
  86 +
  87 + // 调用
  88 + String url = socialClientService.getAuthorizeUrl(socialType, userType, redirectUri);
  89 + // 断言
  90 + assertEquals("https://www.iocoder.cn?redirect_uri=sss", url);
  91 + }
  92 + }
  93 +
  94 + @Test
  95 + public void testAuthSocialUser_success() {
  96 + // 准备参数
  97 + Integer socialType = SocialTypeEnum.WECHAT_MP.getType();
  98 + Integer userType = randomPojo(UserTypeEnum.class).getValue();
  99 + String code = randomString();
  100 + String state = randomString();
  101 + // mock 方法(AuthRequest)
  102 + AuthRequest authRequest = mock(AuthRequest.class);
  103 + when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest);
  104 + // mock 方法(AuthResponse)
  105 + AuthUser authUser = randomPojo(AuthUser.class);
  106 + AuthResponse<?> authResponse = new AuthResponse<>(2000, null, authUser);
  107 + when(authRequest.login(argThat(authCallback -> {
  108 + assertEquals(code, authCallback.getCode());
  109 + assertEquals(state, authCallback.getState());
  110 + return true;
  111 + }))).thenReturn(authResponse);
  112 +
  113 + // 调用
  114 + AuthUser result = socialClientService.getAuthUser(socialType, userType, code, state);
  115 + // 断言
  116 + assertSame(authUser, result);
  117 + }
  118 +
  119 + @Test
  120 + public void testAuthSocialUser_fail() {
  121 + // 准备参数
  122 + Integer socialType = SocialTypeEnum.WECHAT_MP.getType();
  123 + Integer userType = randomPojo(UserTypeEnum.class).getValue();
  124 + String code = randomString();
  125 + String state = randomString();
  126 + // mock 方法(AuthRequest)
  127 + AuthRequest authRequest = mock(AuthRequest.class);
  128 + when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest);
  129 + // mock 方法(AuthResponse)
  130 + AuthResponse<?> authResponse = new AuthResponse<>(0, "模拟失败", null);
  131 + when(authRequest.login(argThat(authCallback -> {
  132 + assertEquals(code, authCallback.getCode());
  133 + assertEquals(state, authCallback.getState());
  134 + return true;
  135 + }))).thenReturn(authResponse);
  136 +
  137 + // 调用并断言
  138 + assertServiceException(
  139 + () -> socialClientService.getAuthUser(socialType, userType, code, state),
  140 + SOCIAL_USER_AUTH_FAILURE, "模拟失败");
  141 + }
  142 +
  143 + @Test
  144 + public void testBuildAuthRequest_clientNull() {
  145 + // 准备参数
  146 + Integer socialType = SocialTypeEnum.WECHAT_MP.getType();
  147 + Integer userType = randomPojo(SocialTypeEnum.class).getType();
  148 + // mock 获得对应的 AuthRequest 实现
  149 + AuthRequest authRequest = mock(AuthDefaultRequest.class);
  150 + AuthConfig authConfig = (AuthConfig) ReflectUtil.getFieldValue(authRequest, "config");
  151 + when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest);
  152 +
  153 + // 调用
  154 + AuthRequest result = socialClientService.buildAuthRequest(socialType, userType);
  155 + // 断言
  156 + assertSame(authRequest, result);
  157 + assertSame(authConfig, ReflectUtil.getFieldValue(authConfig, "config"));
  158 + }
  159 +
  160 + @Test
  161 + public void testBuildAuthRequest_clientDisable() {
  162 + // 准备参数
  163 + Integer socialType = SocialTypeEnum.WECHAT_MP.getType();
  164 + Integer userType = randomPojo(SocialTypeEnum.class).getType();
  165 + // mock 获得对应的 AuthRequest 实现
  166 + AuthRequest authRequest = mock(AuthDefaultRequest.class);
  167 + AuthConfig authConfig = (AuthConfig) ReflectUtil.getFieldValue(authRequest, "config");
  168 + when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest);
  169 + // mock 数据
  170 + SocialClientDO client = randomPojo(SocialClientDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())
  171 + .setUserType(userType).setSocialType(socialType));
  172 + socialClientMapper.insert(client);
  173 +
  174 + // 调用
  175 + AuthRequest result = socialClientService.buildAuthRequest(socialType, userType);
  176 + // 断言
  177 + assertSame(authRequest, result);
  178 + assertSame(authConfig, ReflectUtil.getFieldValue(authConfig, "config"));
  179 + }
  180 +
  181 + @Test
  182 + public void testBuildAuthRequest_clientEnable() {
  183 + // 准备参数
  184 + Integer socialType = SocialTypeEnum.WECHAT_MP.getType();
  185 + Integer userType = randomPojo(SocialTypeEnum.class).getType();
  186 + // mock 获得对应的 AuthRequest 实现
  187 + AuthConfig authConfig = mock(AuthConfig.class);
  188 + AuthRequest authRequest = mock(AuthDefaultRequest.class);
  189 + ReflectUtil.setFieldValue(authRequest, "config", authConfig);
  190 + when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest);
  191 + // mock 数据
  192 + SocialClientDO client = randomPojo(SocialClientDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())
  193 + .setUserType(userType).setSocialType(socialType));
  194 + socialClientMapper.insert(client);
  195 +
  196 + // 调用
  197 + AuthRequest result = socialClientService.buildAuthRequest(socialType, userType);
  198 + // 断言
  199 + assertSame(authRequest, result);
  200 + assertNotSame(authConfig, ReflectUtil.getFieldValue(authRequest, "config"));
  201 + }
  202 +
  203 + // =================== 微信公众号独有 ===================
  204 +
  205 + @Test
  206 + public void testCreateWxMpJsapiSignature() throws WxErrorException {
  207 + // 准备参数
  208 + Integer userType = randomPojo(UserTypeEnum.class).getValue();
  209 + String url = randomString();
  210 + // mock 方法
  211 + WxJsapiSignature signature = randomPojo(WxJsapiSignature.class);
  212 + when(wxMpService.createJsapiSignature(eq(url))).thenReturn(signature);
  213 +
  214 + // 调用
  215 + WxJsapiSignature result = socialClientService.createWxMpJsapiSignature(userType, url);
  216 + // 断言
  217 + assertSame(signature, result);
  218 + }
  219 +
  220 + @Test
  221 + public void testGetWxMpService_clientNull() {
  222 + // 准备参数
  223 + Integer userType = randomPojo(UserTypeEnum.class).getValue();
  224 + // mock 方法
  225 +
  226 + // 调用
  227 + WxMpService result = socialClientService.getWxMpService(userType);
  228 + // 断言
  229 + assertSame(wxMpService, result);
  230 + }
  231 +
  232 + @Test
  233 + public void testGetWxMpService_clientDisable() {
  234 + // 准备参数
  235 + Integer userType = randomPojo(UserTypeEnum.class).getValue();
  236 + // mock 数据
  237 + SocialClientDO client = randomPojo(SocialClientDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())
  238 + .setUserType(userType).setSocialType(SocialTypeEnum.WECHAT_MP.getType()));
  239 + socialClientMapper.insert(client);
  240 +
  241 + // 调用
  242 + WxMpService result = socialClientService.getWxMpService(userType);
  243 + // 断言
  244 + assertSame(wxMpService, result);
  245 + }
  246 +
  247 + @Test
  248 + public void testGetWxMpService_clientEnable() {
  249 + // 准备参数
  250 + Integer userType = randomPojo(UserTypeEnum.class).getValue();
  251 + // mock 数据
  252 + SocialClientDO client = randomPojo(SocialClientDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())
  253 + .setUserType(userType).setSocialType(SocialTypeEnum.WECHAT_MP.getType()));
  254 + socialClientMapper.insert(client);
  255 + // mock 方法
  256 + WxMpProperties.ConfigStorage configStorage = mock(WxMpProperties.ConfigStorage.class);
  257 + when(wxMpProperties.getConfigStorage()).thenReturn(configStorage);
  258 +
  259 + // 调用
  260 + WxMpService result = socialClientService.getWxMpService(userType);
  261 + // 断言
  262 + assertNotSame(wxMpService, result);
  263 + assertEquals(client.getClientId(), result.getWxMpConfigStorage().getAppId());
  264 + assertEquals(client.getClientSecret(), result.getWxMpConfigStorage().getSecret());
  265 + }
  266 +
  267 + // =================== 微信小程序独有 ===================
  268 +
  269 + @Test
  270 + public void testGetWxMaPhoneNumberInfo_success() throws WxErrorException {
  271 + // 准备参数
  272 + Integer userType = randomPojo(UserTypeEnum.class).getValue();
  273 + String phoneCode = randomString();
  274 + // mock 方法
  275 + WxMaUserService userService = mock(WxMaUserService.class);
  276 + when(wxMaService.getUserService()).thenReturn(userService);
  277 + WxMaPhoneNumberInfo phoneNumber = randomPojo(WxMaPhoneNumberInfo.class);
  278 + when(userService.getPhoneNoInfo(eq(phoneCode))).thenReturn(phoneNumber);
  279 +
  280 + // 调用
  281 + WxMaPhoneNumberInfo result = socialClientService.getWxMaPhoneNumberInfo(userType, phoneCode);
  282 + // 断言
  283 + assertSame(phoneNumber, result);
  284 + }
  285 +
  286 + @Test
  287 + public void testGetWxMaPhoneNumberInfo_exception() throws WxErrorException {
  288 + // 准备参数
  289 + Integer userType = randomPojo(UserTypeEnum.class).getValue();
  290 + String phoneCode = randomString();
  291 + // mock 方法
  292 + WxMaUserService userService = mock(WxMaUserService.class);
  293 + when(wxMaService.getUserService()).thenReturn(userService);
  294 + WxErrorException wxErrorException = randomPojo(WxErrorException.class);
  295 + when(userService.getPhoneNoInfo(eq(phoneCode))).thenThrow(wxErrorException);
  296 +
  297 + // 调用并断言异常
  298 + assertServiceException(() -> socialClientService.getWxMaPhoneNumberInfo(userType, phoneCode),
  299 + SOCIAL_CLIENT_WEIXIN_MINI_APP_PHONE_CODE_ERROR);
  300 + }
  301 +
  302 + @Test
  303 + public void testGetWxMaService_clientNull() {
  304 + // 准备参数
  305 + Integer userType = randomPojo(UserTypeEnum.class).getValue();
  306 + // mock 方法
  307 +
  308 + // 调用
  309 + WxMaService result = socialClientService.getWxMaService(userType);
  310 + // 断言
  311 + assertSame(wxMaService, result);
  312 + }
  313 +
  314 + @Test
  315 + public void testGetWxMaService_clientDisable() {
  316 + // 准备参数
  317 + Integer userType = randomPojo(UserTypeEnum.class).getValue();
  318 + // mock 数据
  319 + SocialClientDO client = randomPojo(SocialClientDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())
  320 + .setUserType(userType).setSocialType(SocialTypeEnum.WECHAT_MINI_APP.getType()));
  321 + socialClientMapper.insert(client);
  322 +
  323 + // 调用
  324 + WxMaService result = socialClientService.getWxMaService(userType);
  325 + // 断言
  326 + assertSame(wxMaService, result);
  327 + }
  328 +
  329 + @Test
  330 + public void testGetWxMaService_clientEnable() {
  331 + // 准备参数
  332 + Integer userType = randomPojo(UserTypeEnum.class).getValue();
  333 + // mock 数据
  334 + SocialClientDO client = randomPojo(SocialClientDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())
  335 + .setUserType(userType).setSocialType(SocialTypeEnum.WECHAT_MINI_APP.getType()));
  336 + socialClientMapper.insert(client);
  337 + // mock 方法
  338 + WxMaProperties.ConfigStorage configStorage = mock(WxMaProperties.ConfigStorage.class);
  339 + when(wxMaProperties.getConfigStorage()).thenReturn(configStorage);
  340 +
  341 + // 调用
  342 + WxMaService result = socialClientService.getWxMaService(userType);
  343 + // 断言
  344 + assertNotSame(wxMaService, result);
  345 + assertEquals(client.getClientId(), result.getWxMaConfig().getAppid());
  346 + assertEquals(client.getClientSecret(), result.getWxMaConfig().getSecret());
  347 + }
  348 +
  349 + // =================== 客户端管理 ===================
  350 +
39 @Test 351 @Test
40 public void testCreateSocialClient_success() { 352 public void testCreateSocialClient_success() {
41 // 准备参数 353 // 准备参数
42 - SocialClientSaveReqVO reqVO = randomPojo(SocialClientSaveReqVO.class) 354 + SocialClientSaveReqVO reqVO = randomPojo(SocialClientSaveReqVO.class,
  355 + o -> o.setSocialType(randomEle(SocialTypeEnum.values()).getType())
  356 + .setUserType(randomEle(UserTypeEnum.values()).getValue())
  357 + .setStatus(randomCommonStatus()))
43 .setId(null); // 防止 id 被赋值 358 .setId(null); // 防止 id 被赋值
44 359
45 // 调用 360 // 调用
@@ -59,6 +374,9 @@ public class SocialClientServiceImplTest extends BaseDbUnitTest { @@ -59,6 +374,9 @@ public class SocialClientServiceImplTest extends BaseDbUnitTest {
59 // 准备参数 374 // 准备参数
60 SocialClientSaveReqVO reqVO = randomPojo(SocialClientSaveReqVO.class, o -> { 375 SocialClientSaveReqVO reqVO = randomPojo(SocialClientSaveReqVO.class, o -> {
61 o.setId(dbSocialClient.getId()); // 设置更新的 ID 376 o.setId(dbSocialClient.getId()); // 设置更新的 ID
  377 + o.setSocialType(randomEle(SocialTypeEnum.values()).getType())
  378 + .setUserType(randomEle(UserTypeEnum.values()).getValue())
  379 + .setStatus(randomCommonStatus());
62 }); 380 });
63 381
64 // 调用 382 // 调用
@@ -101,40 +419,47 @@ public class SocialClientServiceImplTest extends BaseDbUnitTest { @@ -101,40 +419,47 @@ public class SocialClientServiceImplTest extends BaseDbUnitTest {
101 } 419 }
102 420
103 @Test 421 @Test
104 - @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 422 + public void testGetSocialClient() {
  423 + // mock 数据
  424 + SocialClientDO dbSocialClient = randomPojo(SocialClientDO.class);
  425 + socialClientMapper.insert(dbSocialClient);// @Sql: 先插入出一条存在的数据
  426 + // 准备参数
  427 + Long id = dbSocialClient.getId();
  428 +
  429 + // 调用
  430 + SocialClientDO socialClient = socialClientService.getSocialClient(id);
  431 + // 校验数据正确
  432 + assertPojoEquals(dbSocialClient, socialClient);
  433 + }
  434 +
  435 + @Test
105 public void testGetSocialClientPage() { 436 public void testGetSocialClientPage() {
106 // mock 数据 437 // mock 数据
107 SocialClientDO dbSocialClient = randomPojo(SocialClientDO.class, o -> { // 等会查询到 438 SocialClientDO dbSocialClient = randomPojo(SocialClientDO.class, o -> { // 等会查询到
108 - o.setName(null);  
109 - o.setSocialType(null);  
110 - o.setUserType(null);  
111 - o.setClientId(null);  
112 - o.setClientSecret(null);  
113 - o.setStatus(null);  
114 - o.setCreateTime(null); 439 + o.setName("芋头");
  440 + o.setSocialType(SocialTypeEnum.GITEE.getType());
  441 + o.setUserType(UserTypeEnum.ADMIN.getValue());
  442 + o.setClientId("yudao");
  443 + o.setStatus(CommonStatusEnum.ENABLE.getStatus());
115 }); 444 });
116 socialClientMapper.insert(dbSocialClient); 445 socialClientMapper.insert(dbSocialClient);
117 // 测试 name 不匹配 446 // 测试 name 不匹配
118 - socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setName(null))); 447 + socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setName(randomString())));
119 // 测试 socialType 不匹配 448 // 测试 socialType 不匹配
120 - socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setSocialType(null))); 449 + socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setSocialType(SocialTypeEnum.DINGTALK.getType())));
121 // 测试 userType 不匹配 450 // 测试 userType 不匹配
122 - socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setUserType(null))); 451 + socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setUserType(UserTypeEnum.MEMBER.getValue())));
123 // 测试 clientId 不匹配 452 // 测试 clientId 不匹配
124 - socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setClientId(null)));  
125 - // 测试 clientSecret 不匹配  
126 - socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setClientSecret(null))); 453 + socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setClientId("dao")));
127 // 测试 status 不匹配 454 // 测试 status 不匹配
128 - socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setStatus(null)));  
129 - // 测试 createTime 不匹配  
130 - socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setCreateTime(null))); 455 + socialClientMapper.insert(cloneIgnoreId(dbSocialClient, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
131 // 准备参数 456 // 准备参数
132 SocialClientPageReqVO reqVO = new SocialClientPageReqVO(); 457 SocialClientPageReqVO reqVO = new SocialClientPageReqVO();
133 - reqVO.setName(null);  
134 - reqVO.setSocialType(null);  
135 - reqVO.setUserType(null);  
136 - reqVO.setClientId(null);  
137 - reqVO.setStatus(null); 458 + reqVO.setName("芋");
  459 + reqVO.setSocialType(SocialTypeEnum.GITEE.getType());
  460 + reqVO.setUserType(UserTypeEnum.ADMIN.getValue());
  461 + reqVO.setClientId("yu");
  462 + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
138 463
139 // 调用 464 // 调用
140 PageResult<SocialClientDO> pageResult = socialClientService.getSocialClientPage(reqVO); 465 PageResult<SocialClientDO> pageResult = socialClientService.getSocialClientPage(reqVO);
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/social/SocialUserServiceImplTest.java
1 package cn.iocoder.yudao.module.system.service.social; 1 package cn.iocoder.yudao.module.system.service.social;
2 2
3 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; 3 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; 5 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
5 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; 6 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
6 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; 7 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
  8 +import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO;
7 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserBindDO; 9 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserBindDO;
8 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO; 10 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO;
9 import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserBindMapper; 11 import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserBindMapper;
10 import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserMapper; 12 import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserMapper;
11 import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; 13 import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
12 -import com.xingyuv.jushauth.enums.AuthResponseStatus;  
13 -import com.xingyuv.jushauth.model.AuthCallback;  
14 -import com.xingyuv.jushauth.model.AuthResponse;  
15 import com.xingyuv.jushauth.model.AuthUser; 14 import com.xingyuv.jushauth.model.AuthUser;
16 -import com.xingyuv.jushauth.request.AuthRequest;  
17 -import com.xingyuv.justauth.AuthRequestFactory;  
18 -import org.junit.jupiter.api.Disabled;  
19 import org.junit.jupiter.api.Test; 15 import org.junit.jupiter.api.Test;
20 import org.springframework.boot.test.mock.mockito.MockBean; 16 import org.springframework.boot.test.mock.mockito.MockBean;
21 import org.springframework.context.annotation.Import; 17 import org.springframework.context.annotation.Import;
@@ -23,18 +19,27 @@ import org.springframework.context.annotation.Import; @@ -23,18 +19,27 @@ import org.springframework.context.annotation.Import;
23 import javax.annotation.Resource; 19 import javax.annotation.Resource;
24 import java.util.List; 20 import java.util.List;
25 21
26 -import static cn.hutool.core.util.RandomUtil.*; 22 +import static cn.hutool.core.util.RandomUtil.randomEle;
  23 +import static cn.hutool.core.util.RandomUtil.randomLong;
  24 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
  25 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
27 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; 26 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
  27 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
28 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; 28 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
29 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; 29 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
30 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; 30 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
31 -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_USER_AUTH_FAILURE; 31 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
32 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_USER_NOT_FOUND; 32 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_USER_NOT_FOUND;
33 import static org.junit.jupiter.api.Assertions.assertEquals; 33 import static org.junit.jupiter.api.Assertions.assertEquals;
34 -import static org.mockito.Mockito.*; 34 +import static org.mockito.Mockito.eq;
  35 +import static org.mockito.Mockito.when;
35 36
  37 +/**
  38 + * {@link SocialUserServiceImpl} 的单元测试类
  39 + *
  40 + * @author 芋道源码
  41 + */
36 @Import(SocialUserServiceImpl.class) 42 @Import(SocialUserServiceImpl.class)
37 -@Disabled // TODO 芋艿:后续统一修复  
38 public class SocialUserServiceImplTest extends BaseDbUnitTest { 43 public class SocialUserServiceImplTest extends BaseDbUnitTest {
39 44
40 @Resource 45 @Resource
@@ -46,119 +51,7 @@ public class SocialUserServiceImplTest extends BaseDbUnitTest { @@ -46,119 +51,7 @@ public class SocialUserServiceImplTest extends BaseDbUnitTest {
46 private SocialUserBindMapper socialUserBindMapper; 51 private SocialUserBindMapper socialUserBindMapper;
47 52
48 @MockBean 53 @MockBean
49 - private AuthRequestFactory authRequestFactory;  
50 -  
51 - // TODO 芋艿:后续统一修复  
52 -// @Test  
53 -// public void testGetAuthorizeUrl() {  
54 -// try (MockedStatic<AuthStateUtils> authStateUtilsMock = mockStatic(AuthStateUtils.class)) {  
55 -// // 准备参数  
56 -// Integer type = SocialTypeEnum.WECHAT_MP.getType();  
57 -// String redirectUri = "sss";  
58 -// // mock 获得对应的 AuthRequest 实现  
59 -// AuthRequest authRequest = mock(AuthRequest.class);  
60 -// when(authRequestFactory.get(eq("WECHAT_MP"))).thenReturn(authRequest);  
61 -// // mock 方法  
62 -// authStateUtilsMock.when(AuthStateUtils::createState).thenReturn("aoteman");  
63 -// when(authRequest.authorize(eq("aoteman"))).thenReturn("https://www.iocoder.cn?redirect_uri=yyy");  
64 -//  
65 -// // 调用  
66 -// String url = socialUserService.getAuthorizeUrl(type, redirectUri);  
67 -// // 断言  
68 -// assertEquals("https://www.iocoder.cn?redirect_uri=sss", url);  
69 -// }  
70 -// }  
71 -  
72 - @Test  
73 - public void testAuthSocialUser_exists() {  
74 - // 准备参数  
75 - Integer socialType = SocialTypeEnum.GITEE.getType();  
76 - Integer userType = randomEle(SocialTypeEnum.values()).getType();  
77 - String code = "tudou";  
78 - String state = "yuanma";  
79 - // mock 方法  
80 - SocialUserDO socialUser = randomPojo(SocialUserDO.class).setType(socialType).setCode(code).setState(state);  
81 - socialUserMapper.insert(socialUser);  
82 -  
83 - // 调用  
84 - SocialUserDO result = socialUserService.authSocialUser(socialType, userType, code, state);  
85 - // 断言  
86 - assertPojoEquals(socialUser, result);  
87 - }  
88 -  
89 - @Test  
90 - public void testAuthSocialUser_authFailure() {  
91 - // 准备参数  
92 - Integer socialType = SocialTypeEnum.GITEE.getType();  
93 - Integer userType = randomEle(SocialTypeEnum.values()).getType();  
94 - // mock 方法  
95 - AuthRequest authRequest = mock(AuthRequest.class);  
96 - when(authRequestFactory.get(anyString())).thenReturn(authRequest);  
97 - AuthResponse<?> authResponse = new AuthResponse<>(0, "模拟失败", null);  
98 - when(authRequest.login(any(AuthCallback.class))).thenReturn(authResponse);  
99 -  
100 - // 调用并断言  
101 - assertServiceException(  
102 - () -> socialUserService.authSocialUser(socialType, userType, randomString(10), randomString(10)),  
103 - SOCIAL_USER_AUTH_FAILURE, "模拟失败");  
104 - }  
105 -  
106 - @Test  
107 - public void testAuthSocialUser_insert() {  
108 - // 准备参数  
109 - Integer socialType = SocialTypeEnum.GITEE.getType();  
110 - Integer userType = randomEle(SocialTypeEnum.values()).getType();  
111 - String code = "tudou";  
112 - String state = "yuanma";  
113 - // mock 方法  
114 - AuthRequest authRequest = mock(AuthRequest.class);  
115 - when(authRequestFactory.get(eq(SocialTypeEnum.GITEE.getSource()))).thenReturn(authRequest);  
116 - AuthUser authUser = randomPojo(AuthUser.class);  
117 - AuthResponse<AuthUser> authResponse = new AuthResponse<>(AuthResponseStatus.SUCCESS.getCode(), null, authUser);  
118 - when(authRequest.login(any(AuthCallback.class))).thenReturn(authResponse);  
119 -  
120 - // 调用  
121 - SocialUserDO result = socialUserService.authSocialUser(socialType, userType, code, state);  
122 - // 断言  
123 - assertBindSocialUser(socialType, result, authResponse.getData());  
124 - assertEquals(code, result.getCode());  
125 - assertEquals(state, result.getState());  
126 - }  
127 -  
128 - @Test  
129 - public void testAuthSocialUser_update() {  
130 - // 准备参数  
131 - Integer socialType = SocialTypeEnum.GITEE.getType();  
132 - Integer userType = randomEle(SocialTypeEnum.values()).getType();  
133 - String code = "tudou";  
134 - String state = "yuanma";  
135 - // mock 数据  
136 - socialUserMapper.insert(randomPojo(SocialUserDO.class).setType(socialType).setOpenid("test_openid"));  
137 - // mock 方法  
138 - AuthRequest authRequest = mock(AuthRequest.class);  
139 - when(authRequestFactory.get(eq(SocialTypeEnum.GITEE.getSource()))).thenReturn(authRequest);  
140 - AuthUser authUser = randomPojo(AuthUser.class);  
141 - authUser.getToken().setOpenId("test_openid");  
142 - AuthResponse<AuthUser> authResponse = new AuthResponse<>(AuthResponseStatus.SUCCESS.getCode(), null, authUser);  
143 - when(authRequest.login(any(AuthCallback.class))).thenReturn(authResponse);  
144 -  
145 - // 调用  
146 - SocialUserDO result = socialUserService.authSocialUser(socialType, userType, code, state);  
147 - // 断言  
148 - assertBindSocialUser(socialType, result, authResponse.getData());  
149 - assertEquals(code, result.getCode());  
150 - assertEquals(state, result.getState());  
151 - }  
152 -  
153 - private void assertBindSocialUser(Integer type, SocialUserDO socialUser, AuthUser authUser) {  
154 - assertEquals(authUser.getToken().getAccessToken(), socialUser.getToken());  
155 - assertEquals(toJsonString(authUser.getToken()), socialUser.getRawTokenInfo());  
156 - assertEquals(authUser.getNickname(), socialUser.getNickname());  
157 - assertEquals(authUser.getAvatar(), socialUser.getAvatar());  
158 - assertEquals(toJsonString(authUser.getRawUserInfo()), socialUser.getRawUserInfo());  
159 - assertEquals(type, socialUser.getType());  
160 - assertEquals(authUser.getUuid(), socialUser.getOpenid());  
161 - } 54 + private SocialClientService socialClientService;
162 55
163 @Test 56 @Test
164 public void testGetSocialUserList() { 57 public void testGetSocialUserList() {
@@ -260,4 +153,136 @@ public class SocialUserServiceImplTest extends BaseDbUnitTest { @@ -260,4 +153,136 @@ public class SocialUserServiceImplTest extends BaseDbUnitTest {
260 assertEquals(socialUserDO.getOpenid(), socialUser.getOpenid()); 153 assertEquals(socialUserDO.getOpenid(), socialUser.getOpenid());
261 } 154 }
262 155
  156 + @Test
  157 + public void testAuthSocialUser_exists() {
  158 + // 准备参数
  159 + Integer socialType = SocialTypeEnum.GITEE.getType();
  160 + Integer userType = randomEle(SocialTypeEnum.values()).getType();
  161 + String code = "tudou";
  162 + String state = "yuanma";
  163 + // mock 方法
  164 + SocialUserDO socialUser = randomPojo(SocialUserDO.class).setType(socialType).setCode(code).setState(state);
  165 + socialUserMapper.insert(socialUser);
  166 +
  167 + // 调用
  168 + SocialUserDO result = socialUserService.authSocialUser(socialType, userType, code, state);
  169 + // 断言
  170 + assertPojoEquals(socialUser, result);
  171 + }
  172 +
  173 + @Test
  174 + public void testAuthSocialUser_notNull() {
  175 + // mock 数据
  176 + SocialUserDO socialUser = randomPojo(SocialUserDO.class,
  177 + o -> o.setType(SocialTypeEnum.GITEE.getType()).setCode("tudou").setState("yuanma"));
  178 + socialUserMapper.insert(socialUser);
  179 + // 准备参数
  180 + Integer socialType = SocialTypeEnum.GITEE.getType();
  181 + Integer userType = randomEle(SocialTypeEnum.values()).getType();
  182 + String code = "tudou";
  183 + String state = "yuanma";
  184 +
  185 + // 调用
  186 + SocialUserDO result = socialUserService.authSocialUser(socialType, userType, code, state);
  187 + // 断言
  188 + assertPojoEquals(socialUser, result);
  189 + }
  190 +
  191 + @Test
  192 + public void testAuthSocialUser_insert() {
  193 + // 准备参数
  194 + Integer socialType = SocialTypeEnum.GITEE.getType();
  195 + Integer userType = randomEle(SocialTypeEnum.values()).getType();
  196 + String code = "tudou";
  197 + String state = "yuanma";
  198 + // mock 方法
  199 + AuthUser authUser = randomPojo(AuthUser.class);
  200 + when(socialClientService.getAuthUser(eq(socialType), eq(userType), eq(code), eq(state))).thenReturn(authUser);
  201 +
  202 + // 调用
  203 + SocialUserDO result = socialUserService.authSocialUser(socialType, userType, code, state);
  204 + // 断言
  205 + assertBindSocialUser(socialType, result, authUser);
  206 + assertEquals(code, result.getCode());
  207 + assertEquals(state, result.getState());
  208 + }
  209 +
  210 + @Test
  211 + public void testAuthSocialUser_update() {
  212 + // 准备参数
  213 + Integer socialType = SocialTypeEnum.GITEE.getType();
  214 + Integer userType = randomEle(SocialTypeEnum.values()).getType();
  215 + String code = "tudou";
  216 + String state = "yuanma";
  217 + // mock 数据
  218 + socialUserMapper.insert(randomPojo(SocialUserDO.class).setType(socialType).setOpenid("test_openid"));
  219 + // mock 方法
  220 + AuthUser authUser = randomPojo(AuthUser.class);
  221 + when(socialClientService.getAuthUser(eq(socialType), eq(userType), eq(code), eq(state))).thenReturn(authUser);
  222 +
  223 + // 调用
  224 + SocialUserDO result = socialUserService.authSocialUser(socialType, userType, code, state);
  225 + // 断言
  226 + assertBindSocialUser(socialType, result, authUser);
  227 + assertEquals(code, result.getCode());
  228 + assertEquals(state, result.getState());
  229 + }
  230 +
  231 + private void assertBindSocialUser(Integer type, SocialUserDO socialUser, AuthUser authUser) {
  232 + assertEquals(authUser.getToken().getAccessToken(), socialUser.getToken());
  233 + assertEquals(toJsonString(authUser.getToken()), socialUser.getRawTokenInfo());
  234 + assertEquals(authUser.getNickname(), socialUser.getNickname());
  235 + assertEquals(authUser.getAvatar(), socialUser.getAvatar());
  236 + assertEquals(toJsonString(authUser.getRawUserInfo()), socialUser.getRawUserInfo());
  237 + assertEquals(type, socialUser.getType());
  238 + assertEquals(authUser.getUuid(), socialUser.getOpenid());
  239 + }
  240 +
  241 + @Test
  242 + public void testGetSocialUser_id() {
  243 + // mock 数据
  244 + SocialUserDO socialUserDO = randomPojo(SocialUserDO.class);
  245 + socialUserMapper.insert(socialUserDO);
  246 + // 参数准备
  247 + Long id = socialUserDO.getId();
  248 +
  249 + // 调用
  250 + SocialUserDO dbSocialUserDO = socialUserService.getSocialUser(id);
  251 + // 断言
  252 + assertPojoEquals(socialUserDO, dbSocialUserDO);
  253 + }
  254 +
  255 + @Test
  256 + public void testGetSocialUserPage() {
  257 + // mock 数据
  258 + SocialUserDO dbSocialUser = randomPojo(SocialUserDO.class, o -> { // 等会查询到
  259 + o.setType(SocialTypeEnum.GITEE.getType());
  260 + o.setNickname("芋艿");
  261 + o.setOpenid("yudaoyuanma");
  262 + o.setCreateTime(buildTime(2020, 1, 15));
  263 + });
  264 + socialUserMapper.insert(dbSocialUser);
  265 + // 测试 type 不匹配
  266 + socialUserMapper.insert(cloneIgnoreId(dbSocialUser, o -> o.setType(SocialTypeEnum.DINGTALK.getType())));
  267 + // 测试 nickname 不匹配
  268 + socialUserMapper.insert(cloneIgnoreId(dbSocialUser, o -> o.setNickname(randomString())));
  269 + // 测试 openid 不匹配
  270 + socialUserMapper.insert(cloneIgnoreId(dbSocialUser, o -> o.setOpenid("java")));
  271 + // 测试 createTime 不匹配
  272 + socialUserMapper.insert(cloneIgnoreId(dbSocialUser, o -> o.setCreateTime(buildTime(2020, 1, 21))));
  273 + // 准备参数
  274 + SocialUserPageReqVO reqVO = new SocialUserPageReqVO();
  275 + reqVO.setType(SocialTypeEnum.GITEE.getType());
  276 + reqVO.setNickname("芋");
  277 + reqVO.setOpenid("yudao");
  278 + reqVO.setCreateTime(buildBetweenTime(2020, 1, 10, 2020, 1, 20));
  279 +
  280 + // 调用
  281 + PageResult<SocialUserDO> pageResult = socialUserService.getSocialUserPage(reqVO);
  282 + // 断言
  283 + assertEquals(1, pageResult.getTotal());
  284 + assertEquals(1, pageResult.getList().size());
  285 + assertPojoEquals(dbSocialUser, pageResult.getList().get(0));
  286 + }
  287 +
263 } 288 }
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImplTest.java
@@ -332,6 +332,18 @@ public class TenantServiceImplTest extends BaseDbUnitTest { @@ -332,6 +332,18 @@ public class TenantServiceImplTest extends BaseDbUnitTest {
332 } 332 }
333 333
334 @Test 334 @Test
  335 + public void testGetTenantByWebsite() {
  336 + // mock 数据
  337 + TenantDO dbTenant = randomPojo(TenantDO.class, o -> o.setWebsite("https://www.iocoder.cn"));
  338 + tenantMapper.insert(dbTenant);// @Sql: 先插入出一条存在的数据
  339 +
  340 + // 调用
  341 + TenantDO result = tenantService.getTenantByWebsite("https://www.iocoder.cn");
  342 + // 校验存在
  343 + assertPojoEquals(result, dbTenant);
  344 + }
  345 +
  346 + @Test
335 public void testGetTenantListByPackageId() { 347 public void testGetTenantListByPackageId() {
336 // mock 数据 348 // mock 数据
337 TenantDO dbTenant1 = randomPojo(TenantDO.class, o -> o.setPackageId(1L)); 349 TenantDO dbTenant1 = randomPojo(TenantDO.class, o -> o.setPackageId(1L));
yudao-module-system/yudao-module-system-biz/src/test/resources/sql/create_tables.sql
@@ -361,13 +361,14 @@ CREATE TABLE IF NOT EXISTS &quot;system_social_client&quot; ( @@ -361,13 +361,14 @@ CREATE TABLE IF NOT EXISTS &quot;system_social_client&quot; (
361 "user_type" int NOT NULL, 361 "user_type" int NOT NULL,
362 "client_id" varchar(255) NOT NULL, 362 "client_id" varchar(255) NOT NULL,
363 "client_secret" varchar(255) NOT NULL, 363 "client_secret" varchar(255) NOT NULL,
  364 + "agent_id" varchar(255) NOT NULL,
364 "status" int NOT NULL, 365 "status" int NOT NULL,
365 "creator" varchar(64) DEFAULT '', 366 "creator" varchar(64) DEFAULT '',
366 "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, 367 "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
367 "updater" varchar(64) DEFAULT '', 368 "updater" varchar(64) DEFAULT '',
368 "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 369 "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
369 "deleted" bit NOT NULL DEFAULT FALSE, 370 "deleted" bit NOT NULL DEFAULT FALSE,
370 - "tenant_id" bigint NOT NULL, 371 + "tenant_id" bigint not null default '0',
371 PRIMARY KEY ("id") 372 PRIMARY KEY ("id")
372 ) COMMENT '社交客户端表'; 373 ) COMMENT '社交客户端表';
373 374