背景
1、生态目前没有成型的接口文档,接口定义都散落在每个需求的技术方案里面。前端搜集整理过到mocks里,但后端不愿意编写维护文档,效果较差
2、社区对于使用注解生成接口文档和描述数据生成TypeScript代码有着成熟的实践
具体做法
1、前端自己拉分支,部署在日常、预发环境,不发布到线上
2、Swagger生成文档和描述数据
依赖引入:
- Swagger建议使用高版本,2.9.2。低版本如2.2.2等会解析不了引入自二方包的参数
高本版依赖高版本 guava ,低版本会使应用启动不了
<dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.9.2</version></dependency><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>2.9.2</version></dependency><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>20.0</version><exclusions><exclusion><groupId>com.google.guava</groupId><artifactId>guava</artifactId></exclusion></exclusions></dependency>
3、swagger配置:
/*** swagger2配置类*/@Configuration@EnableSwagger2public class SwaggerConfig {@Beanpublic Docket createRestApi() {return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select().apis(RequestHandlerSelectors.basePackage("com.aliyun")).paths(PathSelectors.any()).build();}private ApiInfo apiInfo() {return new ApiInfoBuilder().title("基于Swagger构建的Rest API文档").description("更多请咨询开发").termsOfServiceUrl("http://prm.aliyun-inc.test/prm/#/epp/manage").version("1.0").build();}}
4、生成内容查看
在线文档地址:
/swagger-ui.html#/
描述数据:
/v2/api-docs (API SPEC的内容,可以使用postman获取。目前数据为本地部署后获取,日常环境需要处理Buc登录、CSRF token 问题,较麻烦)
5、生成TS Service
pont文档:
https://github.com/alibaba/pont
核心点:
1、pont封装了Swagger JSON的解析和TS文件创建,比提供了vscode快捷插件,降低了生成TS的成本
2、但核心的如何生成TS时候文件需要自己完成
3、Integer、Long等Java存在前端不存在的类型需要处理
个人模板
export default class MyGenerator extends CodeGenerator {getInterfaceContentInDeclaration(inter: Interface) {let requestParams = inter.getRequestParams();const paramsCode = inter.getParamsCode('Params');requestParams = this.formatParamsType(requestParams)let result = `export ${paramsCode}export type Response = ${inter.responseType}export const init: Response;export function request(${requestParams}): Promise<Response>;`;return this.resultFormat(result)}getBaseClassInDeclaration(base: BaseClass) {const originProps = base.properties;base.properties = base.properties.map(prop => {return new Property({...prop,required: false});});const result = super.getBaseClassInDeclaration(base);base.properties = originProps;return result;}getInterfaceContent(inter: Interface) {const method = inter.method.toUpperCase();let requestParams = inter.getRequestParams(Surrounding.typeScript);const bodyParams = inter.getBodyParamsCode();const paramsCode = inter.getParamsCode('Params', this.surrounding);requestParams = this.formatParamsType(requestParams)let result = `/*** @desc ${inter.description}*/import axios from 'axios';export ${paramsCode}export type Response = ${inter.responseType}export const init = ${inter.response.getInitialValue()};exportexport async function request(${requestParams}): Promise<Response> {let res = await axios.request({url: "${inter.path}",${paramsCode ? 'params,' : ''}${bodyParams ? 'data: body,' : ''}method: "${method}",baseUrl:'',...options});return res?.data}`;return this.resultFormat(result)}formatParamsType(params) {params = params.replace('int', 'Number')params = params.replace('long', 'Number')params = params.replace('ModelAndView', 'any')params = params.replace('Model', 'any')params = params.replace('defs.ObjectMap', 'ObjectMap')params = params.replace('ref', 'any')return params}resultFormat(result) {result = result.replace('defs.ObjectMap', 'ObjectMap')result = result.replace('ref', 'any')return result}}

遗留问题
1、GET 请求的参数为复杂类型时:
原始Java:
Class QueryProgramInfoParam implements Serializable {private String parentCode;private ProgramConfigs configs;}
生成的描述文件:
"parameters": [{"name": "configs.name","in": "query","required": false,"type": "string"},{"name": "configs.programConfigs[0].order","in": "query","required": false,"type": "integer","format": "int32"},{"name": "configs.programConfigs[0].programCode","in": "query","required": false,"type": "string"},{"name": "configs.programConfigs[0].status","in": "query","required": false,"type": "string","enum": ["ENABLE","INVISIBLE"]},{"name": "parentCode","in": "query","required": false,"type": "string"}]
生成的TS:
export class Params {/** name */name?: string;/** order */order?: number;/** programCode */programCode?: string;/** status */status?: 'ENABLE' | 'INVISIBLE';/** parentCode */parentCode?: string;}
临时做法:
要求后端GET参数不要用复杂类型
