From 791999610e5a6028bfe8dfe44293beb3f267857c Mon Sep 17 00:00:00 2001 From: binchoo <079111w@gmail.com> Date: Wed, 27 Apr 2022 12:49:05 +0900 Subject: [PATCH] Verify multipart argument binding and property binding behaviors onto controller --- .../standalone/MultipartControllerTests.java | 109 +++++++++++++++++- 1 file changed, 106 insertions(+), 3 deletions(-) diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/samples/standalone/MultipartControllerTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/samples/standalone/MultipartControllerTests.java index e61d50f0d6e4..96d0842065cc 100644 --- a/spring-test/src/test/java/org/springframework/test/web/servlet/samples/standalone/MultipartControllerTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/servlet/samples/standalone/MultipartControllerTests.java @@ -38,6 +38,9 @@ import org.springframework.stereotype.Controller; import org.springframework.test.web.servlet.MockMvc; import org.springframework.ui.Model; +import org.springframework.util.StreamUtils; +import org.springframework.validation.BindException; +import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; @@ -55,6 +58,7 @@ /** * @author Rossen Stoyanchev * @author Juergen Hoeller + * @author Jaebin Joo */ public class MultipartControllerTests { @@ -224,7 +228,7 @@ public void multipartRequestWithOptionalFileListNotPresent() throws Exception { } @Test - public void multipartRequestWithServletParts() throws Exception { + public void multipartRequestWithParts_resolvesMultipartFileArguments() throws Exception { byte[] fileContent = "bar".getBytes(StandardCharsets.UTF_8); MockPart filePart = new MockPart("file", "orig", fileContent); @@ -239,6 +243,50 @@ public void multipartRequestWithServletParts() throws Exception { .andExpect(model().attribute("jsonContent", Collections.singletonMap("name", "yeeeah"))); } + @Test + public void multipartRequestWithParts_resolvesPartArguments() throws Exception { + byte[] fileContent = "bar".getBytes(StandardCharsets.UTF_8); + MockPart filePart = new MockPart("file", "orig", fileContent); + + byte[] json = "{\"name\":\"yeeeah\"}".getBytes(StandardCharsets.UTF_8); + MockPart jsonPart = new MockPart("json", json); + jsonPart.getHeaders().setContentType(MediaType.APPLICATION_JSON); + + standaloneSetup(new MultipartController()).build() + .perform(multipart("/part").part(filePart).part(jsonPart)) + .andExpect(status().isFound()) + .andExpect(model().attribute("fileContent", fileContent)) + .andExpect(model().attribute("jsonContent", Collections.singletonMap("name", "yeeeah"))); + } + + @Test + public void multipartRequestWithParts_resolvesMultipartFileProperties() throws Exception { + byte[] fileContent = "bar".getBytes(StandardCharsets.UTF_8); + MockPart filePart = new MockPart("file", "orig", fileContent); + + standaloneSetup(new MultipartController()).build() + .perform(multipart("/multipartfileproperty").part(filePart)) + .andExpect(status().isFound()) + .andExpect(model().attribute("fileContent", fileContent)); + } + + @Test + public void multipartRequestWithParts_cannotResolvePartProperties() throws Exception { + byte[] fileContent = "bar".getBytes(StandardCharsets.UTF_8); + MockPart filePart = new MockPart("file", "orig", fileContent); + + Exception exception = standaloneSetup(new MultipartController()).build() + .perform(multipart("/partproperty").part(filePart)) + .andExpect(status().is4xxClientError()) + .andReturn() + .getResolvedException(); + + assertThat(exception).isNotNull(); + assertThat(exception).isInstanceOf(BindException.class); + assertThat(((BindException) exception).getFieldError("file")) + .as("MultipartRequest would not bind Part properties.").isNotNull(); + } + @Test // SPR-13317 public void multipartRequestWrapped() throws Exception { byte[] json = "{\"name\":\"yeeeah\"}".getBytes(StandardCharsets.UTF_8); @@ -342,10 +390,13 @@ public String processOptionalFileList(@RequestParam Optional } @RequestMapping(value = "/part", method = RequestMethod.POST) - public String processPart(@RequestParam Part part, + public String processPart(@RequestPart Part file, @RequestPart Map json, Model model) throws IOException { - model.addAttribute("fileContent", part.getInputStream()); + if (file != null) { + byte[] content = StreamUtils.copyToByteArray(file.getInputStream()); + model.addAttribute("fileContent", content); + } model.addAttribute("jsonContent", json); return "redirect:/index"; @@ -356,8 +407,60 @@ public String processMultipart(@RequestPart Map json, Model mode model.addAttribute("json", json); return "redirect:/index"; } + + @RequestMapping(value = "/multipartfileproperty", method = RequestMethod.POST) + public String processMultipartFileBean(MultipartFileBean multipartFileBean, Model model, BindingResult bindingResult) + throws IOException { + + if (!bindingResult.hasErrors()) { + MultipartFile file = multipartFileBean.getFile(); + if (file != null) { + model.addAttribute("fileContent", file.getBytes()); + } + } + return "redirect:/index"; + } + + @RequestMapping(value = "/partproperty", method = RequestMethod.POST) + public String processPartBean(PartBean partBean, Model model, BindingResult bindingResult) + throws IOException { + + if (!bindingResult.hasErrors()) { + Part file = partBean.getFile(); + if (file != null) { + byte[] content = StreamUtils.copyToByteArray(file.getInputStream()); + model.addAttribute("fileContent", content); + } + } + return "redirect:/index"; + } } + private static class MultipartFileBean { + + private MultipartFile file; + + public MultipartFile getFile() { + return file; + } + + public void setFile(MultipartFile file) { + this.file = file; + } + } + + private static class PartBean { + + private Part file; + + public Part getFile() { + return file; + } + + public void setFile(Part file) { + this.file = file; + } + } private static class RequestWrappingFilter extends OncePerRequestFilter {