当前位置: 首页 > 知识库问答 >
问题:

Spring restTemplate执行()POST大文件并获取响应

班安平
2023-03-14

这花了我很长时间才弄清楚,所以我想分享它。大多数信息来自SO,我想整合到这个地方。

我的要求是使用 RESTFul POST 上传文件,由于可能文件很大,我想流式传输文件。我显然希望能够阅读回复。

我计划使用泽西作为REST服务器,使用Spring的RestTemplate作为客户端(并用于测试)。

我面临的问题是流式传输POST并接收响应。我该怎么做?(反问句 - 我回答这个!

共有2个答案

景令秋
2023-03-14

我使用SpringBoot1.2.4.RELEASE与泽西被拉入:

compile("org.springframework.boot:spring-boot-starter-jersey")

我用出色的Spring Starter项目(Spring Tool Suite)创建了这个项目

compile('commons-io:commons-io:2.4')

我编写了这个服务器端代码。

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;

import org.me.fileStore.service.FileStoreService;

@RestController
@Path("/filestore")
public class FileStoreRestService {
    private static Logger logger = LoggerFactory.getLogger(FileStoreRestService.class);

    @Autowired
    private FileStoreService fileStoreService;


    @POST
    @Path("upload")
    @Consumes(MediaType.APPLICATION_OCTET_STREAM)
    @Produces(MediaType.APPLICATION_JSON)
    public Response Upload(InputStream stream) throws IOException, URISyntaxException { //
        String location = fileStoreService.upload(stream);  // relative path
        URI loc = new URI(location);
        Response response = Response.created(loc).build();
        System.out.println("POST - response: " + response + ", :" + response.getHeaders());
        return response;
    }

我遇到最多麻烦的地方是获得一个位置的响应。

首先,我必须处理流式处理大文件。我跟踪了https://stackoverflow.com/a/15785322/1019307正如你在下面的测试中看到的。根据该帖子,无论我使用HttpMessageConverterExtractor进行什么尝试,我都没有得到响应:

final HttpMessageConverterExtractor<String> responseExtractor =
new HttpMessageConverterExtractor<String>(String.class, restTemplate.getMessageConverters());

找到https://stackoverflow.com/a/6006147/1019307后,我写道:

private static class ResponseFromHeadersExtractor implements ResponseExtractor<ClientHttpResponse> {

    @Override
    public ClientHttpResponse extractData(ClientHttpResponse response) {
        System.out.println("StringFromHeadersExtractor - response headers: " + response.getHeaders());
        return response;
    }
}

这给了我这个测试:

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.test.IntegrationTest;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.boot.test.TestRestTemplate;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.web.client.RequestCallback;
import org.springframework.web.client.ResponseExtractor;
import org.springframework.web.client.RestTemplate;


@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = FileStoreApplication.class)
@WebAppConfiguration
@IntegrationTest("server.port:9000")
public class FileStoreRestServiceTest {
    private static Logger logger = LoggerFactory.getLogger(FileStoreRestServiceTest.class);
    protected final Log logger2 = LogFactory.getLog(getClass());

    String base = "http://localhost:9000/filestore";
    private RestTemplate restTemplate = new TestRestTemplate();

@Test
public void testMyMethodExecute() throws IOException {
    String content = "This is file contents\nWith another line.\n";
    Path theTestFilePath = TestingUtils.getTempPath(content);
    InputStream inputStream = Files.newInputStream(theTestFilePath);

    String url = base + "/upload";
    final RequestCallback requestCallback = new RequestCallback() {
        @Override
        public void doWithRequest(final ClientHttpRequest request) throws IOException {
            request.getHeaders().setContentType(MediaType.APPLICATION_OCTET_STREAM);
            IOUtils.copy(inputStream, request.getBody());
        }
    };
    final RestTemplate restTemplate = new RestTemplate();
    SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
    requestFactory.setBufferRequestBody(false);
    restTemplate.setRequestFactory(requestFactory);
    ClientHttpResponse response = restTemplate.execute(url, HttpMethod.POST, requestCallback,
            new ResponseFromHeadersExtractor());
    URI location = response.getHeaders().getLocation();
    System.out.println("Location: " + location);
    Assert.assertNotNull(location);
    Assert.assertNotEquals(0, location.getPath().length());

}

private static class ResponseFromHeadersExtractor implements ResponseExtractor<ClientHttpResponse> {

    @Override
    public ClientHttpResponse extractData(ClientHttpResponse response) {
        System.out.println("StringFromHeadersExtractor - response headers: " + response.getHeaders());
        return response;
    }
}

我需要将测试中的很多内容重构到一些服务中。

艾才良
2023-03-14

没有必要用RequestCallback来经历所有这些困难。只需使用PathResource

PathResource pathResource = new PathResource(theTestFilePath);
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(pathResource), String.class);

Spring将使用资源Http消息转换器来序列化由给定路径标识的文件到请求正文。在内部,Spring 4.x实现使用4096字节的缓冲区大小(这也是IOUtils#copy(..)使用的)。

显然,您可以提供您想要的响应类型。上面的示例期望响应正文为< code >字符串。使用< code>ResponseEntity,您可以使用

HttpHeaders responseHeaders = response.getHeaders();
 类似资料:
  • > 我正在尝试迭代文件夹中的文件。每个文件都有多个用换行符分隔的json字符串。一旦检索到json,就必须获取json的特定节点并将其发布到http服务器。 最初我想使用csv数据集配置,但我能够从文件中获得嵌套的json。在完成了一些jmeter的阅读教程之后,我终于使用JSR223创建了一个自定义脚本,该脚本读取文件并放入ctx,采样器将使用ctx发送数据。 以下是我到现在为止所做的。 nul

  • 问题内容: 为了下载文件,我正在创建一个urlopen对象(urllib2类)并分块读取它。 我想多次连接到服务器,并在六个不同的会话中下载文件。这样做,下载速度应该会更快。许多下载管理器都具有此功能。 我考虑过在每次会话中指定要下载的文件部分,并以某种方式在同一时间处理所有会话。我不确定如何实现这一目标。 问题答案: 听起来您想使用可用的HTTP Range 风格之一。 编辑 更新的链接以指向w

  • 问题内容: 我有一个大文件,需要阅读并制作字典。我希望尽快。但是我在python中的代码太慢了。这是显示问题的最小示例。 首先制作一些假数据 现在,这里是一个最小的python代码片段,可以读入它并制作一个字典。 时间: 但是,可以更快地读取整个文件,如下所示: 我的CPU有8个核心,是否可以在python中并行化此程序以加快速度? 一种可能是读取大块输入,然后在不同的非重叠子块上并行运行8个进程

  • 另外,附带问题-如果我更喜欢使用Alamofire,我是否也需要使用swiftyJSON?还是只是为了解析?

  • 问题内容: 我的删除页面代码(delete.php) 虽然我的deleteAtc.php代码是: 我在这里想要做的是删除记录而不重定向到,它将删除记录并替换 我可以知道我在ajax方面出了什么问题吗? 请参考下面的更新问题 根据以下答案,这是我的更新代码: delete.php 脚本 deleteAtc.php 以某种方式,如果我一次删除两个记录,则只有第一个记录会回显结果,而删除的第二个结果不会

  • 问题内容: 我有一个简单的jQuery AJAX POST代码: 我希望获取cookie并使用cookies-js保存。 但是根据http://www.w3.org/TR/XMLHttpRequest/#the- getallresponseheaders%28%29-method : 将所有响应标头( 不包括与Set-Cookie或Set-Cookie2不区分大小写的标头) 作为单个字符串返回,