目录
一、代码实现
二、MultipartFile工具类
三、HttpClient使用
四、参考链接
一、代码实现
1、A服务接收前端上传文件并发送至B服务
引入依赖
<dependency>
<groupId></groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
<dependency>
<groupId></groupId>
<artifactId>httpmime</artifactId>
<version>4.5.13</version>
</dependency>
使用MultipartFile接收前端文件
@RequestMapping("/test")
@ResponseBody
public JSONObject getZzRxbd(HttpServletRequest request,MultipartFile file) {
//略
}
调取第三方接口,发送 MultipartFile 文件
/**
* 以post方式调用第三方接口,以form-data 形式 发送 MultipartFile 文件数据
*
* @param url post请求url
* @param fileParamName 文件参数名称
* @param multipartFile 文件
* @param paramMap 表单里其他参数
* @return 响应结果
*/
public static JSONObject doPostFormData(String url, String fileParamName, MultipartFile multipartFile, Map<String, Object> paramMap) {
// 创建Http实例
CloseableHttpClient httpClient = ();
JSONObject jsonResult = null;
// 创建HttpPost实例
HttpPost httpPost = new HttpPost(url);
// 请求参数配置
RequestConfig requestConfig = ().setSocketTimeout(60000).setConnectTimeout(60000)
.setConnectionRequestTimeout(10000).build();
(requestConfig);
try {
MultipartEntityBuilder builder = ();
(StandardCharsets.UTF_8);
(HttpMultipartMode.BROWSER_COMPATIBLE);
String fileName = ();
// 文件流
(fileParamName, (), ContentType.MULTIPART_FORM_DATA, fileName);
//表单中其他参数
for (<String, Object> entry : ()) {
((), new StringBody((String) (), ("text/plain", Consts.UTF_8)));
}
HttpEntity entity = ();
(entity);
// 执行提交
HttpResponse response = (httpPost);
if (().getStatusCode() == HttpStatus.SC_OK) {
// 返回
String s = ((), StandardCharsets.UTF_8);
jsonResult = (s);
return jsonResult;
}
} catch (Exception e) {
();
("调用HttpPost失败!" + ());
} finally {
if (httpClient != null) {
try {
();
} catch (IOException e) {
("关闭HttpPost连接失败!");
}
}
}
return null;
}
2、B服务接收文件
@PostMapping(value = "/import", headers = "content-type=multipart/form-data")
@ApiOperation("接收上传文件")
public Result<Object> importExcel(HttpServletRequest request, HttpServletResponse response) {
CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver(().getServletContext());
("utf-8");
if ((request)){
MultipartHttpServletRequest mulReq = (MultipartHttpServletRequest) request;
Map<String, MultipartFile> map = ();
// fileParamName
MultipartFile multiFile = ("fileParamName");
// 后续文件处理逻辑......
}
return new Result<>().error("请求内容有误!");
}
二、MultipartFile工具类
简介:MultipartFile是SpringMVC提供简化上传操作的工具类,在不使用框架之前,都是使用原生的HttpServletRequest来接收上传的数据,文件是以二进制流传递到后端的,然后需要我们自己转换为File类。使用了MultipartFile工具类之后,我们对文件上传的操作就简便许多了。
MultipartFile工具类的接口方法
package ;
import .slf4j.Slf4j;
import ;
import ;
import ;
import ;
import ;
import .BASE64Decoder;
import ;
import .*;
import ;
import ;
import ;
import ;
import ;
import .Base64;
import ;
import ;
import ;
import static .*;
/**
* @auther: Lilei
* @date: 2021/8/23 10:52
*/
@Slf4j
public class FileUtils {
private static final int BUFFER_SIZE = 2 * 1024;
/**
* url转MultipartFile
*/
public static MultipartFile base64ToMultipartFile(String base64) throws Exception {
File file = null;
MultipartFile multipartFile = null;
try {
//TODO 将base64转成字符流
byte[] bytes = ().decode(base64);
ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
file = inputStreamToFile(stream,"");
multipartFile = fileToMultipartFile(file);
} catch (Exception e) {
(());
();
}
return multipartFile;
}
/**
* base64转MultipartFile
*/
public static File base64ToFile(String base64,String fliePath) throws Exception {
File file = null;
MultipartFile multipartFile = null;
try {
// 将base64转成字符流
byte[] bytes = ().decode(("\r\n", ""));
ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
file = inputStreamToFile(stream,fliePath);
// multipartFile = fileToMultipartFile(file);
} catch (Exception e) {
(());
();
}
return file;
}
/**
* base64字符串转化成文件,可以是JPEG、PNG、TXT和AVI等等
*
* @param base64FileStr
* @param filePath
* @return
* @throws Exception
*/
public static boolean generateFile(String base64FileStr, String filePath) throws Exception {
// 数据为空
if (base64FileStr == null) {
(" 不行,oops! ");
return false;
}
BASE64Decoder decoder = new BASE64Decoder();
// Base64解码,对字节数组字符串进行Base64解码并生成文件
byte[] byt = (base64FileStr);
for (int i = 0, len = ; i < len; ++i) {
// 调整异常数据
if (byt[i] < 0) {
byt[i] += 256;
}
}
OutputStream out = null;
InputStream input = new ByteArrayInputStream(byt);
try {
// 生成指定格式的文件
out = new FileOutputStream(filePath);
byte[] buff = new byte[1024];
int len = 0;
while ((len = (buff)) != -1) {
(buff, 0, len);
}
} catch (IOException e) {
();
} finally {
();
();
}
return true;
}
/**
* String转MultipartFile
*/
public static File jsonStrToFile(String json,String fliePath) throws Exception {
File file = null;
MultipartFile multipartFile = null;
try {
//TODO 将base64转成字符流
InputStream stream = new ByteArrayInputStream((StandardCharsets.UTF_8));
file = inputStreamToFile(stream,fliePath);
// multipartFile = fileToMultipartFile(file);
} catch (Exception e) {
(());
();
}
return file;
}
/**
* file转multipartFile
*/
public static MultipartFile fileToMultipartFile(File file) {
FileItemFactory factory = new DiskFileItemFactory(16, null);
FileItem item=((),"text/plain",true,());
int bytesRead = 0;
byte[] buffer = new byte[8192];
try {
FileInputStream fis = new FileInputStream(file);
OutputStream os = ();
while ((bytesRead = (buffer, 0, 8192)) != -1) {
(buffer, 0, bytesRead);
}
();
();
} catch (IOException e) {
();
}
return new CommonsMultipartFile(item);
}
/* *//**
* inputStream 转 File
*//*
public static File inputStreamToFile(InputStream ins, String name) throws Exception{
File file = new File(("") + + name);
OutputStream os = new FileOutputStream(file);
int bytesRead;
int len = 8192;
byte[] buffer = new byte[len];
while ((bytesRead = (buffer, 0, len)) != -1) {
(buffer, 0, bytesRead);
}
();
();
return file;
}*/
/**
* inputStream 转 File
*/
public static File inputStreamToFile(InputStream ins,String filePath) throws Exception{
File file = new File(filePath );
OutputStream os = new FileOutputStream(file);
int bytesRead;
int len = 8192;
byte[] buffer = new byte[len];
while ((bytesRead = (buffer, 0, len)) != -1) {
(buffer, 0, bytesRead);
}
();
();
return file;
}
/**
* 预览视频文件
* @param file
* @param response
* @throws UnsupportedEncodingException
*/
public static void previewVideo(File file, HttpServletResponse response) throws UnsupportedEncodingException {
try {
FileInputStream fis = new FileInputStream(file);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int n;
while ((n = (b)) != -1) {
(b, 0, n);
}
();
();
byte[] buffer = ();
("application/octet-stream");
("Accept-Ranges", "bytes");
();
().write(buffer);
} catch (FileNotFoundException e) {
();
} catch (IOException e) {
();
}
}
/**
* 压缩成ZIP 方法1
* @param srcDir 压缩文件夹路径
* @param out 压缩文件输出流
* @param KeepDirStructure 是否保留原来的目录结构,true:保留目录结构;
* false:所有文件跑到压缩包根目录下(注意:不保留目录结构可能会出现同名文件,会压缩失败)
* @throws RuntimeException 压缩失败会抛出运行时异常
*/
public static void toZip(String srcDir, OutputStream out, boolean KeepDirStructure)
throws RuntimeException{
long start = ();
ZipOutputStream zos = null ;
try {
zos = new ZipOutputStream(out);
File sourceFile = new File(srcDir);
compress(sourceFile,zos,(),KeepDirStructure);
long end = ();
("压缩完成,耗时:" + (end - start) +" ms");
} catch (Exception e) {
throw new RuntimeException("zip error from ZipUtils",e);
}finally{
if(zos != null){
try {
();
} catch (IOException e) {
();
}
}
}
}
/**
* 压缩成ZIP 方法2
* @param srcFiles 需要压缩的文件列表
* @param out 压缩文件输出流
* @throws RuntimeException 压缩失败会抛出运行时异常
*/
public static void toZip(List<File> srcFiles , OutputStream out)throws RuntimeException {
long start = ();
ZipOutputStream zos = null ;
try {
zos = new ZipOutputStream(out);
for (File srcFile : srcFiles) {
byte[] buf = new byte[BUFFER_SIZE];
(new ZipEntry(()));
int len;
FileInputStream in = new FileInputStream(srcFile);
while ((len = (buf)) != -1){
(buf, 0, len);
}
();
();
}
long end = ();
("压缩完成,耗时:" + (end - start) +" ms");
} catch (Exception e) {
throw new RuntimeException("zip error from ZipUtils",e);
}finally{
if(zos != null){
try {
();
} catch (IOException e) {
();
}
}
}
}
/**
* 递归压缩方法
* @param sourceFile 源文件
* @param zos zip输出流
* @param name 压缩后的名称
* @param KeepDirStructure 是否保留原来的目录结构,true:保留目录结构;
* false:所有文件跑到压缩包根目录下(注意:不保留目录结构可能会出现同名文件,会压缩失败)
* @throws Exception
*/
private static void compress(File sourceFile, ZipOutputStream zos, String name,
boolean KeepDirStructure) throws Exception{
byte[] buf = new byte[BUFFER_SIZE];
if(()){
// 向zip输出流中添加一个zip实体,构造器中name为zip实体的文件的名字
(new ZipEntry(name));
// copy文件到zip输出流中
int len;
FileInputStream in = new FileInputStream(sourceFile);
while ((len = (buf)) != -1){
(buf, 0, len);
}
// Complete the entry
();
();
} else {
File[] listFiles = ();
if(listFiles == null || == 0){
// 需要保留原来的文件结构时,需要对空文件夹进行处理
if(KeepDirStructure){
// 空文件夹的处理
(new ZipEntry(name + "/"));
// 没有文件,不需要文件的copy
();
}
}else {
for (File file : listFiles) {
// 判断是否需要保留原来的文件结构
if (KeepDirStructure) {
// 注意:()前面需要带上父文件夹的名字加一斜杠,
// 不然最后压缩包中就不能保留原来的文件结构,即:所有文件都跑到压缩包根目录下了
compress(file, zos, name + "/" + (),KeepDirStructure);
} else {
compress(file, zos, (),KeepDirStructure);
}
}
}
}
}
/**
* 创建文件顺便创建父目录
*
* @param path 文件字符串路径例如d:/fulld/why/ass/a/asd
*/
public static void createFile(String path) {
createFile(new File(path));
}
/**
* 创建文件顺便创建父目录
*
* @param file file类
*/
private static void createFile(File file) {
if (() && ()) {
();
try {
();
} catch (IOException e) {
();
}
return;
}
File parentFile = ();
if (()) {
if (()) {
();
();
}
} else {
();
}
try {
();
} catch (IOException e) {
();
}
}
/**
* 创建文件夹顺便创建父目录
*
* @param path 文件夹的路径字符串例如d:/fulld/why/ass/a/asd/
* @return 如果本来就存在或者创建成功,那么就返回true
*/
public static void mkdirs(String path) {
mkdirs(new File(path));
}
/**
* 创建文件夹顺便创建父目录
*
* @param file file类
*/
public static void mkdirs(File file) {
if (() && ()) {
return;
}
if (()) {
();
();
} else {
();
}
}
}
三、HttpClient使用
使用httpclient,需要下载httpclient-4.、httpmime-4.两个包,下载地址为:/ 大致看了下源码,其实也是使用字符拼接,只是封装后使用起来更简洁方便一些。、
httpclient需要注意的4点:
1.HttpClient4.3版本往后,原来的MultipartEntity过时不建议再使用了,替换成新的httpmime下面的MultipartEntityBuilder
最好设置contentType和boundary,不然会导致后面接收文件时的第一种方法接收不到文件报错。
3.使用addBinaryBody的坑:addBinaryBody 有6种不同用法,一般都是如下代码所示上传File即可,但是当传byte[]字节数组时,必须使用4参传值,且第四参必须带后缀名,例如:(“file”,new byte[]{},ContentType.DEFAULT_BINARY,“”);否则会导致接收文件时getFileNames()为空。
4.不使用addBinaryBody,也可以直接使用addPart,先把文件转换成FileBody就可以了
contentType使用【multipart/form-data】:它会将表单的数据处理为一条消息,以标签为单元,用分隔符分开。既可以上传键值对,也可以上传文件,
boundary:请求体中的boundary参数指定的就是分隔体,请求参数之间需要通过分隔体分隔,不然就会被识别成一个参数。
四、参考链接
multipart/form-data