问题描述
今天在做表单提交的时候遇到一个问题:
- 如何将表单与上传的文件流一起上传至后台服务器,整个过程中只允许存在一次请求。
- 于是在网上搜了许久,并没有直接讲到将表单数据与文件流一起上传至后台进行数据处理
- 然后就一直自己在调试,终于找到了解决办法。
代码展示
首先先展示前端代码(前端代码为伪代码)
/**
* 首先我们会有一个表单JSON对象
* 我这里假设为 submissionData
* 里面的参数我就不写,因为现在没有具体数据,并且这不是重点
*/
var submissionData={};
/**
* 然后,我这里会存在很多个附件……
*/
var files = [……,……,……];
/**
* 创建一个FormData,
* 我们先把附件数据逐个放入formData
* 然后把表单对象放入formData
* 表单对象放入之前请序列化成字符串 JSON.stringify
* 但是formData请不要序列化
*/
var formData = new FormData();
for(i=0;i<files.length;i++){
formData.append("file_"+i,files[i]);
}
formData.append("submissionData",JSON.stringify(submissionData));
/**
* 开始请求后台,发送请求的时候请将
* contentType:false
* 或者
* Content-Type:undefined
* 具体情况看个人所使用前端的框架,发送的请求框架样式来决定的,
* 如果这里写法存在困难需要查看对应框架的API
* 请求过程因为框架不同,我这里伪代码也不展示了
*/
/**
* 最后说一下,我这里使用的POST请求
*/
后端代码展示(这块不是伪代码,粘贴就能用)
依赖jar包
//依赖jar包
import com.alibaba.fastjson.JSONObject;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
具体代码展示,这里我代码做了重构
/**
* 接口-保存方法
* @param response
* @param request
*/
@PostMapping("/saveFromData")
public void saveFromData(HttpServletResponse response, HttpServletRequest request){
//获取表单数据
JSONObject jsonObject = getSubmissionData(request);
//获取文件流
List<MultipartFile> files = monitorFile(request);
}
/**
* 获取表单中的数据
* @param request
* @return
*/
private JSONObject getSubmissionData(HttpServletRequest request) {
//获取表单数据
String jsonText = request.getParameter("submissionData");
//将表单数据序列化之后的数据转换为JSONObject类型(此步骤我们就获取完成了表单的)
JSONObject jsonObject = JSONObject.parseObject(jsonText);
return jsonObject;
}
/**
* 开始检测request中的文件流信息
* @param request
* @return
*/
private List<MultipartFile> monitorFile(HttpServletRequest request){
//将当前上下文初始化给commonsMultipartResolver
CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver(request.getSession().getServletContext());
//判断request是否为MultipartHttpServletRequest类型
if (request instanceof MultipartHttpServletRequest) {
//解析文件流,查看是否存在文件信息
return analysisFile(request, commonsMultipartResolver);
}
return null;
}
/**
* 解析文件流,查看是否存在文件信息
* @param request
* @param commonsMultipartResolver
* @return
*/
private List<MultipartFile> analysisFile(HttpServletRequest request, CommonsMultipartResolver commonsMultipartResolver) {
//将request强转为MultipartHttpServletRequest类型
MultipartHttpServletRequest multipartHttpServletRequest = (MultipartHttpServletRequest) request;
//创建一个迭代器,为接下来的迭代做准备
Iterator<String> iterator = multipartHttpServletRequest.getFileNames();
//检查form中是否有enctype="multipart/form-data",并且判断Iterator是否还存在值
if (commonsMultipartResolver.isMultipart(request) && iterator.hasNext()) {
//开始遍历文件
return ergodicIteratorFile(multipartHttpServletRequest,iterator);
}
return null;
}
/**
* 遍历文件集合,并做返回
* @param multipartHttpServletRequest
* @param iterator
* @return
*/
private List<MultipartFile> ergodicIteratorFile(MultipartHttpServletRequest multipartHttpServletRequest,Iterator<String> iterator){
//创建文件存储的一个集合,并初始化
// (这里使用Vector,而不使用ArrayLsit,是怕引起线程安全问题,因为后面会引用到相同的内存地址)
List<MultipartFile> fileList= new Vector<>();
//对iterator进行遍历
while (iterator.hasNext()) {
//将当前文件名一致的文件流放入同一个集合中
List<MultipartFile> fileRows = multipartHttpServletRequest.getFiles(iterator.next());
//对文件做去重设置
monitorRepeat(fileList, fileRows);
}
return fileList;
}
/**
* 对文件做去重设置
* @param fileList
* @param fileRows
*/
private void monitorRepeat(List<MultipartFile> fileList, List<MultipartFile> fileRows) {
//判断集合是否存在,并且是否大于0
if (fileRows != null && fileRows.size() != 0) {
//对文件集合进行遍历
for (MultipartFile file : fileRows) {
//判断文件是否存在
if (file != null && !file.isEmpty()) {
//添加文件
fileList.add(file);
}
}
}
}
pom相关依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.61</version>
</dependency>