简体   繁体   English

如何处理Swagger Codegen的org.springframework.core.io.Resource

[英]How to handle org.springframework.core.io.Resource for Swagger Codegen

I am developing a web application using Spring Boot 2, which have 2 Spring projects working together: one is the REST API server serving the application logic via REST APIs, the other is the web project responsible for rendering web pages and calling the API server. 我正在使用Spring Boot 2开发一个Web应用程序,它有两个Spring项目协同工作:一个是通过REST API为应用程序逻辑提供服务的REST API服务器,另一个是负责呈现网页和调用API服务器的Web项目。 The web project uses Swagger Codegen to auto generate classes for calling the APIs. Web项目使用Swagger Codegen自动生成用于调用API的类。

In the API server, I have a controller ResourceController with an endpoint for serving a file content (ie download a file), as follows 在API服务器中,我有一个控制器ResourceController ,其端点用于提供文件内容(即下载文件),如下所示

@GetMapping("/files/{uuid}")
@ResponseBody
public org.springframework.core.io.Resource getFile(@PathVariable String uuid) {
    String systemPath = fileService.getFilePath(uuid);
    return new FileSystemResource(systemPath);
}

At the web client, Swagger generate ResourceControllerApi with the method translated to 在Web客户端,Swagger使用转换为的方法生成ResourceControllerApi

public io.swagger.client.model.Resource getFileUsingGET(String uuid) {...}

I want to create a controller at the web project that pass through the request and response between the user's browser to the API server. 我想在Web项目中创建一个控制器,该控制器通过用户浏览器和API服务器之间的请求和响应。 I tried 我试过了

@GetMapping("/client/files/{uuid}")
@ResponseBody
public io.swagger.client.model.Resource getFile(@PathVariable String uuid) {
    return resourceControllerApi.getFileUsingGET(uuid);
}

When calling the API (at client web), I got this error 在调用API时(在客户端Web上),我收到此错误

org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class io.swagger.client.model.Resource] and content type [image/jpeg]

I expect that when I put the url like http://myweb/client/files/dee38be4-6ef9-460d-bc44-f1b93770ab83 , the browser download the file content. 我希望当我把网址如http://myweb/client/files/dee38be4-6ef9-460d-bc44-f1b93770ab83 ,浏览器下载文件内容。 I have been looking a way to converting io.swagger.client.model.Resource to org.springframework.core.io.Resource but could not figure out. 我一直在寻找一种方法将io.swagger.client.model.Resource转换为org.springframework.core.io.Resource但无法弄清楚。

Following is the content of the auto generated io.swagger.client.model.Resource 以下是自动生成的io.swagger.client.model.Resource的内容

/*
 * NPA Marketplace REST API
 * API to manage NPA Marketplace.
 *
 * OpenAPI spec version: 1.0
 * 
 *
 * NOTE: This class is auto generated by the swagger code generator program.
 * https://github.com/swagger-api/swagger-codegen.git
 * Do not edit the class manually.
 */


package io.swagger.client.model;

import java.util.Objects;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.client.model.InputStream;
import io.swagger.client.model.URI;
import io.swagger.client.model.URL;

/**
 * Resource
 */
@javax.annotation.Generated(value = "io.swagger.codegen.languages.JavaClientCodegen", date = "2018-03-08T14:55:08.754+07:00")
public class Resource {
  @JsonProperty("description")
  private String description = null;

  @JsonProperty("file")
  private java.io.File file = null;

  @JsonProperty("filename")
  private String filename = null;

  @JsonProperty("inputStream")
  private InputStream inputStream = null;

  @JsonProperty("open")
  private Boolean open = null;

  @JsonProperty("readable")
  private Boolean readable = null;

  @JsonProperty("uri")
  private URI uri = null;

  @JsonProperty("url")
  private URL url = null;

  public Resource description(String description) {
    this.description = description;
    return this;
  }

   /**
   * Get description
   * @return description
  **/
  @ApiModelProperty(value = "")
  public String getDescription() {
    return description;
  }

  public void setDescription(String description) {
    this.description = description;
  }

  public Resource file(java.io.File file) {
    this.file = file;
    return this;
  }

   /**
   * Get file
   * @return file
  **/
  @ApiModelProperty(value = "")
  public java.io.File getFile() {
    return file;
  }

  public void setFile(java.io.File file) {
    this.file = file;
  }

  public Resource filename(String filename) {
    this.filename = filename;
    return this;
  }

   /**
   * Get filename
   * @return filename
  **/
  @ApiModelProperty(value = "")
  public String getFilename() {
    return filename;
  }

  public void setFilename(String filename) {
    this.filename = filename;
  }

  public Resource inputStream(InputStream inputStream) {
    this.inputStream = inputStream;
    return this;
  }

   /**
   * Get inputStream
   * @return inputStream
  **/
  @ApiModelProperty(value = "")
  public InputStream getInputStream() {
    return inputStream;
  }

  public void setInputStream(InputStream inputStream) {
    this.inputStream = inputStream;
  }

  public Resource open(Boolean open) {
    this.open = open;
    return this;
  }

   /**
   * Get open
   * @return open
  **/
  @ApiModelProperty(value = "")
  public Boolean isOpen() {
    return open;
  }

  public void setOpen(Boolean open) {
    this.open = open;
  }

  public Resource readable(Boolean readable) {
    this.readable = readable;
    return this;
  }

   /**
   * Get readable
   * @return readable
  **/
  @ApiModelProperty(value = "")
  public Boolean isReadable() {
    return readable;
  }

  public void setReadable(Boolean readable) {
    this.readable = readable;
  }

  public Resource uri(URI uri) {
    this.uri = uri;
    return this;
  }

   /**
   * Get uri
   * @return uri
  **/
  @ApiModelProperty(value = "")
  public URI getUri() {
    return uri;
  }

  public void setUri(URI uri) {
    this.uri = uri;
  }

  public Resource url(URL url) {
    this.url = url;
    return this;
  }

   /**
   * Get url
   * @return url
  **/
  @ApiModelProperty(value = "")
  public URL getUrl() {
    return url;
  }

  public void setUrl(URL url) {
    this.url = url;
  }


  @Override
  public boolean equals(java.lang.Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }
    Resource resource = (Resource) o;
    return Objects.equals(this.description, resource.description) &&
        Objects.equals(this.file, resource.file) &&
        Objects.equals(this.filename, resource.filename) &&
        Objects.equals(this.inputStream, resource.inputStream) &&
        Objects.equals(this.open, resource.open) &&
        Objects.equals(this.readable, resource.readable) &&
        Objects.equals(this.uri, resource.uri) &&
        Objects.equals(this.url, resource.url);
  }

  @Override
  public int hashCode() {
    return Objects.hash(description, file, filename, inputStream, open, readable, uri, url);
  }


  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append("class Resource {\n");

    sb.append("    description: ").append(toIndentedString(description)).append("\n");
    sb.append("    file: ").append(toIndentedString(file)).append("\n");
    sb.append("    filename: ").append(toIndentedString(filename)).append("\n");
    sb.append("    inputStream: ").append(toIndentedString(inputStream)).append("\n");
    sb.append("    open: ").append(toIndentedString(open)).append("\n");
    sb.append("    readable: ").append(toIndentedString(readable)).append("\n");
    sb.append("    uri: ").append(toIndentedString(uri)).append("\n");
    sb.append("    url: ").append(toIndentedString(url)).append("\n");
    sb.append("}");
    return sb.toString();
  }

  /**
   * Convert the given object to string with each line indented by 4 spaces
   * (except the first line).
   */
  private String toIndentedString(java.lang.Object o) {
    if (o == null) {
      return "null";
    }
    return o.toString().replace("\n", "\n    ");
  }

}

The error 错误

org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class io.swagger.client.model.Resource] and content type [image/jpeg] 

was emitted from the line 是从线上发出的

ResponseEntity<T> responseEntity = restTemplate.exchange(requestEntity, returnType);

in the class io.swagger.client.ApiClient which is auto-generated by Swagger Codegen of variant library resttemplate , ie equivalent to running command java -jar swagger-codegen-cli.jar generate -i api-specs.json -l java --library resttemplate 在类io.swagger.client.ApiClient ,它由变量库resttemplate的Swagger Codegen自动生成,即相当于运行命令java -jar swagger-codegen-cli.jar generate -i api-specs.json -l java --library resttemplate

The error indicates that the resttemplate does not know how to convert the response data to io.swagger.client.model.Resource and hint us to create the suitable HttpMessageConverter . 该错误表明resttemplate不知道如何将响应数据转换为io.swagger.client.model.Resource并提示我们创建合适的HttpMessageConverter This is a tutorial for creating a HttpMessageConverters and register them with the resttemplate . 这是一个用于创建HttpMessageConverters并使用resttemplate注册它们的教程

In my case, however, the HttpMessageConverter cannot be a solution because the generated io.swagger.client.model.Resource has no property to keep the file data from the API's response. 但是,在我的情况下, HttpMessageConverter不能成为解决方案,因为生成的io.swagger.client.model.Resource没有属性来保存API响应中的文件数据。 It seems Swagger Codegen misunderstands that the controller at the API server would return a JSON representation of org.springframework.core.io.Resource and thus generating the counter part io.swagger.client.model.Resource for receiving the JSON data at the client, but the API server actually responds with a stream of file data, not a JSON. 似乎Swagger Codegen误解了API服务器上的控制器将返回org.springframework.core.io.Resource的JSON表示,从而生成计数器部分io.swagger.client.model.Resource用于在客户端接收JSON数据,但API服务器实际上使用文件数据流而不是JSON进行响应。

I don't know if this can be a bug for Swagger Codegen or I have done it wrong some how. 我不知道这是否可能是Swagger Codegen的错误,或者我做错了一些如何。

Nevertheless, I decide to give up using org.springframework.core.io.Resource at the API server. 不过,我决定放弃在API服务器上使用org.springframework.core.io.Resource Instead, I change the return type of the controller to ResponseEntity<byte[]> and manually configure the response header to have the correct content type and file name, as follows 相反,我将控制器的返回类型更改为ResponseEntity<byte[]>并手动配置响应头以具有正确的内容类型和文件名,如下所示

ResourceController (API Server) ResourceController(API服务器)

@GetMapping("/files/{uuid}")
@ResponseBody
public ResponseEntity<byte[]> getFile(@PathVariable String uuid) {
    FileMetadata myFileData = fileService.getFileMetadata(uuid);
    org.springframework.core.io.Resource res = new FileSystemResource(myFileData.getPaht());
    byte[] data = IOUtils.toByteArray(res.getInputStream());
    HttpHeaders respHeaders = new HttpHeaders();
    respHeaders.setContentType(MediaType.valueOf(myFileData.getContentType()));
    respHeaders.setContentLength(res.getFile().length());
    respHeaders.setContentDispositionFormData("attachment", myFileData.getName());
    return new ResponseEntity<>(data ,respHeaders, HttpStatus.OK);
}

At the web client, I then convert the byte[] data received from the API server to org.springframework.core.io.Resource , passing through the response header from the API server. 在Web客户端,然后我将从API服务器接收的byte[]数据转换为org.springframework.core.io.Resource ,并从API服务器传递响应头。

A controller at web client server Web客户端服务器上的控制器

@GetMapping("/client/files/{uuid}")
@ResponseBody
public ResponseEntity<org.springframework.core.io.Resource> getFile(@PathVariable String uuid) {
    byte[] data = resourceControllerApi.getFileUsingGET(uuid);
    HttpHeaders responseHeader = (HttpHeaders) RequestContextHolder.getRequestAttributes().getAttribute("responseHeader", RequestAttributes.SCOPE_REQUEST);
    return new ResponseEntity<>(new ByteArrayResource(data), responseHeader, HttpStatus.OK);
}

About the way I use to retrieve the response header, since I have no way to get the response header from the generated api class, I have to created a ClientHttpRequestInterceptor to get the header and put it as a request attribute. 关于我用来检索响应头的方式,因为我无法从生成的api类中获取响应头,所以我必须创建一个ClientHttpRequestInterceptor来获取头并将其作为请求属性。

public class ResponseHeaderClientRequestInterceptor implements ClientHttpRequestInterceptor {
    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        ClientHttpResponse response = execution.execute(request, body);
        HttpHeaders responseHeader = response.getHeaders();
        RequestAttributes requestAttrs = RequestContextHolder.getRequestAttributes();
        if (requestAttrs != null) {
            requestAttrs.setAttribute("responseHeader", responseHeader, RequestAttributes.SCOPE_REQUEST);
        }
        return response;
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何记录将返回ResponseEntity的表格规范 <Resource> 其中Resource是org.springframework.core.io.Resource - How to document swagger specification which returns ResponseEntity<Resource> where Resource is org.springframework.core.io.Resource 如何模拟 org.springframework.core.io.Resource object? - How to mock org.springframework.core.io.Resource object? java.lang.ClassNotFoundException: org.springframework.core.io.Resource - java.lang.ClassNotFoundException: org.springframework.core.io.Resource 为 org.springframework.core.io.Resource 对象分配名称 - Assigning name to a org.springframework.core.io.Resource object org.springframework.web.multipart.MultipartFile 和 org.springframework.core.io.Resource 之间的转换 - Conversion between org.springframework.web.multipart.MultipartFile and org.springframework.core.io.Resource 为什么JasperReports尝试加载org.springframework.core.io.Resource类? - Why does JasperReports try to load org.springframework.core.io.Resource class? ClassNotFoundException:IntelliJ IDEA在tomcat7上部署Maven Spring MVC Web项目时出现org.springframework.core.io.Resource - ClassNotFoundException: org.springframework.core.io.Resource when intellij idea deploy maven spring mvc web project on tomcat7 Spring MVC“找不到能够将java.lang.String类型转换为org.springframework.core.io.Resource类型的转换器” - Spring MVC “No converter found capable of converting from type java.lang.String to type org.springframework.core.io.Resource” java.lang.NoClassDefFoundError: org/springframework/core/io/Resource 异常 - java.lang.NoClassDefFoundError: org/springframework/core/io/Resource Exception spring org.springframework.core.io.UrlResource不支持https资源 - spring org.springframework.core.io.UrlResource not support https resource
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM