今天研究了下API框架,在网上查了下swagger相对不错,特别看了下,大体上可以解决问题,但是有些问题一直不知道原因,再次记录,后期希望能够处理掉。
首先是maven+eclipse,引入相应依赖包:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.github.swagger2markup</groupId>
<artifactId>swagger2markup-maven-plugin</artifactId>
<version>1.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctorj</artifactId>
<version>1.5.4.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>org.springframework.restdocs</groupId>
<artifactId>spring-restdocs-mockmvc</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-staticdocs</artifactId>
<version>2.6.1</version>
</dependency>
</dependencies>
可以通过springboot写个简单的接口,然后在类或方法上加上swagger相关注解,比如
@Api(value="/user",tags="UserController")
@RestController
@RequestMapping("/user")
public class UserController {
public static Map<Integer,User> users = Collections.synchronizedMap(new HashMap<Integer, User>());
static{
buildUsers();
}
private static void buildUsers() {
// TODO Auto-generated method stub
for(int i=0;i<10;i++) {
User user = new User();
user.setId(i);
user.setName("name"+i);
user.setCtm(new Date());
user.setAge((int) (20+(Math.random()*10)/2));
users.put(i, user);
}
}
@ApiOperation(value="获取用户信息",notes="根据id查询用户")
@ApiImplicitParams({@ApiImplicitParam(name="id",value="用户id",required=true,dataType="Integer",paramType="path")})
@GetMapping("/{id}")
public ResponseEntity<JsonResult> getUserById(@PathVariable("id") int id){
User user = users.get(id);
JsonResult jr = new JsonResult();
jr.setResult(user);
jr.setStatus("ok");
return ResponseEntity.ok(jr);
}
同时加上swagger相关配置:
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.api.demo"))
.paths(PathSelectors.any())
.build();
//.pathMapping("/myapp"); // 在这里可以设置请求的统一前缀;
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Spring boot API文档")
.description("文档描述")
.termsOfServiceUrl("http://123.com")
.version("1.0.0")
.build();
}
启动项目,此时可以通过 http://localhost:8080/swagger-ui.html访问到项目api并进行测试。
然后将api以文档形式导出,按网上有两种方式实现,
需要用的技术与过程:
1)生成swagger.json/yaml文件,可以通过代码生成或者maven插件swagger-maven-plugin。
2)通过Swagger2markup将Swagger语义(json、yaml)转换成markdown、asciidoc文本格式。
3)通过Asciidoctor将adoc文档转换成html或pdf的最终格式。
实现方式:
a、存代码实现
@WebAppConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes=Application.class)
public class Swagger2MarkupTest {
@Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
@Before
public void setUp() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
// @Test
public void createSpringfoxSwaggerJson()throws Exception{
String outputDir = "src/docs/json";//将api-docs的json数据写入文件
MvcResult mvcResult = this.mockMvc.perform(get("/v2/api-docs")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andReturn();
MockHttpServletResponse response = mvcResult.getResponse();
String swaggerJson = response.getContentAsString();
Files.createDirectories(Paths.get(outputDir));
BufferedWriter writer = Files.newBufferedWriter(Paths.get(outputDir, "swagger.json"), StandardCharsets.UTF_8);
writer.write(swaggerJson);
}
/**
* 通过代码方式实现
* @throws Exception
*/
@Test
public void convertSwaggerToAsciiDoc() throws Exception {
MvcResult mvcResult = this.mockMvc.perform(get("/v2/api-docs")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andReturn();
//文档输出目录
String outputDirectory = "docs/restful/generated";
MockHttpServletResponse response = mvcResult.getResponse();
String swaggerJson = response.getContentAsString();
// swaggerJson = swaggerJson.replace("{\"status\":200,\"message\":\"\",\"data\":", "");
// swaggerJson = swaggerJson.substring(0,swaggerJson.length()-1);
Swagger2MarkupConverter.from(swaggerJson).build().toFolder(Paths.get(outputDirectory));
Asciidoctor asciidoctor = Asciidoctor.Factory.create();
Attributes attributes = new Attributes();
attributes.setCopyCss(true);
attributes.setLinkCss(false);
attributes.setSectNumLevels(3);
attributes.setAnchors(true);
attributes.setSectionNumbers(true);
attributes.setHardbreaks(true);
attributes.setTableOfContents(Placement.LEFT);
attributes.setAttribute("generated", "generated");
OptionsBuilder optionsBuilder = OptionsBuilder.options()
.backend("html5")
.docType("book")
.eruby("")
.inPlace(true)
.safe(SafeMode.UNSAFE)
.attributes(attributes);
String asciiInputFile = "docs/restful/index.adoc";//先定义该文件
initIndex(asciiInputFile);
asciidoctor.convertFile(
new File(asciiInputFile),
optionsBuilder.get());
}
public static void initIndex(String path) {
File index = new File(path);//index.adoc
if(index.exists() && index.isDirectory() && "index.adoc".equals(index.getName())) {
}else {
try {
FileUtils.copyFile(new File("temp/index.adoc"), index);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
其中index.adoc需要自己编写。
b)通过maven插件实现:
首先编写生成swagger.json代码(为什么写在代码里,这是一个问题)
@WebAppConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
//@AutoConfigureRestDocs(outputDir = "build/asciidoc/snippets")
@SpringBootTest(classes=Application.class)
public class Swagger2MarkupDoc {
@Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
@Before
public void setUp() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
@Test
public void createSpringfoxSwaggerJson(){
String outputDir = "src/docs/json";//将api-docs的json数据写入文件
// String outputDir = System.getProperty("io.springfox.staticdocs.outputDir");
BufferedWriter writer = null;
try {
MvcResult mvcResult = this.mockMvc.perform(get("/v2/api-docs")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andReturn();
MockHttpServletResponse response = mvcResult.getResponse();
String swaggerJson = response.getContentAsString();
Files.createDirectories(Paths.get(outputDir));
writer = Files.newBufferedWriter(Paths.get(outputDir, "swagger.json"), StandardCharsets.UTF_8);
writer.write(swaggerJson);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if(writer!=null) writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
然后在pom引入相关包和插件:
<pluginRepositories>
<pluginRepository>
<id>jcenter-snapshots</id>
<name>jcenter</name>
<url>http://oss.jfrog.org/artifactory/oss-snapshot-local/</url>
</pluginRepository>
<pluginRepository>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>jcenter-releases</id>
<name>jcenter</name>
<url>http://jcenter.bintray.com</url>
</pluginRepository>
</pluginRepositories>
<build>
<plugins>
<plugin>
<groupId>io.github.swagger2markup</groupId>
<artifactId>swagger2markup-maven-plugin</artifactId>
<version>${swagger2markup.version}</version>
<dependencies>
<dependency>
<groupId>io.github.swagger2markup</groupId>
<artifactId>swagger2markup-import-files-ext</artifactId>
<version>${swagger2markup.version}</version>
</dependency>
<dependency>
<groupId>io.github.swagger2markup</groupId>
<artifactId>swagger2markup-spring-restdocs-ext</artifactId>
<version>${swagger2markup.version}</version>
</dependency>
</dependencies>
<configuration>
<swaggerInput>${swagger.input}</swaggerInput>
<outputDir>${generated.asciidoc.directory}</outputDir>
<config>
<swagger2markup.markupLanguage>ASCIIDOC</swagger2markup.markupLanguage>
<swagger2markup.pathsGroupedBy>TAGS</swagger2markup.pathsGroupedBy>
<swagger2markup.extensions.dynamicOverview.contentPath>${project.basedir}/src/docs/asciidoc/extensions/overview</swagger2markup.extensions.dynamicOverview.contentPath>
<swagger2markup.extensions.dynamicDefinitions.contentPath>${project.basedir}/src/docs/asciidoc/extensions/definitions</swagger2markup.extensions.dynamicDefinitions.contentPath>
<swagger2markup.extensions.dynamicPaths.contentPath>${project.basedir}/src/docs/asciidoc/extensions/paths</swagger2markup.extensions.dynamicPaths.contentPath>
<swagger2markup.extensions.dynamicSecurity.contentPath>${project.basedir}src/docs/asciidoc/extensions/security/</swagger2markup.extensions.dynamicSecurity.contentPath>
<swagger2markup.extensions.springRestDocs.snippetBaseUri>${swagger.snippetOutput.dir}</swagger2markup.extensions.springRestDocs.snippetBaseUri>
<swagger2markup.extensions.springRestDocs.defaultSnippets>false</swagger2markup.extensions.springRestDocs.defaultSnippets>
</config>
</configuration>
<executions>
<execution>
<phase>test</phase>
<goals>
<goal>convertSwagger2markup</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Then, run the generated asciidoc through Asciidoctor to generate
other documentation types, such as PDFs or HTML5 -->
<plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
<version>1.5.3</version>
<!-- Include Asciidoctor PDF for pdf generation -->
<dependencies>
<dependency>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctorj-pdf</artifactId>
<version>1.5.0-alpha.11</version>
</dependency>
<dependency>
<groupId>org.jruby</groupId>
<artifactId>jruby-complete</artifactId>
<version>1.7.21</version>
</dependency>
</dependencies>
<!-- Configure generic document generation settings -->
<configuration>
<sourceDirectory>${asciidoctor.input.directory}</sourceDirectory>
<sourceDocumentName>index.adoc</sourceDocumentName>
<attributes>
<doctype>book</doctype>
<toc>left</toc>
<toclevels>3</toclevels>
<numbered></numbered>
<hardbreaks></hardbreaks>
<sectlinks></sectlinks>
<sectanchors></sectanchors>
<generated>${generated.asciidoc.directory}</generated>
</attributes>
</configuration>
<!-- Since each execution can only handle one backend, run separate executions
for each desired output type -->
<executions>
<execution>
<id>output-html</id>
<phase>test</phase>
<goals>
<goal>process-asciidoc</goal>
</goals>
<configuration>
<backend>html5</backend>
<outputDirectory>${asciidoctor.html.output.directory}</outputDirectory>
</configuration>
</execution>
<execution>
<id>output-pdf</id>
<phase>test</phase>
<goals>
<goal>process-asciidoc</goal>
</goals>
<configuration>
<backend>pdf</backend>
<outputDirectory>${asciidoctor.pdf.output.directory}</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<io.springfox.staticdocs.outputDir>${swagger.output.dir}</io.springfox.staticdocs.outputDir>
<io.springfox.staticdocs.snippetsOutputDir>${swagger.snippetOutput.dir}</io.springfox.staticdocs.snippetsOutputDir>
</systemPropertyVariables>
<!-- 跳过mvn test -->
<skip>false</skip>
<!-- 只测试swagger包下的类 -->
<!-- <test>swagger.*</test> -->
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerVersion>${java.version}</compilerVersion>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>UTF-8</encoding>
<!-- prevents endPosTable exception for maven compile -->
<useIncrementalCompilation>false</useIncrementalCompilation>
</configuration>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>
com.github.kongchen
</groupId>
<artifactId>
swagger-maven-plugin
</artifactId>
<versionRange>
[3.1.5,)
</versionRange>
<goals>
<goal>generate</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore></ignore>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
通过mvn test命令即可生成文档,路径为target/asciidoc下。
问题:
1、通过代码生成只要引入相关的jar包即可,主要问题体现在通过maven插件,首先我们在生成swagger.json文件,目前是通过代码实现,而不是swagger-maven-plugin插件,因为在使用此插件时生成的json文件不完整,没有包含任何接口相关的信息,一直没找到原因,在网上示例中也是正常的,不知道与springboot有没关系;
示例代码代码