diff --git a/api/build.gradle b/api/build.gradle index 76d6aad..14551f2 100644 --- a/api/build.gradle +++ b/api/build.gradle @@ -32,6 +32,11 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-quartz' implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' + // open api + implementation 'org.springdoc:springdoc-openapi-ui:1.6.8' + implementation 'io.swagger.core.v3:swagger-core:2.2.0' + implementation 'io.swagger.core.v3:swagger-annotations:2.2.0' + implementation 'org.flywaydb:flyway-core' } diff --git a/api/src/main/java/com/databasir/api/OperationLogController.java b/api/src/main/java/com/databasir/api/AuditLogController.java similarity index 80% rename from api/src/main/java/com/databasir/api/OperationLogController.java rename to api/src/main/java/com/databasir/api/AuditLogController.java index 7c0e94f..13a5c8d 100644 --- a/api/src/main/java/com/databasir/api/OperationLogController.java +++ b/api/src/main/java/com/databasir/api/AuditLogController.java @@ -4,6 +4,8 @@ import com.databasir.common.JsonData; import com.databasir.core.domain.log.data.OperationLogPageCondition; import com.databasir.core.domain.log.data.OperationLogPageResponse; import com.databasir.core.domain.log.service.OperationLogService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -17,14 +19,16 @@ import org.springframework.web.bind.annotation.RestController; @RestController @RequiredArgsConstructor @Validated -public class OperationLogController { +@Tag(name = "AuditLogController", description = "操作日志 API") +public class AuditLogController { private final OperationLogService operationLogService; @GetMapping(Routes.OperationLog.LIST) @PreAuthorize("hasAnyAuthority('SYS_OWNER')") + @Operation(summary = "查询操作日志") public JsonData> list(@PageableDefault(sort = "id", direction = Sort.Direction.DESC) - Pageable page, + Pageable page, OperationLogPageCondition condition) { Page pageData = operationLogService.list(page, condition); return JsonData.ok(pageData); diff --git a/api/src/main/java/com/databasir/api/DatabaseTypeController.java b/api/src/main/java/com/databasir/api/DatabaseTypeController.java index c7e576f..d13485a 100644 --- a/api/src/main/java/com/databasir/api/DatabaseTypeController.java +++ b/api/src/main/java/com/databasir/api/DatabaseTypeController.java @@ -5,6 +5,8 @@ import com.databasir.common.JsonData; import com.databasir.core.domain.database.data.*; import com.databasir.core.domain.database.service.DatabaseTypeService; import com.databasir.core.domain.log.annotation.AuditLog; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -23,6 +25,7 @@ import static org.springframework.data.domain.Sort.Direction.DESC; @RequiredArgsConstructor @Validated @RestController +@Tag(name = "DatabaseTypeController", description = "数据库类型 API") public class DatabaseTypeController { private final DatabaseTypeService databaseTypeService; @@ -30,11 +33,13 @@ public class DatabaseTypeController { private final DatabaseTypeValidator databaseTypeValidator; @GetMapping(Routes.DatabaseType.LIST_SIMPLE) + @Operation(summary = "获取所有数据库类型") public JsonData> listSimpleDatabaseTypes() { return JsonData.ok(databaseTypeService.listSimpleDatabaseTypes()); } @GetMapping(Routes.DatabaseType.LIST_PAGE) + @Operation(summary = "分页获取数据库类型") public JsonData> listPage(@PageableDefault(sort = "id", direction = DESC) Pageable page, DatabaseTypePageCondition condition) { @@ -45,6 +50,7 @@ public class DatabaseTypeController { @PostMapping(Routes.DatabaseType.CREATE) @AuditLog(module = AuditLog.Modules.DATABASE_TYPE, name = "创建数据库类型") @PreAuthorize("hasAnyAuthority('SYS_OWNER')") + @Operation(summary = "创建数据库类型") public JsonData create(@RequestBody @Valid DatabaseTypeCreateRequest request) { databaseTypeValidator.isValidUrlPattern(request.getUrlPattern()); Integer id = databaseTypeService.create(request); @@ -54,6 +60,7 @@ public class DatabaseTypeController { @PatchMapping(Routes.DatabaseType.UPDATE) @AuditLog(module = AuditLog.Modules.DATABASE_TYPE, name = "更新数据库类型") @PreAuthorize("hasAnyAuthority('SYS_OWNER')") + @Operation(summary = "更新数据库类型") public JsonData update(@RequestBody @Valid DatabaseTypeUpdateRequest request) { databaseTypeValidator.isValidUrlPattern(request.getUrlPattern()); databaseTypeService.update(request); @@ -63,12 +70,14 @@ public class DatabaseTypeController { @DeleteMapping(Routes.DatabaseType.DELETE_ONE) @AuditLog(module = AuditLog.Modules.DATABASE_TYPE, name = "删除数据库类型") @PreAuthorize("hasAnyAuthority('SYS_OWNER')") + @Operation(summary = "删除数据库类型") public JsonData delete(@PathVariable Integer id) { databaseTypeService.deleteById(id); return JsonData.ok(); } @GetMapping(Routes.DatabaseType.GET_ONE) + @Operation(summary = "获取数据库类型") public JsonData getOne(@PathVariable Integer id) { Optional data = databaseTypeService.selectOne(id); return JsonData.ok(data); @@ -76,6 +85,7 @@ public class DatabaseTypeController { @PostMapping(Routes.DatabaseType.RESOLVE_DRIVER_CLASS_NAME) @PreAuthorize("hasAnyAuthority('SYS_OWNER')") + @Operation(summary = "解析数据库驱动类名") public JsonData resolveDriverClassName(@RequestBody @Valid DriverClassNameResolveRequest request) { String driverClassName = databaseTypeService.resolveDriverClassName(request); return JsonData.ok(driverClassName); @@ -83,6 +93,7 @@ public class DatabaseTypeController { @PostMapping(Routes.DatabaseType.UPLOAD_DRIVER) @PreAuthorize("hasAnyAuthority('SYS_OWNER')") + @Operation(summary = "上传数据库驱动") public JsonData uploadDriver(@RequestPart MultipartFile file) { String driverPath = databaseTypeService.uploadDriver(file); return JsonData.ok(driverPath); diff --git a/api/src/main/java/com/databasir/api/DocumentController.java b/api/src/main/java/com/databasir/api/DocumentController.java index 9398591..8010480 100644 --- a/api/src/main/java/com/databasir/api/DocumentController.java +++ b/api/src/main/java/com/databasir/api/DocumentController.java @@ -7,6 +7,8 @@ import com.databasir.core.domain.document.generator.DocumentFileType; import com.databasir.core.domain.document.service.DocumentService; import com.databasir.core.domain.log.annotation.AuditLog; import com.databasir.core.domain.project.service.ProjectService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -29,6 +31,7 @@ import static org.springframework.data.domain.Sort.Direction.DESC; @RequiredArgsConstructor @Validated @RestController +@Tag(name = "DocumentController", description = "数据库文档 API") public class DocumentController { private final DocumentService documentService; @@ -37,6 +40,7 @@ public class DocumentController { @PostMapping(Routes.Document.SYNC_ONE) @AuditLog(module = AuditLog.Modules.PROJECT, name = "文档同步", involvedProjectId = "#projectId") + @Operation(summary = "同步文档") public JsonData sync(@PathVariable Integer projectId) { Integer userId = LoginUserContext.getLoginUserId(); Optional taskIdOpt = projectService.createSyncTask(projectId, userId, false); @@ -44,6 +48,7 @@ public class DocumentController { } @GetMapping(Routes.Document.GET_ONE) + @Operation(summary = "获取文档") public JsonData getByProjectId(@PathVariable Integer projectId, @RequestParam(required = false) Long version) { return documentService.getOneByProjectId(projectId, version) @@ -52,6 +57,7 @@ public class DocumentController { } @GetMapping(Routes.Document.LIST_VERSIONS) + @Operation(summary = "获取文档版本列表") public JsonData> getVersionsByProjectId(@PathVariable Integer projectId, @PageableDefault(sort = "id", direction = DESC) @@ -60,6 +66,7 @@ public class DocumentController { } @GetMapping(Routes.Document.EXPORT) + @Operation(summary = "导出文档") public ResponseEntity getDocumentFiles(@PathVariable Integer projectId, @RequestParam(required = false) Long version, @@ -76,6 +83,7 @@ public class DocumentController { } @GetMapping(Routes.Document.GET_SIMPLE_ONE) + @Operation(summary = "获取文档(无详情信息)") public JsonData getSimpleByProjectId(@PathVariable Integer projectId, @RequestParam(required = false) Long version, @@ -85,6 +93,7 @@ public class DocumentController { } @PostMapping(Routes.Document.GET_TABLE_DETAIL) + @Operation(summary = "获取表详情") public JsonData> getTableDocument(@PathVariable Integer projectId, @PathVariable Integer documentId, @RequestBody @Valid TableDocumentRequest request) { @@ -92,6 +101,7 @@ public class DocumentController { } @GetMapping(Routes.Document.LIST_TABLES) + @Operation(summary = "获取表列表") public JsonData> listTables(@PathVariable Integer projectId, @RequestParam(required = false) Long version) { return JsonData.ok(documentService.getTableAndColumns(projectId, version)); diff --git a/api/src/main/java/com/databasir/api/DocumentDescriptionController.java b/api/src/main/java/com/databasir/api/DocumentDescriptionController.java index 1f00976..d65d9d4 100644 --- a/api/src/main/java/com/databasir/api/DocumentDescriptionController.java +++ b/api/src/main/java/com/databasir/api/DocumentDescriptionController.java @@ -5,6 +5,8 @@ import com.databasir.common.JsonData; import com.databasir.core.domain.description.data.DocumentDescriptionSaveRequest; import com.databasir.core.domain.description.service.DocumentDescriptionService; import com.databasir.core.domain.log.annotation.AuditLog; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.context.SecurityContextHolder; @@ -19,6 +21,7 @@ import javax.validation.Valid; @RestController @Validated @RequiredArgsConstructor +@Tag(name = "DocumentDescriptionController", description = "文档描述 API") public class DocumentDescriptionController { private final DocumentDescriptionService documentDescriptionService; @@ -28,6 +31,7 @@ public class DocumentDescriptionController { @AuditLog(module = AuditLog.Modules.PROJECT, name = "更新描述", involvedProjectId = "#projectId") + @Operation(summary = "更新描述") public JsonData save(@PathVariable Integer groupId, @PathVariable Integer projectId, @RequestBody @Valid DocumentDescriptionSaveRequest request) { diff --git a/api/src/main/java/com/databasir/api/DocumentDiscussionController.java b/api/src/main/java/com/databasir/api/DocumentDiscussionController.java index be05c6b..1b9fd41 100644 --- a/api/src/main/java/com/databasir/api/DocumentDiscussionController.java +++ b/api/src/main/java/com/databasir/api/DocumentDiscussionController.java @@ -2,11 +2,13 @@ package com.databasir.api; import com.databasir.api.config.security.DatabasirUserDetails; import com.databasir.common.JsonData; -import com.databasir.core.domain.log.annotation.AuditLog; import com.databasir.core.domain.discussion.data.DiscussionCreateRequest; import com.databasir.core.domain.discussion.data.DiscussionListCondition; import com.databasir.core.domain.discussion.data.DiscussionResponse; import com.databasir.core.domain.discussion.service.DocumentDiscussionService; +import com.databasir.core.domain.log.annotation.AuditLog; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -22,11 +24,13 @@ import javax.validation.Valid; @RestController @Validated @RequiredArgsConstructor +@Tag(name = "DocumentDiscussionController", description = "文档讨论 API") public class DocumentDiscussionController { private final DocumentDiscussionService documentDiscussionService; @GetMapping(Routes.DocumentDiscussion.LIST) + @Operation(summary = "获取文档评论列表") public JsonData> listByProjectId(@PathVariable Integer groupId, @PathVariable Integer projectId, @PageableDefault(sort = "id", @@ -42,6 +46,7 @@ public class DocumentDiscussionController { @AuditLog(module = AuditLog.Modules.PROJECT, name = "删除评论", involvedProjectId = "#projectId") + @Operation(summary = "删除评论") public JsonData delete(@PathVariable Integer groupId, @PathVariable Integer projectId, @PathVariable Integer discussionId) { @@ -54,6 +59,7 @@ public class DocumentDiscussionController { @AuditLog(module = AuditLog.Modules.PROJECT, name = "新增评论", involvedProjectId = "#projectId") + @Operation(summary = "新增评论") public JsonData create(@PathVariable Integer groupId, @PathVariable Integer projectId, @RequestBody @Valid DiscussionCreateRequest request) { diff --git a/api/src/main/java/com/databasir/api/DocumentTemplateController.java b/api/src/main/java/com/databasir/api/DocumentTemplateController.java index 393e856..7ca738e 100644 --- a/api/src/main/java/com/databasir/api/DocumentTemplateController.java +++ b/api/src/main/java/com/databasir/api/DocumentTemplateController.java @@ -5,6 +5,8 @@ import com.databasir.core.domain.document.data.DocumentTemplatePropertiesRespons import com.databasir.core.domain.document.data.DocumentTemplatePropertiesUpdateRequest; import com.databasir.core.domain.document.service.DocumentTemplateService; import com.databasir.core.domain.log.annotation.AuditLog; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; @@ -18,11 +20,13 @@ import javax.validation.Valid; @RequiredArgsConstructor @Validated @RestController +@Tag(name = "DocumentTemplateController", description = "文档模板 API") public class DocumentTemplateController { private final DocumentTemplateService documentTemplateService; @GetMapping(Routes.DocumentTemplateProperty.API) + @Operation(summary = "获取模板属性") public JsonData getAllProperties() { return JsonData.ok(documentTemplateService.getAllProperties()); } @@ -30,6 +34,7 @@ public class DocumentTemplateController { @PatchMapping(Routes.DocumentTemplateProperty.API) @PreAuthorize("hasAnyAuthority('SYS_OWNER')") @AuditLog(module = AuditLog.Modules.SETTING, name = "更新模板") + @Operation(summary = "更新模板属性") public JsonData updateByType(@RequestBody @Valid DocumentTemplatePropertiesUpdateRequest request) { documentTemplateService.updateByType(request); return JsonData.ok(); diff --git a/api/src/main/java/com/databasir/api/GroupController.java b/api/src/main/java/com/databasir/api/GroupController.java index d40a50b..6a2a064 100644 --- a/api/src/main/java/com/databasir/api/GroupController.java +++ b/api/src/main/java/com/databasir/api/GroupController.java @@ -5,6 +5,8 @@ import com.databasir.common.JsonData; import com.databasir.core.domain.group.data.*; import com.databasir.core.domain.group.service.GroupService; import com.databasir.core.domain.log.annotation.AuditLog; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -24,6 +26,7 @@ import static org.springframework.data.domain.Sort.Direction.DESC; @RestController @RequiredArgsConstructor @Validated +@Tag(name = "GroupController", description = "分组 API") public class GroupController { private final GroupService groupService; @@ -33,6 +36,7 @@ public class GroupController { @PostMapping(Routes.Group.CREATE) @PreAuthorize("hasAnyAuthority('SYS_OWNER')") @AuditLog(module = AuditLog.Modules.GROUP, name = "创建分组") + @Operation(summary = "创建分组") public JsonData create(@RequestBody @Valid GroupCreateRequest request) { groupService.create(request); return JsonData.ok(); @@ -43,12 +47,14 @@ public class GroupController { @AuditLog(module = AuditLog.Modules.GROUP, name = "更新分组", involvedGroupId = "#request.id") + @Operation(summary = "更新分组") public JsonData update(@RequestBody @Valid GroupUpdateRequest request) { groupService.update(request); return JsonData.ok(); } @GetMapping(Routes.Group.LIST) + @Operation(summary = "分页查询分组") public JsonData> list(@PageableDefault(sort = "id", direction = DESC) Pageable page, GroupPageCondition condition) { @@ -60,17 +66,20 @@ public class GroupController { @AuditLog(module = AuditLog.Modules.GROUP, name = "删除分组", involvedGroupId = "#groupId") + @Operation(summary = "删除分组") public JsonData deleteById(@PathVariable Integer groupId) { groupService.delete(groupId); return JsonData.ok(); } @GetMapping(Routes.Group.GET_ONE) + @Operation(summary = "查询分组") public JsonData getOne(@PathVariable Integer groupId) { return JsonData.ok(groupService.get(groupId)); } @GetMapping(Routes.Group.MEMBERS) + @Operation(summary = "查询分组成员") public JsonData> listGroupMembers(@PathVariable Integer groupId, @PageableDefault(sort = "user_role.create_at", direction = DESC) @@ -85,6 +94,7 @@ public class GroupController { name = "添加组员", involvedGroupId = "#groupId", involvedUserId = "#request.userId") + @Operation(summary = "添加组员") public JsonData addGroupMember(@PathVariable Integer groupId, @RequestBody @Valid GroupMemberCreateRequest request) { userOperationValidator.forbiddenIfUpdateSelfRole(request.getUserId()); @@ -102,6 +112,7 @@ public class GroupController { name = "移除组员", involvedGroupId = "#groupId", involvedUserId = "#userId") + @Operation(summary = "移除组员") public JsonData removeGroupMember(@PathVariable Integer groupId, @PathVariable Integer userId) { userOperationValidator.forbiddenIfUpdateSelfRole(userId); @@ -115,6 +126,7 @@ public class GroupController { name = "更新组员角色", involvedGroupId = "#groupId", involvedUserId = "#userId") + @Operation(summary = "更新组员角色") public JsonData updateGroupMemberRole(@PathVariable Integer groupId, @PathVariable Integer userId, @RequestBody GroupMemberRoleUpdateRequest request) { diff --git a/api/src/main/java/com/databasir/api/IndexController.java b/api/src/main/java/com/databasir/api/IndexController.java index e8f4d9a..8f9a239 100644 --- a/api/src/main/java/com/databasir/api/IndexController.java +++ b/api/src/main/java/com/databasir/api/IndexController.java @@ -1,6 +1,8 @@ package com.databasir.api; import com.databasir.common.JsonData; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @@ -8,10 +10,12 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; @Controller +@Tag(name = "IndexController", description = "测活 API") public class IndexController { @GetMapping("/live") @ResponseBody + @Operation(summary = "测活") public JsonData live() { return JsonData.ok("ok"); } @@ -22,6 +26,7 @@ public class IndexController { } @ResponseStatus(HttpStatus.NOT_FOUND) + @Operation(summary = "404 统一跳转") public String handleResourceNotFoundException() { return "/index.html"; } diff --git a/api/src/main/java/com/databasir/api/LoginAppController.java b/api/src/main/java/com/databasir/api/LoginAppController.java index a4763f5..982550b 100644 --- a/api/src/main/java/com/databasir/api/LoginAppController.java +++ b/api/src/main/java/com/databasir/api/LoginAppController.java @@ -5,12 +5,15 @@ import com.databasir.core.domain.app.OpenAuthAppService; import com.databasir.core.domain.app.data.*; import com.databasir.core.domain.app.handler.OpenAuthHandlers; import com.databasir.core.domain.log.annotation.AuditLog; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.web.PageableDefault; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Controller; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; @@ -22,6 +25,8 @@ import static org.springframework.data.domain.Sort.Direction.DESC; @Controller @RequiredArgsConstructor +@Validated +@Tag(name = "LoginAppController", description = "OAuth2 应用 API") public class LoginAppController { private final OpenAuthAppService openAuthAppService; @@ -33,6 +38,7 @@ public class LoginAppController { */ @GetMapping("/oauth2/apps") @ResponseBody + @Operation(summary = "获取登录应用") public JsonData> listApps() { return JsonData.ok(openAuthAppService.listAll()); } @@ -42,6 +48,7 @@ public class LoginAppController { */ @GetMapping("/oauth2/authorization/{registrationId}") @ResponseBody + @Operation(summary = "OAuth2 授权回调") public JsonData authorization(@PathVariable String registrationId, HttpServletRequest request) { Map parameters = request.getParameterMap(); @@ -52,8 +59,9 @@ public class LoginAppController { @GetMapping(Routes.OAuth2App.LIST_PAGE) @PreAuthorize("hasAnyAuthority('SYS_OWNER')") @ResponseBody + @Operation(summary = "分页查询登录应用") public JsonData> listPage(@PageableDefault(sort = "id", direction = DESC) - Pageable page, + Pageable page, OAuthAppPageCondition condition) { return JsonData.ok(openAuthAppService.listPage(page, condition)); } @@ -61,6 +69,7 @@ public class LoginAppController { @GetMapping(Routes.OAuth2App.GET_ONE) @PreAuthorize("hasAnyAuthority('SYS_OWNER')") @ResponseBody + @Operation(summary = "查询登录应用详情") public JsonData getOne(@PathVariable Integer id) { return JsonData.ok(openAuthAppService.getOne(id)); @@ -70,6 +79,7 @@ public class LoginAppController { @PreAuthorize("hasAnyAuthority('SYS_OWNER')") @ResponseBody @AuditLog(module = AuditLog.Modules.LOGIN_APP, name = "创建登录应用") + @Operation(summary = "创建登录应用") public JsonData create(@RequestBody @Valid OAuthAppCreateRequest request) { Integer id = openAuthAppService.create(request); return JsonData.ok(id); @@ -79,6 +89,7 @@ public class LoginAppController { @PreAuthorize("hasAnyAuthority('SYS_OWNER')") @ResponseBody @AuditLog(module = AuditLog.Modules.LOGIN_APP, name = "更新登录应用") + @Operation(summary = "更新登录应用") public JsonData updateById(@RequestBody @Valid OAuthAppUpdateRequest request) { openAuthAppService.updateById(request); return JsonData.ok(); @@ -88,6 +99,7 @@ public class LoginAppController { @PreAuthorize("hasAnyAuthority('SYS_OWNER')") @ResponseBody @AuditLog(module = AuditLog.Modules.LOGIN_APP, name = "删除登录应用") + @Operation(summary = "删除登录应用") public JsonData deleteById(@PathVariable Integer id) { openAuthAppService.deleteById(id); return JsonData.ok(); diff --git a/api/src/main/java/com/databasir/api/LoginController.java b/api/src/main/java/com/databasir/api/LoginController.java index acd5f98..174695f 100644 --- a/api/src/main/java/com/databasir/api/LoginController.java +++ b/api/src/main/java/com/databasir/api/LoginController.java @@ -10,6 +10,8 @@ import com.databasir.core.domain.login.data.AccessTokenRefreshRequest; import com.databasir.core.domain.login.data.AccessTokenRefreshResponse; import com.databasir.core.domain.login.data.UserLoginResponse; import com.databasir.core.domain.login.service.LoginService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.security.core.context.SecurityContextHolder; @@ -26,18 +28,21 @@ import java.util.Objects; @RequiredArgsConstructor @Validated @Slf4j +@Tag(name = "LoginController", description = "登录 API") public class LoginController { private final LoginService loginService; @GetMapping(Routes.Login.LOGOUT) @AuditLog(module = AuditLog.Modules.USER, name = "注销登录") + @Operation(summary = "注销登录") public JsonData logout() { SecurityContextHolder.clearContext(); return JsonData.ok(); } @PostMapping(Routes.Login.REFRESH_ACCESS_TOKEN) + @Operation(summary = "刷新 Access Token") public JsonData refreshAccessTokens(@RequestBody @Valid AccessTokenRefreshRequest request) { try { @@ -54,6 +59,7 @@ public class LoginController { } @GetMapping(Routes.Login.LOGIN_INFO) + @Operation(summary = "获取登录信息") public JsonData getUserLoginData() { DatabasirUserDetails user = (DatabasirUserDetails) SecurityContextHolder.getContext() .getAuthentication() diff --git a/api/src/main/java/com/databasir/api/MockDataController.java b/api/src/main/java/com/databasir/api/MockDataController.java index ac395fe..fd94328 100644 --- a/api/src/main/java/com/databasir/api/MockDataController.java +++ b/api/src/main/java/com/databasir/api/MockDataController.java @@ -6,6 +6,8 @@ import com.databasir.core.domain.mock.data.ColumnMockRuleSaveRequest; import com.databasir.core.domain.mock.data.MockDataGenerateCondition; import com.databasir.core.domain.mock.data.MockDataRuleListCondition; import com.databasir.core.domain.mock.data.MockDataRuleResponse; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; @@ -17,11 +19,13 @@ import java.util.List; @RestController @RequiredArgsConstructor @Validated +@Tag(name = "MockDataController", description = "MOCK SQL API") public class MockDataController { private final MockDataService mockDataService; @GetMapping(Routes.MockData.GET_SQL_MOCK_DATA) + @Operation(summary = "获取 Mock Insert SQL") public JsonData getMockSql(@PathVariable("groupId") Integer groupId, @PathVariable("projectId") Integer projectId, @Valid MockDataGenerateCondition condition) { @@ -30,6 +34,7 @@ public class MockDataController { } @GetMapping(Routes.MockData.GET_MOCK_RULE) + @Operation(summary = "获取 Mock Rule") public JsonData> getMockRules(@PathVariable("groupId") Integer groupId, @PathVariable("projectId") Integer projectId, @Valid MockDataRuleListCondition condition) { @@ -39,6 +44,7 @@ public class MockDataController { @PostMapping(Routes.MockData.SAVE_MOCK_RULE) @PreAuthorize("hasAnyAuthority('SYS_OWNER', 'GROUP_OWNER?groupId='+#groupId, 'GROUP_MEMBER?groupId='+#groupId)") + @Operation(summary = "保存 Mock Rule") public JsonData saveMockRules(@PathVariable Integer groupId, @PathVariable Integer projectId, @PathVariable Integer tableId, diff --git a/api/src/main/java/com/databasir/api/ProjectController.java b/api/src/main/java/com/databasir/api/ProjectController.java index 2c107a6..9b2f115 100644 --- a/api/src/main/java/com/databasir/api/ProjectController.java +++ b/api/src/main/java/com/databasir/api/ProjectController.java @@ -8,6 +8,8 @@ import com.databasir.core.domain.project.data.*; import com.databasir.core.domain.project.data.task.ProjectSimpleTaskResponse; import com.databasir.core.domain.project.data.task.ProjectTaskListCondition; import com.databasir.core.domain.project.service.ProjectService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -24,6 +26,7 @@ import java.util.List; @RestController @RequiredArgsConstructor @Validated +@Tag(name = "ProjectController", description = "项目 API") public class ProjectController { private final ProjectService projectService; @@ -36,6 +39,7 @@ public class ProjectController { @AuditLog(module = AuditLog.Modules.PROJECT, name = "创建项目", involvedGroupId = "#request.groupId") + @Operation(summary = "创建项目") public JsonData create(@RequestBody @Valid ProjectCreateRequest request) { cronExpressionValidator.isValidCron(request); projectService.create(request); @@ -48,6 +52,7 @@ public class ProjectController { name = "更新项目", involvedGroupId = "#groupId", involvedProjectId = "#request.id") + @Operation(summary = "更新项目") public JsonData update(@RequestBody @Valid ProjectUpdateRequest request, @PathVariable Integer groupId) { cronExpressionValidator.isValidCron(request); @@ -61,6 +66,7 @@ public class ProjectController { name = "删除项目", involvedGroupId = "#groupId", involvedProjectId = "#projectId") + @Operation(summary = "删除项目") public JsonData delete(@PathVariable Integer groupId, @PathVariable Integer projectId) { projectService.delete(projectId); @@ -68,11 +74,13 @@ public class ProjectController { } @GetMapping(Routes.GroupProject.GET_ONE) + @Operation(summary = "获取项目详情") public JsonData getOne(@PathVariable Integer projectId) { return JsonData.ok(projectService.getOne(projectId)); } @GetMapping(Routes.GroupProject.LIST) + @Operation(summary = "获取项目列表") public JsonData> list(@PageableDefault(sort = "id", direction = Sort.Direction.DESC) Pageable page, ProjectListCondition condition) { @@ -84,18 +92,21 @@ public class ProjectController { } @PostMapping(Routes.GroupProject.TEST_CONNECTION) + @Operation(summary = "测试连接") public JsonData testConnection(@RequestBody @Valid ProjectTestConnectionRequest request) { projectService.testConnection(request); return JsonData.ok(); } @PostMapping(Routes.GroupProject.LIST_MANUAL_TASKS) + @Operation(summary = "获取同步任务列表") public JsonData> listManualTasks(@PathVariable Integer projectId, @RequestBody ProjectTaskListCondition condition) { return JsonData.ok(projectService.listManualTasks(projectId, condition)); } @PatchMapping(Routes.GroupProject.CANCEL_MANUAL_TASK) + @Operation(summary = "取消同步任务") public JsonData cancelTask(@PathVariable Integer projectId, @PathVariable Integer taskId) { projectService.cancelTask(projectId, taskId); diff --git a/api/src/main/java/com/databasir/api/SettingController.java b/api/src/main/java/com/databasir/api/SettingController.java index 2ceba48..4cb8b5f 100644 --- a/api/src/main/java/com/databasir/api/SettingController.java +++ b/api/src/main/java/com/databasir/api/SettingController.java @@ -5,6 +5,8 @@ import com.databasir.core.domain.log.annotation.AuditLog; import com.databasir.core.domain.system.data.SystemEmailResponse; import com.databasir.core.domain.system.data.SystemEmailUpdateRequest; import com.databasir.core.domain.system.service.SystemService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; @@ -16,11 +18,13 @@ import javax.validation.Valid; @RequiredArgsConstructor @Validated @PreAuthorize("hasAnyAuthority('SYS_OWNER')") +@Tag(name = "SettingController", description = "系统设置 API") public class SettingController { private final SystemService systemService; @GetMapping(Routes.Setting.GET_SYS_EMAIL) + @Operation(summary = "获取系统邮箱配置") public JsonData getSystemEmailSetting() { return systemService.getEmailSetting() .map(JsonData::ok) @@ -29,6 +33,7 @@ public class SettingController { @DeleteMapping(Routes.Setting.DELETE_SYS_EMAIL) @AuditLog(module = AuditLog.Modules.SETTING, name = "重置系统邮箱") + @Operation(summary = "重置系统邮箱") public JsonData deleteSysEmail() { systemService.deleteSystemEmail(); return JsonData.ok(); @@ -36,6 +41,7 @@ public class SettingController { @PostMapping(Routes.Setting.UPDATE_SYS_EMAIL) @AuditLog(module = AuditLog.Modules.SETTING, name = "更新邮件配置") + @Operation(summary = "更新邮件配置") public JsonData updateSystemEmailSetting(@RequestBody @Valid SystemEmailUpdateRequest request) { systemService.updateEmailSetting(request); return JsonData.ok(); diff --git a/api/src/main/java/com/databasir/api/UserController.java b/api/src/main/java/com/databasir/api/UserController.java index 6473417..9b07912 100644 --- a/api/src/main/java/com/databasir/api/UserController.java +++ b/api/src/main/java/com/databasir/api/UserController.java @@ -8,6 +8,8 @@ import com.databasir.core.domain.DomainErrors; import com.databasir.core.domain.log.annotation.AuditLog; import com.databasir.core.domain.user.data.*; import com.databasir.core.domain.user.service.UserService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -22,6 +24,7 @@ import javax.validation.Valid; @RestController @RequiredArgsConstructor @Validated +@Tag(name = "UserController", description = "用户 API") public class UserController { private final UserService userService; @@ -29,8 +32,9 @@ public class UserController { private final UserOperationValidator userOperationValidator; @GetMapping(Routes.User.LIST) + @Operation(summary = "分页查询用户") public JsonData> list(@PageableDefault(sort = "id", direction = Sort.Direction.DESC) - Pageable pageable, + Pageable pageable, UserPageCondition condition) { return JsonData.ok(userService.list(pageable, condition)); } @@ -38,6 +42,7 @@ public class UserController { @PostMapping(Routes.User.DISABLE) @PreAuthorize("hasAnyAuthority('SYS_OWNER')") @AuditLog(module = AuditLog.Modules.USER, name = "禁用用户", involvedUserId = "#userId") + @Operation(summary = "禁用用户") public JsonData disableUser(@PathVariable Integer userId) { if (userOperationValidator.isMyself(userId)) { throw DomainErrors.CANNOT_UPDATE_SELF_ENABLED_STATUS.exception(); @@ -49,6 +54,7 @@ public class UserController { @PostMapping(Routes.User.ENABLE) @PreAuthorize("hasAnyAuthority('SYS_OWNER')") @AuditLog(module = AuditLog.Modules.USER, name = "启用用户", involvedUserId = "#userId") + @Operation(summary = "启用用户") public JsonData enableUser(@PathVariable Integer userId) { if (userOperationValidator.isMyself(userId)) { throw DomainErrors.CANNOT_UPDATE_SELF_ENABLED_STATUS.exception(); @@ -60,18 +66,21 @@ public class UserController { @PostMapping(Routes.User.CREATE) @PreAuthorize("hasAnyAuthority('SYS_OWNER')") @AuditLog(module = AuditLog.Modules.USER, name = "创建用户") + @Operation(summary = "创建用户") public JsonData create(@RequestBody @Valid UserCreateRequest request) { userService.create(request, UserSource.MANUAL); return JsonData.ok(); } @GetMapping(Routes.User.GET_ONE) + @Operation(summary = "根据 ID 查询用户") public JsonData getOne(@PathVariable Integer userId) { return JsonData.ok(userService.get(userId)); } @DeleteMapping(Routes.User.DELETE_ONE) @PreAuthorize("hasAnyAuthority('SYS_OWNER')") + @Operation(summary = "根据 ID 删除用户") public JsonData deleteOne(@PathVariable Integer userId) { if (userOperationValidator.isMyself(userId)) { throw DomainErrors.CANNOT_DELETE_SELF.exception(); @@ -83,6 +92,7 @@ public class UserController { @PostMapping(Routes.User.RENEW_PASSWORD) @PreAuthorize("hasAnyAuthority('SYS_OWNER')") @AuditLog(module = AuditLog.Modules.USER, name = "重置用户密码", involvedUserId = "#userId") + @Operation(summary = "重置用户密码") public JsonData renewPassword(@PathVariable Integer userId) { Integer operatorUserId = LoginUserContext.getLoginUserId(); userService.renewPassword(operatorUserId, userId); @@ -92,6 +102,7 @@ public class UserController { @PostMapping(Routes.User.ADD_OR_REMOVE_SYS_OWNER) @PreAuthorize("hasAnyAuthority('SYS_OWNER')") @AuditLog(module = AuditLog.Modules.USER, name = "添加系统管理员", involvedUserId = "#userId") + @Operation(summary = "添加系统管理员") public JsonData addSysOwner(@PathVariable Integer userId) { userOperationValidator.forbiddenIfUpdateSelfRole(userId); userService.addSysOwnerTo(userId); @@ -101,6 +112,7 @@ public class UserController { @DeleteMapping(Routes.User.ADD_OR_REMOVE_SYS_OWNER) @PreAuthorize("hasAnyAuthority('SYS_OWNER')") @AuditLog(module = AuditLog.Modules.USER, name = "移除系统管理员", involvedUserId = "#userId") + @Operation(summary = "移除系统管理员") public JsonData removeSysOwner(@PathVariable Integer userId) { userOperationValidator.forbiddenIfUpdateSelfRole(userId); userService.removeSysOwnerFrom(userId); @@ -109,6 +121,7 @@ public class UserController { @PostMapping(Routes.User.UPDATE_PASSWORD) @AuditLog(module = AuditLog.Modules.USER, name = "更新密码", involvedUserId = "#userId") + @Operation(summary = "更新密码") public JsonData updatePassword(@PathVariable Integer userId, @RequestBody @Valid UserPasswordUpdateRequest request) { if (userOperationValidator.isMyself(userId)) { @@ -121,6 +134,7 @@ public class UserController { @PostMapping(Routes.User.UPDATE_NICKNAME) @AuditLog(module = AuditLog.Modules.USER, name = "更新昵称", involvedUserId = "#userId") + @Operation(summary = "更新昵称") public JsonData updateNickname(@PathVariable Integer userId, @RequestBody @Valid UserNicknameUpdateRequest request) { if (userOperationValidator.isMyself(userId)) { diff --git a/api/src/main/java/com/databasir/api/UserProjectController.java b/api/src/main/java/com/databasir/api/UserProjectController.java index 8981667..a517917 100644 --- a/api/src/main/java/com/databasir/api/UserProjectController.java +++ b/api/src/main/java/com/databasir/api/UserProjectController.java @@ -5,6 +5,8 @@ import com.databasir.common.JsonData; import com.databasir.core.domain.user.data.FavoriteProjectPageCondition; import com.databasir.core.domain.user.data.FavoriteProjectPageResponse; import com.databasir.core.domain.user.service.UserProjectService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -18,11 +20,13 @@ import static org.springframework.data.domain.Sort.Direction.DESC; @RestController @RequiredArgsConstructor @Validated +@Tag(name = "UserProjectController", description = "用户关注项目 API") public class UserProjectController { private final UserProjectService userProjectService; @GetMapping(Routes.UserProject.LIST) + @Operation(summary = "获取用户关注项目列表") public JsonData> listFavorites( @PageableDefault(sort = "id", direction = DESC) Pageable pageable, FavoriteProjectPageCondition condition) { @@ -34,6 +38,7 @@ public class UserProjectController { } @PostMapping(Routes.UserProject.ADD) + @Operation(summary = "添加用户关注项目") public JsonData addFavorite(@PathVariable Integer projectId) { DatabasirUserDetails user = (DatabasirUserDetails) SecurityContextHolder.getContext() .getAuthentication() @@ -44,12 +49,13 @@ public class UserProjectController { } @DeleteMapping(Routes.UserProject.REMOVE) + @Operation(summary = "删除用户关注项目") public JsonData removeFavorite(@PathVariable Integer projectId) { DatabasirUserDetails user = (DatabasirUserDetails) SecurityContextHolder.getContext() .getAuthentication() .getPrincipal(); Integer userId = user.getUserPojo().getId(); - userProjectService.removeFavorites(projectId, userId); + userProjectService.removeFavorites(projectId, userId); return JsonData.ok(); } } diff --git a/api/src/main/resources/application-local.properties b/api/src/main/resources/application-local.properties index 7d146b2..5ef23d5 100644 --- a/api/src/main/resources/application-local.properties +++ b/api/src/main/resources/application-local.properties @@ -1,6 +1,7 @@ server.port=8080 logging.level.org.jooq=INFO spring.jooq.sql-dialect=mysql +springdoc.swagger-ui.path=/open-api.html # flyway spring.flyway.enabled=true spring.flyway.baseline-on-migrate=true diff --git a/api/src/main/resources/application.properties b/api/src/main/resources/application.properties index 123072e..17e82cb 100644 --- a/api/src/main/resources/application.properties +++ b/api/src/main/resources/application.properties @@ -14,4 +14,6 @@ spring.flyway.baseline-on-migrate=true spring.flyway.locations=classpath:db/migration # driver directory databasir.db.driver-directory=drivers -databasir.jwt.secret=${DATABASIR_JWT_SECRET:${random.uuid}} \ No newline at end of file +databasir.jwt.secret=${DATABASIR_JWT_SECRET:${random.uuid}} +# api doc +springdoc.api-docs.enabled=false \ No newline at end of file diff --git a/build.gradle b/build.gradle index 78f7c55..5ee1b14 100644 --- a/build.gradle +++ b/build.gradle @@ -39,6 +39,7 @@ subprojects { freemarkerVersion = '2.3.31' retrofitVersion = '2.9.0' commonsIoVersion = '2.11.0' + springDocVersion = '1.6.8' } dependencies { diff --git a/databasir-frontend b/databasir-frontend index db483af..2de726a 160000 --- a/databasir-frontend +++ b/databasir-frontend @@ -1 +1 @@ -Subproject commit db483af6ed4b2b1571f756403b52158b123e6023 +Subproject commit 2de726a650c5ea6641a175090220ec19bafe8296