api接口开发

This commit is contained in:
暮光:城中城
2021-12-27 23:29:04 +08:00
parent 990c2379ff
commit bc7ae4fc67
11 changed files with 138 additions and 74 deletions

View File

@@ -39,7 +39,7 @@ public class ApiCustomRequestController {
@ResponseBody @ResponseBody
@PostMapping(value = "/add") @PostMapping(value = "/add")
public ResponseJson<Object> add(ApiCustomRequest apiCustomRequest) { public ResponseJson<Object> add(ApiCustomRequest apiCustomRequest) {
apiCustomRequestService.addRequest(apiCustomRequest); ApiCustomRequest requestSaved = apiCustomRequestService.addRequest(apiCustomRequest);
return DocResponseJson.ok(); return DocResponseJson.ok(requestSaved);
} }
} }

View File

@@ -12,6 +12,16 @@ public class ApiCustomDocVo implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/**
* 接口ID
*/
private Long requestId;
/**
* 文件夹ID
*/
private Long folderId;
/** /**
* 接口名称 * 接口名称
*/ */
@@ -102,4 +112,20 @@ public class ApiCustomDocVo implements Serializable {
public void setMethod(String method) { public void setMethod(String method) {
this.method = method; this.method = method;
} }
public Long getRequestId() {
return requestId;
}
public void setRequestId(Long requestId) {
this.requestId = requestId;
}
public Long getFolderId() {
return folderId;
}
public void setFolderId(Long folderId) {
this.folderId = folderId;
}
} }

View File

@@ -13,6 +13,11 @@ public class ApiCustomVo implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/**
* 文件夹ID
*/
private Long folderId;
/** /**
* 文件夹名称 * 文件夹名称
*/ */
@@ -64,4 +69,12 @@ public class ApiCustomVo implements Serializable {
public void setApis(List<ApiCustomDocVo> apis) { public void setApis(List<ApiCustomDocVo> apis) {
this.apis = apis; this.apis = apis;
} }
public Long getFolderId() {
return folderId;
}
public void setFolderId(Long folderId) {
this.folderId = folderId;
}
} }

View File

@@ -32,5 +32,5 @@ public interface ApiCustomRequestService extends IService<ApiCustomRequest> {
* @author 暮光:城中城 * @author 暮光:城中城
* @since 2021-12-22 * @since 2021-12-22
*/ */
void addRequest(ApiCustomRequest apiCustomRequest); ApiCustomRequest addRequest(ApiCustomRequest apiCustomRequest);
} }

View File

@@ -70,7 +70,7 @@ public class ApiCustomRequestServiceImpl extends ServiceImpl<ApiCustomRequestMap
} }
@Override @Override
public void addRequest(ApiCustomRequest apiCustomRequest) { public ApiCustomRequest addRequest(ApiCustomRequest apiCustomRequest) {
apiDocAuthJudgeService.judgeDevelopAndThrow(apiCustomRequest.getDocId()); apiDocAuthJudgeService.judgeDevelopAndThrow(apiCustomRequest.getDocId());
DocUserDetails currentUser = DocUserUtil.getCurrentUser(); DocUserDetails currentUser = DocUserUtil.getCurrentUser();
if (apiCustomRequest.getId() == null) { if (apiCustomRequest.getId() == null) {
@@ -84,6 +84,7 @@ public class ApiCustomRequestServiceImpl extends ServiceImpl<ApiCustomRequestMap
apiCustomRequest.setCreateUserName(null); apiCustomRequest.setCreateUserName(null);
} }
this.saveOrUpdate(apiCustomRequest); this.saveOrUpdate(apiCustomRequest);
return apiCustomRequest;
} }
/** /**
@@ -103,6 +104,7 @@ public class ApiCustomRequestServiceImpl extends ServiceImpl<ApiCustomRequestMap
List<ApiCustomVo> customGroupChildren = this.getCustomGroupChildren(children, apiGroupMap, apiMap); List<ApiCustomVo> customGroupChildren = this.getCustomGroupChildren(children, apiGroupMap, apiMap);
List<ApiCustomDocVo> apis = this.buildApiCustomDocVo(apiCustomList); List<ApiCustomDocVo> apis = this.buildApiCustomDocVo(apiCustomList);
ApiCustomVo apiCustomVo = new ApiCustomVo(); ApiCustomVo apiCustomVo = new ApiCustomVo();
apiCustomVo.setFolderId(customGroup.getId());
apiCustomVo.setName(customGroup.getFolderName()); apiCustomVo.setName(customGroup.getFolderName());
apiCustomVo.setDesc(customGroup.getFolderDesc()); apiCustomVo.setDesc(customGroup.getFolderDesc());
apiCustomVo.setChildren(customGroupChildren); apiCustomVo.setChildren(customGroupChildren);
@@ -117,6 +119,8 @@ public class ApiCustomRequestServiceImpl extends ServiceImpl<ApiCustomRequestMap
if (CollectionUtils.isNotEmpty(apiCustomList)) { if (CollectionUtils.isNotEmpty(apiCustomList)) {
for (ApiCustomRequest apiCustom : apiCustomList) { for (ApiCustomRequest apiCustom : apiCustomList) {
ApiCustomDocVo apiCustomDocVo = new ApiCustomDocVo(); ApiCustomDocVo apiCustomDocVo = new ApiCustomDocVo();
apiCustomDocVo.setRequestId(apiCustom.getId());
apiCustomDocVo.setFolderId(apiCustom.getFolderId());
apiCustomDocVo.setApiUrl(apiCustom.getApiUrl()); apiCustomDocVo.setApiUrl(apiCustom.getApiUrl());
apiCustomDocVo.setMethod(apiCustom.getMethod()); apiCustomDocVo.setMethod(apiCustom.getMethod());
apiCustomDocVo.setApiName(apiCustom.getApiName()); apiCustomDocVo.setApiName(apiCustom.getApiName());

View File

@@ -1,17 +1,11 @@
package com.zyplayer.doc.db.framework.db.mapper.base; package com.zyplayer.doc.db.framework.db.mapper.base;
import com.alibaba.druid.pool.DruidPooledConnection; import com.alibaba.druid.pool.DruidPooledConnection;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.zyplayer.doc.data.service.manage.DbHistoryService;
import com.zyplayer.doc.db.framework.db.bean.DatabaseFactoryBean; import com.zyplayer.doc.db.framework.db.bean.DatabaseFactoryBean;
import com.zyplayer.doc.db.framework.db.bean.DatabaseRegistrationBean; import com.zyplayer.doc.db.framework.db.bean.DatabaseRegistrationBean;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.ibatis.builder.SqlSourceBuilder;
import org.apache.ibatis.builder.StaticSqlSource;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.ParameterMapping; import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.parsing.GenericTokenParser;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
@@ -20,7 +14,10 @@ import javax.annotation.Resource;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.ResultSetMetaData; import java.sql.ResultSetMetaData;
import java.util.*; import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
/** /**
@@ -35,14 +32,13 @@ public class SqlExecutor {
@Resource @Resource
DatabaseRegistrationBean databaseRegistrationBean; DatabaseRegistrationBean databaseRegistrationBean;
@Resource
DbHistoryService dbHistoryService;
// 执行中的PreparedStatement信息用于强制取消执行 // 执行中的PreparedStatement信息用于强制取消执行
private static final Map<String, PreparedStatement> statementMap = new ConcurrentHashMap<>(); private static final Map<String, PreparedStatement> statementMap = new ConcurrentHashMap<>();
/** /**
* 取消执行 * 取消执行
*
* @author 暮光:城中城 * @author 暮光:城中城
* @since 2019年8月18日 * @since 2019年8月18日
*/ */
@@ -62,6 +58,7 @@ public class SqlExecutor {
/** /**
* 执行sql返回结果 * 执行sql返回结果
*
* @author 暮光:城中城 * @author 暮光:城中城
* @since 2019年8月18日 * @since 2019年8月18日
*/ */
@@ -72,6 +69,7 @@ public class SqlExecutor {
/** /**
* 执行sql返回结果 * 执行sql返回结果
*
* @author 暮光:城中城 * @author 暮光:城中城
* @since 2019年8月18日 * @since 2019年8月18日
*/ */
@@ -82,6 +80,7 @@ public class SqlExecutor {
/** /**
* 执行sql可通过handler回调每一行的结果 * 执行sql可通过handler回调每一行的结果
*
* @author 暮光:城中城 * @author 暮光:城中城
* @since 2019年8月18日 * @since 2019年8月18日
*/ */
@@ -89,9 +88,6 @@ public class SqlExecutor {
if (factoryBean == null) { if (factoryBean == null) {
return ExecuteResult.error("未找到数据库连接", executeParam.getSql()); return ExecuteResult.error("未找到数据库连接", executeParam.getSql());
} }
// BoundSql boundSql = getBoundSql(sql, paramMap);
// sql = boundSql.getSql();
// String sqlStr = SqlLogUtil.getSqlString(paramMap, boundSql);
// 有参数的时候不输出日志,暂时只有导数据才有参数 // 有参数的时候不输出日志,暂时只有导数据才有参数
if (CollectionUtils.isEmpty(executeParam.getParamList())) { if (CollectionUtils.isEmpty(executeParam.getParamList())) {
if (StringUtils.isNotBlank(executeParam.getPrefixSql())) { if (StringUtils.isNotBlank(executeParam.getPrefixSql())) {
@@ -99,7 +95,6 @@ public class SqlExecutor {
} }
logger.info("sql ==> {}", executeParam.getSql()); logger.info("sql ==> {}", executeParam.getSql());
} }
// List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
PreparedStatement preparedStatement = null; PreparedStatement preparedStatement = null;
PreparedStatement prefixStatement = null; PreparedStatement prefixStatement = null;
DruidPooledConnection connection = null; DruidPooledConnection connection = null;
@@ -181,16 +176,4 @@ public class SqlExecutor {
} }
} }
} }
private BoundSql getBoundSql(String sql, Map<String, Object> paramMap){
// 组装参数
GenericTokenParser parser = new GenericTokenParser("${", "}", content -> {
Object o = paramMap.get(content);
return (o == null) ? null : String.valueOf(o);
});
sql = parser.parse(sql);
SqlSourceBuilder sqlSourceBuilder = new SqlSourceBuilder(new MybatisConfiguration());
StaticSqlSource parse = (StaticSqlSource) sqlSourceBuilder.parse(sql, Object.class, paramMap);
return parse.getBoundSql(new Object());
}
} }

View File

@@ -214,7 +214,7 @@
"dependencies": { "dependencies": {
"@ant-design/colors": { "@ant-design/colors": {
"version": "6.0.0", "version": "6.0.0",
"resolved": "https://r.cnpmjs.org/@ant-design/colors/download/@ant-design/colors-6.0.0.tgz", "resolved": "https://registry.npm.taobao.org/@ant-design/colors/download/@ant-design/colors-6.0.0.tgz",
"integrity": "sha1-m5NmJXz/zEfbQrnQIDu1ksE8Apg=", "integrity": "sha1-m5NmJXz/zEfbQrnQIDu1ksE8Apg=",
"requires": { "requires": {
"@ctrl/tinycolor": "^3.4.0" "@ctrl/tinycolor": "^3.4.0"
@@ -1029,7 +1029,7 @@
"dependencies": { "dependencies": {
"assert-plus": { "assert-plus": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://r.cnpmjs.org/assert-plus/download/assert-plus-1.0.0.tgz", "resolved": "https://registry.nlark.com/assert-plus/download/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
"optional": true "optional": true
} }

View File

@@ -22,5 +22,8 @@ export const zyplayerApi = {
docAuthList: data => apiClient({url: '/doc-api/doc/auth/list', method: 'post', data: data}), docAuthList: data => apiClient({url: '/doc-api/doc/auth/list', method: 'post', data: data}),
docAuthAssign: data => apiClient({url: '/doc-api/doc/auth/assign', method: 'post', data: data}), docAuthAssign: data => apiClient({url: '/doc-api/doc/auth/assign', method: 'post', data: data}),
docAuthDelete: data => apiClient({url: '/doc-api/doc/auth/delete', method: 'post', data: data}), docAuthDelete: data => apiClient({url: '/doc-api/doc/auth/delete', method: 'post', data: data}),
apiCustomFolderAdd: data => apiClient({url: '/api-custom-folder/add', method: 'post', data: data}),
apiCustomRequestAdd: data => apiClient({url: '/api-custom-request/add', method: 'post', data: data}),
}; };

View File

@@ -31,7 +31,7 @@ function getTreeDataChildren(customRequest, keywords, metaInfo, treeIndex) {
customRequest.children.forEach(item => { customRequest.children.forEach(item => {
let tempTreeId = treeIndex + "_" + indexFolder + "_" + indexApi; let tempTreeId = treeIndex + "_" + indexFolder + "_" + indexApi;
let treeChildren = getTreeDataChildren(item, keywords, metaInfo, tempTreeId); let treeChildren = getTreeDataChildren(item, keywords, metaInfo, tempTreeId);
treeData.push({title: item.name, key: tempTreeId, children: treeChildren}); treeData.push({title: item.name, key: tempTreeId, folderId: item.folderId, isLeaf: false, children: treeChildren});
indexApi++; indexApi++;
}); });
} }
@@ -43,10 +43,11 @@ function getTreeDataChildren(customRequest, keywords, metaInfo, treeIndex) {
key: tempTreeId, key: tempTreeId,
isLeaf: true, isLeaf: true,
method: item.method, method: item.method,
folderId: item.folderId,
query: { query: {
...metaInfo, ...metaInfo,
path: item.apiUrl, requestId: item.requestId,
method: item.method, folderId: item.folderId,
} }
}); });
indexApi++; indexApi++;

View File

@@ -71,6 +71,8 @@
docChoiceId.value = parseInt(route.query.id); docChoiceId.value = parseInt(route.query.id);
} else if (route.path === '/openapi/view' && route.query.id){ } else if (route.path === '/openapi/view' && route.query.id){
docChoiceId.value = parseInt(route.query.id); docChoiceId.value = parseInt(route.query.id);
} else if (route.path === '/custom/request' && route.query.id){
docChoiceId.value = parseInt(route.query.id);
} else { } else {
docChoiceId.value = docResourceList.value[0].id; docChoiceId.value = docResourceList.value[0].id;
} }

View File

@@ -1,42 +1,38 @@
<template> <template>
<a-directory-tree :showIcon="false" :tree-data="treeData" v-model:expandedKeys="expandedKeys" @select="docChecked"> <a-directory-tree :showIcon="false" :tree-data="treeData" v-model:expandedKeys="expandedKeys" @select="docChecked">
<template #title="{ title, isLeaf, method, children, key }"> <template #title="record">
<template v-if="key === 'info'"> <template v-if="record.key === 'info'">
<file-text-outlined style="margin-right: 3px;"/> <file-text-outlined style="margin-right: 3px;"/>
</template> </template>
<template v-if="isLeaf"> <template v-if="record.isLeaf">
<a-tag color="pink" v-if="method === 'get'">get</a-tag> <a-tag color="pink" v-if="record.method === 'get'">get</a-tag>
<a-tag color="red" v-else-if="method === 'post'">post</a-tag> <a-tag color="red" v-else-if="record.method === 'post'">post</a-tag>
<a-tag color="orange" v-else-if="method === 'put'">put</a-tag> <a-tag color="orange" v-else-if="record.method === 'put'">put</a-tag>
<a-tag color="green" v-else-if="method === 'head'">head</a-tag> <a-tag color="green" v-else-if="record.method === 'head'">head</a-tag>
<a-tag color="cyan" v-else-if="method === 'patch'">patch</a-tag> <a-tag color="cyan" v-else-if="record.method === 'patch'">patch</a-tag>
<a-tag color="blue" v-else-if="method === 'delete'">delete</a-tag> <a-tag color="blue" v-else-if="record.method === 'delete'">delete</a-tag>
<a-tag color="purple" v-else-if="method === 'options'">options</a-tag> <a-tag color="purple" v-else-if="record.method === 'options'">options</a-tag>
<a-tag color="purple" v-else-if="method === 'trace'">trace</a-tag> <a-tag color="purple" v-else-if="record.method === 'trace'">trace</a-tag>
</template> </template>
<span style="margin: 0 6px 0 3px;">{{title}}</span> <span style="margin: 0 6px 0 3px;">{{record.title}}</span>
<template v-if="children"> <template v-if="record.children">
<a-badge :count="children.length" :number-style="{backgroundColor: '#fff', color: '#999', boxShadow: '0 0 0 1px #d9d9d9 inset'}"/> <a-badge :count="record.children.length" showZero :number-style="{backgroundColor: '#fff', color: '#999', boxShadow: '0 0 0 1px #d9d9d9 inset'}"/>
<a-dropdown :trigger="['click']"> <a-dropdown :trigger="['click']">
<span @click.stop="" style="padding: 3px 10px;"><ellipsis-outlined /></span> <span @click.stop="" style="padding: 3px 10px;"><ellipsis-outlined /></span>
<template #overlay> <template #overlay>
<a-menu> <a-menu @click="handleMenuClick($event, record)">
<a-menu-item> <a-menu-item key="newRequest">
<plus-outlined /> <plus-outlined /> 新建接口
<a href="javascript:;"> 新建接口</a>
</a-menu-item> </a-menu-item>
<a-menu-item> <a-menu-item key="newFolder">
<folder-add-outlined /> <folder-add-outlined /> 新建文件夹
<a href="javascript:;"> 新建文件夹</a>
</a-menu-item> </a-menu-item>
<a-menu-divider /> <a-menu-divider />
<a-menu-item> <a-menu-item key="edit">
<edit-outlined /> <edit-outlined /> 编辑
<a href="javascript:;"> 编辑</a>
</a-menu-item> </a-menu-item>
<a-menu-item> <a-menu-item key="delete">
<delete-outlined /> <delete-outlined /> 删除
<a href="javascript:;"> 删除</a>
</a-menu-item> </a-menu-item>
</a-menu> </a-menu>
</template> </template>
@@ -63,21 +59,20 @@
const router = useRouter(); const router = useRouter();
let tagPathMap = ref({}); let tagPathMap = ref({});
let customRequestDoc = ref({}); let customRequestDoc = {};
let treeData = ref([]); let treeData = ref([]);
let expandedKeys = ref([]); let expandedKeys = ref(['main']);
let choiceDocId = ref(''); let choiceDocId = '';
let searchKeyword = '';
const docChecked = (val, node) => { const docChecked = (val, node) => {
if (node.node.key === 'info') { if (node.node.isLeaf) {
router.push({path: '/custom/info'});
} else if (node.node.isLeaf) {
let dataRef = node.node.dataRef; let dataRef = node.node.dataRef;
router.push({path: '/custom/view', query: dataRef.query}); router.push({path: '/custom/request', query: dataRef.query});
} }
}; };
const loadDoc = (docId, keyword, callback) => { const loadDoc = (docId, keyword, callback) => {
choiceDocId.value = docId; choiceDocId = docId;
zyplayerApi.apiDocApisDetail({id: docId}).then(res => { zyplayerApi.apiDocApisDetail({id: docId}).then(res => {
let v2Doc = res.data; let v2Doc = res.data;
if (!v2Doc && v2Doc.length != 1) { if (!v2Doc && v2Doc.length != 1) {
@@ -85,7 +80,7 @@
message.error('获取文档数据失败'); message.error('获取文档数据失败');
return; return;
} }
customRequestDoc.value = v2Doc; customRequestDoc = v2Doc;
store.commit('setCustomRequestDoc', v2Doc); store.commit('setCustomRequestDoc', v2Doc);
loadTreeData(keyword); loadTreeData(keyword);
callback(true); callback(true);
@@ -94,11 +89,47 @@
}); });
}; };
const loadTreeData = async (keyword) => { const loadTreeData = async (keyword) => {
let metaInfo = {id: choiceDocId.value}; let metaInfo = {id: choiceDocId};
treeData.value = getTreeDataForTag(customRequestDoc.value, keyword, metaInfo); searchKeyword = keyword;
treeData.value = getTreeDataForTag(customRequestDoc, keyword, metaInfo);
treeData.value.unshift({key: 'info', title: '文档说明信息', isLeaf: true}); treeData.value.unshift({key: 'info', title: '文档说明信息', isLeaf: true});
await nextTick(); };
expandedKeys.value = ['main']; const handleMenuClick = (event, record) => {
if (event.key === 'newFolder') {
let params = {
// id: '',
docId: choiceDocId,
parentFolderId: record.folderId,
folderName: '新建文件夹',
folderDesc: '',
};
zyplayerApi.apiCustomFolderAdd(params).then(res => {
loadDoc(choiceDocId, searchKeyword);
});
} else if (event.key === 'newRequest') {
let params = {
// id: '',
docId: choiceDocId,
folderId: record.folderId,
apiName: '新建接口',
method: 'get',
apiUrl: '',
// formData: '测试xxx',
// bodyData: '测试xxx',
// headerData: '测试xxx',
// cookieData: '测试xxx',
};
zyplayerApi.apiCustomRequestAdd(params).then(res => {
loadDoc(choiceDocId, searchKeyword);
let requestSaved = res.data;
let queryInfo = {
id: choiceDocId,
requestId: requestSaved.id,
folderId: requestSaved.folderId,
};
router.push({path: '/custom/request', query: queryInfo});
});
}
}; };
const toJsonObj = (value) => { const toJsonObj = (value) => {
if (typeof value !== 'string') { if (typeof value !== 'string') {
@@ -121,6 +152,7 @@
loadDoc, loadDoc,
loadTreeData, loadTreeData,
treeData, treeData,
handleMenuClick,
}; };
}, },
}; };