IDEA-2018.3
org.springframework.boot
spring-boot-starter-web
commons-io
commons-io
2.8.0
compile
都为本机地址 localhost
调用服务端(客户端)发送一个文件(示例为 11.jpg图片文件)和一个字符串普通参数 给 提供服务的被调用端(服务端); 之后 提供服务的被调用端(服务端) 再返回一个文件和字符串普通参数给 调用服务端(客户端)。 具体如下所示:
/**
* 用于在HTTP传输时,同时传输文件和相应参数的自定义类
*/
public class MagicFile {
public String fileName = null;
public byte[] fileBytesArray = null;
public MagicFile(){}
public MagicFile(String fileName, byte[] fileBytesArray){
this.fileName = fileName;
this.fileBytesArray = fileBytesArray;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public byte[] getFileBytesArray() {
return fileBytesArray;
}
public void setFileBytesArray(byte[] fileBytesArray) {
this.fileBytesArray = fileBytesArray;
}
}
① 将准备发送的文件 使用 FileUtils工具 转换成字节数组,再包装成字节数组资源(ByteArrayResource) ----文件参数已准备好
② 准备需要发生的String型参数 ---- 字符串普通参数已准备好
③ 通过 MultiValueMap 映射类型将 文件参数和字符串普通参数再次封装 ---- 整体参数已准备好
④ 调用restTemplate的postForEntity方法,将准备好的整体多值参数(MultiValueMap)作postForEntity方法的数据参数 发送给 被调用端,同时期待返回自定义的MagicFile类(其中封装了文件字节数组和普通的字符串参数)
① 被调用端借助@RequestParam注解,按键名取值的方式把字节数组形式的文件和普通参数获取到
② 使用MultipartFile类来作接收文件的类型
③ 使用String类来作接收字符串数组的类型 ---- 字符串参数获取已完成
④ 将MultipartFile类的文件转换为字节数组形式
⑤ 将字节数组形式的文件 通过 FileUtils工具 转换为 File文件 ---- 文件参数获取已完成
① 将待返回的文件使用 FileUtils工具 转换为 字节数组 ---- 文件参数已准备好
② 设置待返回的字符串参数 ---- 字符串普通参数已准备好
③ 借助 自定义的MagicFile类 封装 字节数组形式的文件和字符串参数 ---- 整体参数已准备好
④ 使用 ResponseEntity< MagicFile > ,将 整体参数放入 ResponseEntity的 body 后返回
① 调用端由于先前使用了postForEntity方法,其返回值为 ResponseEntity< MagicFile>,此时获得了ResponseEntity
② 通过ResponseEntity 的 getBody()方法,获取 自定义的MagicFile对象 ---- 整个返回的参数已获得
③ 通过MagicFile对象的成员fileBytesArray,获取返回的字节数组形式的文件参数
④ 通过MagicFile对象的成员filename,获取返回的字符串普通参数 ---- 返回的字符串参数已获得
⑤ 再次使用 FileUtils工具 将字节数组形式的文件转换为本地文件 ---- 返回的文件参数已获得
@Resource
RestTemplate restTemplate;
@RequestMapping("/upload")
public String getUpload(Model model){
String url = "http://localhost:8001/restUpload2";
// 将 本地文件 --> 字节数组 --> 字节数组资源
File file = new File("D:/11.jpg");
byte[] bytesFile = null;
try{
bytesFile = FileUtils.readFileToByteArray(file);
} catch (IOException e) {
e.printStackTrace();
}
ByteArrayResource byteArrayResource = new ByteArrayResource(bytesFile) {
// 必须重写该方法,否则服务器MultipartRequest.getFile获取文件为空,
// 但是return的变量名 作SubmittedFileName(可自定义),并非做接收端按键取值时的文件的键名
// 即上传的文件具有两个名字: 键名 和 提交的文件名SubmittedFileName
@Override
public String getFilename() {
return "xxxxx";
}
};
// httpRequest body
MultiValueMap paramsMap = new LinkedMultiValueMap<>();
paramsMap.add("file", byteArrayResource);
paramsMap.add("fileName", "11.jpg");
// httpRequest header
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("Content-Type", "multipart/form-data");
HttpEntity> request =
new HttpEntity>(paramsMap , httpHeaders);
ResponseEntity response = restTemplate.postForEntity(url, paramsMap, MagicFile.class);
// ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
// 接收 被调用端(S) 返回的 带有 文件和普通字符串 自定义MagicFile类型的参数
MagicFile magicFile = response.getBody();
byte[] returnBytesFile = null;
String mes = null;
try{
returnBytesFile = magicFile.getFileBytesArray();
if(returnBytesFile == null){
throw new RuntimeException("接收二进制文件流为空!");
}
mes = magicFile.getFileName();
if(mes == null){
throw new RuntimeException("接收二进制文件流 的 信息 为空!");
}
}catch (Exception e){
e.printStackTrace();
}
String downloadPath = "E:/download/";
UUID uuid = UUID.randomUUID();
String downloadFileName = downloadPath + uuid+".nc";
File downloadFile = new File(downloadFileName);
try{
FileUtils.writeByteArrayToFile(downloadFile, returnBytesFile);
System.err.println("返回的文件已保存完毕!!!");
}catch (IOException e){
e.printStackTrace();
}
// 往返回的前端index页面 添加参数
model.addAttribute("message", mes);
// 返回 index 页面
return "index";
}
/**
* 以注解的形式获取请求中携带的参数
* @param file
* @param fileName
* @return
*/
@RequestMapping("/restUpload2")
public ResponseEntity restUpload(@RequestParam("file") MultipartFile file,
@RequestParam("fileName")String fileName){
// 获取传递的参数
byte[] bytesFile = null;
try{
if(file == null){
throw new RuntimeException("接收的文件为空!");
}
if (fileName == null){
throw new RuntimeException("接收的文件名为空!");
}
bytesFile = file.getBytes();
}catch (Exception e){
e.printStackTrace();
}
// 字节数组 --> 本地文件
String downLoadUrl = "E:/upload/";
String uuid = UUID.randomUUID().toString();
String filePath = downLoadUrl + uuid + ".jpg";
File receiveFile = new File(filePath);
try {
FileUtils.writeByteArrayToFile(receiveFile, bytesFile);
System.err.println("创建本地文件成功 -- 方式2");
}
catch(Exception e){
e.printStackTrace();
}
//准备 返回的 文件参数和 普通字符串参数
File returnFile = new File("D:/test.nc");
byte[] returnBytesFile = null;
try{
returnBytesFile = FileUtils.readFileToByteArray(returnFile);
}catch (IOException e){
e.printStackTrace();
}
MagicFile magicFile = new MagicFile(fileName, returnBytesFile);
return new ResponseEntity(magicFile, HttpStatus.OK);
}
在 B -> S 模拟发送文件时,使用的示例是11.jpg,被调用端(S)接收该文件时,需要预先知道传输文件的后缀名 .jpg,才可以正确接收。
即有如下代码:
String downLoadUrl = "E:/upload/";
String uuid = UUID.randomUUID().toString();
String filePath = downLoadUrl + uuid + ".jpg";
File receiveFile = new File(filePath);
同样,在S -> B 返回文件时,使用的示例是test.nc文件,故调用端(B)接收该文件时,也需要预先知道传输文件的后缀名 .nc,才可以正确接收。
即有如下代码:
String downloadPath = "E:/download/";
UUID uuid = UUID.randomUUID();
String downloadFileName = downloadPath + uuid+".nc";
File downloadFile = new File(downloadFileName);