parent
							
								
									caaf83b8e6
								
							
						
					
					
						commit
						f0d149b330
					
				|  | @ -1,5 +1,5 @@ | |||
| /* | ||||
|  * Copyright 2002-2020 the original author or authors. | ||||
|  * Copyright 2002-2022 the original author or authors. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  | @ -32,15 +32,16 @@ import javax.servlet.http.HttpServletResponse; | |||
| import javax.servlet.http.Part; | ||||
| 
 | ||||
| import org.junit.jupiter.api.Test; | ||||
| import org.junit.jupiter.params.ParameterizedTest; | ||||
| import org.junit.jupiter.params.provider.ValueSource; | ||||
| 
 | ||||
| import org.springframework.http.MediaType; | ||||
| import org.springframework.mock.web.MockMultipartFile; | ||||
| import org.springframework.mock.web.MockPart; | ||||
| import org.springframework.stereotype.Controller; | ||||
| import org.springframework.test.web.servlet.MockMvc; | ||||
| import org.springframework.test.web.servlet.request.MockMultipartHttpServletRequestBuilder; | ||||
| 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; | ||||
|  | @ -63,16 +64,20 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standal | |||
|  */ | ||||
| public class MultipartControllerTests { | ||||
| 
 | ||||
| 	@Test | ||||
| 	public void multipartRequestWithSingleFile() throws Exception { | ||||
| 	@ParameterizedTest | ||||
| 	@ValueSource(strings = {"/multipartfile", "/part"}) | ||||
| 	public void multipartRequestWithSingleFileOrPart(String url) throws Exception { | ||||
| 		byte[] fileContent = "bar".getBytes(StandardCharsets.UTF_8); | ||||
| 		MockMultipartFile filePart = new MockMultipartFile("file", "orig", null, fileContent); | ||||
| 
 | ||||
| 		byte[] json = "{\"name\":\"yeeeah\"}".getBytes(StandardCharsets.UTF_8); | ||||
| 		MockMultipartFile jsonPart = new MockMultipartFile("json", "json", "application/json", json); | ||||
| 
 | ||||
| 		MockMultipartHttpServletRequestBuilder requestBuilder = (url.endsWith("file") ? | ||||
| 				multipart(url).file(new MockMultipartFile("file", "orig", null, fileContent)) : | ||||
| 				multipart(url).part(new MockPart("part", "orig", fileContent))); | ||||
| 
 | ||||
| 		standaloneSetup(new MultipartController()).build() | ||||
| 				.perform(multipart("/multipartfile").file(filePart).file(jsonPart)) | ||||
| 				.perform(requestBuilder.file(jsonPart)) | ||||
| 				.andExpect(status().isFound()) | ||||
| 				.andExpect(model().attribute("fileContent", fileContent)) | ||||
| 				.andExpect(model().attribute("jsonContent", Collections.singletonMap("name", "yeeeah"))); | ||||
|  | @ -229,65 +234,16 @@ public class MultipartControllerTests { | |||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	public void multipartRequestWithParts_resolvesMultipartFileArguments() 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("/multipartfile").part(filePart).part(jsonPart)) | ||||
| 				.andExpect(status().isFound()) | ||||
| 				.andExpect(model().attribute("fileContent", fileContent)) | ||||
| 				.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 { | ||||
| 	public void multipartRequestWithDataBindingToFile() 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)) | ||||
| 				.perform(multipart("/multipartfilebinding").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); | ||||
|  | @ -391,11 +347,11 @@ public class MultipartControllerTests { | |||
| 		} | ||||
| 
 | ||||
| 		@RequestMapping(value = "/part", method = RequestMethod.POST) | ||||
| 		public String processPart(@RequestPart Part file, | ||||
| 		public String processPart(@RequestPart Part part, | ||||
| 				@RequestPart Map<String, String> json, Model model) throws IOException { | ||||
| 
 | ||||
| 			if (file != null) { | ||||
| 				byte[] content = StreamUtils.copyToByteArray(file.getInputStream()); | ||||
| 			if (part != null) { | ||||
| 				byte[] content = StreamUtils.copyToByteArray(part.getInputStream()); | ||||
| 				model.addAttribute("fileContent", content); | ||||
| 			} | ||||
| 			model.addAttribute("jsonContent", json); | ||||
|  | @ -409,9 +365,9 @@ public class MultipartControllerTests { | |||
| 			return "redirect:/index"; | ||||
| 		} | ||||
| 
 | ||||
| 		@RequestMapping(value = "/multipartfileproperty", method = RequestMethod.POST) | ||||
| 		public String processMultipartFileBean(MultipartFileBean multipartFileBean, Model model, BindingResult bindingResult) | ||||
| 				throws IOException { | ||||
| 		@RequestMapping(value = "/multipartfilebinding", method = RequestMethod.POST) | ||||
| 		public String processMultipartFileBean( | ||||
| 				MultipartFileBean multipartFileBean, Model model, BindingResult bindingResult) throws IOException { | ||||
| 
 | ||||
| 			if (!bindingResult.hasErrors()) { | ||||
| 				MultipartFile file = multipartFileBean.getFile(); | ||||
|  | @ -421,20 +377,6 @@ public class MultipartControllerTests { | |||
| 			} | ||||
| 			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 { | ||||
|  | @ -450,18 +392,6 @@ public class MultipartControllerTests { | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	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 { | ||||
| 
 | ||||
|  |  | |||
|  | @ -104,9 +104,8 @@ public class ServletRequestDataBinder extends WebDataBinder { | |||
| 	 * HTTP parameters: i.e. "uploadedFile" to an "uploadedFile" bean property, | ||||
| 	 * invoking a "setUploadedFile" setter method. | ||||
| 	 * <p>The type of the target property for a multipart file can be MultipartFile, | ||||
| 	 * Part, byte[], or String. The Part binding is only supported when the request | ||||
| 	 * is not a MultipartRequest. The latter two receive the contents of the uploaded file; | ||||
| 	 * all metadata like original file name, content type, etc are lost in those cases. | ||||
| 	 * byte[], or String. Servlet Part binding is also supported when the | ||||
| 	 * request has not been parsed to MultipartRequest via MultipartResolver. | ||||
| 	 * @param request the request with parameters to bind (can be multipart) | ||||
| 	 * @see org.springframework.web.multipart.MultipartHttpServletRequest | ||||
| 	 * @see org.springframework.web.multipart.MultipartRequest | ||||
|  |  | |||
|  | @ -107,10 +107,9 @@ public class WebRequestDataBinder extends WebDataBinder { | |||
| 	 * <p>Multipart files are bound via their parameter name, just like normal | ||||
| 	 * HTTP parameters: i.e. "uploadedFile" to an "uploadedFile" bean property, | ||||
| 	 * invoking a "setUploadedFile" setter method. | ||||
| 	 * <p>The type of the target property for a multipart file can be Part, MultipartFile, | ||||
| 	 * byte[], or String. The Part binding is only supported when the request | ||||
| 	 * is not a MultipartRequest. The latter two receive the contents of the uploaded file; | ||||
| 	 * all metadata like original file name, content type, etc are lost in those cases. | ||||
| 	 * <p>The type of the target property for a multipart file can be MultipartFile, | ||||
| 	 * byte[], or String. Servlet Part binding is also supported when the | ||||
| 	 * request has not been parsed to MultipartRequest via MultipartResolver. | ||||
| 	 * @param request the request with parameters to bind (can be multipart) | ||||
| 	 * @see org.springframework.web.multipart.MultipartRequest | ||||
| 	 * @see org.springframework.web.multipart.MultipartFile | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue