Compare commits
2 Commits
1eabec1d74
...
eec0468ca3
| Author | SHA1 | Date | |
|---|---|---|---|
| eec0468ca3 | |||
| 2ea58667e0 |
@@ -61,9 +61,6 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>2.5.15</version>
|
||||
<configuration>
|
||||
<fork>true</fork> <!-- 如果没有该配置,devtools不会生效 -->
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
|
||||
@@ -14,7 +14,6 @@ import com.test.common.enums.BusinessType;
|
||||
import com.test.test.domain.TestApi;
|
||||
import com.test.test.service.ITestApiService;
|
||||
import com.test.common.core.page.TableDataInfo;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* 接口Controller
|
||||
|
||||
@@ -20,7 +20,7 @@ public class TestGroupController extends BaseController {
|
||||
private ITestGroupService testGroupService;
|
||||
|
||||
/**
|
||||
* 查询接口节点列表
|
||||
* 查询节点列表
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public AjaxResult list(String type) {
|
||||
@@ -29,27 +29,27 @@ public class TestGroupController extends BaseController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增接口节点
|
||||
* 新增节点
|
||||
*/
|
||||
@Log(title = "接口节点", businessType = BusinessType.INSERT)
|
||||
@Log(title = "节点", businessType = BusinessType.INSERT)
|
||||
@PostMapping("/add")
|
||||
public AjaxResult add(@RequestBody TestGroup testGroup) {
|
||||
return success(testGroupService.insertTestGroup(testGroup));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改接口节点
|
||||
* 修改节点
|
||||
*/
|
||||
@Log(title = "接口节点", businessType = BusinessType.UPDATE)
|
||||
@Log(title = "节点", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/edit")
|
||||
public AjaxResult edit(@RequestBody TestGroup testGroup) {
|
||||
return toAjax(testGroupService.updateTestGroup(testGroup));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除接口节点
|
||||
* 删除节点
|
||||
*/
|
||||
@Log(title = "接口节点", businessType = BusinessType.DELETE)
|
||||
@Log(title = "节点", businessType = BusinessType.DELETE)
|
||||
@PostMapping("/del")
|
||||
public AjaxResult remove(@RequestBody @Validated GroupDelectQO qo) throws Exception {
|
||||
return toAjax(testGroupService.deleteTestGroupById(qo));
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
package com.test.test.domain.dto;
|
||||
|
||||
public class SwaggerInfo {
|
||||
}
|
||||
@@ -33,4 +33,5 @@ public interface TestGroupMapper
|
||||
*/
|
||||
int deleteTestGroupByIds(List<Long> ids);
|
||||
|
||||
TestGroup selectGroup(String name, Long parentId, String type);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.test.test.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.test.test.domain.TestGroup;
|
||||
import com.test.test.domain.qo.GroupDelectQO;
|
||||
|
||||
@@ -9,8 +10,7 @@ import com.test.test.domain.qo.GroupDelectQO;
|
||||
*
|
||||
* @author xiaoe
|
||||
*/
|
||||
public interface ITestGroupService
|
||||
{
|
||||
public interface ITestGroupService {
|
||||
/**
|
||||
* 查询节点(文件夹)列表
|
||||
*/
|
||||
@@ -21,6 +21,11 @@ public interface ITestGroupService
|
||||
*/
|
||||
TestGroup insertTestGroup(TestGroup testGroup);
|
||||
|
||||
/**
|
||||
* 查询节点(文件夹)
|
||||
*/
|
||||
TestGroup selectGroup(String name, Long parentId, String type);
|
||||
|
||||
/**
|
||||
* 修改节点(文件夹)
|
||||
*/
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
package com.test.test.service.impl;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.test.common.utils.DateUtils;
|
||||
import com.test.common.utils.http.HttpUtils;
|
||||
import com.test.test.domain.TestGroup;
|
||||
import com.test.test.domain.qo.TestApiListQO;
|
||||
import com.test.test.service.ITestGroupService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.test.test.mapper.TestApiMapper;
|
||||
import com.test.test.domain.TestApi;
|
||||
import com.test.test.service.ITestApiService;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* 接口Service业务层处理
|
||||
@@ -22,6 +26,9 @@ public class TestApiServiceImpl implements ITestApiService {
|
||||
@Resource
|
||||
private TestApiMapper testApiMapper;
|
||||
|
||||
@Resource
|
||||
private ITestGroupService testGroupService;
|
||||
|
||||
/**
|
||||
* 查询接口
|
||||
*
|
||||
@@ -57,9 +64,159 @@ public class TestApiServiceImpl implements ITestApiService {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public int importSwaggerApi(String url) {
|
||||
JSONObject json = JSONObject.parse(HttpUtils.sendGet(url));
|
||||
return 0;
|
||||
AtomicInteger count = new AtomicInteger();
|
||||
JSONObject jsonObject = JSONObject.parseObject(HttpUtils.sendGet(url));
|
||||
String title = jsonObject.getJSONObject("info").getString("title");
|
||||
// 设置顶级节点
|
||||
Long parentId = getGroupId(title, 0L);
|
||||
// 获取Schemas
|
||||
JSONObject schemas = jsonObject.getJSONObject("components").getJSONObject("schemas");
|
||||
// 获取所有接口
|
||||
jsonObject.getJSONObject("paths").forEach((uri, pathJson) -> {
|
||||
((JSONObject) pathJson).forEach((method, v) -> {
|
||||
JSONObject json = (JSONObject) v;
|
||||
// 获取接口名
|
||||
String name = json.getString("summary");
|
||||
if (name == null) name = uri;
|
||||
// 获取接口分组
|
||||
String groupName = title;
|
||||
List<String> tags = json.getList("tags", String.class);
|
||||
if (!tags.isEmpty()) {
|
||||
groupName = tags.get(0);
|
||||
}
|
||||
// 获取body
|
||||
String body = "";
|
||||
String contentType = "";
|
||||
if (json.getJSONObject("requestBody") != null) {
|
||||
JSONObject bodyJson = json.getJSONObject("requestBody").getJSONObject("content");
|
||||
if (bodyJson != null) {
|
||||
Set<String> keys = bodyJson.keySet();
|
||||
if (!keys.isEmpty()) {
|
||||
contentType = keys.iterator().next();
|
||||
JSONObject schema = bodyJson.getJSONObject(contentType).getJSONObject("schema");
|
||||
body = JSONObject.toJSONString(parseSchema(schema, schemas));
|
||||
}
|
||||
}
|
||||
}
|
||||
// 获取Param
|
||||
String param = "";
|
||||
JSONObject parameters = json.getJSONObject("parameters");
|
||||
if (parameters!=null) {
|
||||
JSONObject paramsJson = parseParams(parameters, schemas);
|
||||
param = JSONObject.toJSONString(paramsJson);
|
||||
}
|
||||
TestApi testApi = new TestApi();
|
||||
testApi.setUri(uri);
|
||||
testApi.setMethod(method);
|
||||
testApi.setName(name);
|
||||
testApi.setGroupId(getGroupId(groupName, parentId));
|
||||
testApi.setBody(body);
|
||||
testApi.setParam(param);
|
||||
|
||||
count.addAndGet(testApiMapper.insertTestApi(testApi));
|
||||
});
|
||||
});
|
||||
return count.get();
|
||||
}
|
||||
|
||||
private static JSONObject parseSchema(JSONObject schema, JSONObject schemas) {
|
||||
JSONObject result = new JSONObject();
|
||||
|
||||
// 如果 schema 包含 $ref,则解析引用
|
||||
if (schema.containsKey("$ref")) {
|
||||
String ref = schema.getString("$ref");
|
||||
// 去掉 #/components/schemas/ 前缀,获取引用的 schema 名称
|
||||
String schemaName = ref.replace("#/components/schemas/", "");
|
||||
JSONObject referencedSchema = schemas.getJSONObject(schemaName);
|
||||
// 递归解析引用的 schema
|
||||
return parseSchema(referencedSchema, schemas);
|
||||
}
|
||||
|
||||
// 如果 schema 包含 type,则直接根据类型构建结果
|
||||
if (schema.containsKey("type")) {
|
||||
String type = schema.getString("type");
|
||||
switch (type) {
|
||||
case "integer":
|
||||
result.put("value", 0);
|
||||
break;
|
||||
case "string":
|
||||
result.put("value", "string");
|
||||
break;
|
||||
case "boolean":
|
||||
result.put("value", false);
|
||||
break;
|
||||
default:
|
||||
result.put("value", type);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果 schema 有 properties,则遍历 properties 并递归解析
|
||||
if (schema.containsKey("properties")) {
|
||||
JSONObject properties = schema.getJSONObject("properties");
|
||||
for (Map.Entry<String, Object> entry : properties.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
JSONObject propertySchema = (JSONObject) entry.getValue();
|
||||
JSONObject propertyResult = parseSchema(propertySchema, schemas); // 递归解析每个字段
|
||||
result.put(key, propertyResult.get("value")); // 获取解析结果的值
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static JSONObject parseParams(JSONObject params, JSONObject schemas) {
|
||||
JSONObject result = new JSONObject();
|
||||
|
||||
// 遍历 params 中的每个参数
|
||||
for (String key : params.keySet()) {
|
||||
// 获取当前参数的 schema 定义
|
||||
Object value = params.get(key);
|
||||
|
||||
// 获取 schema
|
||||
JSONObject schema = schemas.getJSONObject(key);
|
||||
|
||||
// 如果 schema 是基础类型,则直接赋值
|
||||
if (schema != null && schema.containsKey("type")) {
|
||||
String type = schema.getString("type");
|
||||
if ("string".equals(type)) {
|
||||
result.put(key, value != null ? value : "string"); // 默认值为 "string"
|
||||
} else if ("integer".equals(type)) {
|
||||
result.put(key, value != null ? value : 0); // 默认值为 0
|
||||
} else if ("boolean".equals(type)) {
|
||||
result.put(key, value != null ? value : false); // 默认值为 false
|
||||
}
|
||||
}
|
||||
// 如果 schema 是引用类型,则递归解析该引用
|
||||
else if (schema != null && schema.containsKey("$ref")) {
|
||||
String ref = schema.getString("$ref");
|
||||
String schemaName = ref.replace("#/components/schemas/", "");
|
||||
JSONObject referencedSchema = schemas.getJSONObject(schemaName);
|
||||
|
||||
// 如果引用的 schema 存在,递归解析该 schema
|
||||
if (referencedSchema != null) {
|
||||
// 递归调用,解析引用的 schema
|
||||
JSONObject nestedResult = parseParams(new JSONObject(), schemas);
|
||||
result.putAll(nestedResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Long getGroupId(String groupName, Long parentId) {
|
||||
TestGroup group = testGroupService.selectGroup(groupName, parentId, "api");
|
||||
if (group == null) {
|
||||
group = new TestGroup();
|
||||
group.setParentId(parentId);
|
||||
group.setName(groupName);
|
||||
group.setType("api");
|
||||
group.setCreateTime(DateUtils.getNowDate());
|
||||
testGroupService.insertTestGroup(group);
|
||||
}
|
||||
return group.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.test.common.utils.DateUtils;
|
||||
import com.test.common.utils.StringUtils;
|
||||
import com.test.test.domain.qo.GroupDelectQO;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.test.test.mapper.TestGroupMapper;
|
||||
import com.test.test.domain.TestGroup;
|
||||
@@ -26,6 +27,7 @@ public class TestGroupServiceImpl implements ITestGroupService {
|
||||
private TestGroupMapper testGroupMapper;
|
||||
|
||||
@Resource
|
||||
@Lazy
|
||||
private TestApiServiceImpl testApiServiceImpl;
|
||||
|
||||
/**
|
||||
@@ -46,6 +48,11 @@ public class TestGroupServiceImpl implements ITestGroupService {
|
||||
return testGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TestGroup selectGroup(String name, Long parentId, String type) {
|
||||
return testGroupMapper.selectGroup(name, parentId, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改节点(文件夹)
|
||||
*/
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
<if test="method != null and method != ''"> and method = #{method}</if>
|
||||
<if test="uri != null and uri != ''"> and uri like concat('%', #{uri}, '%')</if>
|
||||
</where>
|
||||
order by create_time desc
|
||||
</select>
|
||||
|
||||
<select id="selectTestApiById" parameterType="Long" resultMap="TestApiResult">
|
||||
|
||||
@@ -37,6 +37,13 @@
|
||||
</where>
|
||||
</select>
|
||||
|
||||
<select id="selectGroup" parameterType="String" resultMap="TestGroupResult">
|
||||
<include refid="selectTestGroupVo"/>
|
||||
<where>
|
||||
name = #{name} and type = #{type} and parent_id = #{parentId}
|
||||
</where>
|
||||
</select>
|
||||
|
||||
<insert id="insertTestGroup" parameterType="TestGroup" useGeneratedKeys="true" keyProperty="id">
|
||||
insert into test_group
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
|
||||
@@ -39,8 +39,16 @@ export function updateApi(data) {
|
||||
// 删除接口
|
||||
export function delApi(id) {
|
||||
return request({
|
||||
url: '/test/api/del/',
|
||||
url: '/test/api/del',
|
||||
method: 'post',
|
||||
params: {id}
|
||||
data: {id}
|
||||
})
|
||||
}
|
||||
|
||||
export function importApi(url) {
|
||||
return request({
|
||||
url: '/test/api/import/swagger',
|
||||
method: 'post',
|
||||
params: url
|
||||
})
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ export default {
|
||||
this.form.header.splice(scope.$index, 1)
|
||||
},
|
||||
cancel() {
|
||||
this.$tab.closeOpenPage({ path: "/api" });
|
||||
this.$tab.closeOpenPage({path: "/api"});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -158,9 +158,11 @@ export default {
|
||||
::v-deep .el-collapse-item__wrap {
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
::v-deep.el-select {
|
||||
width: 130px;
|
||||
}
|
||||
|
||||
.input-with-select ::v-deep .el-input-group__prepend {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ export default {
|
||||
contentType: this.form.contentType,
|
||||
body: this.form.body,
|
||||
}).then(res => {
|
||||
this.$message.success("新增成功");
|
||||
this.$message.success("修改成功");
|
||||
this.cancel();
|
||||
})
|
||||
},
|
||||
@@ -165,7 +165,7 @@ export default {
|
||||
this.form.header.splice(scope.$index, 1)
|
||||
},
|
||||
cancel() {
|
||||
this.$tab.closeOpenPage({ path: "/api" });
|
||||
this.$tab.closeOpenPage({path: "/api"});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -180,9 +180,11 @@ export default {
|
||||
::v-deep .el-collapse-item__wrap {
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
::v-deep.el-select {
|
||||
width: 130px;
|
||||
}
|
||||
|
||||
.input-with-select ::v-deep .el-input-group__prepend {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
@@ -1,22 +1,46 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
import
|
||||
<div>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="swagger" prop="url">
|
||||
<el-input v-model="form.url" placeholder="请输入swagger文档链接"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {importApi} from "@/api/test/api";
|
||||
|
||||
export default {
|
||||
name: "ApiImport",
|
||||
dicts: ['http_method'],
|
||||
created () {
|
||||
console.log(this.$route.query.groupId)
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 表单参数
|
||||
form: {},
|
||||
// 表单校验
|
||||
rules: {}
|
||||
rules: {
|
||||
url: [{required: true, message: "swagger文档链接不能为空", trigger: "blur"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (valid) {
|
||||
importApi({url: this.form.url}).then((res) => {
|
||||
this.$message.success("导入成功")
|
||||
this.cancel();
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
cancel() {
|
||||
this.$emit('close')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
<el-table-column label="接口名称" align="center" prop="name"/>
|
||||
<el-table-column label="接口请求类型" align="center" prop="method"/>
|
||||
<el-table-column label="接口路径" align="center" prop="uri"/>
|
||||
<el-table-column label="创建时间" align="center" prop="createTime"/>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)">修改</el-button>
|
||||
@@ -35,18 +36,21 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList"/>
|
||||
<el-dialog title="导入接口" :visible.sync="dialogVisible" :close-on-click-modal="false" destroy-on-close>
|
||||
<api-import @close="() => dialogVisible = false"/>
|
||||
</el-dialog>
|
||||
</folder-page>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {listApi, delApi} from "@/api/test/api";
|
||||
import FolderPage from "@/components/FolderPage/index.vue";
|
||||
import ApiImport from "@/views/test/api/import.vue";
|
||||
|
||||
export default {
|
||||
name: "Api",
|
||||
components: {FolderPage},
|
||||
components: {ApiImport, FolderPage},
|
||||
dicts: ['http_method'],
|
||||
data() {
|
||||
return {
|
||||
@@ -62,6 +66,7 @@ export default {
|
||||
method: null,
|
||||
uri: null,
|
||||
},
|
||||
dialogVisible: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
@@ -97,7 +102,7 @@ export default {
|
||||
this.$tab.openPage("添加接口", "/api/add", {groupId: this.queryParams.groupId});
|
||||
},
|
||||
handleImport() {
|
||||
this.$tab.openPage("导入接口", "/api/import", {groupId: this.queryParams.groupId});
|
||||
this.dialogVisible = true;
|
||||
},
|
||||
/** 修改按钮操作 */
|
||||
handleUpdate(row) {
|
||||
|
||||
Reference in New Issue
Block a user