项目服务有时候需要接收前端传来的文件再转给第三方接口,在这过程中能在本地接口做身份验证、参数调整等工作,也让前端用户的文件有机会发给只有专用网络才能访问到的服务。
要点
1、接收与保存本地文件
接收后保存在本地的操作,会给每个文件都创建一个不重复的目录,保证并发或重名时不被占用和覆盖。文件复制可以用MultipartFile的 transferTo(File) 方法来做。
2、用HttpClient发送form-data格式的带文件请求。
这里用到的包是org.apache.commons.httpclient系列,请求实体用MultipartRequestEntity对象,其中的字符串型数据用StringPart, 文件用FilePart。
需要注意的是,为了保证传输中文名的文件在接收端那边字符正确,需要重写PostMethod的getRequestCharSet方法以及FilePart的sendDispositionHeader方法,
实现
先用postman工具测试最终需要接收文件的接口,以form-data的格式发送带文件与其他参数的post请求,确认最终接口能正常接收文件与响应。
下面提供springboot接收前端文件数据,并以form-data形式发给第三方接口的示例。
@ResponseBody
@RequestMapping(value="/fileForward", produces="application/json;charset=UTF-8")
public String fileForward(MultipartFile file, String resourceType, HttpServletRequest request) {
String tmpFileDir = null;
String fileName = null;
File dirFile = null;
File localFile = null;
try {
log.info("资源类型: : " + resourceType);
//制作每个文件特有的目录,保证并发或重名时不出问题
String randomFileName = UUID.randomUUID().toString();
tmpFileDir = "D:/tmp/tmpFile/"+randomFileName;
dirFile = new File(tmpFileDir);
if(!dirFile.exists()) {
dirFile.mkdirs();
}
//MultipartFile转成File对象
fileName = tmpFileDir+"/"+file.getOriginalFilename();
localFile = new File(fileName);
file.transferTo(localFile);
HttpClient client = new HttpClient();
//文件传输可能受带宽影响导致时间太长,慎用。
// client.getHttpConnectionManager().getParams().setConnectionTimeout(3000);
// client.getHttpConnectionManager().getParams().setSoTimeout(3000);
//转发的地址,可以根据需要从配置文件中读
String url = "http://127.0.0.1:9006/upload/resource/upload";
//覆盖PostMethod的getRequestCharSet,返回为UTF-8
PostMethod postMethod=new PostMethod(url) {
public String getRequestCharSet() {
return "UTF-8";
}
};
//请求参数里的文件
FilePart fp = new FilePart("file", localFile) {
protected void sendDispositionHeader(OutputStream out) throws IOException {
//实现父类super.sendDispositionHeader(out)的逻辑
out.write(CONTENT_DISPOSITION_BYTES);
out.write(QUOTE_BYTES);
out.write(EncodingUtil.getBytes(getName(),"utf-8"));
out.write(QUOTE_BYTES);
String fileName = getSource().getFileName();
// 解决中文文件名乱码
if (!StringUtils.isEmpty(fileName)){
out.write(EncodingUtil.getAsciiBytes(FILE_NAME));
out.write(QUOTE_BYTES);
out.write(EncodingUtil.getBytes(fileName,"utf-8"));
out.write(QUOTE_BYTES);
}
}
};
//请求参数数组
Part[] parts = {new StringPart("resourceType", resourceType), fp};
RequestEntity requestEntity = new MultipartRequestEntity(parts, postMethod.getParams());
postMethod.setRequestEntity(requestEntity);
int resultCode = client.executeMethod(postMethod);
if(resultCode == 200){
log.info("第三方接口返回: " + postMethod.getResponseBodyAsString());
return postMethod.getResponseBodyAsString();
}else{
return "发送第三方接口出错:" + postMethod.getResponseBodyAsString();
}
} catch (Exception e) {
log.error("文件转发出错:" + e.getMessage(), e);
return "文件转发出错:" + e.getMessage();
} finally {
//根据需要处理存在本地的文件,如压缩、删除等
}
}
写完用postman工具请求
检查自己后台的日志:
能看到自己的服务成功接收请求,后台请求最终接口也获得了成功的响应。