多模块重构 6:tool 模块的迁移完成

This commit is contained in:
YunaiV
2022-01-31 19:26:39 +08:00
parent fffd023d31
commit e7e3b18704
77 changed files with 791 additions and 641 deletions

View File

@ -0,0 +1,167 @@
package cn.iocoder.yudao.module.tool.controller.admin.codegen;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ZipUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.tool.controller.admin.codegen.vo.CodegenDetailRespVO;
import cn.iocoder.yudao.module.tool.controller.admin.codegen.vo.CodegenPreviewRespVO;
import cn.iocoder.yudao.module.tool.controller.admin.codegen.vo.CodegenUpdateReqVO;
import cn.iocoder.yudao.module.tool.controller.admin.codegen.vo.table.CodegenTablePageReqVO;
import cn.iocoder.yudao.module.tool.controller.admin.codegen.vo.table.CodegenTableRespVO;
import cn.iocoder.yudao.module.tool.controller.admin.codegen.vo.table.SchemaTableRespVO;
import cn.iocoder.yudao.module.tool.convert.codegen.CodegenConvert;
import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.CodegenColumnDO;
import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.CodegenTableDO;
import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.SchemaTableDO;
import cn.iocoder.yudao.module.tool.service.codegen.CodegenService;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Api(tags = "管理后台 - 代码生成器")
@RestController
@RequestMapping("/tool/codegen")
@Validated
public class CodegenController {
@Resource
private CodegenService codegenService;
@GetMapping("/db/table/list")
@ApiOperation(value = "获得数据库自带的表定义列表", notes = "会过滤掉已经导入 Codegen 的表")
@ApiImplicitParams({
@ApiImplicitParam(name = "tableName", value = "表名,模糊匹配", required = true, example = "yudao", dataTypeClass = String.class),
@ApiImplicitParam(name = "tableComment", value = "描述,模糊匹配", required = true, example = "芋道", dataTypeClass = String.class)
})
@PreAuthorize("@ss.hasPermission('tool:codegen:query')")
public CommonResult<List<SchemaTableRespVO>> getSchemaTableList(
@RequestParam(value = "tableName", required = false) String tableName,
@RequestParam(value = "tableComment", required = false) String tableComment) {
// 获得数据库自带的表定义列表
List<SchemaTableDO> schemaTables = codegenService.getSchemaTableList(tableName, tableComment);
// 移除在 Codegen 中,已经存在的
Set<String> existsTables = CollectionUtils.convertSet(codegenService.getCodeGenTableList(), CodegenTableDO::getTableName);
schemaTables.removeIf(table -> existsTables.contains(table.getTableName()));
return success(CodegenConvert.INSTANCE.convertList04(schemaTables));
}
@GetMapping("/table/page")
@ApiOperation("获得表定义分页")
@PreAuthorize("@ss.hasPermission('tool:codegen:query')")
public CommonResult<PageResult<CodegenTableRespVO>> getCodeGenTablePage(@Valid CodegenTablePageReqVO pageReqVO) {
PageResult<CodegenTableDO> pageResult = codegenService.getCodegenTablePage(pageReqVO);
return success(CodegenConvert.INSTANCE.convertPage(pageResult));
}
@GetMapping("/detail")
@ApiOperation("获得表和字段的明细")
@ApiImplicitParam(name = "tableId", value = "表编号", required = true, example = "1024", dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('tool:codegen:query')")
public CommonResult<CodegenDetailRespVO> getCodegenDetail(@RequestParam("tableId") Long tableId) {
CodegenTableDO table = codegenService.getCodegenTablePage(tableId);
List<CodegenColumnDO> columns = codegenService.getCodegenColumnListByTableId(tableId);
// 拼装返回
return success(CodegenConvert.INSTANCE.convert(table, columns));
}
@ApiOperation("基于数据库的表结构,创建代码生成器的表和字段定义")
@ApiImplicitParam(name = "tableNames", value = "表名数组", required = true, example = "sys_user", dataTypeClass = List.class)
@PostMapping("/create-list-from-db")
@PreAuthorize("@ss.hasPermission('tool:codegen:create')")
public CommonResult<List<Long>> createCodegenListFromDB(@RequestParam("tableNames") List<String> tableNames) {
return success(codegenService.createCodegenListFromDB(tableNames));
}
@ApiOperation("基于 SQL 建表语句,创建代码生成器的表和字段定义")
@ApiImplicitParam(name = "sql", value = "SQL 建表语句", required = true, example = "sql", dataTypeClass = String.class)
@PostMapping("/create-list-from-sql")
@PreAuthorize("@ss.hasPermission('tool:codegen:create')")
public CommonResult<Long> createCodegenListFromSQL(@RequestParam("sql") String sql) {
return success(codegenService.createCodegenListFromSQL(sql));
}
@ApiOperation("更新数据库的表和字段定义")
@PutMapping("/update")
@PreAuthorize("@ss.hasPermission('tool:codegen:update')")
public CommonResult<Boolean> updateCodegen(@Valid @RequestBody CodegenUpdateReqVO updateReqVO) {
codegenService.updateCodegen(updateReqVO);
return success(true);
}
@ApiOperation("基于数据库的表结构,同步数据库的表和字段定义")
@PutMapping("/sync-from-db")
@ApiImplicitParam(name = "tableId", value = "表编号", required = true, example = "1024", dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('tool:codegen:update')")
public CommonResult<Boolean> syncCodegenFromDB(@RequestParam("tableId") Long tableId) {
codegenService.syncCodegenFromDB(tableId);
return success(true);
}
@ApiOperation("基于 SQL 建表语句,同步数据库的表和字段定义")
@PutMapping("/sync-from-sql")
@ApiImplicitParams({
@ApiImplicitParam(name = "tableId", value = "表编号", required = true, example = "1024", dataTypeClass = Long.class),
@ApiImplicitParam(name = "sql", value = "SQL 建表语句", required = true, example = "sql", dataTypeClass = String.class)
})
@PreAuthorize("@ss.hasPermission('tool:codegen:update')")
public CommonResult<Boolean> syncCodegenFromSQL(@RequestParam("tableId") Long tableId,
@RequestParam("sql") String sql) {
codegenService.syncCodegenFromSQL(tableId, sql);
return success(true);
}
@ApiOperation("删除数据库的表和字段定义")
@DeleteMapping("/delete")
@ApiImplicitParam(name = "tableId", value = "表编号", required = true, example = "1024", dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('tool:codegen:delete')")
public CommonResult<Boolean> deleteCodegen(@RequestParam("tableId") Long tableId) {
codegenService.deleteCodegen(tableId);
return success(true);
}
@ApiOperation("预览生成代码")
@GetMapping("/preview")
@ApiImplicitParam(name = "tableId", value = "表编号", required = true, example = "1024", dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('tool:codegen:preview')")
public CommonResult<List<CodegenPreviewRespVO>> previewCodegen(@RequestParam("tableId") Long tableId) {
Map<String, String> codes = codegenService.generationCodes(tableId);
return success(CodegenConvert.INSTANCE.convert(codes));
}
@ApiOperation("下载生成代码")
@GetMapping("/download")
@ApiImplicitParam(name = "tableId", value = "表编号", required = true, example = "1024", dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('tool:codegen:download')")
public void downloadCodegen(@RequestParam("tableId") Long tableId,
HttpServletResponse response) throws IOException {
// 生成代码
Map<String, String> codes = codegenService.generationCodes(tableId);
// 构建 zip 包
String[] paths = codes.keySet().toArray(new String[0]);
ByteArrayInputStream[] ins = codes.values().stream().map(IoUtil::toUtf8Stream).toArray(ByteArrayInputStream[]::new);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ZipUtil.zip(outputStream, paths, ins);
// 输出
ServletUtils.writeAttachment(response, "codegen.zip", outputStream.toByteArray());
}
}

View File

@ -0,0 +1,21 @@
package cn.iocoder.yudao.module.tool.controller.admin.codegen.vo;
import cn.iocoder.yudao.module.tool.controller.admin.codegen.vo.column.CodegenColumnRespVO;
import cn.iocoder.yudao.module.tool.controller.admin.codegen.vo.table.CodegenTableRespVO;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
@ApiModel("管理后台 - 代码生成表和字段的明细 Response VO")
@Data
public class CodegenDetailRespVO {
@ApiModelProperty("表定义")
private CodegenTableRespVO table;
@ApiModelProperty("字段定义")
private List<CodegenColumnRespVO> columns;
}

View File

@ -0,0 +1,17 @@
package cn.iocoder.yudao.module.tool.controller.admin.codegen.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@ApiModel(value = "管理后台 - 代码生成预览 Response VO", description ="注意,每个文件都是一个该对象")
@Data
public class CodegenPreviewRespVO {
@ApiModelProperty(value = "文件路径", required = true, example = "java/cn/iocoder/yudao/adminserver/modules/system/controller/test/SysTestDemoController.java")
private String filePath;
@ApiModelProperty(value = "代码", required = true, example = "Hello World")
private String code;
}

View File

@ -0,0 +1,49 @@
package cn.iocoder.yudao.module.tool.controller.admin.codegen.vo;
import cn.iocoder.yudao.module.tool.controller.admin.codegen.vo.table.CodegenTableBaseVO;
import cn.iocoder.yudao.module.tool.controller.admin.codegen.vo.column.CodegenColumnBaseVO;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.util.List;
@ApiModel("管理后台 - 代码生成表和字段的修改 Request VO")
@Data
public class CodegenUpdateReqVO {
@Valid // 校验内嵌的字段
@NotNull(message = "表定义不能为空")
private Table table;
@Valid // 校验内嵌的字段
@NotNull(message = "字段定义不能为空")
private List<Column> columns;
@ApiModel("更新表定义")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public static class Table extends CodegenTableBaseVO {
@ApiModelProperty(value = "编号", required = true, example = "1")
private Long id;
}
@ApiModel("更新表定义")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public static class Column extends CodegenColumnBaseVO {
@ApiModelProperty(value = "编号", required = true, example = "1")
private Long id;
}
}

View File

@ -0,0 +1,85 @@
package cn.iocoder.yudao.module.tool.controller.admin.codegen.vo.column;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
/**
* 代码生成字段定义 Base VO提供给添加、修改、详细的子 VO 使用
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
*/
@Data
public class CodegenColumnBaseVO {
@ApiModelProperty(value = "表编号", required = true, example = "1")
@NotNull(message = "表编号不能为空")
private Long tableId;
@ApiModelProperty(value = "字段名", required = true, example = "user_age")
@NotNull(message = "字段名不能为空")
private String columnName;
@ApiModelProperty(value = "字段类型", required = true, example = "int(11)")
@NotNull(message = "字段类型不能为空")
private String columnType;
@ApiModelProperty(value = "字段描述", required = true, example = "年龄")
@NotNull(message = "字段描述不能为空")
private String columnComment;
@ApiModelProperty(value = "是否允许为空", required = true, example = "true")
@NotNull(message = "是否允许为空不能为空")
private Boolean nullable;
@ApiModelProperty(value = "是否主键", required = true, example = "false")
@NotNull(message = "是否主键不能为空")
private Boolean primaryKey;
@ApiModelProperty(value = "是否自增", required = true, example = "true")
@NotNull(message = "是否自增不能为空")
private String autoIncrement;
@ApiModelProperty(value = "排序", required = true, example = "10")
@NotNull(message = "排序不能为空")
private Integer ordinalPosition;
@ApiModelProperty(value = "Java 属性类型", required = true, example = "userAge")
@NotNull(message = "Java 属性类型不能为空")
private String javaType;
@ApiModelProperty(value = "Java 属性名", required = true, example = "Integer")
@NotNull(message = "Java 属性名不能为空")
private String javaField;
@ApiModelProperty(value = "字典类型", example = "sys_gender")
private String dictType;
@ApiModelProperty(value = "数据示例", example = "1024")
private String example;
@ApiModelProperty(value = "是否为 Create 创建操作的字段", required = true, example = "true")
@NotNull(message = "是否为 Create 创建操作的字段不能为空")
private Boolean createOperation;
@ApiModelProperty(value = "是否为 Update 更新操作的字段", required = true, example = "false")
@NotNull(message = "是否为 Update 更新操作的字段不能为空")
private Boolean updateOperation;
@ApiModelProperty(value = "是否为 List 查询操作的字段", required = true, example = "true")
@NotNull(message = "是否为 List 查询操作的字段不能为空")
private Boolean listOperation;
@ApiModelProperty(value = "List 查询操作的条件类型", required = true, example = "LIKE", notes = "参见 CodegenColumnListConditionEnum 枚举")
@NotNull(message = "List 查询操作的条件类型不能为空")
private String listOperationCondition;
@ApiModelProperty(value = "是否为 List 查询操作的返回字段", required = true, example = "true")
@NotNull(message = "是否为 List 查询操作的返回字段不能为空")
private Boolean listOperationResult;
@ApiModelProperty(value = "显示类型", required = true, example = "input")
@NotNull(message = "显示类型不能为空")
private String htmlType;
}

View File

@ -0,0 +1,23 @@
package cn.iocoder.yudao.module.tool.controller.admin.codegen.vo.column;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.util.Date;
@ApiModel("管理后台 - 代码生成字段定义 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class CodegenColumnRespVO extends CodegenColumnBaseVO {
@ApiModelProperty(value = "编号", required = true, example = "1")
private Long id;
@ApiModelProperty(value = "创建时间", required = true)
private Date createTime;
}

View File

@ -0,0 +1,57 @@
package cn.iocoder.yudao.module.tool.controller.admin.codegen.vo.table;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
/**
* 代码生成 Base VO提供给添加、修改、详细的子 VO 使用
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
*/
@Data
public class CodegenTableBaseVO {
@ApiModelProperty(value = "导入类型", required = true, example = "1", notes = "参见 CodegenImportTypeEnum 枚举")
@NotNull(message = "导入类型不能为空")
private Integer importType;
@ApiModelProperty(value = "表名称", required = true, example = "yudao")
@NotNull(message = "表名称不能为空")
private String tableName;
@ApiModelProperty(value = "表描述", required = true, example = "芋道")
@NotNull(message = "表描述不能为空")
private String tableComment;
@ApiModelProperty(value = "备注", example = "我是备注")
private String remark;
@ApiModelProperty(value = "模块名", required = true, example = "system")
@NotNull(message = "模块名不能为空")
private String moduleName;
@ApiModelProperty(value = "业务名", required = true, example = "codegen")
@NotNull(message = "业务名不能为空")
private String businessName;
@ApiModelProperty(value = "类名称", required = true, example = "CodegenTable")
@NotNull(message = "类名称不能为空")
private String className;
@ApiModelProperty(value = "类描述", required = true, example = "代码生成器的表定义")
@NotNull(message = "类描述不能为空")
private String classComment;
@ApiModelProperty(value = "作者", required = true, example = "芋道源码")
@NotNull(message = "作者不能为空")
private String author;
@ApiModelProperty(value = "模板类型", required = true, example = "1", notes = "参见 CodegenTemplateTypeEnum 枚举")
@NotNull(message = "模板类型不能为空")
private Integer templateType;
@ApiModelProperty(value = "父菜单编号", example = "1024")
private Long parentMenuId;
}

View File

@ -0,0 +1,35 @@
package cn.iocoder.yudao.module.tool.controller.admin.codegen.vo.table;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel("管理后台 - 表定义分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class CodegenTablePageReqVO extends PageParam {
@ApiModelProperty(value = "表名称", example = "yudao", notes = "模糊匹配")
private String tableName;
@ApiModelProperty(value = "表描述", example = "芋道", notes = "模糊匹配")
private String tableComment;
@ApiModelProperty(value = "开始创建时间", example = "2020-10-24 00:00:00")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date beginCreateTime;
@ApiModelProperty(value = "结束创建时间", example = "2020-10-24 23:59:59")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date endCreateTime;
}

View File

@ -0,0 +1,26 @@
package cn.iocoder.yudao.module.tool.controller.admin.codegen.vo.table;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.util.Date;
@ApiModel("管理后台 - 代码生成表定义 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class CodegenTableRespVO extends CodegenTableBaseVO {
@ApiModelProperty(value = "编号", required = true, example = "1")
private Long id;
@ApiModelProperty(value = "创建时间", required = true)
private Date createTime;
@ApiModelProperty(value = "更新时间", required = true)
private Date updateTime;
}

View File

@ -0,0 +1,25 @@
package cn.iocoder.yudao.module.tool.controller.admin.codegen.vo.table;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
@ApiModel("管理后台 - 数据字典的表定义 Response VO")
@Data
public class SchemaTableRespVO {
@ApiModelProperty(value = "数据库", required = true, example = "yudao")
private String tableSchema;
@ApiModelProperty(value = "表名称", required = true, example = "yuanma")
private String tableName;
@ApiModelProperty(value = "表描述", required = true, example = "芋道源码")
private String tableComment;
@ApiModelProperty(value = "创建时间", required = true)
private Date createTime;
}

View File

@ -0,0 +1,9 @@
### 请求 /tool/test-demo/get 接口 => 成功
GET {{baseUrl}}/tool/test-demo/get?id=1
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
### 请求 /tool/test-demo/list 接口 => 成功
GET {{baseUrl}}/tool/test-demo/list?ids=1
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}

View File

@ -0,0 +1,101 @@
package cn.iocoder.yudao.module.tool.controller.admin.test;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.module.tool.controller.admin.test.vo.*;
import cn.iocoder.yudao.module.tool.convert.test.TestDemoConvert;
import cn.iocoder.yudao.module.tool.dal.dataobject.test.TestDemoDO;
import cn.iocoder.yudao.module.tool.service.test.TestDemoService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
@Api(tags = "管理后台 - 测试示例")
@RestController
@RequestMapping("/tool/test-demo")
@Validated
public class TestDemoController {
@Resource
private TestDemoService testDemoService;
@PostMapping("/create")
@ApiOperation("创建测试示例")
@PreAuthorize("@ss.hasPermission('tool:test-demo:create')")
public CommonResult<Long> createTestDemo(@Valid @RequestBody TestDemoCreateReqVO createReqVO) {
return success(testDemoService.createTestDemo(createReqVO));
}
@PutMapping("/update")
@ApiOperation("更新测试示例")
@PreAuthorize("@ss.hasPermission('tool:test-demo:update')")
public CommonResult<Boolean> updateTestDemo(@Valid @RequestBody TestDemoUpdateReqVO updateReqVO) {
testDemoService.updateTestDemo(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@ApiOperation("删除测试示例")
@ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('tool:test-demo:delete')")
public CommonResult<Boolean> deleteTestDemo(@RequestParam("id") Long id) {
testDemoService.deleteTestDemo(id);
return success(true);
}
@GetMapping("/get")
@ApiOperation("获得测试示例")
@ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
@PreAuthorize("@ss.hasPermission('tool:test-demo:query')")
// @Lock4j // 分布式锁
public CommonResult<TestDemoRespVO> getTestDemo(@RequestParam("id") Long id) {
TestDemoDO testDemo = testDemoService.getTestDemo(id);
return success(TestDemoConvert.INSTANCE.convert(testDemo));
}
@GetMapping("/list")
@ApiOperation("获得测试示例列表")
@ApiImplicitParam(name = "ids", value = "编号列表", required = true, dataTypeClass = List.class)
@PreAuthorize("@ss.hasPermission('tool:test-demo:query')")
// @RateLimiter(name = "backendA")
public CommonResult<List<TestDemoRespVO>> getTestDemoList(@RequestParam("ids") Collection<Long> ids) {
List<TestDemoDO> list = testDemoService.getTestDemoList(ids);
return success(TestDemoConvert.INSTANCE.convertList(list));
}
@GetMapping("/page")
@ApiOperation("获得测试示例分页")
@PreAuthorize("@ss.hasPermission('tool:test-demo:query')")
public CommonResult<PageResult<TestDemoRespVO>> getTestDemoPage(@Valid TestDemoPageReqVO pageVO) {
PageResult<TestDemoDO> pageResult = testDemoService.getTestDemoPage(pageVO);
return success(TestDemoConvert.INSTANCE.convertPage(pageResult));
}
@GetMapping("/export-excel")
@ApiOperation("导出测试示例 Excel")
@PreAuthorize("@ss.hasPermission('tool:test-demo:export')")
@OperateLog(type = EXPORT)
public void exportTestDemoExcel(@Valid TestDemoExportReqVO exportReqVO,
HttpServletResponse response) throws IOException {
List<TestDemoDO> list = testDemoService.getTestDemoList(exportReqVO);
// 导出 Excel
List<TestDemoExcelVO> datas = TestDemoConvert.INSTANCE.convertList02(list);
ExcelUtils.write(response, "测试示例.xls", "数据", TestDemoExcelVO.class, datas);
}
}

View File

@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.tool.controller.admin.test.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
/**
* 字典类型 Base VO提供给添加、修改、详细的子 VO 使用
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
*/
@Data
public class TestDemoBaseVO {
@ApiModelProperty(value = "名字", required = true, example = "芋道")
@NotNull(message = "名字不能为空")
private String name;
@ApiModelProperty(value = "状态", required = true, example = "1")
@NotNull(message = "状态不能为空")
private Integer status;
@ApiModelProperty(value = "类型", required = true, example = "2")
@NotNull(message = "类型不能为空")
private Integer type;
@ApiModelProperty(value = "分类", required = true, example = "3")
@NotNull(message = "分类不能为空")
private Integer category;
@ApiModelProperty(value = "备注", example = "我是备注")
private String remark;
}

View File

@ -0,0 +1,14 @@
package cn.iocoder.yudao.module.tool.controller.admin.test.vo;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@ApiModel("管理后台 - 字典类型创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class TestDemoCreateReqVO extends TestDemoBaseVO {
}

View File

@ -0,0 +1,42 @@
package cn.iocoder.yudao.module.tool.controller.admin.test.vo;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import java.util.Date;
/**
* 测试示例 Excel VO
*
* @author 芋艿
*/
@Data
public class TestDemoExcelVO {
@ExcelProperty("编号")
private Long id;
@ExcelProperty("名字")
private String name;
@ExcelProperty(value = "状态", converter = DictConvert.class)
@DictFormat("")
private Integer status;
@ExcelProperty(value = "类型", converter = DictConvert.class)
@DictFormat("sys_common_status")
private Integer type;
@ExcelProperty(value = "分类", converter = DictConvert.class)
@DictFormat("inf_redis_timeout_type")
private Integer category;
@ExcelProperty("备注")
private String remark;
@ExcelProperty("创建时间")
private Date createTime;
}

View File

@ -0,0 +1,39 @@
package cn.iocoder.yudao.module.tool.controller.admin.test.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel(value = "管理后台 - 字典类型 Excel 导出 Request VO", description = "参数和 TestDemoPageReqVO 是一致的")
@Data
public class TestDemoExportReqVO {
@ApiModelProperty(value = "名字", example = "芋道")
private String name;
@ApiModelProperty(value = "状态", example = "1")
private Integer status;
@ApiModelProperty(value = "类型", example = "2")
private Integer type;
@ApiModelProperty(value = "分类", example = "3")
private Integer category;
@ApiModelProperty(value = "备注", example = "我是备注")
private String remark;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "开始创建时间")
private Date beginCreateTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "结束创建时间")
private Date endCreateTime;
}

View File

@ -0,0 +1,44 @@
package cn.iocoder.yudao.module.tool.controller.admin.test.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel("管理后台 - 字典类型分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class TestDemoPageReqVO extends PageParam {
@ApiModelProperty(value = "名字", example = "芋道")
private String name;
@ApiModelProperty(value = "状态", example = "1")
private Integer status;
@ApiModelProperty(value = "类型", example = "2")
private Integer type;
@ApiModelProperty(value = "分类", example = "3")
private Integer category;
@ApiModelProperty(value = "备注", example = "我是备注")
private String remark;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "开始创建时间")
private Date beginCreateTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "结束创建时间")
private Date endCreateTime;
}

View File

@ -0,0 +1,23 @@
package cn.iocoder.yudao.module.tool.controller.admin.test.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.util.Date;
@ApiModel("管理后台 - 字典类型 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class TestDemoRespVO extends TestDemoBaseVO {
@ApiModelProperty(value = "编号", required = true, example = "1")
private Long id;
@ApiModelProperty(value = "创建时间", required = true)
private Date createTime;
}

View File

@ -0,0 +1,21 @@
package cn.iocoder.yudao.module.tool.controller.admin.test.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import javax.validation.constraints.NotNull;
@ApiModel("管理后台 - 字典类型更新 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class TestDemoUpdateReqVO extends TestDemoBaseVO {
@ApiModelProperty(value = "编号", required = true, example = "1")
@NotNull(message = "编号不能为空")
private Long id;
}

View File

@ -0,0 +1,4 @@
/**
* 占位,避免 package 无法提交到 Git 仓库
*/
package cn.iocoder.yudao.module.tool.controller.app;

View File

@ -0,0 +1,6 @@
/**
* 提供 RESTful API 给前端:
* 1. admin 包:提供给管理后台 yudao-ui-admin 前端项目
* 2. app 包:提供给用户 APP yudao-ui-app 前端项目,它的 Controller 和 VO 都要添加 App 前缀,用于和管理后台进行区分
*/
package cn.iocoder.yudao.module.tool.controller;

View File

@ -0,0 +1,70 @@
package cn.iocoder.yudao.module.tool.convert.codegen;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.tool.controller.admin.codegen.vo.CodegenDetailRespVO;
import cn.iocoder.yudao.module.tool.controller.admin.codegen.vo.CodegenPreviewRespVO;
import cn.iocoder.yudao.module.tool.controller.admin.codegen.vo.CodegenUpdateReqVO;
import cn.iocoder.yudao.module.tool.controller.admin.codegen.vo.column.CodegenColumnRespVO;
import cn.iocoder.yudao.module.tool.controller.admin.codegen.vo.table.CodegenTableRespVO;
import cn.iocoder.yudao.module.tool.controller.admin.codegen.vo.table.SchemaTableRespVO;
import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.CodegenColumnDO;
import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.CodegenTableDO;
import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.SchemaColumnDO;
import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.SchemaTableDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Mapper
public interface CodegenConvert {
CodegenConvert INSTANCE = Mappers.getMapper(CodegenConvert.class);
// ========== InformationSchemaTableDO 和 InformationSchemaColumnDO 相关 ==========
CodegenTableDO convert(SchemaTableDO bean);
List<CodegenColumnDO> convertList(List<SchemaColumnDO> list);
CodegenTableRespVO convert(SchemaColumnDO bean);
// ========== CodegenTableDO 相关 ==========
// List<CodegenTableRespVO> convertList02(List<CodegenTableDO> list);
CodegenTableRespVO convert(CodegenTableDO bean);
PageResult<CodegenTableRespVO> convertPage(PageResult<CodegenTableDO> page);
// ========== CodegenTableDO 相关 ==========
List<CodegenColumnRespVO> convertList02(List<CodegenColumnDO> list);
CodegenTableDO convert(CodegenUpdateReqVO.Table bean);
List<CodegenColumnDO> convertList03(List<CodegenUpdateReqVO.Column> columns);
List<SchemaTableRespVO> convertList04(List<SchemaTableDO> list);
// ========== 其它 ==========
default CodegenDetailRespVO convert(CodegenTableDO table, List<CodegenColumnDO> columns) {
CodegenDetailRespVO respVO = new CodegenDetailRespVO();
respVO.setTable(convert(table));
respVO.setColumns(convertList02(columns));
return respVO;
}
default List<CodegenPreviewRespVO> convert(Map<String, String> codes) {
return codes.entrySet().stream().map(entry -> {
CodegenPreviewRespVO respVO = new CodegenPreviewRespVO();
respVO.setFilePath(entry.getKey());
respVO.setCode(entry.getValue());
return respVO;
}).collect(Collectors.toList());
}
}

View File

@ -0,0 +1,32 @@
package cn.iocoder.yudao.module.tool.convert.test;
import java.util.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.tool.controller.admin.test.vo.TestDemoCreateReqVO;
import cn.iocoder.yudao.module.tool.controller.admin.test.vo.TestDemoExcelVO;
import cn.iocoder.yudao.module.tool.controller.admin.test.vo.TestDemoRespVO;
import cn.iocoder.yudao.module.tool.controller.admin.test.vo.TestDemoUpdateReqVO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import cn.iocoder.yudao.module.tool.dal.dataobject.test.TestDemoDO;
@Mapper
public interface TestDemoConvert {
TestDemoConvert INSTANCE = Mappers.getMapper(TestDemoConvert.class);
TestDemoDO convert(TestDemoCreateReqVO bean);
TestDemoDO convert(TestDemoUpdateReqVO bean);
TestDemoRespVO convert(TestDemoDO bean);
List<TestDemoRespVO> convertList(List<TestDemoDO> list);
PageResult<TestDemoRespVO> convertPage(PageResult<TestDemoDO> page);
List<TestDemoExcelVO> convertList02(List<TestDemoDO> list);
}

View File

@ -0,0 +1,124 @@
package cn.iocoder.yudao.module.tool.dal.dataobject.codegen;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.tool.enums.codegen.CodegenColumnHtmlTypeEnum;
import cn.iocoder.yudao.module.tool.enums.codegen.CodegenColumnListConditionEnum;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* 代码生成 column 字段定义
*
* @author 芋道源码
*/
@TableName(value = "tool_codegen_column", autoResultMap = true)
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public class CodegenColumnDO extends BaseDO {
/**
* ID 编号
*/
@TableId
private Long id;
/**
* 表编号
*
* 关联 {@link CodegenTableDO#getId()}
*/
private Long tableId;
// ========== 表相关字段 ==========
/**
* 字段名
*/
private String columnName;
/**
* 字段类型
*/
private String columnType;
/**
* 字段描述
*/
private String columnComment;
/**
* 是否允许为空
*/
private Boolean nullable;
/**
* 是否主键
*/
private Boolean primaryKey;
/**
* 是否自增
*/
private Boolean autoIncrement;
/**
* 排序
*/
private Integer ordinalPosition;
// ========== Java 相关字段 ==========
/**
* Java 属性类型
*
* 例如说 String、Boolean 等等
*/
private String javaType;
/**
* Java 属性名
*/
// @NotBlank(message = "Java属性不能为空")
private String javaField;
/**
* 字典类型
*
* 关联 DictTypeDO 的 type 属性
*/
private String dictType;
/**
* 数据示例,主要用于生成 Swagger 注解的 example 字段
*/
private String example;
// ========== CRUD 相关字段 ==========
/**
* 是否为 Create 创建操作的字段
*/
private Boolean createOperation;
/**
* 是否为 Update 更新操作的字段
*/
private Boolean updateOperation;
/**
* 是否为 List 查询操作的字段
*/
private Boolean listOperation;
/**
* List 查询操作的条件类型
*
* 枚举 {@link CodegenColumnListConditionEnum}
*/
private String listOperationCondition;
/**
* 是否为 List 查询操作的返回字段
*/
private Boolean listOperationResult;
// ========== UI 相关字段 ==========
/**
* 显示类型
*
* 枚举 {@link CodegenColumnHtmlTypeEnum}
*/
private String htmlType;
}

View File

@ -0,0 +1,95 @@
package cn.iocoder.yudao.module.tool.dal.dataobject.codegen;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.tool.enums.codegen.CodegenTemplateTypeEnum;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* 代码生成 table 表定义
*
* @author 芋道源码
*/
@TableName(value = "tool_codegen_table", autoResultMap = true)
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public class CodegenTableDO extends BaseDO {
/**
* ID 编号
*/
private Long id;
/**
* 导入类型
*
* 枚举 {@link CodegenTemplateTypeEnum}
*/
private Integer importType;
// ========== 表相关字段 ==========
/**
* 表名称
*/
private String tableName;
/**
* 表描述
*/
private String tableComment;
/**
* 备注
*/
private String remark;
// ========== 类相关字段 ==========
/**
* 模块名,即一级目录
*
* 例如说system、infra、tool 等等
*/
private String moduleName;
/**
* 业务名,即二级目录
*
* 例如说user、permission、dict 等等
*/
private String businessName;
/**
* 类名称(首字母大写)
*
* 例如说SysUser、SysMenu、SysDictData 等等
*/
private String className;
/**
* 类描述
*/
private String classComment;
/**
* 作者
*/
private String author;
// ========== 生成相关字段 ==========
/**
* 模板类型
*
* 枚举 {@link CodegenTemplateTypeEnum}
*/
private Integer templateType;
// ========== 菜单相关字段 ==========
/**
* 父菜单编号
*
* 关联 MenuDO 的 id 属性
*/
private Long parentMenuId;
}

View File

@ -0,0 +1,54 @@
package cn.iocoder.yudao.module.tool.dal.dataobject.codegen;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Builder;
import lombok.Data;
/**
* MySQL 数据库中的 column 字段定义
*
* @author 芋道源码
*/
@TableName(value = "information_schema.columns", autoResultMap = true)
@Data
@Builder
public class SchemaColumnDO {
/**
* 表名称
*/
private String tableName;
/**
* 字段名
*/
private String columnName;
/**
* 字段类型
*/
private String columnType;
/**
* 字段描述
*/
private String columnComment;
/**
* 是否允许为空
*/
@TableField("case when is_nullable = 'yes' then '1' else '0' end")
private Boolean nullable;
/**
* 是否主键
*/
@TableField("case when column_key = 'PRI' then '1' else '0' end")
private Boolean primaryKey;
/**
* 是否自增
*/
@TableField("case when extra = 'auto_increment' then '1' else '0' end")
private Boolean autoIncrement;
/**
* 排序字段
*/
private Integer ordinalPosition;
}

View File

@ -0,0 +1,36 @@
package cn.iocoder.yudao.module.tool.dal.dataobject.codegen;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Builder;
import lombok.Data;
import java.util.Date;
/**
* MySQL 数据库中的 table 表定义
*
* @author 芋道源码
*/
@TableName(value = "information_schema.tables", autoResultMap = true)
@Data
@Builder
public class SchemaTableDO {
/**
* 数据库
*/
private String tableSchema;
/**
* 表名称
*/
private String tableName;
/**
* 表描述
*/
private String tableComment;
/**
* 创建时间
*/
private Date createTime;
}

View File

@ -0,0 +1,47 @@
package cn.iocoder.yudao.module.tool.dal.dataobject.test;
import lombok.*;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
/**
* 测试示例 DO
*
* @author 芋艿
*/
@TableName("tool_test_demo")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TestDemoDO extends BaseDO {
/**
* 编号
*/
@TableId
private Long id;
/**
* 名字
*/
private String name;
/**
* 状态
*/
private Integer status;
/**
* 类型
*/
private Integer type;
/**
* 分类
*/
private Integer category;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,22 @@
package cn.iocoder.yudao.module.tool.dal.mysql.codegen;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.CodegenColumnDO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface CodegenColumnMapper extends BaseMapperX<CodegenColumnDO> {
default List<CodegenColumnDO> selectListByTableId(Long tableId) {
return selectList(new QueryWrapper<CodegenColumnDO>().eq("table_id", tableId)
.orderByAsc("ordinal_position"));
}
default void deleteListByTableId(Long tableId) {
delete(new QueryWrapper<CodegenColumnDO>().eq("table_id", tableId));
}
}

View File

@ -0,0 +1,25 @@
package cn.iocoder.yudao.module.tool.dal.mysql.codegen;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import cn.iocoder.yudao.module.tool.controller.admin.codegen.vo.table.CodegenTablePageReqVO;
import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.CodegenTableDO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface CodegenTableMapper extends BaseMapperX<CodegenTableDO> {
default CodegenTableDO selectByTableName(String tableName) {
return selectOne(new QueryWrapper<CodegenTableDO>().eq("table_name", tableName));
}
default PageResult<CodegenTableDO> selectPage(CodegenTablePageReqVO pageReqVO) {
return selectPage(pageReqVO, new QueryWrapperX<CodegenTableDO>()
.likeIfPresent("table_name", pageReqVO.getTableName())
.likeIfPresent("table_comment", pageReqVO.getTableComment())
.betweenIfPresent("create_time", pageReqVO.getBeginCreateTime(), pageReqVO.getEndCreateTime()));
}
}

View File

@ -0,0 +1,19 @@
package cn.iocoder.yudao.module.tool.dal.mysql.codegen;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.SchemaColumnDO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface SchemaColumnMapper extends BaseMapperX<SchemaColumnDO> {
default List<SchemaColumnDO> selectListByTableName(String tableSchema, String tableName) {
return selectList(new QueryWrapper<SchemaColumnDO>().eq("table_name", tableName)
.eq("table_schema", tableSchema)
.orderByAsc("ordinal_position"));
}
}

View File

@ -0,0 +1,26 @@
package cn.iocoder.yudao.module.tool.dal.mysql.codegen;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.SchemaTableDO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.ibatis.annotations.Mapper;
import java.util.Collection;
import java.util.List;
@Mapper
public interface SchemaTableMapper extends BaseMapperX<SchemaTableDO> {
default List<SchemaTableDO> selectList(Collection<String> tableSchemas, String tableName, String tableComment) {
return selectList(new QueryWrapperX<SchemaTableDO>().in("table_schema", tableSchemas)
.likeIfPresent("table_name", tableName)
.likeIfPresent("table_comment", tableComment));
}
default SchemaTableDO selectByTableSchemaAndTableName(String tableSchema, String tableName) {
return selectOne(new QueryWrapper<SchemaTableDO>().eq("table_schema",tableSchema)
.eq("table_name", tableName));
}
}

View File

@ -0,0 +1,38 @@
package cn.iocoder.yudao.module.tool.dal.mysql.test;
import java.util.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.tool.controller.admin.test.vo.TestDemoExportReqVO;
import cn.iocoder.yudao.module.tool.controller.admin.test.vo.TestDemoPageReqVO;
import cn.iocoder.yudao.module.tool.dal.dataobject.test.TestDemoDO;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface TestDemoMapper extends BaseMapperX<TestDemoDO> {
default PageResult<TestDemoDO> selectPage(TestDemoPageReqVO reqVO) {
return selectPage(reqVO, new QueryWrapperX<TestDemoDO>()
.likeIfPresent("name", reqVO.getName())
.eqIfPresent("status", reqVO.getStatus())
.eqIfPresent("type", reqVO.getType())
.eqIfPresent("category", reqVO.getCategory())
.eqIfPresent("remark", reqVO.getRemark())
.betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
.orderByDesc("id"));
}
default List<TestDemoDO> selectList(TestDemoExportReqVO reqVO) {
return selectList(new QueryWrapperX<TestDemoDO>()
.likeIfPresent("name", reqVO.getName())
.eqIfPresent("status", reqVO.getStatus())
.eqIfPresent("type", reqVO.getType())
.eqIfPresent("category", reqVO.getCategory())
.eqIfPresent("remark", reqVO.getRemark())
.betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
.orderByDesc("id"));
}
}

View File

@ -0,0 +1,29 @@
package cn.iocoder.yudao.module.tool.enums.codegen;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 代码生成器的字段 HTML 展示枚举
*/
@AllArgsConstructor
@Getter
public enum CodegenColumnHtmlTypeEnum {
INPUT("input"), // 文本框
TEXTAREA("textarea"), // 文本域
SELECT("select"), // 下拉框
RADIO("radio"), // 单选框
CHECKBOX("checkbox"), // 复选框
DATETIME("datetime"), // 日期控件
UPLOAD_IMAGE("upload_image"), // 上传图片
UPLOAD_FILE("upload_file"), // 上传文件
EDITOR("editor"), // 富文本控件
;
/**
* 条件
*/
private final String type;
}

View File

@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.tool.enums.codegen;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 代码生成器的字段过滤条件枚举
*/
@AllArgsConstructor
@Getter
public enum CodegenColumnListConditionEnum {
EQ("="),
NE("!="),
GT(">"),
GTE(">="),
LT("<"),
LTE("<="),
LIKE("LIKE"),
BETWEEN("BETWEEN");
/**
* 条件
*/
private final String condition;
}

View File

@ -0,0 +1,23 @@
package cn.iocoder.yudao.module.tool.enums.codegen;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 代码生成的导入类型
*
* @author 芋道源码
*/
@AllArgsConstructor
@Getter
public enum CodegenImportTypeEnum {
DB(1), // 从 information_schema 的 table 和 columns 表导入
SQL(2); // 基于建表 SQL 语句导入
/**
* 类型
*/
private final Integer type;
}

View File

@ -0,0 +1,24 @@
package cn.iocoder.yudao.module.tool.enums.codegen;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 代码生成模板类型
*
* @author 芋道源码
*/
@AllArgsConstructor
@Getter
public enum CodegenTemplateTypeEnum {
CRUD(1), // 单表(增删改查)
TREE(2), // 树表(增删改查)
;
/**
* 类型
*/
private final Integer type;
}

View File

@ -0,0 +1,4 @@
/**
* 占位
*/
package cn.iocoder.yudao.module.tool.enums;

View File

@ -0,0 +1,9 @@
package cn.iocoder.yudao.module.tool.framework.codegen.config;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableConfigurationProperties(CodegenProperties.class)
public class CodegenConfiguration {
}

View File

@ -0,0 +1,28 @@
package cn.iocoder.yudao.module.tool.framework.codegen.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Collection;
@ConfigurationProperties(prefix = "yudao.codegen")
@Validated
@Data
public class CodegenProperties {
/**
* 生成的 Java 代码的基础包
*/
@NotNull(message = "Java 代码的基础包不能为空")
private String basePackage;
/**
* 数据库名数组
*/
@NotEmpty(message = "数据库不能为空")
private Collection<String> dbSchemas;
}

View File

@ -0,0 +1,4 @@
/**
* 代码生成器
*/
package cn.iocoder.yudao.module.tool.framework.codegen;

View File

@ -0,0 +1,6 @@
/**
* 属于 tool 模块的 framework 封装
*
* @author 芋道源码
*/
package cn.iocoder.yudao.module.tool.framework;

View File

@ -0,0 +1,8 @@
/**
* tool 模块下,我们放研发工具,提升研发效率与质量。
* 例如说:代码生成器、接口文档等等
*
* 1. Controller URL以 /tool/ 开头,避免和其它 Module 冲突
* 2. DataObject 表名:以 tool_ 开头,方便在数据库中区分
*/
package cn.iocoder.yudao.module.tool;

View File

@ -0,0 +1,121 @@
package cn.iocoder.yudao.module.tool.service.codegen;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.tool.controller.admin.codegen.vo.CodegenUpdateReqVO;
import cn.iocoder.yudao.module.tool.controller.admin.codegen.vo.table.CodegenTablePageReqVO;
import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.CodegenColumnDO;
import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.CodegenTableDO;
import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.SchemaTableDO;
import java.util.List;
import java.util.Map;
/**
* 代码生成 Service 接口
*
* @author 芋道源码
*/
public interface CodegenService {
/**
* 基于 SQL 建表语句,创建代码生成器的表定义
*
* @param sql SQL 建表语句
* @return 创建的表定义的编号
*/
Long createCodegenListFromSQL(String sql);
/**
* 基于数据库的表结构,创建代码生成器的表定义
*
* @param tableName 表名称
* @return 创建的表定义的编号
*/
Long createCodegen(String tableName);
/**
* 基于 {@link #createCodegen(String)} 的批量创建
*
* @param tableNames 表名称数组
* @return 创建的表定义的编号数组
*/
List<Long> createCodegenListFromDB(List<String> tableNames);
/**
* 更新数据库的表和字段定义
*
* @param updateReqVO 更新信息
*/
void updateCodegen(CodegenUpdateReqVO updateReqVO);
/**
* 基于数据库的表结构,同步数据库的表和字段定义
*
* @param tableId 表编号
*/
void syncCodegenFromDB(Long tableId);
/**
* 基于 SQL 建表语句,同步数据库的表和字段定义
*
* @param tableId 表编号
* @param sql SQL 建表语句
*/
void syncCodegenFromSQL(Long tableId, String sql);
/**
* 删除数据库的表和字段定义
*
* @param tableId 数据编号
*/
void deleteCodegen(Long tableId);
/**
* 获得表定义分页
*
* @param pageReqVO 分页条件
* @return 表定义分页
*/
PageResult<CodegenTableDO> getCodegenTablePage(CodegenTablePageReqVO pageReqVO);
/**
* 获得表定义
*
* @param id 表编号
* @return 表定义
*/
CodegenTableDO getCodegenTablePage(Long id);
/**
* 获得全部表定义
*
* @return 表定义数组
*/
List<CodegenTableDO> getCodeGenTableList();
/**
* 获得指定表的字段定义数组
*
* @param tableId 表编号
* @return 字段定义数组
*/
List<CodegenColumnDO> getCodegenColumnListByTableId(Long tableId);
/**
* 执行指定表的代码生成
*
* @param tableId 表编号
* @return 生成结果。key 为文件路径value 为对应的代码内容
*/
Map<String, String> generationCodes(Long tableId);
/**
* 获得数据库自带的表定义列表
*
* @param tableName 表名称
* @param tableComment 表描述
* @return 表定义列表
*/
List<SchemaTableDO> getSchemaTableList(String tableName, String tableComment);
}

View File

@ -0,0 +1,287 @@
package cn.iocoder.yudao.module.tool.service.codegen;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.tool.framework.codegen.config.CodegenProperties;
import cn.iocoder.yudao.module.tool.controller.admin.codegen.vo.CodegenUpdateReqVO;
import cn.iocoder.yudao.module.tool.controller.admin.codegen.vo.table.CodegenTablePageReqVO;
import cn.iocoder.yudao.module.tool.convert.codegen.CodegenConvert;
import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.CodegenColumnDO;
import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.CodegenTableDO;
import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.SchemaColumnDO;
import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.SchemaTableDO;
import cn.iocoder.yudao.module.tool.dal.mysql.codegen.CodegenColumnMapper;
import cn.iocoder.yudao.module.tool.dal.mysql.codegen.CodegenTableMapper;
import cn.iocoder.yudao.module.tool.dal.mysql.codegen.SchemaColumnMapper;
import cn.iocoder.yudao.module.tool.dal.mysql.codegen.SchemaTableMapper;
import cn.iocoder.yudao.module.tool.enums.codegen.CodegenImportTypeEnum;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.tool.service.codegen.inner.CodegenBuilder;
import cn.iocoder.yudao.module.tool.service.codegen.inner.CodegenEngine;
import cn.iocoder.yudao.module.tool.service.codegen.inner.CodegenSQLParser;
import org.apache.commons.collections4.KeyValue;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.tool.enums.ErrorCodeConstants.*;
/**
* 代码生成 Service 实现类
*
* @author 芋道源码
*/
@Service
public class CodegenServiceImpl implements CodegenService {
@Resource
private SchemaTableMapper schemaTableMapper;
@Resource
private SchemaColumnMapper schemaColumnMapper;
@Resource
private CodegenTableMapper codegenTableMapper;
@Resource
private CodegenColumnMapper codegenColumnMapper;
@Resource
private CodegenBuilder codegenBuilder;
@Resource
private CodegenEngine codegenEngine;
@Resource
private CodegenProperties codegenProperties;
private Long createCodegen0(CodegenImportTypeEnum importType,
SchemaTableDO schemaTable, List<SchemaColumnDO> schemaColumns) {
// 校验导入的表和字段非空
if (schemaTable == null) {
throw exception(CODEGEN_IMPORT_TABLE_NULL);
}
if (CollUtil.isEmpty(schemaColumns)) {
throw exception(CODEGEN_IMPORT_COLUMNS_NULL);
}
// 校验是否已经存在
if (codegenTableMapper.selectByTableName(schemaTable.getTableName()) != null) {
throw exception(CODEGEN_TABLE_EXISTS);
}
// 构建 CodegenTableDO 对象,插入到 DB 中
CodegenTableDO table = codegenBuilder.buildTable(schemaTable);
table.setImportType(importType.getType());
codegenTableMapper.insert(table);
// 构建 CodegenColumnDO 数组,插入到 DB 中
List<CodegenColumnDO> columns = codegenBuilder.buildColumns(schemaColumns);
columns.forEach(column -> {
column.setTableId(table.getId());
codegenColumnMapper.insert(column); // TODO 批量插入
});
return table.getId();
}
@Override
public Long createCodegenListFromSQL(String sql) {
// 从 SQL 中,获得数据库表结构
SchemaTableDO schemaTable;
List<SchemaColumnDO> schemaColumns;
try {
KeyValue<SchemaTableDO, List<SchemaColumnDO>> result = CodegenSQLParser.parse(sql);
schemaTable = result.getKey();
schemaColumns = result.getValue();
} catch (Exception ex) {
throw exception(CODEGEN_PARSE_SQL_ERROR);
}
// 导入
return this.createCodegen0(CodegenImportTypeEnum.SQL, schemaTable, schemaColumns);
}
@Override
public Long createCodegen(String tableName) {
// 获取当前schema
String tableSchema = codegenProperties.getDbSchemas().iterator().next();
// 从数据库中,获得数据库表结构
SchemaTableDO schemaTable = schemaTableMapper.selectByTableSchemaAndTableName(tableSchema, tableName);
List<SchemaColumnDO> schemaColumns = schemaColumnMapper.selectListByTableName(tableSchema, tableName);
// 导入
return this.createCodegen0(CodegenImportTypeEnum.DB, schemaTable, schemaColumns);
}
@Override
@Transactional(rollbackFor = Exception.class)
public List<Long> createCodegenListFromDB(List<String> tableNames) {
List<Long> ids = new ArrayList<>(tableNames.size());
// 遍历添加。虽然效率会低一点,但是没必要做成完全批量,因为不会这么大量
tableNames.forEach(tableName -> ids.add(createCodegen(tableName)));
return ids;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateCodegen(CodegenUpdateReqVO updateReqVO) {
// 校验是否已经存在
if (codegenTableMapper.selectById(updateReqVO.getTable().getId()) == null) {
throw exception(CODEGEN_TABLE_NOT_EXISTS);
}
// 更新 table 表定义
CodegenTableDO updateTableObj = CodegenConvert.INSTANCE.convert(updateReqVO.getTable());
codegenTableMapper.updateById(updateTableObj);
// 更新 column 字段定义
List<CodegenColumnDO> updateColumnObjs = CodegenConvert.INSTANCE.convertList03(updateReqVO.getColumns());
updateColumnObjs.forEach(updateColumnObj -> codegenColumnMapper.updateById(updateColumnObj));
}
@Override
@Transactional(rollbackFor = Exception.class)
public void syncCodegenFromDB(Long tableId) {
// 校验是否已经存在
CodegenTableDO table = codegenTableMapper.selectById(tableId);
if (table == null) {
throw exception(CODEGEN_TABLE_NOT_EXISTS);
}
String tableSchema = codegenProperties.getDbSchemas().iterator().next();
// 从数据库中,获得数据库表结构
List<SchemaColumnDO> schemaColumns = schemaColumnMapper.selectListByTableName(tableSchema, table.getTableName());
// 执行同步
this.syncCodegen0(tableId, schemaColumns);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void syncCodegenFromSQL(Long tableId, String sql) {
// 校验是否已经存在
CodegenTableDO table = codegenTableMapper.selectById(tableId);
if (table == null) {
throw exception(CODEGEN_TABLE_NOT_EXISTS);
}
// 从 SQL 中,获得数据库表结构
List<SchemaColumnDO> schemaColumns;
try {
KeyValue<SchemaTableDO, List<SchemaColumnDO>> result = CodegenSQLParser.parse(sql);
schemaColumns = result.getValue();
} catch (Exception ex) {
throw exception(CODEGEN_PARSE_SQL_ERROR);
}
// 执行同步
this.syncCodegen0(tableId, schemaColumns);
}
private void syncCodegen0(Long tableId, List<SchemaColumnDO> schemaColumns) {
// 校验导入的字段不为空
if (CollUtil.isEmpty(schemaColumns)) {
throw exception(CODEGEN_SYNC_COLUMNS_NULL);
}
Set<String> schemaColumnNames = CollectionUtils.convertSet(schemaColumns, SchemaColumnDO::getColumnName);
// 构建 CodegenColumnDO 数组,只同步新增的字段
List<CodegenColumnDO> codegenColumns = codegenColumnMapper.selectListByTableId(tableId);
Set<String> codegenColumnNames = CollectionUtils.convertSet(codegenColumns, CodegenColumnDO::getColumnName);
// 移除已经存在的字段
schemaColumns.removeIf(column -> codegenColumnNames.contains(column.getColumnName()));
// 计算需要删除的字段
Set<Long> deleteColumnIds = codegenColumns.stream().filter(column -> !schemaColumnNames.contains(column.getColumnName()))
.map(CodegenColumnDO::getId).collect(Collectors.toSet());
if (CollUtil.isEmpty(schemaColumns) && CollUtil.isEmpty(deleteColumnIds)) {
throw exception(CODEGEN_SYNC_NONE_CHANGE);
}
// 插入新增的字段
List<CodegenColumnDO> columns = codegenBuilder.buildColumns(schemaColumns);
columns.forEach(column -> {
column.setTableId(tableId);
codegenColumnMapper.insert(column); // TODO 批量插入
});
// 删除不存在的字段
if (CollUtil.isNotEmpty(deleteColumnIds)) {
codegenColumnMapper.deleteBatchIds(deleteColumnIds);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteCodegen(Long tableId) {
// 校验是否已经存在
if (codegenTableMapper.selectById(tableId) == null) {
throw exception(CODEGEN_TABLE_NOT_EXISTS);
}
// 删除 table 表定义
codegenTableMapper.deleteById(tableId);
// 删除 column 字段定义
codegenColumnMapper.deleteListByTableId(tableId);
}
@Override
public PageResult<CodegenTableDO> getCodegenTablePage(CodegenTablePageReqVO pageReqVO) {
return codegenTableMapper.selectPage(pageReqVO);
}
@Override
public CodegenTableDO getCodegenTablePage(Long id) {
return codegenTableMapper.selectById(id);
}
@Override
public List<CodegenTableDO> getCodeGenTableList() {
return codegenTableMapper.selectList();
}
@Override
public List<CodegenColumnDO> getCodegenColumnListByTableId(Long tableId) {
return codegenColumnMapper.selectListByTableId(tableId);
}
@Override
public Map<String, String> generationCodes(Long tableId) {
// 校验是否已经存在
CodegenTableDO table = codegenTableMapper.selectById(tableId);
if (codegenTableMapper.selectById(tableId) == null) {
throw exception(CODEGEN_TABLE_NOT_EXISTS);
}
List<CodegenColumnDO> columns = codegenColumnMapper.selectListByTableId(tableId);
if (CollUtil.isEmpty(columns)) {
throw exception(CODEGEN_COLUMN_NOT_EXISTS);
}
// 执行生成
return codegenEngine.execute(table, columns);
}
@Override
public List<SchemaTableDO> getSchemaTableList(String tableName, String tableComment) {
List<SchemaTableDO> tables = schemaTableMapper.selectList(codegenProperties.getDbSchemas(), tableName, tableComment);
// TODO 强制移除 Quartz 的表,未来做成可配置
tables.removeIf(table -> table.getTableName().startsWith("QRTZ_"));
tables.removeIf(table -> table.getTableName().startsWith("ACT_"));
return tables;
}
// /**
// * 修改保存参数校验
// *
// * @param genTable 业务信息
// */
// @Override
// public void validateEdit(GenTable genTable) {
// if (GenConstants.TPL_TREE.equals(genTable.getTplCategory())) {
// String options = JSON.toJSONString(genTable.getParams());
// JSONObject paramsObj = JSONObject.parseObject(options);
// if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_CODE))) {
// throw new CustomException("树编码字段不能为空");
// } else if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_PARENT_CODE))) {
// throw new CustomException("树父编码字段不能为空");
// } else if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_NAME))) {
// throw new CustomException("树名称字段不能为空");
// }
// }
// }
}

View File

@ -0,0 +1,234 @@
package cn.iocoder.yudao.module.tool.service.codegen.inner;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.tool.convert.codegen.CodegenConvert;
import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.CodegenColumnDO;
import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.CodegenTableDO;
import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.SchemaColumnDO;
import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.SchemaTableDO;
import cn.iocoder.yudao.module.tool.enums.codegen.CodegenColumnHtmlTypeEnum;
import cn.iocoder.yudao.module.tool.enums.codegen.CodegenColumnListConditionEnum;
import cn.iocoder.yudao.module.tool.enums.codegen.CodegenTemplateTypeEnum;
import com.google.common.collect.Sets;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.util.*;
import static cn.hutool.core.text.CharSequenceUtil.*;
/**
* 代码生成器的 Builder负责
* 1. 将数据库的表 {@link SchemaTableDO} 定义,构建成 {@link CodegenTableDO}
* 2. 将数据库的列 {@link SchemaColumnDO} 构定义,建成 {@link CodegenColumnDO}
*/
@Component
public class CodegenBuilder {
/**
* Module 名字的映射 TODO 后续梳理到配置类
*
* key模块的完整名
* value模块的缩写名
*/
private static final Map<String, String> moduleNames = MapUtil.<String, String>builder()
.put("system", "sys")
.put("infra", "inf")
.put("tool", "tool")
.build();
/**
* 字段名与 {@link CodegenColumnListConditionEnum} 的默认映射
* 注意,字段的匹配以后缀的方式
*/
private static final Map<String, CodegenColumnListConditionEnum> columnListOperationConditionMappings =
MapUtil.<String, CodegenColumnListConditionEnum>builder()
.put("name", CodegenColumnListConditionEnum.LIKE)
.put("time", CodegenColumnListConditionEnum.BETWEEN)
.put("date", CodegenColumnListConditionEnum.BETWEEN)
.build();
/**
* 字段名与 {@link CodegenColumnHtmlTypeEnum} 的默认映射
* 注意,字段的匹配以后缀的方式
*/
private static final Map<String, CodegenColumnHtmlTypeEnum> columnHtmlTypeMappings =
MapUtil.<String, CodegenColumnHtmlTypeEnum>builder()
.put("status", CodegenColumnHtmlTypeEnum.RADIO)
.put("sex", CodegenColumnHtmlTypeEnum.RADIO)
.put("type", CodegenColumnHtmlTypeEnum.SELECT)
.put("image", CodegenColumnHtmlTypeEnum.UPLOAD_IMAGE)
.put("file", CodegenColumnHtmlTypeEnum.UPLOAD_FILE)
.put("content", CodegenColumnHtmlTypeEnum.EDITOR)
.put("time", CodegenColumnHtmlTypeEnum.DATETIME)
.put("date", CodegenColumnHtmlTypeEnum.DATETIME)
.build();
/**
* {@link BaseDO} 的字段
*/
public static final Set<String> BASE_DO_FIELDS = new HashSet<>();
/**
* 新增操作,不需要传递的字段
*/
private static final Set<String> CREATE_OPERATION_EXCLUDE_COLUMN = Sets.newHashSet("id");
/**
* 修改操作,不需要传递的字段
*/
private static final Set<String> UPDATE_OPERATION_EXCLUDE_COLUMN = Sets.newHashSet();
/**
* 列表操作的条件,不需要传递的字段
*/
private static final Set<String> LIST_OPERATION_EXCLUDE_COLUMN = Sets.newHashSet("id");
/**
* 列表操作的结果,不需要返回的字段
*/
private static final Set<String> LIST_OPERATION_RESULT_EXCLUDE_COLUMN = Sets.newHashSet();
/**
* Java 类型与 MySQL 类型的映射关系
*/
private static final Map<String, Set<String>> javaTypeMappings = MapUtil.<String, Set<String>>builder()
.put(Boolean.class.getSimpleName(), Sets.newHashSet("bit"))
.put(Integer.class.getSimpleName(), Sets.newHashSet("tinyint", "smallint", "mediumint", "int"))
.put(Long.class.getSimpleName(), Collections.singleton("bigint"))
.put(Double.class.getSimpleName(), Sets.newHashSet("float", "double"))
.put(BigDecimal.class.getSimpleName(), Sets.newHashSet("decimal", "numeric"))
.put(String.class.getSimpleName(), Sets.newHashSet("tinytext", "text", "mediumtext", "longtext", // 长文本
"char", "varchar", "nvarchar", "varchar2")) // 短文本
.put(Date.class.getSimpleName(), Sets.newHashSet("datetime", "time", "date", "timestamp"))
.put("byte[]", Sets.newHashSet("blob"))
.build();
static {
Arrays.stream(BaseDO.class.getDeclaredFields()).forEach(field -> BASE_DO_FIELDS.add(field.getName()));
// 处理 OPERATION 相关的字段
CREATE_OPERATION_EXCLUDE_COLUMN.addAll(BASE_DO_FIELDS);
UPDATE_OPERATION_EXCLUDE_COLUMN.addAll(BASE_DO_FIELDS);
LIST_OPERATION_EXCLUDE_COLUMN.addAll(BASE_DO_FIELDS);
LIST_OPERATION_EXCLUDE_COLUMN.remove("createTime"); // 创建时间,还是可能需要传递的
LIST_OPERATION_RESULT_EXCLUDE_COLUMN.addAll(BASE_DO_FIELDS);
LIST_OPERATION_RESULT_EXCLUDE_COLUMN.remove("createTime"); // 创建时间,还是需要返回的
}
public CodegenTableDO buildTable(SchemaTableDO schemaTable) {
CodegenTableDO table = CodegenConvert.INSTANCE.convert(schemaTable);
initTableDefault(table);
return table;
}
/**
* 初始化 Table 表的默认字段
*
* @param table 表定义
*/
private void initTableDefault(CodegenTableDO table) {
table.setModuleName(getFullModuleName(StrUtil.subBefore(table.getTableName(),
'_', false))); // 第一个 _ 前缀的前面,作为 module 名字
table.setBusinessName(toCamelCase(subAfter(table.getTableName(),
'_', false))); // 第一步,第一个 _ 前缀的后面,作为 module 名字; 第二步,可能存在多个 _ 的情况,转换成驼峰
table.setClassName(upperFirst(toCamelCase(table.getTableName()))); // 驼峰 + 首字母大写
table.setClassComment(subBefore(table.getTableComment(), // 去除结尾的表,作为类描述
'表', true));
table.setAuthor("芋艿"); // TODO 稍后改成创建人
table.setTemplateType(CodegenTemplateTypeEnum.CRUD.getType());
}
public List<CodegenColumnDO> buildColumns(List<SchemaColumnDO> schemaColumns) {
List<CodegenColumnDO> columns = CodegenConvert.INSTANCE.convertList(schemaColumns);
columns.forEach(this::initColumnDefault);
return columns;
}
/**
* 初始化 Column 列的默认字段
*
* @param column 列定义
*/
private void initColumnDefault(CodegenColumnDO column) {
// 处理 Java 相关的字段的默认值
processColumnJava(column);
// 处理 CRUD 相关的字段的默认值
processColumnOperation(column);
// 处理 UI 相关的字段的默认值
processColumnUI(column);
}
private void processColumnJava(CodegenColumnDO column) {
// 处理 javaField 字段
column.setJavaField(toCamelCase(column.getColumnName()));
// 处理 dictType 字段,暂无
// 处理 javaType 字段
String dbType = StrUtil.subBefore(column.getColumnType(), '(', false);
javaTypeMappings.entrySet().stream()
.filter(entry -> entry.getValue().contains(dbType))
.findFirst().ifPresent(entry -> column.setJavaType(entry.getKey()));
if (column.getJavaType() == null) {
throw new IllegalStateException(String.format("column(%s) 的数据库类型(%s) 找不到匹配的 Java 类型",
column.getColumnName(), column.getColumnType()));
}
}
private void processColumnOperation(CodegenColumnDO column) {
// 处理 createOperation 字段
column.setCreateOperation(!CREATE_OPERATION_EXCLUDE_COLUMN.contains(column.getJavaField())
&& !column.getPrimaryKey()); // 对于主键,创建时无需传递
// 处理 updateOperation 字段
column.setUpdateOperation(!UPDATE_OPERATION_EXCLUDE_COLUMN.contains(column.getJavaField())
|| column.getPrimaryKey()); // 对于主键,更新时需要传递
// 处理 listOperation 字段
column.setListOperation(!LIST_OPERATION_EXCLUDE_COLUMN.contains(column.getJavaField())
&& !column.getPrimaryKey()); // 对于主键,列表过滤不需要传递
// 处理 listOperationCondition 字段
columnListOperationConditionMappings.entrySet().stream()
.filter(entry -> StrUtil.endWithIgnoreCase(column.getJavaField(), entry.getKey()))
.findFirst().ifPresent(entry -> column.setListOperationCondition(entry.getValue().getCondition()));
if (column.getListOperationCondition() == null) {
column.setListOperationCondition(CodegenColumnListConditionEnum.EQ.getCondition());
}
// 处理 listOperationResult 字段
column.setListOperationResult(!LIST_OPERATION_RESULT_EXCLUDE_COLUMN.contains(column.getJavaField()));
}
private void processColumnUI(CodegenColumnDO column) {
// 基于后缀进行匹配
columnHtmlTypeMappings.entrySet().stream()
.filter(entry -> StrUtil.endWithIgnoreCase(column.getJavaField(), entry.getKey()))
.findFirst().ifPresent(entry -> column.setHtmlType(entry.getValue().getType()));
// 如果是 Boolean 类型时,设置为 radio 类型.
// 其它类型,因为字段名可以相对保障,所以不进行处理。例如说 date 对应 datetime 类型.
if (Boolean.class.getSimpleName().equals(column.getJavaType())) {
column.setHtmlType(CodegenColumnHtmlTypeEnum.RADIO.getType());
}
// 兜底,设置默认为 input 类型
if (column.getHtmlType() == null) {
column.setHtmlType(CodegenColumnHtmlTypeEnum.INPUT.getType());
}
}
/**
* 获得模块的缩略名
*
* @param fullModuleName 模块的完整名
* @return 缩略名
*/
public String getSimpleModuleName(String fullModuleName) {
return moduleNames.getOrDefault(fullModuleName, fullModuleName);
}
/**
* 获得模块的完整名
*
* @param shortModuleName 模块的缩略名
* @return 完整名
*/
public String getFullModuleName(String shortModuleName) {
return moduleNames.entrySet().stream()
.filter(entry -> entry.getValue().equals(shortModuleName)) // 匹配
.findFirst().map(Map.Entry::getKey) // 返回 key
.orElse(shortModuleName); // 兜底返回 shortModuleName
}
}

View File

@ -0,0 +1,209 @@
package cn.iocoder.yudao.module.tool.service.codegen.inner;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.template.TemplateConfig;
import cn.hutool.extra.template.TemplateEngine;
import cn.hutool.extra.template.engine.velocity.VelocityEngine;
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.tool.framework.codegen.config.CodegenProperties;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.CodegenColumnDO;
import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.CodegenTableDO;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import com.google.common.collect.Maps;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import static cn.hutool.core.map.MapUtil.getStr;
import static cn.hutool.core.text.CharSequenceUtil.*;
/**
* 代码生成的引擎,用于具体生成代码
* 目前基于 {@link org.apache.velocity.app.Velocity} 模板引擎实现
*
* 考虑到 Java 模板引擎的框架非常多Freemarker、Velocity、Thymeleaf 等等,所以我们采用 hutool 封装的 {@link cn.hutool.extra.template.Template} 抽象
*
* @author 芋道源码
*/
@Component
public class CodegenEngine {
/**
* 模板配置
* key模板在 resources 的地址
* value生成的路径
*/
private static final Map<String, String> TEMPLATES = MapUtil.<String, String>builder(new LinkedHashMap<>()) // 有序
// Java Main
.put(javaTemplatePath("controller/vo/baseVO"),
javaFilePath("controller/${table.businessName}/vo/${table.className}BaseVO"))
.put(javaTemplatePath("controller/vo/createReqVO"),
javaFilePath("controller/${table.businessName}/vo/${table.className}CreateReqVO"))
.put(javaTemplatePath("controller/vo/pageReqVO"),
javaFilePath("controller/${table.businessName}/vo/${table.className}PageReqVO"))
.put(javaTemplatePath("controller/vo/respVO"),
javaFilePath("controller/${table.businessName}/vo/${table.className}RespVO"))
.put(javaTemplatePath("controller/vo/updateReqVO"),
javaFilePath("controller/${table.businessName}/vo/${table.className}UpdateReqVO"))
.put(javaTemplatePath("controller/vo/exportReqVO"),
javaFilePath("controller/${table.businessName}/vo/${table.className}ExportReqVO"))
.put(javaTemplatePath("controller/vo/excelVO"),
javaFilePath("controller/${table.businessName}/vo/${table.className}ExcelVO"))
.put(javaTemplatePath("controller/controller"),
javaFilePath("controller/${table.businessName}/${table.className}Controller"))
.put(javaTemplatePath("convert/convert"),
javaFilePath("convert/${table.businessName}/${table.className}Convert"))
.put(javaTemplatePath("dal/do"),
javaFilePath("dal/dataobject/${table.businessName}/${table.className}DO"))
.put(javaTemplatePath("dal/mapper"),
javaFilePath("dal/mysql/${table.businessName}/${table.className}Mapper"))
.put(javaTemplatePath("enums/errorcode"),
javaFilePath("enums/${simpleModuleName_upperFirst}ErrorCodeConstants"))
.put(javaTemplatePath("service/serviceImpl"),
javaFilePath("service/${table.businessName}/impl/${table.className}ServiceImpl"))
.put(javaTemplatePath("service/service"),
javaFilePath("service/${table.businessName}/${table.className}Service"))
// Java Test
.put(javaTemplatePath("test/serviceTest"),
javaFilePath("service/${table.businessName}/${table.className}ServiceTest"))
// Vue
.put(vueTemplatePath("views/index.vue"),
vueFilePath("views/${table.moduleName}/${classNameVar}/index.vue"))
.put(vueTemplatePath("api/api.js"),
vueFilePath("api/${table.moduleName}/${classNameVar}.js"))
// SQL
.put("codegen/sql/sql.vm", "sql/sql.sql")
.build();
@Resource
private CodegenBuilder codegenBuilder;
@Resource
private CodegenProperties codegenProperties;
/**
* 模板引擎,由 hutool 实现
*/
private final TemplateEngine templateEngine;
/**
* 全局通用变量映射
*/
private final Map<String, Object> globalBindingMap = new HashMap<>();
public CodegenEngine() {
// 初始化 TemplateEngine 属性
TemplateConfig config = new TemplateConfig();
config.setResourceMode(TemplateConfig.ResourceMode.CLASSPATH);
this.templateEngine = new VelocityEngine(config);
}
@PostConstruct
private void initGlobalBindingMap() {
// 全局配置
globalBindingMap.put("basePackage", codegenProperties.getBasePackage());
globalBindingMap.put("baseFrameworkPackage", StrUtil.subBefore(codegenProperties.getBasePackage(),
'.', true) + '.' + "framework");
// 全局 Java Bean
globalBindingMap.put("CommonResultClassName", CommonResult.class.getName());
globalBindingMap.put("PageResultClassName", PageResult.class.getName());
// VO 类,独有字段
globalBindingMap.put("PageParamClassName", PageParam.class.getName());
globalBindingMap.put("DictFormatClassName", DictFormat.class.getName());
// DO 类,独有字段
globalBindingMap.put("baseDOFields", CodegenBuilder.BASE_DO_FIELDS);
globalBindingMap.put("BaseDOClassName", BaseDO.class.getName());
globalBindingMap.put("QueryWrapperClassName", QueryWrapperX.class.getName());
globalBindingMap.put("BaseMapperClassName", BaseMapperX.class.getName());
// Util 工具类
globalBindingMap.put("ServiceExceptionUtilClassName", ServiceExceptionUtil.class.getName());
globalBindingMap.put("DateUtilsClassName", DateUtils.class.getName());
globalBindingMap.put("ExcelUtilsClassName", ExcelUtils.class.getName());
globalBindingMap.put("ObjectUtilsClassName", ObjectUtils.class.getName());
globalBindingMap.put("DictConvertClassName", DictConvert.class.getName());
globalBindingMap.put("OperateLogClassName", OperateLog.class.getName());
globalBindingMap.put("OperateTypeEnumClassName", OperateTypeEnum.class.getName());
}
public Map<String, String> execute(CodegenTableDO table, List<CodegenColumnDO> columns) {
// 创建 bindingMap
Map<String, Object> bindingMap = new HashMap<>(globalBindingMap);
bindingMap.put("table", table);
bindingMap.put("columns", columns);
bindingMap.put("primaryColumn", CollectionUtils.findFirst(columns, CodegenColumnDO::getPrimaryKey)); // 主键字段
// moduleName 相关
String simpleModuleName = codegenBuilder.getSimpleModuleName(table.getModuleName());
bindingMap.put("simpleModuleName", simpleModuleName); // 将 system 转成 sys
bindingMap.put("simpleModuleName_upperFirst", upperFirst(simpleModuleName)); // 将 sys 转成 Sys
// className 相关
// 去掉指定前缀 将 TestDictType 转换成 DictType. 因为在 create 等方法后,不需要带上 Test 前缀
String simpleClassName = removePrefix(table.getClassName(), upperFirst(simpleModuleName));
bindingMap.put("simpleClassName", simpleClassName);
bindingMap.put("simpleClassName_underlineCase", toUnderlineCase(simpleClassName)); // 将 DictType 转换成 dict_type
bindingMap.put("classNameVar", lowerFirst(simpleClassName)); // 将 DictType 转换成 dictType用于变量
String simpleClassNameStrikeCase = toSymbolCase(simpleClassName, '-'); // 将 DictType 转换成 dict-type
bindingMap.put("simpleClassName_strikeCase", simpleClassNameStrikeCase);
// permission 前缀
bindingMap.put("permissionPrefix", table.getModuleName() + ":" + simpleClassNameStrikeCase);
// 执行生成
final Map<String, String> result = Maps.newLinkedHashMapWithExpectedSize(TEMPLATES.size()); // 有序
TEMPLATES.forEach((vmPath, filePath) -> {
filePath = formatFilePath(filePath, bindingMap);
String content = templateEngine.getTemplate(vmPath).render(bindingMap);
result.put(filePath, content);
});
return result;
}
private String formatFilePath(String filePath, Map<String, Object> bindingMap) {
filePath = StrUtil.replace(filePath, "${basePackage}",
getStr(bindingMap, "basePackage").replaceAll("\\.", "/"));
filePath = StrUtil.replace(filePath, "${simpleModuleName_upperFirst}",
getStr(bindingMap, "simpleModuleName_upperFirst"));
filePath = StrUtil.replace(filePath, "${classNameVar}",
getStr(bindingMap, "classNameVar"));
// table 包含的字段
CodegenTableDO table = (CodegenTableDO) bindingMap.get("table");
filePath = StrUtil.replace(filePath, "${table.moduleName}", table.getModuleName());
filePath = StrUtil.replace(filePath, "${table.businessName}", table.getBusinessName());
filePath = StrUtil.replace(filePath, "${table.className}", table.getClassName());
return filePath;
}
private static String javaTemplatePath(String path) {
return "codegen/java/" + path + ".vm";
}
private static String javaFilePath(String path) {
return "java/${basePackage}/modules/${table.moduleName}/" + path + ".java";
}
private static String vueTemplatePath(String path) {
return "codegen/vue/" + path + ".vm";
}
private static String vueFilePath(String path) {
return "vue/" + path;
}
}

View File

@ -0,0 +1,117 @@
package cn.iocoder.yudao.module.tool.service.codegen.inner;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.SchemaColumnDO;
import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.SchemaTableDO;
import com.alibaba.druid.DbType;
import com.alibaba.druid.sql.ast.expr.SQLCharExpr;
import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition;
import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLPrimaryKey;
import com.alibaba.druid.sql.ast.statement.SQLTableElement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement;
import com.alibaba.druid.sql.repository.SchemaRepository;
import org.apache.commons.collections4.KeyValue;
import org.apache.commons.collections4.keyvalue.DefaultKeyValue;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import static com.alibaba.druid.sql.SQLUtils.normalize;
/**
* SQL 解析器,将创建表的 SQL解析成 {@link SchemaTableDO} 和 {@link SchemaColumnDO} 对象,
* 后续可以基于它们,生成代码~
*
* @author 芋道源码
*/
public class CodegenSQLParser {
/**
* 解析建表 SQL 语句,返回 {@link SchemaTableDO} 和 {@link SchemaColumnDO} 对象
*
* @param sql 建表 SQL 语句
* @return 解析结果
*/
public static KeyValue<SchemaTableDO, List<SchemaColumnDO>> parse(String sql) {
// 解析 SQL 成 Statement
SQLCreateTableStatement statement = parseCreateSQL(sql);
// 解析 Table 表
SchemaTableDO table = parseTable(statement);
// 解析 Column 字段
List<SchemaColumnDO> columns = parseColumns(statement);
columns.forEach(column -> column.setTableName(table.getTableName()));
// 返回
return new DefaultKeyValue<>(table, columns);
}
/**
* 使用 Druid 工具,建表 SQL 语句
*
* @param sql 建表 SQL 语句
* @return 创建 Statement
*/
private static SQLCreateTableStatement parseCreateSQL(String sql) {
// 解析 SQL
SchemaRepository repository = new SchemaRepository(DbType.mysql);
repository.console(sql);
// 获得该表对应的 MySqlCreateTableStatement 对象
String tableName = CollUtil.getFirst(repository.getDefaultSchema().getObjects()).getName();
return (MySqlCreateTableStatement) repository.findTable(tableName).getStatement();
}
private static SchemaTableDO parseTable(SQLCreateTableStatement statement) {
return SchemaTableDO.builder()
.tableName(statement.getTableSource().getTableName(true))
.tableComment(getCommentText(statement))
.build();
}
private static String getCommentText(SQLCreateTableStatement statement) {
if (statement == null || statement.getComment() == null) {
return "";
}
return ((SQLCharExpr) statement.getComment()).getText();
}
private static List<SchemaColumnDO> parseColumns(SQLCreateTableStatement statement) {
List<SchemaColumnDO> columns = new ArrayList<>();
statement.getTableElementList().forEach(element -> parseColumn(columns, element));
return columns;
}
private static void parseColumn(List<SchemaColumnDO> columns, SQLTableElement element) {
// 处理主键
if (element instanceof SQLPrimaryKey) {
parsePrimaryKey(columns, (SQLPrimaryKey) element);
return;
}
// 处理字段定义
if (element instanceof SQLColumnDefinition) {
parseColumnDefinition(columns, (SQLColumnDefinition) element);
}
}
private static void parsePrimaryKey(List<SchemaColumnDO> columns, SQLPrimaryKey primaryKey) {
String columnName = normalize(primaryKey.getColumns().get(0).toString()); // 暂时不考虑联合主键
// 匹配 columns 主键字段,设置为 primary
columns.stream().filter(column -> column.getColumnName().equals(columnName))
.forEach(column -> column.setPrimaryKey(true));
}
private static void parseColumnDefinition(List<SchemaColumnDO> columns, SQLColumnDefinition definition) {
String text = definition.toString().toUpperCase();
columns.add(SchemaColumnDO.builder()
.columnName(normalize(definition.getColumnName()))
.columnType(definition.getDataType().toString())
.columnComment(Objects.isNull(definition.getComment()) ? ""
: normalize(definition.getComment().toString()))
.nullable(!text.contains(" NOT NULL"))
.primaryKey(false)
.autoIncrement(text.contains("AUTO_INCREMENT"))
.ordinalPosition(columns.size() + 1)
.build());
}
}

View File

@ -0,0 +1,74 @@
package cn.iocoder.yudao.module.tool.service.test;
import java.util.*;
import javax.validation.*;
import cn.iocoder.yudao.module.tool.controller.admin.test.vo.TestDemoCreateReqVO;
import cn.iocoder.yudao.module.tool.controller.admin.test.vo.TestDemoExportReqVO;
import cn.iocoder.yudao.module.tool.controller.admin.test.vo.TestDemoPageReqVO;
import cn.iocoder.yudao.module.tool.controller.admin.test.vo.TestDemoUpdateReqVO;
import cn.iocoder.yudao.module.tool.dal.dataobject.test.TestDemoDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
/**
* 测试示例 Service 接口
*
* @author 芋艿
*/
public interface TestDemoService {
/**
* 创建字典类型
*
* @param createReqVO 创建信息
* @return 编号
*/
Long createTestDemo(@Valid TestDemoCreateReqVO createReqVO);
/**
* 更新字典类型
*
* @param updateReqVO 更新信息
*/
void updateTestDemo(@Valid TestDemoUpdateReqVO updateReqVO);
/**
* 删除字典类型
*
* @param id 编号
*/
void deleteTestDemo(Long id);
/**
* 获得字典类型
*
* @param id 编号
* @return 字典类型
*/
TestDemoDO getTestDemo(Long id);
/**
* 获得字典类型列表
*
* @param ids 编号
* @return 字典类型列表
*/
List<TestDemoDO> getTestDemoList(Collection<Long> ids);
/**
* 获得字典类型分页
*
* @param pageReqVO 分页查询
* @return 字典类型分页
*/
PageResult<TestDemoDO> getTestDemoPage(TestDemoPageReqVO pageReqVO);
/**
* 获得字典类型列表, 用于 Excel 导出
*
* @param exportReqVO 查询条件
* @return 字典类型列表
*/
List<TestDemoDO> getTestDemoList(TestDemoExportReqVO exportReqVO);
}

View File

@ -0,0 +1,86 @@
package cn.iocoder.yudao.module.tool.service.test;
import cn.iocoder.yudao.module.tool.controller.admin.test.vo.TestDemoCreateReqVO;
import cn.iocoder.yudao.module.tool.controller.admin.test.vo.TestDemoExportReqVO;
import cn.iocoder.yudao.module.tool.controller.admin.test.vo.TestDemoPageReqVO;
import cn.iocoder.yudao.module.tool.controller.admin.test.vo.TestDemoUpdateReqVO;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import java.util.*;
import cn.iocoder.yudao.module.tool.dal.dataobject.test.TestDemoDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.tool.convert.test.TestDemoConvert;
import cn.iocoder.yudao.module.tool.dal.mysql.test.TestDemoMapper;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.tool.enums.ErrorCodeConstants.*;
/**
* 测试示例 Service 实现类
*
* @author 芋艿
*/
@Service
@Validated
public class TestDemoServiceImpl implements TestDemoService {
@Resource
private TestDemoMapper testDemoMapper;
@Override
public Long createTestDemo(TestDemoCreateReqVO createReqVO) {
// 插入
TestDemoDO testDemo = TestDemoConvert.INSTANCE.convert(createReqVO);
testDemoMapper.insert(testDemo);
// 返回
return testDemo.getId();
}
@Override
public void updateTestDemo(TestDemoUpdateReqVO updateReqVO) {
// 校验存在
this.validateTestDemoExists(updateReqVO.getId());
// 更新
TestDemoDO updateObj = TestDemoConvert.INSTANCE.convert(updateReqVO);
testDemoMapper.updateById(updateObj);
}
@Override
public void deleteTestDemo(Long id) {
// 校验存在
this.validateTestDemoExists(id);
// 删除
testDemoMapper.deleteById(id);
}
private void validateTestDemoExists(Long id) {
if (testDemoMapper.selectById(id) == null) {
throw exception(TEST_DEMO_NOT_EXISTS);
}
}
@Override
public TestDemoDO getTestDemo(Long id) {
return testDemoMapper.selectById(id);
}
@Override
public List<TestDemoDO> getTestDemoList(Collection<Long> ids) {
return testDemoMapper.selectBatchIds(ids);
}
@Override
public PageResult<TestDemoDO> getTestDemoPage(TestDemoPageReqVO pageReqVO) {
return testDemoMapper.selectPage(pageReqVO);
}
@Override
public List<TestDemoDO> getTestDemoList(TestDemoExportReqVO exportReqVO) {
return testDemoMapper.selectList(exportReqVO);
}
}