pow*_*ilk 6 gson kotlin swagger-ui spring-boot openapi
我从 Springfox Swagger 迁移到 Springdoc OpenApi。我在有关 springdoc 的配置中添加了几行:
springdoc:
  pathsToMatch: /api/**
  api-docs:
    path: /api-docs
  swagger-ui:
    path: /swagger-ui.html
Run Code Online (Sandbox Code Playgroud)
在配置类中MainConfig.kt我有以下代码:
val customGson: Gson = GsonBuilder()
        .registerTypeAdapter(LocalDateTime::class.java, DateSerializer())
        .registerTypeAdapter(ZonedDateTime::class.java, ZonedDateSerializer())
        .addSerializationExclusionStrategy(AnnotationExclusionStrategy())
        .enableComplexMapKeySerialization()
        .setPrettyPrinting()
        .create()
    override fun configureMessageConverters(converters: MutableList<HttpMessageConverter<*>>) {
        converters.add(GsonHttpMessageConverter(customGson))
    }
Run Code Online (Sandbox Code Playgroud)
当我访问 http://localhost:8013/swagger-ui.html (在我的配置中server.port: 8013)时,页面不会重定向到swagger-ui/index.html?url=/api-docs&validatorUrl=. 但这不是我的主要问题:)。当我访问时,swagger-ui/index.html?url=/api-docs&validatorUrl=我得到了包含以下信息的页面:
无法呈现此定义 提供的定义未指定有效的版本字段。 请指明有效的 Swagger 或 OpenAPI 版本字段。支持的版本字段包括 swagger: "2.0" 和那些匹配 openapi: 3.0.n 的字段(例如 openapi: 3.0.0)。
但是当我访问 http://localhost:8013/api-docs 时,我得到了这个结果:
"{\"openapi\":\"3.0.1\",\"info\":{(...)}}"
Run Code Online (Sandbox Code Playgroud)
我尝试使用默认配置,并评论了configureMessageConverters()方法,结果\api-docs现在看起来像正常的 JSON:
Unable to render this definition The provided definition does not specify a valid version field. Please indicate a valid Swagger or OpenAPI version field. Supported version fields are swagger: "2.0" and those that match openapi: 3.0.n (for example, openapi: 3.0.0).
我记得当我使用 Springfox 时,序列化出现问题,并且我customGson有附加行:.registerTypeAdapter(Json::class.java, JsonSerializer<Json> { src, _, _ -> JsonParser.parseString(src.value()) })
我想知道我应该有特别的JsonSerializer。调试后,我的第一个想法是导致包OpenApi中的类io.swagger.v3.oas.models。我添加了这段代码:.registerTypeAdapter(OpenAPI::class.java, JsonSerializer<OpenAPI> { _, _, _ -> JsonParser.parseString("") })并且customGson没有任何改变...所以,我正在深入挖掘...
当我运行 Swagger 测试后:
"{\"openapi\":\"3.0.1\",\"info\":{(...)}}"
Run Code Online (Sandbox Code Playgroud)
我在控制台看到了这个:
MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /api-docs
       Parameters = {}
          Headers = []
             Body = null
    Session Attrs = {}
Handler:
             Type = org.springdoc.api.OpenApiResource
           Method = org.springdoc.api.OpenApiResource#openapiJson(HttpServletRequest, String)
Run Code Online (Sandbox Code Playgroud)
接下来我登记openapiJson入住OpenApiResource并...
// 20191218134933
// http://localhost:8013/api-docs
{
  "openapi": "3.0.1",
  "info": {(...)}
}
Run Code Online (Sandbox Code Playgroud)
好吧,杰克逊...我已经禁用了杰克逊,@EnableAutoConfiguration(exclude = [(JacksonAutoConfiguration::class)])因为我(和我的同事)更喜欢 GSON,但这并不能解释为什么添加自定义后序列化会出错GsonHttpMessageConverter。我不知道我做了什么坏事。这openapiJson()是终点,也许它会弄乱一些东西......我不知道。我不知道。您有类似的问题吗?你能给一些建议或提示吗?
附言。对不起,我的英语不好 :)。
小智 2
我在用 Java 编写的项目中遇到了同样的问题,我刚刚通过定义一个过滤器来使用 Gson 格式化我的 springdoc-openapi json 文档来解决这个问题。我想您可以轻松地将这个解决方法移植到 Kotlin。
@Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
        throws IOException, ServletException {
    ByteResponseWrapper byteResponseWrapper = new ByteResponseWrapper((HttpServletResponse) response);
    ByteRequestWrapper byteRequestWrapper = new ByteRequestWrapper((HttpServletRequest) request);
    chain.doFilter(byteRequestWrapper, byteResponseWrapper);
    String jsonResponse = new String(byteResponseWrapper.getBytes(), response.getCharacterEncoding());
    response.getOutputStream().write((new com.google.gson.JsonParser().parse(jsonResponse).getAsString())
            .getBytes(response.getCharacterEncoding()));
}
@Override
public void destroy() {
}
static class ByteResponseWrapper extends HttpServletResponseWrapper {
    private PrintWriter writer;
    private ByteOutputStream output;
    public byte[] getBytes() {
        writer.flush();
        return output.getBytes();
    }
    public ByteResponseWrapper(HttpServletResponse response) {
        super(response);
        output = new ByteOutputStream();
        writer = new PrintWriter(output);
    }
    @Override
    public PrintWriter getWriter() {
        return writer;
    }
    @Override
    public ServletOutputStream getOutputStream() {
        return output;
    }
}
static class ByteRequestWrapper extends HttpServletRequestWrapper {
    byte[] requestBytes = null;
    private ByteInputStream byteInputStream;
    public ByteRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        InputStream inputStream = request.getInputStream();
        byte[] buffer = new byte[4096];
        int read = 0;
        while ((read = inputStream.read(buffer)) != -1) {
            baos.write(buffer, 0, read);
        }
        replaceRequestPayload(baos.toByteArray());
    }
    @Override
    public BufferedReader getReader() {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }
    @Override
    public ServletInputStream getInputStream() {
        return byteInputStream;
    }
    public void replaceRequestPayload(byte[] newPayload) {
        requestBytes = newPayload;
        byteInputStream = new ByteInputStream(new ByteArrayInputStream(requestBytes));
    }
}
static class ByteOutputStream extends ServletOutputStream {
    private ByteArrayOutputStream bos = new ByteArrayOutputStream();
    @Override
    public void write(int b) {
        bos.write(b);
    }
    public byte[] getBytes() {
        return bos.toByteArray();
    }
    @Override
    public boolean isReady() {
        return false;
    }
    @Override
    public void setWriteListener(WriteListener writeListener) {
    }
}
static class ByteInputStream extends ServletInputStream {
    private InputStream inputStream;
    public ByteInputStream(final InputStream inputStream) {
        this.inputStream = inputStream;
    }
    @Override
    public int read() throws IOException {
        return inputStream.read();
    }
    @Override
    public boolean isFinished() {
        return false;
    }
    @Override
    public boolean isReady() {
        return false;
    }
    @Override
    public void setReadListener(ReadListener readListener) {
    }
}
Run Code Online (Sandbox Code Playgroud)
您还必须仅为您的文档 url 模式注册过滤器。
@Bean
public FilterRegistrationBean<DocsFormatterFilter> loggingFilter() {
    FilterRegistrationBean<DocsFormatterFilter> registrationBean = new FilterRegistrationBean<>();
    registrationBean.setFilter(new DocsFormatterFilter());
    registrationBean.addUrlPatterns("/v3/api-docs");
    return registrationBean;
}
Run Code Online (Sandbox Code Playgroud)
        |   归档时间:  |  
           
  |  
        
|   查看次数:  |  
           6811 次  |  
        
|   最近记录:  |