Spring中如何通过form-data传输多文件数据

需求

后端接收前端传递的文件,封装到form-data中然后发起https请求调用第三方接口进行上传.

Input

请求方式:POST(JSON)form-data

参数名称 类型 描述
file[] form-data 上传的文件,可以选择多个

Ouput

{
    "ret": 0,
    "msg": "OK",
    "errorcode": 0,
    "data": []
}

技术方案

使用Spring的RestTemplate传输文件,需要使用到AbstractResource的子类,而不能通过File这种形式进行传输

  • FileSystemResource

它需要传递一个文件。得到是文件源是一个MultipartFile(继承自InputStreamSource),需要在本地创建一个临时文件,然后把InputStream写入到文件中去。使用完之后,还需要把文件删除。

  • ByteArrayResource

通过字节流的方式传输,无需创建临时文件,需要重写getFilename()

  • InputStreamResource
    本文没有用到这种形式传输,有兴趣的朋友可以参考 InputStreamResource

Code

  • web
@RestController
@RequestMapping("/material/file")
public class MaterialFileController {

    @Autowired
    private MaterialFileService MaterialFileService;

    @ApiOperation(value = "图片或者文件等上传,使用文件传输")
    @PostMapping("/upload/file")
    public JSONObject uploadWithFileSystemResource(@RequestParam("file[]") List multipartFiles) {
        JSONObject result = MaterialFileService.uploadWithFileSystemResource(multipartFiles);
        return result;
    }

    @ApiOperation(value = "图片或者文件等上传,使用字节流传输")
    @PostMapping("/upload/byte")
    public JSONObject uploadWithByteArrayResource(@RequestParam("file[]") List multipartFiles) {
        JSONObject result = MaterialFileService.uploadWithByteArrayResource(multipartFiles);
        return result;
    }

}
  • service
public interface MaterialFileService {
    /**
     * 使用文件进行http传输
     *
     * @param multipartFiles
     * @return
     */
    JSONObject uploadWithFileSystemResource(List multipartFiles);

    /**
     * 使用字节流进行http传输
     *
     * @param multipartFiles
     * @return
     */
    JSONObject uploadWithByteArrayResource(List multipartFiles);
}
  • serviceImpl
@Service
@Slf4j
public class MaterialFileServiceImpl implements MaterialFileService {

    // 这里写要上传的域名
    private final static String GW_DOMAIN = "www.test.com";

    @Resource(name = "MyRestTemplate")
    private RestTemplate restTemplate;

    @Override
    public JSONObject uploadWithFileSystemResource(List multipartFiles) {
        MultiValueMap request = new LinkedMultiValueMap<>();
        // 设置请求头
        HttpHeaders headers = new HttpHeaders();
        // form-data方式提交
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        // 暂存文件目录地址
        String url = "D:/tmp/file";
        List files = new ArrayList<>(multipartFiles.size());
        multipartFiles.forEach(multipartFile -> {
            File localFile = new File(url, "/" + multipartFile.getOriginalFilename());
            try {
                multipartFile.transferTo(localFile);
            } catch (IOException e) {
                log.error("文件暂存本地异常,error:{}", e);
                throw new RestException("文件暂存本地异常,error:{}", e);
            }
            files.add(localFile);
            request.add("file[]", new FileSystemResource(localFile));
        });
        // 用HttpEntity封装整个请求报文
        HttpEntity> httpEntity = new HttpEntity<>(request, headers);
        JSONObject resultJson = restTemplate.postForObject(GW_DOMAIN + "/content/upload", httpEntity, JSONObject.class);
        // 删除临时文件
        files.stream().filter(File::exists).forEach(File::delete);
        return resultJson;
    }

    @Override
    public JSONObject uploadWithByteArrayResource(List multipartFiles) {
        MultiValueMap request = new LinkedMultiValueMap<>();
        // 设置请求头
        HttpHeaders headers = new HttpHeaders();
        // form-data方式提交
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        multipartFiles.forEach(multipartFile -> {
            try {
                byte[] bytes = multipartFile.getBytes();
                // 将字节数组转成 ByteArrayResource
                ByteArrayResource byteArrayResource = new ByteArrayResource(bytes) {
                    @Override
                    public String getFilename() {
                        return multipartFile.getOriginalFilename();
                    }
                };
                request.add("file[]", byteArrayResource);
            } catch (IOException e) {
                log.error("解析成字节流异常,error:{}", e);
                throw new RestException("解析成字节流异常,error:{}", e);
            }
        });
        // 用HttpEntity封装请求报文
        HttpEntity> httpEntity = new HttpEntity<>(request, headers);
        JSONObject resultJson = restTemplate.postForObject(GW_DOMAIN + "/content/upload", httpEntity, JSONObject.class);
        return resultJson;
    }
}
  • RestTemplateConfig
@Configuration
public class RestTemplateConfig {
    @Bean("MyRestTemplate")
    public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
        return new RestTemplate(factory);
    }

    @Bean
    public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        // 读取超时
        factory.setReadTimeout(5000);
        // 连接超时
        factory.setConnectTimeout(15000);
        return factory;
    }
}

你可能感兴趣的:(Spring中如何通过form-data传输多文件数据)