Spring MVC 4.1 No. 025 ファイルのアップロード
Java EE 6、Servlet 3.0から標準でファイルのアップロードができるようになりました。今回はServlet 3.0のファイルアップロードを行います。
ファイルアップロードする場合には、web.xmlにアップロードの設定が必要です(もしくはServletのアノテーションですが、DispathcerServletなのでweb.xmlになります)。web.xmlのDispatcherServletの設定を次のようにします。
<servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/spring-context.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> <multipart-config> <location>/tmp</location> <max-file-size>1000000</max-file-size> <max-request-size>1000000</max-request-size> <file-size-threshold>10000</file-size-threshold> </multipart-config> </servlet>
また、Springの設定も必要になります。Serlvet 3.0のファイルアップロードを使用する設定になります。
<bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver"> </bean>
Controllerは以下のようにします。受け取る際には、@RequestPartアノテーションを付けた引数で受け取ります。
package com.example.spring.controller.c025; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.multipart.MultipartFile; @Controller @RequestMapping("/c025") public class C025Controller { @RequestMapping("/uploadForm") public String uploadForm() { return "c025/uploadForm"; } @RequestMapping(value = "/uploadRecv", method = RequestMethod.POST) public String uploadRecv(@RequestParam String test, @RequestParam MultipartFile file, Model model) throws IOException { model.addAttribute("test", test); Path path = Paths.get(System.getProperty("java.io.tmpdir"), file.getOriginalFilename()); file.transferTo(path.toFile()); model.addAttribute("fileName", path); return "c025/uploadRecv"; } }
今回はファイルを一時領域に保管し、そのファイルのパスをtestパラメータと一緒にmodelに格納します。
ファイルを送信するuploadForm.jspです。
<%@page contentType="text/html; charset=utf-8" %><%-- --%><!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>サンプル</title> </head> <body> <form action="uploadRecv" method="post" enctype="multipart/form-data"> <input type="text" name="test"><br> <input type="file" name="file"><br> <input type="submit" value="送信"> </form> </body> </html>
結果表示のuploadRecv.jspです。日本語ファイル名も問題なく表示できます。
<%@page contentType="text/html; charset=utf-8" %><%-- --%><!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>サンプル</title> </head> <body> アップロードされました。<br> ファイル名は<c:out value="${fileName}" /><br> 送信されたtestパラメータは<c:out value="${test}" /> </body> </html>
確認用のテストケースは次のとおりです。ファイルアップロードのテストも標準でサポートされています。
package com.example.spring.controller.c025; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; import java.nio.file.Paths; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.mock.web.MockMultipartFile; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.web.servlet.MockMvc; import org.springframework.web.context.WebApplicationContext; @RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration @ContextConfiguration(locations = { "file:src/main/webapp/WEB-INF/spring/spring-context.xml" }) public class C025ControllerTest { @Autowired private WebApplicationContext wac; private MockMvc mockMvc; @Before public void setup() { mockMvc = webAppContextSetup(wac).build(); } @Test public void uploadFormのGET() throws Exception { mockMvc.perform(get("/c025/uploadForm")).andExpect(status().isOk()) .andExpect(view().name("c025/uploadForm")); } @Test public void uploadRecvのPOST() throws Exception { byte[] fileImage = null; Path path = Paths.get("src/test/resources/c025/kappa.png"); if (Files.exists(path, LinkOption.NOFOLLOW_LINKS)) { fileImage = Files.readAllBytes(path); } // ローカルのファイル名もエミュレーションできる。 String fileName = "画像.png"; MockMultipartFile file = new MockMultipartFile("file", fileName, null, fileImage); // アップロードされるファイルのパス Path actualFile = Paths.get(System.getProperty("java.io.tmpdir"), "画像.png"); mockMvc.perform( fileUpload("/c025/uploadRecv").file(file).param("test", "testParam")).andExpect(status().isOk()) .andExpect(view().name("c025/uploadRecv")) .andExpect(model().attribute("test", is("testParam"))) .andExpect(model().attribute("fileName", actualFile)); // 画像が保管されていることを確認する assertThat(Files.exists(actualFile, LinkOption.NOFOLLOW_LINKS), is(true)); byte[] actualImage = Files.readAllBytes(actualFile); assertThat(actualImage, is(equalTo(fileImage))); // アップロードされたファイルの削除 Files.delete(actualFile); } }
ソースは https://github.com/kuwalab/spring-mvc41 にあります。タグ025が今回のサンプルです。
まとめ http://kuwalab.hatenablog.jp/entry/spring
最初 http://kuwalab.hatenablog.jp/entry/spring_mvc41/001
前回 http://kuwalab.hatenablog.jp/entry/spring_mvc41/024
次回 http://kuwalab.hatenablog.jp/entry/spring_mvc41/026