美文网首页
Spring后台 RestTemplate post Multi

Spring后台 RestTemplate post Multi

作者: LAMYMAY | 来源:发表于2020-01-15 17:52 被阅读0次

原文:
resttemplate multipart post with InputStreamResource not working SPR-13571

方案一:需要将 MultipartFile 从控制器接收后存储在本地,然后通过FileSystemResource用RestTemplate发送。
缺点是:多次I/O,使用临时文件,临时文件需要清理


方案二:如github上的方案一样:
我不想将此文件的内容存储在本地(用 FileSystemResource 或 ByteArrayResource )
如果你只使用 ByteArrayResource 将会抛出异常,所以需要创建一个新类 MultipartFileResource 去继承 ByteArrayResource 后复写 Resource.getFilename()

使用 ByteArrayResource 问题集中在,
1节数组只能读取一次,
2 Spring RestTemplate 为了正确地写出多参数请求,用进行 FormHttpMessageConverter 自动配置RestTemplate;
如果部件从Resource继承,它将调用该Resource.getFilename()方法以获取文件名,请参见 getFilename()方法。
如果未找到文件名,则此部分将作为“常规”部分而不是文件写入消息的内容处置部分。


缺点:这种方式调用 multipartFile.getBytes()是一个好主意。 那是会将整个文件读入堆中,有可能遇到非常大的文件(或者并发处理的时候)时候OOM

代码:
client send file to aServer
than aServer deliver the received file to bServer.


import com.arc.core.model.vo.ResponseVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.*;
import org.springframework.stereotype.Controller;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * 转发MultipartFile 文件测试
 * aServer
 * bServer
 * client send file to aServer than deliver to bServer.
 *
 * @author May
 * @since 2020/1/15 16:48
 */
@Slf4j
@Controller
public class TransferMultipartFileController {


    //接受前段上传的文件数据 转发给 v1 处理
    @PostMapping("/server/a")
    @ResponseBody
    public ResponseVo prepareFileV0(MultipartFile file) throws IOException {
        long t1 = System.currentTimeMillis();

        // 1 body
        //方法一:重新实现 ByteArrayResource 并复写   @Override   public String getFilename() {
        ByteArrayResource resource = new MultipartFileResource(file);
        // 方法二:接受到文件流后先暂时持久化到本地临时文件夹,然后转发
        //FileSystemResource resource = new FileSystemResource(new File("文件本地磁盘路径"));
        MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
        body.add("file", resource);

        //2、 headers
        HttpHeaders headers = new HttpHeaders();

        //设置 接受的类型
        ArrayList<MediaType> acceptMediaTypes = new ArrayList<>();
        acceptMediaTypes.add(MediaType.APPLICATION_JSON);

        //2.1 设置header 等效 headers.add("Accept", APPLICATION_JSON.toString());
        headers.setAccept(acceptMediaTypes);

        //2.2 设置header 是表单提交 等效 headers.setContentType(MediaType.parseMediaType("multipart/form-data;charset=UTF-8"));
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);


        //3、构造请求体 body+header
        HttpEntity<Object> requestEntity = new HttpEntity<>(body, headers);

        //4、发送请求
        String url = "http://127.0.0.1:8001/zero/test/zip/upload/v1";
        ResponseEntity<Object> responseEntity = new RestTemplate().exchange(url, HttpMethod.POST, requestEntity, Object.class);

        //测试返回数据是什么  ResponseEntity
        log.debug("BIO cost time", System.currentTimeMillis() - t1);
        log.debug("结果={}", responseEntity);
        log.debug("getStatusCodeValue结果={}", responseEntity.getStatusCodeValue());
        log.debug("getBody结果={}", responseEntity.getBody());
        log.debug("getHeaders结果={}", responseEntity.getHeaders());
        return ResponseVo.success(true);
    }


    //========================  模拟 bServer

    //数据准备
    @PostMapping("/server/b")
    @ResponseBody
    public ResponseVo prepareFileForDownloadMultiFileInZip(HttpServletRequest request, MultipartFile file) {
        long t1 = System.currentTimeMillis();
        //1、上传文件,简单校验
        if (file == null || file.isEmpty()) {
            return ResponseVo.failure("file is null");
        }

        //2、文件持久化到磁盘
        String path = "T:\\data\\output\\" + file.getOriginalFilename();
        log.debug("文件所在路径={}" + path);
        boolean result = false;
        try {
            log.debug(" try");
            file.transferTo(new File(path));
            result = true;
        } catch (IOException e) {
            log.debug("执行到catch,{}", e);
        } finally {
            log.debug("执行到finally");
        }


        //3、响应一个返回数据--这里为了测试header 数据做了获取封装后返回了,(获取到请求头数据在响应回去)
        Map<Object, Object> map = new HashMap<>();
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String key = headerNames.nextElement();
            String value = request.getHeader(key);
            log.debug("请求头重的key/value={}/{}", key, value);
            map.put(key, value);
        }

        map.put(result, result);
        map.put("BIO cost time", System.currentTimeMillis() - t1);
        map.put("file size", file.getSize());
        map.put("file name", file.getName());
        map.put("file originalFilename", file.getOriginalFilename());
        map.put("file contentType", file.getContentType());

        return ResponseVo.success(map);
    }
}

import org.springframework.core.io.ByteArrayResource;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;

/**
 * 参考:
 * https://github.com/spring-projects/spring-framework/issues/18147
 *
 * @author May
 * @since 2020/1/15 15:32
 */
public class MultipartFileResource extends ByteArrayResource {

    private String filename;

    public MultipartFileResource(MultipartFile multipartFile) throws IOException {
        super(multipartFile.getBytes());
        this.filename = multipartFile.getOriginalFilename();
    }

    @Override
    public String getFilename() {
        return this.filename;
    }
}

相关文章

网友评论

      本文标题:Spring后台 RestTemplate post Multi

      本文链接:https://www.haomeiwen.com/subject/kjatzctx.html