McL*_*vin 16 spring multipartform-data spring-mvc spring-boot
Spring引导的默认MultiPartResolver接口通过将多部分文件存储在本地文件系统上来处理它们的上载.在输入控制器方法之前,整个多部分文件必须完成上传到服务器.
我们将所有上传的文件直接存储到数据库中,我们的服务器的磁盘配额非常小,所以如果上传大文件,我们会看到IOExeption - Disk quota exceeded.
有没有办法在Spring的MultiPartResolver将文件存储在本地文件系统之前直接从客户端的传入请求获取流,以便我们可以直接流式传输到我们的数据库?
Ber*_*ard 16
你可以直接使用apache,如https://commons.apache.org/proper/commons-fileupload/streaming.html所述.
@Controller
public class UploadController {
@RequestMapping("/upload")
public String upload(HttpServletRequest request) throws IOException, FileUploadException {
ServletFileUpload upload = new ServletFileUpload();
FileItemIterator iterator = upload.getItemIterator(request);
while (iterator.hasNext()) {
FileItemStream item = iterator.next();
if (!item.isFormField()) {
InputStream inputStream = item.openStream();
//...
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
确保禁用弹簧多部分解析机制.
application.yml:
spring:
http:
multipart:
enabled: false
Run Code Online (Sandbox Code Playgroud)
实际上这不是一项微不足道的任务.如果要将流从客户端写入数据库,则必须手动处理请求.有一些库可以使这个任务更简单.其中之一是"Apache Commons FileUpload".下面是一个非常简单的例子,你如何处理multipart/form-data这个库的传入请求.
@Controller
public class Controller{
@RequestMapping("/upload")
public String upload(HttpServletRequest request){
String boundary = extractBoundary(request);
try {
MultipartStream multipartStream = new MultipartStream(request.getInputStream(),
boundary.getBytes(), 1024, null);
boolean nextPart = multipartStream.skipPreamble();
while(nextPart) {
String header = multipartStream.readHeaders();
if(header.contains("filename")){
//if input is file
OutputStream output = createDbOutputStream();
multipartStream.readBodyData(output);
output.flush();
output.close();
} else {
//if input is not file (text, checkbox etc)
ByteArrayOutputStream output = new ByteArrayOutputStream();
multipartStream.readBodyData(output);
String value = output.toString("utf-8");
//... do something with extracted value
}
nextPart = multipartStream.readBoundary();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private String extractBoundary(HttpServletRequest request) {
String boundaryHeader = "boundary=";
int i = request.getContentType().indexOf(boundaryHeader)+
boundaryHeader.length();
return request.getContentType().substring(i);
}
}
Run Code Online (Sandbox Code Playgroud)
文件字段的标题将如下所示:
Content-Disposition: form-data; name="fieldName"; filename="fileName.jpg"
Content-Type: image/jpeg
Run Code Online (Sandbox Code Playgroud)
简单字段的标题将如下所示:
Content-Disposition: form-data; name="fieldName";
Run Code Online (Sandbox Code Playgroud)
请注意,此代码段只是向您展示方向的简化示例.没有一些细节,例如:从标题中提取字段名称,创建数据库输出流等.您可以自己实现所有这些内容.您可以在RFC1867中找到的多部分请求的字段标题的示例.有关multipart/form-data RFC2388的信息.
| 归档时间: |
|
| 查看次数: |
13423 次 |
| 最近记录: |