Swagger自己设置格式用于提升开发效率
引言
随着前后台代码的分离,以及Restful API风格的流行,后台程序员既需要编写代码,又需要编写接口文档,无形之中加重了后台程序员的工作强度,同时后台程序员往往是不怎样喜欢编写文档的,此时一款自动生成接口文档的工具就显得非常不可缺少。Swagger的诞生,肯定程度上拯救了程序员,它能自动生成接口文档,但却并未彻底拯救,由于格式不是我们想要的,但是程序员站在Swagger的基础上即可以完全实现自我救赎。
一、方法:
Swagger是一个可以自动生成API接口文档的工具,使用它,开发者可以节约文档编写的时间。要想使用它生成API文档需要先引入Swagger的jar包,本文通过结合idea编译器和java代码来演示。
1.1引入Swagger
首先我们需要先新建一个Springboot工程(新建的时候可以不选择依赖项),新建完毕后,我们在pom文件中增加swagger相关的依赖项和插件,用于引入Swagger。依赖项和插件如下所示:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>com.spring4all</groupId> <artifactId>swagger-spring-boot-starter</artifactId> <version>1.7.1.RELEASE</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.16</version> <scope>provided</scope> </dependency> <dependency> <groupId>io.github.swagger2markup</groupId> <artifactId>swagger2markup</artifactId> <version>1.3.1</version> </dependency> <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.51</version> </dependency></dependencies><build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <plugin> <groupId>io.github.swagger2markup</groupId> <artifactId>swagger2markup-maven-plugin</artifactId> <version>1.3.1</version> <configuration> <swaggerInput>http://localhost:8080/v2/api-docs</swaggerInput> <outputDir>src/docs/asciidoc/generated</outputDir> <config> <swagger2markup.markupLanguage>ASCIIDOC</swagger2markup.markupLanguage> </config> </configuration> </plugin> <plugin> <groupId>org.asciidoctor</groupId> <artifactId>asciidoctor-maven-plugin</artifactId> <version>1.5.6</version> <configuration> <sourceDirectory>src/docs/asciidoc/generated</sourceDirectory> <outputDirectory>src/docs/asciidoc/html</outputDirectory> <backend>html</backend> <sourceHighlighter>coderay</sourceHighlighter> <attributes> <toc>left</toc> </attributes> </configuration> </plugin> </plugins></build><repositories> <repository> <snapshots> <enabled>false</enabled> </snapshots> <id>jcenter-releases</id> <name>jcenter</name> <url>http://jcenter.bintray.com</url> </repository></repositories>
1.2增加注释项
在引入Swagger之后需要在对外提供的接口上增加注释,如下所示:
package com.wcf.swagger.apihtml.controller;import com.wcf.swagger.apihtml.model.EvaluationInfo;import com.wcf.swagger.apihtml.model.TestModel;import com.wcf.swagger.apihtml.response.TestResult;import io.swagger.annotations.Api;import io.swagger.annotations.ApiImplicitParam;import io.swagger.annotations.ApiImplicitParams;import io.swagger.annotations.ApiOperation;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;/***@author wangcanfeng*@note description*@note Created in13:59-2018/11/28 */@RestController@RequestMapping("/test")@Api(description= "主要用于展现少量测试接口信息", value = "测试接口集合", produces = "application/json")public class TestController { @PostMapping("/submit") @ApiOperation("提交测试结果") @ApiImplicitParams({@ApiImplicitParam(type= "body", dataType = "EvaluationInfo", name = "planCode", value = "考评结果", required = true)})public TestResultsubmitEvaluation(@RequestBodyTestModel info) { return new TestResult("0", true); } }package com.wcf.swagger.apihtml.model;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;/***@author wangcanfeng*@note description*@note Created in 14:05-2018/11/28 */@Data@ApiModel("人员信息")@NoArgsConstructor@AllArgsConstructorpublic class TestModel { @ApiModelProperty("名称信息") private Stringname; @ApiModelProperty("年龄") private Integerage;}package com.wcf.swagger.apihtml.response;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.Data;/***@author wangcanfeng*@note description*@note Created in10:45-2018/11/24 */@Data@ApiModel("返回结果")public class TestResult<T> { @ApiModelProperty("状态码") private String code; @ApiModelProperty("数据实体") private T data; @ApiModelProperty("状态信息") private Stringmsg; public TestResult(String code, T data){ this.code=code; this .data=data; }}
1.2生成HTML文档
本文先通过swagger生成了ascii文档,而后再生成HTML文档,步骤如下所示:
(1)在生成文档前,要保证程序运行没有bug,否则不能生成文档。可以编写一个test类,而后再使用test方法生成ascii:
@Testpublic void generateAsciiDocsToFile() throwsException { // 输出Ascii到单文件 Swagger2MarkupConfig config = new Swagger2MarkupConfigBuilder() .withMarkupLanguage(MarkupLanguage. ASCIIDOC) .withOutputLanguage(Language. ZH) //选择语言为中文 .withGeneratedExamples() //选择需要输出入参和返回值样例 .build(); //localhost和8080可以改成指定的ip和端口号 Swagger2MarkupConverter.from(new URL("http://localhost:8080/v2/api-docs")) .withConfig(config) .build()//这里是输出文档的位置.toFile(Paths.get("src/docs/asciidoc/generated/all"));}
(2)配置plugin插件,设置输入输出文件位置:
<plugin> <groupId>org.asciidoctor</groupId> <artifactId>asciidoctor-maven-plugin</artifactId> <version>1.5.6</version> <configuration> <sourceDirectory>src/docs/asciidoc/generated</sourceDirectory> <outputDirectory>src/docs/asciidoc/html</outputDirectory> <backend>html</backend> <sourceHighlighter>coderay</sourceHighlighter> <attributes> <toc>left</toc> </attributes> </configuration></plugin>
在sourceDirectory配置项中设置ascii文件的位置,在outputDirectory配置项中设置输出文件的位置。
(3)运行插件,输出HTML
点击idea的侧边栏中的Maven Projects菜单,而后打开Plugins,而后点击asciidoctor:process-asciidoc,如下所示:
image.png
到这里就生成了html文档了,但是格式并不是我们想要的,并不能完全提高效率,提高生产率。
image.png
image.png
1.3自己设置格式
(1)Swagger提供的配置项,并没有设置修改格式的,所以需要修改源码,源码可以在github或者者通过idea直接下载,而后自行创立一个maven工程去修改Swagger。由于我们不满意的地方是入参表,出参表,以及结构体定义表。打开源码,主要需要修改的部分为:
image.png
其中PropertiesTableComponent结构体定义的参数表对象类,ParameterTableComponent为入参表的对象类,而后ResponseComponent这个是返回参数对象类。修改它们的apply方法,可以调整表格中各个列的顺序,以及各个列中数据的值。具体的源码量较大,参见附录,附录贴了这三个主要修改类的的源码。而后修改lang文件夹中的labels_zh.properties,可以修改表头等地方的中文字样。
将这个修改过的源码打包,install到我们的maven目录中,而后再通过自己新建的maven工程配置的groupId和artifacId以及version信息引入修改过的swagger,替换源码:
<dependency> <groupId>com.test.swagger</groupId> <artifactId>wcf-swagger</artifactId> <version>1.0-SNAPSHOT</version></dependency>
替换成
<dependency> <groupId>io.github.swagger2markup</groupId> <artifactId>swagger2markup</artifactId> <version>1.3.1</version></dependency>
(2)修改后的展现效果:
image.png
image.png
image.png
到这里表格的格式已经基本符合我们的要求了,效果不错,假如还有别的要求可以继续修改源码。
二、总结:
Swagger源码生成的API文档尽管可以直接使用,但是它的格式在不同程度上影响了我们的使用,通常我们需要对它生成文档进行各种编辑或者者只是复制出部分数据到我们已经编辑好格式的文档中,这么做不仅麻烦,还有可能出错。假如需要让它彻底的适应自身的文档格式需求,可以修改源码使得生成我们想要的文档格式。
通过修改Swagger源码,生成的自身所需求的文档格式,极大程度上减少了文档格式修改的时间,降低了开发成本,减少了开发环节,提升程序员的开发体验和舒适度。
三、附录:
3.1 ParameterTableComponent类源码:
/* * Copyright 2017 Robert Winkler * * 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. */package io.github.swagger2markup.internal.component;import ch.netzwerg.paleo.StringColumn;import io.github.swagger2markup.Swagger2MarkupConverter;import io.github.swagger2markup.internal.adapter.ParameterAdapter;import io.github.swagger2markup.internal.resolver.DocumentResolver;import io.github.swagger2markup.internal.type.ObjectType;import io.github.swagger2markup.markup.builder.MarkupDocBuilder;import io.github.swagger2markup.model.PathOperation;import io.github.swagger2markup.spi.MarkupComponent;import io.github.swagger2markup.spi.PathsDocumentExtension;import io.swagger.models.parameters.Parameter;import org.apache.commons.collections4.CollectionUtils;import org.apache.commons.lang3.StringUtils;import org.apache.commons.lang3.Validate;import java.util.List;import java.util.stream.Collectors;import static ch.netzwerg.paleo.ColumnIds.StringColumnId;import static io.github.swagger2markup.Labels.*;import static io.github.swagger2markup.internal.utils.MarkupDocBuilderUtils.copyMarkupDocBuilder;import static org.apache.commons.lang3.StringUtils.isNotBlank;public class ParameterTableComponent extends MarkupComponent<ParameterTableComponent.Parameters> { private final DocumentResolver definitionDocumentResolver; private final TableComponent tableComponent; ParameterTableComponent(Swagger2MarkupConverter.Context context, DocumentResolver definitionDocumentResolver) { super(context); this.definitionDocumentResolver = Validate.notNull(definitionDocumentResolver, "DocumentResolver must not be null"); this.tableComponent = new TableComponent(context); } public static Parameters parameters(PathOperation operation, List<ObjectType> inlineDefinitions, int titleLevel) { return new Parameters(operation, inlineDefinitions, titleLevel); } @Override public MarkupDocBuilder apply(MarkupDocBuilder markupDocBuilder, Parameters params) { PathOperation operation = params.operation; List<ObjectType> inlineDefinitions = params.inlineDefinitions; List<Parameter> parameters = operation.getOperation().getParameters(); if (config.getParameterOrdering() != null) parameters.sort(config.getParameterOrdering()); // Filter parameters to display in parameters section List<Parameter> filteredParameters = parameters.stream() .filter(this::filterParameter).collect(Collectors.toList()); MarkupDocBuilder parametersBuilder = copyMarkupDocBuilder(markupDocBuilder); applyPathsDocumentExtension(new PathsDocumentExtension.Context(PathsDocumentExtension.Position.OPERATION_PARAMETERS_BEGIN, parametersBuilder, operation)); if (CollectionUtils.isNotEmpty(filteredParameters)) {// StringColumn.Builder typeColumnBuilder = StringColumn.builder(StringColumnId.of(labels.getLabel(TYPE_COLUMN)))// .putMetaData(TableComponent.WIDTH_RATIO, "2"); StringColumn.Builder nameColumnBuilder = StringColumn.builder(StringColumnId.of(labels.getLabel(NAME_COLUMN))) .putMetaData(TableComponent.WIDTH_RATIO, "5"); StringColumn.Builder descriptionColumnBuilder = StringColumn.builder(StringColumnId.of(labels.getLabel(DESCRIPTION_COLUMN))) .putMetaData(TableComponent.WIDTH_RATIO, "9") .putMetaData(TableComponent.HEADER_COLUMN, "true"); StringColumn.Builder schemaColumnBuilder = StringColumn.builder(StringColumnId.of(labels.getLabel(SCHEMA_COLUMN))) .putMetaData(TableComponent.WIDTH_RATIO, "3") .putMetaData(TableComponent.HEADER_COLUMN, "true");// StringColumn.Builder defaultColumnBuilder = StringColumn.builder(StringColumnId.of(labels.getLabel(DEFAULT_COLUMN)))// .putMetaData(TableComponent.WIDTH_RATIO, "2")// .putMetaData(TableComponent.HEADER_COLUMN, "true"); //能否必填的列 StringColumn.Builder requireColumnBuilder = StringColumn.builder(StringColumnId.of(labels.getLabel(REQUIRE))) .putMetaData(TableComponent.WIDTH_RATIO, "3"); for (Parameter parameter : filteredParameters) { ParameterAdapter parameterAdapter = new ParameterAdapter(context, operation, parameter, definitionDocumentResolver); inlineDefinitions.addAll(parameterAdapter.getInlineDefinitions()); requireColumnBuilder.add(getParameterRequireColumnContent(markupDocBuilder,parameterAdapter));// typeColumnBuilder.add(parameterAdapter.displayType(markupDocBuilder)); nameColumnBuilder.add(getParameterNameColumnContent(markupDocBuilder, parameterAdapter)); schemaColumnBuilder.add(parameterAdapter.displaySchema(markupDocBuilder));// defaultColumnBuilder.add(parameterAdapter.displayDefaultValue(markupDocBuilder)); descriptionColumnBuilder.add(parameterAdapter.displayDescription(markupDocBuilder)); } //调整这里的参数顺序可以修改最后生成的表格的列的顺序 parametersBuilder = tableComponent.apply(parametersBuilder, TableComponent.parameters(// typeColumnBuilder.build(), nameColumnBuilder.build(), schemaColumnBuilder.build(), requireColumnBuilder.build(), descriptionColumnBuilder.build()// defaultColumnBuilder.build() )); } applyPathsDocumentExtension(new PathsDocumentExtension.Context(PathsDocumentExtension.Position.OPERATION_PARAMETERS_END, parametersBuilder, operation)); String parametersContent = parametersBuilder.toString(); applyPathsDocumentExtension(new PathsDocumentExtension.Context(PathsDocumentExtension.Position.OPERATION_PARAMETERS_BEFORE, markupDocBuilder, operation)); if (isNotBlank(parametersContent)) { markupDocBuilder.sectionTitleLevel(params.titleLevel, labels.getLabel(PARAMETERS)); markupDocBuilder.text(parametersContent); } applyPathsDocumentExtension(new PathsDocumentExtension.Context(PathsDocumentExtension.Position.OPERATION_PARAMETERS_AFTER, markupDocBuilder, operation)); return markupDocBuilder; } private String getParameterNameColumnContent(MarkupDocBuilder markupDocBuilder, ParameterAdapter parameter) { MarkupDocBuilder parameterNameContent = copyMarkupDocBuilder(markupDocBuilder); parameterNameContent.boldTextLine(parameter.getName(), true); //能否必填的信息都存在单独列里面 //生成的名称列不需要有能否必填// if (parameter.getRequired())// parameterNameContent.italicText(labels.getLabel(FLAGS_REQUIRED).toLowerCase());// else// parameterNameContent.italicText(labels.getLabel(FLAGS_OPTIONAL).toLowerCase()); return parameterNameContent.toString(); } /** * 功能形容: * @param markupDocBuilder 文件编辑器 * @param parameter 参数对象 * @return: 不用管 * @since: v2.2 * @Author:wangcanfeng * @Date: 2018/11/23 14:32 */ private String getParameterRequireColumnContent(MarkupDocBuilder markupDocBuilder, ParameterAdapter parameter) { MarkupDocBuilder parameterReuqireContent = copyMarkupDocBuilder(markupDocBuilder); //能否必填的信息都存在单独列里面 if (parameter.getRequired()) parameterReuqireContent.italicText(labels.getLabel(FLAGS_REQUIRED).toLowerCase()); else parameterReuqireContent.italicText(labels.getLabel(FLAGS_OPTIONAL).toLowerCase()); return parameterReuqireContent.toString(); } /** * Filter parameters to display in parameters section * * @param parameter parameter to filter * @return true if parameter can be displayed */ private boolean filterParameter(Parameter parameter) { return (!config.isFlatBodyEnabled() || !StringUtils.equals(parameter.getIn(), "body")); } /** * Apply extension context to all OperationsContentExtension. * * @param context context */ private void applyPathsDocumentExtension(PathsDocumentExtension.Context context) { extensionRegistry.getPathsDocumentExtensions().forEach(extension -> extension.apply(context)); } public static class Parameters { private final PathOperation operation; private final int titleLevel; private final List<ObjectType> inlineDefinitions; public Parameters(PathOperation operation, List<ObjectType> inlineDefinitions, int titleLevel) { this.operation = Validate.notNull(operation, "PathOperation must not be null"); this.inlineDefinitions = Validate.notNull(inlineDefinitions, "InlineDefinitions must not be null"); this.titleLevel = titleLevel; } }}
3.2 PropertiesTableComponent源码:
/* * Copyright 2017 Robert Winkler * * 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. */package io.github.swagger2markup.internal.component;import ch.netzwerg.paleo.ColumnIds;import ch.netzwerg.paleo.StringColumn;import io.github.swagger2markup.Swagger2MarkupConverter;import io.github.swagger2markup.internal.adapter.ParameterAdapter;import io.github.swagger2markup.internal.adapter.PropertyAdapter;import io.github.swagger2markup.internal.resolver.DocumentResolver;import io.github.swagger2markup.internal.type.ObjectType;import io.github.swagger2markup.internal.type.Type;import io.github.swagger2markup.markup.builder.MarkupDocBuilder;import io.github.swagger2markup.spi.MarkupComponent;import io.swagger.models.properties.Property;import io.swagger.util.Json;import org.apache.commons.collections4.MapUtils;import org.apache.commons.lang3.Validate;import java.math.BigDecimal;import java.text.DecimalFormat;import java.text.DecimalFormatSymbols;import java.util.List;import java.util.Map;import java.util.Optional;import static io.github.swagger2markup.Labels.*;import static io.github.swagger2markup.internal.utils.InlineSchemaUtils.createInlineType;import static io.github.swagger2markup.internal.utils.MapUtils.toSortedMap;import static io.github.swagger2markup.internal.utils.MarkupDocBuilderUtils.copyMarkupDocBuilder;import static io.github.swagger2markup.internal.utils.MarkupDocBuilderUtils.markupDescription;import static org.apache.commons.lang3.StringUtils.isNotBlank;public class PropertiesTableComponent extends MarkupComponent<PropertiesTableComponent.Parameters> { private final DocumentResolver definitionDocumentResolver; private final TableComponent tableComponent; /** * Build a generic property table * * @param definitionDocumentResolver definition document resolver to apply to property type cross-reference */ PropertiesTableComponent(Swagger2MarkupConverter.Context context, DocumentResolver definitionDocumentResolver) { super(context); this.definitionDocumentResolver = definitionDocumentResolver; this.tableComponent = new TableComponent(context); } public static Parameters parameters(Map<String, Property> properties, String parameterName, List<ObjectType> inlineDefinitions) { return new Parameters(properties, parameterName, inlineDefinitions); } public MarkupDocBuilder apply(MarkupDocBuilder markupDocBuilder, Parameters params) { //TODO: This method is too complex, split it up in smaller methods to increase readability //展现属性名,类型,能否必填,形容列表 //名称 StringColumn.Builder nameColumnBuilder = StringColumn.builder( ColumnIds.StringColumnId.of(labels.getLabel(NAME_COLUMN))) .putMetaData(TableComponent.WIDTH_RATIO, "5"); //形容 StringColumn.Builder descriptionColumnBuilder = StringColumn.builder( ColumnIds.StringColumnId.of( labels.getLabel(DESCRIPTION_COLUMN))) .putMetaData(TableComponent.WIDTH_RATIO, "9") .putMetaData(TableComponent.HEADER_COLUMN, "true"); //内容 StringColumn.Builder schemaColumnBuilder = StringColumn.builder( ColumnIds.StringColumnId.of(labels.getLabel(SCHEMA_COLUMN))) .putMetaData(TableComponent.WIDTH_RATIO, "3") .putMetaData(TableComponent.HEADER_COLUMN, "true"); //能否必填的列 StringColumn.Builder requireColumnBuilder = StringColumn.builder( ColumnIds.StringColumnId.of(labels.getLabel(REQUIRE))) .putMetaData(TableComponent.WIDTH_RATIO, "3"); Map<String, Property> properties = params.properties; if (MapUtils.isNotEmpty(properties)) { Map<String, Property> sortedProperties = toSortedMap(properties, config.getPropertyOrdering()); sortedProperties.forEach((String propertyName, Property property) -> { PropertyAdapter propertyAdapter = new PropertyAdapter(property); Type propertyType = propertyAdapter.getType(definitionDocumentResolver); if (config.isInlineSchemaEnabled()) { propertyType = createInlineType(propertyType, propertyName, params.parameterName + " " + propertyName, params.inlineDefinitions); } Optional<Object> optionalExample = propertyAdapter.getExample( config.isGeneratedExamplesEnabled(), markupDocBuilder); Optional<Object> optionalDefaultValue = propertyAdapter.getDefaultValue(); Optional<Integer> optionalMaxLength = propertyAdapter.getMaxlength(); Optional<Integer> optionalMinLength = propertyAdapter.getMinlength(); Optional<String> optionalPattern = propertyAdapter.getPattern(); Optional<BigDecimal> optionalMinValue = propertyAdapter.getMin(); boolean exclusiveMin = propertyAdapter.getExclusiveMin(); Optional<BigDecimal> optionalMaxValue = propertyAdapter.getMax(); boolean exclusiveMax = propertyAdapter.getExclusiveMax(); MarkupDocBuilder propertyNameContent = copyMarkupDocBuilder(markupDocBuilder); propertyNameContent.boldTextLine(propertyName, true); //不展现// if (propertyAdapter.getReadOnly()) {// propertyNameContent.newLine(true);// propertyNameContent.italicText(labels.getLabel(FLAGS_READ_ONLY).toLowerCase());// } MarkupDocBuilder descriptionContent = copyMarkupDocBuilder(markupDocBuilder); String description = markupDescription(config.getSwaggerMarkupLanguage(), markupDocBuilder, property.getDescription()); if (isNotBlank(description)) descriptionContent.text(description); if (optionalDefaultValue.isPresent()) { if (isNotBlank(descriptionContent.toString())) { descriptionContent.newLine(true); } descriptionContent.boldText(labels.getLabel(DEFAULT_COLUMN)) .text(COLON).literalText(Json.pretty(optionalDefaultValue.get())); } if (optionalMinLength.isPresent() && optionalMaxLength.isPresent()) { // combination of minlength/maxlength Integer minLength = optionalMinLength.get(); Integer maxLength = optionalMaxLength.get(); if (isNotBlank(descriptionContent.toString())) { descriptionContent.newLine(true); } String lengthRange = minLength + " - " + maxLength; if (minLength.equals(maxLength)) { lengthRange = minLength.toString(); } descriptionContent.boldText(labels.getLabel(LENGTH_COLUMN)) .text(COLON).literalText(lengthRange); } else { if (optionalMinLength.isPresent()) { if (isNotBlank(descriptionContent.toString())) { descriptionContent.newLine(true); } descriptionContent.boldText(labels.getLabel(MINLENGTH_COLUMN)). text(COLON).literalText(optionalMinLength.get().toString()); } if (optionalMaxLength.isPresent()) { if (isNotBlank(descriptionContent.toString())) { descriptionContent.newLine(true); } descriptionContent.boldText(labels.getLabel(MAXLENGTH_COLUMN)). text(COLON).literalText(optionalMaxLength.get().toString()); } } if (optionalPattern.isPresent()) { if (isNotBlank(descriptionContent.toString())) { descriptionContent.newLine(true); } descriptionContent.boldText(labels.getLabel(PATTERN_COLUMN)). text(COLON).literalText(Json.pretty(optionalPattern.get())); } DecimalFormat numberFormatter = new DecimalFormat("#.##", DecimalFormatSymbols.getInstance(config.getOutputLanguage().toLocale())); if (optionalMinValue.isPresent()) { if (isNotBlank(descriptionContent.toString())) { descriptionContent.newLine(true); } String minValueColumn = exclusiveMin ? labels. getLabel(MINVALUE_EXCLUSIVE_COLUMN) : labels.getLabel(MINVALUE_COLUMN); descriptionContent.boldText(minValueColumn).text(COLON) .literalText(numberFormatter.format(optionalMinValue.get())); } if (optionalMaxValue.isPresent()) { if (isNotBlank(descriptionContent.toString())) { descriptionContent.newLine(true); } String maxValueColumn = exclusiveMax ? labels .getLabel(MAXVALUE_EXCLUSIVE_COLUMN) : labels.getLabel(MAXVALUE_COLUMN); descriptionContent.boldText(maxValueColumn).text(COLON) .literalText(numberFormatter.format(optionalMaxValue.get())); } if (optionalExample.isPresent()) { if (isNotBlank(description) || optionalDefaultValue.isPresent()) { descriptionContent.newLine(true); }// descriptionContent.boldText(labels.getLabel(EXAMPLE_COLUMN))// .text(COLON).literalText(Json.pretty(optionalExample.get())); } nameColumnBuilder.add(propertyNameContent.toString()); schemaColumnBuilder.add(propertyType.displaySchema(markupDocBuilder)); requireColumnBuilder.add(getParameterRequireColumnContent(markupDocBuilder,property)); descriptionColumnBuilder.add(descriptionContent.toString()); }); } return tableComponent.apply(markupDocBuilder, TableComponent.parameters( nameColumnBuilder.build(), schemaColumnBuilder.build(), requireColumnBuilder.build(), descriptionColumnBuilder.build() )); } public static class Parameters { private final Map<String, Property> properties; private final String parameterName; private final List<ObjectType> inlineDefinitions; public Parameters(Map<String, Property> properties, String parameterName, List<ObjectType> inlineDefinitions) { this.properties = Validate.notNull(properties, "Properties must not be null"); this.parameterName = Validate.notBlank(parameterName, "ParameterName must not be blank"); this.inlineDefinitions = Validate.notNull(inlineDefinitions, "InlineDefinitions must not be null"); } } /** * 功能形容: * * @param markupDocBuilder 文件编辑器 * @return: 不用管 * @since: v2.2 * @Author:wangcanfeng * @Date: 2018/11/23 14:32 */ private String getParameterRequireColumnContent(MarkupDocBuilder markupDocBuilder,Property property) { MarkupDocBuilder parameterRequireContent = copyMarkupDocBuilder(markupDocBuilder); //能否必填的信息都存在单独列里面 if (property.getRequired()) parameterRequireContent.italicText(labels.getLabel(FLAGS_REQUIRED).toLowerCase()); else parameterRequireContent.italicText(labels.getLabel(FLAGS_OPTIONAL).toLowerCase());// parameterRequireContent.italicText("是"); return parameterRequireContent.toString(); }}
3.3 ResponseComponent源码:
/* * Copyright 2017 Robert Winkler * * 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. */package io.github.swagger2markup.internal.component;import ch.netzwerg.paleo.StringColumn;import io.github.swagger2markup.Swagger2MarkupConverter;import io.github.swagger2markup.internal.adapter.ParameterAdapter;import io.github.swagger2markup.internal.adapter.PropertyAdapter;import io.github.swagger2markup.internal.resolver.DocumentResolver;import io.github.swagger2markup.internal.type.ObjectType;import io.github.swagger2markup.internal.type.Type;import io.github.swagger2markup.markup.builder.MarkupDocBuilder;import io.github.swagger2markup.model.PathOperation;import io.github.swagger2markup.spi.MarkupComponent;import io.github.swagger2markup.spi.PathsDocumentExtension;import io.swagger.models.Response;import io.swagger.models.properties.Property;import io.swagger.util.Json;import org.apache.commons.collections4.MapUtils;import org.apache.commons.lang3.Validate;import java.util.List;import java.util.Map;import java.util.Optional;import static ch.netzwerg.paleo.ColumnIds.StringColumnId;import static io.github.swagger2markup.Labels.*;import static io.github.swagger2markup.internal.utils.InlineSchemaUtils.createInlineType;import static io.github.swagger2markup.internal.utils.MapUtils.toSortedMap;import static io.github.swagger2markup.internal.utils.MarkupDocBuilderUtils.*;import static org.apache.commons.lang3.StringUtils.isNotBlank;public class ResponseComponent extends MarkupComponent<ResponseComponent.Parameters> { private final TableComponent tableComponent; private final DocumentResolver definitionDocumentResolver; ResponseComponent(Swagger2MarkupConverter.Context context, DocumentResolver definitionDocumentResolver) { super(context); this.definitionDocumentResolver = Validate.notNull(definitionDocumentResolver, "DocumentResolver must not be null"); this.tableComponent = new TableComponent(context); } public static Parameters parameters(PathOperation operation, int titleLevel, List<ObjectType> inlineDefinitions) { return new Parameters(operation, titleLevel, inlineDefinitions); } @Override public MarkupDocBuilder apply(MarkupDocBuilder markupDocBuilder, Parameters params) { PathOperation operation = params.operation; Map<String, Response> responses = operation.getOperation().getResponses(); MarkupDocBuilder responsesBuilder = copyMarkupDocBuilder(markupDocBuilder); applyPathsDocumentExtension(new PathsDocumentExtension.Context(PathsDocumentExtension.Position.OPERATION_RESPONSES_BEGIN, responsesBuilder, operation)); if (MapUtils.isNotEmpty(responses)) { //返回参数表也需要按照属性名,参数类型,能否必填,形容来展现 //HTTP代码不需要展现// StringColumn.Builder httpCodeColumnBuilder = StringColumn.builder(StringColumnId.of(labels.getLabel(HTTP_CODE_COLUMN)))// .putMetaData(TableComponent.WIDTH_RATIO, "2"); StringColumn.Builder nameColumnBuilder = StringColumn.builder(StringColumnId.of(labels.getLabel(NAME_COLUMN))) .putMetaData(TableComponent.WIDTH_RATIO, "5"); StringColumn.Builder schemaColumnBuilder = StringColumn.builder(StringColumnId.of(labels.getLabel(SCHEMA_COLUMN))) .putMetaData(TableComponent.WIDTH_RATIO, "3") .putMetaData(TableComponent.HEADER_COLUMN, "true"); //能否必填的列 StringColumn.Builder requireColumnBuilder = StringColumn.builder(StringColumnId.of(labels.getLabel(REQUIRE))) .putMetaData(TableComponent.WIDTH_RATIO, "3") .putMetaData(TableComponent.HEADER_COLUMN, "true"); StringColumn.Builder descriptionColumnBuilder = StringColumn.builder(StringColumnId.of(labels.getLabel(DESCRIPTION_COLUMN))) .putMetaData(TableComponent.WIDTH_RATIO, "9") .putMetaData(TableComponent.HEADER_COLUMN, "true"); Map<String, Response> sortedResponses = toSortedMap(responses, config.getResponseOrdering()); sortedResponses.forEach((String responseName, Response response) -> { String schemaContent = labels.getLabel(NO_CONTENT); if (response.getSchema() != null) { Property property = response.getSchema(); Type type = new PropertyAdapter(property).getType(definitionDocumentResolver); if (config.isInlineSchemaEnabled()) { type = createInlineType(type, labels.getLabel(RESPONSE) + " " + responseName, operation.getId() + " " + labels.getLabel(RESPONSE) + " " + responseName, params.inlineDefinitions); } schemaContent = type.displaySchema(markupDocBuilder); } MarkupDocBuilder descriptionBuilder = copyMarkupDocBuilder(markupDocBuilder); descriptionBuilder.text(markupDescription(config.getSwaggerMarkupLanguage(), markupDocBuilder, response.getDescription()));// Map<String, Property> headers = response.getHeaders();// if (MapUtils.isNotEmpty(headers)) {// descriptionBuilder.newLine(true).boldText(// labels.getLabel(HEADERS_COLUMN)).text(COLON);// for (Map.Entry<String, Property> header : headers.entrySet()) {// descriptionBuilder.newLine(true);// Property headerProperty = header.getValue();// PropertyAdapter headerPropertyAdapter = new PropertyAdapter(headerProperty);// Type propertyType = headerPropertyAdapter.getType(definitionDocumentResolver);// String headerDescription = markupDescription(config.getSwaggerMarkupLanguage(), // markupDocBuilder, headerProperty.getDescription());// Optional<Object> optionalDefaultValue = headerPropertyAdapter.getDefaultValue();//// descriptionBuilder// .literalText(header.getKey())// .text(String.format(" (%s)", propertyType.displaySchema(markupDocBuilder)));//// if (isNotBlank(headerDescription) || optionalDefaultValue.isPresent()) {// descriptionBuilder.text(COLON);//// if (isNotBlank(headerDescription) && !headerDescription.endsWith("."))// headerDescription += ".";//// descriptionBuilder.text(headerDescription);//// optionalDefaultValue.ifPresent(o -> descriptionBuilder.text(" ")// .boldText(labels.getLabel(DEFAULT_COLUMN))// .text(COLON).literalText(Json.pretty(o)));// }// }// } //todo 不需要加载http代码// httpCodeColumnBuilder.add(boldText(markupDocBuilder, responseName)); nameColumnBuilder.add(boldText(markupDocBuilder, responseName)); requireColumnBuilder.add(getParameterRequireColumnContent(markupDocBuilder)); descriptionColumnBuilder.add(descriptionBuilder.toString()); schemaColumnBuilder.add(schemaContent); }); //显示顺序需要改为属性名,类型,能否必填,形容 responsesBuilder = tableComponent.apply(responsesBuilder, TableComponent.parameters(// httpCodeColumnBuilder.build(), nameColumnBuilder.build(), schemaColumnBuilder.build(), requireColumnBuilder.build(), descriptionColumnBuilder.build())); } applyPathsDocumentExtension(new PathsDocumentExtension.Context( PathsDocumentExtension.Position.OPERATION_RESPONSES_END, responsesBuilder, operation)); String responsesContent = responsesBuilder.toString(); applyPathsDocumentExtension(new PathsDocumentExtension.Context( PathsDocumentExtension.Position.OPERATION_RESPONSES_BEFORE, markupDocBuilder, operation)); if (isNotBlank(responsesContent)) { markupDocBuilder.sectionTitleLevel(params.titleLevel, labels.getLabel(RESPONSES)); markupDocBuilder.text(responsesContent); } applyPathsDocumentExtension(new PathsDocumentExtension.Context(PathsDocumentExtension.Position.OPERATION_RESPONSES_AFTER, markupDocBuilder, operation)); return markupDocBuilder; } /** * Apply extension context to all OperationsContentExtension. * * @param context context */ private void applyPathsDocumentExtension(PathsDocumentExtension.Context context) { extensionRegistry.getPathsDocumentExtensions().forEach(extension -> extension.apply(context)); } public static class Parameters { private final PathOperation operation; private final int titleLevel; private final List<ObjectType> inlineDefinitions; public Parameters(PathOperation operation, int titleLevel, List<ObjectType> inlineDefinitions) { this.operation = Validate.notNull(operation, "PathOperation must not be null"); this.titleLevel = titleLevel; this.inlineDefinitions = Validate.notNull(inlineDefinitions, "InlineDefinitions must not be null"); } } /** * 功能形容: * * @param markupDocBuilder 文件编辑器 * @return: 不用管 * @since: v2.2 * @Author:wangcanfeng * @Date: 2018/11/23 14:32 */ private String getParameterRequireColumnContent(MarkupDocBuilder markupDocBuilder) { MarkupDocBuilder parameterRequireContent = copyMarkupDocBuilder(markupDocBuilder); //一律默认为需要 parameterRequireContent.italicText(labels.getLabel(FLAGS_REQUIRED)); return parameterRequireContent.toString(); }}
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » Swagger自己设置格式用于提升开发效率