Swagger 2(Open API v3.0) Java 文档生成指南(下)

先介绍网上“搜刮”的资源:

  • Swagger 从入门到精通,如何编写基于 OpenAPI 规范的 API 文档,https://legacy.gitbook.com/book/huangwenchao/swagger/details https://blog.csdn.net/lucky373125/article/details/80471525
  • Swagger 和 OpenAPI https://www.breakyizhan.com/swagger/2806.html
  • Swagger 2与 OpenAPI 3 https://www.jianshu.com/p/879baf1cff07
  • 官文注解: https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X—Annotations

和 Swagger UI 的集成

怎么把这些 API 信息漂亮地展示出来呢? 接下来我们通过集成 Swagger UI 来实现。首先是下载 Swargger UI,它是一个 react 写成的纯前端项目,可以集成到任意服务端中,只要让可以读取到 API 的定义文件即可,所以呢,哪怕是 file:// 打开也行,它会解析可以访问到的 yaml/json 文件,渲染漂亮的文档出来。

Swagger UI 不过就是 HTML+JS+CSS,到 https://github.com/swagger-api/swagger-ui/tree/master/dist 下载,注意是 dist 发布版本。如果你前端动手能力强,可以使用非 dist 版的,通过 webpack 等其他方案集成。但那样就不是和 Java Web 项目集成了,另外一个 web service 服务在跑。笔者为了省事,集成在当前 java 项目中,用 tomcat 跑。

但也要注意一下访问权限的问题,不能让所有人都访问,特别是包含敏感信息的接口。

下载回来,解压,发现源码包含 map 用于调试的,好几兆呢,我们不要,只要 HTML/JS/CSS 便可。

Swagger 2(Open API v3.0) Java 文档生成指南(下)_第1张图片
运行一下,没毛病呢。

Swagger 2(Open API v3.0) Java 文档生成指南(下)_第2张图片
默认是 PetStore 的,打开 index.html 修改之。
Swagger 2(Open API v3.0) Java 文档生成指南(下)_第3张图片
修改为本地的即可。

是不是觉得很简单呢?还有很多好玩的,例如转换为 markdown,就要看看 swagger2markup https://blog.csdn.net/qq_34368762/article/details/79129303

配置文件 openapi.yaml

配置文件 openapi.yaml 默认放在 classpath 中,才可以被读取。官方另外提供几种途径来编写 Swagger 的配置文件,这里就是不赘述了。
下面是配置文件的一个例子。

resourcePackages:
- com.foo.controller
prettyPrint: true
cacheTTL: 0

openAPI:
  info:
    version: '1.0'
    title: 无忧在线 API
    description: 'HTTP + JSON 接口,接口需要 token'
    termsOfService: http://swagger.io/terms/
    contact:
      email: [email protected]
    license:
      name: Apache 2.0
      url: http://www.apache.org/licenses/LICENSE-2.0.html
  servers:
  - url: /wyzx-pc 

值得注意的有:

  • resourcePackages 要扫描的包名,可以不断添加。
  • openAPI.servers 访问接口的前缀,也就是 Web 项目名称。这里配置正确了才能让 try it out 测试发送 HTTP 请求。

附,我的配置:


	 
	OpenApi
	com.ajaxjs.cms.controller.ApiDocController

	
		openApi.configuration.resourcePackages
		
		com.ajaxjs.shop
	

	

	
	 openApi.configuration.location 
		/openapi.yaml 

	2
 


	OpenApi
	/admin/openapi/*
 


import io.swagger.v3.core.util.Json;
import io.swagger.v3.core.util.Yaml;
import io.swagger.v3.jaxrs2.integration.ServletOpenApiContextBuilder;
import io.swagger.v3.oas.integration.OpenApiConfigurationException;
import io.swagger.v3.oas.integration.OpenApiContextLocator;
import io.swagger.v3.oas.integration.api.OpenApiContext;
import io.swagger.v3.oas.models.OpenAPI;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

import static io.swagger.v3.jaxrs2.integration.ServletConfigContextUtils.getContextIdFromServletConfig;

public class ApiDocController extends HttpServlet {
	private static final long serialVersionUID = 5041371253005960693L;

	public static final String APPLICATION_JSON = "application/json";
	public static final String APPLICATION_YAML = "application/yaml";
	public static final String ACCEPT_HEADER = "Accept";

	@Override
	public void init(ServletConfig config) throws ServletException {
		super.init(config);
		String ctxId = getContextIdFromServletConfig(config);
		
		try {
			new ServletOpenApiContextBuilder<>().servletConfig(config).ctxId(ctxId).buildContext(true);
		} catch (OpenApiConfigurationException e) {
			e.printStackTrace();
		}
	}

	// TODO move to own servlet non jaxrs project and reference from there
	// TODO cleanup and errors
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		req.setCharacterEncoding("utf-8");
		resp.setCharacterEncoding("utf-8");

		String ctxId = getContextIdFromServletConfig(getServletConfig());
		OpenApiContext ctx = OpenApiContextLocator.getInstance().getOpenApiContext(ctxId);
		OpenAPI oas = ctx.read();

		String type = "json";

		String acceptHeader = req.getHeader(ACCEPT_HEADER);
		if (!StringUtils.isBlank(acceptHeader) && acceptHeader.toLowerCase().contains(APPLICATION_YAML)) {
			type = "yaml";
		} else {
			// check URL:
			if (req.getRequestURL().toString().toLowerCase().endsWith("yaml")) {
				type = "yaml";
			}
		}

		boolean pretty = false;
		if (ctx.getOpenApiConfiguration() != null && Boolean.TRUE.equals(ctx.getOpenApiConfiguration().isPrettyPrint())) {
			pretty = true;
		}

		resp.setStatus(200);

		try(PrintWriter pw = resp.getWriter();) {
			if (type.equalsIgnoreCase("yaml")) {
				resp.setContentType(APPLICATION_YAML);
				pw.write(pretty ? Yaml.pretty(oas) : Yaml.mapper().writeValueAsString(oas));
			} else {
				resp.setContentType(APPLICATION_JSON);
				pw.write(pretty ? Json.pretty(oas) : Json.mapper().writeValueAsString(oas));
			}
		}
	}
}

你可能感兴趣的:(Java,架构)