需求
后端接收前端传递的文件,封装到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<MultipartFile> multipartFiles) {
JSONObject result = MaterialFileService.uploadWithFileSystemResource(multipartFiles);
return result;
}
@ApiOperation(value = "图片或者文件等上传,使用字节流传输")
@PostMapping("/upload/byte")
public JSONObject uploadWithByteArrayResource(@RequestParam("file[]") List<MultipartFile> multipartFiles) {
JSONObject result = MaterialFileService.uploadWithByteArrayResource(multipartFiles);
return result;
}
}
- service
public interface MaterialFileService {
/**
* 使用文件进行http传输
*
* @param multipartFiles
* @return
*/
JSONObject uploadWithFileSystemResource(List<MultipartFile> multipartFiles);
/**
* 使用字节流进行http传输
*
* @param multipartFiles
* @return
*/
JSONObject uploadWithByteArrayResource(List<MultipartFile> 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<MultipartFile> multipartFiles) {
MultiValueMap<String, Object> request = new LinkedMultiValueMap<>();
// 设置请求头
HttpHeaders headers = new HttpHeaders();
// form-data方式提交
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
// 暂存文件目录地址
String url = "D:/tmp/file";
List<File> 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<MultiValueMap<String, Object>> 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<MultipartFile> multipartFiles) {
MultiValueMap<String, Object> 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<MultiValueMap<String, Object>> 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;
}
}