mirror of
https://github.com/OtusTeam/Spring.git
synced 2026-05-30 10:50:42 +00:00
2024-07 spring-17-view updated
This commit is contained in:
+13
-4
@@ -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<Person> persons = repository.findAll();
|
||||
List<PersonDto> 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<String> 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:/";
|
||||
}
|
||||
|
||||
+7
@@ -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<String> hobby;
|
||||
}
|
||||
|
||||
+15
-4
@@ -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<String> 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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,4 +19,5 @@ spring:
|
||||
|
||||
logging:
|
||||
level:
|
||||
ROOT: ERROR
|
||||
ROOT: ERROR
|
||||
ru.otus.spring.controller: DEBUG
|
||||
@@ -1,2 +1,10 @@
|
||||
insert into person (id, name) values (1, 'Pushkin');
|
||||
insert into person (id, name) values (2, 'Lermontov');
|
||||
insert into person (id, name) values (2, 'Lermontov');
|
||||
|
||||
insert into person_hobby (person_id, hobby)
|
||||
values
|
||||
(1, 'Fishing'),
|
||||
(1, 'Poetry'),
|
||||
(2, 'Traveling'),
|
||||
(2, 'Poetry')
|
||||
;
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
);
|
||||
@@ -59,6 +59,15 @@
|
||||
<div class="errors" th:if="${#fields.hasErrors('name')}" th:errors="*{name}">Wrong person name error</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<label for="person-hobby-select" th:text="#{person-field-hobby} + ':'">Hobby:</label>
|
||||
<select id="person-hobby-select" name="hobby" multiple>
|
||||
<option value="Fishing" th:selected="*{hobby.contains('Fishing')}">Fishing</option>
|
||||
<option value="Poetry" th:selected="*{hobby.contains('Poetry')}">Poetry</option>
|
||||
<option value="Traveling" th:selected="*{hobby.contains('Traveling')}">Traveling</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<button type="submit" th:text="#{save-button-caption}">Save</button>
|
||||
<a href="list.html" th:href="@{/}"><button type="button" th:text="#{cancel-button-caption}">Cancel</button></a>
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
<tr>
|
||||
<th th:text="#{person-field-id}">ID</th>
|
||||
<th th:text="#{person-field-name}">Name</th>
|
||||
<th th:text="#{person-field-hobby}">Hobby</th>
|
||||
<th th:text="#{persons-table-column-action}">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -64,6 +65,7 @@
|
||||
<tr th:each="person : ${persons}">
|
||||
<td th:text="${person.id}">1</td>
|
||||
<td th:text="${person.name}">John Doe</td>
|
||||
<td th:text="${person.hobbyAsString()}">Hobby1, hobby2</td>
|
||||
<td>
|
||||
<a th:href="@{/edit(id=${person.id})}" href="edit.html" th:text="#{edit-button-caption}">Edit</a>
|
||||
</td>
|
||||
|
||||
+8
-3
@@ -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<Person> persons = List.of(new Person(1L, "Vasya"), new Person(2L, "Dima"));
|
||||
private List<Person> 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<PersonDto> 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
|
||||
|
||||
Reference in New Issue
Block a user