去掉db、api模块,后续只专注于维护wiki知识库模块,最后支持的代码存放于 full-latest 分支

This commit is contained in:
sswiki
2024-12-02 22:39:06 +08:00
parent cd0651db1b
commit 9bcd72d2e6
573 changed files with 53 additions and 198717 deletions

19
pom.xml
View File

@@ -8,7 +8,7 @@
<packaging>pom</packaging>
<name>zyplayer-doc</name>
<description>定位为所有文档的管理项目swagger文档、数据库文档、WIKI文档等</description>
<description>zyplayer-doc文档管理系统</description>
<properties>
<skipTests>true</skipTests>
@@ -24,8 +24,6 @@
<modules>
<module>zyplayer-doc-manage</module>
<module>zyplayer-doc-db</module>
<module>zyplayer-doc-api</module>
<module>zyplayer-doc-wiki</module>
<module>zyplayer-doc-core</module>
<module>zyplayer-doc-data</module>
@@ -100,6 +98,11 @@
<artifactId>curator-recipes</artifactId>
<version>2.12.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
@@ -181,16 +184,6 @@
<artifactId>zyplayer-doc-data</artifactId>
<version>${zyplayer.doc.version}</version>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>zyplayer-doc-db</artifactId>
<version>${zyplayer.doc.version}</version>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>zyplayer-doc-api</artifactId>
<version>${zyplayer.doc.version}</version>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>zyplayer-doc-wiki</artifactId>

View File

@@ -1,96 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>zyplayer-doc-api</artifactId>
<packaging>jar</packaging>
<name>zyplayer-doc-api</name>
<description>zyplayer-doc-api是一款接口文档管理系统</description>
<url>https://gitee.com/zyplayer/zyplayer-doc/zyplayer-doc</url>
<developers>
<developer>
<id>zyplayer</id>
<name>暮光:城中城</name>
<email>806783409@qq.com</email>
<roles>
<role>Java Development Engineer</role>
</roles>
<timezone>2018-05-22 16:06:06</timezone>
</developer>
</developers>
<parent>
<groupId>org.dromara</groupId>
<artifactId>zyplayer-doc</artifactId>
<version>1.0.0</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<!-- 打包跳过单元测试 -->
<skipTests>true</skipTests>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>zyplayer-doc-core</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>zyplayer-doc-data</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
</license>
</licenses>
<scm>
<connection>scm:git@git.oschina.net:zyplayer/zyplayer-doc.git</connection>
<developerConnection>scm:git@git.oschina.net:zyplayer/zyplayer-doc.git</developerConnection>
<url>git@git.oschina.net:zyplayer/zyplayer-doc.git</url>
</scm>
<distributionManagement>
<snapshotRepository>
<id>snapshots</id>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</snapshotRepository>
<repository>
<id>snapshots</id>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
<build>
<resources>
<resource>
<directory>src/main/resources/dist</directory>
<targetPath>META-INF/resources/</targetPath>
</resource>
</resources>
</build>
</project>

View File

@@ -1,157 +0,0 @@
package org.dromara.zyplayer.api.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.dromara.zyplayer.api.controller.vo.ApiCustomParamsVo;
import org.dromara.zyplayer.core.annotation.AuthMan;
import org.dromara.zyplayer.core.json.DocResponseJson;
import org.dromara.zyplayer.core.json.ResponseJson;
import org.dromara.zyplayer.data.repository.manage.entity.ApiCustomNode;
import org.dromara.zyplayer.data.repository.manage.entity.ApiCustomParams;
import org.dromara.zyplayer.data.service.common.ApiDocAuthJudgeService;
import org.dromara.zyplayer.data.service.manage.ApiCustomNodeService;
import org.dromara.zyplayer.data.service.manage.ApiCustomParamsService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
/**
* <p>
* 自建接口文档分组 前端控制器
* </p>
*
* @author 暮光:城中城
* @since 2021-12-22
*/
@AuthMan
@Controller
@RequestMapping("/api-custom-node")
public class ApiCustomNodeController {
@Resource
ApiCustomNodeService apiCustomNodeService;
@Resource
ApiCustomParamsService apiCustomParamsService;
@Resource
ApiDocAuthJudgeService apiDocAuthJudgeService;
/**
* 1. 新增文件夹
* 2. 修改文件夹名称说明等
* 3. 修改父文件夹
*
* @return 文档内容
* @author 暮光:城中城
* @since 2021年12月22日
*/
@ResponseBody
@PostMapping(value = "/add")
public ResponseJson<Object> add(ApiCustomNode apiCustomNode, ApiCustomParams apiCustomParams) {
apiCustomNodeService.addNode(apiCustomNode, apiCustomParams);
return DocResponseJson.ok(apiCustomNode);
}
/**
* 修改文件夹
*
* @return 文档内容
* @author 暮光:城中城
* @since 2021年12月22日
*/
@ResponseBody
@PostMapping(value = "/update")
public ResponseJson<Object> update(ApiCustomNode apiCustomNode) {
// 参数未传不处理
if (apiCustomNode.getId() == null) {
return DocResponseJson.ok();
}
if (StringUtils.isBlank(apiCustomNode.getNodeName()) && StringUtils.isBlank(apiCustomNode.getNodeDesc())) {
return DocResponseJson.ok();
}
ApiCustomNode apiCustomFolderSel = apiCustomNodeService.getById(apiCustomNode.getId());
apiDocAuthJudgeService.judgeDevelopAndThrow(apiCustomFolderSel.getDocId());
// 执行修改
ApiCustomNode nodeUp = new ApiCustomNode();
nodeUp.setId(apiCustomNode.getId());
nodeUp.setNodeName(apiCustomNode.getNodeName());
nodeUp.setNodeDesc(apiCustomNode.getNodeDesc());
apiCustomNodeService.updateById(nodeUp);
return DocResponseJson.ok();
}
/**
* 删除文件夹
*
* @return 文档内容
* @author 暮光:城中城
* @since 2021年12月22日
*/
@ResponseBody
@PostMapping(value = "/delete")
public ResponseJson<Object> delete(Long id) {
ApiCustomNode apiCustomFolderSel = apiCustomNodeService.getById(id);
apiDocAuthJudgeService.judgeDevelopAndThrow(apiCustomFolderSel.getDocId());
apiCustomNodeService.deleteNode(id);
return DocResponseJson.ok();
}
/**
* 删除文件夹
*
* @return 文档内容
* @author 暮光:城中城
* @since 2021年12月22日
*/
@ResponseBody
@PostMapping(value = "/changeParent")
public ResponseJson<Object> changeParent(Long id, Long parentId, Integer targetType, Integer targetSeq) {
ApiCustomNode apiCustomFolderSel = apiCustomNodeService.getById(id);
apiDocAuthJudgeService.judgeDevelopAndThrow(apiCustomFolderSel.getDocId());
apiCustomNodeService.changeParent(id, parentId, targetType, targetSeq);
return DocResponseJson.ok();
}
/**
* 自定义接口详情
*
* @return 文档内容
* @author 暮光:城中城
* @since 2022年01月05日
*/
@ResponseBody
@PostMapping(value = "/detail")
public ResponseJson<Object> detail(Long id) {
ApiCustomNode apiCustomNode = apiCustomNodeService.getById(id);
if (apiCustomNode == null) {
return DocResponseJson.warn("接口不存在");
}
apiDocAuthJudgeService.judgeDevelopAndThrow(apiCustomNode.getDocId());
QueryWrapper<ApiCustomParams> paramsWrapper = new QueryWrapper<>();
paramsWrapper.eq("yn", 1);
paramsWrapper.eq("node_id", id);
ApiCustomParams apiCustomParams = apiCustomParamsService.getOne(paramsWrapper);
// 组装结果对象
ApiCustomParamsVo customParamsVo = new ApiCustomParamsVo();
customParamsVo.setId(apiCustomNode.getId());
customParamsVo.setDocId(apiCustomNode.getDocId());
customParamsVo.setParentId(apiCustomNode.getParentId());
customParamsVo.setNodeType(apiCustomNode.getNodeType());
customParamsVo.setNodeName(apiCustomNode.getNodeName());
customParamsVo.setNodeDesc(apiCustomNode.getNodeDesc());
customParamsVo.setSeqNo(apiCustomNode.getSeqNo());
customParamsVo.setNodeId(apiCustomNode.getId());
if (apiCustomParams != null) {
customParamsVo.setMethod(apiCustomParams.getMethod());
customParamsVo.setApiUrl(apiCustomParams.getApiUrl());
customParamsVo.setFormData(apiCustomParams.getFormData());
customParamsVo.setBodyData(apiCustomParams.getBodyData());
customParamsVo.setHeaderData(apiCustomParams.getHeaderData());
customParamsVo.setCookieData(apiCustomParams.getCookieData());
}
return DocResponseJson.ok(customParamsVo);
}
}

View File

@@ -1,132 +0,0 @@
package org.dromara.zyplayer.api.controller;
import org.dromara.zyplayer.api.controller.vo.DocUserAuthVo;
import org.dromara.zyplayer.core.annotation.AuthMan;
import org.dromara.zyplayer.core.json.DocResponseJson;
import org.dromara.zyplayer.core.json.ResponseJson;
import org.dromara.zyplayer.data.config.security.DocUserDetails;
import org.dromara.zyplayer.data.config.security.DocUserUtil;
import org.dromara.zyplayer.data.repository.manage.entity.AuthInfo;
import org.dromara.zyplayer.data.repository.manage.entity.UserAuth;
import org.dromara.zyplayer.data.repository.manage.entity.UserInfo;
import org.dromara.zyplayer.data.repository.support.consts.ApiAuthType;
import org.dromara.zyplayer.data.repository.support.consts.DocSysModuleType;
import org.dromara.zyplayer.data.repository.support.consts.DocSysType;
import org.dromara.zyplayer.data.service.common.ApiDocAuthJudgeService;
import org.dromara.zyplayer.data.service.manage.ApiDocService;
import org.dromara.zyplayer.data.service.manage.AuthInfoService;
import org.dromara.zyplayer.data.service.manage.UserAuthService;
import org.dromara.zyplayer.data.service.manage.UserInfoService;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
/**
* api权限控制器
*
* @author 暮光:城中城
* @since 2021年12月12日
*/
@AuthMan
@RestController
@RequestMapping("/doc-api/doc/auth")
public class ApiDocAuthController {
private static final Logger logger = LoggerFactory.getLogger(ApiDocAuthController.class);
@Resource
UserAuthService userAuthService;
@Resource
AuthInfoService authInfoService;
@Resource
UserInfoService userInfoService;
@Resource
ApiDocService apiDocService;
@Resource
ApiDocAuthJudgeService apiDocAuthJudgeService;
@PostMapping("/list")
public ResponseJson<Object> list(Long docId) {
if (!apiDocAuthJudgeService.haveManageAuth(docId)) {
return DocResponseJson.warn("没有此文档的操作权限");
}
List<UserAuth> authList = userAuthService.getModuleAuthList(DocSysType.API.getType(), DocSysModuleType.Api.DOC.getType(), docId);
if (CollectionUtils.isEmpty(authList)) {
return DocResponseJson.ok();
}
// 权限ID对应的权限名
Collection<AuthInfo> authInfoList = authInfoService.listByIds(authList.stream().map(UserAuth::getAuthId).collect(Collectors.toSet()));
Map<Long, String> authInfoMap = authInfoList.stream().collect(Collectors.toMap(AuthInfo::getId, AuthInfo::getAuthName));
Collection<UserInfo> userInfoList = userInfoService.listByIds(authList.stream().map(UserAuth::getUserId).collect(Collectors.toSet()));
Map<Long, UserInfo> userInfoMap = userInfoList.stream().collect(Collectors.toMap(UserInfo::getId, val -> val));
// 返回结果组装
List<DocUserAuthVo> authVoList = new LinkedList<>();
for (UserAuth userAuth : authList) {
UserInfo userInfo = userInfoMap.get(userAuth.getUserId());
String authCode = authInfoMap.get(userAuth.getAuthId());
DocUserAuthVo authVo = new DocUserAuthVo();
authVo.setAuthType(ApiAuthType.typeOf(authCode).getType());
authVo.setUserId(userAuth.getUserId());
authVo.setUserNo(userInfo.getUserNo());
authVo.setUserName(userInfo.getUserName());
authVo.setEmail(userInfo.getEmail());
authVo.setPhone(userInfo.getPhone());
authVo.setSex(userInfo.getSex());
authVoList.add(authVo);
}
return DocResponseJson.ok(authVoList);
}
@PostMapping("/assign")
public ResponseJson<Object> assign(Long docId, Long userId, Integer authType) {
if (!apiDocAuthJudgeService.haveManageAuth(docId)) {
return DocResponseJson.warn("没有此文档的操作权限");
}
DocUserDetails currentUser = DocUserUtil.getCurrentUser();
String authCode = ApiAuthType.typeOf(authType).getCode();
AuthInfo authInfo = authInfoService.getByCode(authCode);
List<UserAuth> userModuleAuthList = userAuthService.getUserModuleAuthList(userId, DocSysType.API.getType(), DocSysModuleType.Api.DOC.getType(), docId);
if (CollectionUtils.isNotEmpty(userModuleAuthList)) {
UserAuth userAuth = userModuleAuthList.remove(0);
// 错误数据兼容移除
if (!userModuleAuthList.isEmpty()) {
List<Long> authIdList = userModuleAuthList.stream().map(UserAuth::getId).collect(Collectors.toList());
userAuthService.removeByIds(authIdList);
}
userAuth.setAuthId(authInfo.getId());
userAuth.setUpdateTime(new Date());
userAuth.setUpdateUid(currentUser.getUserId());
userAuthService.updateById(userAuth);
} else {
UserAuth userAuth = new UserAuth();
userAuth.setUserId(userId);
userAuth.setSysType(DocSysType.API.getType());
userAuth.setSysModuleType(DocSysModuleType.Api.DOC.getType());
userAuth.setSysModuleId(docId);
userAuth.setAuthId(authInfo.getId());
userAuth.setCreationTime(new Date());
userAuth.setCreateUid(currentUser.getUserId());
userAuth.setUpdateTime(new Date());
userAuth.setUpdateUid(currentUser.getUserId());
userAuth.setDelFlag(0);
userAuthService.save(userAuth);
}
return DocResponseJson.ok();
}
@PostMapping("/delete")
public ResponseJson<Object> delete(Long docId, Long userId) {
if (!apiDocAuthJudgeService.haveManageAuth(docId)) {
return DocResponseJson.warn("没有此文档的操作权限");
}
userAuthService.deleteUserModuleAuth(userId, DocSysType.API.getType(), DocSysModuleType.Api.DOC.getType(), docId);
return DocResponseJson.ok();
}
}

View File

@@ -1,230 +0,0 @@
package org.dromara.zyplayer.api.controller;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.dromara.zyplayer.api.framework.utils.SwaggerDocUtil;
import org.dromara.zyplayer.api.service.SwaggerHttpRequestService;
import org.dromara.zyplayer.core.annotation.AuthMan;
import org.dromara.zyplayer.core.json.DocResponseJson;
import org.dromara.zyplayer.core.json.ResponseJson;
import org.dromara.zyplayer.data.config.security.DocUserDetails;
import org.dromara.zyplayer.data.config.security.DocUserUtil;
import org.dromara.zyplayer.data.repository.manage.entity.ApiDoc;
import org.dromara.zyplayer.data.repository.manage.vo.ApiCustomDocVo;
import org.dromara.zyplayer.data.repository.manage.vo.ApiDocVo;
import org.dromara.zyplayer.data.repository.support.consts.ApiAuthType;
import org.dromara.zyplayer.data.service.common.ApiDocAuthJudgeService;
import org.dromara.zyplayer.data.service.manage.ApiCustomNodeService;
import org.dromara.zyplayer.data.service.manage.ApiDocService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.swagger.web.SwaggerResource;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;
import java.util.Objects;
/**
* 文档控制器
*
* @author 暮光:城中城
* @since 2021年10月16日
*/
@AuthMan
@RestController
@RequestMapping("/doc-api/doc")
public class ApiDocumentController {
private static final Logger logger = LoggerFactory.getLogger(ApiDocumentController.class);
@Resource
ApiDocAuthJudgeService apiDocAuthJudgeService;
@Resource
private ApiDocService apiDocService;
@Resource
private SwaggerHttpRequestService swaggerHttpRequestService;
@Resource
ApiCustomNodeService apiCustomNodeService;
/**
* 获取所有的文档地址
*
* @return 文档内容
* @author 暮光:城中城
* @since 2021年10月16日
*/
@ResponseBody
@PostMapping(value = "/list")
public ResponseJson<List<ApiDocVo>> list(ApiDoc apiDoc, Integer pageNum, Integer pageSize) {
IPage<ApiDocVo> docList = apiDocService.getApiDocList(apiDoc, pageNum, pageSize);
return DocResponseJson.ok(docList);
}
/**
* 获取文档内容
*
* @return 文档内容
* @author 暮光:城中城
* @since 2021年10月16日
*/
@ResponseBody
@PostMapping(value = "/detail")
public ResponseJson<List<ApiDoc>> detail(Long id) {
ApiDoc apiDoc = apiDocService.getById(id);
if (!apiDocAuthJudgeService.haveDevelopAuth(apiDoc)) {
return DocResponseJson.warn("没有此文档的查看权限");
}
ApiDocVo apiDocVo = new ApiDocVo();
BeanUtil.copyProperties(apiDoc, apiDocVo);
Integer authType = apiDocAuthJudgeService.haveManageAuth(apiDoc) ? ApiAuthType.MANAGE.getType() : ApiAuthType.DEVELOPER.getType();
apiDocVo.setAuthType(authType);
return DocResponseJson.ok(apiDocVo);
}
/**
* 添加文档
*
* @return 文档内容
* @author 暮光:城中城
* @since 2021年10月16日
*/
@ResponseBody
@PostMapping(value = "/add")
public ResponseJson<Object> add(HttpServletRequest request, ApiDoc apiDoc) {
DocUserDetails currentUser = DocUserUtil.getCurrentUser();
apiDoc.setYn(1);
apiDoc.setCreateTime(new Date());
apiDoc.setCreateUserId(currentUser.getUserId());
apiDoc.setCreateUserName(currentUser.getUsername());
if (apiDoc.getId() == null) {
apiDoc.setShareUuid(IdUtil.simpleUUID());
} else {
ApiDoc apiDocSel = apiDocService.getById(apiDoc.getId());
if (apiDocSel == null) {
return DocResponseJson.warn("未找到指定的文档记录信息");
}
if (!apiDocAuthJudgeService.haveManageAuth(apiDocSel)) {
return DocResponseJson.warn("没有此文档的操作权限");
}
if (StringUtils.isBlank(apiDocSel.getShareUuid())) {
apiDoc.setShareUuid(IdUtil.simpleUUID());
}
}
// url类型
if (Objects.equals(apiDoc.getDocType(), 1)) {
// UI地址替换为文档json地址
String docUrl = SwaggerDocUtil.replaceSwaggerResources(apiDoc.getDocUrl());
if (SwaggerDocUtil.isSwaggerResources(docUrl)) {
String swaggerDomain = SwaggerDocUtil.getSwaggerResourceDomain(docUrl);
List<SwaggerResource> resourceList;
try {
String resourcesStr = swaggerHttpRequestService.requestSwaggerUrl(request, 0L, docUrl, swaggerDomain);
resourceList = JSON.parseArray(resourcesStr, SwaggerResource.class);
} catch (Exception e) {
e.printStackTrace();
return DocResponseJson.warn("解析文档地址失败:" + e.getMessage());
}
if (resourceList == null || resourceList.isEmpty()) {
return DocResponseJson.warn("该地址未找到文档");
}
// 删除原有文档
if (apiDoc.getId() != null) {
apiDocService.removeById(apiDoc.getId());
}
// 存明细地址
for (SwaggerResource resource : resourceList) {
apiDoc.setId(null);
apiDoc.setDocUrl(swaggerDomain + resource.getUrl());
apiDoc.setName(resource.getName());
apiDoc.setShareUuid(IdUtil.simpleUUID());
apiDocService.save(apiDoc);
}
} else {
apiDocService.saveOrUpdate(apiDoc);
}
} else if (Objects.equals(apiDoc.getDocType(), 2)
|| Objects.equals(apiDoc.getDocType(), 3)
|| Objects.equals(apiDoc.getDocType(), 4)
|| Objects.equals(apiDoc.getDocType(), 5)) {
apiDocService.saveOrUpdate(apiDoc);
} else {
return DocResponseJson.warn("暂不支持的文档类型");
}
return DocResponseJson.ok(apiDoc);
}
/**
* 修改文档基本信息
*
* @return 无
* @author 暮光:城中城
* @since 2021年10月16日
*/
@ResponseBody
@PostMapping(value = "/update")
public ResponseJson<List<ApiDoc>> update(ApiDoc apiDoc) {
if (apiDoc.getId() == null) {
return DocResponseJson.warn("请指定修改的记录ID");
}
// 基本信息可以改,删除需要管理员权限
if (Objects.equals(apiDoc.getYn(), 0)) {
if (!apiDocAuthJudgeService.haveManageAuth(apiDoc.getId())) {
return DocResponseJson.warn("没有此文档的删除权限");
}
} else {
if (!apiDocAuthJudgeService.haveDevelopAuth(apiDoc.getId())) {
return DocResponseJson.warn("没有此文档的编辑权限");
}
}
ApiDoc swaggerDocUp = new ApiDoc();
swaggerDocUp.setId(apiDoc.getId());
swaggerDocUp.setDocStatus(apiDoc.getDocStatus());
swaggerDocUp.setShareInstruction(apiDoc.getShareInstruction());
swaggerDocUp.setYn(apiDoc.getYn());
apiDocService.updateById(swaggerDocUp);
return DocResponseJson.ok();
}
@RequestMapping("/apis")
public ResponseJson<List<ApiDoc>> resources() {
List<ApiDoc> docList = apiDocService.getApiDocList();
return DocResponseJson.ok(docList);
}
@RequestMapping("/apis/detail")
public ResponseJson<Object> detail(HttpServletRequest request, Long id) {
ApiDoc apiDoc = apiDocService.getById(id);
if (apiDoc == null) {
return DocResponseJson.warn("文档不存在");
}
if (!apiDocAuthJudgeService.haveDevelopAuth(apiDoc)) {
return DocResponseJson.warn("没有此文档的查看权限");
}
if (Objects.equals(apiDoc.getDocType(), 1) || Objects.equals(apiDoc.getDocType(), 3)) {
try {
String docsDomain = SwaggerDocUtil.getV2ApiDocsDomain(apiDoc.getDocUrl());
String contentStr = swaggerHttpRequestService.requestSwaggerUrl(request, apiDoc.getId(), apiDoc.getDocUrl(), docsDomain);
return DocResponseJson.ok(contentStr);
} catch (Exception e) {
e.printStackTrace();
return DocResponseJson.warn("请求文档失败");
}
}
if (Objects.equals(apiDoc.getDocType(), 2) || Objects.equals(apiDoc.getDocType(), 4)) {
return DocResponseJson.ok(apiDoc.getJsonContent());
}
if (Objects.equals(apiDoc.getDocType(), 5)) {
List<ApiCustomDocVo> customVoList = apiCustomNodeService.buildCustomApiList(apiDoc);
return DocResponseJson.ok(customVoList);
}
return DocResponseJson.warn("暂不支持的文档类型");
}
}

View File

@@ -1,118 +0,0 @@
package org.dromara.zyplayer.api.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.dromara.zyplayer.core.annotation.AuthMan;
import org.dromara.zyplayer.core.json.DocResponseJson;
import org.dromara.zyplayer.core.json.ResponseJson;
import org.dromara.zyplayer.data.config.security.DocUserDetails;
import org.dromara.zyplayer.data.config.security.DocUserUtil;
import org.dromara.zyplayer.data.repository.manage.entity.ApiDoc;
import org.dromara.zyplayer.data.repository.manage.entity.ApiGlobalParam;
import org.dromara.zyplayer.data.service.common.ApiDocAuthJudgeService;
import org.dromara.zyplayer.data.service.manage.ApiGlobalParamService;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
/**
* 全局参数控制器
*
* @author 暮光:城中城
* @since 2021年10月16日
*/
@AuthMan
@RestController
@RequestMapping("/doc-api/global-param")
public class ApiGlobalParamController {
private static final Logger logger = LoggerFactory.getLogger(ApiGlobalParamController.class);
@Resource
private ApiGlobalParamService apiGlobalParamService;
@Resource
ApiDocAuthJudgeService apiDocAuthJudgeService;
/**
* 获取所有的全局参数
*
* @return 全局参数列表
* @author 暮光:城中城
* @since 2021年10月16日
*/
@ResponseBody
@PostMapping(value = "/list")
public ResponseJson<List<ApiGlobalParam>> list(Long docId) {
Long docIdNew = Optional.ofNullable(docId).orElse(0L);
if (docIdNew > 0 && !apiDocAuthJudgeService.haveDevelopAuth(docIdNew)) {
return DocResponseJson.warn("没有此文档的查看权限");
}
DocUserDetails currentUser = DocUserUtil.getCurrentUser();
QueryWrapper<ApiGlobalParam> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("yn", 1);
queryWrapper.eq("doc_id", docIdNew);
// 全局参数才按创建人来控制,文档的全局参数大家共用
queryWrapper.eq(docIdNew == 0, "create_user_id", currentUser.getUserId());
queryWrapper.orderByDesc("id");
List<ApiGlobalParam> globalParamList = apiGlobalParamService.list(queryWrapper);
return DocResponseJson.ok(globalParamList);
}
/**
* 修改全局参数
*
* @return 无
* @author 暮光:城中城
* @since 2021年10月16日
*/
@ResponseBody
@PostMapping(value = "/update")
public ResponseJson<List<ApiDoc>> update(ApiGlobalParam globalParam) {
DocUserDetails currentUser = DocUserUtil.getCurrentUser();
globalParam.setDocId(Optional.ofNullable(globalParam.getDocId()).orElse(0L));
// 新的文档ID是否有权限
if (globalParam.getDocId() > 0 && !apiDocAuthJudgeService.haveDevelopAuth(globalParam.getDocId())) {
return DocResponseJson.warn("没有此文档的查看权限");
}
if (globalParam.getId() == null) {
globalParam.setYn(1);
globalParam.setCreateTime(new Date());
globalParam.setCreateUserId(currentUser.getUserId());
globalParam.setCreateUserName(currentUser.getUsername());
} else {
ApiGlobalParam param = apiGlobalParamService.getById(globalParam.getId());
if (param.getDocId() > 0) {
// 已有的文档ID是否有权限
if (!apiDocAuthJudgeService.haveDevelopAuth(param.getDocId())) {
return DocResponseJson.warn("没有此文档的查看权限");
}
} else {
if (!Objects.equals(param.getCreateUserId(), currentUser.getUserId())) {
return DocResponseJson.warn("目标全局参数不存在");
}
}
}
QueryWrapper<ApiGlobalParam> wrapper = new QueryWrapper<>();
wrapper.eq("yn", 1);
wrapper.eq("param_key", globalParam.getParamKey());
wrapper.eq("doc_id", globalParam.getDocId());
// 全局参数才按创建人来控制,文档的全局参数大家共用
wrapper.eq(globalParam.getDocId() == 0, "create_user_id", currentUser.getUserId());
List<ApiGlobalParam> paramList = apiGlobalParamService.list(wrapper);
if (CollectionUtils.isNotEmpty(paramList)) {
if (paramList.size() > 1 || !Objects.equals(paramList.get(0).getId(), globalParam.getId())) {
return DocResponseJson.warn("全局参数名称不能重复");
}
}
apiGlobalParamService.saveOrUpdate(globalParam);
return DocResponseJson.ok();
}
}

View File

@@ -1,83 +0,0 @@
package org.dromara.zyplayer.api.controller;
import org.dromara.zyplayer.core.annotation.AuthMan;
import org.dromara.zyplayer.core.json.DocResponseJson;
import org.dromara.zyplayer.core.json.ResponseJson;
import org.dromara.zyplayer.api.controller.param.ProxyRequestParam;
import org.dromara.zyplayer.api.controller.vo.ProxyRequestResultVo;
import org.dromara.zyplayer.api.service.SwaggerHttpRequestService;
import org.dromara.zyplayer.data.repository.manage.entity.ApiCustomNode;
import org.dromara.zyplayer.data.repository.manage.entity.ApiCustomParams;
import org.dromara.zyplayer.data.service.manage.ApiCustomNodeService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 请求参数控制器
*
* @author 暮光:城中城
* @since 2021年10月16日
*/
@AuthMan
@RestController
@RequestMapping("/doc-api/proxy")
public class ApiPoxyRequestController {
private static final Logger logger = LoggerFactory.getLogger(ApiPoxyRequestController.class);
@Resource
ApiCustomNodeService apiCustomNodeService;
@Resource
private SwaggerHttpRequestService swaggerHttpRequestService;
/**
* 代理接口请求
*
* @return 请求参数
* @author 暮光:城中城
* @since 2021年10月16日
*/
@ResponseBody
@PostMapping(value = "/request")
public ResponseJson<ProxyRequestResultVo> request(HttpServletRequest request, ProxyRequestParam requestParam) {
// 自建接口请求时保存信息
if (requestParam.getNodeId() != null) {
ApiCustomNode apiCustomNode = new ApiCustomNode();
apiCustomNode.setNodeType(1);
apiCustomNode.setId(requestParam.getNodeId());
apiCustomNode.setDocId(requestParam.getDocId());
apiCustomNode.setNodeName(requestParam.getApiName());
ApiCustomParams apiCustomParams = new ApiCustomParams();
apiCustomParams.setApiUrl(requestParam.getUrl());
apiCustomParams.setMethod(requestParam.getMethod());
apiCustomParams.setFormData(requestParam.getFormParam());
apiCustomParams.setBodyData(requestParam.getBodyParam());
apiCustomParams.setHeaderData(requestParam.getHeaderParam());
apiCustomParams.setCookieData(requestParam.getCookieParam());
apiCustomNodeService.addNode(apiCustomNode, apiCustomParams);
}
ProxyRequestResultVo requestResult = swaggerHttpRequestService.proxyRequest(request, requestParam);
return DocResponseJson.ok(requestResult);
}
/**
* 代理接口下载请求
*
* @return 请求参数
* @author 暮光:城中城
* @since 2021年10月16日
*/
@ResponseBody
@PostMapping(value = "/download")
public ResponseJson<ProxyRequestResultVo> download(HttpServletRequest request, HttpServletResponse response, ProxyRequestParam requestParam) {
swaggerHttpRequestService.proxyDownload(request, response, requestParam);
return DocResponseJson.ok();
}
}

View File

@@ -1,75 +0,0 @@
package org.dromara.zyplayer.api.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.dromara.zyplayer.core.annotation.AuthMan;
import org.dromara.zyplayer.core.json.DocResponseJson;
import org.dromara.zyplayer.core.json.ResponseJson;
import org.dromara.zyplayer.data.config.security.DocUserDetails;
import org.dromara.zyplayer.data.config.security.DocUserUtil;
import org.dromara.zyplayer.data.repository.manage.entity.ApiDoc;
import org.dromara.zyplayer.data.repository.manage.entity.ApiRequestParam;
import org.dromara.zyplayer.data.service.manage.ApiRequestParamService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
/**
* 请求参数控制器
*
* @author 暮光:城中城
* @since 2021年10月16日
*/
@AuthMan
@RestController
@RequestMapping("/doc-api/request-param")
public class ApiRequestParamController {
private static final Logger logger = LoggerFactory.getLogger(ApiRequestParamController.class);
@Resource
private ApiRequestParamService apiRequestParamService;
/**
* 获取所有的请求参数
*
* @return 请求参数
* @author 暮光:城中城
* @since 2021年10月16日
*/
@ResponseBody
@PostMapping(value = "/query")
public ResponseJson<ApiRequestParam> query(String docUrl) {
QueryWrapper<ApiRequestParam> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("yn", 1);
queryWrapper.eq("doc_url", docUrl);
ApiRequestParam requestParam = apiRequestParamService.getOne(queryWrapper);
return DocResponseJson.ok(requestParam);
}
/**
* 修改请求参数
*
* @return 无
* @author 暮光:城中城
* @since 2021年10月16日
*/
@ResponseBody
@PostMapping(value = "/update")
public ResponseJson<List<ApiDoc>> update(ApiRequestParam apiRequestParam) {
QueryWrapper<ApiRequestParam> updateWrapper = new QueryWrapper<>();
updateWrapper.eq("doc_url", apiRequestParam.getDocUrl());
DocUserDetails currentUser = DocUserUtil.getCurrentUser();
apiRequestParam.setYn(1);
apiRequestParam.setCreateTime(new Date());
apiRequestParam.setCreateUserId(currentUser.getUserId());
apiRequestParam.setCreateUserName(currentUser.getUsername());
apiRequestParamService.update(apiRequestParam, updateWrapper);
return DocResponseJson.ok();
}
}

View File

@@ -1,77 +0,0 @@
package org.dromara.zyplayer.api.controller;
import org.dromara.zyplayer.api.framework.utils.SwaggerDocUtil;
import org.dromara.zyplayer.api.service.SwaggerHttpRequestService;
import org.dromara.zyplayer.core.json.DocResponseJson;
import org.dromara.zyplayer.core.json.ResponseJson;
import org.dromara.zyplayer.data.repository.manage.entity.ApiDoc;
import org.dromara.zyplayer.data.service.manage.ApiDocService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Objects;
/**
* 文档控制器
*
* @author 暮光:城中城
* @since 2021年10月16日
*/
@RestController
@RequestMapping("/doc-api/share")
public class ApiShareDocumentController {
private static final Logger logger = LoggerFactory.getLogger(ApiShareDocumentController.class);
@Resource
private ApiDocService swaggerDocService;
@Resource
private SwaggerHttpRequestService swaggerHttpRequestService;
/**
* 获取文档内容
*
* @return 文档内容
* @author 暮光:城中城
* @since 2021年10月16日
*/
@ResponseBody
@PostMapping(value = "/detail")
public ResponseJson<List<ApiDoc>> detail(String shareUuid) {
ApiDoc apiDoc = swaggerDocService.getByShareUuid(shareUuid);
if (apiDoc == null) {
return DocResponseJson.warn("文档不存在");
}
apiDoc.setDocUrl(null);
apiDoc.setJsonContent(null);
return DocResponseJson.ok(apiDoc);
}
@RequestMapping("/apis/detail")
public ResponseJson<Object> detail(HttpServletRequest request, String shareUuid) {
ApiDoc apiDoc = swaggerDocService.getByShareUuid(shareUuid);
if (apiDoc == null) {
return DocResponseJson.warn("文档不存在");
}
if (Objects.equals(apiDoc.getDocType(), 1)) {
try {
String docsDomain = SwaggerDocUtil.getV2ApiDocsDomain(apiDoc.getDocUrl());
String contentStr = swaggerHttpRequestService.requestSwaggerUrl(request, apiDoc.getId(), apiDoc.getDocUrl(), docsDomain);
return DocResponseJson.ok(contentStr);
} catch (Exception e) {
e.printStackTrace();
return DocResponseJson.warn("请求文档失败");
}
}
if (Objects.equals(apiDoc.getDocType(), 2) || Objects.equals(apiDoc.getDocType(), 4)) {
return DocResponseJson.ok(apiDoc.getJsonContent());
}
return DocResponseJson.warn("暂不支持的文档类型");
}
}

View File

@@ -1,99 +0,0 @@
package org.dromara.zyplayer.api.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.dromara.zyplayer.core.annotation.AuthMan;
import org.dromara.zyplayer.core.exception.ConfirmException;
import org.dromara.zyplayer.core.json.DocResponseJson;
import org.dromara.zyplayer.data.repository.manage.entity.ApiDoc;
import org.dromara.zyplayer.data.service.manage.ApiDocService;
import org.dromara.zyplayer.api.controller.vo.SwaggerResourceVo;
import org.dromara.zyplayer.api.framework.utils.SwaggerDocUtil;
import org.dromara.zyplayer.api.service.SwaggerHttpRequestService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.MimeTypeUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.spring.web.json.Json;
import springfox.documentation.swagger.web.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
/**
* 承接了所有的ApiResourceController的接口
*
* @author 暮光:城中城
* @since 2021年10月16日
*/
@AuthMan
@RestController
public class ApiSwaggerProxyController {
private static final String HAL_MEDIA_TYPE = "application/hal+json";
@Resource
private ApiDocService apiDocService;
@Resource
private SwaggerHttpRequestService swaggerHttpRequestService;
@ResponseBody
@RequestMapping("/swagger-resources")
public List<SwaggerResourceVo> swaggerResources() {
List<SwaggerResourceVo> resourceList = new LinkedList<>();
QueryWrapper<ApiDoc> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("yn", 1);
queryWrapper.eq("doc_status", 1);
queryWrapper.eq("open_visit", 1);
queryWrapper.in("doc_type", 1, 2);
queryWrapper.orderByAsc("id");
queryWrapper.select("id", "name", "rewrite_domain");
List<ApiDoc> docList = apiDocService.list(queryWrapper);
for (ApiDoc apiDoc : docList) {
SwaggerResourceVo resource = new SwaggerResourceVo();
resource.setUrl("/v2/api-docs?id=" + apiDoc.getId());
resource.setName(apiDoc.getName());
resource.setSwaggerVersion("2.0");
resource.setRewriteDomain(apiDoc.getRewriteDomain());
resourceList.add(resource);
}
return resourceList;
}
@ResponseBody
@RequestMapping(value = "/v2/api-docs", produces = {MimeTypeUtils.APPLICATION_JSON_VALUE, HAL_MEDIA_TYPE})
public ResponseEntity<Object> content(HttpServletRequest request, Long id) {
ApiDoc apiDoc = apiDocService.getById(id);
if (apiDoc == null || !Objects.equals(apiDoc.getOpenVisit(), 1)) {
throw new ConfirmException("文档不存在");
}
if (Objects.equals(apiDoc.getDocType(), 1)) {
try {
String docsDomain = SwaggerDocUtil.getV2ApiDocsDomain(apiDoc.getDocUrl());
String contentStr = swaggerHttpRequestService.requestSwaggerUrl(request, apiDoc.getId(), apiDoc.getDocUrl(), docsDomain);
return new ResponseEntity<>(new Json(contentStr), HttpStatus.OK);
} catch (Exception e) {
e.printStackTrace();
return new ResponseEntity<>(DocResponseJson.warn("请求文档失败"), HttpStatus.OK);
}
}
return new ResponseEntity<>(new Json(apiDoc.getJsonContent()), HttpStatus.OK);
}
@ResponseBody
@RequestMapping(value = "/swagger-resources/configuration/security")
public ResponseEntity<SecurityConfiguration> securityConfiguration() {
SecurityConfiguration securityConfiguration = SecurityConfigurationBuilder.builder().build();
return new ResponseEntity<>(securityConfiguration, HttpStatus.OK);
}
@ResponseBody
@RequestMapping(value = "/swagger-resources/configuration/ui")
public ResponseEntity<UiConfiguration> uiConfiguration() {
UiConfiguration uiConfiguration = UiConfigurationBuilder.builder().build();
return new ResponseEntity<>(uiConfiguration, HttpStatus.OK);
}
}

View File

@@ -1,15 +0,0 @@
package org.dromara.zyplayer.api.controller.param;
import lombok.Data;
/**
* 参数信息
*
* @author 暮光:城中城
* @since 2021-11-04
*/
@Data
public class ParamData {
private String code;
private String value;
}

View File

@@ -1,45 +0,0 @@
package org.dromara.zyplayer.api.controller.param;
import com.alibaba.fastjson.JSON;
import lombok.Data;
import java.util.List;
/**
* 代理请求参数
*
* @author 暮光:城中城
* @since 2021-11-04
*/
@Data
public class ProxyRequestParam {
private Long docId;
private Long nodeId;
private String url;
private String host;
private String method;
private String contentType;
private String headerParam;
private String cookieParam;
private String formParam;
private String formEncodeParam;
private String bodyParam;
private String apiName;
public List<ParamData> getHeaderParamData() {
return JSON.parseArray(headerParam, ParamData.class);
}
public List<ParamData> getCookieParamData() {
return JSON.parseArray(cookieParam, ParamData.class);
}
public List<ParamData> getFormParamData() {
return JSON.parseArray(formParam, ParamData.class);
}
public List<ParamData> getFormEncodeParamData() {
return JSON.parseArray(formEncodeParam, ParamData.class);
}
}

View File

@@ -1,78 +0,0 @@
package org.dromara.zyplayer.api.controller.vo;
import lombok.Data;
@Data
public class ApiCustomParamsVo {
/**
* 节点ID
*/
private Long id;
/**
* 父文件夹ID
*/
private Long parentId;
/**
* 节点类型 0=目录 1=接口
*/
private Integer nodeType;
/**
* 节点名称
*/
private String nodeName;
/**
* 节点说明
*/
private String nodeDesc;
/**
* 节点顺序
*/
private Integer seqNo;
/**
* api_doc主键ID
*/
private Long docId;
/**
* 节点ID
*/
private Long nodeId;
/**
* 请求方式get、head、post、put、patch、delete、options、trace
*/
private String method;
/**
* 接口url
*/
private String apiUrl;
/**
* form参数
*/
private String formData;
/**
* body参数
*/
private String bodyData;
/**
* header参数
*/
private String headerData;
/**
* cookie参数
*/
private String cookieData;
}

View File

@@ -1,83 +0,0 @@
package org.dromara.zyplayer.api.controller.vo;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* api文档地址Vo
*
* @author 暮光:城中城
* @since 2021-11-25
*/
@Data
public class ApiDocVo implements Serializable {
private Long id;
/**
* 文档名称
*/
private String name;
/**
* 文档类型 1=swagger url 2=swagger json 3=openapi url 4=openapi json 5=自建API分组
*/
private Integer docType;
/**
* 文档URL地址
*/
private String docUrl;
/**
* 文档json内容
*/
private String jsonContent;
/**
* 重写的域名
*/
private String rewriteDomain;
/**
* 是否开放访问 0=否 1=是
*/
private Integer openVisit;
/**
* 状态 1=启用 2=禁用
*/
private Integer docStatus;
/**
* 开放文档UUID
*/
private String shareUuid;
/**
* 开放文档使用说明
*/
private String shareInstruction;
/**
* 创建人ID
*/
private Long createUserId;
/**
* 创建人名字
*/
private String createUserName;
/**
* 创建时间
*/
private Date createTime;
/**
* 是否有效 0=无效 1=有效
*/
private Integer yn;
}

View File

@@ -1,48 +0,0 @@
package org.dromara.zyplayer.api.controller.vo;
import lombok.Data;
/**
* 用户权限返回值对象
*
* @author 暮光:城中城
* @since 2021年12月12日
*/
@Data
public class DocUserAuthVo {
/**
* 权限类型
*/
private Integer authType;
/**
* 用户ID
*/
private Long userId;
/**
* 用户编号,用于登录等
*/
private String userNo;
/**
* 用户名
*/
private String userName;
/**
* 邮箱
*/
private String email;
/**
* 手机号
*/
private String phone;
/**
* 性别 0=女 1=男
*/
private Integer sex;
}

View File

@@ -1,19 +0,0 @@
package org.dromara.zyplayer.api.controller.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* cookie返回值对象
*
* @author 暮光:城中城
* @since 2018年8月21日
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class HttpCookieVo {
private String name;
private String value;
}

View File

@@ -1,15 +0,0 @@
package org.dromara.zyplayer.api.controller.vo;
import lombok.Data;
/**
* header返回值对象
*
* @author 暮光:城中城
* @since 2018年8月21日
*/
@Data
public class HttpHeaderVo {
private String name;
private String value;
}

View File

@@ -1,23 +0,0 @@
package org.dromara.zyplayer.api.controller.vo;
import lombok.Data;
import java.util.List;
/**
* 代理请求结果
*
* @author 暮光:城中城
* @since 2021-11-04
*/
@Data
public class ProxyRequestResultVo {
private List<HttpCookieVo> cookies;
private List<HttpHeaderVo> headers;
private Integer status;
private Long useTime;
private Integer contentLength;
private String data;
private String errorMsg;
}

View File

@@ -1,26 +0,0 @@
package org.dromara.zyplayer.api.controller.vo;
import com.google.common.collect.ComparisonChain;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* swagger资源信息
*
* @author 暮光:城中城
* @since 2021-11-04
*/
@Data
@NoArgsConstructor
public class SwaggerResourceVo implements Comparable<SwaggerResourceVo> {
private String name;
private String url;
private String swaggerVersion;
private String rewriteDomain;
@Override
public int compareTo(SwaggerResourceVo other) {
return ComparisonChain.start().compare(this.swaggerVersion, other.swaggerVersion).compare(this.name, other.name).result();
}
}

View File

@@ -1,23 +0,0 @@
package org.dromara.zyplayer.api.framework.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import java.lang.annotation.*;
/**
* 开启api接口文档模块注解
*
* @author 暮光:城中城
* @since 2021-11-04
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@ComponentScan(basePackages = {
"org.dromara.zyplayer.api",
})
public @interface EnableDocApi {
}

View File

@@ -1,53 +0,0 @@
package org.dromara.zyplayer.api.framework.utils;
/**
* swagger文档工具类
*
* @author 暮光:城中城
* @since 2021-11-04
*/
public class SwaggerDocUtil {
public static String replaceSwaggerResources(String docUrl) {
int htmlIndex = docUrl.indexOf("/swagger-ui.html");
if (htmlIndex > 0) {
docUrl = docUrl.substring(0, htmlIndex) + "/swagger-resources";
}
return docUrl;
}
public static boolean isSwaggerResources(String docUrl) {
return docUrl.contains("/swagger-resources");
}
public static String getSwaggerResourceDomain(String docUrl) {
int index = docUrl.indexOf("/swagger-resources");
if (index >= 0) {
return docUrl.substring(0, index);
}
return "";
}
public static String getV2ApiDocsDomain(String docUrl) {
int index = docUrl.indexOf("/v2/api-docs");
if (index >= 0) {
return docUrl.substring(0, index);
}
return "";
}
public static String getDomainHost(String domain) {
domain = domain.replace("http://", "");
domain = domain.replace("https://", "");
int index = domain.indexOf("/");
if (index >= 0) {
return domain.substring(0, index);
}
return domain;
}
public static boolean isSwaggerLocation(String docUrl) {
return docUrl.contains("/v2/api-docs");
}
}

View File

@@ -1,250 +0,0 @@
package org.dromara.zyplayer.api.service;
import cn.hutool.core.io.resource.BytesResource;
import cn.hutool.core.io.resource.MultiResource;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import org.dromara.zyplayer.api.controller.param.ProxyRequestParam;
import org.dromara.zyplayer.api.controller.vo.HttpCookieVo;
import org.dromara.zyplayer.api.controller.vo.HttpHeaderVo;
import org.dromara.zyplayer.api.controller.vo.ProxyRequestResultVo;
import org.dromara.zyplayer.api.framework.utils.SwaggerDocUtil;
import org.dromara.zyplayer.core.exception.ConfirmException;
import org.dromara.zyplayer.data.repository.manage.entity.ApiGlobalParam;
import org.dromara.zyplayer.data.service.manage.ApiGlobalParamService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;
import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.HttpCookie;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* swagger请求服务
*
* @author 暮光:城中城
* @since 2021-11-04
*/
@Service
public class SwaggerHttpRequestService {
private static final Logger logger = LoggerFactory.getLogger(SwaggerHttpRequestService.class);
@Resource
private ApiGlobalParamService apiGlobalParamService;
private static final Map<String, Method> requestMethodMap = Stream.of(Method.values()).collect(Collectors.toMap(val -> val.name().toLowerCase(), val -> val));
final List<String> domainHeaderKeys = Arrays.asList("referer", "origin");
final List<String> needRequestHeaderKeys = Collections.singletonList("user-agent");
/**
* 请求真实的swagger文档内容
*
* @author 暮光:城中城
* @since 2021-11-04
*/
public String requestSwaggerUrl(HttpServletRequest request, Long docId, String docUrl, String docDomain) {
List<ApiGlobalParam> globalParamList = apiGlobalParamService.getGlobalParamList(docId);
Map<String, Object> globalFormParamMap = globalParamList.stream().filter(item -> Objects.equals(item.getParamType(), 1))
.collect(Collectors.toMap(ApiGlobalParam::getParamKey, ApiGlobalParam::getParamValue, (val1, val2) -> val1));
Map<String, String> globalHeaderParamMap = globalParamList.stream().filter(item -> Objects.equals(item.getParamType(), 2))
.collect(Collectors.toMap(ApiGlobalParam::getParamKey, ApiGlobalParam::getParamValue, (val1, val2) -> val1));
Map<String, String> globalCookieParamMap = globalParamList.stream().filter(item -> Objects.equals(item.getParamType(), 3))
.collect(Collectors.toMap(ApiGlobalParam::getParamKey, ApiGlobalParam::getParamValue, (val1, val2) -> val1));
Map<String, String> requestHeaders = this.getHttpHeader(request, globalHeaderParamMap);
if (StringUtils.isNotBlank(docDomain)) {
domainHeaderKeys.forEach(key -> requestHeaders.put(key, docDomain));
requestHeaders.put("host", SwaggerDocUtil.getDomainHost(docDomain));
}
// 执行请求
return HttpRequest.get(docUrl)
.form(globalFormParamMap)
.addHeaders(requestHeaders)
.header("Accept", "application/json, text/javascript, */*; q=0.01")
.cookie(this.getHttpCookie(request, globalCookieParamMap, null))
.timeout(10000).execute().body();
}
/**
* 执行代理请求
*
* @author 暮光:城中城
* @since 2021-11-04
*/
public void proxyDownload(HttpServletRequest request, HttpServletResponse response, ProxyRequestParam requestParam) {
try {
HttpResponse httpResponse = this.getHttpResponse(request, requestParam);
Map<String, List<String>> responseHeaders = httpResponse.headers();
if (MapUtils.isNotEmpty(responseHeaders)) {
for (Map.Entry<String, List<String>> httpHeader : responseHeaders.entrySet()) {
response.addHeader(httpHeader.getKey(), String.join(";", httpHeader.getValue()));
}
}
httpResponse.writeBody(response.getOutputStream(), true, null);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 执行代理请求
*
* @author 暮光:城中城
* @since 2021-11-04
*/
public ProxyRequestResultVo proxyRequest(HttpServletRequest request, ProxyRequestParam requestParam) {
ProxyRequestResultVo resultVo = new ProxyRequestResultVo();
long startTime = System.currentTimeMillis();
try {
HttpResponse httpResponse = getHttpResponse(request, requestParam);
resultVo.setData(httpResponse.body());
resultVo.setStatus(httpResponse.getStatus());
resultVo.setContentLength(httpResponse.bodyBytes().length);
// 设置返回的cookies
List<HttpCookie> responseCookies = httpResponse.getCookies();
if (CollectionUtils.isNotEmpty(responseCookies)) {
resultVo.setCookies(responseCookies.stream().map(val -> new HttpCookieVo(val.getName(), val.getValue())).collect(Collectors.toList()));
}
// 设置返回的headers
Map<String, List<String>> responseHeaders = httpResponse.headers();
if (MapUtils.isNotEmpty(responseHeaders)) {
List<HttpHeaderVo> headerList = new ArrayList<>(responseHeaders.size());
for (Map.Entry<String, List<String>> httpHeader : responseHeaders.entrySet()) {
HttpHeaderVo vo = new HttpHeaderVo();
vo.setName(httpHeader.getKey());
vo.setValue(String.join(";", httpHeader.getValue()));
headerList.add(vo);
}
resultVo.setHeaders(headerList);
}
} catch (Exception e) {
e.printStackTrace();
resultVo.setErrorMsg(e.getMessage());
}
resultVo.setUseTime(System.currentTimeMillis() - startTime);
return resultVo;
}
private HttpResponse getHttpResponse(HttpServletRequest request, ProxyRequestParam requestParam) {
// 执行请求
Method method = requestMethodMap.get(requestParam.getMethod());
if (method == null) {
throw new ConfirmException("不支持的请求方式:" + requestParam.getMethod());
}
HttpRequest httpRequest = HttpUtil.createRequest(method, requestParam.getUrl());
// header获取
Map<String, String> headerParam = new HashMap<>();
requestParam.getHeaderParamData().forEach(item -> headerParam.put(item.getCode(), item.getValue()));
Map<String, String> requestHeaders = this.getHttpHeader(request, headerParam);
if (StringUtils.isNotBlank(requestParam.getHost())) {
domainHeaderKeys.forEach(key -> requestHeaders.put(key, requestParam.getHost()));
requestHeaders.put("host", SwaggerDocUtil.getDomainHost(requestParam.getHost()));
}
// http自带参数
httpRequest.addHeaders(requestHeaders);
// 用户输入的参数
requestParam.getFormParamData().forEach(data -> httpRequest.form(data.getCode(), data.getValue()));
requestParam.getFormEncodeParamData().forEach(data -> httpRequest.form(data.getCode(), data.getValue()));
// 文件参数
if (request instanceof StandardMultipartHttpServletRequest) {
StandardMultipartHttpServletRequest multipartRequest = (StandardMultipartHttpServletRequest) request;
Iterator<String> fileNames = multipartRequest.getFileNames();
while (fileNames.hasNext()) {
String fileName = fileNames.next();
String originKey = fileName.replace("_file_", "");
List<MultipartFile> fileList = multipartRequest.getFiles(fileName);
try {
if (fileList.size() > 1) {
MultiResource multiResource = new MultiResource();
for (MultipartFile file : fileList) {
multiResource.add(new BytesResource(file.getBytes(), file.getOriginalFilename()));
}
httpRequest.form(originKey, multiResource);
} else if (!fileList.isEmpty()) {
MultipartFile multipartFile = fileList.get(0);
httpRequest.form(originKey, multipartFile.getBytes(), multipartFile.getOriginalFilename());
}
} catch (IOException e) {
logger.error("读取上传的文件失败", e);
}
}
}
// cookie参数
Map<String, String> cookieParam = new HashMap<>();
String headerCookie = headerParam.getOrDefault("Cookie", headerParam.get("cookie"));
requestParam.getCookieParamData().forEach(item -> cookieParam.put(item.getCode(), item.getValue()));
httpRequest.cookie(this.getHttpCookie(request, cookieParam, headerCookie));
if (StringUtils.isNotBlank(requestParam.getBodyParam())) {
httpRequest.body(requestParam.getBodyParam());
}
// 强制设置类型貌似不用刻意设置如果写的application/json参数是表单传过去收不到值先注释这个
// if (StringUtils.isNotBlank(requestParam.getContentType())) {
// httpRequest.contentType(requestParam.getContentType());
// }
// 执行请求
return httpRequest.timeout(10000).execute();
}
/**
* 获取http的cookie
*
* @author 暮光:城中城
* @since 2021-11-04
*/
private List<HttpCookie> getHttpCookie(HttpServletRequest request, Map<String, String> globalCookieParamMap, String headerCookie) {
List<HttpCookie> httpCookies = new LinkedList<>();
if (request.getCookies() != null) {
for (Cookie cookie : request.getCookies()) {
httpCookies.add(new HttpCookie(cookie.getName(), cookie.getValue()));
}
}
if (StringUtils.isNotBlank(headerCookie)) {
Arrays.stream(headerCookie.split(";")).map(String::trim).forEach(cookie -> {
String[] cookieArr = StringUtils.split(cookie, "=", 2);
if (ArrayUtils.getLength(cookieArr) == 2) {
httpCookies.add(new HttpCookie(cookieArr[0], cookieArr[1]));
}
});
}
if (MapUtils.isNotEmpty(globalCookieParamMap)) {
globalCookieParamMap.forEach((key, value) -> httpCookies.add(new HttpCookie(key, value)));
}
return httpCookies;
}
/**
* 获取http的header
*
* @author 暮光:城中城
* @since 2021-11-04
*/
private Map<String, String> getHttpHeader(HttpServletRequest request, Map<String, String> globalHeaderParamMap) {
Map<String, String> headerParamMap = new HashMap<>();
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = StringUtils.lowerCase(headerNames.nextElement());
if (needRequestHeaderKeys.contains(headerName)) {
headerParamMap.put(headerName, request.getHeader(headerName));
}
}
if (MapUtils.isNotEmpty(globalHeaderParamMap)) {
headerParamMap.putAll(globalHeaderParamMap);
}
return headerParamMap;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
import{u as S,a9 as w,r as c,o as a,c as l,w as t,a as o,k as g,t as n,b as i,F as f,s,e as m,d as M}from"./vendor.6399378c.js";import{m as B}from"./index.086d0536.js";import{_ as C}from"./main.5fd30069.js";const N={setup(){const _=S(),D=w(()=>_.state.swaggerDoc),u=w(()=>_.state.swaggerDoc.info),e=w(()=>_.state.swaggerMethodStatistic);return{swaggerDoc:D,swaggerDocInfo:u,swaggerMethodStatistic:e,getDescription:I=>B.exports.markdownIt.render(I||"")}}},V=["href"],j=["href"],L=["href"],O=["innerHTML"],T={key:1,style:{"text-align":"center"}};function E(_,D,u,e,p,I){const r=c("a-form-item"),h=c("a-divider"),v=c("a-statistic"),k=c("a-card"),b=c("a-col"),y=c("a-row"),x=c("a-form");return a(),l(k,null,{default:t(()=>[e.swaggerDocInfo?(a(),l(x,{key:0,"label-col":{span:4},"wrapper-col":{span:20}},{default:t(()=>[o(r,{label:"\u6807\u9898"},{default:t(()=>[g(n(e.swaggerDocInfo.title),1)]),_:1}),o(r,{label:"\u7248\u672C"},{default:t(()=>[g(n(e.swaggerDocInfo.version),1)]),_:1}),e.swaggerDocInfo.contact?(a(),l(r,{key:0,label:"\u4F5C\u8005"},{default:t(()=>[e.swaggerDocInfo.contact.name?(a(),i(f,{key:0},[g(n(e.swaggerDocInfo.contact.name),1)],64)):s("",!0),e.swaggerDocInfo.contact.email?(a(),i(f,{key:1},[o(h,{type:"vertical"}),g(n(e.swaggerDocInfo.contact.email),1)],64)):s("",!0),e.swaggerDocInfo.contact.url?(a(),i(f,{key:2},[o(h,{type:"vertical"}),m("a",{href:e.swaggerDocInfo.contact.url,target:"_blank"},n(e.swaggerDocInfo.contact.url),9,V)],64)):s("",!0)]),_:1})):s("",!0),o(r,{label:"host"},{default:t(()=>[g(n(e.swaggerDoc.host),1)]),_:1}),e.swaggerDocInfo.license?(a(),l(r,{key:1,label:"\u8BB8\u53EF\u8BC1"},{default:t(()=>[m("a",{href:e.swaggerDocInfo.license.url,target:"_blank"},n(e.swaggerDocInfo.license.name),9,j)]),_:1})):s("",!0),e.swaggerDocInfo.termsOfService?(a(),l(r,{key:2,label:"\u670D\u52A1\u6761\u6B3E"},{default:t(()=>[m("a",{href:e.swaggerDocInfo.termsOfService,target:"_blank"},n(e.swaggerDocInfo.termsOfService),9,L)]),_:1})):s("",!0),o(r,{label:"\u6587\u6863\u8BF4\u660E"},{default:t(()=>[m("div",{class:"markdown-body",innerHTML:e.getDescription(e.swaggerDocInfo.description)},null,8,O)]),_:1}),o(r,{label:"\u63A5\u53E3\u7EDF\u8BA1"},{default:t(()=>[o(y,{gutter:[16,16]},{default:t(()=>[(a(),i(f,null,M(["get","post","put","delete","head","patch","options","trace","total"],d=>(a(),i(f,null,[e.swaggerMethodStatistic[d]?(a(),l(b,{key:0,span:6},{default:t(()=>[o(k,{size:"small"},{default:t(()=>[o(v,{title:d==="total"?"\u603B\u8BA1":d.toUpperCase()+"\u65B9\u6CD5",value:e.swaggerMethodStatistic[d],suffix:"\u4E2A"},null,8,["title","value"])]),_:2},1024)]),_:2},1024)):s("",!0)],64))),64))]),_:1})]),_:1})]),_:1})):(a(),i("div",T,"\u6682\u65E0\u6587\u6863\u4FE1\u606F\uFF0C\u8BF7\u5148\u9009\u62E9\u6587\u6863"))]),_:1})}var U=C(N,[["render",E]]);export{U as default};

View File

@@ -1 +0,0 @@
import{u as S,a9 as D,r as i,o as t,c as l,w as o,a as n,k as p,t as c,b as s,F as f,s as r,e as m,d as w}from"./vendor.6399378c.js";import{m as M}from"./index.086d0536.js";import{_ as B}from"./main.5fd30069.js";const C={setup(){const _=S(),A=D(()=>_.state.openApiDoc),u=D(()=>_.state.openApiDoc.info),e=D(()=>_.state.openApiMethodStatistic);return{openApiDoc:A,openApiDocInfo:u,openApiMethodStatistic:e,getDescription:I=>M.exports.markdownIt.render(I||"")}}},N=["href"],V=["href"],j=["href"],L=["innerHTML"],O={key:1,style:{"text-align":"center"}};function T(_,A,u,e,v,I){const a=i("a-form-item"),h=i("a-divider"),b=i("a-statistic"),k=i("a-card"),y=i("a-col"),g=i("a-row"),x=i("a-form");return t(),l(k,null,{default:o(()=>[e.openApiDocInfo?(t(),l(x,{key:0,"label-col":{span:4},"wrapper-col":{span:20}},{default:o(()=>[n(a,{label:"\u6807\u9898"},{default:o(()=>[p(c(e.openApiDocInfo.title),1)]),_:1}),n(a,{label:"\u7248\u672C"},{default:o(()=>[p(c(e.openApiDocInfo.version),1)]),_:1}),e.openApiDocInfo.contact?(t(),l(a,{key:0,label:"\u4F5C\u8005"},{default:o(()=>[e.openApiDocInfo.contact.name?(t(),s(f,{key:0},[p(c(e.openApiDocInfo.contact.name),1)],64)):r("",!0),e.openApiDocInfo.contact.email?(t(),s(f,{key:1},[n(h,{type:"vertical"}),p(c(e.openApiDocInfo.contact.email),1)],64)):r("",!0),e.openApiDocInfo.contact.url?(t(),s(f,{key:2},[n(h,{type:"vertical"}),m("a",{href:e.openApiDocInfo.contact.url,target:"_blank"},c(e.openApiDocInfo.contact.url),9,N)],64)):r("",!0)]),_:1})):r("",!0),n(a,{label:"host"},{default:o(()=>[p(c(e.openApiDoc.host),1)]),_:1}),e.openApiDocInfo.license?(t(),l(a,{key:1,label:"\u8BB8\u53EF\u8BC1"},{default:o(()=>[m("a",{href:e.openApiDocInfo.license.url,target:"_blank"},c(e.openApiDocInfo.license.name),9,V)]),_:1})):r("",!0),e.openApiDocInfo.termsOfService?(t(),l(a,{key:2,label:"\u670D\u52A1\u6761\u6B3E"},{default:o(()=>[m("a",{href:e.openApiDocInfo.termsOfService,target:"_blank"},c(e.openApiDocInfo.termsOfService),9,j)]),_:1})):r("",!0),n(a,{label:"\u6587\u6863\u8BF4\u660E"},{default:o(()=>[m("div",{class:"markdown-body",innerHTML:e.getDescription(e.openApiDocInfo.description)},null,8,L)]),_:1}),n(a,{label:"\u63A5\u53E3\u7EDF\u8BA1"},{default:o(()=>[n(g,{gutter:[16,16]},{default:o(()=>[(t(),s(f,null,w(["get","post","put","delete","head","patch","options","trace","total"],d=>(t(),s(f,null,[e.openApiMethodStatistic[d]?(t(),l(y,{key:0,span:6},{default:o(()=>[n(k,{size:"small"},{default:o(()=>[n(b,{title:d==="total"?"\u603B\u8BA1":d.toUpperCase()+"\u65B9\u6CD5",value:e.openApiMethodStatistic[d],suffix:"\u4E2A"},null,8,["title","value"])]),_:2},1024)]),_:2},1024)):r("",!0)],64))),64))]),_:1})]),_:1})]),_:1})):(t(),s("div",O,"\u6682\u65E0\u6587\u6863\u4FE1\u606F\uFF0C\u8BF7\u5148\u9009\u62E9\u6587\u6863"))]),_:1})}var z=B(C,[["render",T]]);export{z as default};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
import{v as y,u as j,y as n,W as k,r as h,o as g,c as v,w,B as x,e as D}from"./vendor.6399378c.js";import{D as I,o as _}from"./DocContent.6940f3d1.js";import{m as M}from"./index.086d0536.js";import{_ as q}from"./main.5fd30069.js";import"./logUtil.6309fa68.js";const C={components:{DocContent:I},setup(){const a=y(),t=j();let p=n("doc"),o=n([]),r=n([]),i=n({url:"",description:"",method:"",consumes:"",produces:""}),s=n(!1),c=0,l;const m=()=>{let P=a.query.path+"."+a.query.method;if(Object.keys(t.state.openApiUrlMethodMap).length<=0){console.log("\u6587\u6863\u5C1A\u672A\u52A0\u8F7D\uFF0C\u7B49\u5F85\u52A0\u8F7D\u5B8C\u6210"),l||(l=setInterval(()=>{if(s.value||c++>50){clearInterval(l);return}Object.keys(t.state.openApiUrlMethodMap).length>0&&(console.log("\u6587\u6863\u5185\u5BB9\u6539\u53D8\uFF0C\u91CD\u65B0\u52A0\u8F7D\u6587\u6863"),m())},1e3));return}let e=t.state.openApiUrlMethodMap[P];if(!e){x.error("\u6CA1\u6709\u627E\u5230\u5BF9\u5E94\u7684\u6587\u6863");return}s.value=!0,t.commit("addTableName",{key:a.fullPath,val:e.summary});let d="",u="";e.consumes&&e.consumes.length>0&&(d=e.consumes.join(" ")),e.produces&&e.produces.length>0&&(u=e.produces.join(" "));let L=M.exports.markdownIt.render(e.description||e.summary||"");i.value={url:e.url,description:L,method:e.method||"",consumes:d,produces:u};let f=t.state.openApiComponents;o.value=_.getRequestParamList(e.parameters,f),r.value=_.getResponseParamList(e.responses,f)};return k(()=>{m()}),{docInfoShow:i,activePage:p,changePage:()=>{},isLoadSuccess:s,requestParamList:o,responseParamList:r}}},S=D("div",{style:{padding:"20px 0",height:"100px"}},null,-1);function A(a,t,p,o,r,i){const s=h("DocContent"),c=h("a-spin");return o.isLoadSuccess?(g(),v(s,{key:0,docInfoShow:o.docInfoShow,requestParamList:o.requestParamList,responseParamList:o.responseParamList},null,8,["docInfoShow","requestParamList","responseParamList"])):(g(),v(c,{key:1,tip:"\u6587\u6863\u6570\u636E\u52A0\u8F7D\u4E2D..."},{default:w(()=>[S]),_:1}))}var T=q(C,[["render",A]]);export{T as default};

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
import{v as L,u as y,y as a,W as j,r as g,o as h,c as v,w as D,B as k,e as x}from"./vendor.6399378c.js";import{D as I,s as _}from"./DocContent.a9f68c91.js";import{m as M}from"./index.086d0536.js";import{_ as q}from"./main.5fd30069.js";import"./logUtil.6309fa68.js";const S={components:{DocContent:I},setup(){const r=L(),s=y();let m=a("doc"),t=a([]),n=a([]),c=a({url:"",description:"",method:"",consumes:"",produces:""}),o=a(!1),i=0,l;const u=()=>{let P=r.query.path+"."+r.query.method;if(Object.keys(s.state.swaggerUrlMethodMap).length<=0){console.log("\u6587\u6863\u5C1A\u672A\u52A0\u8F7D\uFF0C\u7B49\u5F85\u52A0\u8F7D\u5B8C\u6210"),l||(l=setInterval(()=>{if(o.value||i++>50){clearInterval(l);return}Object.keys(s.state.swaggerUrlMethodMap).length>0&&(console.log("\u6587\u6863\u5185\u5BB9\u6539\u53D8\uFF0C\u91CD\u65B0\u52A0\u8F7D\u6587\u6863"),u())},1e3));return}let e=s.state.swaggerUrlMethodMap[P];if(!e){k.error("\u6CA1\u6709\u627E\u5230\u5BF9\u5E94\u7684\u6587\u6863");return}o.value=!0,s.commit("addTableName",{key:r.fullPath,val:e.summary});let d="",p="";e.consumes&&e.consumes.length>0&&(d=e.consumes.join(" ")),e.produces&&e.produces.length>0&&(p=e.produces.join(" "));let w=M.exports.markdownIt.render(e.description||e.summary||"");c.value={url:e.url,description:w,method:e.method||"",consumes:d,produces:p};let f=s.state.swaggerDefinitions;t.value=_.getRequestParamList(e.parameters,f),n.value=_.getResponseParamList(e.responses,f)};return j(()=>{u()}),{docInfoShow:c,activePage:m,changePage:()=>{},isLoadSuccess:o,requestParamList:t,responseParamList:n}}},C=x("div",{style:{padding:"20px 0",height:"100px"}},null,-1);function B(r,s,m,t,n,c){const o=g("DocContent"),i=g("a-spin");return t.isLoadSuccess?(h(),v(o,{key:0,docInfoShow:t.docInfoShow,requestParamList:t.requestParamList,responseParamList:t.responseParamList},null,8,["docInfoShow","requestParamList","responseParamList"])):(h(),v(i,{key:1,tip:"\u6587\u6863\u6570\u636E\u52A0\u8F7D\u4E2D..."},{default:D(()=>[C]),_:1}))}var V=q(S,[["render",B]]);export{V as default};

View File

@@ -1 +0,0 @@
var K=Object.defineProperty;var I=Object.getOwnPropertySymbols;var N=Object.prototype.hasOwnProperty,O=Object.prototype.propertyIsEnumerable;var B=(s,e,a)=>e in s?K(s,e,{enumerable:!0,configurable:!0,writable:!0,value:a}):s[e]=a,x=(s,e)=>{for(var a in e||(e={}))N.call(e,a)&&B(s,a,e[a]);if(I)for(var a of I(e))O.call(e,a)&&B(s,a,e[a]);return s};import{z as V}from"./custom.471d0de0.js";import{P as S,a4 as U,R as j,u as A,y as L,W as F,r as m,o as l,b as u,e as z,a as d,w as n,F as f,c as k,t as G,s as g,B as R,k as c}from"./vendor.6399378c.js";import{_ as H}from"./main.5fd30069.js";const q={components:{PlusOutlined:S,SearchOutlined:U,ReloadOutlined:j},props:{dynamicParam:{type:Object,required:!0}},setup(s){const e=A();let a=L([]),t=L(!1);const h=async()=>{i.value={},t.value=!0,V.docApiGlobalParamList(s.dynamicParam).then(o=>{setTimeout(()=>t.value=!1,500),a.value=o.data||[],e.commit("setGlobalParamOnChange",a.value,s.dynamicParam.id)})};let i=L({}),D=L();const p=()=>{i.value.isEdit&&v(i.value);let o={isEdit:!0,paramType:1};a.value.unshift(o),i.value=o,setTimeout(()=>{let r=document.getElementsByClassName("ant-table-body")[0];r.scrollTop=0},0)},P=o=>{i.value.isEdit&&v(i.value),o.isEdit=!0,i.value=x({},o)},v=o=>{o.isEdit=!1,o.id?a.value.forEach(r=>r.isEdit=!1):a.value=a.value.filter(r=>r!==o),i.value={}},E=o=>{if(!i.value.paramKey||!i.value.paramValue){R.error("\u53C2\u6570\u540D\u6216\u53C2\u6570\u503C\u4E0D\u80FD\u4E3A\u7A7A");return}let r=x(x({},s.dynamicParam),i.value);V.docApiGlobalParamUpdate(r).then(w=>{o.isEdit=!1,h()})},T=async o=>{V.docApiGlobalParamUpdate({id:o.id,yn:0}).then(r=>{h()})};return F(()=>{h()}),{docList:a,docListLoading:t,docEdit:i,tableRef:D,searchDocList:h,deleteDoc:T,editDoc:P,saveEditDoc:E,cancelEditDoc:v,addDocLine:p,docListColumns:[{title:"\u53C2\u6570\u540D\u79F0",dataIndex:"paramKey",width:250},{title:"\u53C2\u6570\u503C",dataIndex:"paramValue"},{title:"\u53C2\u6570\u4F4D\u7F6E",dataIndex:"paramType",width:120},{title:"\u64CD\u4F5C",dataIndex:"operation",fixed:"right",width:170}]}}},M={style:{"margin-bottom":"10px","text-align":"right"}},W=c(" \u5237\u65B0"),J=c(" \u65B0\u5EFA"),Q={key:1},X={key:1},Y=c("Form"),Z=c("Header"),$=c("Cookie"),ee=c("Form"),ae=c("Header"),te=c("Cookie"),oe=c("\u53D6\u6D88"),ne=c("\u4FDD\u5B58"),le=c("\u7F16\u8F91"),ie=c("\u5220\u9664");function de(s,e,a,t,h,i){const D=m("reload-outlined"),p=m("a-button"),P=m("plus-outlined"),v=m("a-input"),E=m("a-select-option"),T=m("a-select"),o=m("a-tag"),r=m("a-popconfirm"),w=m("a-table");return l(),u(f,null,[z("div",M,[d(p,{onClick:t.searchDocList,type:"primary"},{icon:n(()=>[d(D)]),default:n(()=>[W]),_:1},8,["onClick"]),d(p,{onClick:t.addDocLine},{icon:n(()=>[d(P)]),default:n(()=>[J]),_:1},8,["onClick"])]),d(w,{dataSource:t.docList,columns:t.docListColumns,size:"middle",id:"paramTable",loading:t.docListLoading,pagination:!1,scroll:{x:1e3,y:"calc(100vh - 240px)"}},{bodyCell:n(({column:b,text:C,record:y})=>[b.dataIndex==="paramKey"?(l(),u(f,{key:0},[y.isEdit?(l(),k(v,{key:0,placeholder:"\u8BF7\u8F93\u5165\u53C2\u6570\u540D\u79F0",value:t.docEdit.paramKey,"onUpdate:value":e[0]||(e[0]=_=>t.docEdit.paramKey=_)},null,8,["value"])):(l(),u("span",Q,G(C),1))],64)):g("",!0),b.dataIndex==="paramValue"?(l(),u(f,{key:1},[y.isEdit?(l(),k(v,{key:0,rows:1,placeholder:"\u8BF7\u8F93\u5165\u53C2\u6570\u503C",value:t.docEdit.paramValue,"onUpdate:value":e[1]||(e[1]=_=>t.docEdit.paramValue=_)},null,8,["value"])):(l(),u("span",X,G(C),1))],64)):g("",!0),b.dataIndex==="paramType"?(l(),u(f,{key:2},[y.isEdit?(l(),k(T,{key:0,placeholder:"\u53C2\u6570\u4F4D\u7F6E",value:t.docEdit.paramType,"onUpdate:value":e[2]||(e[2]=_=>t.docEdit.paramType=_),style:{width:"110px"}},{default:n(()=>[d(E,{value:1},{default:n(()=>[Y]),_:1}),d(E,{value:2},{default:n(()=>[Z]),_:1}),d(E,{value:3},{default:n(()=>[$]),_:1})]),_:1},8,["value"])):(l(),u(f,{key:1},[C===1?(l(),k(o,{key:0,color:"green"},{default:n(()=>[ee]),_:1})):C===2?(l(),k(o,{key:1,color:"pink"},{default:n(()=>[ae]),_:1})):C===3?(l(),k(o,{key:2,color:"pink"},{default:n(()=>[te]),_:1})):g("",!0)],64))],64)):g("",!0),b.dataIndex==="operation"?(l(),u(f,{key:3},[y.isEdit?(l(),u(f,{key:0},[d(p,{type:"link",onClick:_=>t.cancelEditDoc(y)},{default:n(()=>[oe]),_:2},1032,["onClick"]),d(p,{type:"link",onClick:_=>t.saveEditDoc(y)},{default:n(()=>[ne]),_:2},1032,["onClick"])],64)):(l(),u(f,{key:1},[d(p,{type:"link",onClick:_=>t.editDoc(y)},{default:n(()=>[le]),_:2},1032,["onClick"]),d(r,{title:"\u786E\u5B9A\u8981\u5220\u9664\u5417\uFF1F",onConfirm:_=>t.deleteDoc(y)},{default:n(()=>[d(p,{type:"link",danger:""},{default:n(()=>[ie]),_:1})]),_:2},1032,["onConfirm"])],64))],64)):g("",!0)]),_:1},8,["dataSource","columns","loading","scroll"])],64)}var _e=H(q,[["render",de]]);export{_e as E};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
import"./custom.471d0de0.js";import{E as a}from"./EditGlobalParam.ede9d5a9.js";import{_ as r}from"./main.5fd30069.js";import{r as t,o as e,c as s}from"./vendor.6399378c.js";const m={components:{EditGlobalParam:a},setup(){return{}}};function n(c,d,p,l,i,_){const o=t("EditGlobalParam");return e(),s(o,{"dynamic-param":{docId:0}})}var G=r(m,[["render",n]]);export{G as default};

View File

@@ -1 +0,0 @@
import{_ as e}from"./main.5fd30069.js";import{o as t,b as o}from"./vendor.6399378c.js";const n={name:"SettingView",components:{},data(){return{}},computed:{},mounted(){},methods:{}};function r(a,s,c,m,d,i){return t(),o("div",null," \u5C55\u793A\u914D\u7F6E\u9875\u9762 ")}var f=e(n,[["render",r]]);export{f as default};

View File

@@ -1 +0,0 @@
import{u as p,y as g,W as f,N as x,o as i,b as l,e as _,F as k,d as L,af as N,ag as C,t as I,a9 as S,r as m,a as v,w as u,c as H,s as A}from"./vendor.6399378c.js";import{m as T}from"./index.086d0536.js";import{_ as y}from"./main.5fd30069.js";const D={props:{heading:{type:Array,default:[]}},setup(r){const s=p();let a=g("100px");f(()=>{window.onresize=()=>{n()},setTimeout(()=>{n()},100)}),x(s.getters.getLeftAsideWidth,()=>{n()});let e=g();const n=()=>{a.value=window.getComputedStyle(e.value,null).width};return{navigationRef:e,navigationWidth:a,headingItemClick:t=>{t.node.scrollIntoView({behavior:"smooth",block:"start",inline:"nearest"})}}}},b={class:"navigation"},W={ref:"navigationRef",style:{display:"inline-block",width:"100%",height:"1px"}},B=["onClick"];function M(r,s,a,e,n,c){return i(),l("div",b,[_("div",W,null,512),_("div",{class:"navigation-heading",style:N({width:e.navigationWidth})},[(i(!0),l(k,null,L(a.heading,t=>(i(),l("div",{class:C("heading-item heading-"+t.level),onClick:o=>e.headingItemClick(t)},I(t.text),11,B))),256))],4)])}var R=y(D,[["render",M]]);const V={components:{Navigation:R},setup(){const r=p(),s=S(()=>r.state.apiDoc);let a=g();x(r.getters.getApiDoc,()=>{setTimeout(()=>{c(".share-instruction")},100)});const e=t=>T.exports.markdownIt.render(t||"");let n=g([]);const c=t=>{if(!document.querySelector(t))return[];let o=document.querySelector(t).querySelectorAll("h1,h2,h3,h4,h5,h6");if(o.length<=0)return[];let d=[];o.forEach(h=>{let w=h.innerHTML.replace(/^\s+/g,"").replace(/\s+$/g,"").replace(/<\/?[^>]+(>|$)/g,"");d.push({node:h,level:parseInt(h.tagName.replace(/[h]/i,""),10),text:w})}),n.value=d};return f(()=>{}),{apiDoc:s,navigationRef:a,navigationList:n,markdownToHtml:e}}},$={key:0},j=["innerHTML"],q={key:1,style:{"text-align":"center"}};function z(r,s,a,e,n,c){const t=m("Navigation"),o=m("a-col"),d=m("a-row");return e.apiDoc.shareInstruction?(i(),l("div",$,[v(d,null,{default:u(()=>[e.navigationList.length>0?(i(),H(o,{key:0,xs:0,sm:4,md:4,lg:6,xl:6},{default:u(()=>[v(t,{ref:"navigationRef",heading:e.navigationList},null,8,["heading"])]),_:1})):A("",!0),v(o,{xs:24,sm:e.navigationList.length>0?20:24,md:e.navigationList.length>0?20:24,lg:e.navigationList.length>0?18:24,xl:e.navigationList.length>0?18:24},{default:u(()=>[_("div",{class:"markdown-body share-instruction",innerHTML:e.markdownToHtml(e.apiDoc.shareInstruction),style:{margin:"0 auto","max-width":"1000px"}},null,8,j)]),_:1},8,["sm","md","lg","xl"])]),_:1})])):(i(),l("div",q,"\u6B22\u8FCE\u8BBF\u95EE\u5F00\u653EAPI\u6587\u6863"))}var G=y(V,[["render",z]]);export{G as default};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

View File

@@ -1 +0,0 @@
var E=Object.defineProperty,I=Object.defineProperties;var O=Object.getOwnPropertyDescriptors;var L=Object.getOwnPropertySymbols;var b=Object.prototype.hasOwnProperty,D=Object.prototype.propertyIsEnumerable;var x=(r,e,t)=>e in r?E(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t,m=(r,e)=>{for(var t in e||(e={}))b.call(e,t)&&x(r,t,e[t]);if(L)for(var t of L(e))D.call(e,t)&&x(r,t,e[t]);return r},_=(r,e)=>I(r,O(e));import{_ as k}from"./main.5fd30069.js";import{W as M,y as v,o as j,b as z,e as R}from"./vendor.6399378c.js";const A=["get","head","post","put","patch","delete","options","trace"];function q(r){let e={},t={},n={},h=r.paths;return h?(Object.keys(h).forEach(o=>{let l=h[o];for(let a of A){if(!l[a]||!l[a].tags)continue;let i=a.toLowerCase();n[i]=(n[i]||0)+1,n.total=(n.total||0)+1,l[a].tags.forEach(f=>{let d=e[f];d||(d=e[f]={});let s=d[o];s||(s=d[o]={});let c=o+"."+a;s[a]=l[a],s[a].path=c,s[a].url=o,s[a].method=a,t[c]=l[a]})}}),{urlMethodMap:t,tagPathMap:e,methodStatistic:n}):{urlMethodMap:t,tagPathMap:e,methodStatistic:n}}function G(r,e,t,n){let h=[],o=1,l=r.tags||[];return l.length<=0&&Object.keys(e).forEach(a=>l.push({name:a})),l.forEach(a=>{let i=1,f=[],d=e[a.name];!d||(Object.keys(d).forEach(s=>{let c=1,p=d[s];Object.keys(p).forEach(y=>{let g=o+"_"+i+"_"+c,u=p[y];if(!$(s,u,t))return;u.treeId=g;let T=u.summary||u.path;f.push({title:T,key:g,isLeaf:!0,method:u.method,query:_(m({},n),{path:u.url,method:u.method})}),c++}),i++}),f.length>0&&h.push({title:a.name,key:o,children:f}),o++)}),[{key:"main",title:r.info.title||"Swagger\u63A5\u53E3\u6587\u6863",children:h}]}function $(r,e,t){if(!t||!r||(r=r.toLowerCase(),t=t.toLowerCase(),r.indexOf(t)>=0))return!0;let n=e.path+e.method+e.summary+e.description+e.tags;return n&&n.toLowerCase().indexOf(t)>=0}const P=["get","head","post","put","patch","delete","options","trace"];function H(r){let e={},t={},n={},h=r.paths;return h?(Object.keys(h).forEach(o=>{let l=h[o];for(let a of P){if(!l[a]||!l[a].tags)continue;let i=a.toLowerCase();n[i]=(n[i]||0)+1,n.total=(n.total||0)+1,l[a].tags.forEach(f=>{let d=e[f];d||(d=e[f]={});let s=d[o];s||(s=d[o]={});let c=o+"."+a;s[a]=l[a],s[a].path=c,s[a].url=o,s[a].method=a,t[c]=l[a]})}}),{urlMethodMap:t,tagPathMap:e,methodStatistic:n}):{urlMethodMap:t,tagPathMap:e,methodStatistic:n}}function J(r,e,t,n){let h=[],o=1,l=r.tags||[];return l.length<=0&&Object.keys(e).forEach(a=>l.push({name:a})),l.forEach(a=>{let i=1,f=[],d=e[a.name];!d||(Object.keys(d).forEach(s=>{let c=1,p=d[s];Object.keys(p).forEach(y=>{let g=o+"_"+i+"_"+c,u=p[y];if(!B(s,u,t))return;u.treeId=g;let T=u.summary||u.path;f.push({title:T,key:g,isLeaf:!0,method:u.method,query:_(m({},n),{path:u.url,method:u.method})}),c++}),i++}),f.length>0&&h.push({title:a.name,key:o,children:f}),o++)}),[{key:"main",title:r.info.title||"OpenApi\u63A5\u53E3\u6587\u6863",children:h}]}function B(r,e,t){if(!t||!r||(r=r.toLowerCase(),t=t.toLowerCase(),r.indexOf(t)>=0))return!0;let n=e.path+e.method+e.summary+e.description+e.tags;return n&&n.toLowerCase().indexOf(t)>=0}function K(r,e,t,n){let h=r[0],o=C(h,e,t,n,1);return[{key:"main",isLeaf:!1,title:h.name||"\u81EA\u5EFAAPI\u63A5\u53E3\u6587\u6863",children:o}]}function C(r,e,t,n,h){let o=[];if(!r)return o;let l=1,a=1;return r.children&&r.children.length>0&&r.children.forEach(i=>{n.originNodeMap[i.nodeId]=i;let f=h+"_"+l+"_"+a;if(i.nodeType===1)o.push({title:i.nodeName,key:f,isLeaf:!0,method:i.method,nodeId:i.nodeId,query:_(m({},t),{nodeId:i.nodeId})}),a++;else{let d=C(i,e,t,n,f),s=U(i,e);(d.length>0||s)&&(o.push({title:i.nodeName,key:f,nodeId:i.nodeId,isLeaf:!1,editing:!1,titleEditing:i.nodeName,children:d}),a++)}}),l++,o}function U(r,e){if(!e||!r)return!0;e=e.toLowerCase();let t=r.name;return t&&t.toLowerCase().indexOf(e)>=0}const w={emits:["update:value","change"],setup(r,{emit:e}){M(()=>{o()});let t=v(300),n=v(),h=v();const o=()=>{let l=n.value,a=h.value;l.onmousedown=i=>{let f=i.clientX;return l.style.background="#ccc",a.style.background="#aaa",l.left=l.offsetLeft,document.onmousemove=d=>{let s=d.clientX,c=f-s;(c<0&&t.value<600||c>0&&t.value>300)&&(f=s,t.value-=c,t.value<300&&(t.value=300),e("update:value",t.value),e("change",t.value))},document.onmouseup=()=>{l.style.background="#fafafa",a.style.background="#ccc",document.onmousemove=null,document.onmouseup=null},!1}};return{leftAsideWidth:t,leftResizeRef:n,leftResizeBarRef:h}}},F={ref:"leftResizeRef",class:"left-resize"},S={ref:"leftResizeBarRef"};function X(r,e,t,n,h,o){return j(),z("div",F,[R("i",S,"...",512)],512)}var Q=k(w,[["render",X],["__scopeId","data-v-33303c20"]]),Y="assets/api-logo.952f0c92.png";export{Q as L,Y as _,q as a,H as b,J as c,K as d,G as g};

File diff suppressed because one or more lines are too long

View File

@@ -1,72 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>Copyright (C) 2017 by original authors @ fontello.com</metadata>
<defs>
<font id="fontello" horiz-adv-x="1000" >
<font-face font-family="fontello" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
<missing-glyph horiz-adv-x="1000" />
<glyph glyph-name="bold" unicode="&#xe800;" d="M310 1q41-18 78-18 210 0 210 187 0 64-23 101-15 24-34 41t-38 26-45 14-47 6-53 1q-40 0-56-6 0-29 0-88t-1-88q0-5 0-38t0-54 2-47 7-37z m-8 417q23-4 61-4 46 0 80 7t61 25 42 50 14 79q0 39-16 68t-45 46-60 24-69 8q-28 0-73-7 0-28 3-84t2-85q0-15 0-45t-1-44q0-26 1-38z m-302-497l1 53q9 2 48 9t59 15q4 7 7 15t4 19 4 18 1 21 0 19v36q0 548-12 572-2 5-12 8t-25 6-28 4-27 3-17 2l-2 46q55 1 190 6t208 6q13 0 38-1t38 0q39 0 76-7t72-24 60-39 41-59 16-76q0-29-9-54t-22-40-36-32-41-25-47-22q86-20 144-75t57-138q0-56-20-101t-52-72-77-48-91-27-98-8q-25 0-74 2t-74 1q-59 0-171-6t-129-7z" horiz-adv-x="785.7" />
<glyph glyph-name="italic" unicode="&#xe801;" d="M0-78l10 48q12 4 34 9t40 11 33 13q16 19 23 56 1 4 35 162t63 303 29 165v14q-13 8-30 11t-39 4-32 3l10 58q19-1 67-4t84-4 67-1q27 0 55 1t68 4 54 4q-2-22-10-50-17-6-57-16t-60-19q-5-10-8-23t-5-23-4-25-4-24q-15-82-49-234t-43-198q-1-5-7-32t-11-51-9-46-4-32l1-10q9-3 103-18-2-24-9-55-6 0-18-1t-18-1q-16 0-49 6t-48 6q-77 1-115 1-28 0-79-5t-68-7z" horiz-adv-x="571.4" />
<glyph glyph-name="thumb-tack" unicode="&#xe802;" d="M650 779q12 0 24-5 19-8 29-23t11-35v-719q0-19-11-35t-29-23q-10-4-24-4-27 0-47 18l-246 236-246-236q-20-19-46-19-13 0-25 5-18 7-29 23t-11 35v719q0 19 11 35t29 23q12 5 25 5h585z" horiz-adv-x="714.3" />
<glyph glyph-name="link" unicode="&#xe803;" d="M813 171q0 23-16 38l-116 116q-16 16-38 16-24 0-40-18 1-1 10-10t12-12 9-11 7-14 2-15q0-23-16-38t-38-16q-8 0-15 2t-14 7-11 9-12 12-10 10q-19-17-19-40 0-23 16-38l115-116q15-15 38-15 22 0 38 15l82 81q16 16 16 37z m-393 394q0 22-15 38l-115 115q-16 16-38 16-22 0-38-15l-82-82q-16-15-16-37 0-22 16-38l116-116q15-15 38-15 23 0 40 17-2 2-11 11t-12 12-8 10-7 14-2 16q0 22 15 38t38 15q9 0 16-2t14-7 11-8 12-12 10-11q18 17 18 41z m500-394q0-66-48-113l-82-81q-46-47-113-47-68 0-114 48l-115 115q-46 47-46 114 0 68 49 116l-49 49q-48-49-116-49-67 0-114 47l-116 116q-47 47-47 114t47 113l82 82q47 46 114 46 67 0 114-47l115-116q46-46 46-113 0-69-49-117l49-49q48 49 116 49 67 0 114-47l116-116q47-47 47-114z" horiz-adv-x="928.6" />
<glyph glyph-name="picture-o" unicode="&#xe804;" d="M357 529q0-45-31-76t-76-32-76 32-31 76 31 76 76 31 76-31 31-76z m572-215v-250h-786v107l178 179 90-89 285 285z m53 393h-893q-7 0-12-5t-6-13v-678q0-7 6-13t12-5h893q7 0 13 5t5 13v678q0 8-5 13t-13 5z m89-18v-678q0-37-26-63t-63-27h-893q-36 0-63 27t-26 63v678q0 37 26 63t63 27h893q37 0 63-27t26-63z" horiz-adv-x="1071.4" />
<glyph glyph-name="repeat" unicode="&#xe805;" d="M857 707v-250q0-14-10-25t-26-11h-250q-23 0-32 23-10 22 7 38l77 77q-82 77-194 77-58 0-111-23t-91-61-61-91-23-111 23-111 61-91 91-61 111-23q66 0 125 29t100 82q4 6 13 7 8 0 14-5l76-77q5-4 6-11t-5-13q-60-74-147-114t-182-41q-87 0-167 34t-136 92-92 137-34 166 34 166 92 137 136 92 167 34q82 0 158-31t137-88l72 72q17 18 39 8 22-9 22-33z" horiz-adv-x="857.1" />
<glyph glyph-name="undo" unicode="&#xe806;" d="M857 350q0-87-34-166t-91-137-137-92-166-34q-96 0-183 41t-147 114q-4 6-4 13t5 11l76 77q6 5 14 5 9-1 13-7 41-53 100-82t126-29q58 0 110 23t92 61 61 91 22 111-22 111-61 91-92 61-110 23q-55 0-105-20t-90-57l77-77q17-16 8-38-10-23-33-23h-250q-15 0-25 11t-11 25v250q0 24 22 33 22 10 39-8l72-72q60 57 137 88t159 31q87 0 166-34t137-92 91-137 34-166z" horiz-adv-x="857.1" />
<glyph glyph-name="trash-o" unicode="&#xe807;" d="M286 439v-321q0-8-5-13t-13-5h-36q-8 0-13 5t-5 13v321q0 8 5 13t13 5h36q8 0 13-5t5-13z m143 0v-321q0-8-5-13t-13-5h-36q-8 0-13 5t-5 13v321q0 8 5 13t13 5h36q8 0 13-5t5-13z m142 0v-321q0-8-5-13t-12-5h-36q-8 0-13 5t-5 13v321q0 8 5 13t13 5h36q7 0 12-5t5-13z m72-404v529h-500v-529q0-12 4-22t8-15 6-5h464q2 0 6 5t8 15 4 22z m-375 601h250l-27 65q-4 5-9 6h-177q-6-1-10-6z m518-18v-36q0-8-5-13t-13-5h-54v-529q0-46-26-80t-63-34h-464q-37 0-63 33t-27 79v531h-53q-8 0-13 5t-5 13v36q0 8 5 13t13 5h172l39 93q9 21 31 35t44 15h178q23 0 44-15t30-35l39-93h173q8 0 13-5t5-13z" horiz-adv-x="785.7" />
<glyph glyph-name="floppy-o" unicode="&#xe808;" d="M214-7h429v214h-429v-214z m500 0h72v500q0 8-6 21t-11 20l-157 156q-5 6-19 12t-22 5v-232q0-22-15-38t-38-16h-322q-22 0-37 16t-16 38v232h-72v-714h72v232q0 22 16 38t37 16h465q22 0 38-16t15-38v-232z m-214 518v178q0 8-5 13t-13 5h-107q-7 0-13-5t-5-13v-178q0-7 5-13t13-5h107q7 0 13 5t5 13z m357-18v-518q0-22-15-38t-38-16h-750q-23 0-38 16t-16 38v750q0 22 16 38t38 16h517q23 0 50-12t42-26l156-157q16-15 27-42t11-49z" horiz-adv-x="857.1" />
<glyph glyph-name="compress" unicode="&#xe809;" d="M429 314v-250q0-14-11-25t-25-10-25 10l-81 81-185-186q-5-5-13-5t-12 5l-64 64q-6 6-6 13t6 13l185 185-80 80q-11 11-11 25t11 25 25 11h250q14 0 25-11t11-25z m421 375q0-7-6-12l-185-186 80-80q11-11 11-25t-11-25-25-11h-250q-14 0-25 11t-10 25v250q0 14 10 25t25 10 25-10l81-80 185 185q6 5 13 5t13-5l63-64q6-5 6-13z" horiz-adv-x="857.1" />
<glyph glyph-name="eye" unicode="&#xe80a;" d="M929 314q-85 132-213 197 34-58 34-125 0-103-73-177t-177-73-177 73-73 177q0 67 34 125-128-65-213-197 75-114 187-182t242-68 243 68 186 182z m-402 215q0 11-8 19t-19 7q-70 0-120-50t-50-119q0-11 8-19t19-8 19 8 8 19q0 48 34 82t82 34q11 0 19 8t8 19z m473-215q0-19-11-38-78-129-210-206t-279-77-279 77-210 206q-11 19-11 38t11 39q78 128 210 205t279 78 279-78 210-205q11-20 11-39z" horiz-adv-x="1000" />
<glyph glyph-name="eye-slash" unicode="&#xe80b;" d="M310 105l43 79q-48 35-76 88t-27 114q0 67 34 125-128-65-213-197 94-144 239-209z m217 424q0 11-8 19t-19 7q-70 0-120-50t-50-119q0-11 8-19t19-8 19 8 8 19q0 48 34 82t82 34q11 0 19 8t8 19z m202 106q0-4 0-5-59-105-176-316t-176-316l-28-50q-5-9-15-9-7 0-75 39-9 6-9 16 0 7 25 49-80 36-147 96t-117 137q-11 17-11 38t11 39q86 131 212 207t277 76q50 0 100-10l31 54q5 9 15 9 3 0 10-3t18-9 18-10 18-10 10-7q9-5 9-15z m21-249q0-78-44-142t-117-91l157 280q4-25 4-47z m250-72q0-19-11-38-22-36-61-81-84-96-194-149t-234-53l41 74q119 10 219 76t169 171q-65 100-158 164l35 63q53-36 102-85t81-103q11-19 11-39z" horiz-adv-x="1000" />
<glyph glyph-name="question-circle" unicode="&#xe80c;" d="M500 82v107q0 8-5 13t-13 5h-107q-8 0-13-5t-5-13v-107q0-8 5-13t13-5h107q8 0 13 5t5 13z m143 375q0 49-31 91t-77 65-95 23q-136 0-207-119-9-13 4-24l74-55q4-4 10-4 9 0 14 7 30 38 48 51 19 14 48 14 27 0 48-15t21-33q0-21-11-34t-38-25q-35-15-65-48t-29-70v-20q0-8 5-13t13-5h107q8 0 13 5t5 13q0 10 12 27t30 28q18 10 28 16t25 19 25 27 16 34 7 45z m214-107q0-117-57-215t-156-156-215-58-216 58-155 156-58 215 58 215 155 156 216 58 215-58 156-156 57-215z" horiz-adv-x="857.1" />
<glyph glyph-name="times" unicode="&#xe80d;" d="M724 112q0-22-15-38l-76-76q-16-15-38-15t-38 15l-164 165-164-165q-16-15-38-15t-38 15l-76 76q-16 16-16 38t16 38l164 164-164 164q-16 16-16 38t16 38l76 76q16 16 38 16t38-16l164-164 164 164q16 16 38 16t38-16l76-76q15-15 15-38t-15-38l-164-164 164-164q15-15 15-38z" horiz-adv-x="785.7" />
<glyph glyph-name="align-left" unicode="&#xe80f;" d="M1000 100v-71q0-15-11-25t-25-11h-928q-15 0-25 11t-11 25v71q0 15 11 25t25 11h928q15 0 25-11t11-25z m-214 214v-71q0-15-11-25t-25-11h-714q-15 0-25 11t-11 25v71q0 15 11 25t25 11h714q15 0 25-11t11-25z m143 215v-72q0-14-11-25t-25-11h-857q-15 0-25 11t-11 25v72q0 14 11 25t25 10h857q14 0 25-10t11-25z m-215 214v-72q0-14-10-25t-25-10h-643q-15 0-25 10t-11 25v72q0 14 11 25t25 11h643q14 0 25-11t10-25z" horiz-adv-x="1000" />
<glyph glyph-name="align-center" unicode="&#xe810;" d="M1000 100v-71q0-15-11-25t-25-11h-928q-15 0-25 11t-11 25v71q0 15 11 25t25 11h928q15 0 25-11t11-25z m-214 214v-71q0-15-11-25t-25-11h-500q-14 0-25 11t-11 25v71q0 15 11 25t25 11h500q15 0 25-11t11-25z m143 215v-72q0-14-11-25t-25-11h-786q-14 0-25 11t-11 25v72q0 14 11 25t25 10h786q14 0 25-10t11-25z m-215 214v-72q0-14-10-25t-25-10h-358q-14 0-25 10t-10 25v72q0 14 10 25t25 11h358q14 0 25-11t10-25z" horiz-adv-x="1000" />
<glyph glyph-name="align-right" unicode="&#xe811;" d="M1000 100v-71q0-15-11-25t-25-11h-928q-15 0-25 11t-11 25v71q0 15 11 25t25 11h928q15 0 25-11t11-25z m0 214v-71q0-15-11-25t-25-11h-714q-14 0-25 11t-11 25v71q0 15 11 25t25 11h714q15 0 25-11t11-25z m0 215v-72q0-14-11-25t-25-11h-857q-14 0-25 11t-11 25v72q0 14 11 25t25 10h857q15 0 25-10t11-25z m0 214v-72q0-14-11-25t-25-10h-643q-14 0-25 10t-10 25v72q0 14 10 25t25 11h643q15 0 25-11t11-25z" horiz-adv-x="1000" />
<glyph glyph-name="arrows-alt" unicode="&#xf0b2;" d="M716 548l-198-198 198-198 80 80q17 18 39 8 22-9 22-33v-250q0-14-10-25t-26-11h-250q-23 0-32 23-10 21 7 38l81 81-198 198-198-198 80-81q17-17 8-38-10-23-33-23h-250q-15 0-25 11t-11 25v250q0 24 22 33 22 10 39-8l80-80 198 198-198 198-80-80q-11-11-25-11-7 0-14 3-22 9-22 33v250q0 14 11 25t25 11h250q23 0 33-23 9-21-8-38l-80-81 198-198 198 198-81 81q-17 17-7 38 9 23 32 23h250q15 0 26-11t10-25v-250q0-24-22-33-7-3-14-3-14 0-25 11z" horiz-adv-x="857.1" />
<glyph glyph-name="bars" unicode="&#xf0c9;" d="M857 100v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 25t25 11h785q15 0 26-11t10-25z m0 286v-72q0-14-10-25t-26-10h-785q-15 0-25 10t-11 25v72q0 14 11 25t25 10h785q15 0 26-10t10-25z m0 285v-71q0-14-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 26t25 10h785q15 0 26-10t10-26z" horiz-adv-x="857.1" />
<glyph glyph-name="list-ul" unicode="&#xf0ca;" d="M214 64q0-44-31-76t-76-31-76 31-31 76 31 76 76 31 76-31 31-76z m0 286q0-45-31-76t-76-31-76 31-31 76 31 76 76 31 76-31 31-76z m786-232v-107q0-7-5-13t-13-5h-678q-8 0-13 5t-5 13v107q0 7 5 12t13 6h678q7 0 13-6t5-12z m-786 518q0-45-31-76t-76-31-76 31-31 76 31 76 76 31 76-31 31-76z m786-232v-108q0-7-5-12t-13-5h-678q-8 0-13 5t-5 12v108q0 7 5 12t13 5h678q7 0 13-5t5-12z m0 285v-107q0-7-5-12t-13-6h-678q-8 0-13 6t-5 12v107q0 8 5 13t13 5h678q7 0 13-5t5-13z" horiz-adv-x="1000" />
<glyph glyph-name="list-ol" unicode="&#xf0cb;" d="M213-54q0-45-31-70t-75-26q-60 0-96 37l31 49q28-25 60-25 16 0 28 8t12 24q0 35-59 31l-14 31q4 6 18 24t24 31 20 21v1q-9 0-27-1t-27 0v-30h-59v85h186v-49l-53-65q28-6 45-27t17-49z m1 350v-89h-202q-4 20-4 30 0 29 14 52t31 38 37 27 31 24 14 25q0 14-9 22t-22 7q-25 0-45-32l-47 33q13 28 40 44t59 16q40 0 68-23t28-63q0-28-19-51t-42-36-42-28-20-30h71v34h59z m786-178v-107q0-7-5-13t-13-5h-678q-8 0-13 5t-5 13v107q0 8 5 13t13 5h678q7 0 13-6t5-12z m-786 502v-56h-187v56h60q0 22 0 67t1 68v7h-1q-5-10-28-30l-40 42 76 71h59v-225h60z m786-216v-108q0-7-5-12t-13-5h-678q-8 0-13 5t-5 12v108q0 7 5 12t13 5h678q7 0 13-5t5-12z m0 285v-107q0-7-5-12t-13-6h-678q-8 0-13 6t-5 12v107q0 8 5 13t13 5h678q7 0 13-5t5-13z" horiz-adv-x="1000" />
<glyph glyph-name="strikethrough" unicode="&#xf0cc;" d="M982 350q8 0 13-5t5-13v-36q0-7-5-12t-13-5h-964q-8 0-13 5t-5 12v36q0 8 5 13t13 5h964z m-712 36q-16 19-29 44-27 55-27 105 0 101 75 173 74 71 219 71 28 0 94-11 36-7 98-27 6-21 12-66 8-68 8-102 0-10-3-25l-7-2-46 4-8 1q-28 83-58 114-49 51-117 51-64 0-101-33-38-32-38-81 0-41 37-78t156-72q38-12 96-37 33-16 53-29h-414z m283-143h229q4-22 4-51 0-62-23-119-13-31-40-58-20-19-61-45-44-27-85-37-45-12-113-12-64 0-109 13l-78 23q-32 8-40 15-5 5-5 12v8q0 60-1 87 0 17 0 38l1 20v25l57 1q8-19 17-40t12-31 7-15q20-32 45-52 24-20 59-32 33-12 73-12 36 0 78 15 43 14 68 48 26 34 26 72 0 47-45 87-19 16-76 40z" horiz-adv-x="1000" />
<glyph glyph-name="underline" unicode="&#xf0cd;" d="M27 726q-21 1-25 2l-2 49q7 1 22 1 34 0 63-3 74-4 93-4 47 0 93 2 65 2 82 3 31 0 48 1l-1-8 1-36v-5q-33-5-69-5-33 0-44-14-7-7-7-73 0-7 0-18t0-15l1-127 8-157q3-69 28-112 20-33 54-52 49-26 98-26 59 0 107 16 31 10 55 28 27 20 37 36 20 31 29 63 12 41 12 128 0 44-2 72t-6 68-8 89l-2 33q-3 37-13 49-19 20-43 19l-56-1-8 2 1 48h47l114-6q43-2 110 6l10-1q3-22 3-29 0-4-2-17-25-7-47-8-41-6-44-9-8-8-8-23 0-4 0-15t1-17q5-11 13-221 3-109-9-170-8-42-23-68-21-36-62-69-42-31-102-49-61-19-142-19-93 0-159 26-66 26-99 68-34 42-47 109-9 45-9 132v186q0 105-9 119-14 20-82 22z m830-787v36q0 8-5 13t-13 5h-821q-8 0-13-5t-5-13v-36q0-8 5-13t13-5h821q8 0 13 5t5 13z" horiz-adv-x="857.1" />
<glyph glyph-name="table" unicode="&#xf0ce;" d="M286 82v107q0 8-5 13t-13 5h-179q-7 0-12-5t-6-13v-107q0-8 6-13t12-5h179q8 0 13 5t5 13z m0 214v108q0 7-5 12t-13 5h-179q-7 0-12-5t-6-12v-108q0-7 6-12t12-5h179q8 0 13 5t5 12z m285-214v107q0 8-5 13t-12 5h-179q-8 0-13-5t-5-13v-107q0-8 5-13t13-5h179q7 0 12 5t5 13z m-285 429v107q0 8-5 13t-13 5h-179q-7 0-12-5t-6-13v-107q0-8 6-13t12-5h179q8 0 13 5t5 13z m285-215v108q0 7-5 12t-12 5h-179q-8 0-13-5t-5-12v-108q0-7 5-12t13-5h179q7 0 12 5t5 12z m286-214v107q0 8-5 13t-13 5h-178q-8 0-13-5t-5-13v-107q0-8 5-13t13-5h178q8 0 13 5t5 13z m-286 429v107q0 8-5 13t-12 5h-179q-8 0-13-5t-5-13v-107q0-8 5-13t13-5h179q7 0 12 5t5 13z m286-215v108q0 7-5 12t-13 5h-178q-8 0-13-5t-5-12v-108q0-7 5-12t13-5h178q8 0 13 5t5 12z m0 215v107q0 8-5 13t-13 5h-178q-8 0-13-5t-5-13v-107q0-8 5-13t13-5h178q8 0 13 5t5 13z m72 178v-607q0-37-27-63t-63-26h-750q-36 0-63 26t-26 63v607q0 37 26 63t63 27h750q37 0 63-27t27-63z" horiz-adv-x="928.6" />
<glyph glyph-name="columns" unicode="&#xf0db;" d="M89-7h340v643h-358v-625q0-7 6-13t12-5z m768 18v625h-357v-643h339q8 0 13 5t5 13z m72 678v-678q0-37-27-63t-63-27h-750q-36 0-63 27t-26 63v678q0 37 26 63t63 27h750q37 0 63-27t27-63z" horiz-adv-x="928.6" />
<glyph glyph-name="quote-left" unicode="&#xf10d;" d="M429 314v-214q0-45-32-76t-76-31h-214q-44 0-76 31t-31 76v393q0 58 23 111t61 91 91 61 111 23h35q15 0 26-11t10-25v-72q0-14-10-25t-26-10h-35q-59 0-101-42t-42-101v-18q0-22 16-38t37-16h125q45 0 76-31t32-76z m500 0v-214q0-45-32-76t-76-31h-214q-44 0-76 31t-31 76v393q0 58 23 111t61 91 91 61 111 23h35q15 0 26-11t10-25v-72q0-14-10-25t-26-10h-35q-59 0-101-42t-42-101v-18q0-22 16-38t37-16h125q45 0 76-31t32-76z" horiz-adv-x="928.6" />
<glyph glyph-name="code" unicode="&#xf121;" d="M344 69l-28-28q-5-5-12-5t-13 5l-260 261q-6 5-6 12t6 13l260 260q5 6 13 6t12-6l28-28q6-5 6-13t-6-12l-219-220 219-219q6-6 6-13t-6-13z m330 596l-208-721q-2-7-9-11t-13-1l-34 9q-8 3-11 9t-2 14l209 720q2 8 8 11t13 2l35-10q7-2 11-9t1-13z m367-363l-260-261q-6-5-13-5t-13 5l-28 28q-5 6-5 13t5 13l219 219-219 220q-5 5-5 12t5 13l28 28q6 6 13 6t13-6l260-260q5-5 5-13t-5-12z" horiz-adv-x="1071.4" />
<glyph glyph-name="superscript" unicode="&#xf12b;" d="M501 86v-93h-139l-89 141-13 23q-4 5-6 12h-2q0-2-1-4t-2-4-2-4q-5-11-14-25l-86-139h-144v93h71l110 162-103 152h-76v94h154l77-127q1-2 13-24 4-5 6-11h2q1 5 6 11l14 24 78 127h143v-94h-69l-103-149 114-165h61z m355 379v-115h-287l-1 15q-3 16-3 26 0 36 15 65t36 48 47 37 47 30 36 30 15 36q0 21-17 35t-39 13q-29 0-54-21-8-6-20-22l-59 52q15 20 35 37 47 36 105 36 61 0 99-33t38-89q0-31-13-57t-35-43-45-33-46-28-37-28-17-36h130v45h70z" horiz-adv-x="857.1" />
<glyph glyph-name="subscript" unicode="&#xf12c;" d="M501 86v-93h-139l-89 141-13 23q-4 5-6 12h-2q0-2-1-4t-2-4-2-4q-5-11-14-25l-86-139h-144v93h71l110 162-103 152h-76v94h154l77-127q1-2 13-24 4-5 6-11h2q1 5 6 11l14 24 78 127h143v-94h-69l-103-149 114-165h61z m356-121v-115h-287l-2 15q-2 25-2 26 0 35 15 65t36 48 47 37 47 30 36 30 15 36q0 21-17 35t-39 13q-28 0-54-21-8-6-20-22l-59 52q15 20 35 37 45 36 105 36 62 0 100-33t37-89q0-37-19-66t-47-48-55-35-49-35-23-41h130v45h70z" horiz-adv-x="857.1" />
<glyph glyph-name="header" unicode="&#xf1dc;" d="M939-79q-25 0-74 2t-75 2q-24 0-73-2t-74-2q-13 0-21 12t-7 25q0 18 9 26t22 9 29 4 25 9q18 11 18 78l0 218q0 12-1 17-7 3-28 3h-376q-22 0-29-3 0-5 0-17l-1-207q0-79 21-91 9-6 26-8t32-2 25-8 11-26q0-14-6-26t-21-13q-26 0-78 2t-77 2q-24 0-71-2t-71-2q-13 0-20 12t-7 25q0 17 9 25t20 10 26 4 24 9q18 13 18 80l-1 31v454q0 2 1 15t0 20-1 21-2 24-4 20-6 18-9 10q-8 5-25 7t-29 1-23 7-10 26q0 14 6 26t20 13q26 0 78-2t77-2q23 0 71 2t70 2q14 0 21-13t7-26q0-17-9-25t-22-8-27-2-24-7q-20-12-20-90l1-178q0-12 0-18 7-2 22-2h390q14 0 21 2 1 6 1 18l0 178q0 78-19 90-10 6-33 7t-37 7-14 28q0 14 7 26t21 13q24 0 74-2t73-2q24 0 72 2t72 2q14 0 21-13t7-26q0-17-10-25t-22-8-29-2-24-7q-20-13-20-90l1-526q0-66 19-78 9-6 25-8t30-2 23-9 10-25q0-14-6-26t-20-13z" horiz-adv-x="1000" />
<glyph glyph-name="window-maximize" unicode="&#xf2d0;" d="M143 64h714v429h-714v-429z m857 625v-678q0-37-26-63t-63-27h-822q-36 0-63 27t-26 63v678q0 37 26 63t63 27h822q37 0 63-27t26-63z" horiz-adv-x="1000" />
</font>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
import{B as r}from"./vendor.6399378c.js";var g={log(o,l,s){console.log(o+"-\u9047\u5230\u672A\u5904\u7406\u7684\u7C7B\u578B\uFF0C\u8BF7\u8054\u7CFB\u5F00\u53D1\u4EBA\u5458\u4FEE\u6539\uFF1A"+l,s)},logMessage(o,l,s){console.log(o+"-\u9047\u5230\u672A\u5904\u7406\u7684\u7C7B\u578B\uFF0C\u8BF7\u8054\u7CFB\u5F00\u53D1\u4EBA\u5458\u4FEE\u6539\uFF1A"+l,s),r.error(o+"-\u9047\u5230\u672A\u5904\u7406\u7684\u7C7B\u578B\uFF0C\u8BF7\u8054\u7CFB\u5F00\u53D1\u4EBA\u5458\u4FEE\u6539\uFF1A"+l)}};export{g as l};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,16 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="api-logo.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>API文档管理</title>
<script type="module" crossorigin src="assets/main.5fd30069.js"></script>
<link rel="modulepreload" href="assets/vendor.6399378c.js">
<link rel="stylesheet" href="assets/style.9e577f5e.css">
</head>
<body>
<div id="app"></div>
</body>
</html>

View File

@@ -33,6 +33,10 @@
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-core</artifactId>

View File

@@ -1,192 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and
distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright
owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities
that control, are controlled by, or are under common control with that entity.
For the purposes of this definition, "control" means (i) the power, direct or
indirect, to cause the direction or management of such entity, whether by
contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising
permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including
but not limited to software source code, documentation source, and configuration
files.
"Object" form shall mean any form resulting from mechanical transformation or
translation of a Source form, including but not limited to compiled object code,
generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form, made
available under the License, as indicated by a copyright notice that is included
in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that
is based on (or derived from) the Work and for which the editorial revisions,
annotations, elaborations, or other modifications represent, as a whole, an
original work of authorship. For the purposes of this License, Derivative Works
shall not include works that remain separable from, or merely link (or bind by
name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version
of the Work and any modifications or additions to that Work or Derivative Works
thereof, that is intentionally submitted to Licensor for inclusion in the Work
by the copyright owner or by an individual or Legal Entity authorized to submit
on behalf of the copyright owner. For the purposes of this definition,
"submitted" means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems, and
issue tracking systems that are managed by, or on behalf of, the Licensor for
the purpose of discussing and improving the Work, but excluding communication
that is conspicuously marked or otherwise designated in writing by the copyright
owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
of whom a Contribution has been received by Licensor and subsequently
incorporated within the Work.
2. Grant of Copyright License.
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the Work and such
Derivative Works in Source or Object form.
3. Grant of Patent License.
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable (except as stated in this section) patent license to make, have
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
such license applies only to those patent claims licensable by such Contributor
that are necessarily infringed by their Contribution(s) alone or by combination
of their Contribution(s) with the Work to which such Contribution(s) was
submitted. If You institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
Contribution incorporated within the Work constitutes direct or contributory
patent infringement, then any patent licenses granted to You under this License
for that Work shall terminate as of the date such litigation is filed.
4. Redistribution.
You may reproduce and distribute copies of the Work or Derivative Works thereof
in any medium, with or without modifications, and in Source or Object form,
provided that You meet the following conditions:
You must give any other recipients of the Work or Derivative Works a copy of
this License; and
You must cause any modified files to carry prominent notices stating that You
changed the files; and
You must retain, in the Source form of any Derivative Works that You distribute,
all copyright, patent, trademark, and attribution notices from the Source form
of the Work, excluding those notices that do not pertain to any part of the
Derivative Works; and
If the Work includes a "NOTICE" text file as part of its distribution, then any
Derivative Works that You distribute must include a readable copy of the
attribution notices contained within such NOTICE file, excluding those notices
that do not pertain to any part of the Derivative Works, in at least one of the
following places: within a NOTICE text file distributed as part of the
Derivative Works; within the Source form or documentation, if provided along
with the Derivative Works; or, within a display generated by the Derivative
Works, if and wherever such third-party notices normally appear. The contents of
the NOTICE file are for informational purposes only and do not modify the
License. You may add Your own attribution notices within Derivative Works that
You distribute, alongside or as an addendum to the NOTICE text from the Work,
provided that such additional attribution notices cannot be construed as
modifying the License.
You may add Your own copyright statement to Your modifications and may provide
additional or different license terms and conditions for use, reproduction, or
distribution of Your modifications, or for any such Derivative Works as a whole,
provided Your use, reproduction, and distribution of the Work otherwise complies
with the conditions stated in this License.
5. Submission of Contributions.
Unless You explicitly state otherwise, any Contribution intentionally submitted
for inclusion in the Work by You to the Licensor shall be under the terms and
conditions of this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify the terms of
any separate license agreement you may have executed with Licensor regarding
such Contributions.
6. Trademarks.
This License does not grant permission to use the trade names, trademarks,
service marks, or product names of the Licensor, except as required for
reasonable and customary use in describing the origin of the Work and
reproducing the content of the NOTICE file.
7. Disclaimer of Warranty.
Unless required by applicable law or agreed to in writing, Licensor provides the
Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
including, without limitation, any warranties or conditions of TITLE,
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
solely responsible for determining the appropriateness of using or
redistributing the Work and assume any risks associated with Your exercise of
permissions under this License.
8. Limitation of Liability.
In no event and under no legal theory, whether in tort (including negligence),
contract, or otherwise, unless required by applicable law (such as deliberate
and grossly negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special, incidental,
or consequential damages of any character arising as a result of this License or
out of the use or inability to use the Work (including but not limited to
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
any and all other commercial damages or losses), even if such Contributor has
been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability.
While redistributing the Work or Derivative Works thereof, You may choose to
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
other liability obligations and/or rights consistent with this License. However,
in accepting such obligations, You may act only on Your own behalf and on Your
sole responsibility, not on behalf of any other Contributor, and only if You
agree to indemnify, defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason of your
accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work
To apply the Apache License to your work, attach the following boilerplate
notice, with the fields enclosed by brackets "{}" replaced with your own
identifying information. (Don't include the brackets!) The text should be
enclosed in the appropriate comment syntax for the file format. We also
recommend that a file or class name and description of purpose be included on
the same "printed page" as the copyright notice for easier identification within
third-party archives.
Copyright 2018 暮光:城中城
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -1,6 +0,0 @@
# zyplayer-doc-db
#### 项目介绍
数据库文档、管理工具,对表注释、字段注释进行查看、修改、导出等操作,支持字段或注释的模糊查询
支持MySQL、SQLServer、Oracle数据源支持数据库表、字段文档查看修改表文档导出SQL执行、表数据预览、不同数据库之间的数据互导支持多数据源管理。支持按人员、按数据源对用户授权可给用户 库表注释查看、注释修改、SQL执行 粒度的授权。目标是取代Navicat做一个开源免费的在线数据库管理工具。

View File

@@ -1,118 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>zyplayer-doc-db</artifactId>
<packaging>jar</packaging>
<name>zyplayer-doc-db</name>
<description>数据库文档工具</description>
<url>https://gitee.com/zyplayer/zyplayer-doc/zyplayer-doc-db</url>
<developers>
<developer>
<id>zyplayer</id>
<name>暮光:城中城</name>
<email>806783409@qq.com</email>
<roles>
<role>Java Development Engineer</role>
</roles>
<timezone>2018-05-22 16:06:06</timezone>
</developer>
</developers>
<parent>
<groupId>org.dromara</groupId>
<artifactId>zyplayer-doc</artifactId>
<version>1.0.0</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>zyplayer-doc-core</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>zyplayer-doc-data</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<!-- 打包跳过单元测试 -->
<skipTests>true</skipTests>
<elasticsearch.version>7.2.0</elasticsearch.version>
<destDir>${project.build.outputDirectory}/META-INF/resources/webjars/${project.artifactId}/${project.version}</destDir>
</properties>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
</license>
</licenses>
<scm>
<connection>scm:git@git.oschina.net:zyplayer/zyplayer-doc.git</connection>
<developerConnection>scm:git@git.oschina.net:zyplayer/zyplayer-doc.git</developerConnection>
<url>git@git.oschina.net:zyplayer/zyplayer-doc.git</url>
</scm>
<distributionManagement>
<snapshotRepository>
<id>snapshots</id>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</snapshotRepository>
<repository>
<id>snapshots</id>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
<build>
<resources>
<resource>
<directory>src/main/resources/dist</directory>
<targetPath>META-INF/resources/</targetPath>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*</include>
</includes>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/webapp</directory>
<includes>
<include>**/*</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>

View File

@@ -1,227 +0,0 @@
package org.dromara.zyplayer.db.controller;
import org.dromara.zyplayer.core.annotation.AuthMan;
import org.dromara.zyplayer.core.exception.ConfirmException;
import org.dromara.zyplayer.data.config.security.DocUserUtil;
import org.dromara.zyplayer.data.repository.manage.entity.DbDatasource;
import org.dromara.zyplayer.data.repository.support.consts.DocAuthConst;
import org.dromara.zyplayer.data.repository.support.consts.DocSysModuleType;
import org.dromara.zyplayer.data.repository.support.consts.DocSysType;
import org.dromara.zyplayer.data.service.manage.DbDatasourceService;
import org.dromara.zyplayer.db.controller.vo.DatabaseExportVo;
import org.dromara.zyplayer.db.controller.vo.TableColumnVo;
import org.dromara.zyplayer.db.controller.vo.TableColumnVo.TableInfoVo;
import org.dromara.zyplayer.db.controller.vo.TableDdlVo;
import org.dromara.zyplayer.db.controller.vo.TableStatusVo;
import org.dromara.zyplayer.db.framework.consts.DbAuthType;
import org.dromara.zyplayer.db.framework.db.bean.DatabaseFactoryBean;
import org.dromara.zyplayer.db.framework.db.bean.DatabaseRegistrationBean;
import org.dromara.zyplayer.db.framework.db.dto.*;
import org.dromara.zyplayer.db.framework.db.enums.DatabaseProductEnum;
import org.dromara.zyplayer.db.framework.json.DocDbResponseJson;
import org.dromara.zyplayer.db.framework.utils.PoiUtil;
import org.dromara.zyplayer.db.service.database.DatabaseServiceFactory;
import org.dromara.zyplayer.db.service.database.DbBaseService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 文档控制器
*
* @author 暮光:城中城
* @since 2018年8月8日
*/
@AuthMan
@RestController
@RequestMapping("/zyplayer-doc-db/doc-db")
public class DatabaseDocController {
@Resource
DatabaseRegistrationBean databaseRegistrationBean;
@Resource
DbDatasourceService dbDatasourceService;
@Resource
DatabaseServiceFactory databaseServiceFactory;
/**
* 获取数据源列表(管理员返回所有数据源,用户返回有权限的数据源)
* @return ResponseJson
*/
@PostMapping("/getDataSourceList")
public DocDbResponseJson getDataSourceList() {
List<DbDatasource> dataSourceList = dbDatasourceService.getDataSourceList();
return DocDbResponseJson.ok(dataSourceList);
}
/**
* 获取数据源
*/
@PostMapping("/getDataSource")
public DocDbResponseJson getDataSource(Long sourceId) {
DbDatasource dataSource = dbDatasourceService.getDataSource(sourceId);
return DocDbResponseJson.ok(dataSource);
}
/**
* 获取数据源基本信息
*
* @param sourceId 数据源ID
* @return 基本信息
*/
@PostMapping(value = "/getSourceBaseInfo")
public DocDbResponseJson getSourceBaseInfo(Long sourceId) {
DbBaseService dbBaseService = databaseServiceFactory.getDbBaseService(sourceId);
Map<String, Object> dbResultMap = new HashMap<>();
dbResultMap.put("product", dbBaseService.getDatabaseProduct().name().toLowerCase());
return DocDbResponseJson.ok(dbResultMap);
}
@PostMapping(value = "/getTableDdl")
public DocDbResponseJson getTableDdl(Long sourceId, String dbName, String tableName) {
DbBaseService dbBaseService = databaseServiceFactory.getDbBaseService(sourceId);
TableDdlVo tableDdlVo = dbBaseService.getTableDdl(sourceId, dbName, tableName);
return DocDbResponseJson.ok(tableDdlVo);
}
@PostMapping(value = "/getDatabaseList")
public DocDbResponseJson getDatabaseList(Long sourceId) {
DbBaseService dbBaseService = databaseServiceFactory.getDbBaseService(sourceId);
List<DatabaseInfoDto> databaseList = dbBaseService.getDatabaseList(sourceId);
return DocDbResponseJson.ok(databaseList);
}
@PostMapping(value = "/getTableStatus")
public DocDbResponseJson getTableStatus(Long sourceId, String dbName, String tableName) {
DbBaseService dbBaseService = databaseServiceFactory.getDbBaseService(sourceId);
TableStatusVo tableStatusVo = dbBaseService.getTableStatus(sourceId, dbName, tableName);
return DocDbResponseJson.ok(tableStatusVo);
}
@PostMapping(value = "/getTableList")
public DocDbResponseJson getTableList(Long sourceId, String dbName) {
DbBaseService dbBaseService = databaseServiceFactory.getDbBaseService(sourceId);
List<TableInfoDto> tableList = dbBaseService.getTableList(sourceId, dbName);
return DocDbResponseJson.ok(tableList);
}
@PostMapping(value = "/getTableColumnList")
public DocDbResponseJson getTableColumnList(Long sourceId, String dbName, String tableName) {
DbBaseService dbBaseService = databaseServiceFactory.getDbBaseService(sourceId);
TableColumnVo tableColumnVo = dbBaseService.getTableColumnList(sourceId, dbName, tableName);
return DocDbResponseJson.ok(tableColumnVo);
}
@PostMapping(value = "/getTableAndColumnBySearch")
public DocDbResponseJson getTableAndColumnBySearch(Long sourceId, String dbName, String searchText) {
if (StringUtils.isBlank(searchText)) {
return DocDbResponseJson.ok();
}
DbBaseService dbBaseService = databaseServiceFactory.getDbBaseService(sourceId);
List<QueryTableColumnDescDto> columnDescDto = dbBaseService.getTableAndColumnBySearch(sourceId, dbName, searchText);
return DocDbResponseJson.ok(columnDescDto);
}
@PostMapping(value = "/getTableDescList")
public DocDbResponseJson getTableDescList(Long sourceId, String dbName, String tableName) {
DbBaseService dbBaseService = databaseServiceFactory.getDbBaseService(sourceId);
List<TableDescDto> tableDescList = dbBaseService.getTableDescList(sourceId, dbName, tableName);
return DocDbResponseJson.ok(tableDescList);
}
@PostMapping(value = "/updateTableDesc")
public DocDbResponseJson updateTableDesc(Long sourceId, String dbName, String tableName, String newDesc) {
this.judgeAuth(sourceId, DbAuthType.DESC_EDIT.getName(), "没有修改该表注释的权限");
DbBaseService dbBaseService = databaseServiceFactory.getDbBaseService(sourceId);
dbBaseService.updateTableDesc(sourceId, dbName, tableName, newDesc);
return DocDbResponseJson.ok();
}
@PostMapping(value = "/updateTableColumnDesc")
public DocDbResponseJson updateTableColumnDesc(Long sourceId, String dbName, String tableName, String columnName, String newDesc) {
this.judgeAuth(sourceId, DbAuthType.DESC_EDIT.getName(), "没有修改该表字段注释的权限");
DbBaseService dbBaseService = databaseServiceFactory.getDbBaseService(sourceId);
dbBaseService.updateTableColumnDesc(sourceId, dbName, tableName, columnName, newDesc);
return DocDbResponseJson.ok();
}
@PostMapping(value = "/exportDatabase")
public DocDbResponseJson exportDatabase(HttpServletResponse response, Long sourceId, String dbName, String tableNames, Integer exportType, Integer exportFormat) {
if (StringUtils.isBlank(tableNames)) {
return DocDbResponseJson.warn("请选择需要导出的表");
}
List<String> tableNameList = Stream.of(tableNames.split(",")).filter(StringUtils::isNotBlank).collect(Collectors.toList());
if (Objects.equals(exportType, 1)) {
return this.exportForTableDoc(response, sourceId, dbName, tableNameList, exportFormat);
} else if (Objects.equals(exportType, 2)) {
return this.exportForTableDdl(response, sourceId, dbName, tableNameList, exportFormat);
}
return DocDbResponseJson.ok();
}
private DocDbResponseJson exportForTableDdl(HttpServletResponse response, Long sourceId, String dbName, List<String> tableNameList, Integer exportFormat) {
DbBaseService dbBaseService = databaseServiceFactory.getDbBaseService(sourceId);
Map<String, String> ddlSqlMap = new HashMap<>();
for (String tableName : tableNameList) {
TableDdlVo tableDdlVo = dbBaseService.getTableDdl(sourceId, dbName, tableName);
ddlSqlMap.put(tableName, tableDdlVo.getTableDDLByType());
}
try {
DatabaseFactoryBean databaseFactoryBean = databaseRegistrationBean.getOrCreateFactoryById(sourceId);
DatabaseProductEnum databaseProduct = databaseFactoryBean.getDatabaseProduct();
PoiUtil.exportByDdl(ddlSqlMap, dbName, databaseProduct.name(), response);
} catch (Exception e) {
e.printStackTrace();
return DocDbResponseJson.error("导出失败:" + e.getMessage());
}
return DocDbResponseJson.ok();
}
private DocDbResponseJson exportForTableDoc(HttpServletResponse response, Long sourceId, String dbName, List<String> tableNameList, Integer exportFormat) {
DbBaseService dbBaseService = databaseServiceFactory.getDbBaseService(sourceId);
// 数据组装
List<TableInfoVo> tableList = new LinkedList<>();
Map<String, List<TableColumnDescDto>> columnList = new HashMap<>();
for (String tableName : tableNameList) {
TableColumnVo tableColumnVo = dbBaseService.getTableColumnList(sourceId, dbName, tableName);
columnList.put(tableName, tableColumnVo.getColumnList());
tableList.add(tableColumnVo.getTableInfo());
}
try {
DatabaseExportVo exportVo = new DatabaseExportVo(columnList, tableList);
if (Objects.equals(exportFormat, 1)) {
PoiUtil.exportByText(exportVo, response);
return null;
} else if (Objects.equals(exportFormat, 2)) {
PoiUtil.exportByXlsx(exportVo, response);
return null;
} else if (Objects.equals(exportFormat, 3)) {
PoiUtil.exportByDocx(dbName, exportVo, response);
return null;
}
return DocDbResponseJson.error("导出失败:请先选择导出类型");
} catch (Exception e) {
e.printStackTrace();
return DocDbResponseJson.error("导出失败:" + e.getMessage());
}
}
/**
* 权限判断
*
* @author 暮光:城中城
*/
private void judgeAuth(Long sourceId, String authName, String noAuthInfo) {
if (!DocUserUtil.haveAuth(DocAuthConst.DB_DATASOURCE_MANAGE)
&& !DocUserUtil.haveCustomAuth(authName, DocSysType.DB.getType(), DocSysModuleType.Db.DATASOURCE.getType(), sourceId)) {
throw new ConfirmException(noAuthInfo);
}
}
}

View File

@@ -1,154 +0,0 @@
package org.dromara.zyplayer.db.controller;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.dromara.zyplayer.core.annotation.AuthMan;
import org.dromara.zyplayer.core.json.DocResponseJson;
import org.dromara.zyplayer.core.json.ResponseJson;
import org.dromara.zyplayer.data.config.security.DocUserDetails;
import org.dromara.zyplayer.data.config.security.DocUserUtil;
import org.dromara.zyplayer.data.repository.manage.entity.AuthInfo;
import org.dromara.zyplayer.data.repository.manage.entity.UserAuth;
import org.dromara.zyplayer.data.repository.manage.entity.UserInfo;
import org.dromara.zyplayer.data.repository.support.consts.DocAuthConst;
import org.dromara.zyplayer.data.repository.support.consts.DocSysModuleType;
import org.dromara.zyplayer.data.repository.support.consts.DocSysType;
import org.dromara.zyplayer.data.service.manage.AuthInfoService;
import org.dromara.zyplayer.data.service.manage.UserAuthService;
import org.dromara.zyplayer.data.service.manage.UserInfoService;
import org.dromara.zyplayer.db.controller.vo.UserDbAuthVo;
import org.dromara.zyplayer.db.framework.consts.DbAuthType;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 数据库权限控制器
*
* @author 暮光:城中城
* @since 2019年8月18日
*/
@RestController
@AuthMan(DocAuthConst.DB_DATASOURCE_MANAGE)
@RequestMapping("/zyplayer-doc-db/auth")
public class DbDataSourceAuthController {
private static final Logger logger = LoggerFactory.getLogger(DbDataSourceAuthController.class);
@Resource
UserInfoService userInfoService;
@Resource
UserAuthService userAuthService;
@Resource
AuthInfoService authInfoService;
@PostMapping("/assign")
public ResponseJson<Object> assign(Long sourceId, String authList) {
DocUserDetails currentUser = DocUserUtil.getCurrentUser();
List<String> authNameList = Stream.of(DbAuthType.values()).map(DbAuthType::getName).collect(Collectors.toList());
QueryWrapper<AuthInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.in("auth_name", authNameList);
Collection<AuthInfo> authInfoList = authInfoService.list(queryWrapper);
Map<String, Long> authInfoMap = authInfoList.stream().collect(Collectors.toMap(AuthInfo::getAuthName, AuthInfo::getId));
// 先删除所有用户的权限
userAuthService.deleteModuleAuth(DocSysType.DB.getType(), DocSysModuleType.Db.DATASOURCE.getType(), sourceId);
List<UserDbAuthVo> authVoList = JSON.parseArray(authList, UserDbAuthVo.class);
for (UserDbAuthVo authVo : authVoList) {
List<UserAuth> userAuthList = new LinkedList<>();
int executeAuth = Optional.ofNullable(authVo.getExecuteAuth()).orElse(0);
if (executeAuth <= 0) {
Long authId = authInfoMap.get(DbAuthType.NO_AUTH.getName());
UserAuth userAuth = this.createUserAuth(sourceId, currentUser.getUserId(), authVo.getUserId(), authId);
userAuthList.add(userAuth);
}
if (executeAuth >= 1) {
Long authId = authInfoMap.get(DbAuthType.VIEW.getName());
UserAuth userAuth = this.createUserAuth(sourceId, currentUser.getUserId(), authVo.getUserId(), authId);
userAuthList.add(userAuth);
}
if (executeAuth >= 2) {
Long authId = authInfoMap.get(DbAuthType.SELECT.getName());
UserAuth userAuth = this.createUserAuth(sourceId, currentUser.getUserId(), authVo.getUserId(), authId);
userAuthList.add(userAuth);
}
if (executeAuth >= 3) {
Long authId = authInfoMap.get(DbAuthType.UPDATE.getName());
UserAuth userAuth = this.createUserAuth(sourceId, currentUser.getUserId(), authVo.getUserId(), authId);
userAuthList.add(userAuth);
}
if (Objects.equals(authVo.getDescEditAuth(), 1)) {
Long authId = authInfoMap.get(DbAuthType.DESC_EDIT.getName());
UserAuth userAuth = this.createUserAuth(sourceId, currentUser.getUserId(), authVo.getUserId(), authId);
userAuthList.add(userAuth);
}
if (Objects.equals(authVo.getProcEditAuth(), 1)) {
Long authId = authInfoMap.get(DbAuthType.PROC_EDIT.getName());
UserAuth userAuth = this.createUserAuth(sourceId, currentUser.getUserId(), authVo.getUserId(), authId);
userAuthList.add(userAuth);
}
// 保存权限,重新登录后可用,后期可以考虑在这里直接修改缓存里的用户权限
userAuthService.saveBatch(userAuthList);
}
return DocResponseJson.ok();
}
@PostMapping("/list")
public ResponseJson<Object> list(Long sourceId) {
List<UserAuth> authList = userAuthService.getModuleAuthList(DocSysType.DB.getType(), DocSysModuleType.Db.DATASOURCE.getType(), sourceId);
if (CollectionUtils.isEmpty(authList)) {
return DocResponseJson.ok();
}
// 权限ID对应的权限名
Collection<AuthInfo> authInfoList = authInfoService.listByIds(authList.stream().map(UserAuth::getAuthId).collect(Collectors.toList()));
Map<Long, String> authInfoMap = authInfoList.stream().collect(Collectors.toMap(AuthInfo::getId, AuthInfo::getAuthName));
// 查询用户信息
Map<Long, List<UserAuth>> userAuthGroup = authList.stream().collect(Collectors.groupingBy(UserAuth::getUserId));
Collection<UserInfo> userInfos = userInfoService.listByIds(userAuthGroup.keySet());
Map<Long, String> userInfoMap = userInfos.stream().collect(Collectors.toMap(UserInfo::getId, UserInfo::getUserName));
List<UserDbAuthVo> authVoList = new LinkedList<>();
// 组装结果集
userAuthGroup.forEach((key, value) -> {
Set<String> authNameSet = value.stream().map(auth -> authInfoMap.get(auth.getAuthId())).collect(Collectors.toSet());
UserDbAuthVo authVo = new UserDbAuthVo();
if (this.haveAuth(authNameSet, DbAuthType.UPDATE) == 1) {
authVo.setExecuteAuth(3);
} else if (this.haveAuth(authNameSet, DbAuthType.SELECT) == 1) {
authVo.setExecuteAuth(2);
} else if (this.haveAuth(authNameSet, DbAuthType.VIEW) == 1) {
authVo.setExecuteAuth(1);
}
authVo.setDescEditAuth(this.haveAuth(authNameSet, DbAuthType.DESC_EDIT));
authVo.setProcEditAuth(this.haveAuth(authNameSet, DbAuthType.PROC_EDIT));
authVo.setUserId(key);
authVo.setUserName(userInfoMap.get(key));
authVoList.add(authVo);
});
return DocResponseJson.ok(authVoList);
}
private Integer haveAuth(Set<String> authNameSet, DbAuthType dbAuthType) {
return authNameSet.contains(dbAuthType.getName()) ? 1 : 0;
}
private UserAuth createUserAuth(Long sourceId, Long loginUserId, Long userId, Long authId) {
UserAuth userAuth = new UserAuth();
userAuth.setSysType(DocSysType.DB.getType());
userAuth.setSysModuleType(DocSysModuleType.Db.DATASOURCE.getType());
userAuth.setSysModuleId(sourceId);
userAuth.setCreationTime(new Date());
userAuth.setCreateUid(loginUserId);
userAuth.setDelFlag(0);
userAuth.setUserId(userId);
userAuth.setAuthId(authId);
return userAuth;
}
}

View File

@@ -1,175 +0,0 @@
package org.dromara.zyplayer.db.controller;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.util.TypeUtils;
import org.dromara.zyplayer.core.annotation.AuthMan;
import org.dromara.zyplayer.db.controller.download.FormatDownloadConst;
import org.dromara.zyplayer.db.controller.download.FormatDownloadService;
import org.dromara.zyplayer.db.controller.param.DataViewParam;
import org.dromara.zyplayer.db.framework.db.mapper.base.ExecuteParam;
import org.dromara.zyplayer.db.framework.db.mapper.base.ExecuteResult;
import org.dromara.zyplayer.db.framework.db.mapper.base.ExecuteType;
import org.dromara.zyplayer.db.framework.db.mapper.base.SqlExecutor;
import org.dromara.zyplayer.db.framework.json.DocDbResponseJson;
import org.dromara.zyplayer.db.framework.utils.JSONUtil;
import org.dromara.zyplayer.db.service.common.ExecuteAuthService;
import org.dromara.zyplayer.db.service.database.DatabaseServiceFactory;
import org.dromara.zyplayer.db.service.database.DbBaseService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
/**
* 表数据查看控制器
*
* @author 暮光:城中城
* @since 2021年5月16日
*/
@AuthMan
@RestController
@RequestMapping("/zyplayer-doc-db/data-view")
public class DbDataViewController {
private static final Logger logger = LoggerFactory.getLogger(DbDataViewController.class);
@Resource
ExecuteAuthService executeAuthService;
@Resource
SqlExecutor sqlExecutor;
@Resource
DatabaseServiceFactory databaseServiceFactory;
@Resource
Map<String, FormatDownloadService> formatDownloadServiceMap;
// 最大允许导出的行数设置的过大有可能会导致内存溢出默认10W条
@Value("${zyplayer.doc.db.download-max-row:100000}")
Integer downloadMaxRow;
/**
* 数据查询接口
*
* @author 暮光:城中城
* @since 2021-08-14
*/
@PostMapping(value = "/query")
public DocDbResponseJson query(DataViewParam param) {
// 数据查询
ExecuteType executeType = executeAuthService.getExecuteType(param.getSourceId());
DbBaseService dbBaseService = databaseServiceFactory.getDbBaseService(param.getSourceId());
String queryPageSql = dbBaseService.getQueryPageSql(param);
ExecuteResult executeResult = this.query(param.getSourceId(), param.getExecuteId(), executeType, queryPageSql);
// 数据组装
List<String> resultList = new LinkedList<>();
resultList.add(JSON.toJSONString(executeResult, JSONUtil.serializeConfig, SerializerFeature.WriteMapNullValue));
DocDbResponseJson responseJson = DocDbResponseJson.ok(resultList);
// 计算总条数,第一页才查询总条数
if (CollectionUtils.isNotEmpty(executeResult.getResult()) && Objects.equals(param.getPageNum(), 1)) {
responseJson.setTotal((long) executeResult.getResult().size());
if (executeResult.getResult().size() >= param.getPageSize()) {
responseJson.setTotal(this.getDataCount(param, executeType));
}
}
return responseJson;
}
/**
* 删除表数据
*
* @author 暮光:城中城
*/
@PostMapping(value = "/deleteTableLineData")
public DocDbResponseJson deleteTableLineData(Long sourceId, String dbName, String tableName, String lineJson) {
JSONArray lineJsonArr = JSON.parseArray(lineJson);
DbBaseService dbBaseService = databaseServiceFactory.getDbBaseService(sourceId);
dbBaseService.deleteTableLineData(sourceId, dbName, tableName, lineJsonArr);
return DocDbResponseJson.ok();
}
/**
* 多表下载
*
* @param response
* @param param
* @return
* @author 暮光:城中城
*/
@PostMapping(value = "/downloadMultiple")
public DocDbResponseJson downloadMultiple(HttpServletResponse response, DataViewParam param) {
if (StringUtils.isBlank(param.getTableNames())) {
return DocDbResponseJson.warn("请选择导出的表");
}
param.setExecuteId(IdUtil.simpleUUID());
String[] tableNameArr = param.getTableNames().split(",");
try {
// 先校验总条数是否超过限制
for (String tableName : tableNameArr) {
param.setTableName(tableName);
ExecuteType executeType = executeAuthService.getExecuteType(param.getSourceId());
if (this.getDataCount(param, executeType) > downloadMaxRow) {
return DocDbResponseJson.error(String.format("导出失败,表:%s 数据行数超过最大导出配置 %s请联系管理员修改", tableName, downloadMaxRow));
}
}
FormatDownloadService formatDownloadService = formatDownloadServiceMap.getOrDefault(param.getDownloadType(), formatDownloadServiceMap.get(FormatDownloadConst.COMMON));
formatDownloadService.download(response, param, tableNameArr);
} catch (Exception e) {
e.printStackTrace();
return DocDbResponseJson.error("导出失败:" + e.getMessage());
}
return null;
}
/**
* 获取数据总条数
*
* @author 暮光:城中城
* @since 2021-08-14
*/
private Long getDataCount(DataViewParam param, ExecuteType executeType) {
DbBaseService dbBaseService = databaseServiceFactory.getDbBaseService(param.getSourceId());
String queryCountSql = dbBaseService.getQueryCountSql(param);
ExecuteResult countResult = this.query(param.getSourceId(), param.getExecuteId(), executeType, queryCountSql);
if (CollectionUtils.isNotEmpty(countResult.getResult()) && MapUtils.isNotEmpty(countResult.getResult().get(0))) {
Map<String, Object> countMap = countResult.getResult().get(0);
Optional<Object> countAny = countMap.values().stream().findAny();
return TypeUtils.castToLong(countAny.orElse(0));
}
return 0L;
}
/**
* 执行数据查询
*
* @param sourceId
* @param executeId
* @param executeType
* @param executeSql
* @return
* @author 暮光:城中城
*/
private ExecuteResult query(Long sourceId, String executeId, ExecuteType executeType, String executeSql) {
try {
ExecuteParam executeParam = new ExecuteParam();
executeParam.setDatasourceId(sourceId);
executeParam.setExecuteId(executeId);
executeParam.setExecuteType(executeType);
executeParam.setSql(executeSql);
executeParam.setMaxRows(1000);
return sqlExecutor.execute(executeParam);
} catch (Exception e) {
logger.error("执行出错", e);
return ExecuteResult.error(ExceptionUtils.getStackTrace(e), executeSql);
}
}
}

View File

@@ -1,130 +0,0 @@
package org.dromara.zyplayer.db.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.dromara.zyplayer.core.annotation.AuthMan;
import org.dromara.zyplayer.core.exception.ConfirmException;
import org.dromara.zyplayer.data.config.security.DocUserDetails;
import org.dromara.zyplayer.data.config.security.DocUserUtil;
import org.dromara.zyplayer.data.repository.manage.entity.DbDatasource;
import org.dromara.zyplayer.data.repository.support.consts.DocAuthConst;
import org.dromara.zyplayer.data.service.manage.DbDatasourceService;
import org.dromara.zyplayer.db.framework.configuration.DatasourceUtil;
import org.dromara.zyplayer.db.framework.db.bean.DatabaseFactoryBean;
import org.dromara.zyplayer.db.framework.db.bean.DatabaseRegistrationBean;
import org.dromara.zyplayer.db.framework.json.DocDbResponseJson;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
/**
* 数据源控制器
*
* @author 暮光:城中城
* @since 2019年6月29日
*/
@RestController
@AuthMan(DocAuthConst.DB_DATASOURCE_MANAGE)
@RequestMapping("/zyplayer-doc-db/datasource")
public class DbDatasourceController {
@Resource
DatabaseRegistrationBean databaseRegistrationBean;
@Resource
DbDatasourceService dbDatasourceService;
@PostMapping(value = "/list")
public DocDbResponseJson list(Integer pageNum, Integer pageSize, String name, String groupName) {
QueryWrapper<DbDatasource> wrapper = new QueryWrapper<>();
wrapper.eq("yn", 1);
wrapper.eq(StringUtils.isNotBlank(groupName), "group_name", groupName);
wrapper.like(StringUtils.isNotBlank(name), "name", "%" + name + "%");
IPage<DbDatasource> page = new Page<>(pageNum, pageSize, pageNum == 1);
dbDatasourceService.page(page, wrapper);
for (DbDatasource dbDatasource : page.getRecords()) {
dbDatasource.setSourcePassword("***");
}
return DocDbResponseJson.ok(page);
}
@PostMapping(value = "/groups")
public DocDbResponseJson groups() {
QueryWrapper<DbDatasource> wrapper = new QueryWrapper<>();
wrapper.eq("yn", 1);
wrapper.isNotNull("group_name");
wrapper.select("group_name");
wrapper.groupBy("group_name");
List<DbDatasource> datasourceList = dbDatasourceService.list(wrapper);
if (CollectionUtils.isEmpty(datasourceList)) {
return DocDbResponseJson.ok();
}
Set<String> groupNameSet = datasourceList.stream().map(DbDatasource::getGroupName).filter(StringUtils::isNotBlank).collect(Collectors.toSet());
return DocDbResponseJson.ok(groupNameSet);
}
@PostMapping(value = "/test")
public DocDbResponseJson test(DbDatasource dbDatasource) {
// 验证新的数据源
try {
// 获取原始密码
if (Objects.equals("***", dbDatasource.getSourcePassword()) && dbDatasource.getId() != null) {
DbDatasource dbDatasourceSel = dbDatasourceService.getById(dbDatasource.getId());
if (dbDatasourceSel != null) {
dbDatasource.setSourcePassword(dbDatasourceSel.getSourcePassword());
}
}
DatabaseFactoryBean databaseFactoryBean = DatasourceUtil.createDatabaseFactoryBean(dbDatasource, true);
databaseFactoryBean.getDataSource().close();
} catch (ConfirmException e) {
return DocDbResponseJson.warn(e.getMessage());
} catch (Exception e) {
e.printStackTrace();
return DocDbResponseJson.warn(ExceptionUtils.getStackTrace(e));
}
return DocDbResponseJson.ok();
}
@PostMapping(value = "/update")
public DocDbResponseJson update(DbDatasource dbDatasource) {
if (StringUtils.isBlank(dbDatasource.getName())) {
return DocDbResponseJson.warn("名字必填");
} else if (StringUtils.isBlank(dbDatasource.getDriverClassName())) {
return DocDbResponseJson.warn("驱动类必选");
} else if (StringUtils.isBlank(dbDatasource.getSourceUrl())) {
return DocDbResponseJson.warn("地址必填");
} else if (StringUtils.isBlank(dbDatasource.getSourceName())) {
return DocDbResponseJson.warn("用户名必填");
} else if (StringUtils.isBlank(dbDatasource.getSourcePassword())) {
return DocDbResponseJson.warn("密码必填");
}
if (Objects.equals("***", dbDatasource.getSourcePassword())) {
dbDatasource.setSourcePassword(null);
}
// 这三项不需要修改
dbDatasource.setCreateTime(null);
dbDatasource.setCreateUserId(null);
dbDatasource.setCreateUserName(null);
Long sourceId = Optional.ofNullable(dbDatasource.getId()).orElse(0L);
if (sourceId > 0) {
dbDatasourceService.updateById(dbDatasource);
// 关闭旧数据源
databaseRegistrationBean.closeDatasource(dbDatasource.getId());
} else {
DocUserDetails currentUser = DocUserUtil.getCurrentUser();
dbDatasource.setCreateTime(new Date());
dbDatasource.setCreateUserId(currentUser.getUserId());
dbDatasource.setCreateUserName(currentUser.getUsername());
dbDatasource.setYn(1);
dbDatasourceService.save(dbDatasource);
}
return DocDbResponseJson.ok();
}
}

View File

@@ -1,221 +0,0 @@
package org.dromara.zyplayer.db.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.dromara.zyplayer.core.annotation.AuthMan;
import org.dromara.zyplayer.core.exception.ConfirmException;
import org.dromara.zyplayer.data.config.security.DocUserDetails;
import org.dromara.zyplayer.data.config.security.DocUserUtil;
import org.dromara.zyplayer.data.repository.manage.entity.DbProcLog;
import org.dromara.zyplayer.data.repository.support.consts.DocAuthConst;
import org.dromara.zyplayer.data.repository.support.consts.DocSysModuleType;
import org.dromara.zyplayer.data.repository.support.consts.DocSysType;
import org.dromara.zyplayer.data.service.manage.DbProcLogService;
import org.dromara.zyplayer.db.controller.param.ProcedureListParam;
import org.dromara.zyplayer.db.framework.consts.DbAuthType;
import org.dromara.zyplayer.db.framework.db.dto.ProcedureDto;
import org.dromara.zyplayer.db.framework.db.mapper.base.ExecuteResult;
import org.dromara.zyplayer.db.framework.json.DocDbResponseJson;
import org.dromara.zyplayer.db.service.database.DatabaseServiceFactory;
import org.dromara.zyplayer.db.service.database.DbBaseService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
/**
* 存储过程管理控制器
*
* @author 暮光:城中城
* @since 2021年4月24日
*/
@AuthMan
@RestController
@RequestMapping("/zyplayer-doc-db/procedure")
public class DbProcedureController {
private static final Logger logger = LoggerFactory.getLogger(DbProcedureController.class);
@Resource
DatabaseServiceFactory databaseServiceFactory;
@Resource
DbProcLogService dbProcLogService;
/**
* 存储过程列表
*
* @param procedureParam 参数
* @return 列表
*/
@PostMapping(value = "/list")
public DocDbResponseJson list(ProcedureListParam procedureParam) {
try {
DbBaseService dbBaseService = databaseServiceFactory.getDbBaseService(procedureParam.getSourceId());
procedureParam.setOffset((procedureParam.getPageNum() - 1) * procedureParam.getPageSize());
List<ProcedureDto> procedureDtoList = dbBaseService.getProcedureList(procedureParam);
DocDbResponseJson responseJson = DocDbResponseJson.ok(procedureDtoList);
if (procedureParam.getPageNum() == 1) {
responseJson.setTotal(dbBaseService.getProcedureCount(procedureParam));
}
return responseJson;
} catch (Exception e) {
// 一般是数据库的帐号没权限查存储过程
return DocDbResponseJson.error(e.getMessage());
}
}
/**
* 获取函数详情
*
* @param sourceId 数据源ID
* @param dbName 数据库名
* @param typeName 类型名
* @param procName 函数名
* @return 详情
*/
@PostMapping(value = "/detail")
public DocDbResponseJson detail(Long sourceId, String dbName, String typeName, String procName) {
DbBaseService dbBaseService = databaseServiceFactory.getDbBaseService(sourceId);
try {
ProcedureDto procedureDto = dbBaseService.getProcedureDetail(sourceId, dbName, typeName, procName);
return DocDbResponseJson.ok(procedureDto);
} catch (Exception e) {
// 一般是数据库的帐号没权限查存储过程
return DocDbResponseJson.error(e.getMessage());
}
}
/**
* 删除函数
*
* @param sourceId 数据源ID
* @param dbName 数据库名
* @param typeName 类型名
* @param procName 函数名
* @return 结果
*/
@PostMapping(value = "/delete")
public DocDbResponseJson delete(Long sourceId, String dbName, String typeName, String procName) {
this.judgeAuth(sourceId, DbAuthType.PROC_EDIT.getName(), "没有修改该库函数的权限");
DbProcLog dbProcLog = this.createDbProcLog(sourceId, dbName, typeName, procName, "删除函数操作");
try {
DbBaseService dbBaseService = databaseServiceFactory.getDbBaseService(sourceId);
dbBaseService.deleteProcedure(sourceId, dbName, typeName, procName);
return DocDbResponseJson.ok();
} catch (Exception e) {
dbProcLog.setStatus(2);
// 一般是数据库的帐号没权限查存储过程
return DocDbResponseJson.error(e.getMessage());
} finally {
dbProcLogService.save(dbProcLog);
}
}
/**
* 保存函数
*
* @param sourceId 数据源ID
* @param dbName 数据库名
* @param typeName 类型名
* @param procName 函数名
* @param procSql 存储过程创建SQL
* @return 结果
*/
@PostMapping(value = "/save")
public DocDbResponseJson save(Long sourceId, String dbName, String typeName, String procName, String procSql) {
this.judgeAuth(sourceId, DbAuthType.PROC_EDIT.getName(), "没有修改该库函数的权限");
DbProcLog dbProcLog = this.createDbProcLog(sourceId, dbName, typeName, procName, procSql);
try {
DbBaseService dbBaseService = databaseServiceFactory.getDbBaseService(sourceId);
ExecuteResult executeResult = dbBaseService.saveProcedure(sourceId, dbName, typeName, procName, procSql);
if (StringUtils.isNotBlank(executeResult.getErrMsg())) {
dbProcLog.setStatus(2);
}
return DocDbResponseJson.ok(executeResult);
} catch (Exception e) {
dbProcLog.setStatus(2);
// 一般是数据库的帐号没权限查存储过程
return DocDbResponseJson.error(e.getMessage());
} finally {
dbProcLogService.save(dbProcLog);
}
}
/**
* 存储过程修改日志列表
*
* @param sourceId 数据源ID
* @param dbName 数据库名
* @param typeName 类型名
* @param procName 函数名
* @return 列表
*/
@PostMapping(value = "/log/list")
public DocDbResponseJson logList(Integer pageNum, Integer pageSize, Long sourceId, String dbName, String typeName, String procName) {
QueryWrapper<DbProcLog> wrapper = new QueryWrapper<>();
wrapper.eq("datasource_id", sourceId);
wrapper.eq("proc_db", dbName);
wrapper.eq("proc_name", procName);
wrapper.eq("proc_type", typeName);
wrapper.orderByDesc("id");
wrapper.select("id", "proc_body", "create_user_name", "create_time", "status");
IPage<DbProcLog> page = new Page<>(pageNum, pageSize, pageNum == 1);
dbProcLogService.page(page, wrapper);
return DocDbResponseJson.ok(page);
}
/**
* 存储过程修改日志详情
*
* @param logId 日志ID
* @return 详情
*/
@PostMapping(value = "/log/detail")
public DocDbResponseJson logDetail(Long logId) {
DbProcLog dbProcLog = dbProcLogService.getById(logId);
return DocDbResponseJson.ok(dbProcLog);
}
/**
* 权限判断
*
* @author 暮光:城中城
*/
private void judgeAuth(Long sourceId, String authName, String noAuthInfo) {
if (!DocUserUtil.haveAuth(DocAuthConst.DB_DATASOURCE_MANAGE)
&& !DocUserUtil.haveCustomAuth(authName, DocSysType.DB.getType(), DocSysModuleType.Db.DATASOURCE.getType(), sourceId)) {
throw new ConfirmException(noAuthInfo);
}
}
/**
* 创建日志对象
*
* @param sourceId
* @param dbName
* @param typeName
* @param procName
* @param procSql
* @return
*/
public DbProcLog createDbProcLog(Long sourceId, String dbName, String typeName, String procName, String procSql) {
DocUserDetails currentUser = DocUserUtil.getCurrentUser();
DbProcLog dbProcLog = new DbProcLog();
dbProcLog.setDatasourceId(sourceId);
dbProcLog.setCreateTime(new Date());
dbProcLog.setCreateUserId(currentUser.getUserId());
dbProcLog.setCreateUserName(currentUser.getUsername());
dbProcLog.setProcDb(dbName);
dbProcLog.setProcName(procName);
dbProcLog.setProcType(typeName);
dbProcLog.setProcBody(procSql);
dbProcLog.setStatus(1);
return dbProcLog;
}
}

View File

@@ -1,240 +0,0 @@
package org.dromara.zyplayer.db.controller;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.alibaba.druid.DbType;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
import com.alibaba.druid.sql.parser.SQLStatementParser;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import org.dromara.zyplayer.core.annotation.AuthMan;
import org.dromara.zyplayer.data.config.security.DocUserDetails;
import org.dromara.zyplayer.data.config.security.DocUserUtil;
import org.dromara.zyplayer.data.repository.manage.entity.DbFavorite;
import org.dromara.zyplayer.data.repository.manage.entity.DbHistory;
import org.dromara.zyplayer.data.repository.support.consts.DocAuthConst;
import org.dromara.zyplayer.data.repository.support.consts.DocSysModuleType;
import org.dromara.zyplayer.data.repository.support.consts.DocSysType;
import org.dromara.zyplayer.data.service.manage.DbFavoriteService;
import org.dromara.zyplayer.data.service.manage.DbHistoryService;
import org.dromara.zyplayer.db.framework.consts.DbAuthType;
import org.dromara.zyplayer.db.framework.db.mapper.base.ColumnExecuteResult;
import org.dromara.zyplayer.db.framework.db.mapper.base.ColumnSqlExecutor;
import org.dromara.zyplayer.db.framework.db.mapper.base.ExecuteParam;
import org.dromara.zyplayer.db.framework.db.mapper.base.ExecuteType;
import org.dromara.zyplayer.db.framework.db.transfer.SqlParseUtil;
import org.dromara.zyplayer.db.framework.json.DocDbResponseJson;
import org.dromara.zyplayer.db.framework.utils.SQLTransformUtils;
import org.dromara.zyplayer.db.service.database.DatabaseServiceFactory;
import org.dromara.zyplayer.db.service.database.DbBaseService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.*;
/**
* sql执行器
*
* @author 暮光:城中城
* @since 2019年8月18日
*/
@AuthMan
@RestController
@RequestMapping("/zyplayer-doc-db/executor")
public class DbSqlExecutorController {
private static final Logger logger = LoggerFactory.getLogger(DbSqlExecutorController.class);
@Resource
ColumnSqlExecutor columnSqlExecutor;
@Resource
DbHistoryService dbHistoryService;
@Resource
DbFavoriteService dbFavoriteService;
@Resource
DatabaseServiceFactory databaseServiceFactory;
/**
* sql执行器
* @param sourceId
* @param executeId
* @param dbName
* @param sql
* @param params
* @param pageSize
* @param pageNum
* @param type noPage:无分页 其他:有分页
* @return
*/
@PostMapping(value = "/execute")
public DocDbResponseJson execute(Long sourceId, String executeId, String dbName, String sql, String params,Integer pageSize,Integer pageNum,String type) {
if (StringUtils.isBlank(sql)) {
return DocDbResponseJson.warn("执行的SQL不能为空");
}
boolean manageAuth = DocUserUtil.haveAuth(DocAuthConst.DB_DATASOURCE_MANAGE);
boolean select = DocUserUtil.haveCustomAuth(DbAuthType.SELECT.getName(), DocSysType.DB.getType(), DocSysModuleType.Db.DATASOURCE.getType(), sourceId);
boolean update = DocUserUtil.haveCustomAuth(DbAuthType.UPDATE.getName(), DocSysType.DB.getType(), DocSysModuleType.Db.DATASOURCE.getType(), sourceId);
if (!manageAuth && !select && !update) {
return DocDbResponseJson.warn("没有该数据源的执行权限");
}
DbBaseService dbBaseService = databaseServiceFactory.getDbBaseService(sourceId);
String useDbSql = dbBaseService.getUseDbSql(dbName);
// 保留历史记录
dbHistoryService.saveHistory(sql.trim(), params, sourceId);
// 参数处理
Map<String, Object> paramMap = JSON.parseObject(params);
// 解析出多个执行的SQL
List<Map<String,Object>> analysisQuerySqlList = new LinkedList<>();
try {
String driverClassName = dbBaseService.getDatabaseProduct().getDriverClassName();
List<SQLStatement> sqlStatements;
//根据驱动程序类名获取数据库类型
DbType dbType = SQLTransformUtils.getDbTypeByDriverClassName(driverClassName);
sqlStatements = new SQLStatementParser(sql,dbType).parseStatementList();
for (SQLStatement sqlStatement : sqlStatements) {
StringBuffer sb = new StringBuffer(sqlStatement.toString());
if(sb.length()>0&&';' == (sb.charAt(sb.length()-1))){
sb.deleteCharAt(sb.length()-1);
}
Map<String,Object> map = new HashMap<>();
//原始sql
map.put("originalSql",sb);
//sql解析类型
map.put("sqlType","");
//获取数据总量sql
map.put("getAllCountSql","");
//判断sql解析类型
if(sqlStatement instanceof SQLSelectStatement){
map.put("getAllCountSql","select count(1) from ("+sb+") r");
map.put("sqlType","select");
}
analysisQuerySqlList.add(map);
}
} catch (Exception e) {
return DocDbResponseJson.warn("SQL解析失败" + e.getMessage());
}
// 执行条数太多,反应慢,展示结果栏太多,也不应该在这一次执行很多条语句,应该使用导入
if (analysisQuerySqlList.size() > 20) {
return DocDbResponseJson.warn("单次执行最多支持20条语句同时执行当前语句条数" + analysisQuerySqlList.size());
}
List<ColumnExecuteResult> resultList = new LinkedList<>();
for (int i = 0; i < analysisQuerySqlList.size(); i++) {
Map<String, Object> map = analysisQuerySqlList.get(i);
ColumnExecuteResult executeResult;
ColumnExecuteResult executeCountResult;
//原始sql
String originalSql = map.get("originalSql").toString();
try {
ExecuteType executeType = (manageAuth || update) ? ExecuteType.ALL : ExecuteType.SELECT;
ExecuteParam executeParam = new ExecuteParam();
executeParam.setDatasourceId(sourceId);
executeParam.setExecuteId(executeId);
executeParam.setExecuteType(executeType);
executeParam.setPrefixSql(useDbSql);
if(!StrUtil.equals(type,"noPage")){
executeParam.setMaxRows(1000);
}
//sql解析类型为select
if(map.get("sqlType").equals("select")){
if(StrUtil.equals(type,"noPage")){
executeParam = SqlParseUtil.getSingleExecuteParam(executeParam,originalSql, paramMap);
//设置最后一次标志
if(i==analysisQuerySqlList.size()-1){
executeParam.setIsLastTime(true);
}
executeResult = columnSqlExecutor.execute(executeParam);
resultList.add(executeResult);
continue;
}
//获取总数据量sql
String getAllCountSql = map.get("getAllCountSql").toString();
executeParam = SqlParseUtil.getSingleExecuteParam(executeParam,getAllCountSql, paramMap);
executeCountResult = columnSqlExecutor.execute(executeParam);
List<List<Object>> data = executeCountResult.getData();
long count = 0;
if(data!=null){
count = Long.parseLong(data.get(0).get(0)+"");
}
//设置最后一次标志
if(i==analysisQuerySqlList.size()-1){
executeParam.setIsLastTime(true);
}
//总数据量大于1000进行分页
if(count>1000){
String pageSql = dbBaseService.getQueryPageSqlBySql(originalSql,pageSize,pageNum);
executeParam = SqlParseUtil.getSingleExecuteParam(executeParam,pageSql, paramMap);
executeResult = columnSqlExecutor.execute(executeParam);
executeResult.setSelectCount(count);
resultList.add(executeResult);
continue;
}
}
executeParam = SqlParseUtil.getSingleExecuteParam(executeParam,originalSql, paramMap);
executeResult = columnSqlExecutor.execute(executeParam);
} catch (Exception e) {
logger.error("执行出错", e);
executeResult = ColumnExecuteResult.error(originalSql, e.getMessage(), e);
}
resultList.add(executeResult);
}
//预处理返回数据(解决大数据量下的性能问题)
JSONArray array = JSONUtil.parseArray(resultList);
return DocDbResponseJson.ok(array);
}
@PostMapping(value = "/cancel")
public DocDbResponseJson cancel(String executeId) {
columnSqlExecutor.cancel(executeId);
return DocDbResponseJson.ok();
}
@PostMapping(value = "/history/list")
public DocDbResponseJson historyList(Long sourceId) {
UpdateWrapper<DbHistory> wrapper = new UpdateWrapper<>();
wrapper.eq(sourceId != null, "datasource_id", sourceId);
wrapper.orderByDesc("id");
List<DbHistory> favoriteList = dbHistoryService.list(wrapper);
return DocDbResponseJson.ok(favoriteList);
}
@PostMapping(value = "/favorite/list")
public DocDbResponseJson favoriteList(Long sourceId) {
DocUserDetails currentUser = DocUserUtil.getCurrentUser();
UpdateWrapper<DbFavorite> wrapper = new UpdateWrapper<>();
wrapper.eq(sourceId != null, "datasource_id", sourceId);
wrapper.eq("create_user_id", currentUser.getUserId());
wrapper.eq("yn", 1);
wrapper.orderByDesc("id");
List<DbFavorite> favoriteList = dbFavoriteService.list(wrapper);
return DocDbResponseJson.ok(favoriteList);
}
@PostMapping(value = "/favorite/add")
public DocDbResponseJson addFavorite(DbFavorite dbFavorite) {
Integer yn = Optional.ofNullable(dbFavorite.getYn()).orElse(1);
if (yn == 1) {
if (StringUtils.isBlank(dbFavorite.getContent())) {
return DocDbResponseJson.warn("收藏的SQL不能为空");
}
dbFavorite.setContent(dbFavorite.getContent().trim());
}
DocUserDetails currentUser = DocUserUtil.getCurrentUser();
if (dbFavorite.getId() != null && dbFavorite.getId() > 0) {
dbFavoriteService.updateById(dbFavorite);
} else {
dbFavorite.setCreateTime(new Date());
dbFavorite.setCreateUserId(currentUser.getUserId());
dbFavorite.setCreateUserName(currentUser.getUsername());
dbFavorite.setYn(1);
dbFavoriteService.save(dbFavorite);
}
return DocDbResponseJson.ok();
}
}

View File

@@ -1,138 +0,0 @@
package org.dromara.zyplayer.db.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.dromara.zyplayer.core.annotation.AuthMan;
import org.dromara.zyplayer.data.repository.manage.entity.DbTableRelation;
import org.dromara.zyplayer.data.repository.manage.param.TableRelationParam;
import org.dromara.zyplayer.data.repository.manage.vo.TableRelationVo;
import org.dromara.zyplayer.data.service.manage.DbTableRelationService;
import org.dromara.zyplayer.db.controller.vo.TableColumnVo;
import org.dromara.zyplayer.db.framework.consts.DbAuthType;
import org.dromara.zyplayer.db.framework.db.dto.TableColumnDescDto;
import org.dromara.zyplayer.db.framework.json.DocDbResponseJson;
import org.dromara.zyplayer.db.service.database.DatabaseServiceFactory;
import org.dromara.zyplayer.db.service.database.DbBaseService;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.*;
/**
* 表关系控制器
*
* @author 暮光:城中城
* @since 2021年6月6日
*/
@AuthMan
@RestController
@RequestMapping("/zyplayer-doc-db/table-relation")
public class DbTableRelationController {
private static final Logger logger = LoggerFactory.getLogger(DbTableRelationController.class);
@Resource
DatabaseServiceFactory databaseServiceFactory;
@Resource
DbTableRelationService dbTableRelationService;
@PostMapping(value = "/update")
public DocDbResponseJson update(TableRelationParam param) {
DbBaseService dbBaseService = databaseServiceFactory.getDbBaseService(param.getSourceId());
dbBaseService.judgeAuth(param.getSourceId(), DbAuthType.UPDATE.getName(), "没有该库的执行权限");
dbTableRelationService.update(param);
return DocDbResponseJson.ok();
}
@PostMapping(value = "/getRelation")
public DocDbResponseJson getRelation(TableRelationParam param) {
TableRelationVo relationVo = new TableRelationVo();
relationVo.setDbName(param.getDbName());
relationVo.setName(param.getTableName());
DbBaseService dbBaseService = databaseServiceFactory.getDbBaseService(param.getSourceId());
TableColumnVo tableColumn = dbBaseService.getTableColumnList(param.getSourceId(), param.getDbName(), param.getTableName());
if (CollectionUtils.isNotEmpty(tableColumn.getColumnList())) {
Set<String> drillPath = new HashSet<>();
List<TableRelationVo> childrenRelationList = new LinkedList<>();
for (TableColumnDescDto columnDto : tableColumn.getColumnList()) {
drillPath.add(param.getDbName() + "." + param.getTableName() + "." + columnDto.getName());
TableRelationVo relationVoChildren = new TableRelationVo();
relationVoChildren.setNodeType(1);
relationVoChildren.setDbName(param.getDbName());
relationVoChildren.setTableName(param.getTableName());
relationVoChildren.setName(columnDto.getName());
relationVoChildren.setColumnName(columnDto.getName());
relationVoChildren.setChildren(this.getRelation(param.getSourceId(), param.getDbName(), param.getTableName(), columnDto.getName(), drillPath, 1));
childrenRelationList.add(relationVoChildren);
}
relationVo.setChildren(childrenRelationList);
}
return DocDbResponseJson.ok(relationVo);
}
public List<TableRelationVo> getRelation(Long sourceId, String dbName, String tableName, String columnName, Set<String> drillPath, int recursion) {
// 最大支持5层关系链展示
if (recursion >= 5) {
return Collections.emptyList();
}
QueryWrapper<DbTableRelation> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("datasource_id", sourceId);
queryWrapper.and(wrapper -> wrapper.or(or -> or.eq("start_db_name", dbName)
.eq("start_table_name", tableName)
.eq("start_column_name", columnName)
).or(or -> or.eq("end_db_name", dbName)
.eq("end_table_name", tableName)
.eq("end_column_name", columnName)
));
List<TableRelationVo> resultRelationList = new LinkedList<>();
List<DbTableRelation> relationList = dbTableRelationService.list(queryWrapper);
if (CollectionUtils.isEmpty(relationList)) {
return resultRelationList;
}
DbBaseService dbBaseService = databaseServiceFactory.getDbBaseService(sourceId);
for (DbTableRelation tableRelation : relationList) {
String endDbName = tableRelation.getStartDbName();
String endTableName = tableRelation.getStartTableName();
String endColumnName = tableRelation.getStartColumnName();
if (Objects.equals(tableRelation.getStartDbName(), dbName)
&& Objects.equals(tableRelation.getStartTableName(), tableName)
&& Objects.equals(tableRelation.getStartColumnName(), columnName)) {
endDbName = tableRelation.getEndDbName();
endTableName = tableRelation.getEndTableName();
endColumnName = tableRelation.getEndColumnName();
}
if (drillPath.contains(endDbName + "." + endTableName + "." + endColumnName)) {
continue;
}
TableRelationVo relationVo = new TableRelationVo();
relationVo.setDbName(endDbName);
relationVo.setTableName(endTableName);
relationVo.setName("表:" + endTableName + "\n列" + endColumnName);
relationVo.setColumnName(endColumnName);
TableColumnVo tableColumn = dbBaseService.getTableColumnList(sourceId, endDbName, endTableName);
if (CollectionUtils.isNotEmpty(tableColumn.getColumnList())) {
List<TableRelationVo> childrenRelationList = new LinkedList<>();
for (TableColumnDescDto columnDto : tableColumn.getColumnList()) {
boolean contains = drillPath.contains(endDbName + "." + endTableName + "." + columnDto.getName());
drillPath.add(endDbName + "." + endTableName + "." + columnDto.getName());
TableRelationVo relationVoChildren = new TableRelationVo();
relationVoChildren.setNodeType(1);
relationVoChildren.setDbName(endDbName);
relationVoChildren.setTableName(endTableName);
relationVoChildren.setName(columnDto.getName());
relationVoChildren.setColumnName(columnDto.getName());
if (!contains) {
relationVoChildren.setChildren(this.getRelation(sourceId, endDbName, endTableName, columnDto.getName(), drillPath, recursion + 1));
}
childrenRelationList.add(relationVoChildren);
}
relationVo.setChildren(childrenRelationList);
}
resultRelationList.add(relationVo);
}
return resultRelationList;
}
}

View File

@@ -1,94 +0,0 @@
package org.dromara.zyplayer.db.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.dromara.zyplayer.core.annotation.AuthMan;
import org.dromara.zyplayer.data.config.security.DocUserDetails;
import org.dromara.zyplayer.data.config.security.DocUserUtil;
import org.dromara.zyplayer.data.repository.manage.entity.DbTransferTask;
import org.dromara.zyplayer.data.service.manage.DbTransferTaskService;
import org.dromara.zyplayer.db.framework.db.transfer.SqlParseUtil;
import org.dromara.zyplayer.db.framework.db.transfer.TransferDataServer;
import org.dromara.zyplayer.db.framework.json.DocDbResponseJson;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
/**
* 数据互导工具
*
* @author 暮光:城中城
* @since 2019年9月28日
*/
@AuthMan
@RestController
@RequestMapping("/zyplayer-doc-db/transfer")
public class DbTransferDataController {
@Resource
TransferDataServer transferDataServer;
@Resource
DbTransferTaskService dbTransferTaskService;
@PostMapping(value = "/start")
public DocDbResponseJson doTransfer(Long id) {
transferDataServer.transferData(id);
return DocDbResponseJson.ok();
}
@PostMapping(value = "/cancel")
public DocDbResponseJson cancel(Long id) {
transferDataServer.cancel(id);
return DocDbResponseJson.ok();
}
@PostMapping(value = "/list")
public DocDbResponseJson list() {
QueryWrapper<DbTransferTask> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("del_flag", 0);
queryWrapper.select(
"id", "name", "query_datasource_id", "storage_datasource_id", "need_count", "last_execute_status",
"query_sql", "storage_sql", "last_execute_time", "create_user_name", "create_time"
);
List<DbTransferTask> taskList = dbTransferTaskService.list(queryWrapper);
return DocDbResponseJson.ok(taskList);
}
@PostMapping(value = "/detail")
public DocDbResponseJson detail(Long id) {
DbTransferTask transferTask = dbTransferTaskService.getById(id);
return DocDbResponseJson.ok(transferTask);
}
@PostMapping(value = "/update")
public DocDbResponseJson update(DbTransferTask transferTask) {
DbTransferTask transferTaskUp = new DbTransferTask();
if (transferTask.getId() == null) {
DocUserDetails currentUser = DocUserUtil.getCurrentUser();
transferTaskUp.setCreateTime(new Date());
transferTaskUp.setCreateUserId(currentUser.getUserId());
transferTaskUp.setCreateUserName(currentUser.getUsername());
transferTaskUp.setDelFlag(0);
} else {
transferTaskUp.setId(transferTask.getId());
}
transferTaskUp.setName(transferTask.getName());
transferTaskUp.setQueryDatasourceId(transferTask.getQueryDatasourceId());
transferTaskUp.setStorageDatasourceId(transferTask.getStorageDatasourceId());
transferTaskUp.setQuerySql(transferTask.getQuerySql());
transferTaskUp.setStorageSql(transferTask.getStorageSql());
transferTaskUp.setNeedCount(transferTask.getNeedCount());
transferTaskUp.setDelFlag(transferTask.getDelFlag());
dbTransferTaskService.saveOrUpdate(transferTaskUp);
return DocDbResponseJson.ok();
}
@PostMapping("/sqlColumns")
public DocDbResponseJson sqlColumns(String sql) {
List<String> selectNames = SqlParseUtil.getSelectNames(sql);
return DocDbResponseJson.ok(selectNames);
}
}

View File

@@ -1,121 +0,0 @@
package org.dromara.zyplayer.db.controller.download;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.dromara.zyplayer.core.exception.ConfirmException;
import org.dromara.zyplayer.core.util.ZyplayerDocVersion;
import org.dromara.zyplayer.db.controller.param.DataViewParam;
import org.dromara.zyplayer.db.controller.vo.TableColumnVo;
import org.dromara.zyplayer.db.framework.db.dto.TableColumnDescDto;
import org.dromara.zyplayer.db.framework.db.mapper.base.ExecuteParam;
import org.dromara.zyplayer.db.framework.db.mapper.base.ExecuteType;
import org.dromara.zyplayer.db.service.common.ExecuteAuthService;
import org.dromara.zyplayer.db.service.database.DatabaseServiceFactory;
import org.dromara.zyplayer.db.service.database.DbBaseService;
import org.dromara.zyplayer.db.service.download.BaseDownloadService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 公共的格式化数据下载服务适用于insert、update、json
*
* @author 暮光:城中城
* @since 2021-08-14
*/
@Service(FormatDownloadConst.COMMON)
public class CommonFormatDownloadService implements FormatDownloadService {
@Resource
ExecuteAuthService executeAuthService;
@Resource
DatabaseServiceFactory databaseServiceFactory;
@Resource
BaseDownloadService baseDownloadService;
@Override
public void download(HttpServletResponse response, DataViewParam param, String[] tableNameArr) throws Exception {
DbBaseService dbBaseService = databaseServiceFactory.getDbBaseService(param.getSourceId());
boolean multipleFile = Objects.equals(param.getDownloadFileType(), 2);
boolean isJson = Objects.equals(param.getDownloadType(), FormatDownloadConst.JSON);
boolean isUpdate = Objects.equals(param.getDownloadType(), FormatDownloadConst.UPDATE);
// 此服务支持的下载格式判断
if (!FormatDownloadConst.INSERT.equals(param.getDownloadType())
&& !FormatDownloadConst.UPDATE.equals(param.getDownloadType())
&& !FormatDownloadConst.JSON.equals(param.getDownloadType())) {
throw new ConfirmException("不支持的数据下载格式");
}
JSONObject conditionMap = StringUtils.isBlank(param.getConditionJson()) ? new JSONObject() : JSON.parseObject(param.getConditionJson());
JSONObject conditionColumnMap = StringUtils.isBlank(param.getConditionColumnJson()) ? new JSONObject() : JSON.parseObject(param.getConditionColumnJson());
JSONObject getRetainColumnMap = StringUtils.isBlank(param.getRetainColumnJson()) ? new JSONObject() : JSON.parseObject(param.getRetainColumnJson());
// 结果
StringBuilder resultSb = new StringBuilder("/*\n" +
" 数据库 : " + param.getDbName() + "\n" +
" 数据库类型 : " + dbBaseService.getDatabaseProduct().name() + "\n" +
" 导出时间 : " + DateTime.now() + "\n" +
" 导出软件 : zyplayer-doc\n" +
" 软件版本 : " + ZyplayerDocVersion.version + "\n" +
"*/\n\n");
String tempDir = System.getProperty("java.io.tmpdir");
String tempDirName = tempDir + "zyplayer-doc-" + IdUtil.fastSimpleUUID();
try {
// 创建临时文件夹
FileUtil.mkdir(tempDirName);
// 再分表查数据
String suffix = isJson ? ".json" : ".sql";
for (String tableName : tableNameArr) {
param.setTableName(tableName);
param.setCondition(conditionMap.getString(tableName));
param.setConditionColumn(conditionColumnMap.getString(tableName));
param.setRetainColumn(getRetainColumnMap.getString(tableName));
ExecuteType executeType = executeAuthService.getExecuteType(param.getSourceId());
// 获取列信息等
TableColumnVo tableColumnVo = dbBaseService.getTableColumnList(param.getSourceId(), param.getDbName(), tableName);
List<TableColumnDescDto> columnList = tableColumnVo.getColumnList();
// 默认找主键作为更新条件
Set<String> primaryKeyColumnSet = columnList.stream().filter(item -> Objects.equals(item.getPrimaryKey(), "1")).map(TableColumnDescDto::getName).collect(Collectors.toSet());
// 更新条件列
Set<String> conditionColumnSet = new HashSet<>();
if (isUpdate) {
conditionColumnSet.addAll(StringUtils.isBlank(param.getConditionColumn()) ? primaryKeyColumnSet : Stream.of(param.getConditionColumn().split(",")).collect(Collectors.toSet()));
}
// 保留的列
Set<String> retainColumnSet = StringUtils.isBlank(param.getRetainColumn()) ? Collections.emptySet() : Stream.of(param.getRetainColumn().split(",")).collect(Collectors.toSet());
List<TableColumnDescDto> columnListRetain = columnList.stream().filter(item -> retainColumnSet.isEmpty() || retainColumnSet.contains(item.getName()) || conditionColumnSet.contains(item.getName())).collect(Collectors.toList());
// 数据查询
String queryAllSql = dbBaseService.getQueryAllSql(param);
ExecuteParam executeParam = new ExecuteParam();
executeParam.setDatasourceId(param.getSourceId());
executeParam.setExecuteId(param.getExecuteId());
executeParam.setExecuteType(executeType);
executeParam.setSql(queryAllSql);
String downloadTableData = dbBaseService.getDownloadTableData(param, executeParam, columnListRetain, conditionColumnSet);
// 写入临时文件
if (multipleFile) {
File tempFile = FileUtil.file(tempDirName + "/" + tableName + suffix);
String tableDataSb = isJson ? downloadTableData : resultSb + String.format("-- 导出数据表:`%s`.`%s` --\n", param.getDbName(), tableName) + downloadTableData;
FileUtil.writeUtf8String(tableDataSb, tempFile);
} else {
resultSb.append(String.format("-- 导出数据表:`%s`.`%s` --\n", param.getDbName(), tableName));
resultSb.append(downloadTableData).append("\n");
}
}
if (multipleFile) {
baseDownloadService.sendResponse(response, param.getDbName(), tempDirName);
} else {
baseDownloadService.sendResponse(response, param.getDbName(), suffix, resultSb.toString());
}
} finally {
FileUtil.del(tempDirName);
}
}
}

View File

@@ -1,167 +0,0 @@
package org.dromara.zyplayer.db.controller.download;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.dromara.zyplayer.db.controller.param.DataViewParam;
import org.dromara.zyplayer.db.controller.vo.TableColumnVo;
import org.dromara.zyplayer.db.framework.db.dto.TableColumnDescDto;
import org.dromara.zyplayer.db.framework.db.mapper.base.ExecuteParam;
import org.dromara.zyplayer.db.framework.db.mapper.base.ExecuteResult;
import org.dromara.zyplayer.db.framework.db.mapper.base.ExecuteType;
import org.dromara.zyplayer.db.framework.db.mapper.base.SqlExecutor;
import org.dromara.zyplayer.db.framework.utils.SQLTransformUtils;
import org.dromara.zyplayer.db.service.common.ExecuteAuthService;
import org.dromara.zyplayer.db.service.database.DatabaseServiceFactory;
import org.dromara.zyplayer.db.service.database.DbBaseService;
import org.dromara.zyplayer.db.service.download.BaseDownloadService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.net.URLEncoder;
import java.sql.Clob;
import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* excel格式化数据下载服务
*
* @author 暮光:城中城
* @since 2021-08-14
*/
@Service(FormatDownloadConst.EXCEL)
public class ExcelFormatDownloadService implements FormatDownloadService {
private static final Logger logger = LoggerFactory.getLogger(ExcelFormatDownloadService.class);
@Resource
ExecuteAuthService executeAuthService;
@Resource
DatabaseServiceFactory databaseServiceFactory;
@Resource
BaseDownloadService baseDownloadService;
@Resource
SqlExecutor sqlExecutor;
@Override
public void download(HttpServletResponse response, DataViewParam param, String[] tableNameArr) throws Exception {
DbBaseService dbBaseService = databaseServiceFactory.getDbBaseService(param.getSourceId());
boolean multipleFile = Objects.equals(param.getDownloadFileType(), 2);
JSONObject conditionMap = StringUtils.isBlank(param.getConditionJson()) ? new JSONObject() : JSON.parseObject(param.getConditionJson());
JSONObject conditionColumnMap = StringUtils.isBlank(param.getConditionColumnJson()) ? new JSONObject() : JSON.parseObject(param.getConditionColumnJson());
JSONObject getRetainColumnMap = StringUtils.isBlank(param.getRetainColumnJson()) ? new JSONObject() : JSON.parseObject(param.getRetainColumnJson());
// 结果
String tempDir = System.getProperty("java.io.tmpdir");
String tempDirName = tempDir + "zyplayer-doc-" + IdUtil.fastSimpleUUID();
ExcelWriter excelWriter = null;
boolean excelWriterIsFinish = false;
try {
String suffix = ".xlsx";
if (!multipleFile) {
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
String fileNameOrigin = "数据库表数据导出." + DateTime.now().toString("yyyyMMddHHmmss");
String fileName = URLEncoder.encode(fileNameOrigin, "UTF-8");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + suffix);
excelWriter = EasyExcel.write(response.getOutputStream()).build();
}
// 创建临时文件夹
FileUtil.mkdir(tempDirName);
// 再分表查数据
int tableIndex = 0;
for (String tableName : tableNameArr) {
param.setTableName(tableName);
param.setCondition(conditionMap.getString(tableName));
param.setConditionColumn(conditionColumnMap.getString(tableName));
param.setRetainColumn(getRetainColumnMap.getString(tableName));
ExecuteType executeType = executeAuthService.getExecuteType(param.getSourceId());
// 获取列信息等
TableColumnVo tableColumnVo = dbBaseService.getTableColumnList(param.getSourceId(), param.getDbName(), tableName);
List<TableColumnDescDto> columnList = tableColumnVo.getColumnList();
// 保留的列
Set<String> retainColumnSet = StringUtils.isBlank(param.getRetainColumn()) ? Collections.emptySet() : Stream.of(param.getRetainColumn().split(",")).collect(Collectors.toSet());
List<TableColumnDescDto> columnListRetain = columnList.stream().filter(item -> retainColumnSet.isEmpty() || retainColumnSet.contains(item.getName())).collect(Collectors.toList());
// 数据查询
String queryAllSql = dbBaseService.getQueryAllSql(param);
ExecuteParam executeParam = new ExecuteParam();
executeParam.setDatasourceId(param.getSourceId());
executeParam.setExecuteId(param.getExecuteId());
executeParam.setExecuteType(executeType);
executeParam.setSql(queryAllSql);
ExecuteResult executeResult = sqlExecutor.execute(executeParam);
List<Map<String, Object>> executeResultData = executeResult.getResult();
if (CollectionUtils.isEmpty(executeResultData)) {
executeResultData = Collections.emptyList();
if (StringUtils.isNotBlank(executeResult.getErrMsg())) {
logger.error("执行sql失败{} {}", executeResult.getSql(), executeResult.getErrMsg());
}
}
// 处理成表格下载所需格式
List<List<Object>> downloadDataList = new LinkedList<>();
for (Map<String, Object> dataMap : executeResultData) {
downloadDataList.add(new LinkedList<Object>() {{
for (TableColumnDescDto columnDto : columnListRetain) {
Object data = dataMap.get(columnDto.getName());
//CLOB类型数据处理
if(columnDto.getType().equals("CLOB")){
if(data!=null){
data = SQLTransformUtils.ClobToString((Clob) data);
}
}
// 数据格式处理,不处理有些格式会造成乱码,打不开文件
if (!(data == null || data instanceof Number || data instanceof CharSequence)) {
if (data instanceof Timestamp) {
data = DateTime.of(((Timestamp) data).getTime()).toJdkDate();
} else {
data = String.valueOf(data);
}
}
add(data);
}
}});
}
List<List<String>> sheetHeadList = this.getSheetHeadList(columnListRetain);
if (multipleFile) {
// 写入临时文件
File tempFile = FileUtil.file(tempDirName + "/" + tableName + suffix);
EasyExcel.write(tempFile).head(sheetHeadList).sheet(tableName).doWrite(downloadDataList);
} else {
WriteSheet writeSheet = EasyExcel.writerSheet(tableIndex++, tableName).head(sheetHeadList).build();
excelWriter.write(downloadDataList, writeSheet);
}
}
if (multipleFile) {
baseDownloadService.sendResponse(response, param.getDbName(), tempDirName);
} else {
excelWriter.finish();
excelWriterIsFinish = true;
}
} finally {
FileUtil.del(tempDirName);
if (excelWriterIsFinish && excelWriter != null) {
excelWriter.finish();
}
}
}
private List<List<String>> getSheetHeadList(List<TableColumnDescDto> columnListRetain) {
List<List<String>> sheetHeadList = new ArrayList<>();
for (TableColumnDescDto dataCol : columnListRetain) {
sheetHeadList.add(new ArrayList<String>() {{
add(dataCol.getName());
}});
}
return sheetHeadList;
}
}

View File

@@ -1,19 +0,0 @@
package org.dromara.zyplayer.db.controller.download;
/**
* 下载类型枚举
* @author 暮光:城中城
* @since 2021-08-14
*/
public class FormatDownloadConst {
/**
* 公共类型,没有自己的处理类型时使用
*/
public static final String COMMON = "common";
public static final String INSERT = "insert";
public static final String UPDATE = "update";
public static final String JSON = "json";
public static final String EXCEL = "excel";
public static final String CVS = "cvs";
}

View File

@@ -1,29 +0,0 @@
package org.dromara.zyplayer.db.controller.download;
/**
* 下载类型枚举
* @author 暮光:城中城
* @since 2021-08-14
*/
public enum FormatDownloadEnum {
INSERT(FormatDownloadConst.INSERT),
UPDATE(FormatDownloadConst.UPDATE),
JSON(FormatDownloadConst.JSON),
EXCEL(FormatDownloadConst.EXCEL),
CVS(FormatDownloadConst.CVS),
;
private String type;
FormatDownloadEnum(String type) {
this.type = type;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}

View File

@@ -1,17 +0,0 @@
package org.dromara.zyplayer.db.controller.download;
import org.dromara.zyplayer.db.controller.param.DataViewParam;
import javax.servlet.http.HttpServletResponse;
/**
* 下载服务
*
* @author 暮光:城中城
* @since 2021-08-14
*/
public interface FormatDownloadService {
void download(HttpServletResponse response, DataViewParam param, String[] tableNameArr) throws Exception;
}

View File

@@ -1,17 +0,0 @@
package org.dromara.zyplayer.db.controller.param;
import lombok.Data;
/**
* 查询参数
* @author 暮光:城中城
* @since 2021-05-20
*/
@Data
public class DataDownloadParam {
private Long sourceId;
private String dbName;
private String tableName;
private String downloadType;
private String conditionColumn;
}

View File

@@ -1,43 +0,0 @@
package org.dromara.zyplayer.db.controller.param;
import lombok.Data;
/**
* 数据预览查询参数
*
* @author 暮光:城中城
* @since 2021-05-20
*/
@Data
public class DataViewParam {
// 基本信息
private String executeId;
private Long sourceId;
private Integer pageSize;
private Integer pageNum;
private String dbName;
private String tableName;
// 保留的列json多个使用英文逗号分隔{"user_info": "id,name,age"}
private String retainColumnJson;
// 查询的条件json{"user_info": "id > 0"}
private String conditionJson;
// 哪些列作为update语句的更新条件json{"user_info": "id,name"}用于update语句拼where条件使用
private String conditionColumnJson;
// 解析之后设置的,待使用
private String condition;
private String retainColumn;
private String conditionColumn;
// 下载多张数据表
private String tableNames;
private String downloadType;
private Integer dropTableFlag;
private Integer createTableFlag;
private Integer downloadFileType;
// 数据查询时使用,导出暂不支持排序
private String orderColumn;
private String orderType;
public Integer getOffset() {
return ((this.pageNum - 1) * this.pageSize);
}
}

View File

@@ -1,20 +0,0 @@
package org.dromara.zyplayer.db.controller.param;
import lombok.Data;
/**
* 存储过程列表查询参数
*
* @author 暮光:城中城
* @since 2021-04-25
*/
@Data
public class ProcedureListParam {
private Long sourceId;
private String dbName;
private Integer pageNum;
private Integer pageSize;
private Integer offset;
private String name;
private String type;
}

View File

@@ -1,27 +0,0 @@
package org.dromara.zyplayer.db.controller.vo;
import org.dromara.zyplayer.db.controller.vo.TableColumnVo.TableInfoVo;
import org.dromara.zyplayer.db.framework.db.dto.TableColumnDescDto;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.List;
import java.util.Map;
/**
* 数据库表导出
*
* @author 暮光:城中城
* @since 2018-11-27
*/
@Data
@AllArgsConstructor
public class DatabaseExportVo {
// 表字段注释信息列表
private Map<String, List<TableColumnDescDto>> columnList;
// 数据库表列表
private List<TableInfoVo> tableList;
}

View File

@@ -1,37 +0,0 @@
package org.dromara.zyplayer.db.controller.vo;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import org.dromara.zyplayer.db.framework.db.dto.TableColumnDescDto;
import lombok.Data;
import java.util.List;
/**
* 表字段信息
*
* @author 暮光:城中城
* @since 2018-11-27
*/
@Data
public class TableColumnVo {
// 表字段注释信息
private List<TableColumnDescDto> columnList;
// 表名+表注释
private TableInfoVo tableInfo;
@Data
public static class TableInfoVo {
@ColumnWidth(20)
@ExcelProperty("表名")
private String tableName;
@ColumnWidth(80)
@ExcelProperty("表注释")
private String description;
}
}

View File

@@ -1,46 +0,0 @@
package org.dromara.zyplayer.db.controller.vo;
import org.dromara.zyplayer.db.framework.db.enums.DatabaseProductEnum;
import lombok.Data;
import java.util.Objects;
/**
* 表ddl信息
*
* @author 暮光:城中城
* @since 2021-04-23
*/
@Data
public class TableDdlVo {
private String current;
private String mysql;
private String sqlserver;
private String oracle;
private String dm;
private String postgresql;
private String hive;
// 获取连接类型的ddl
public String getTableDDLByType() {
if (Objects.equals(current, DatabaseProductEnum.MYSQL.name().toLowerCase())) {
return mysql;
}
if (Objects.equals(current, DatabaseProductEnum.SQLSERVER.name().toLowerCase())) {
return sqlserver;
}
if (Objects.equals(current, DatabaseProductEnum.ORACLE.name().toLowerCase())) {
return oracle;
}
if (Objects.equals(current, DatabaseProductEnum.DM.name().toLowerCase())) {
return dm;
}
if (Objects.equals(current, DatabaseProductEnum.POSTGRESQL.name().toLowerCase())) {
return postgresql;
}
if (Objects.equals(current, DatabaseProductEnum.HIVE.name().toLowerCase())) {
return hive;
}
return null;
}
}

View File

@@ -1,35 +0,0 @@
package org.dromara.zyplayer.db.controller.vo;
import lombok.Data;
import java.util.Date;
/**
* 表基本信息
*
* @author 暮光:城中城
* @since 2019-09-04
*/
@Data
public class TableStatusVo {
// 表名
private String name;
private String engine;
private Long version;
private String rowFormat;
private Long rows;
private Long avgRowLength;
private Long dataLength;
private Long maxDataLength;
private Long indexLength;
private Long dataFree;
private Long autoIncrement;
private Date createTime;
private Date updateTime;
private Date checkTime;
private String collation;
private String checksum;
private String createOptions;
private String comment;
private String dbType;
}

View File

@@ -1,18 +0,0 @@
package org.dromara.zyplayer.db.controller.vo;
import lombok.Data;
/**
* 用户数据库授权信息
*
* @author 暮光:城中城
* @since 2019-08-22
*/
@Data
public class UserDbAuthVo {
private String userName;
private Long userId;
private Integer executeAuth;
private Integer descEditAuth;
private Integer procEditAuth;
}

View File

@@ -1,21 +0,0 @@
package org.dromara.zyplayer.db.framework.configuration;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
/**
* 应用启动监听
*
* @author 暮光:城中城
* @since 2018-11-27
*/
@Component
public class ApplicationListenerBean implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
}
}

View File

@@ -1,62 +0,0 @@
package org.dromara.zyplayer.db.framework.configuration;
import com.alibaba.druid.pool.DruidDataSource;
import org.dromara.zyplayer.core.exception.ConfirmException;
import org.dromara.zyplayer.data.repository.manage.entity.DbDatasource;
import org.dromara.zyplayer.data.utils.DruidDataSourceUtil;
import org.dromara.zyplayer.db.framework.configuration.analysis.*;
import org.dromara.zyplayer.db.framework.db.bean.DatabaseFactoryBean;
import org.dromara.zyplayer.db.framework.db.enums.DatabaseProductEnum;
import org.dromara.zyplayer.db.framework.db.interceptor.SqlLogInterceptor;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.core.io.Resource;
import java.util.HashMap;
import java.util.Map;
/**
* 数据库连接工具类
*
* @author 暮光:城中城
* @since 2019-07-04
*/
public class DatasourceUtil {
private static final SqlLogInterceptor sqlLogInterceptor = new SqlLogInterceptor();
// url解析
private static final Map<String, AnalysisApi> analysisApiMap = new HashMap<String, AnalysisApi>() {{
put(DatabaseProductEnum.MYSQL.getDriverClassName(), new MysqlAnalysis());
put(DatabaseProductEnum.HIVE.getDriverClassName(), new HiveAnalysis());
put(DatabaseProductEnum.ORACLE.getDriverClassName(), new OracleAnalysis());
put(DatabaseProductEnum.DM.getDriverClassName(), new DmAnalysis());
put(DatabaseProductEnum.POSTGRESQL.getDriverClassName(), new PostgresqlAnalysis());
put(DatabaseProductEnum.SQLSERVER.getDriverClassName(), new SqlserverAnalysis());
}};
public static DatabaseFactoryBean createDatabaseFactoryBean(DbDatasource dbDatasource, boolean breakAfterAcquireFailure) throws Exception {
// 描述连接信息的对象
DatabaseFactoryBean databaseFactoryBean = new DatabaseFactoryBean();
String dbUrl = dbDatasource.getSourceUrl();
String driverClassName = dbDatasource.getDriverClassName();
AnalysisApi analysisApi = analysisApiMap.get(driverClassName);
if (analysisApi == null) {
throw new ConfirmException("暂未支持的数据源类型");
}
Resource[] resources = analysisApi.process(dbUrl, databaseFactoryBean);
// 数据源配置
DruidDataSource dataSource = DruidDataSourceUtil.createDataSource(dbDatasource.getDriverClassName(), dbDatasource.getSourceUrl(), dbDatasource.getSourceName(), dbDatasource.getSourcePassword(), breakAfterAcquireFailure);
// 创建sqlSessionTemplate
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
sqlSessionFactoryBean.setMapperLocations(resources);
sqlSessionFactoryBean.setPlugins(sqlLogInterceptor);
SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(sqlSessionFactoryBean.getObject());
// 组装自定义的bean
databaseFactoryBean.setId(dbDatasource.getId());
databaseFactoryBean.setCnName(dbDatasource.getName());
databaseFactoryBean.setDataSource(dataSource);
databaseFactoryBean.setSqlSessionTemplate(sqlSessionTemplate);
databaseFactoryBean.setUrl(dbUrl);
return databaseFactoryBean;
}
}

View File

@@ -1,22 +0,0 @@
package org.dromara.zyplayer.db.framework.configuration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import java.lang.annotation.*;
/**
* 开启db模块的注解
*
* @author 暮光:城中城
* @since 2018-11-27
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@ComponentScan(basePackages = {
"org.dromara.zyplayer.db",
})
public @interface EnableDocDb {
}

View File

@@ -1,16 +0,0 @@
package org.dromara.zyplayer.db.framework.configuration.analysis;
import org.dromara.zyplayer.db.framework.db.bean.DatabaseFactoryBean;
import org.springframework.core.io.Resource;
/**
* 数据库链接url解析api
*
* @author 暮光:城中城
* @since 2021-05-13
*/
public interface AnalysisApi {
Resource[] process(String dbUrl, DatabaseFactoryBean databaseFactoryBean) throws Exception;
}

View File

@@ -1,27 +0,0 @@
package org.dromara.zyplayer.db.framework.configuration.analysis;
import org.dromara.zyplayer.db.framework.db.bean.DatabaseFactoryBean;
import org.dromara.zyplayer.db.framework.db.enums.DatabaseProductEnum;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
/**
* 达梦链接url解析
*
* @author diantu
* @since 2023-02-01
*/
public class DmAnalysis implements AnalysisApi{
@Override
public Resource[] process(String dbUrl, DatabaseFactoryBean databaseFactoryBean) throws Exception {
// jdbc:dm://127.0.0.1:5236?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=utf-8
String[] urlParamArr = dbUrl.split("\\?");
String[] urlDbNameArr = urlParamArr[0].split("://");
urlDbNameArr = urlDbNameArr[0].split(":");
databaseFactoryBean.setDbName(urlDbNameArr[urlDbNameArr.length - 1]);
databaseFactoryBean.setDatabaseProduct(DatabaseProductEnum.DM);
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
return resolver.getResources("classpath:com/zyplayer/doc/db/framework/db/mapper/dm/*.xml");
}
}

View File

@@ -1,29 +0,0 @@
package org.dromara.zyplayer.db.framework.configuration.analysis;
import org.dromara.zyplayer.db.framework.db.bean.DatabaseFactoryBean;
import org.dromara.zyplayer.db.framework.db.enums.DatabaseProductEnum;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
/**
* hive链接url解析
*
* @author 暮光:城中城
* @since 2021-05-13
*/
public class HiveAnalysis implements AnalysisApi {
@Override
public Resource[] process(String dbUrl, DatabaseFactoryBean databaseFactoryBean) throws Exception {
// jdbc:hive2://127.0.0.1:21050/ads_data;auth=noSasl
String[] urlParamArr = dbUrl.split(";");
String[] urlDbNameArr = urlParamArr[0].split("/");
if (urlDbNameArr.length >= 2) {
databaseFactoryBean.setDbName(urlDbNameArr[urlDbNameArr.length - 1]);
}
databaseFactoryBean.setDatabaseProduct(DatabaseProductEnum.HIVE);
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
return resolver.getResources("classpath:com/zyplayer/doc/db/framework/db/mapper/hive/*.xml");
}
}

View File

@@ -1,30 +0,0 @@
package org.dromara.zyplayer.db.framework.configuration.analysis;
import org.dromara.zyplayer.db.framework.db.bean.DatabaseFactoryBean;
import org.dromara.zyplayer.db.framework.db.enums.DatabaseProductEnum;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
/**
* mysql链接url解析
*
* @author 暮光:城中城
* @since 2021-05-13
*/
public class MysqlAnalysis implements AnalysisApi {
@Override
public Resource[] process(String dbUrl, DatabaseFactoryBean databaseFactoryBean) throws Exception {
// jdbc:mysql://192.168.0.1:3306/user_info?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&autoReconnect=true
String[] urlParamArr = dbUrl.split("\\?");
String[] urlDbNameArr = urlParamArr[0].split("/");
if (urlDbNameArr.length >= 2) {
databaseFactoryBean.setDbName(urlDbNameArr[urlDbNameArr.length - 1]);
//databaseFactoryBean.setHost(urlDbNameArr[urlDbNameArr.length - 2]);
}
databaseFactoryBean.setDatabaseProduct(DatabaseProductEnum.MYSQL);
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
return resolver.getResources("classpath:com/zyplayer/doc/db/framework/db/mapper/mysql/*.xml");
}
}

View File

@@ -1,30 +0,0 @@
package org.dromara.zyplayer.db.framework.configuration.analysis;
import org.dromara.zyplayer.db.framework.db.bean.DatabaseFactoryBean;
import org.dromara.zyplayer.db.framework.db.enums.DatabaseProductEnum;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
/**
* Oracle链接url解析
*
* @author 暮光:城中城
* @since 2021-05-13
*/
public class OracleAnalysis implements AnalysisApi {
@Override
public Resource[] process(String dbUrl, DatabaseFactoryBean databaseFactoryBean) throws Exception {
// jdbc:oracle:thin:@127.0.0.1:1521:user_info
String[] urlParamArr = dbUrl.split("\\?")[0].split("@");
String[] urlDbNameArr = urlParamArr[0].split("/");
if (urlDbNameArr.length <= 1) {
urlDbNameArr = urlParamArr[0].split(":");
}
databaseFactoryBean.setDbName(urlDbNameArr[urlDbNameArr.length - 1]);
databaseFactoryBean.setDatabaseProduct(DatabaseProductEnum.ORACLE);
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
return resolver.getResources("classpath:com/zyplayer/doc/db/framework/db/mapper/oracle/*.xml");
}
}

View File

@@ -1,30 +0,0 @@
package org.dromara.zyplayer.db.framework.configuration.analysis;
import org.dromara.zyplayer.db.framework.db.bean.DatabaseFactoryBean;
import org.dromara.zyplayer.db.framework.db.enums.DatabaseProductEnum;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
/**
* Postgresql链接url解析
*
* @author 暮光:城中城
* @since 2021-05-13
*/
public class PostgresqlAnalysis implements AnalysisApi {
@Override
public Resource[] process(String dbUrl, DatabaseFactoryBean databaseFactoryBean) throws Exception {
// jdbc:mysql://192.168.0.1:3306/user_info?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&autoReconnect=true
String[] urlParamArr = dbUrl.split("\\?");
String[] urlDbNameArr = urlParamArr[0].split("/");
if (urlDbNameArr.length >= 2) {
databaseFactoryBean.setDbName(urlDbNameArr[urlDbNameArr.length - 1]);
//databaseFactoryBean.setHost(urlDbNameArr[urlDbNameArr.length - 2]);
}
databaseFactoryBean.setDatabaseProduct(DatabaseProductEnum.POSTGRESQL);
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
return resolver.getResources("classpath:com/zyplayer/doc/db/framework/db/mapper/postgresql/*.xml");
}
}

View File

@@ -1,33 +0,0 @@
package org.dromara.zyplayer.db.framework.configuration.analysis;
import org.dromara.zyplayer.db.framework.db.bean.DatabaseFactoryBean;
import org.dromara.zyplayer.db.framework.db.enums.DatabaseProductEnum;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
/**
* Sqlserver链接url解析
*
* @author 暮光:城中城
* @since 2021-05-13
*/
public class SqlserverAnalysis implements AnalysisApi {
@Override
public Resource[] process(String dbUrl, DatabaseFactoryBean databaseFactoryBean) throws Exception {
// jdbc:jtds:sqlserver://192.168.0.1:33434;socketTimeout=60;DatabaseName=user_info;
String[] urlParamArr = dbUrl.split(";");
//String[] urlDbNameArr = urlParamArr[0].split("/");
//databaseFactoryBean.setHost(urlDbNameArr[urlDbNameArr.length - 1]);
for (String urlParam : urlParamArr) {
String[] keyValArr = urlParam.split("=");
if (keyValArr.length >= 2 && keyValArr[0].equalsIgnoreCase("DatabaseName")) {
databaseFactoryBean.setDbName(keyValArr[1]);
}
}
databaseFactoryBean.setDatabaseProduct(DatabaseProductEnum.SQLSERVER);
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
return resolver.getResources("classpath:com/zyplayer/doc/db/framework/db/mapper/sqlserver/*.xml");
}
}

View File

@@ -1,45 +0,0 @@
package org.dromara.zyplayer.db.framework.configuration.async;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 异步线程核心配置类
*
* @author diantu
* @since 2023年3月3日
*/
@EnableAsync
@Configuration
public class AsyncConfigurer {
/**
* 核心线程数 = cpu 核心数 + 1
*/
private final int CORE = Runtime.getRuntime().availableProcessors() + 1;
@Bean(name = "myTaskExecutor")
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数:线程池创建时候初始化的线程数
executor.setCorePoolSize(CORE);
// 最大线程数:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
executor.setMaxPoolSize(CORE * 2);
// 缓冲队列:用来缓冲执行任务的队列
executor.setQueueCapacity(300);
// 允许线程的空闲时间60秒当超过了核心线程之外的线程在空闲时间到达之后会被销毁
executor.setKeepAliveSeconds(60);
// 线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
executor.setThreadNamePrefix("AsyncExecutor-");
// 缓冲队列满了之后的拒绝策略:不在新线程中执行任务,而是有调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 初始化
executor.initialize();
return executor;
}
}

View File

@@ -1,40 +0,0 @@
package org.dromara.zyplayer.db.framework.consts;
/**
* 数据库授权前缀
*
* @author 暮光:城中城
* @since 2019-08-22
*/
public enum DbAuthType {
NO_AUTH(0, "DB_NO_AUTH_"),
VIEW(1, "DB_VIEW_"),
SELECT(2, "DB_SELECT_"),
UPDATE(3, "DB_UPDATE_"),
DESC_EDIT(4, "DB_DESC_EDIT_"),
PROC_EDIT(5, "DB_PROC_EDIT_"),
;
private Integer type;
private String name;
DbAuthType(Integer type, String name) {
this.type = type;
this.name = name;
}
public Integer getType() {
return type;
}
public void setType(Integer type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@@ -1,25 +0,0 @@
package org.dromara.zyplayer.db.framework.db.bean;
import com.alibaba.druid.pool.DruidDataSource;
import org.dromara.zyplayer.db.framework.db.enums.DatabaseProductEnum;
import lombok.Data;
import org.mybatis.spring.SqlSessionTemplate;
/**
* 描述连接信息的对象
*
* @author 暮光:城中城
* @since 2018年8月8日
*/
@Data
public class DatabaseFactoryBean {
private Long id;
private DruidDataSource dataSource;
private SqlSessionTemplate sqlSessionTemplate;
private String url;
private String dbName;
private String cnName;
private String groupName;
private DatabaseProductEnum databaseProduct;
}

View File

@@ -1,122 +0,0 @@
package org.dromara.zyplayer.db.framework.db.bean;
import org.dromara.zyplayer.core.exception.ConfirmException;
import org.dromara.zyplayer.data.repository.manage.entity.DbDatasource;
import org.dromara.zyplayer.data.service.manage.DbDatasourceService;
import org.dromara.zyplayer.db.framework.configuration.DatasourceUtil;
import org.dromara.zyplayer.db.framework.db.mapper.base.BaseMapper;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.stereotype.Repository;
import javax.annotation.Resource;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 所有的数据源管理类
*
* @author 暮光:城中城
* @since 2018年8月8日
*/
@Repository
public class DatabaseRegistrationBean {
@Resource
DbDatasourceService dbDatasourceService;
// 描述连接信息的对象列表
private final Map<Long, DatabaseFactoryBean> databaseFactoryBeanMap = new ConcurrentHashMap<>();
/**
* 获取BaseMapper
*
* @param sourceId 数据源ID
* @param cls 指定类
* @return BaseMapper
*/
public <T> T getBaseMapper(Long sourceId, Class<T> cls) {
DatabaseFactoryBean factoryBean = getOrCreateFactoryById(sourceId);
if (factoryBean != null) {
SqlSessionTemplate sessionTemplate = factoryBean.getSqlSessionTemplate();
try {
return sessionTemplate.getMapper(cls);
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
/**
* 获取BaseMapper
*
* @param sourceId 数据源ID
* @return BaseMapper
*/
public BaseMapper getBaseMapperById(Long sourceId) {
DatabaseFactoryBean databaseFactoryBean = this.getOrCreateFactoryById(sourceId);
if (databaseFactoryBean == null) {
return null;
}
try {
SqlSessionTemplate sessionTemplate = databaseFactoryBean.getSqlSessionTemplate();
return sessionTemplate.getMapper(BaseMapper.class);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 关闭数据源
*
* @param sourceId 数据源ID
*/
public void closeDatasource(Long sourceId) {
DatabaseFactoryBean factoryBean = databaseFactoryBeanMap.remove(sourceId);
if (factoryBean != null) {
try {
// 关闭数据源
factoryBean.getDataSource().close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 通过数据源ID获取或创建新的数据源
*
* @param sourceId 数据源ID
* @return 数据源对象
*/
public DatabaseFactoryBean getOrCreateFactoryById(Long sourceId) {
DatabaseFactoryBean factoryBean = databaseFactoryBeanMap.get(sourceId);
if (factoryBean != null) return factoryBean;
return this.createFactoryById(sourceId);
}
/**
* 创建数据源的同步方法
*
* @param sourceId 数据源ID
* @return 新数据源对象
*/
private synchronized DatabaseFactoryBean createFactoryById(Long sourceId) {
DatabaseFactoryBean factoryBean = databaseFactoryBeanMap.get(sourceId);
if (factoryBean != null) {
return factoryBean;
}
DbDatasource dbDatasource = dbDatasourceService.getById(sourceId);
if (dbDatasource == null) {
throw new ConfirmException("未找到指定数据源配置信息");
}
try {
DatabaseFactoryBean databaseFactoryBean = DatasourceUtil.createDatabaseFactoryBean(dbDatasource, false);
databaseFactoryBeanMap.put(sourceId, databaseFactoryBean);
return databaseFactoryBean;
} catch (Exception e) {
throw new ConfirmException("创建数据源失败", e);
}
}
}

View File

@@ -1,16 +0,0 @@
package org.dromara.zyplayer.db.framework.db.bean;
import lombok.Data;
/**
* 数据库配置信息
* @author 暮光:城中城
* @since 2018年8月8日
*/
@Data
public class DbConfigBean {
private String driverClassName;
private String url;
private String username;
private String password;
}

View File

@@ -1,17 +0,0 @@
package org.dromara.zyplayer.db.framework.db.dto;
import lombok.Data;
/**
* 字段信息
*
* @author 暮光:城中城
* @since 2018-11-27
*/
@Data
public class ColumnInfoDto {
private String isNullable;
private String columnType;
private String columnDefault;
private String extra;
}

View File

@@ -1,14 +0,0 @@
package org.dromara.zyplayer.db.framework.db.dto;
import lombok.Data;
/**
* 数据库信息
*
* @author 暮光:城中城
* @since 2018-11-27
*/
@Data
public class DatabaseInfoDto {
private String dbName;
}

View File

@@ -1,21 +0,0 @@
package org.dromara.zyplayer.db.framework.db.dto;
import lombok.Data;
/**
* 存储过程信息
*
* @author 暮光:城中城
* @since 2021-04-25
*/
@Data
public class ProcedureDto {
private String db;
private String name;
private String type;
private String definer;
private String body;
private String paramList;
private String returns;
private String created;
}

View File

@@ -1,16 +0,0 @@
package org.dromara.zyplayer.db.framework.db.dto;
import lombok.Data;
/**
* 表字段注释信息
*
* @author 暮光:城中城
* @since 2018-11-27
*/
@Data
public class QueryTableColumnDescDto {
private String tableName;
private String columnName;
private String description;
}

View File

@@ -1,50 +0,0 @@
package org.dromara.zyplayer.db.framework.db.dto;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import lombok.Data;
/**
* 表字段注释信息
*
* @author 暮光:城中城
* @since 2018-11-27
*/
@Data
public class TableColumnDescDto {
@ColumnWidth(20)
@ExcelProperty("表名")
private String tableName;
@ColumnWidth(20)
@ExcelProperty("字段名")
private String name;
@ColumnWidth(15)
@ExcelProperty("是否自增")
private String selfIncrement;
@ColumnWidth(20)
@ExcelProperty("类型")
private String type;
@ColumnWidth(10)
@ExcelProperty("空值")
private String nullable;
@ColumnWidth(10)
@ExcelProperty("长度")
private String length;
@ColumnWidth(10)
@ExcelProperty("小数点")
private String numericScale;
@ColumnWidth(10)
@ExcelProperty("主键")
private String primaryKey;
@ColumnWidth(80)
@ExcelProperty("注释")
private String description;
}

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