diff --git a/spring-web-modules/spring-mvc-forms-thymeleaf/pom.xml b/spring-web-modules/spring-mvc-forms-thymeleaf/pom.xml index fdd569d144..37bcee0b8d 100644 --- a/spring-web-modules/spring-mvc-forms-thymeleaf/pom.xml +++ b/spring-web-modules/spring-mvc-forms-thymeleaf/pom.xml @@ -24,6 +24,11 @@ org.springframework.boot spring-boot-starter-thymeleaf + + org.projectlombok + lombok + + org.springframework.boot diff --git a/spring-web-modules/spring-mvc-forms-thymeleaf/src/main/java/com/baeldung/multipartupload/Employee.java b/spring-web-modules/spring-mvc-forms-thymeleaf/src/main/java/com/baeldung/multipartupload/Employee.java new file mode 100644 index 0000000000..0bc600dd6a --- /dev/null +++ b/spring-web-modules/spring-mvc-forms-thymeleaf/src/main/java/com/baeldung/multipartupload/Employee.java @@ -0,0 +1,16 @@ +package com.baeldung.multipartupload; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.web.multipart.MultipartFile; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Employee { + private String name; + private MultipartFile document; +} diff --git a/spring-web-modules/spring-mvc-forms-thymeleaf/src/main/java/com/baeldung/multipartupload/EmployeeController.java b/spring-web-modules/spring-mvc-forms-thymeleaf/src/main/java/com/baeldung/multipartupload/EmployeeController.java new file mode 100644 index 0000000000..e02844233e --- /dev/null +++ b/spring-web-modules/spring-mvc-forms-thymeleaf/src/main/java/com/baeldung/multipartupload/EmployeeController.java @@ -0,0 +1,49 @@ +package com.baeldung.multipartupload; + +import lombok.AllArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.multipart.MultipartFile; + +import static org.springframework.web.bind.annotation.RequestMethod.POST; + +@Controller +@AllArgsConstructor +public class EmployeeController { + + private final EmployeeService employeeService; + + @GetMapping(value = "/employee") + public String showEmployeeForm(Model model) { + model.addAttribute("employee", new Employee()); + return "employee/createEmployeeForm"; + } + + @RequestMapping(path = "/employee", method = POST, consumes = { MediaType.MULTIPART_FORM_DATA_VALUE }) + public String saveEmployee(@ModelAttribute Employee employee) { + employeeService.save(employee); + return "employee/success"; + } + + @RequestMapping(path = "/requestpart/employee", method = POST, consumes = { MediaType.MULTIPART_FORM_DATA_VALUE }) + public ResponseEntity saveEmployee(@RequestPart Employee employee, @RequestPart MultipartFile document) { + employee.setDocument(document); + employeeService.save(employee); + return ResponseEntity.ok().build(); + } + + @RequestMapping(path = "/requestparam/employee", method = POST, consumes = { MediaType.MULTIPART_FORM_DATA_VALUE }) + public ResponseEntity saveEmployee(@RequestParam String name, @RequestPart MultipartFile document) { + Employee employee = new Employee(name, document); + employeeService.save(employee); + return ResponseEntity.ok().build(); + } + +} \ No newline at end of file diff --git a/spring-web-modules/spring-mvc-forms-thymeleaf/src/main/java/com/baeldung/multipartupload/EmployeeRepository.java b/spring-web-modules/spring-mvc-forms-thymeleaf/src/main/java/com/baeldung/multipartupload/EmployeeRepository.java new file mode 100644 index 0000000000..d4182e100d --- /dev/null +++ b/spring-web-modules/spring-mvc-forms-thymeleaf/src/main/java/com/baeldung/multipartupload/EmployeeRepository.java @@ -0,0 +1,8 @@ +package com.baeldung.multipartupload; + +import org.springframework.stereotype.Repository; + +@Repository +public interface EmployeeRepository { + void saveEmployee(Employee employee); +} \ No newline at end of file diff --git a/spring-web-modules/spring-mvc-forms-thymeleaf/src/main/java/com/baeldung/multipartupload/EmployeeService.java b/spring-web-modules/spring-mvc-forms-thymeleaf/src/main/java/com/baeldung/multipartupload/EmployeeService.java new file mode 100644 index 0000000000..f6906c8ba9 --- /dev/null +++ b/spring-web-modules/spring-mvc-forms-thymeleaf/src/main/java/com/baeldung/multipartupload/EmployeeService.java @@ -0,0 +1,36 @@ +package com.baeldung.multipartupload; + +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; + +@Service +public class EmployeeService { + + public void save(Employee employee) { + saveFile(employee.getDocument()); + // save other employee data + } + + private void saveFile(MultipartFile multipartFile) { + try { + saveToFilesystem(multipartFile); + } catch (Exception e) { + throw new RuntimeException("Unable to save file", e); + } + } + + private static void saveToFilesystem(MultipartFile multipartFile) throws IOException { + String dir = Files.createTempDirectory("tmpDir").toFile().getAbsolutePath(); + File file = new File(dir + File.pathSeparator + multipartFile.getName()); + + try (OutputStream os = new FileOutputStream(file)) { + os.write(multipartFile.getBytes()); + } + } +} diff --git a/spring-web-modules/spring-mvc-forms-thymeleaf/src/main/java/com/baeldung/multipartupload/MultipartUploadApplication.java b/spring-web-modules/spring-mvc-forms-thymeleaf/src/main/java/com/baeldung/multipartupload/MultipartUploadApplication.java new file mode 100644 index 0000000000..299a5c2325 --- /dev/null +++ b/spring-web-modules/spring-mvc-forms-thymeleaf/src/main/java/com/baeldung/multipartupload/MultipartUploadApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.multipartupload; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class MultipartUploadApplication { + + public static void main(String[] args) { + SpringApplication.run(MultipartUploadApplication.class, args); + } + +} diff --git a/spring-web-modules/spring-mvc-forms-thymeleaf/src/main/resources/templates/employee/createEmployeeForm.html b/spring-web-modules/spring-mvc-forms-thymeleaf/src/main/resources/templates/employee/createEmployeeForm.html new file mode 100644 index 0000000000..c88a8b9318 --- /dev/null +++ b/spring-web-modules/spring-mvc-forms-thymeleaf/src/main/resources/templates/employee/createEmployeeForm.html @@ -0,0 +1,16 @@ + + + + Getting Started: Handling Form Submission + + + +

Form

+
+

name:

+

document: + +

+
+ + \ No newline at end of file diff --git a/spring-web-modules/spring-mvc-forms-thymeleaf/src/main/resources/templates/employee/success.html b/spring-web-modules/spring-mvc-forms-thymeleaf/src/main/resources/templates/employee/success.html new file mode 100644 index 0000000000..2a49c01613 --- /dev/null +++ b/spring-web-modules/spring-mvc-forms-thymeleaf/src/main/resources/templates/employee/success.html @@ -0,0 +1,8 @@ + + + + + + Employee data submitted. + + \ No newline at end of file diff --git a/spring-web-modules/spring-mvc-forms-thymeleaf/src/test/java/com/baeldung/multipartupload/EmployeeControllerIntegrationTest.java b/spring-web-modules/spring-mvc-forms-thymeleaf/src/test/java/com/baeldung/multipartupload/EmployeeControllerIntegrationTest.java new file mode 100644 index 0000000000..73cf905a34 --- /dev/null +++ b/spring-web-modules/spring-mvc-forms-thymeleaf/src/test/java/com/baeldung/multipartupload/EmployeeControllerIntegrationTest.java @@ -0,0 +1,56 @@ +package com.baeldung.multipartupload; + +import org.junit.jupiter.api.Test; +import org.mockito.BDDMockito; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + +import static org.apache.http.entity.ContentType.DEFAULT_BINARY; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest +@EnableWebMvc +public class EmployeeControllerIntegrationTest { + + private static final MockMultipartFile A_FILE = new MockMultipartFile("document", null, DEFAULT_BINARY.toString(), "Employee Record".getBytes()); + + @Autowired + private MockMvc mockMvc; + + @MockBean + private EmployeeService employeeService; + + @Test + public void givenFormData_whenPost_thenReturns200OK() throws Exception { + + mockMvc.perform(multipart("/employee") + .file(A_FILE) + .param("name", "testname")) + .andExpect(status().isOk()); + } + + @Test + public void givenEmployeeJsonAndMultipartFile_whenPostWithRequestPart_thenReturnsOK() throws Exception { + MockMultipartFile employeeJson = new MockMultipartFile("employee", null, + "application/json", "{\"name\": \"Emp Name\"}".getBytes()); + + mockMvc.perform(multipart("/requestpart/employee") + .file(A_FILE) + .file(employeeJson)) + .andExpect(status().isOk()); + } + + @Test + public void givenRequestPartAndRequestParam_whenPost_thenReturns200OK() throws Exception { + mockMvc.perform(multipart("/requestparam/employee") + .file(A_FILE) + .param("name", "testname")) + .andExpect(status().isOk()); + } +} \ No newline at end of file