技巧:
一个接口有很多实现类,当调用 接口方法的时候,想知道 接口用的是哪个实现类,就用如下方法: 动态的获取接口用到的实现类
OutputStream outputStream = item.getOutputStream();// 查看 实际走的OutputStream 接口的 哪个实现类// class org.apache.tomcat.util.http.fileupload.DeferredFileOutputStreamSystem.out.println(outputStream.getClass());
1. springboot
将 一个 文件 (字节数组) 从 A 系统 传个 B 系统
A 系统:
@GetMapping("test")public void test(HttpServletRequest request, HttpServletResponse response) throws IOException {// 生成字节数组 byte[] bytes = BarCodeUtils.generateBarCode128("DCTK_202108030001", 10.00, 0.3, true, false);MultiValueMap<String, Object> multiValueMap = new LinkedMultiValueMap<>();HttpHeaders header = new HttpHeaders();header.setContentType(MediaType.MULTIPART_FORM_DATA);HttpHeaders fileHeader = new HttpHeaders();// TODO// fileHeader.setContentType(MediaType.parseMediaType(uploadFile.getContentType()));fileHeader.setContentDispositionFormData("file", "123456789");Map result = null;// 创建字节流的 HttpEntity 对象HttpEntity<ByteArrayResource> fileEntity = new HttpEntity<>(new ByteArrayResource(bytes),fileHeader);// file 和 Controller 方法的 接参对应multiValueMap.add("file", fileEntity);// other params//multiValueMap.add("uploader", uploader);// B 系统的 访问链接String url = "http://127.0.0.1:8092/fileUpload";HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(multiValueMap, header);ResponseEntity<UploadFileOutput> resultFromB = restTemplate.postForEntity(url, httpEntity, UploadFileOutput.class);System.out.println(result.toString());System.out.println(result.toString());}
系统B 接受:
/*** 上传文件* @param file 文件* @return*/@PostMapping(value = {"/fileUpload","uploadFile"})@ResponseBodypublic UploadFileOutput uploadFile(@RequestParam(value = "file") MultipartFile file, HttpServletResponse response) {try {byte[] bytes = file.getBytes();response.setContentType("image/png");InputStream in = new ByteArrayInputStream(bytes);} catch (IOException e) {e.printStackTrace();}return new UploadFileOutput("123456789","条形码");}
2. springcloud
将 一个 文件(字节数组)从 A 系统 传个 B 系统
A系统:
// FeignClient 里 有 url 属性(IP 端口 ) ,指定 路由到 服务注册中心的哪台机器
@FeignClient(value = "document-service", fallback = DocumentFeignClientFallBack.class)
public interface SystemFeignClient {/*** 上传图片* @param @RequestHeader(name = "X-USER-INFO") String token,* @return*/@PostMapping(value = "/document/sys/fileUpload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)BaseResponse<UploadFileOutput> fileUpload(@RequestPart("file") MultipartFile file , @RequestParam("fileTypes")List<String> fileTypes,@RequestParam("maxBytes") String maxBytes);}
准备调用(生成byte 数组):
byte[] bytes = BarCodeUtils.generateBarCode(xsRefundFromDb.getXReimbursementno(), 10.00, 0.3, true, false);// 构建 MultipartFile 对象CustomMultipartFile multiFile = new CustomMultipartFile(xsRefundFromDb.getXReimbursementno()+".jpg",bytes) ;UploadFileResult uploadFileResult = documentService.fileUpload(multiFile, Arrays.asList(".jpg"), "2345634565");
自定义 多媒体对象:
package com.longfor.crm3.finance.client.system.request;import org.apache.commons.io.FileUtils;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;import javax.activation.MimetypesFileTypeMap;
import java.io.*;
import java.nio.file.Files;/*** @program: crm3-finance8* @description: 自定义多媒体文件* @author: guoyiguang* @create: 2021-08-03 20:46**/
public class CustomMultipartFile implements MultipartFile, Serializable {private String fileName;/*** 文件服务器只接受file参数*/private String attachmentName = "file";private byte[] fileData;public CustomMultipartFile(String fileName,byte[] fileData) {this.fileName = fileName;this.fileData = fileData;this.attachmentName = attachmentName;}public CustomMultipartFile(String attachmentName, String fileName,byte[] fileData) {this.fileName = fileName;this.fileData = fileData;this.attachmentName = attachmentName;}@Overridepublic String getName() {return attachmentName;}@Overridepublic String getOriginalFilename() {return fileName;}@Overridepublic String getContentType() {return new MimetypesFileTypeMap().getContentType(fileName);}@Overridepublic boolean isEmpty() {return fileData == null || fileData.length == 0;}@Overridepublic long getSize() {return fileData.length;}@Overridepublic byte[] getBytes() {return fileData;}// B 系统 Controller 里 MultipartFile 调用 getInputStream() 就是 调用// 这个被重写的方法获取流(原生的是 通过 路径去获取 文件流 )@Overridepublic InputStream getInputStream() {ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(fileData);return byteArrayInputStream;}@Overridepublic void transferTo(File dest) throws IOException {FileUtils.writeByteArrayToFile(dest, fileData);if (dest.isAbsolute() && !dest.exists()) {FileCopyUtils.copy(this.getInputStream(), Files.newOutputStream(dest.toPath()));}}
}
字节数组转MultipartFile 参考文章:
https://www.thinbug.com/q/18381928
也可以参考spring 代码:生成 MultipartFile 接口的 子类:
@SneakyThrows@Testpublic void testList32() {// windows C:\Users\dell\AppData\Local\TempFile location = new File(System.getProperty("java.io.tmpdir"));// sizeThreshold: The threshold (阈值 ) above which uploads will be stored on disk.// 封装了临时文件的全路径(包括文件名)// 定义磁盘 上 文件的 临时仓库(目录) FileItem item = new DiskFileItem("hh", "image/png",false, "fileName.jpg", 1, location);// 生成 临时文件 File 对象 和 临时文件名称 (以 .temp 后缀命名)OutputStream outputStream = item.getOutputStream();// 查看 实际走的OutputStream 接口的 哪个实现类// class org.apache.tomcat.util.http.fileupload.DeferredFileOutputStreamSystem.out.println(outputStream.getClass());// DeferredFileOutputStream 父类的 write 方法// 写入内容 outputStream.write("DCTK_2021080300011234565432123456543234565432234543234543234543234554323456".getBytes(StandardCharsets.UTF_8));ApplicationPart part = new ApplicationPart(item, location);// 构建 MultipartFile 接口的 对象(spring的 StandardMultipartFile 是私有的, 所以 重新 创建一个类似的 类)MultipartFile multipartFile = new StandardMultipartFile2(part,"hh");System.out.println(multipartFile);// multipartFile.getInputStream();String s = new String(multipartFile.getBytes());System.out.println(s);}
用到的实体类如下:
package com.example.demo.entity.spring;import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.Part;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;/*** @program: springboot_01 spring 的 StandardMultipartFile 方法是私有的,所以重新写一个* @description:* @author: guoyiguang* @create: 2021-08-05 20:24**/
public class StandardMultipartFile2 implements MultipartFile, Serializable {private final Part part;private final String filename;public StandardMultipartFile2(Part part, String filename) {this.part = part;this.filename = filename;}@Overridepublic String getName() {return this.part.getName();}@Overridepublic String getOriginalFilename() {return this.filename;}@Overridepublic String getContentType() {return this.part.getContentType();}@Overridepublic boolean isEmpty() {return (this.part.getSize() == 0);}@Overridepublic long getSize() {return this.part.getSize();}@Overridepublic byte[] getBytes() throws IOException {return FileCopyUtils.copyToByteArray(this.part.getInputStream());}@Overridepublic InputStream getInputStream() throws IOException {return this.part.getInputStream();}@Overridepublic void transferTo(File dest) throws IOException, IllegalStateException {this.part.write(dest.getPath());}
}
缺点:生成了临时文件,需要运维人员定期维护
或者 通过 JVM 垃圾回收 , 监控 文件对象(或者MuiltpartFile 或者 其他对象)被回收了,通过虚引用 对象获取 临时目录,对相应的目录进行文件删除
B系统:
@PostMapping(value = {"/fileUpload","uploadFile"})public UploadFileResult uploadFile(@RequestParam(value = "file") MultipartFile multipartFile, UploadFileDTO uploadFileDTO, HttpServletRequest request) {return null ;}