Java 如何使用 Spring 以编程方式使用来自 Rest API 的文件?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26613035/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 02:56:04  来源:igfitidea点击:

How to programmatically consume a file from a Rest API using Spring?

javaspringrest

提问by Sami

I have the following Rest resource which downloads a file from DB. It works fine from the browser, however, when I try to do it from a Java client as below, I get 406 (Not accepted error).

我有以下 Rest 资源,它从数据库下载文件。它在浏览器中运行良好,但是,当我尝试从 Java 客户端执行此操作时,如下所示,出现 406(未接受错误)。

...
 @RequestMapping(value="/download/{name}", method=RequestMethod.GET, 
        produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public @ResponseBody HttpEntity<byte[]> downloadActivityJar(@PathVariable String name) throws IOException
{
    logger.info("downloading : " + name + " ... ");
    byte[] file = IOUtils.toByteArray(artifactRepository.downloadJar(name));
    HttpHeaders header = new HttpHeaders();
    header.set("Content-Disposition", "attachment; filename="+ name + ".jar");
    header.setContentLength(file.length);

    return new HttpEntity<byte[]>(file, header);
}
...

The client is deployed on the same server with different port (message gives the correct name) :

客户端部署在具有不同端口的同一服务器上(消息给出了正确的名称):

    ...
    RestTemplate restTemplate = new RestTemplate();
    String url = "http://localhost:8080/activities/download/" + message.getActivity().getName();
    File jar = restTemplate.getForObject(url, File.class);
    logger.info("File size: " + jar.length() + " Name: " + jar.getName());
    ...

What am I missing here?

我在这里缺少什么?

采纳答案by GreyFairer

The response code is 406 Not Accepted. You need to specify an 'Accept' request header which must match the 'produces' field of your RequestMapping.

响应代码是 406 Not Accepted。您需要指定一个“Accept”请求标头,该标头必须与 RequestMapping 的“produces”字段匹配。

RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new ByteArrayHttpMessageConverter());    
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM));
HttpEntity<String> entity = new HttpEntity<String>(headers);

ResponseEntity<byte[]> response = restTemplate.exchange(URI, HttpMethod.GET, entity, byte[].class, "1");

if(response.getStatusCode().equals(HttpStatus.OK))
        {       
                FileOutputStream output = new FileOutputStream(new File("filename.jar"));
                IOUtils.write(response.getBody(), output);

        }

A small warning: don't do this for large files. RestTemplate.exchange(...) always loads the entire response into memory, so you could get OutOfMemory exceptions. To avoid this, do not use Spring RestTemplate, but rather use the Java standard HttpUrlConnection directly or apache http-components.

一个小警告:不要对大文件这样做。RestTemplate.exchange(...) 总是将整个响应加载到内存中,因此您可能会遇到 OutOfMemory 异常。为了避免这种情况,不要使用 Spring RestTemplate,而是直接使用 Java 标准 HttpUrlConnection 或 apache http-components。

回答by Triton Man

maybe try this, change your rest method as such:

也许试试这个,改变你的休息方法:

public javax.ws.rs.core.Response downloadActivityJar(@PathVariable String name) throws IOException {
    byte[] file = IOUtils.toByteArray(artifactRepository.downloadJar(name));
    return Response.status(200).entity(file).header("Content-Disposition", "attachment; filename=\"" + name + ".jar\"").build();
}

Also, use something like this to download the file, you are doing it wrong.

另外,使用这样的东西来下载文件,你做错了。

org.apache.commons.io.FileUtils.copyURLToFile(new URL("http://localhost:8080/activities/download/" + message.getActivity().getName()), new File("locationOfFile.jar"));

You need to tell it where to save the file, the REST API won't do that for you I don't think.

您需要告诉它保存文件的位置,我认为 REST API 不会为您做到这一点。

回答by Rafal G.

Try using the execute method on RestTemplate with ResponseExtractor and read the data from stream using extractor.

尝试使用 RestTemplate 上的 execute 方法和 ResponseExtractor 并使用提取器从流中读取数据。

回答by marknorkin

You may use InputStreamResource with ByteArrayInputStream.

您可以将 InputStreamResource 与 ByteArrayInputStream 一起使用。

@RestController
public class SomeController {
    public ResponseEntity<InputStreamResource> someResource() {
         byte[] byteArr = ...;
         return ResponseEntity.status(HttpStatus.OK).body(new InputStreamResource(new ByteArrayInputStream(byteArr)));
    }
}

回答by Rohit Ahuja

Use this for downloading an JPEG image using exchange. This works perfect.

使用它通过交换下载 JPEG 图像。这工作完美。

URI uri = new URI(packing_url.trim());

HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.IMAGE_JPEG));
HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);

// Send the request as GET
ResponseEntity<byte[]> result= template.exchange(uri, HttpMethod.GET, entity, byte[].class);

out.write(result.getBody());