同步最新 master 代码

pull/70/head
YunaiV 2023-11-27 18:35:03 +08:00
parent 61cb7d94ac
commit 04b4e090bd
41 changed files with 629 additions and 657 deletions

View File

@ -14,7 +14,7 @@
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
<properties>
<revision>1.8.2-snapshot</revision>
<revision>1.8.3-snapshot</revision>
<flatten-maven-plugin.version>1.5.0</flatten-maven-plugin.version>
<!-- 统一依赖管理 -->
<spring.boot.version>3.1.4</spring.boot.version>
@ -24,6 +24,8 @@
<servlet.versoin>2.5</servlet.versoin>
<springdoc.version>2.2.0</springdoc.version>
<knife4j.version>4.3.0</knife4j.version>
<!-- 消息队列 -->
<rocketmq-spring.version>2.2.3</rocketmq-spring.version>
<!-- DB 相关 -->
<druid.version>1.2.19</druid.version>
<mybatis-plus.version>3.5.3.2</mybatis-plus.version>
@ -133,11 +135,6 @@
<artifactId>yudao-spring-boot-starter-biz-pay</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-biz-weixin</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
@ -148,11 +145,6 @@
<artifactId>yudao-spring-boot-starter-biz-data-permission</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-biz-social</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-biz-error-code</artifactId>
@ -201,6 +193,12 @@
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.iocoder.cloud</groupId>
<artifactId>yudao-spring-boot-starter-websocket</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
@ -298,6 +296,12 @@
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>${rocketmq-spring.version}</version>
</dependency>
<!-- 服务保障相关 -->
<dependency>
<groupId>cn.iocoder.cloud</groupId>
@ -616,12 +620,12 @@
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-mp</artifactId>
<artifactId>wx-java-mp-spring-boot-starter</artifactId>
<version>${weixin-java.version}</version>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java-mp-spring-boot-starter</artifactId>
<artifactId>wx-java-miniapp-spring-boot-starter</artifactId>
<version>${weixin-java.version}</version>
</dependency>

View File

@ -1,34 +0,0 @@
package cn.iocoder.yudao.framework.weixin;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.test.context.SpringBootTest;
import jakarta.annotation.Resource;
@SpringBootTest(classes = WxMpServiceTest.Application.class)
public class WxMpServiceTest {
@Resource
private WxMpService wxMpService;
@Test
public void testGetAccessToken() throws WxErrorException {
String accessToken = wxMpService.getAccessToken();
System.out.println(accessToken);
}
@Test
public void testGet() throws WxErrorException {
String jsapiTicket = wxMpService.getJsapiTicket();
System.out.println(jsapiTicket);
}
@SpringBootApplication
public static class Application {
}
}

View File

@ -40,4 +40,4 @@
</dependency>
</dependencies>
</project>
</project>

View File

@ -1,40 +0,0 @@
package cn.iocoder.yudao.framework.mq.core.bus;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.bus.ServiceMatcher;
import org.springframework.cloud.bus.event.RemoteApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
/**
* Spring Cloud Bus Producer
*
* @author
*/
public abstract class AbstractBusProducer {
@Resource
protected ApplicationEventPublisher applicationEventPublisher;
@Resource
protected ServiceMatcher serviceMatcher;
@Value("${spring.application.name}")
protected String applicationName;
protected void publishEvent(RemoteApplicationEvent event) {
applicationEventPublisher.publishEvent(event);
}
/**
* @return 广
*/
protected String selfDestinationService() {
return applicationName + ":**";
}
protected String getBusId() {
return serviceMatcher.getBusId();
}
}

View File

@ -1,3 +1,3 @@
cn.iocoder.yudao.framework.mq.redis.config.YudaoRedisMQProducerAutoConfiguration
cn.iocoder.yudao.framework.mq.redis.config.YudaoRedisMQConsumerAutoConfiguration
cn.iocoder.yudao.framework.mq.rabbitmq.config.YudaoRabbitMQAutoConfiguration
cn.iocoder.yudao.framework.mq.rabbitmq.config.YudaoRabbitMQAutoConfiguration

View File

@ -56,7 +56,7 @@ public class BpmOALeaveServiceImpl implements BpmOALeaveService {
processInstanceVariables.put("day", day);
String processInstanceId = processInstanceApi.createProcessInstance(userId,
new BpmProcessInstanceCreateReqDTO().setProcessDefinitionKey(PROCESS_KEY)
.setVariables(processInstanceVariables).setBusinessKey(String.valueOf(leave.getId()))).getCheckedData();
.setVariables(processInstanceVariables).setBusinessKey(String.valueOf(leave.getId())));
// 将工作流的编号,更新到 OA 请假单中
leaveMapper.updateById(new BpmOALeaveDO().setId(leave.getId()).setProcessInstanceId(processInstanceId));

View File

@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.bpm.service.task;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*;
import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO;
import jakarta.validation.Valid;
import org.flowable.task.api.Task;
@ -22,7 +23,6 @@ public interface BpmTaskService {
*
* @param userId
* @param pageReqVO
*
* @return
*/
PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageReqVO);
@ -32,7 +32,6 @@ public interface BpmTaskService {
*
* @param userId
* @param pageReqVO
*
* @return
*/
PageResult<BpmTaskDonePageItemRespVO> getDoneTaskPage(Long userId, BpmTaskDonePageReqVO pageReqVO);
@ -41,19 +40,17 @@ public interface BpmTaskService {
* Map
*
* @param processInstanceIds
*
* @return Map
*/
default Map<String, List<Task>> getTaskMapByProcessInstanceIds(List<String> processInstanceIds) {
return CollectionUtils.convertMultiMap(getTasksByProcessInstanceIds(processInstanceIds),
Task::getProcessInstanceId);
Task::getProcessInstanceId);
}
/**
*
*
* @param processInstanceIds
*
* @return
*/
List<Task> getTasksByProcessInstanceIds(List<String> processInstanceIds);
@ -62,11 +59,19 @@ public interface BpmTaskService {
*
*
* @param processInstanceId
*
* @return
*/
List<BpmTaskRespVO> getTaskListByProcessInstanceId(String processInstanceId);
/**
* ID
*
* @param taskIdList ID
* @return
*/
List<BpmTaskExtDO> getTaskListByTaskIdList(List<String> taskIdList);
/**
*
*
@ -127,4 +132,53 @@ public interface BpmTaskService {
*/
void updateTaskExtAssign(Task task);
/**
* 退
*
* @param taskId ID
* @return 退
*/
List<BpmTaskSimpleRespVO> getReturnTaskList(String taskId);
/**
* 退 targetDefinitionKey
*
* @param userId
* @param reqVO 退keyID
*/
void returnTask(Long userId, BpmTaskReturnReqVO reqVO);
/**
*
*
* @param userId
* @param reqVO
*/
void delegateTask(Long userId, BpmTaskDelegateReqVO reqVO);
/**
*
*
* @param userId ID
* @param reqVO ID
*/
void createSignTask(Long userId, BpmTaskAddSignReqVO reqVO);
/**
*
*
* @param userId ID
* @param reqVO ID
*/
void deleteSignTask(Long userId, BpmTaskSubSignReqVO reqVO);
/**
*
*
* @param parentId ID
* @return
*/
List<BpmTaskSubSignRespVO> getChildrenTaskList(String parentId);
}

View File

@ -58,7 +58,6 @@ import java.util.stream.Stream;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.TASK_TARGET_NODE_NOT_EXISTS;
/**
* Service

View File

@ -1,97 +0,0 @@
package cn.iocoder.yudao.module.infra.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.infra.controller.admin.test.vo.*;
import cn.iocoder.yudao.module.infra.convert.test.TestDemoConvert;
import cn.iocoder.yudao.module.infra.dal.dataobject.test.TestDemoDO;
import cn.iocoder.yudao.module.infra.service.test.TestDemoService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
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;
@Tag(name = "管理后台 - 字典类型")
@RestController
@RequestMapping("/infra/test-demo")
@Validated
public class TestDemoController {
@Resource
private TestDemoService testDemoService;
@PostMapping("/create")
@Operation(summary = "创建字典类型")
@PreAuthorize("@ss.hasPermission('infra:test-demo:create')")
public CommonResult<Long> createTestDemo(@Valid @RequestBody TestDemoCreateReqVO createReqVO) {
return success(testDemoService.createTestDemo(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新字典类型")
@PreAuthorize("@ss.hasPermission('infra:test-demo:update')")
public CommonResult<Boolean> updateTestDemo(@Valid @RequestBody TestDemoUpdateReqVO updateReqVO) {
testDemoService.updateTestDemo(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除字典类型")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('infra:test-demo:delete')")
public CommonResult<Boolean> deleteTestDemo(@RequestParam("id") Long id) {
testDemoService.deleteTestDemo(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得字典类型")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('infra:test-demo:query')")
public CommonResult<TestDemoRespVO> getTestDemo(@RequestParam("id") Long id) {
TestDemoDO testDemo = testDemoService.getTestDemo(id);
return success(TestDemoConvert.INSTANCE.convert(testDemo));
}
@GetMapping("/list")
@Operation(summary = "获得字典类型列表")
@Parameter(name = "ids", description = "编号列表", required = true, example = "1024,2048")
@PreAuthorize("@ss.hasPermission('infra:test-demo:query')")
public CommonResult<List<TestDemoRespVO>> getTestDemoList(@RequestParam("ids") Collection<Long> ids) {
List<TestDemoDO> list = testDemoService.getTestDemoList(ids);
return success(TestDemoConvert.INSTANCE.convertList(list));
}
@GetMapping("/page")
@Operation(summary = "获得字典类型分页")
@PreAuthorize("@ss.hasPermission('infra: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")
@Operation(summary = "导出字典类型 Excel")
@PreAuthorize("@ss.hasPermission('infra: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

@ -1,33 +0,0 @@
package cn.iocoder.yudao.module.infra.controller.admin.test.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
/**
* Base VO VO 使
* VO Swagger
*/
@Data
public class TestDemoBaseVO {
@Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "名字不能为空")
private String name;
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "状态不能为空")
private Integer status;
@Schema(description = "类型", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "类型不能为空")
private Integer type;
@Schema(description = "分类", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "分类不能为空")
private Integer category;
@Schema(description = "备注")
private String remark;
}

View File

@ -14,6 +14,7 @@ import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenColumnMapper;
import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenTableMapper;
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum;
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties;
import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenBuilder;
import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenEngine;
@ -25,10 +26,7 @@ import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import java.util.function.BiPredicate;
import java.util.stream.Collectors;
@ -129,6 +127,16 @@ public class CodegenServiceImpl implements CodegenService {
if (codegenTableMapper.selectById(updateReqVO.getTable().getId()) == null) {
throw exception(CODEGEN_TABLE_NOT_EXISTS);
}
// 校验主表字段存在
if (Objects.equals(updateReqVO.getTable().getTemplateType(), CodegenTemplateTypeEnum.SUB.getType())) {
if (codegenTableMapper.selectById(updateReqVO.getTable().getMasterTableId()) == null) {
throw exception(CODEGEN_MASTER_TABLE_NOT_EXISTS, updateReqVO.getTable().getMasterTableId());
}
if (CollUtil.findOne(updateReqVO.getColumns(), // 关联主表的字段不存在
column -> column.getId().equals(updateReqVO.getTable().getSubJoinColumnId())) == null) {
throw exception(CODEGEN_SUB_COLUMN_NOT_EXISTS, updateReqVO.getTable().getSubJoinColumnId());
}
}
// 更新 table 表定义
CodegenTableDO updateTableObj = CodegenConvert.INSTANCE.convert(updateReqVO.getTable());
@ -208,6 +216,11 @@ public class CodegenServiceImpl implements CodegenService {
codegenColumnMapper.deleteListByTableId(tableId);
}
@Override
public List<CodegenTableDO> getCodegenTableList(Long dataSourceConfigId) {
return codegenTableMapper.selectListByDataSourceConfigId(dataSourceConfigId);
}
@Override
public PageResult<CodegenTableDO> getCodegenTablePage(CodegenTablePageReqVO pageReqVO) {
return codegenTableMapper.selectPage(pageReqVO);
@ -235,14 +248,34 @@ public class CodegenServiceImpl implements CodegenService {
throw exception(CODEGEN_COLUMN_NOT_EXISTS);
}
// 如果是主子表,则加载对应的子表信息
List<CodegenTableDO> subTables = null;
List<List<CodegenColumnDO>> subColumnsList = null;
if (CodegenTemplateTypeEnum.isMaster(table.getTemplateType())) {
// 校验子表存在
subTables = codegenTableMapper.selectListByTemplateTypeAndMasterTableId(
CodegenTemplateTypeEnum.SUB.getType(), tableId);
if (CollUtil.isEmpty(subTables)) {
throw exception(CODEGEN_MASTER_GENERATION_FAIL_NO_SUB_TABLE);
}
// 校验子表的关联字段存在
subColumnsList = new ArrayList<>();
for (CodegenTableDO subTable : subTables) {
List<CodegenColumnDO> subColumns = codegenColumnMapper.selectListByTableId(subTable.getId());
if (CollUtil.findOne(subColumns, column -> column.getId().equals(subTable.getSubJoinColumnId())) == null) {
throw exception(CODEGEN_SUB_COLUMN_NOT_EXISTS, subTable.getId());
}
subColumnsList.add(subColumns);
}
}
// 执行生成
return codegenEngine.execute(table, columns);
return codegenEngine.execute(table, columns, subTables, subColumnsList);
}
@Override
public List<DatabaseTableRespVO> getDatabaseTableList(Long dataSourceConfigId, String name, String comment) {
List<TableInfo> tables = databaseTableService.getTableList(dataSourceConfigId, name, comment);
// 移除已经生成的表
// 移除在 Codegen 中,已经存在的
Set<String> existsTables = CollectionUtils.convertSet(
codegenTableMapper.selectListByDataSourceConfigId(dataSourceConfigId), CodegenTableDO::getTableName);

View File

@ -64,7 +64,7 @@ public class CodegenBuilder {
*/
public static final String TENANT_ID_FIELD = "tenantId";
/**
* {@link cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO}
* {@link BaseDO}
*/
public static final Set<String> BASE_DO_FIELDS = new HashSet<>();
/**

View File

@ -1,6 +1,8 @@
package cn.iocoder.yudao.module.infra.service.codegen.inner;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.template.TemplateConfig;
import cn.hutool.extra.template.TemplateEngine;
@ -12,7 +14,9 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
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;
@ -25,7 +29,9 @@ import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum;
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum;
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableTable;
import com.google.common.collect.Maps;
import com.google.common.collect.Table;
@ -33,10 +39,7 @@ import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import static cn.hutool.core.map.MapUtil.getStr;
import static cn.hutool.core.text.CharSequenceUtil.*;
@ -60,20 +63,19 @@ public class CodegenEngine {
*/
private static final Map<String, String> SERVER_TEMPLATES = MapUtil.<String, String>builder(new LinkedHashMap<>()) // 有序
// Java module-biz Main
.put(javaTemplatePath("controller/vo/baseVO"), javaModuleImplVOFilePath("BaseVO"))
.put(javaTemplatePath("controller/vo/createReqVO"), javaModuleImplVOFilePath("CreateReqVO"))
.put(javaTemplatePath("controller/vo/pageReqVO"), javaModuleImplVOFilePath("PageReqVO"))
.put(javaTemplatePath("controller/vo/listReqVO"), javaModuleImplVOFilePath("ListReqVO"))
.put(javaTemplatePath("controller/vo/respVO"), javaModuleImplVOFilePath("RespVO"))
.put(javaTemplatePath("controller/vo/updateReqVO"), javaModuleImplVOFilePath("UpdateReqVO"))
.put(javaTemplatePath("controller/vo/exportReqVO"), javaModuleImplVOFilePath("ExportReqVO"))
.put(javaTemplatePath("controller/vo/excelVO"), javaModuleImplVOFilePath("ExcelVO"))
.put(javaTemplatePath("controller/vo/saveReqVO"), javaModuleImplVOFilePath("SaveReqVO"))
.put(javaTemplatePath("controller/controller"), javaModuleImplControllerFilePath())
.put(javaTemplatePath("convert/convert"),
javaModuleImplMainFilePath("convert/${table.businessName}/${table.className}Convert"))
.put(javaTemplatePath("dal/do"),
javaModuleImplMainFilePath("dal/dataobject/${table.businessName}/${table.className}DO"))
.put(javaTemplatePath("dal/do_sub"), // 特殊:主子表专属逻辑
javaModuleImplMainFilePath("dal/dataobject/${table.businessName}/${subTable.className}DO"))
.put(javaTemplatePath("dal/mapper"),
javaModuleImplMainFilePath("dal/mysql/${table.businessName}/${table.className}Mapper"))
.put(javaTemplatePath("dal/mapper_sub"), // 特殊:主子表专属逻辑
javaModuleImplMainFilePath("dal/mysql/${table.businessName}/${subTable.className}Mapper"))
.put(javaTemplatePath("dal/mapper.xml"), mapperXmlFilePath())
.put(javaTemplatePath("service/serviceImpl"),
javaModuleImplMainFilePath("service/${table.businessName}/${table.className}ServiceImpl"))
@ -99,34 +101,44 @@ public class CodegenEngine {
private static final Table<Integer, String, String> FRONT_TEMPLATES = ImmutableTable.<Integer, String, String>builder()
// Vue2 标准模版
.put(CodegenFrontTypeEnum.VUE2.getType(), vueTemplatePath("views/index.vue"),
vueFilePath("views/${table.moduleName}/${classNameVar}/index.vue"))
vueFilePath("views/${table.moduleName}/${table.businessName}/index.vue"))
.put(CodegenFrontTypeEnum.VUE2.getType(), vueTemplatePath("api/api.js"),
vueFilePath("api/${table.moduleName}/${classNameVar}.js"))
// Vue3 标准模版
.put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/index.vue"),
vue3FilePath("views/${table.moduleName}/${classNameVar}/index.vue"))
vue3FilePath("views/${table.moduleName}/${table.businessName}/index.vue"))
.put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/form.vue"),
vue3FilePath("views/${table.moduleName}/${classNameVar}/${simpleClassName}Form.vue"))
vue3FilePath("views/${table.moduleName}/${table.businessName}/${simpleClassName}Form.vue"))
.put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/components/form_sub_normal.vue"), // 特殊:主子表专属逻辑
vue3FilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}Form.vue"))
.put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/components/form_sub_inner.vue"), // 特殊:主子表专属逻辑
vue3FilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}Form.vue"))
.put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/components/form_sub_erp.vue"), // 特殊:主子表专属逻辑
vue3FilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}Form.vue"))
.put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/components/list_sub_inner.vue"), // 特殊:主子表专属逻辑
vue3FilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}List.vue"))
.put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/components/list_sub_erp.vue"), // 特殊:主子表专属逻辑
vue3FilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}List.vue"))
.put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("api/api.ts"),
vue3FilePath("api/${table.moduleName}/${classNameVar}/index.ts"))
vue3FilePath("api/${table.moduleName}/${table.businessName}/index.ts"))
// Vue3 Schema 模版
.put(CodegenFrontTypeEnum.VUE3_SCHEMA.getType(), vue3SchemaTemplatePath("views/data.ts"),
vue3FilePath("views/${table.moduleName}/${classNameVar}/${classNameVar}.data.ts"))
vue3FilePath("views/${table.moduleName}/${table.businessName}/${classNameVar}.data.ts"))
.put(CodegenFrontTypeEnum.VUE3_SCHEMA.getType(), vue3SchemaTemplatePath("views/index.vue"),
vue3FilePath("views/${table.moduleName}/${classNameVar}/index.vue"))
vue3FilePath("views/${table.moduleName}/${table.businessName}/index.vue"))
.put(CodegenFrontTypeEnum.VUE3_SCHEMA.getType(), vue3SchemaTemplatePath("views/form.vue"),
vue3FilePath("views/${table.moduleName}/${classNameVar}/${simpleClassName}Form.vue"))
vue3FilePath("views/${table.moduleName}/${table.businessName}/${simpleClassName}Form.vue"))
.put(CodegenFrontTypeEnum.VUE3_SCHEMA.getType(), vue3SchemaTemplatePath("api/api.ts"),
vue3FilePath("api/${table.moduleName}/${classNameVar}/index.ts"))
vue3FilePath("api/${table.moduleName}/${table.businessName}/index.ts"))
// Vue3 vben 模版
.put(CodegenFrontTypeEnum.VUE3_VBEN.getType(), vue3VbenTemplatePath("views/data.ts"),
vue3FilePath("views/${table.moduleName}/${classNameVar}/${classNameVar}.data.ts"))
vue3FilePath("views/${table.moduleName}/${table.businessName}/${classNameVar}.data.ts"))
.put(CodegenFrontTypeEnum.VUE3_VBEN.getType(), vue3VbenTemplatePath("views/index.vue"),
vue3FilePath("views/${table.moduleName}/${classNameVar}/index.vue"))
vue3FilePath("views/${table.moduleName}/${table.businessName}/index.vue"))
.put(CodegenFrontTypeEnum.VUE3_VBEN.getType(), vue3VbenTemplatePath("views/form.vue"),
vue3FilePath("views/${table.moduleName}/${classNameVar}/${simpleClassName}Modal.vue"))
vue3FilePath("views/${table.moduleName}/${table.businessName}/${simpleClassName}Modal.vue"))
.put(CodegenFrontTypeEnum.VUE3_VBEN.getType(), vue3VbenTemplatePath("api/api.ts"),
vue3FilePath("api/${table.moduleName}/${classNameVar}/index.ts"))
vue3FilePath("api/${table.moduleName}/${table.businessName}/index.ts"))
.build();
@Resource
@ -149,7 +161,8 @@ public class CodegenEngine {
}
@PostConstruct
private void initGlobalBindingMap() {
@VisibleForTesting
void initGlobalBindingMap() {
// 全局配置
globalBindingMap.put("basePackage", codegenProperties.getBasePackage());
globalBindingMap.put("baseFrameworkPackage", codegenProperties.getBasePackage()
@ -174,9 +187,122 @@ public class CodegenEngine {
globalBindingMap.put("DictConvertClassName", DictConvert.class.getName());
globalBindingMap.put("OperateLogClassName", OperateLog.class.getName());
globalBindingMap.put("OperateTypeEnumClassName", OperateTypeEnum.class.getName());
globalBindingMap.put("BeanUtils", BeanUtils.class.getName());
}
public Map<String, String> execute(CodegenTableDO table, List<CodegenColumnDO> columns) {
/**
*
*
* @param table
* @param columns table
* @param subTables 使
* @param subColumnsList subTables
* @return key value
*/
public Map<String, String> execute(CodegenTableDO table, List<CodegenColumnDO> columns,
List<CodegenTableDO> subTables, List<List<CodegenColumnDO>> subColumnsList) {
// 1.1 初始化 bindMap 上下文
Map<String, Object> bindingMap = initBindingMap(table, columns, subTables, subColumnsList);
// 1.2 获得模版
Map<String, String> templates = getTemplates(table.getFrontType());
// 2. 执行生成
Map<String, String> result = Maps.newLinkedHashMapWithExpectedSize(templates.size()); // 有序
templates.forEach((vmPath, filePath) -> {
// 2.1 特殊:主子表专属逻辑
if (isSubTemplate(vmPath)) {
generateSubCode(table, subTables, result, vmPath, filePath, bindingMap);
return;
// 2.2 特殊:树表专属逻辑
} else if (isPageReqVOTemplate(vmPath)) {
// 减少多余的类生成,例如说 PageVO.java 类
if (CodegenTemplateTypeEnum.isTree(table.getTemplateType())) {
return;
}
} else if (isListReqVOTemplate(vmPath)) {
// 减少多余的类生成,例如说 ListVO.java 类
if (!CodegenTemplateTypeEnum.isTree(table.getTemplateType())) {
return;
}
}
// 2.3 默认生成
generateCode(result, vmPath, filePath, bindingMap);
});
return result;
}
private void generateCode(Map<String, String> result, String vmPath,
String filePath, Map<String, Object> bindingMap) {
filePath = formatFilePath(filePath, bindingMap);
String content = templateEngine.getTemplate(vmPath).render(bindingMap);
// 格式化代码
content = prettyCode(content);
result.put(filePath, content);
}
private void generateSubCode(CodegenTableDO table, List<CodegenTableDO> subTables,
Map<String, String> result, String vmPath,
String filePath, Map<String, Object> bindingMap) {
// 没有子表,所以不生成
if (CollUtil.isEmpty(subTables)) {
return;
}
// 主子表的模式匹配。目的:过滤掉个性化的模版
if (vmPath.contains("_normal")
&& ObjectUtil.notEqual(table.getTemplateType(), CodegenTemplateTypeEnum.MASTER_NORMAL.getType())) {
return;
}
if (vmPath.contains("_erp")
&& ObjectUtil.notEqual(table.getTemplateType(), CodegenTemplateTypeEnum.MASTER_ERP.getType())) {
return;
}
if (vmPath.contains("_inner")
&& ObjectUtil.notEqual(table.getTemplateType(), CodegenTemplateTypeEnum.MASTER_INNER.getType())) {
return;
}
// 逐个生成
for (int i = 0; i < subTables.size(); i++) {
bindingMap.put("subIndex", i);
generateCode(result, vmPath, filePath, bindingMap);
}
bindingMap.remove("subIndex");
}
/**
*
*
* vm
* Vue Pretty
*
* @param content
* @return
*/
private String prettyCode(String content) {
// Vue 界面:去除字段后面多余的 , 逗号,解决前端的 Pretty 代码格式检查的报错
content = content.replaceAll(",\n}", "\n}").replaceAll(",\n }", "\n }");
// Vue 界面:去除多的 dateFormatter只有一个的情况下说明没使用到
if (StrUtil.count(content, "dateFormatter") == 1) {
content = StrUtils.removeLineContains(content, "dateFormatter");
}
// Vue 界面:去除多的 dict 相关,只有一个的情况下,说明没使用到
if (StrUtil.count(content, "getIntDictOptions") == 1) {
content = content.replace("getIntDictOptions, ", "");
}
if (StrUtil.count(content, "getStrDictOptions") == 1) {
content = content.replace("getStrDictOptions, ", "");
}
if (StrUtil.count(content, "getBoolDictOptions") == 1) {
content = content.replace("getBoolDictOptions, ", "");
}
if (StrUtil.count(content, "DICT_TYPE.") == 0) {
content = StrUtils.removeLineContains(content, "DICT_TYPE");
}
return content;
}
private Map<String, Object> initBindingMap(CodegenTableDO table, List<CodegenColumnDO> columns,
List<CodegenTableDO> subTables, List<List<CodegenColumnDO>> subColumnsList) {
// 创建 bindingMap
Map<String, Object> bindingMap = new HashMap<>(globalBindingMap);
bindingMap.put("table", table);
@ -196,17 +322,54 @@ public class CodegenEngine {
// permission 前缀
bindingMap.put("permissionPrefix", table.getModuleName() + ":" + simpleClassNameStrikeCase);
// 执行生成
Map<String, String> templates = getTemplates(table.getFrontType());
Map<String, String> result = Maps.newLinkedHashMapWithExpectedSize(templates.size()); // 有序
templates.forEach((vmPath, filePath) -> {
filePath = formatFilePath(filePath, bindingMap);
String content = templateEngine.getTemplate(vmPath).render(bindingMap);
// 去除字段后面多余的 , 逗号
content = content.replaceAll(",\n}", "\n}").replaceAll(",\n }", "\n }");
result.put(filePath, content);
});
return result;
// 特殊:树表专属逻辑
if (CodegenTemplateTypeEnum.isTree(table.getTemplateType())) {
CodegenColumnDO treeParentColumn = CollUtil.findOne(columns,
column -> Objects.equals(column.getId(), table.getTreeParentColumnId()));
bindingMap.put("treeParentColumn", treeParentColumn);
bindingMap.put("treeParentColumn_javaField_underlineCase", toUnderlineCase(treeParentColumn.getJavaField()));
CodegenColumnDO treeNameColumn = CollUtil.findOne(columns,
column -> Objects.equals(column.getId(), table.getTreeNameColumnId()));
bindingMap.put("treeNameColumn", treeNameColumn);
bindingMap.put("treeNameColumn_javaField_underlineCase", toUnderlineCase(treeNameColumn.getJavaField()));
}
// 特殊:主子表专属逻辑
if (CollUtil.isNotEmpty(subTables)) {
// 创建 bindingMap
bindingMap.put("subTables", subTables);
bindingMap.put("subColumnsList", subColumnsList);
List<CodegenColumnDO> subPrimaryColumns = new ArrayList<>();
List<CodegenColumnDO> subJoinColumns = new ArrayList<>();
List<String> subJoinColumnStrikeCases = new ArrayList<>();
List<String> subSimpleClassNames = new ArrayList<>();
List<String> subClassNameVars = new ArrayList<>();
List<String> simpleClassNameUnderlineCases = new ArrayList<>();
List<String> subSimpleClassNameStrikeCases = new ArrayList<>();
for (int i = 0; i < subTables.size(); i++) {
CodegenTableDO subTable = subTables.get(i);
List<CodegenColumnDO> subColumns = subColumnsList.get(i);
subPrimaryColumns.add(CollectionUtils.findFirst(subColumns, CodegenColumnDO::getPrimaryKey)); //
CodegenColumnDO subColumn = CollectionUtils.findFirst(subColumns, // 关联的字段
column -> Objects.equals(column.getId(), subTable.getSubJoinColumnId()));
subJoinColumns.add(subColumn);
subJoinColumnStrikeCases.add(toSymbolCase(subColumn.getJavaField(), '-')); // 将 DictType 转换成 dict-type
// className 相关
String subSimpleClassName = removePrefix(subTable.getClassName(), upperFirst(subTable.getModuleName()));
subSimpleClassNames.add(subSimpleClassName);
simpleClassNameUnderlineCases.add(toUnderlineCase(subSimpleClassName)); // 将 DictType 转换成 dict_type
subClassNameVars.add(lowerFirst(subSimpleClassName)); // 将 DictType 转换成 dictType用于变量
subSimpleClassNameStrikeCases.add(toSymbolCase(subSimpleClassName, '-')); // 将 DictType 转换成 dict-type
}
bindingMap.put("subPrimaryColumns", subPrimaryColumns);
bindingMap.put("subJoinColumns", subJoinColumns);
bindingMap.put("subJoinColumn_strikeCases", subJoinColumnStrikeCases);
bindingMap.put("subSimpleClassNames", subSimpleClassNames);
bindingMap.put("simpleClassNameUnderlineCases", simpleClassNameUnderlineCases);
bindingMap.put("subClassNameVars", subClassNameVars);
bindingMap.put("subSimpleClassName_strikeCases", subSimpleClassNameStrikeCases);
}
return bindingMap;
}
private Map<String, String> getTemplates(Integer frontType) {
@ -216,6 +379,7 @@ public class CodegenEngine {
return templates;
}
@SuppressWarnings("unchecked")
private String formatFilePath(String filePath, Map<String, Object> bindingMap) {
filePath = StrUtil.replace(filePath, "${basePackage}",
getStr(bindingMap, "basePackage").replaceAll("\\.", "/"));
@ -232,6 +396,16 @@ public class CodegenEngine {
filePath = StrUtil.replace(filePath, "${table.moduleName}", table.getModuleName());
filePath = StrUtil.replace(filePath, "${table.businessName}", table.getBusinessName());
filePath = StrUtil.replace(filePath, "${table.className}", table.getClassName());
// 特殊:主子表专属逻辑
Integer subIndex = (Integer) bindingMap.get("subIndex");
if (subIndex != null) {
CodegenTableDO subTable = ((List<CodegenTableDO>) bindingMap.get("subTables")).get(subIndex);
filePath = StrUtil.replace(filePath, "${subTable.moduleName}", subTable.getModuleName());
filePath = StrUtil.replace(filePath, "${subTable.businessName}", subTable.getBusinessName());
filePath = StrUtil.replace(filePath, "${subTable.className}", subTable.getClassName());
filePath = StrUtil.replace(filePath, "${subSimpleClassName}",
((List<String>) bindingMap.get("subSimpleClassNames")).get(subIndex));
}
return filePath;
}
@ -298,4 +472,17 @@ public class CodegenEngine {
private static String vue3VbenTemplatePath(String path) {
return "codegen/vue3_vben/" + path + ".vm";
}
private static boolean isSubTemplate(String path) {
return path.contains("_sub");
}
private static boolean isPageReqVOTemplate(String path) {
return path.contains("pageReqVO");
}
private static boolean isListReqVOTemplate(String path) {
return path.contains("listReqVO");
}
}

View File

@ -8,9 +8,11 @@ import cn.iocoder.yudao.module.infra.convert.logger.ApiAccessLogConvert;
import cn.iocoder.yudao.module.infra.dal.dataobject.logger.ApiAccessLogDO;
import cn.iocoder.yudao.module.infra.dal.mysql.logger.ApiAccessLogMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.time.LocalDateTime;
import java.util.List;
/**
@ -18,6 +20,7 @@ import java.util.List;
*
* @author
*/
@Slf4j
@Service
@Validated
public class ApiAccessLogServiceImpl implements ApiAccessLogService {
@ -41,4 +44,21 @@ public class ApiAccessLogServiceImpl implements ApiAccessLogService {
return apiAccessLogMapper.selectList(exportReqVO);
}
@Override
@SuppressWarnings("DuplicatedCode")
public Integer cleanAccessLog(Integer exceedDay, Integer deleteLimit) {
int count = 0;
LocalDateTime expireDate = LocalDateTime.now().minusDays(exceedDay);
// 循环删除,直到没有满足条件的数据
for (int i = 0; i < Short.MAX_VALUE; i++) {
int deleteCount = apiAccessLogMapper.deleteByCreateTimeLt(expireDate, deleteLimit);
count += deleteCount;
// 达到删除预期条数,说明到底了
if (deleteCount < deleteLimit) {
break;
}
}
return count;
}
}

View File

@ -9,6 +9,7 @@ import cn.iocoder.yudao.module.infra.dal.dataobject.logger.ApiErrorLogDO;
import cn.iocoder.yudao.module.infra.dal.mysql.logger.ApiErrorLogMapper;
import cn.iocoder.yudao.module.infra.enums.logger.ApiErrorLogProcessStatusEnum;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
@ -24,6 +25,7 @@ import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.API_ERROR_L
*
* @author
*/
@Slf4j
@Service
@Validated
public class ApiErrorLogServiceImpl implements ApiErrorLogService {
@ -62,4 +64,21 @@ public class ApiErrorLogServiceImpl implements ApiErrorLogService {
.processUserId(processUserId).processTime(LocalDateTime.now()).build());
}
@Override
@SuppressWarnings("DuplicatedCode")
public Integer cleanErrorLog(Integer exceedDay, Integer deleteLimit) {
int count = 0;
LocalDateTime expireDate = LocalDateTime.now().minusDays(exceedDay);
// 循环删除,直到没有满足条件的数据
for (int i = 0; i < Short.MAX_VALUE; i++) {
int deleteCount = apiErrorLogMapper.deleteByCreateTimeLt(expireDate, deleteLimit);
count += deleteCount;
// 达到删除预期条数,说明到底了
if (deleteCount < deleteLimit) {
break;
}
}
return count;
}
}

View File

@ -1,75 +0,0 @@
package cn.iocoder.yudao.module.infra.service.test;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.infra.controller.admin.test.vo.TestDemoCreateReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.test.vo.TestDemoExportReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.test.vo.TestDemoPageReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.test.vo.TestDemoUpdateReqVO;
import cn.iocoder.yudao.module.infra.dal.dataobject.test.TestDemoDO;
import jakarta.validation.Valid;
import java.util.Collection;
import java.util.List;
/**
* 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

@ -1,91 +0,0 @@
package cn.iocoder.yudao.module.infra.service.test;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.infra.controller.admin.test.vo.TestDemoCreateReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.test.vo.TestDemoExportReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.test.vo.TestDemoPageReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.test.vo.TestDemoUpdateReqVO;
import cn.iocoder.yudao.module.infra.convert.test.TestDemoConvert;
import cn.iocoder.yudao.module.infra.dal.dataobject.test.TestDemoDO;
import cn.iocoder.yudao.module.infra.dal.mysql.test.TestDemoMapper;
import jakarta.annotation.Resource;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.util.Collection;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.TEST_DEMO_NOT_EXISTS;
/**
* 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
@CacheEvict(value = "test", key = "#updateReqVO.id")
public void updateTestDemo(TestDemoUpdateReqVO updateReqVO) {
// 校验存在
validateTestDemoExists(updateReqVO.getId());
// 更新
TestDemoDO updateObj = TestDemoConvert.INSTANCE.convert(updateReqVO);
testDemoMapper.updateById(updateObj);
}
@Override
@CacheEvict(value = "test", key = "#id")
public void deleteTestDemo(Long id) {
// 校验存在
validateTestDemoExists(id);
// 删除
testDemoMapper.deleteById(id);
}
private void validateTestDemoExists(Long id) {
if (testDemoMapper.selectById(id) == null) {
throw exception(TEST_DEMO_NOT_EXISTS);
}
}
@Override
@Cacheable(cacheNames = "test", key = "#id")
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) {
// testDemoMapper.selectList2();
return testDemoMapper.selectPage(pageReqVO);
}
@Override
public List<TestDemoDO> getTestDemoList(TestDemoExportReqVO exportReqVO) {
return testDemoMapper.selectList(exportReqVO);
}
}

View File

@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.product.enums.ApiConstants;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
/**
@ -18,17 +19,17 @@ public class SecurityConfiguration {
return new AuthorizeRequestsCustomizer() {
@Override
public void customize(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry) {
public void customize(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry registry) {
// Swagger 接口文档
registry.antMatchers("/v3/api-docs/**").permitAll() // 元数据
.antMatchers("/swagger-ui.html").permitAll(); // Swagger UI
registry.requestMatchers("/v3/api-docs/**").permitAll() // 元数据
.requestMatchers("/swagger-ui.html").permitAll(); // Swagger UI
// Spring Boot Actuator 的安全配置
registry.antMatchers("/actuator").anonymous()
.antMatchers("/actuator/**").anonymous();
registry.requestMatchers("/actuator").anonymous()
.requestMatchers("/actuator/**").anonymous();
// Druid 监控
registry.antMatchers("/druid/**").anonymous();
registry.requestMatchers("/druid/**").anonymous();
// RPC 服务的安全配置
registry.antMatchers(ApiConstants.PREFIX + "/**").permitAll();
registry.requestMatchers(ApiConstants.PREFIX + "/**").permitAll();
}
};

View File

@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.promotion.enums.ApiConstants;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
/**
@ -18,17 +19,17 @@ public class SecurityConfiguration {
return new AuthorizeRequestsCustomizer() {
@Override
public void customize(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry) {
public void customize(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry registry) {
// Swagger 接口文档
registry.antMatchers("/v3/api-docs/**").permitAll() // 元数据
.antMatchers("/swagger-ui.html").permitAll(); // Swagger UI
registry.requestMatchers("/v3/api-docs/**").permitAll() // 元数据
.requestMatchers("/swagger-ui.html").permitAll(); // Swagger UI
// Spring Boot Actuator 的安全配置
registry.antMatchers("/actuator").anonymous()
.antMatchers("/actuator/**").anonymous();
registry.requestMatchers("/actuator").anonymous()
.requestMatchers("/actuator/**").anonymous();
// Druid 监控
registry.antMatchers("/druid/**").anonymous();
registry.requestMatchers("/druid/**").anonymous();
// RPC 服务的安全配置
registry.antMatchers(ApiConstants.PREFIX + "/**").permitAll();
registry.requestMatchers(ApiConstants.PREFIX + "/**").permitAll();
}
};

View File

@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.security.config.AuthorizeRequestsCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
/**
@ -17,15 +18,15 @@ public class SecurityConfiguration {
return new AuthorizeRequestsCustomizer() {
@Override
public void customize(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry) {
public void customize(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry registry) {
// Swagger 接口文档
registry.antMatchers("/v3/api-docs/**").permitAll() // 元数据
.antMatchers("/swagger-ui.html").permitAll(); // Swagger UI
registry.requestMatchers("/v3/api-docs/**").permitAll() // 元数据
.requestMatchers("/swagger-ui.html").permitAll(); // Swagger UI
// Spring Boot Actuator 的安全配置
registry.antMatchers("/actuator").anonymous()
.antMatchers("/actuator/**").anonymous();
registry.requestMatchers("/actuator").anonymous()
.requestMatchers("/actuator/**").anonymous();
// Druid 监控
registry.antMatchers("/druid/**").anonymous();
registry.requestMatchers("/druid/**").anonymous();
}
};

View File

@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.member.enums.ApiConstants;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
/**
@ -18,17 +19,17 @@ public class SecurityConfiguration {
return new AuthorizeRequestsCustomizer() {
@Override
public void customize(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry) {
public void customize(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry registry) {
// Swagger 接口文档
registry.antMatchers("/v3/api-docs/**").permitAll() // 元数据
.antMatchers("/swagger-ui.html").permitAll(); // Swagger UI
registry.requestMatchers("/v3/api-docs/**").permitAll() // 元数据
.requestMatchers("/swagger-ui.html").permitAll(); // Swagger UI
// Spring Boot Actuator 的安全配置
registry.antMatchers("/actuator").anonymous()
.antMatchers("/actuator/**").anonymous();
registry.requestMatchers("/actuator").anonymous()
.requestMatchers("/actuator/**").anonymous();
// Druid 监控
registry.antMatchers("/druid/**").anonymous();
registry.requestMatchers("/druid/**").anonymous();
// RPC 服务的安全配置
registry.antMatchers(ApiConstants.PREFIX + "/**").permitAll();
registry.requestMatchers(ApiConstants.PREFIX + "/**").permitAll();
}
};

View File

@ -643,7 +643,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
tradeOrderItemMapper.updateBatch(updateItems);
// 4. 更新支付订单
payOrderApi.updatePayOrderPrice(order.getPayOrderId(), newPayPrice);
payOrderApi.updatePayOrderPrice(order.getPayOrderId(), newPayPrice).getCheckedData();
// 5. 记录订单日志
TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), order.getStatus(),

View File

@ -1,15 +1,19 @@
package cn.iocoder.yudao.module.pay.api.order;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO;
import cn.iocoder.yudao.module.pay.enums.ApiConstants;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿fallbackFactory =
@Tag(name = "RPC 服务 - 支付单")
@ -19,11 +23,20 @@ public interface PayOrderApi {
@PostMapping(PREFIX + "/create")
@Operation(summary = "创建支付单")
Long createOrder(@Valid @RequestBody PayOrderCreateReqDTO reqDTO);
CommonResult<Long> createOrder(@Valid @RequestBody PayOrderCreateReqDTO reqDTO);
@PostMapping(PREFIX + "/get")
@Operation(summary = "获得支付单")
@Parameter(name = "id", description = "支付单编号", example = "1", required = true)
PayOrderRespDTO getOrder(Long id);
CommonResult<PayOrderRespDTO> getOrder(Long id);
@PutMapping(PREFIX + "/update-price")
@Operation(summary = "更新支付订单价格")
@Parameters({
@Parameter(name = "id", description = "支付单编号", example = "1", required = true),
@Parameter(name = "payPrice", description = "支付单价格", example = "100", required = true)
})
CommonResult<Boolean> updatePayOrderPrice(@RequestParam("id") Long id,
@RequestParam("payPrice") Integer payPrice);
}

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.pay.api.refund;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;
import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundRespDTO;
import cn.iocoder.yudao.module.pay.enums.ApiConstants;
@ -19,11 +20,11 @@ public interface PayRefundApi {
@PostMapping(PREFIX + "/create")
@Operation(summary = "创建退款单")
Long createRefund(@Valid @RequestBody PayRefundCreateReqDTO reqDTO);
CommonResult<Long> createRefund(@Valid @RequestBody PayRefundCreateReqDTO reqDTO);
@PostMapping(PREFIX + "/get")
@Operation(summary = "获得退款单")
@Parameter(name = "id", description = "退款单编号", example = "1", required = true)
PayRefundRespDTO getRefund(Long id);
CommonResult<PayRefundRespDTO> getRefund(Long id);
}

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.pay.api.order;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO;
import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert;
@ -10,6 +11,8 @@ import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Service
@RestController // 提供 RESTful API 接口,给 Feign 调用
@Validated
@ -19,14 +22,20 @@ public class PayOrderApiImpl implements PayOrderApi {
private PayOrderService payOrderService;
@Override
public Long createOrder(PayOrderCreateReqDTO reqDTO) {
return payOrderService.createOrder(reqDTO);
public CommonResult<Long> createOrder(PayOrderCreateReqDTO reqDTO) {
return success(payOrderService.createOrder(reqDTO));
}
@Override
public PayOrderRespDTO getOrder(Long id) {
public CommonResult<PayOrderRespDTO> getOrder(Long id) {
PayOrderDO order = payOrderService.getOrder(id);
return PayOrderConvert.INSTANCE.convert2(order);
return success(PayOrderConvert.INSTANCE.convert2(order));
}
@Override
public CommonResult<Boolean> updatePayOrderPrice(Long id, Integer payPrice) {
payOrderService.updatePayOrderPrice(id, payPrice);
return success(true);
}
}

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.pay.api.refund;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;
import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundRespDTO;
import cn.iocoder.yudao.module.pay.convert.refund.PayRefundConvert;
@ -9,6 +10,8 @@ import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Service
@RestController // 提供 RESTful API 接口,给 Feign 调用
@Validated
@ -18,13 +21,13 @@ public class PayRefundApiImpl implements PayRefundApi {
private PayRefundService payRefundService;
@Override
public Long createRefund(PayRefundCreateReqDTO reqDTO) {
return payRefundService.createPayRefund(reqDTO);
public CommonResult<Long> createRefund(PayRefundCreateReqDTO reqDTO) {
return success(payRefundService.createPayRefund(reqDTO));
}
@Override
public PayRefundRespDTO getRefund(Long id) {
return PayRefundConvert.INSTANCE.convert02(payRefundService.getRefund(id));
public CommonResult<PayRefundRespDTO> getRefund(Long id) {
return success(PayRefundConvert.INSTANCE.convert02(payRefundService.getRefund(id)));
}
}

View File

@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.api.social;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserUnbindReqDTO;
import cn.iocoder.yudao.module.system.enums.ApiConstants;
import io.swagger.v3.oas.annotations.Operation;
@ -18,18 +19,9 @@ public interface SocialUserApi {
String PREFIX = ApiConstants.PREFIX + "/social-user";
@GetMapping("PREFIX + /get-authorize-url")
@Operation(summary = "获得社交平台的授权 URL")
@Parameters({
@Parameter(name = "type", description = "社交平台的类型", example = "1", required = true),
@Parameter(name = "redirectUri", description = "重定向 URL", example = "https://www.iocoder.cn",required = true)
})
CommonResult<String> getAuthorizeUrl(@RequestParam("type") Integer type,
@RequestParam("redirectUri") String redirectUri);
@PostMapping("PREFIX + /bind")
@Operation(summary = "绑定社交用户")
CommonResult<Boolean> bindSocialUser(@Valid @RequestBody SocialUserBindReqDTO reqDTO);
CommonResult<String> bindSocialUser(@Valid @RequestBody SocialUserBindReqDTO reqDTO);
@DeleteMapping("PREFIX + /unbind")
@Operation(summary = "取消绑定社交用户")
@ -43,9 +35,9 @@ public interface SocialUserApi {
@Parameter(name = "code", description = "授权码", required = true, example = "tudou"),
@Parameter(name = "state", description = "state", required = true, example = "coke")
})
CommonResult<Long> getBindUserId(@RequestParam("userType") Integer userType,
@RequestParam("type") Integer type,
@RequestParam("code") String code,
@RequestParam("state") String state);
CommonResult<SocialUserRespDTO> getSocialUser(@RequestParam("userType") Integer userType,
@RequestParam("type") Integer type,
@RequestParam("code") String code,
@RequestParam("state") String state);
}

View File

@ -36,7 +36,7 @@ public class SocialUserBindReqDTO {
*/
@InEnum(SocialTypeEnum.class)
@NotNull(message = "社交平台的类型不能为空")
private Integer type;
private Integer socialType;
/**
*
*/

View File

@ -32,12 +32,12 @@ public class SocialUserUnbindReqDTO {
*/
@InEnum(SocialTypeEnum.class)
@NotNull(message = "社交平台的类型不能为空")
private Integer type;
private Integer socialType;
/**
* unionId
*/
@NotEmpty(message = "社交平台的 unionId 不能为空")
private String unionId;
private String openid;
}

View File

@ -1,10 +1,13 @@
package cn.iocoder.yudao.module.system.controller.admin.auth;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.framework.security.config.SecurityProperties;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*;
import cn.iocoder.yudao.module.system.convert.auth.AuthConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
@ -15,7 +18,7 @@ import cn.iocoder.yudao.module.system.service.auth.AdminAuthService;
import cn.iocoder.yudao.module.system.service.permission.MenuService;
import cn.iocoder.yudao.module.system.service.permission.PermissionService;
import cn.iocoder.yudao.module.system.service.permission.RoleService;
import cn.iocoder.yudao.module.system.service.social.SocialUserService;
import cn.iocoder.yudao.module.system.service.social.SocialClientService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
@ -29,13 +32,13 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.obtainAuthorization;
@Tag(name = "管理后台 - 认证")
@RestController
@ -55,7 +58,7 @@ public class AuthController {
@Resource
private PermissionService permissionService;
@Resource
private SocialUserService socialUserService;
private SocialClientService socialClientService;
@Resource
private SecurityProperties securityProperties;
@ -73,7 +76,8 @@ public class AuthController {
@Operation(summary = "登出系统")
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
public CommonResult<Boolean> logout(HttpServletRequest request) {
String token = obtainAuthorization(request, securityProperties.getTokenHeader());
String token = SecurityFrameworkUtils.obtainAuthorization(request,
securityProperties.getTokenHeader(), securityProperties.getTokenParameter());
if (StrUtil.isNotBlank(token)) {
authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType());
}
@ -100,6 +104,9 @@ public class AuthController {
// 1.2 获得角色列表
Set<Long> roleIds = permissionService.getUserRoleIdListByUserId(getLoginUserId());
if (CollUtil.isEmpty(roleIds)) {
return success(AuthConvert.INSTANCE.convert(user, Collections.emptyList(), Collections.emptyList()));
}
List<RoleDO> roles = roleService.getRoleList(roleIds);
roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); // 移除禁用的角色
@ -142,7 +149,8 @@ public class AuthController {
})
public CommonResult<String> socialLogin(@RequestParam("type") Integer type,
@RequestParam("redirectUri") String redirectUri) {
return CommonResult.success(socialUserService.getAuthorizeUrl(type, redirectUri));
return success(socialClientService.getAuthorizeUrl(
type, UserTypeEnum.ADMIN.getValue(), redirectUri));
}
@PostMapping("/social-login")

View File

@ -2,11 +2,15 @@ package cn.iocoder.yudao.module.system.controller.admin.dept;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
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.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.*;
import cn.iocoder.yudao.module.system.convert.dept.PostConvert;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostRespVO;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostSimpleRespVO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO;
import cn.iocoder.yudao.module.system.service.dept.PostService;
import io.swagger.v3.oas.annotations.Operation;
@ -39,16 +43,16 @@ public class PostController {
@PostMapping("/create")
@Operation(summary = "创建岗位")
@PreAuthorize("@ss.hasPermission('system:post:create')")
public CommonResult<Long> createPost(@Valid @RequestBody PostCreateReqVO reqVO) {
Long postId = postService.createPost(reqVO);
public CommonResult<Long> createPost(@Valid @RequestBody PostSaveReqVO createReqVO) {
Long postId = postService.createPost(createReqVO);
return success(postId);
}
@PutMapping("/update")
@Operation(summary = "修改岗位")
@PreAuthorize("@ss.hasPermission('system:post:update')")
public CommonResult<Boolean> updatePost(@Valid @RequestBody PostUpdateReqVO reqVO) {
postService.updatePost(reqVO);
public CommonResult<Boolean> updatePost(@Valid @RequestBody PostSaveReqVO updateReqVO) {
postService.updatePost(updateReqVO);
return success(true);
}
@ -65,35 +69,38 @@ public class PostController {
@Parameter(name = "id", description = "岗位编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('system:post:query')")
public CommonResult<PostRespVO> getPost(@RequestParam("id") Long id) {
return success(PostConvert.INSTANCE.convert(postService.getPost(id)));
PostDO post = postService.getPost(id);
return success(BeanUtils.toBean(post, PostRespVO.class));
}
@GetMapping("/list-all-simple")
@Operation(summary = "获取岗位精简信息列表", description = "只包含被开启的岗位,主要用于前端的下拉选项")
@Operation(summary = "获取岗位列表", description = "只包含被开启的岗位,主要用于前端的下拉选项")
public CommonResult<List<PostSimpleRespVO>> getSimplePostList() {
// 获得岗位列表,只要开启状态的
List<PostDO> list = postService.getPostList(null, Collections.singleton(CommonStatusEnum.ENABLE.getStatus()));
// 排序后,返回给前端
list.sort(Comparator.comparing(PostDO::getSort));
return success(PostConvert.INSTANCE.convertList02(list));
return success(BeanUtils.toBean(list, PostSimpleRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得岗位分页列表")
@PreAuthorize("@ss.hasPermission('system:post:query')")
public CommonResult<PageResult<PostRespVO>> getPostPage(@Validated PostPageReqVO reqVO) {
return success(PostConvert.INSTANCE.convertPage(postService.getPostPage(reqVO)));
public CommonResult<PageResult<PostRespVO>> getPostPage(@Validated PostPageReqVO pageReqVO) {
PageResult<PostDO> pageResult = postService.getPostPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, PostRespVO.class));
}
@GetMapping("/export")
@Operation(summary = "岗位管理")
@PreAuthorize("@ss.hasPermission('system:post:export')")
@OperateLog(type = EXPORT)
public void export(HttpServletResponse response, @Validated PostExportReqVO reqVO) throws IOException {
List<PostDO> posts = postService.getPostList(reqVO);
List<PostExcelVO> data = PostConvert.INSTANCE.convertList03(posts);
public void export(HttpServletResponse response, @Validated PostPageReqVO reqVO) throws IOException {
reqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<PostDO> list = postService.getPostPage(reqVO).getList();
// 输出
ExcelUtils.write(response, "岗位数据.xls", "岗位列表", PostExcelVO.class, data);
ExcelUtils.write(response, "岗位数据.xls", "岗位列表", PostRespVO.class,
BeanUtils.toBean(list, PostRespVO.class));
}
}

View File

@ -1,21 +1,23 @@
package cn.iocoder.yudao.module.system.controller.admin.dept.vo.post;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
/**
* Base VO VO 使
* VO Swagger
*/
@Schema(description = "管理后台 - 岗位创建/修改 Request VO")
@Data
public class PostBaseVO {
public class PostSaveReqVO {
@Schema(description = "岗位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小博主")
@Schema(description = "岗位编号", example = "1024")
private Long id;
@Schema(description = "岗位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小土豆")
@NotBlank(message = "岗位名称不能为空")
@Size(max = 50, message = "岗位名称长度不能超过50个字符")
@Size(max = 50, message = "岗位名称长度不能超过 50 个字符")
private String name;
@Schema(description = "岗位编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao")
@ -27,10 +29,11 @@ public class PostBaseVO {
@NotNull(message = "显示顺序不能为空")
private Integer sort;
@Schema(description = "状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@InEnum(CommonStatusEnum.class)
private Integer status;
@Schema(description = "备注", example = "快乐的备注")
private String remark;
}
}

View File

@ -1,17 +0,0 @@
package cn.iocoder.yudao.module.system.controller.admin.dept.vo.post;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Schema(description = "管理后台 - 岗位更新 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class PostUpdateReqVO extends PostBaseVO {
@Schema(description = "岗位编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "岗位编号不能为空")
private Long id;
}

View File

@ -29,7 +29,7 @@ public class TenantBaseVO {
private Integer status;
@Schema(description = "绑定域名", example = "https://www.iocoder.cn")
private String domain;
private String website;
@Schema(description = "租户套餐编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "租户套餐编号不能为空")

View File

@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO;
import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*;
import cn.iocoder.yudao.module.system.convert.auth.AuthConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
@ -155,14 +156,14 @@ public class AdminAuthServiceImpl implements AdminAuthService {
@Override
public AuthLoginRespVO socialLogin(AuthSocialLoginReqVO reqVO) {
// 使用 code 授权码,进行登录。然后,获得到绑定的用户编号
Long userId = socialUserService.getBindUserId(UserTypeEnum.ADMIN.getValue(), reqVO.getType(),
SocialUserRespDTO socialUser = socialUserService.getSocialUser(UserTypeEnum.ADMIN.getValue(), reqVO.getType(),
reqVO.getCode(), reqVO.getState());
if (userId == null) {
if (socialUser == null) {
throw exception(AUTH_THIRD_LOGIN_NOT_BIND);
}
// 获得用户
AdminUserDO user = userService.getUser(userId);
AdminUserDO user = userService.getUser(socialUser.getUserId());
if (user == null) {
throw exception(USER_NOT_EXISTS);
}

View File

@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.system.service.sms;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.log.SmsLogExportReqVO;
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.log.SmsLogPageReqVO;
@ -55,13 +54,12 @@ public class SmsLogServiceImpl implements SmsLogService {
}
@Override
public void updateSmsSendResult(Long id, Integer sendCode, String sendMsg,
public void updateSmsSendResult(Long id, Boolean success,
String apiSendCode, String apiSendMsg,
String apiRequestId, String apiSerialNo) {
SmsSendStatusEnum sendStatus = CommonResult.isSuccess(sendCode) ?
SmsSendStatusEnum.SUCCESS : SmsSendStatusEnum.FAILURE;
smsLogMapper.updateById(SmsLogDO.builder().id(id).sendStatus(sendStatus.getStatus())
.sendTime(LocalDateTime.now()).sendCode(sendCode).sendMsg(sendMsg)
SmsSendStatusEnum sendStatus = success ? SmsSendStatusEnum.SUCCESS : SmsSendStatusEnum.FAILURE;
smsLogMapper.updateById(SmsLogDO.builder().id(id)
.sendStatus(sendStatus.getStatus()).sendTime(LocalDateTime.now())
.apiSendCode(apiSendCode).apiSendMsg(apiSendMsg)
.apiRequestId(apiRequestId).apiSerialNo(apiSerialNo).build());
}

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.system.service.sms;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.core.KeyValue;
@ -8,7 +9,6 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
import cn.iocoder.yudao.framework.sms.core.client.SmsClient;
import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO;
@ -20,6 +20,7 @@ import cn.iocoder.yudao.module.system.service.member.MemberService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import com.google.common.annotations.VisibleForTesting;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
@ -35,6 +36,7 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
* @author
*/
@Service
@Slf4j
public class SmsSendServiceImpl implements SmsSendService {
@Resource
@ -158,11 +160,17 @@ public class SmsSendServiceImpl implements SmsSendService {
SmsClient smsClient = smsChannelService.getSmsClient(message.getChannelId());
Assert.notNull(smsClient, "短信客户端({}) 不存在", message.getChannelId());
// 发送短信
SmsCommonResult<SmsSendRespDTO> sendResult = smsClient.sendSms(message.getLogId(), message.getMobile(),
message.getApiTemplateId(), message.getTemplateParams());
smsLogService.updateSmsSendResult(message.getLogId(), sendResult.getCode(), sendResult.getMsg(),
sendResult.getApiCode(), sendResult.getApiMsg(), sendResult.getApiRequestId(),
sendResult.getData() != null ? sendResult.getData().getSerialNo() : null);
try {
SmsSendRespDTO sendResponse = smsClient.sendSms(message.getLogId(), message.getMobile(),
message.getApiTemplateId(), message.getTemplateParams());
smsLogService.updateSmsSendResult(message.getLogId(), sendResponse.getSuccess(),
sendResponse.getApiCode(), sendResponse.getApiMsg(),
sendResponse.getApiRequestId(), sendResponse.getSerialNo());
} catch (Throwable ex) {
log.error("[doSendSms][发送短信异常,日志编号({})]", message.getLogId(), ex);
smsLogService.updateSmsSendResult(message.getLogId(), false,
"EXCEPTION", ExceptionUtil.getRootCauseMessage(ex), null, null);
}
}
@Override

View File

@ -8,9 +8,8 @@ import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialCl
import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import com.xingyuv.jushauth.model.AuthUser;
import me.chanjar.weixin.common.bean.WxJsapiSignature;
import jakarta.validation.Valid;
import me.chanjar.weixin.common.bean.WxJsapiSignature;
/**
* Service

View File

@ -31,6 +31,7 @@ import com.xingyuv.jushauth.model.AuthUser;
import com.xingyuv.jushauth.request.AuthRequest;
import com.xingyuv.jushauth.utils.AuthStateUtils;
import com.xingyuv.justauth.AuthRequestFactory;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.WxJsapiSignature;
@ -42,7 +43,6 @@ import me.chanjar.weixin.mp.config.impl.WxMpRedisConfigImpl;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import java.time.Duration;
import java.util.Objects;

View File

@ -1,11 +1,13 @@
package cn.iocoder.yudao.module.system.service.social;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import java.util.List;
@ -16,31 +18,10 @@ import java.util.List;
*/
public interface SocialUserService {
/**
* URL
*
* @param type {@link SocialTypeEnum}
* @param redirectUri URL
* @return URL
*/
String getAuthorizeUrl(Integer type, String redirectUri);
/**
*
* {@link ServiceException}
*
* @param type {@link SocialTypeEnum}
* @param code
* @param state state
* @return
*/
@NotNull
SocialUserDO authSocialUser(Integer type, String code, String state);
/**
*
*
* @param userId
* @param userId
* @param userType
* @return
*/
@ -50,29 +31,49 @@ public interface SocialUserService {
*
*
* @param reqDTO
* @return openid
*/
void bindSocialUser(@Valid SocialUserBindReqDTO reqDTO);
String bindSocialUser(@Valid SocialUserBindReqDTO reqDTO);
/**
*
*
* @param userId
* @param userType
* @param type {@link SocialTypeEnum}
* @param socialType {@link SocialTypeEnum}
* @param openid openid
*/
void unbindSocialUser(Long userId, Integer userType, Integer type, String openid);
void unbindSocialUser(Long userId, Integer userType, Integer socialType, String openid);
/**
*
* MemberUser AdminUser id
*
*
* {@link ServiceException}
*
* @param userType
* @param type
* @param socialType
* @param code
* @param state state
* @return
* @return
*/
Long getBindUserId(Integer userType, Integer type, String code, String state);
SocialUserRespDTO getSocialUser(Integer userType, Integer socialType, String code, String state);
// ==================== 社交用户 CRUD ====================
/**
*
*
* @param id
* @return
*/
SocialUserDO getSocialUser(Long id);
/**
*
*
* @param pageReqVO
* @return
*/
PageResult<SocialUserDO> getSocialUserPage(SocialUserPageReqVO pageReqVO);
}

View File

@ -2,20 +2,19 @@ package cn.iocoder.yudao.module.system.service.social;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
import cn.iocoder.yudao.framework.social.core.YudaoAuthRequestFactory;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
import cn.iocoder.yudao.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserBindDO;
import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO;
import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserBindMapper;
import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserMapper;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import com.xingyuv.jushauth.model.AuthCallback;
import com.xingyuv.jushauth.model.AuthResponse;
import com.xingyuv.jushauth.model.AuthUser;
import com.xingyuv.jushauth.request.AuthRequest;
import com.xingyuv.jushauth.utils.AuthStateUtils;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -27,7 +26,8 @@ import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.AUTH_THIRD_LOGIN_NOT_BIND;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_USER_NOT_FOUND;
/**
* Service
@ -39,51 +39,13 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
@Slf4j
public class SocialUserServiceImpl implements SocialUserService {
@Resource// 由于自定义了 YudaoAuthRequestFactory 无法覆盖默认的 AuthRequestFactory所以只能注入它
private YudaoAuthRequestFactory yudaoAuthRequestFactory;
@Resource
private SocialUserBindMapper socialUserBindMapper;
@Resource
private SocialUserMapper socialUserMapper;
@Override
public String getAuthorizeUrl(Integer type, String redirectUri) {
// 获得对应的 AuthRequest 实现
AuthRequest authRequest = yudaoAuthRequestFactory.get(SocialTypeEnum.valueOfType(type).getSource());
// 生成跳转地址
String authorizeUri = authRequest.authorize(AuthStateUtils.createState());
return HttpUtils.replaceUrlQuery(authorizeUri, "redirect_uri", redirectUri);
}
@Override
public SocialUserDO authSocialUser(Integer type, String code, String state) {
// 优先从 DB 中获取,因为 code 有且可以使用一次。
// 在社交登录时,当未绑定 User 时,需要绑定登录,此时需要 code 使用两次
SocialUserDO socialUser = socialUserMapper.selectByTypeAndCodeAnState(type, code, state);
if (socialUser != null) {
return socialUser;
}
// 请求获取
AuthUser authUser = getAuthUser(type, code, state);
Assert.notNull(authUser, "三方用户不能为空");
// 保存到 DB 中
socialUser = socialUserMapper.selectByTypeAndOpenid(type, authUser.getUuid());
if (socialUser == null) {
socialUser = new SocialUserDO();
}
socialUser.setType(type).setCode(code).setState(state) // 需要保存 code + state 字段,保证后续可查询
.setOpenid(authUser.getUuid()).setToken(authUser.getToken().getAccessToken()).setRawTokenInfo((toJsonString(authUser.getToken())))
.setNickname(authUser.getNickname()).setAvatar(authUser.getAvatar()).setRawUserInfo(toJsonString(authUser.getRawUserInfo()));
if (socialUser.getId() == null) {
socialUserMapper.insert(socialUser);
} else {
socialUserMapper.updateById(socialUser);
}
return socialUser;
}
@Resource
private SocialClientService socialClientService;
@Override
public List<SocialUserDO> getSocialUserList(Long userId, Integer userType) {
@ -98,9 +60,10 @@ public class SocialUserServiceImpl implements SocialUserService {
@Override
@Transactional
public void bindSocialUser(SocialUserBindReqDTO reqDTO) {
public String bindSocialUser(SocialUserBindReqDTO reqDTO) {
// 获得社交用户
SocialUserDO socialUser = authSocialUser(reqDTO.getType(), reqDTO.getCode(), reqDTO.getState());
SocialUserDO socialUser = authSocialUser(reqDTO.getSocialType(), reqDTO.getUserType(),
reqDTO.getCode(), reqDTO.getState());
Assert.notNull(socialUser, "社交用户不能为空");
// 社交用户可能之前绑定过别的用户,需要进行解绑
@ -115,12 +78,13 @@ public class SocialUserServiceImpl implements SocialUserService {
.userId(reqDTO.getUserId()).userType(reqDTO.getUserType())
.socialUserId(socialUser.getId()).socialType(socialUser.getType()).build();
socialUserBindMapper.insert(socialUserBind);
return socialUser.getOpenid();
}
@Override
public void unbindSocialUser(Long userId, Integer userType, Integer type, String openid) {
public void unbindSocialUser(Long userId, Integer userType, Integer socialType, String openid) {
// 获得 openid 对应的 SocialUserDO 社交用户
SocialUserDO socialUser = socialUserMapper.selectByTypeAndOpenid(type, openid);
SocialUserDO socialUser = socialUserMapper.selectByTypeAndOpenid(socialType, openid);
if (socialUser == null) {
throw exception(SOCIAL_USER_NOT_FOUND);
}
@ -130,9 +94,9 @@ public class SocialUserServiceImpl implements SocialUserService {
}
@Override
public Long getBindUserId(Integer userType, Integer type, String code, String state) {
public SocialUserRespDTO getSocialUser(Integer userType, Integer socialType, String code, String state) {
// 获得社交用户
SocialUserDO socialUser = authSocialUser(type, code, state);
SocialUserDO socialUser = authSocialUser(socialType, userType, code, state);
Assert.notNull(socialUser, "社交用户不能为空");
// 如果未绑定的社交用户,则无法自动登录,进行报错
@ -141,27 +105,59 @@ public class SocialUserServiceImpl implements SocialUserService {
if (socialUserBind == null) {
throw exception(AUTH_THIRD_LOGIN_NOT_BIND);
}
return socialUserBind.getUserId();
return new SocialUserRespDTO(socialUser.getOpenid(), socialUserBind.getUserId());
}
// TODO 芋艿:调整下单测
/**
*
*
* {@link ServiceException}
*
* @param type
* @param code
* @param state state
* @return
* @param socialType {@link SocialTypeEnum}
* @param userType
* @param code
* @param state state
* @return
*/
private AuthUser getAuthUser(Integer type, String code, String state) {
AuthRequest authRequest = yudaoAuthRequestFactory.get(SocialTypeEnum.valueOfType(type).getSource());
AuthCallback authCallback = AuthCallback.builder().code(code).state(state).build();
AuthResponse<?> authResponse = authRequest.login(authCallback);
log.info("[getAuthUser][请求社交平台 type({}) request({}) response({})]", type,
toJsonString(authCallback), toJsonString(authResponse));
if (!authResponse.ok()) {
throw exception(SOCIAL_USER_AUTH_FAILURE, authResponse.getMsg());
@NotNull
public SocialUserDO authSocialUser(Integer socialType, Integer userType, String code, String state) {
// 优先从 DB 中获取,因为 code 有且可以使用一次。
// 在社交登录时,当未绑定 User 时,需要绑定登录,此时需要 code 使用两次
SocialUserDO socialUser = socialUserMapper.selectByTypeAndCodeAnState(socialType, code, state);
if (socialUser != null) {
return socialUser;
}
return (AuthUser) authResponse.getData();
// 请求获取
AuthUser authUser = socialClientService.getAuthUser(socialType, userType, code, state);
Assert.notNull(authUser, "三方用户不能为空");
// 保存到 DB 中
socialUser = socialUserMapper.selectByTypeAndOpenid(socialType, authUser.getUuid());
if (socialUser == null) {
socialUser = new SocialUserDO();
}
socialUser.setType(socialType).setCode(code).setState(state) // 需要保存 code + state 字段,保证后续可查询
.setOpenid(authUser.getUuid()).setToken(authUser.getToken().getAccessToken()).setRawTokenInfo((toJsonString(authUser.getToken())))
.setNickname(authUser.getNickname()).setAvatar(authUser.getAvatar()).setRawUserInfo(toJsonString(authUser.getRawUserInfo()));
if (socialUser.getId() == null) {
socialUserMapper.insert(socialUser);
} else {
socialUserMapper.updateById(socialUser);
}
return socialUser;
}
// ==================== 社交用户 CRUD ====================
@Override
public SocialUserDO getSocialUser(Long id) {
return socialUserMapper.selectById(id);
}
@Override
public PageResult<SocialUserDO> getSocialUserPage(SocialUserPageReqVO pageReqVO) {
return socialUserMapper.selectPage(pageReqVO);
}
}