diff --git a/2024-09/spring-17-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/controller/PersonController.java b/2024-09/spring-17-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/controller/PersonController.java index 8b189d35..4d43c693 100644 --- a/2024-09/spring-17-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/controller/PersonController.java +++ b/2024-09/spring-17-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/controller/PersonController.java @@ -2,6 +2,7 @@ package ru.otus.spring.controller; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; @@ -9,12 +10,12 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; -import ru.otus.spring.domain.Person; import ru.otus.spring.dto.PersonDto; import ru.otus.spring.repostory.PersonRepository; import java.util.List; +@Slf4j @Controller @RequiredArgsConstructor public class PersonController { @@ -23,24 +24,32 @@ public class PersonController { @GetMapping("/") public String listPage(Model model) { - List persons = repository.findAll(); + List persons = repository.findAll().stream() + .map(PersonDto::fromDomainObject).toList(); model.addAttribute("persons", persons); return "list"; } @GetMapping("/edit") public String editPage(@RequestParam("id") long id, Model model) { - Person person = repository.findById(id).orElseThrow(NotFoundException::new); + PersonDto person = repository.findById(id) + .map(PersonDto::fromDomainObject) + .orElseThrow(NotFoundException::new); model.addAttribute("person", person); return "edit"; } @PostMapping("/edit") public String savePerson(@Valid @ModelAttribute("person") PersonDto person, - BindingResult bindingResult, Model model) { + BindingResult bindingResult, + @RequestParam(value = "hobby", defaultValue = "") List hobby) { if (bindingResult.hasErrors()) { return "edit"; } + + log.debug("Hobby from plain RequestParam: {}", String.join(", ", hobby)); + log.debug("Hobby from DTO: {}", person.hobbyAsString()); + repository.save(person.toDomainObject()); return "redirect:/"; } diff --git a/2024-09/spring-17-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/domain/Person.java b/2024-09/spring-17-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/domain/Person.java index e40fd3f9..0252c11f 100644 --- a/2024-09/spring-17-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/domain/Person.java +++ b/2024-09/spring-17-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/domain/Person.java @@ -1,5 +1,7 @@ package ru.otus.spring.domain; +import jakarta.persistence.ElementCollection; +import jakarta.persistence.FetchType; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -9,6 +11,8 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import java.util.List; + @Data @AllArgsConstructor @NoArgsConstructor @@ -19,4 +23,7 @@ public class Person { @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; private String name; + + @ElementCollection(fetch = FetchType.EAGER) + private List hobby; } diff --git a/2024-09/spring-17-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/dto/PersonDto.java b/2024-09/spring-17-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/dto/PersonDto.java index 07f0e7e7..cc84bf38 100644 --- a/2024-09/spring-17-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/dto/PersonDto.java +++ b/2024-09/spring-17-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/dto/PersonDto.java @@ -1,11 +1,14 @@ package ru.otus.spring.dto; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Data; import ru.otus.spring.domain.Person; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.Size; +import java.util.List; + +import static org.springframework.util.CollectionUtils.isEmpty; @Data @AllArgsConstructor @@ -16,12 +19,20 @@ public class PersonDto { @NotBlank(message = "{name-field-should-not-be-blank}") @Size(min = 2, max = 10, message = "{name-field-should-has-expected-size}") private String name; + private List hobby; + + public String hobbyAsString() { + if (isEmpty(hobby)){ + return ""; + } + return String.join(", ", hobby); + } public Person toDomainObject(){ - return new Person(id, name); + return new Person(id, name, hobby); } public static PersonDto fromDomainObject(Person person) { - return new PersonDto(person.getId(), person.getName()); + return new PersonDto(person.getId(), person.getName(), person.getHobby()); } } diff --git a/2024-09/spring-17-view/spring-mvc-view-demo/src/main/resources/application.yml b/2024-09/spring-17-view/spring-mvc-view-demo/src/main/resources/application.yml index ec0f5ba6..6c79a7c5 100644 --- a/2024-09/spring-17-view/spring-mvc-view-demo/src/main/resources/application.yml +++ b/2024-09/spring-17-view/spring-mvc-view-demo/src/main/resources/application.yml @@ -19,4 +19,5 @@ spring: logging: level: - ROOT: ERROR \ No newline at end of file + ROOT: ERROR + ru.otus.spring.controller: DEBUG \ No newline at end of file diff --git a/2024-09/spring-17-view/spring-mvc-view-demo/src/main/resources/data.sql b/2024-09/spring-17-view/spring-mvc-view-demo/src/main/resources/data.sql index 7fa18c96..e3bcb10d 100644 --- a/2024-09/spring-17-view/spring-mvc-view-demo/src/main/resources/data.sql +++ b/2024-09/spring-17-view/spring-mvc-view-demo/src/main/resources/data.sql @@ -1,2 +1,10 @@ insert into person (id, name) values (1, 'Pushkin'); -insert into person (id, name) values (2, 'Lermontov'); \ No newline at end of file +insert into person (id, name) values (2, 'Lermontov'); + +insert into person_hobby (person_id, hobby) +values + (1, 'Fishing'), + (1, 'Poetry'), + (2, 'Traveling'), + (2, 'Poetry') +; \ No newline at end of file diff --git a/2024-09/spring-17-view/spring-mvc-view-demo/src/main/resources/messages.properties b/2024-09/spring-17-view/spring-mvc-view-demo/src/main/resources/messages.properties index 750f957b..372c1b19 100644 --- a/2024-09/spring-17-view/spring-mvc-view-demo/src/main/resources/messages.properties +++ b/2024-09/spring-17-view/spring-mvc-view-demo/src/main/resources/messages.properties @@ -5,6 +5,7 @@ persons-table-header=Persons: persons-table-column-action=Action person-field-id=ID person-field-name=Name +person-field-hobby=Hobby edit-button-caption=Edit person-form-header=Person Info: save-button-caption=Save diff --git a/2024-09/spring-17-view/spring-mvc-view-demo/src/main/resources/messages_en.properties b/2024-09/spring-17-view/spring-mvc-view-demo/src/main/resources/messages_en.properties index 76529cd0..b156844e 100644 --- a/2024-09/spring-17-view/spring-mvc-view-demo/src/main/resources/messages_en.properties +++ b/2024-09/spring-17-view/spring-mvc-view-demo/src/main/resources/messages_en.properties @@ -5,6 +5,7 @@ persons-table-header=Persons: persons-table-column-action=Action person-field-column-id=ID person-field-name=Name +person-field-hobby=Hobby edit-button-caption=Edit person-form-header=Person Info: save-button-caption=Save diff --git a/2024-09/spring-17-view/spring-mvc-view-demo/src/main/resources/messages_ru.properties b/2024-09/spring-17-view/spring-mvc-view-demo/src/main/resources/messages_ru.properties index 7a7fe765..a9739884 100644 --- a/2024-09/spring-17-view/spring-mvc-view-demo/src/main/resources/messages_ru.properties +++ b/2024-09/spring-17-view/spring-mvc-view-demo/src/main/resources/messages_ru.properties @@ -5,6 +5,7 @@ persons-table-header=\u041F\u0451\u0440\u0441\u043E\u043D\u044B: persons-table-column-action=\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u0435 person-field-id=\u0410\u0439\u0414\u0438 person-field-name=\u0418\u043C\u044F +person-field-hobby=\u0425\u043E\u0431\u0431\u0438 edit-button-caption=\u0418\u0437\u043C\u0435\u043D\u0438\u0442\u044C person-form-header=\u0418\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044F \u043E \u043F\u0451\u0440\u0441\u043E\u043D\u0435: save-button-caption=\u0421\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C diff --git a/2024-09/spring-17-view/spring-mvc-view-demo/src/main/resources/schema.sql b/2024-09/spring-17-view/spring-mvc-view-demo/src/main/resources/schema.sql index f36202f2..0482e3d4 100644 --- a/2024-09/spring-17-view/spring-mvc-view-demo/src/main/resources/schema.sql +++ b/2024-09/spring-17-view/spring-mvc-view-demo/src/main/resources/schema.sql @@ -1,4 +1,11 @@ create table person ( id integer generated by default as identity, - name varchar(255), primary key (id) + name varchar(255), + hobby varchar(500), + primary key (id) +); + +create table person_hobby ( + person_id integer references person(id), + hobby varchar(255) ); \ No newline at end of file diff --git a/2024-09/spring-17-view/spring-mvc-view-demo/src/main/resources/templates/edit.html b/2024-09/spring-17-view/spring-mvc-view-demo/src/main/resources/templates/edit.html index 79546a1c..ff0abf12 100644 --- a/2024-09/spring-17-view/spring-mvc-view-demo/src/main/resources/templates/edit.html +++ b/2024-09/spring-17-view/spring-mvc-view-demo/src/main/resources/templates/edit.html @@ -59,6 +59,15 @@
Wrong person name error
+
+ + +
+
diff --git a/2024-09/spring-17-view/spring-mvc-view-demo/src/main/resources/templates/list.html b/2024-09/spring-17-view/spring-mvc-view-demo/src/main/resources/templates/list.html index 324fffad..6acdb815 100644 --- a/2024-09/spring-17-view/spring-mvc-view-demo/src/main/resources/templates/list.html +++ b/2024-09/spring-17-view/spring-mvc-view-demo/src/main/resources/templates/list.html @@ -57,6 +57,7 @@ ID Name + Hobby Action @@ -64,6 +65,7 @@ 1 John Doe + Hobby1, hobby2 Edit diff --git a/2024-09/spring-17-view/spring-mvc-view-demo/src/test/java/ru/otus/spring/controller/PersonControllerTest.java b/2024-09/spring-17-view/spring-mvc-view-demo/src/test/java/ru/otus/spring/controller/PersonControllerTest.java index 3cd8a1d0..ea5b3a4f 100644 --- a/2024-09/spring-17-view/spring-mvc-view-demo/src/test/java/ru/otus/spring/controller/PersonControllerTest.java +++ b/2024-09/spring-17-view/spring-mvc-view-demo/src/test/java/ru/otus/spring/controller/PersonControllerTest.java @@ -6,6 +6,7 @@ import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.web.servlet.MockMvc; import ru.otus.spring.domain.Person; +import ru.otus.spring.dto.PersonDto; import ru.otus.spring.repostory.PersonRepository; import java.util.List; @@ -29,22 +30,26 @@ class PersonControllerTest { @MockBean private PersonRepository personRepository; - private List persons = List.of(new Person(1L, "Vasya"), new Person(2L, "Dima")); + private List persons = List.of(new Person(1L, "Vasya", List.of()), + new Person(2L, "Dima", List.of())); @Test void shouldRenderListPageWithCorrectViewAndModelAttributes() throws Exception { when(personRepository.findAll()).thenReturn(persons); + List expectedPersons = persons.stream() + .map(PersonDto::fromDomainObject).toList(); mvc.perform(get("/")) .andExpect(view().name("list")) - .andExpect(model().attribute("persons", persons)); + .andExpect(model().attribute("persons", expectedPersons)); } @Test void shouldRenderEditPageWithCorrectViewAndModelAttributes() throws Exception { when(personRepository.findById(1L)).thenReturn(Optional.of(persons.get(0))); + PersonDto expectedPerson = PersonDto.fromDomainObject(persons.get(0)); mvc.perform(get("/edit").param("id", "1")) .andExpect(view().name("edit")) - .andExpect(model().attribute("person", persons.get(0))); + .andExpect(model().attribute("person", expectedPerson)); } @Test