Intro
This time, I will try receiving files as “multipart/form-data”.
As same as last time, I will use Undertow as a web server.
Receiving files
When using Undertow, I can’t receive files using “io.micronaut.http.server.multipart.MultipartBody” as I wrote last time.
So I will use “@Part” annotations in this time.
FileController.java
<span>package</span> <span>jp.masanori</span><span>;</span><span>import</span> <span>org.slf4j.Logger</span><span>;</span><span>import</span> <span>org.slf4j.LoggerFactory</span><span>;</span><span>import</span> <span>io.micronaut.http.HttpHeaders</span><span>;</span><span>import</span> <span>io.micronaut.http.MediaType</span><span>;</span><span>import</span> <span>io.micronaut.http.annotation.Controller</span><span>;</span><span>import</span> <span>io.micronaut.http.annotation.Part</span><span>;</span><span>import</span> <span>io.micronaut.http.annotation.Post</span><span>;</span><span>import</span> <span>io.micronaut.http.multipart.CompletedFileUpload</span><span>;</span><span>@Controller</span><span>(</span><span>"/files"</span><span>)</span><span>public</span> <span>class</span> <span>FileController</span> <span>{</span><span>private</span> <span>final</span> <span>Logger</span> <span>logger</span><span>;</span><span>public</span> <span>FileController</span><span>()</span> <span>{</span><span>this</span><span>.</span><span>logger</span> <span>=</span> <span>LoggerFactory</span><span>.</span><span>getLogger</span><span>(</span><span>FileController</span><span>.</span><span>class</span><span>);</span><span>}</span><span>@Post</span><span>(</span><span>uri</span><span>=</span><span>"/sample"</span><span>,</span> <span>consumes</span> <span>=</span> <span>MediaType</span><span>.</span><span>MULTIPART_FORM_DATA</span><span>,</span> <span>produces</span> <span>=</span> <span>MediaType</span><span>.</span><span>TEXT_PLAIN</span><span>)</span><span>public</span> <span>String</span> <span>uploadSampleFiles</span><span>(</span><span>HttpHeaders</span> <span>headers</span><span>,</span> <span>@Part</span><span>(</span><span>"file1"</span><span>)</span> <span>CompletedFileUpload</span> <span>file1</span><span>)</span> <span>{</span><span>logger</span><span>.</span><span>info</span><span>(</span><span>"FileName: "</span> <span>+</span> <span>file1</span><span>.</span><span>getFilename</span><span>()</span> <span>+</span> <span>" size: "</span> <span>+</span> <span>file1</span><span>.</span><span>getSize</span><span>());</span><span>return</span> <span>file1</span><span>.</span><span>getFilename</span><span>();</span><span>}</span><span>}</span><span>package</span> <span>jp.masanori</span><span>;</span> <span>import</span> <span>org.slf4j.Logger</span><span>;</span> <span>import</span> <span>org.slf4j.LoggerFactory</span><span>;</span> <span>import</span> <span>io.micronaut.http.HttpHeaders</span><span>;</span> <span>import</span> <span>io.micronaut.http.MediaType</span><span>;</span> <span>import</span> <span>io.micronaut.http.annotation.Controller</span><span>;</span> <span>import</span> <span>io.micronaut.http.annotation.Part</span><span>;</span> <span>import</span> <span>io.micronaut.http.annotation.Post</span><span>;</span> <span>import</span> <span>io.micronaut.http.multipart.CompletedFileUpload</span><span>;</span> <span>@Controller</span><span>(</span><span>"/files"</span><span>)</span> <span>public</span> <span>class</span> <span>FileController</span> <span>{</span> <span>private</span> <span>final</span> <span>Logger</span> <span>logger</span><span>;</span> <span>public</span> <span>FileController</span><span>()</span> <span>{</span> <span>this</span><span>.</span><span>logger</span> <span>=</span> <span>LoggerFactory</span><span>.</span><span>getLogger</span><span>(</span><span>FileController</span><span>.</span><span>class</span><span>);</span> <span>}</span> <span>@Post</span><span>(</span><span>uri</span><span>=</span><span>"/sample"</span><span>,</span> <span>consumes</span> <span>=</span> <span>MediaType</span><span>.</span><span>MULTIPART_FORM_DATA</span><span>,</span> <span>produces</span> <span>=</span> <span>MediaType</span><span>.</span><span>TEXT_PLAIN</span><span>)</span> <span>public</span> <span>String</span> <span>uploadSampleFiles</span><span>(</span><span>HttpHeaders</span> <span>headers</span><span>,</span> <span>@Part</span><span>(</span><span>"file1"</span><span>)</span> <span>CompletedFileUpload</span> <span>file1</span><span>)</span> <span>{</span> <span>logger</span><span>.</span><span>info</span><span>(</span><span>"FileName: "</span> <span>+</span> <span>file1</span><span>.</span><span>getFilename</span><span>()</span> <span>+</span> <span>" size: "</span> <span>+</span> <span>file1</span><span>.</span><span>getSize</span><span>());</span> <span>return</span> <span>file1</span><span>.</span><span>getFilename</span><span>();</span> <span>}</span> <span>}</span>package jp.masanori; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import io.micronaut.http.HttpHeaders; import io.micronaut.http.MediaType; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Part; import io.micronaut.http.annotation.Post; import io.micronaut.http.multipart.CompletedFileUpload; @Controller("/files") public class FileController { private final Logger logger; public FileController() { this.logger = LoggerFactory.getLogger(FileController.class); } @Post(uri="/sample", consumes = MediaType.MULTIPART_FORM_DATA, produces = MediaType.TEXT_PLAIN) public String uploadSampleFiles(HttpHeaders headers, @Part("file1") CompletedFileUpload file1) { logger.info("FileName: " + file1.getFilename() + " size: " + file1.getSize()); return file1.getFilename(); } }
Enter fullscreen mode Exit fullscreen mode
To use the “@Part” annotation, I have to set “micronaut.server.multipart” enabled.
application.yml
<span>micronaut</span><span>:</span><span>application</span><span>:</span><span>name</span><span>:</span> <span>micronaut-web-app</span><span>router</span><span>:</span><span>static-resources</span><span>:</span><span>default</span><span>:</span><span>enabled</span><span>:</span> <span>true</span><span>paths</span><span>:</span> <span>classpath:static</span><span>server</span><span>:</span><span>port</span><span>:</span> <span>8086</span><span>multipart</span><span>:</span><span># add this line</span><span>enabled</span><span>:</span> <span>true</span><span>max-file-size</span><span>:</span> <span>20971520</span><span>micronaut</span><span>:</span> <span>application</span><span>:</span> <span>name</span><span>:</span> <span>micronaut-web-app</span> <span>router</span><span>:</span> <span>static-resources</span><span>:</span> <span>default</span><span>:</span> <span>enabled</span><span>:</span> <span>true</span> <span>paths</span><span>:</span> <span>classpath:static</span> <span>server</span><span>:</span> <span>port</span><span>:</span> <span>8086</span> <span>multipart</span><span>:</span> <span># add this line</span> <span>enabled</span><span>:</span> <span>true</span> <span>max-file-size</span><span>:</span> <span>20971520</span>micronaut: application: name: micronaut-web-app router: static-resources: default: enabled: true paths: classpath:static server: port: 8086 multipart: # add this line enabled: true max-file-size: 20971520
Enter fullscreen mode Exit fullscreen mode
index.page.ts
<span>window</span><span>.</span><span>Page</span> <span>=</span> <span>{</span><span>send</span><span>()</span> <span>{</span><span>const</span> <span>file1Input</span> <span>=</span> <span>document</span><span>.</span><span>getElementById</span><span>(</span><span>"</span><span>upload_file_1</span><span>"</span><span>)</span> <span>as</span> <span>HTMLInputElement</span><span>;</span><span>const</span> <span>file1</span> <span>=</span> <span>getFile</span><span>(</span><span>file1Input</span><span>.</span><span>files</span><span>);</span><span>const</span> <span>form</span> <span>=</span> <span>new</span> <span>FormData</span><span>();</span><span>// Must set "file1" even if there is no data </span><span>if</span><span>(</span><span>file1</span> <span>==</span> <span>null</span><span>)</span> <span>{</span><span>form</span><span>.</span><span>append</span><span>(</span><span>"</span><span>file1</span><span>"</span><span>,</span> <span>new</span> <span>Blob</span><span>());</span><span>}</span> <span>else</span> <span>{</span><span>form</span><span>.</span><span>append</span><span>(</span><span>"</span><span>file1</span><span>"</span><span>,</span> <span>file1</span><span>);</span><span>}</span><span>fetch</span><span>(</span><span>"</span><span>http://sample.masanori.jp:8086/files/sample</span><span>"</span><span>,</span> <span>{</span><span>method</span><span>:</span> <span>"</span><span>POST</span><span>"</span><span>,</span><span>mode</span><span>:</span> <span>"</span><span>cors</span><span>"</span><span>,</span><span>body</span><span>:</span> <span>form</span><span>}).</span><span>then</span><span>((</span><span>res</span><span>)</span> <span>=></span> <span>res</span><span>.</span><span>text</span><span>())</span><span>.</span><span>then</span><span>((</span><span>res</span><span>)</span> <span>=></span> <span>console</span><span>.</span><span>log</span><span>(</span><span>res</span><span>))</span><span>.</span><span>catch</span><span>(</span><span>err</span> <span>=></span> <span>console</span><span>.</span><span>error</span><span>(</span><span>err</span><span>));</span><span>}</span><span>}</span><span>function</span> <span>getFile</span><span>(</span><span>files</span><span>:</span> <span>FileList</span><span>|</span><span>null</span><span>):</span> <span>File</span><span>|</span><span>null</span> <span>{</span><span>if</span><span>(</span><span>files</span> <span>==</span> <span>null</span><span>)</span> <span>{</span><span>return</span> <span>null</span><span>;</span><span>}</span><span>if</span><span>(</span><span>files</span><span>.</span><span>length</span> <span><=</span> <span>0</span> <span>||</span> <span>files</span><span>[</span><span>0</span><span>]</span> <span>==</span> <span>null</span><span>)</span> <span>{</span><span>return</span> <span>null</span><span>;</span><span>}</span><span>return</span> <span>files</span><span>[</span><span>0</span><span>];</span><span>}</span><span>window</span><span>.</span><span>Page</span> <span>=</span> <span>{</span> <span>send</span><span>()</span> <span>{</span> <span>const</span> <span>file1Input</span> <span>=</span> <span>document</span><span>.</span><span>getElementById</span><span>(</span><span>"</span><span>upload_file_1</span><span>"</span><span>)</span> <span>as</span> <span>HTMLInputElement</span><span>;</span> <span>const</span> <span>file1</span> <span>=</span> <span>getFile</span><span>(</span><span>file1Input</span><span>.</span><span>files</span><span>);</span> <span>const</span> <span>form</span> <span>=</span> <span>new</span> <span>FormData</span><span>();</span> <span>// Must set "file1" even if there is no data </span> <span>if</span><span>(</span><span>file1</span> <span>==</span> <span>null</span><span>)</span> <span>{</span> <span>form</span><span>.</span><span>append</span><span>(</span><span>"</span><span>file1</span><span>"</span><span>,</span> <span>new</span> <span>Blob</span><span>());</span> <span>}</span> <span>else</span> <span>{</span> <span>form</span><span>.</span><span>append</span><span>(</span><span>"</span><span>file1</span><span>"</span><span>,</span> <span>file1</span><span>);</span> <span>}</span> <span>fetch</span><span>(</span><span>"</span><span>http://sample.masanori.jp:8086/files/sample</span><span>"</span><span>,</span> <span>{</span> <span>method</span><span>:</span> <span>"</span><span>POST</span><span>"</span><span>,</span> <span>mode</span><span>:</span> <span>"</span><span>cors</span><span>"</span><span>,</span> <span>body</span><span>:</span> <span>form</span> <span>}).</span><span>then</span><span>((</span><span>res</span><span>)</span> <span>=></span> <span>res</span><span>.</span><span>text</span><span>())</span> <span>.</span><span>then</span><span>((</span><span>res</span><span>)</span> <span>=></span> <span>console</span><span>.</span><span>log</span><span>(</span><span>res</span><span>))</span> <span>.</span><span>catch</span><span>(</span><span>err</span> <span>=></span> <span>console</span><span>.</span><span>error</span><span>(</span><span>err</span><span>));</span> <span>}</span> <span>}</span> <span>function</span> <span>getFile</span><span>(</span><span>files</span><span>:</span> <span>FileList</span><span>|</span><span>null</span><span>):</span> <span>File</span><span>|</span><span>null</span> <span>{</span> <span>if</span><span>(</span><span>files</span> <span>==</span> <span>null</span><span>)</span> <span>{</span> <span>return</span> <span>null</span><span>;</span> <span>}</span> <span>if</span><span>(</span><span>files</span><span>.</span><span>length</span> <span><=</span> <span>0</span> <span>||</span> <span>files</span><span>[</span><span>0</span><span>]</span> <span>==</span> <span>null</span><span>)</span> <span>{</span> <span>return</span> <span>null</span><span>;</span> <span>}</span> <span>return</span> <span>files</span><span>[</span><span>0</span><span>];</span> <span>}</span>window.Page = { send() { const file1Input = document.getElementById("upload_file_1") as HTMLInputElement; const file1 = getFile(file1Input.files); const form = new FormData(); // Must set "file1" even if there is no data if(file1 == null) { form.append("file1", new Blob()); } else { form.append("file1", file1); } fetch("http://sample.masanori.jp:8086/files/sample", { method: "POST", mode: "cors", body: form }).then((res) => res.text()) .then((res) => console.log(res)) .catch(err => console.error(err)); } } function getFile(files: FileList|null): File|null { if(files == null) { return null; } if(files.length <= 0 || files[0] == null) { return null; } return files[0]; }
Enter fullscreen mode Exit fullscreen mode
If the form data does’t have the “file1” parameter, a “Bad Request” error will occur.
{"_links":{"self":[{"href":"/files/sample","templated":false}]},"_embedded":{"errors":[{"message":"Required Part [file1] not specified","path":"/file1"}]},"message":"Bad Request"}{ "_links":{ "self":[{"href":"/files/sample","templated":false}]}, "_embedded":{"errors":[{ "message":"Required Part [file1] not specified","path":"/file1" }]}, "message":"Bad Request" }{ "_links":{ "self":[{"href":"/files/sample","templated":false}]}, "_embedded":{"errors":[{ "message":"Required Part [file1] not specified","path":"/file1" }]}, "message":"Bad Request" }
Enter fullscreen mode Exit fullscreen mode
I can receive two or more files like below.
FileController.java
<span>...</span><span>@Post</span><span>(</span><span>uri</span><span>=</span><span>"/sample"</span><span>,</span> <span>consumes</span> <span>=</span> <span>MediaType</span><span>.</span><span>MULTIPART_FORM_DATA</span><span>,</span> <span>produces</span> <span>=</span> <span>MediaType</span><span>.</span><span>TEXT_PLAIN</span><span>)</span><span>public</span> <span>String</span> <span>uploadSampleFiles</span><span>(</span><span>HttpHeaders</span> <span>headers</span><span>,</span> <span>@Part</span><span>(</span><span>"file1"</span><span>)</span> <span>CompletedFileUpload</span> <span>file1</span><span>,</span><span>@Part</span><span>(</span><span>"file2"</span><span>)</span> <span>CompletedFileUpload</span> <span>file2</span><span>)</span> <span>{</span><span>...</span><span>}</span><span>...</span><span>...</span> <span>@Post</span><span>(</span><span>uri</span><span>=</span><span>"/sample"</span><span>,</span> <span>consumes</span> <span>=</span> <span>MediaType</span><span>.</span><span>MULTIPART_FORM_DATA</span><span>,</span> <span>produces</span> <span>=</span> <span>MediaType</span><span>.</span><span>TEXT_PLAIN</span><span>)</span> <span>public</span> <span>String</span> <span>uploadSampleFiles</span><span>(</span><span>HttpHeaders</span> <span>headers</span><span>,</span> <span>@Part</span><span>(</span><span>"file1"</span><span>)</span> <span>CompletedFileUpload</span> <span>file1</span><span>,</span> <span>@Part</span><span>(</span><span>"file2"</span><span>)</span> <span>CompletedFileUpload</span> <span>file2</span><span>)</span> <span>{</span> <span>...</span> <span>}</span> <span>...</span>... @Post(uri="/sample", consumes = MediaType.MULTIPART_FORM_DATA, produces = MediaType.TEXT_PLAIN) public String uploadSampleFiles(HttpHeaders headers, @Part("file1") CompletedFileUpload file1, @Part("file2") CompletedFileUpload file2) { ... } ...
Enter fullscreen mode Exit fullscreen mode
暂无评论内容