SpringブートのデフォルトのMultiPartResolverインターフェースは、ローカルファイルシステムに保存することにより、マルチパートファイルのアップロードを処理します。コントローラーメソッドを入力する前に、マルチパートファイル全体のサーバーへのアップロードを完了する必要があります。
アップロードされたすべてのファイルをデータベースに直接保存しており、サーバーのディスククォータは非常に小さいため、大きなファイルがアップロードされた場合、IOExeption - Disk quota exceeded
。
SpringのMultiPartResolverがローカルファイルシステムにファイルを保存してからdbに直接ストリーミングできるようにする前に、クライアントの着信リクエストから直接ストリームを取得する方法はありますか?
ここで説明されているように、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();
//...
}
}
}
}
スプリングのマルチパート解決メカニズムを必ず無効にしてください。
application.yml:
spring:
http:
multipart:
enabled: false
実際、それは簡単な作業ではありません。クライアントからデータベースにストリームを直接書き込みたい場合は、リクエストを手動で処理する必要があります。このタスクをより簡単にするライブラリがいくつかあります。それらの1つは "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);
}
}
ファイルフィールドのヘッダーは次のようになります。
Content-Disposition: form-data; name="fieldName"; filename="fileName.jpg"
Content-Type: image/jpeg
シンプルフィールドのヘッダーは次のようになります。
Content-Disposition: form-data; name="fieldName";
このスニペットは、方向を示すための簡単な例にすぎないことに注意してください。ヘッダーからフィールド名を抽出する、データベース出力ストリームを作成するなどの詳細はありません。これらすべてを独自に実装できます。 RFC1867 にあるマルチパートリクエストのフィールドヘッダーの例。についての情報 multipart/form-data
RFC2388 。