使用TypeScript开发Vue应用程序及接入swagger2接口定义

仓库案例

springboot_swagger
vue-ts-swagger

工具准备

安装Visual Studio Code

https://code.visualstudio.com/下载安装
安装好Vetur,vscode-pont及其他插件

安装npm支持

https://nodejs.org/en/下载安装,
使用node -v检查是否成功

创建项目

1
2
# 1. 如果没有安装 Vue CLI 就先安装
npm install --global @vue/cli

图片1

1
2
# 2. 创建一个新工程,并选择 "Manually select features (手动选择特性)" 选项
vue create vue-ts-swagger

图片2

初次访问

1
2
cd vue-ts-swagger
npm run serve

图片4
图片3

配置Pont

在项目根目录创建pont-config.json,示例内容:

1
2
3
4
5
{
"originUrl": "http://localhost:8080/v2/api-docs",
"outDir": "./src/services",
"templatePath": "./pontTemplate"
}

originUrl: 接口平台提供数据源的url
outDir: 成代码的存放路径,使用相对路径即可
templatePath: 指定自定义代码生成器的路径
更多配置项参考https://github.com/nefe/pont

vscode-pont插件检测到项目中有合法的pont-config.json,插件马上启动
图片5
并将自动生成相关的接口文件
图片6
在编辑器左下角有相关的操作按钮
图片7

增加pontTemplate.ts

根据pont-config.json中设置,在项目根目录增加pontTemplate.ts,用于覆盖默认生成模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81

import * as Pont from 'pont-engine';
import { CodeGenerator, Interface } from "pont-engine";

export class FileStructures extends Pont.FileStructures {
}

export default class MyGenerator extends CodeGenerator {
/** 获取接口实现内容的代码 */
getInterfaceContent(inter: Interface) {
const bodyParmas = inter.getBodyParamsCode();
const requestParams = bodyParmas ? `params, bodyParams` : `params`;

return `
/**
* @desc ${inter.description}
*/
import * as defs from '../../baseClass';
import fetch from '@/utils/fetch';
export ${inter.getParamsCode()}
export const init = ${inter.response.initialValue};
export async function request(${requestParams}: any) {
return fetch({
url: '${inter.path}',
${bodyParmas ? 'params: bodyParams' : 'params'},
method: '${inter.method}',
});
}
`;
}

/** 获取所有模块的 index 入口文件 */
getModsIndex() {
let conclusion = `
declare var window;
window.API = {
${this.dataSource.mods.map(mod => mod.name).join(', \n')}
};
`;

// dataSource name means multiple dataSource
if (this.dataSource.name) {
conclusion = `
export const ${this.dataSource.name} = {
${this.dataSource.mods.map(mod => mod.name).join(', \n')}
}
`;
}

return `
${this.dataSource.mods
.map(mod => {
return `import * as ${mod.name} from './${mod.name}';`;
})
.join('\n')}
${conclusion}
`;
}

/** 获取接口类和基类的总的 index 入口文件代码 */
getIndex() {
let conclusion = `
import * as defs from './baseClass';
import './mods/';
declare var window: { defs: any; };
window.defs = defs;
`;

// dataSource name means multiple dataSource
if (this.dataSource.name) {
conclusion = `
import { ${this.dataSource.name} as defs } from './baseClass';
export { ${this.dataSource.name} } from './mods/';
export { defs };
`;
}

return conclusion;
}
}

增加axios请求文件

src/utils/下建立fetch.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import axios from 'axios'

// create an axios instance
const service = axios.create({
baseURL: 'http://localhost:8080/', // api的base_url
timeout: 1000 * 60 * 5 // request timeout
})

// request interceptor
service.interceptors.request.use(config => {
// Do something before request is sent

return config
}, error => {
// Do something with request error
console.log(error) // for debug
Promise.reject(error)
})
// respone interceptor
service.interceptors.response.use(
response => {
console.log(response)
return response
},
error => {
if (error.response) {
// Do something with request error
console.log(error.response)
}
return Promise.reject(error)
})

export default service

使用

可以在main.ts中加入

1
import '@/services/'

即可通过下面API.方式使用自动生成的接口
hello接口
1
2
3
4
5
6
7
//...

mounted () {
API.hello.hello.request({name:'karoy'})
}

//...

注意

baseClass中定义的生成依赖于definitions定义,如后端注解@ApiModel生成的定义,没有将会出现导入错误。

java注解示例

api接口通用返回对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package com.karoy.springboot.common;


import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

import java.io.Serializable;

@ApiModel(value = "ApiResult",description = "api接口通用返回对象")
public class ApiResult implements Serializable {
/**
* @description 返回码
*/
@ApiModelProperty(value = "返回码",dataType = "int")
private int code;

/**
* @description 错误信息
*/
@ApiModelProperty(value = "错误信息",dataType = "String")
private String message;

/**
* @description 响应数据
*/
@ApiModelProperty(value = "响应数据",dataType = "Object")
private Object data;

public final int getCode() {
return this.code;
}

public final void setCode(int code) {
this.code = code;
}

public final String getMessage() {
return this.message;
}

public final void setMessage( String message) {
this.message = message;
}

public final Object getData() {
return this.data;
}

public final void setData(Object data) {
this.data = data;
}

public ApiResult(int code, String message, Object data) {
super();
this.code = code;
this.message = message;
this.data = data;
}
}

HELLO接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.karoy.springboot.action;

import com.karoy.springboot.common.ApiResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@Api(description = "HELLO接口")
@RestController
public class HelloController {
@ApiOperation(value = "欢迎" , notes="欢迎")
@ApiResponses({
@ApiResponse(code = 200, message = "OK", response = ApiResult.class),
@ApiResponse(code = 204, message = "No Content", response = ApiResult.class),
@ApiResponse(code = 401, message = "Unauthorized", response = ApiResult.class),
@ApiResponse(code = 403, message = "Forbidden", response = ApiResult.class),
@ApiResponse(code = 404, message = "Not Found", response = ApiResult.class)
})
@RequestMapping("/hello")
public String hello(@RequestParam("name") String name) {
return "Hello "+name;
}
}

swagger2 json示例

1
{"swagger":"2.0","info":{"description":"Api Documentation","version":"1.0","title":"Api Documentation","termsOfService":"urn:tos","contact":{},"license":{"name":"Apache 2.0","url":"http://www.apache.org/licenses/LICENSE-2.0"}},"host":"localhost:8080","basePath":"/","tags":[{"name":"hello-controller","description":"HELLO接口"}],"paths":{"/hello":{"get":{"tags":["hello-controller"],"summary":"欢迎","description":"欢迎","operationId":"helloUsingGET","produces":["*/*"],"parameters":[{"name":"name","in":"query","description":"name","required":true,"type":"string"}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/ApiResult"}},"204":{"description":"No Content","schema":{"$ref":"#/definitions/ApiResult"}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/ApiResult"}},"403":{"description":"Forbidden","schema":{"$ref":"#/definitions/ApiResult"}},"404":{"description":"Not Found","schema":{"$ref":"#/definitions/ApiResult"}}},"deprecated":false},"head":{"tags":["hello-controller"],"summary":"欢迎","description":"欢迎","operationId":"helloUsingHEAD","consumes":["application/json"],"produces":["*/*"],"parameters":[{"name":"name","in":"query","description":"name","required":true,"type":"string"}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/ApiResult"}},"204":{"description":"No Content","schema":{"$ref":"#/definitions/ApiResult"}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/ApiResult"}},"403":{"description":"Forbidden","schema":{"$ref":"#/definitions/ApiResult"}},"404":{"description":"Not Found","schema":{"$ref":"#/definitions/ApiResult"}}},"deprecated":false},"post":{"tags":["hello-controller"],"summary":"欢迎","description":"欢迎","operationId":"helloUsingPOST","consumes":["application/json"],"produces":["*/*"],"parameters":[{"name":"name","in":"query","description":"name","required":true,"type":"string"}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/ApiResult"}},"201":{"description":"Created"},"204":{"description":"No Content","schema":{"$ref":"#/definitions/ApiResult"}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/ApiResult"}},"403":{"description":"Forbidden","schema":{"$ref":"#/definitions/ApiResult"}},"404":{"description":"Not Found","schema":{"$ref":"#/definitions/ApiResult"}}},"deprecated":false},"put":{"tags":["hello-controller"],"summary":"欢迎","description":"欢迎","operationId":"helloUsingPUT","consumes":["application/json"],"produces":["*/*"],"parameters":[{"name":"name","in":"query","description":"name","required":true,"type":"string"}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/ApiResult"}},"201":{"description":"Created"},"204":{"description":"No Content","schema":{"$ref":"#/definitions/ApiResult"}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/ApiResult"}},"403":{"description":"Forbidden","schema":{"$ref":"#/definitions/ApiResult"}},"404":{"description":"Not Found","schema":{"$ref":"#/definitions/ApiResult"}}},"deprecated":false},"delete":{"tags":["hello-controller"],"summary":"欢迎","description":"欢迎","operationId":"helloUsingDELETE","produces":["*/*"],"parameters":[{"name":"name","in":"query","description":"name","required":true,"type":"string"}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/ApiResult"}},"204":{"description":"No Content","schema":{"$ref":"#/definitions/ApiResult"}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/ApiResult"}},"403":{"description":"Forbidden","schema":{"$ref":"#/definitions/ApiResult"}},"404":{"description":"Not Found","schema":{"$ref":"#/definitions/ApiResult"}}},"deprecated":false},"options":{"tags":["hello-controller"],"summary":"欢迎","description":"欢迎","operationId":"helloUsingOPTIONS","consumes":["application/json"],"produces":["*/*"],"parameters":[{"name":"name","in":"query","description":"name","required":true,"type":"string"}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/ApiResult"}},"204":{"description":"No Content","schema":{"$ref":"#/definitions/ApiResult"}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/ApiResult"}},"403":{"description":"Forbidden","schema":{"$ref":"#/definitions/ApiResult"}},"404":{"description":"Not Found","schema":{"$ref":"#/definitions/ApiResult"}}},"deprecated":false},"patch":{"tags":["hello-controller"],"summary":"欢迎","description":"欢迎","operationId":"helloUsingPATCH","consumes":["application/json"],"produces":["*/*"],"parameters":[{"name":"name","in":"query","description":"name","required":true,"type":"string"}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/ApiResult"}},"204":{"description":"No Content","schema":{"$ref":"#/definitions/ApiResult"}},"401":{"description":"Unauthorized","schema":{"$ref":"#/definitions/ApiResult"}},"403":{"description":"Forbidden","schema":{"$ref":"#/definitions/ApiResult"}},"404":{"description":"Not Found","schema":{"$ref":"#/definitions/ApiResult"}}},"deprecated":false}}},"definitions":{"ApiResult":{"type":"object","properties":{"code":{"type":"integer","format":"int32","description":"返回码"},"data":{"type":"object","description":"响应数据"},"message":{"type":"string","description":"错误信息"}},"title":"ApiResult","description":"api接口通用返回对象"}}}

结束