diff --git a/2025-07/spring-16-view/.gitignore b/2025-07/spring-16-view/.gitignore new file mode 100644 index 00000000..4ea52072 --- /dev/null +++ b/2025-07/spring-16-view/.gitignore @@ -0,0 +1,24 @@ +target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ diff --git a/2025-07/spring-16-view/pom.xml b/2025-07/spring-16-view/pom.xml new file mode 100644 index 00000000..f2ad9bdf --- /dev/null +++ b/2025-07/spring-16-view/pom.xml @@ -0,0 +1,21 @@ + + + 4.0.0 + + ru.otus + spring-mvc-view + 1.0 + + pom + + + spring-mvc-view-exercise + spring-mvc-view-demo + spring-mvc-view-solution1 + spring-mvc-view-solution2 + spring-mvc-view-solution3 + spring-mvc-view-solution4 + + diff --git a/2025-07/spring-16-view/spring-mvc-view-demo/.gitignore b/2025-07/spring-16-view/spring-mvc-view-demo/.gitignore new file mode 100644 index 00000000..4ea52072 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-demo/.gitignore @@ -0,0 +1,24 @@ +target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ diff --git a/2025-07/spring-16-view/spring-mvc-view-demo/pom.xml b/2025-07/spring-16-view/spring-mvc-view-demo/pom.xml new file mode 100644 index 00000000..653cf629 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-demo/pom.xml @@ -0,0 +1,86 @@ + + + 4.0.0 + + ru.otus + spring-mvc-view-demo + 1.0 + + + org.springframework.boot + spring-boot-starter-parent + 3.5.6 + + + + + 17 + 17 + 2.2.220 + 2.0 + + + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + + org.yaml + snakeyaml + ${snakeyaml.version} + + + + com.h2database + h2 + runtime + ${h2.version} + + + + org.projectlombok + lombok + 1.18.36 + provided + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + org.springframework.boot + spring-boot-starter-validation + + + + org.springframework.boot + spring-boot-starter-test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2025-07/spring-16-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/Main.java b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..6ec3d275 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,14 @@ +package ru.otus.spring; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) { + SpringApplication.run(Main.class); + System.out.printf("Чтобы перейти на страницу сайта открывай: %n%s%n", + "http://localhost:8080"); + } +} diff --git a/2025-07/spring-16-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/config/LocalizationConfig.java b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/config/LocalizationConfig.java new file mode 100644 index 00000000..fa2743ac --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/config/LocalizationConfig.java @@ -0,0 +1,34 @@ +package ru.otus.spring.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.LocaleResolver; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.web.servlet.i18n.CookieLocaleResolver; +import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; + +import java.util.Locale; + +@Configuration +public class LocalizationConfig implements WebMvcConfigurer { + + @Bean(name = "localeResolver") + public LocaleResolver localeResolver() { + var resolver = new CookieLocaleResolver("locale"); + resolver.setDefaultLocale(new Locale("en")); + return resolver; + } + + @Bean + public LocaleChangeInterceptor localeChangeInterceptor() { + var localeChangeInterceptor = new LocaleChangeInterceptor(); + localeChangeInterceptor.setParamName("lang"); + return localeChangeInterceptor; + } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(localeChangeInterceptor()); + } +} diff --git a/2025-07/spring-16-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/controller/GlobalExceptionHandler.java b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/controller/GlobalExceptionHandler.java new file mode 100644 index 00000000..028238f5 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/controller/GlobalExceptionHandler.java @@ -0,0 +1,23 @@ +package ru.otus.spring.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.context.MessageSource; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.servlet.ModelAndView; + +@RequiredArgsConstructor +@ControllerAdvice +public class GlobalExceptionHandler { + + private final MessageSource messageSource; + + @ExceptionHandler(NotFoundException.class) + public ModelAndView handeNotFoundException(NotFoundException ex) { + String errorText = messageSource.getMessage("person-not-found-error", null, + LocaleContextHolder.getLocale()); + return new ModelAndView("customError", "errorText", errorText); + } + +} diff --git a/2025-07/spring-16-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/controller/NotFoundException.java b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/controller/NotFoundException.java new file mode 100644 index 00000000..843693e3 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/controller/NotFoundException.java @@ -0,0 +1,8 @@ +package ru.otus.spring.controller; + +public class NotFoundException extends RuntimeException{ + + NotFoundException() { + super("Person not found"); + } +} diff --git a/2025-07/spring-16-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/controller/PersonController.java b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/controller/PersonController.java new file mode 100644 index 00000000..4d43c693 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/controller/PersonController.java @@ -0,0 +1,56 @@ +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; +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.dto.PersonDto; +import ru.otus.spring.repostory.PersonRepository; + +import java.util.List; + +@Slf4j +@Controller +@RequiredArgsConstructor +public class PersonController { + + private final PersonRepository repository; + + @GetMapping("/") + public String listPage(Model model) { + 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) { + 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, + @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/2025-07/spring-16-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/domain/Person.java b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..0252c11f --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,29 @@ +package ru.otus.spring.domain; + +import jakarta.persistence.ElementCollection; +import jakarta.persistence.FetchType; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; + +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Entity +public class Person { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + private String name; + + @ElementCollection(fetch = FetchType.EAGER) + private List hobby; +} diff --git a/2025-07/spring-16-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/dto/PersonDto.java b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/dto/PersonDto.java new file mode 100644 index 00000000..cc84bf38 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/dto/PersonDto.java @@ -0,0 +1,38 @@ +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 java.util.List; + +import static org.springframework.util.CollectionUtils.isEmpty; + +@Data +@AllArgsConstructor +public class PersonDto { + + private long id; + + @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, hobby); + } + + public static PersonDto fromDomainObject(Person person) { + return new PersonDto(person.getId(), person.getName(), person.getHobby()); + } +} diff --git a/2025-07/spring-16-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/repostory/PersonRepository.java b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/repostory/PersonRepository.java new file mode 100644 index 00000000..4fb88650 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/java/ru/otus/spring/repostory/PersonRepository.java @@ -0,0 +1,11 @@ +package ru.otus.spring.repostory; + +import org.springframework.data.repository.CrudRepository; +import ru.otus.spring.domain.Person; + +import java.util.List; + +public interface PersonRepository extends CrudRepository { + + List findAll(); +} diff --git a/2025-07/spring-16-view/spring-mvc-view-demo/src/main/resources/application.yml b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/resources/application.yml new file mode 100644 index 00000000..6c79a7c5 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/resources/application.yml @@ -0,0 +1,23 @@ +spring: + messages: + encoding: UTF-8 + + datasource: + url: jdbc:h2:mem:testdb + sql: + init: + mode: always + + + jpa: + open-in-view: false + generate-ddl: false + hibernate: + ddl-auto: none + + show-sql: true + +logging: + level: + ROOT: ERROR + ru.otus.spring.controller: DEBUG \ No newline at end of file diff --git a/2025-07/spring-16-view/spring-mvc-view-demo/src/main/resources/data.sql b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/resources/data.sql new file mode 100644 index 00000000..e3bcb10d --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/resources/data.sql @@ -0,0 +1,10 @@ +insert into person (id, name) values (1, 'Pushkin'); +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/2025-07/spring-16-view/spring-mvc-view-demo/src/main/resources/messages.properties b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/resources/messages.properties new file mode 100644 index 00000000..372c1b19 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/resources/messages.properties @@ -0,0 +1,16 @@ +lang-switcher-header=Select language +en-lang-switch-button-caption=Language - EN +ru-lang-switch-button-caption=Language - RU +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 +cancel-button-caption=Cancel +name-field-should-not-be-blank=Name field should not be blank +name-field-should-has-expected-size=Name field should be between 2 and 10 characters +error-text-header=Error +person-not-found-error=Person not found \ No newline at end of file diff --git a/2025-07/spring-16-view/spring-mvc-view-demo/src/main/resources/messages_en.properties b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/resources/messages_en.properties new file mode 100644 index 00000000..b156844e --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/resources/messages_en.properties @@ -0,0 +1,16 @@ +lang-switcher-header=Select language +en-lang-switch-button-caption=Language - EN +ru-lang-switch-button-caption=Language - RU +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 +cancel-button-caption=Cancel +name-field-should-not-be-blank=Name field should not be blank +name-field-should-has-expected-size=Name field should be between 2 and 10 characters +error-text-header=Error +person-not-found-error=Person not found \ No newline at end of file diff --git a/2025-07/spring-16-view/spring-mvc-view-demo/src/main/resources/messages_ru.properties b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/resources/messages_ru.properties new file mode 100644 index 00000000..a9739884 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/resources/messages_ru.properties @@ -0,0 +1,16 @@ +lang-switcher-header=\u0412\u044B\u0431\u043E\u0440 \u044F\u0437\u044B\u043A\u0430 +en-lang-switch-button-caption=\u042F\u0437\u044B\u043A - EN +ru-lang-switch-button-caption=\u042F\u0437\u044B\u043A - RU +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 +cancel-button-caption=\u041E\u0442\u043C\u0435\u043D\u0430 +name-field-should-not-be-blank=\u0418\u043C\u044F \u043D\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043F\u0443\u0441\u0442\u044B\u043C +name-field-should-has-expected-size=\u0414\u043B\u0438\u043D\u0430 \u0438\u043C\u0435\u043D\u0438 \u0434\u043E\u043B\u0436\u043D\u0430 \u0431\u044B\u0442\u044C \u043E\u0442 2 \u0434\u043E 10 \u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432 +error-text-header=\u041E\u0448\u0438\u0431\u043A\u0430 +person-not-found-error=\u041F\u0451\u0440\u0441\u043E\u043D \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D \ No newline at end of file diff --git a/2025-07/spring-16-view/spring-mvc-view-demo/src/main/resources/schema.sql b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/resources/schema.sql new file mode 100644 index 00000000..0482e3d4 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/resources/schema.sql @@ -0,0 +1,11 @@ +create table person ( + id integer generated by default as identity, + 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/2025-07/spring-16-view/spring-mvc-view-demo/src/main/resources/static/listmark.png b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/resources/static/listmark.png new file mode 100644 index 00000000..f8eb391b Binary files /dev/null and b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/resources/static/listmark.png differ diff --git a/2025-07/spring-16-view/spring-mvc-view-demo/src/main/resources/templates/customError.html b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/resources/templates/customError.html new file mode 100644 index 00000000..b54ef571 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/resources/templates/customError.html @@ -0,0 +1,34 @@ + + + + + List of all persons + + + + + +

Error text

+ Error text + + diff --git a/2025-07/spring-16-view/spring-mvc-view-demo/src/main/resources/templates/edit.html b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/resources/templates/edit.html new file mode 100644 index 00000000..ff0abf12 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/resources/templates/edit.html @@ -0,0 +1,78 @@ + + + + + Edit person + + + + + + + +
+

Person Info:

+ +
+ + +
+ +
+ + +
Wrong person name error
+
+ +
+ + +
+ +
+ + +
+
+ + + diff --git a/2025-07/spring-16-view/spring-mvc-view-demo/src/main/resources/templates/list.html b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/resources/templates/list.html new file mode 100644 index 00000000..6acdb815 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-demo/src/main/resources/templates/list.html @@ -0,0 +1,76 @@ + + + + + List of all persons + + + + + + +

Select language

+ + +

Persons:

+ + + + + + + + + + + + + + + + + + +
IDNameHobbyAction
1John DoeHobby1, hobby2 + Edit +
+ + diff --git a/2025-07/spring-16-view/spring-mvc-view-demo/src/test/java/ru/otus/spring/controller/PersonControllerTest.java b/2025-07/spring-16-view/spring-mvc-view-demo/src/test/java/ru/otus/spring/controller/PersonControllerTest.java new file mode 100644 index 00000000..fcb8dd5e --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-demo/src/test/java/ru/otus/spring/controller/PersonControllerTest.java @@ -0,0 +1,69 @@ +package ru.otus.spring.controller; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.test.context.bean.override.mockito.MockitoBean; +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; +import java.util.Optional; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; + +@WebMvcTest(PersonController.class) +class PersonControllerTest { + + @Autowired + private MockMvc mvc; + + @MockitoBean + private PersonRepository personRepository; + + 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", 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", expectedPerson)); + } + + @Test + void shouldRenderErrorPageWhenPersonNotFound() throws Exception { + when(personRepository.findById(1L)).thenThrow(new NotFoundException()); + mvc.perform(get("/edit").param("id", "1")) + .andExpect(view().name("customError")); + } + + @Test + void shouldSavePersonAndRedirectToContextPath() throws Exception { + when(personRepository.findById(1L)).thenReturn(Optional.of(persons.get(0))); + mvc.perform(post("/edit").param("id", "3").param("name", "Olya")) + .andExpect(view().name("redirect:/")); + verify(personRepository, times(1)).save(any(Person.class)); + } +} \ No newline at end of file diff --git a/2025-07/spring-16-view/spring-mvc-view-exercise/.gitignore b/2025-07/spring-16-view/spring-mvc-view-exercise/.gitignore new file mode 100644 index 00000000..4ea52072 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-exercise/.gitignore @@ -0,0 +1,24 @@ +target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ diff --git a/2025-07/spring-16-view/spring-mvc-view-exercise/pom.xml b/2025-07/spring-16-view/spring-mvc-view-exercise/pom.xml new file mode 100644 index 00000000..43a238e0 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-exercise/pom.xml @@ -0,0 +1,75 @@ + + + 4.0.0 + + ru.otus + spring-mvc-view-exercise + 1.0 + + + org.springframework.boot + spring-boot-starter-parent + 3.5.6 + + + + + 17 + 17 + 2.2.220 + 2.0 + + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + + org.yaml + snakeyaml + ${snakeyaml.version} + + + + com.h2database + h2 + runtime + ${h2.version} + + + + org.projectlombok + lombok + 1.18.36 + provided + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2025-07/spring-16-view/spring-mvc-view-exercise/src/main/java/ru/otus/spring/Main.java b/2025-07/spring-16-view/spring-mvc-view-exercise/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..09283e91 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-exercise/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,14 @@ +package ru.otus.spring; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Main { + + public static void main(String[] args) { + SpringApplication.run(Main.class); + System.out.printf("Чтобы проверить себя открывай: %n%s%n%s%n", + "http://localhost:8080", "http://localhost:8080/edit?id=1"); + } +} diff --git a/2025-07/spring-16-view/spring-mvc-view-exercise/src/main/java/ru/otus/spring/controller/NotFoundException.java b/2025-07/spring-16-view/spring-mvc-view-exercise/src/main/java/ru/otus/spring/controller/NotFoundException.java new file mode 100644 index 00000000..41b48826 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-exercise/src/main/java/ru/otus/spring/controller/NotFoundException.java @@ -0,0 +1,7 @@ +package ru.otus.spring.controller; + +class NotFoundException extends RuntimeException{ + + NotFoundException() { + } +} diff --git a/2025-07/spring-16-view/spring-mvc-view-exercise/src/main/java/ru/otus/spring/controller/PersonController.java b/2025-07/spring-16-view/spring-mvc-view-exercise/src/main/java/ru/otus/spring/controller/PersonController.java new file mode 100644 index 00000000..5a345bbb --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-exercise/src/main/java/ru/otus/spring/controller/PersonController.java @@ -0,0 +1,30 @@ +package ru.otus.spring.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repostory.PersonRepository; + +import java.util.List; + +@Controller +@RequiredArgsConstructor +public class PersonController { + + private final PersonRepository repository; + + @GetMapping("/") + public String listPage(Model model) { + List persons = repository.findAll(); + model.addAttribute("persons", persons); + return "list"; + } + + @GetMapping("/edit") + public String editPage(@RequestParam("id") long id, Model model) { + return null; + } +} diff --git a/2025-07/spring-16-view/spring-mvc-view-exercise/src/main/java/ru/otus/spring/domain/Person.java b/2025-07/spring-16-view/spring-mvc-view-exercise/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..e40fd3f9 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-exercise/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,22 @@ +package ru.otus.spring.domain; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Entity +public class Person { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + private String name; +} diff --git a/2025-07/spring-16-view/spring-mvc-view-exercise/src/main/java/ru/otus/spring/repostory/PersonRepository.java b/2025-07/spring-16-view/spring-mvc-view-exercise/src/main/java/ru/otus/spring/repostory/PersonRepository.java new file mode 100644 index 00000000..4fb88650 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-exercise/src/main/java/ru/otus/spring/repostory/PersonRepository.java @@ -0,0 +1,11 @@ +package ru.otus.spring.repostory; + +import org.springframework.data.repository.CrudRepository; +import ru.otus.spring.domain.Person; + +import java.util.List; + +public interface PersonRepository extends CrudRepository { + + List findAll(); +} diff --git a/2025-07/spring-16-view/spring-mvc-view-exercise/src/main/resources/application.yml b/2025-07/spring-16-view/spring-mvc-view-exercise/src/main/resources/application.yml new file mode 100644 index 00000000..c1f5d333 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-exercise/src/main/resources/application.yml @@ -0,0 +1,19 @@ +spring: + datasource: + url: jdbc:h2:mem:testdb + sql: + init: + mode: always + + + jpa: + open-in-view: false + generate-ddl: false + hibernate: + ddl-auto: none + + show-sql: true + +logging: + level: + ROOT: ERROR \ No newline at end of file diff --git a/2025-07/spring-16-view/spring-mvc-view-exercise/src/main/resources/data.sql b/2025-07/spring-16-view/spring-mvc-view-exercise/src/main/resources/data.sql new file mode 100644 index 00000000..7fa18c96 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-exercise/src/main/resources/data.sql @@ -0,0 +1,2 @@ +insert into person (id, name) values (1, 'Pushkin'); +insert into person (id, name) values (2, 'Lermontov'); \ No newline at end of file diff --git a/2025-07/spring-16-view/spring-mvc-view-exercise/src/main/resources/schema.sql b/2025-07/spring-16-view/spring-mvc-view-exercise/src/main/resources/schema.sql new file mode 100644 index 00000000..f36202f2 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-exercise/src/main/resources/schema.sql @@ -0,0 +1,4 @@ +create table person ( + id integer generated by default as identity, + name varchar(255), primary key (id) +); \ No newline at end of file diff --git a/2025-07/spring-16-view/spring-mvc-view-exercise/src/main/resources/templates/edit.html b/2025-07/spring-16-view/spring-mvc-view-exercise/src/main/resources/templates/edit.html new file mode 100644 index 00000000..87d8c8f1 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-exercise/src/main/resources/templates/edit.html @@ -0,0 +1,49 @@ + + + + + Edit person + + + + + + +
+

Person Info:

+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+ + + diff --git a/2025-07/spring-16-view/spring-mvc-view-exercise/src/main/resources/templates/list.html b/2025-07/spring-16-view/spring-mvc-view-exercise/src/main/resources/templates/list.html new file mode 100644 index 00000000..a5b52a8d --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-exercise/src/main/resources/templates/list.html @@ -0,0 +1,49 @@ + + + + + List of all persons + + + +

Persons:

+ + + + + + + + + + + + + + + + +
IDNameAction
1John Doe + Edit +
+ + diff --git a/2025-07/spring-16-view/spring-mvc-view-solution1/.gitignore b/2025-07/spring-16-view/spring-mvc-view-solution1/.gitignore new file mode 100644 index 00000000..4ea52072 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution1/.gitignore @@ -0,0 +1,24 @@ +target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ diff --git a/2025-07/spring-16-view/spring-mvc-view-solution1/pom.xml b/2025-07/spring-16-view/spring-mvc-view-solution1/pom.xml new file mode 100644 index 00000000..8cade1e0 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution1/pom.xml @@ -0,0 +1,75 @@ + + + 4.0.0 + + ru.otus + spring-mvc-view-solution1 + 1.0 + + + org.springframework.boot + spring-boot-starter-parent + 3.5.6 + + + + + 17 + 17 + 2.2.220 + 2.0 + + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + + org.yaml + snakeyaml + ${snakeyaml.version} + + + + com.h2database + h2 + runtime + ${h2.version} + + + + org.projectlombok + lombok + 1.18.36 + provided + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2025-07/spring-16-view/spring-mvc-view-solution1/src/main/java/ru/otus/spring/Main.java b/2025-07/spring-16-view/spring-mvc-view-solution1/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..c94edb10 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution1/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,13 @@ +package ru.otus.spring; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +//http://localhost:8080/edit?id=1 +@SpringBootApplication +public class Main { + + public static void main(String[] args) { + SpringApplication.run(Main.class); + } +} diff --git a/2025-07/spring-16-view/spring-mvc-view-solution1/src/main/java/ru/otus/spring/controller/NotFoundException.java b/2025-07/spring-16-view/spring-mvc-view-solution1/src/main/java/ru/otus/spring/controller/NotFoundException.java new file mode 100644 index 00000000..41b48826 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution1/src/main/java/ru/otus/spring/controller/NotFoundException.java @@ -0,0 +1,7 @@ +package ru.otus.spring.controller; + +class NotFoundException extends RuntimeException{ + + NotFoundException() { + } +} diff --git a/2025-07/spring-16-view/spring-mvc-view-solution1/src/main/java/ru/otus/spring/controller/PersonController.java b/2025-07/spring-16-view/spring-mvc-view-solution1/src/main/java/ru/otus/spring/controller/PersonController.java new file mode 100644 index 00000000..2953c703 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution1/src/main/java/ru/otus/spring/controller/PersonController.java @@ -0,0 +1,33 @@ +package ru.otus.spring.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repostory.PersonRepository; + +import java.util.List; + +@Controller +@RequiredArgsConstructor +public class PersonController { + + private final PersonRepository repository; + + @GetMapping("/") + public String listPage(Model model) { + List persons = repository.findAll(); + 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); + model.addAttribute("person", person); + return "edit"; + } +} diff --git a/2025-07/spring-16-view/spring-mvc-view-solution1/src/main/java/ru/otus/spring/domain/Person.java b/2025-07/spring-16-view/spring-mvc-view-solution1/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..e40fd3f9 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution1/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,22 @@ +package ru.otus.spring.domain; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Entity +public class Person { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + private String name; +} diff --git a/2025-07/spring-16-view/spring-mvc-view-solution1/src/main/java/ru/otus/spring/repostory/PersonRepository.java b/2025-07/spring-16-view/spring-mvc-view-solution1/src/main/java/ru/otus/spring/repostory/PersonRepository.java new file mode 100644 index 00000000..4fb88650 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution1/src/main/java/ru/otus/spring/repostory/PersonRepository.java @@ -0,0 +1,11 @@ +package ru.otus.spring.repostory; + +import org.springframework.data.repository.CrudRepository; +import ru.otus.spring.domain.Person; + +import java.util.List; + +public interface PersonRepository extends CrudRepository { + + List findAll(); +} diff --git a/2025-07/spring-16-view/spring-mvc-view-solution1/src/main/resources/application.yml b/2025-07/spring-16-view/spring-mvc-view-solution1/src/main/resources/application.yml new file mode 100644 index 00000000..c1f5d333 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution1/src/main/resources/application.yml @@ -0,0 +1,19 @@ +spring: + datasource: + url: jdbc:h2:mem:testdb + sql: + init: + mode: always + + + jpa: + open-in-view: false + generate-ddl: false + hibernate: + ddl-auto: none + + show-sql: true + +logging: + level: + ROOT: ERROR \ No newline at end of file diff --git a/2025-07/spring-16-view/spring-mvc-view-solution1/src/main/resources/data.sql b/2025-07/spring-16-view/spring-mvc-view-solution1/src/main/resources/data.sql new file mode 100644 index 00000000..7fa18c96 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution1/src/main/resources/data.sql @@ -0,0 +1,2 @@ +insert into person (id, name) values (1, 'Pushkin'); +insert into person (id, name) values (2, 'Lermontov'); \ No newline at end of file diff --git a/2025-07/spring-16-view/spring-mvc-view-solution1/src/main/resources/schema.sql b/2025-07/spring-16-view/spring-mvc-view-solution1/src/main/resources/schema.sql new file mode 100644 index 00000000..f36202f2 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution1/src/main/resources/schema.sql @@ -0,0 +1,4 @@ +create table person ( + id integer generated by default as identity, + name varchar(255), primary key (id) +); \ No newline at end of file diff --git a/2025-07/spring-16-view/spring-mvc-view-solution1/src/main/resources/templates/edit.html b/2025-07/spring-16-view/spring-mvc-view-solution1/src/main/resources/templates/edit.html new file mode 100644 index 00000000..7b3f5d6a --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution1/src/main/resources/templates/edit.html @@ -0,0 +1,48 @@ + + + + + Edit person + + + + + +
+

Person Info:

+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+ + + diff --git a/2025-07/spring-16-view/spring-mvc-view-solution1/src/main/resources/templates/list.html b/2025-07/spring-16-view/spring-mvc-view-solution1/src/main/resources/templates/list.html new file mode 100644 index 00000000..0d59a759 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution1/src/main/resources/templates/list.html @@ -0,0 +1,50 @@ + + + + + List of all persons + + + + +

Persons:

+ + + + + + + + + + + + + + + + +
IDNameAction
1John Doe + Edit +
+ + diff --git a/2025-07/spring-16-view/spring-mvc-view-solution2/.gitignore b/2025-07/spring-16-view/spring-mvc-view-solution2/.gitignore new file mode 100644 index 00000000..4ea52072 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution2/.gitignore @@ -0,0 +1,24 @@ +target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ diff --git a/2025-07/spring-16-view/spring-mvc-view-solution2/pom.xml b/2025-07/spring-16-view/spring-mvc-view-solution2/pom.xml new file mode 100644 index 00000000..177396d5 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution2/pom.xml @@ -0,0 +1,75 @@ + + + 4.0.0 + + ru.otus + spring-mvc-view-solution2 + 1.0 + + + org.springframework.boot + spring-boot-starter-parent + 3.5.6 + + + + + 17 + 17 + 2.2.220 + 2.0 + + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + + org.yaml + snakeyaml + ${snakeyaml.version} + + + + com.h2database + h2 + runtime + ${h2.version} + + + + org.projectlombok + lombok + 1.18.36 + provided + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2025-07/spring-16-view/spring-mvc-view-solution2/src/main/java/ru/otus/spring/Main.java b/2025-07/spring-16-view/spring-mvc-view-solution2/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..c94edb10 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution2/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,13 @@ +package ru.otus.spring; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +//http://localhost:8080/edit?id=1 +@SpringBootApplication +public class Main { + + public static void main(String[] args) { + SpringApplication.run(Main.class); + } +} diff --git a/2025-07/spring-16-view/spring-mvc-view-solution2/src/main/java/ru/otus/spring/controller/NotFoundException.java b/2025-07/spring-16-view/spring-mvc-view-solution2/src/main/java/ru/otus/spring/controller/NotFoundException.java new file mode 100644 index 00000000..41b48826 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution2/src/main/java/ru/otus/spring/controller/NotFoundException.java @@ -0,0 +1,7 @@ +package ru.otus.spring.controller; + +class NotFoundException extends RuntimeException{ + + NotFoundException() { + } +} diff --git a/2025-07/spring-16-view/spring-mvc-view-solution2/src/main/java/ru/otus/spring/controller/PersonController.java b/2025-07/spring-16-view/spring-mvc-view-solution2/src/main/java/ru/otus/spring/controller/PersonController.java new file mode 100644 index 00000000..ad22dbe8 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution2/src/main/java/ru/otus/spring/controller/PersonController.java @@ -0,0 +1,32 @@ +package ru.otus.spring.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repostory.PersonRepository; + +import java.util.List; + +@Controller +@RequiredArgsConstructor +public class PersonController { + + private final PersonRepository repository; + + @GetMapping("/") + public String listPage(Model model) { + List persons = repository.findAll(); + 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); + model.addAttribute("person", person); + return "edit"; + } +} diff --git a/2025-07/spring-16-view/spring-mvc-view-solution2/src/main/java/ru/otus/spring/domain/Person.java b/2025-07/spring-16-view/spring-mvc-view-solution2/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..e40fd3f9 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution2/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,22 @@ +package ru.otus.spring.domain; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Entity +public class Person { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + private String name; +} diff --git a/2025-07/spring-16-view/spring-mvc-view-solution2/src/main/java/ru/otus/spring/repostory/PersonRepository.java b/2025-07/spring-16-view/spring-mvc-view-solution2/src/main/java/ru/otus/spring/repostory/PersonRepository.java new file mode 100644 index 00000000..4fb88650 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution2/src/main/java/ru/otus/spring/repostory/PersonRepository.java @@ -0,0 +1,11 @@ +package ru.otus.spring.repostory; + +import org.springframework.data.repository.CrudRepository; +import ru.otus.spring.domain.Person; + +import java.util.List; + +public interface PersonRepository extends CrudRepository { + + List findAll(); +} diff --git a/2025-07/spring-16-view/spring-mvc-view-solution2/src/main/resources/application.yml b/2025-07/spring-16-view/spring-mvc-view-solution2/src/main/resources/application.yml new file mode 100644 index 00000000..c1f5d333 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution2/src/main/resources/application.yml @@ -0,0 +1,19 @@ +spring: + datasource: + url: jdbc:h2:mem:testdb + sql: + init: + mode: always + + + jpa: + open-in-view: false + generate-ddl: false + hibernate: + ddl-auto: none + + show-sql: true + +logging: + level: + ROOT: ERROR \ No newline at end of file diff --git a/2025-07/spring-16-view/spring-mvc-view-solution2/src/main/resources/data.sql b/2025-07/spring-16-view/spring-mvc-view-solution2/src/main/resources/data.sql new file mode 100644 index 00000000..7fa18c96 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution2/src/main/resources/data.sql @@ -0,0 +1,2 @@ +insert into person (id, name) values (1, 'Pushkin'); +insert into person (id, name) values (2, 'Lermontov'); \ No newline at end of file diff --git a/2025-07/spring-16-view/spring-mvc-view-solution2/src/main/resources/schema.sql b/2025-07/spring-16-view/spring-mvc-view-solution2/src/main/resources/schema.sql new file mode 100644 index 00000000..f36202f2 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution2/src/main/resources/schema.sql @@ -0,0 +1,4 @@ +create table person ( + id integer generated by default as identity, + name varchar(255), primary key (id) +); \ No newline at end of file diff --git a/2025-07/spring-16-view/spring-mvc-view-solution2/src/main/resources/templates/edit.html b/2025-07/spring-16-view/spring-mvc-view-solution2/src/main/resources/templates/edit.html new file mode 100644 index 00000000..ef643cff --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution2/src/main/resources/templates/edit.html @@ -0,0 +1,48 @@ + + + + + Edit person + + + + + +
+

Person Info:

+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+ + + diff --git a/2025-07/spring-16-view/spring-mvc-view-solution2/src/main/resources/templates/list.html b/2025-07/spring-16-view/spring-mvc-view-solution2/src/main/resources/templates/list.html new file mode 100644 index 00000000..a5b52a8d --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution2/src/main/resources/templates/list.html @@ -0,0 +1,49 @@ + + + + + List of all persons + + + +

Persons:

+ + + + + + + + + + + + + + + + +
IDNameAction
1John Doe + Edit +
+ + diff --git a/2025-07/spring-16-view/spring-mvc-view-solution3/.gitignore b/2025-07/spring-16-view/spring-mvc-view-solution3/.gitignore new file mode 100644 index 00000000..4ea52072 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution3/.gitignore @@ -0,0 +1,24 @@ +target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ diff --git a/2025-07/spring-16-view/spring-mvc-view-solution3/pom.xml b/2025-07/spring-16-view/spring-mvc-view-solution3/pom.xml new file mode 100644 index 00000000..e64a8fa3 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution3/pom.xml @@ -0,0 +1,75 @@ + + + 4.0.0 + + ru.otus + spring-mvc-view-solution3 + 1.0 + + + org.springframework.boot + spring-boot-starter-parent + 3.5.6 + + + + + 17 + 17 + 2.2.220 + 2.0 + + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + + org.yaml + snakeyaml + ${snakeyaml.version} + + + + com.h2database + h2 + runtime + ${h2.version} + + + + org.projectlombok + lombok + 1.18.36 + provided + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/java/ru/otus/spring/Main.java b/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..418ecb9b --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,14 @@ +package ru.otus.spring; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +//http://localhost:8080 +//http://localhost:8080/edit?id=1 +@SpringBootApplication +public class Main { + + public static void main(String[] args) { + SpringApplication.run(Main.class); + } +} diff --git a/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/java/ru/otus/spring/controller/NotFoundException.java b/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/java/ru/otus/spring/controller/NotFoundException.java new file mode 100644 index 00000000..41b48826 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/java/ru/otus/spring/controller/NotFoundException.java @@ -0,0 +1,7 @@ +package ru.otus.spring.controller; + +class NotFoundException extends RuntimeException{ + + NotFoundException() { + } +} diff --git a/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/java/ru/otus/spring/controller/PersonController.java b/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/java/ru/otus/spring/controller/PersonController.java new file mode 100644 index 00000000..ad22dbe8 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/java/ru/otus/spring/controller/PersonController.java @@ -0,0 +1,32 @@ +package ru.otus.spring.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repostory.PersonRepository; + +import java.util.List; + +@Controller +@RequiredArgsConstructor +public class PersonController { + + private final PersonRepository repository; + + @GetMapping("/") + public String listPage(Model model) { + List persons = repository.findAll(); + 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); + model.addAttribute("person", person); + return "edit"; + } +} diff --git a/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/java/ru/otus/spring/domain/Person.java b/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..e40fd3f9 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,22 @@ +package ru.otus.spring.domain; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Entity +public class Person { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + private String name; +} diff --git a/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/java/ru/otus/spring/repostory/PersonRepository.java b/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/java/ru/otus/spring/repostory/PersonRepository.java new file mode 100644 index 00000000..4fb88650 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/java/ru/otus/spring/repostory/PersonRepository.java @@ -0,0 +1,11 @@ +package ru.otus.spring.repostory; + +import org.springframework.data.repository.CrudRepository; +import ru.otus.spring.domain.Person; + +import java.util.List; + +public interface PersonRepository extends CrudRepository { + + List findAll(); +} diff --git a/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/resources/application.yml b/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/resources/application.yml new file mode 100644 index 00000000..c1f5d333 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/resources/application.yml @@ -0,0 +1,19 @@ +spring: + datasource: + url: jdbc:h2:mem:testdb + sql: + init: + mode: always + + + jpa: + open-in-view: false + generate-ddl: false + hibernate: + ddl-auto: none + + show-sql: true + +logging: + level: + ROOT: ERROR \ No newline at end of file diff --git a/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/resources/data.sql b/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/resources/data.sql new file mode 100644 index 00000000..7fa18c96 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/resources/data.sql @@ -0,0 +1,2 @@ +insert into person (id, name) values (1, 'Pushkin'); +insert into person (id, name) values (2, 'Lermontov'); \ No newline at end of file diff --git a/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/resources/schema.sql b/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/resources/schema.sql new file mode 100644 index 00000000..f36202f2 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/resources/schema.sql @@ -0,0 +1,4 @@ +create table person ( + id integer generated by default as identity, + name varchar(255), primary key (id) +); \ No newline at end of file diff --git a/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/resources/static/listmark.png b/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/resources/static/listmark.png new file mode 100644 index 00000000..f8eb391b Binary files /dev/null and b/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/resources/static/listmark.png differ diff --git a/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/resources/templates/edit.html b/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/resources/templates/edit.html new file mode 100644 index 00000000..ef643cff --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/resources/templates/edit.html @@ -0,0 +1,48 @@ + + + + + Edit person + + + + + +
+

Person Info:

+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+ + + diff --git a/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/resources/templates/list.html b/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/resources/templates/list.html new file mode 100644 index 00000000..e7983e80 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution3/src/main/resources/templates/list.html @@ -0,0 +1,49 @@ + + + + + List of all persons + + + +

Persons:

+ + + + + + + + + + + + + + + + +
IDNameAction
1John Doe + Edit +
+ + diff --git a/2025-07/spring-16-view/spring-mvc-view-solution4/.gitignore b/2025-07/spring-16-view/spring-mvc-view-solution4/.gitignore new file mode 100644 index 00000000..4ea52072 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution4/.gitignore @@ -0,0 +1,24 @@ +target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ diff --git a/2025-07/spring-16-view/spring-mvc-view-solution4/pom.xml b/2025-07/spring-16-view/spring-mvc-view-solution4/pom.xml new file mode 100644 index 00000000..aa638635 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution4/pom.xml @@ -0,0 +1,75 @@ + + + 4.0.0 + + ru.otus + spring-mvc-view-solution4 + 1.0 + + + org.springframework.boot + spring-boot-starter-parent + 3.5.6 + + + + + 17 + 17 + 2.2.220 + 2.0 + + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + + org.yaml + snakeyaml + ${snakeyaml.version} + + + + com.h2database + h2 + runtime + ${h2.version} + + + + org.projectlombok + lombok + 1.18.36 + provided + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/java/ru/otus/spring/Main.java b/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/java/ru/otus/spring/Main.java new file mode 100644 index 00000000..0335e618 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/java/ru/otus/spring/Main.java @@ -0,0 +1,15 @@ +package ru.otus.spring; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +//http://localhost:8080 +//http://localhost:8080/edit?id=1 +//http://localhost:8080/edit?id=111 +@SpringBootApplication +public class Main { + + public static void main(String[] args) { + SpringApplication.run(Main.class); + } +} diff --git a/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/java/ru/otus/spring/controller/GlobalExceptionHandler.java b/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/java/ru/otus/spring/controller/GlobalExceptionHandler.java new file mode 100644 index 00000000..f700c5e6 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/java/ru/otus/spring/controller/GlobalExceptionHandler.java @@ -0,0 +1,18 @@ +package ru.otus.spring.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.servlet.ModelAndView; + +@RequiredArgsConstructor +@ControllerAdvice +public class GlobalExceptionHandler { + + @ExceptionHandler(NotFoundException.class) + public ModelAndView handeNotFoundException(NotFoundException ex) { + return new ModelAndView("customError", + "errorText", "Person not found"); + } + +} diff --git a/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/java/ru/otus/spring/controller/NotFoundException.java b/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/java/ru/otus/spring/controller/NotFoundException.java new file mode 100644 index 00000000..35b57190 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/java/ru/otus/spring/controller/NotFoundException.java @@ -0,0 +1,7 @@ +package ru.otus.spring.controller; + +public class NotFoundException extends RuntimeException{ + + NotFoundException() { + } +} diff --git a/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/java/ru/otus/spring/controller/PersonController.java b/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/java/ru/otus/spring/controller/PersonController.java new file mode 100644 index 00000000..971bf323 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/java/ru/otus/spring/controller/PersonController.java @@ -0,0 +1,39 @@ +package ru.otus.spring.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import ru.otus.spring.domain.Person; +import ru.otus.spring.repostory.PersonRepository; + +import java.util.List; + +@Controller +@RequiredArgsConstructor +public class PersonController { + + private final PersonRepository repository; + + @GetMapping("/") + public String listPage(Model model) { + List persons = repository.findAll(); + 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); + model.addAttribute("person", person); + return "edit"; + } + + @PostMapping("/edit") + public String savePerson(Person person) { + repository.save(person); + return "redirect:/"; + } +} diff --git a/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/java/ru/otus/spring/domain/Person.java b/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/java/ru/otus/spring/domain/Person.java new file mode 100644 index 00000000..e40fd3f9 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/java/ru/otus/spring/domain/Person.java @@ -0,0 +1,22 @@ +package ru.otus.spring.domain; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Entity +public class Person { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + private String name; +} diff --git a/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/java/ru/otus/spring/repostory/PersonRepository.java b/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/java/ru/otus/spring/repostory/PersonRepository.java new file mode 100644 index 00000000..4fb88650 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/java/ru/otus/spring/repostory/PersonRepository.java @@ -0,0 +1,11 @@ +package ru.otus.spring.repostory; + +import org.springframework.data.repository.CrudRepository; +import ru.otus.spring.domain.Person; + +import java.util.List; + +public interface PersonRepository extends CrudRepository { + + List findAll(); +} diff --git a/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/resources/application.yml b/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/resources/application.yml new file mode 100644 index 00000000..c1f5d333 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/resources/application.yml @@ -0,0 +1,19 @@ +spring: + datasource: + url: jdbc:h2:mem:testdb + sql: + init: + mode: always + + + jpa: + open-in-view: false + generate-ddl: false + hibernate: + ddl-auto: none + + show-sql: true + +logging: + level: + ROOT: ERROR \ No newline at end of file diff --git a/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/resources/data.sql b/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/resources/data.sql new file mode 100644 index 00000000..7fa18c96 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/resources/data.sql @@ -0,0 +1,2 @@ +insert into person (id, name) values (1, 'Pushkin'); +insert into person (id, name) values (2, 'Lermontov'); \ No newline at end of file diff --git a/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/resources/schema.sql b/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/resources/schema.sql new file mode 100644 index 00000000..f36202f2 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/resources/schema.sql @@ -0,0 +1,4 @@ +create table person ( + id integer generated by default as identity, + name varchar(255), primary key (id) +); \ No newline at end of file diff --git a/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/resources/templates/customError.html b/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/resources/templates/customError.html new file mode 100644 index 00000000..a4550575 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/resources/templates/customError.html @@ -0,0 +1,34 @@ + + + + + List of all persons + + + + + +

Error:

+ Error text + + diff --git a/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/resources/templates/edit.html b/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/resources/templates/edit.html new file mode 100644 index 00000000..b5165f40 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/resources/templates/edit.html @@ -0,0 +1,49 @@ + + + + + Edit person + + + + + +
+

Person Info:

+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+ + + diff --git a/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/resources/templates/list.html b/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/resources/templates/list.html new file mode 100644 index 00000000..e93f2235 --- /dev/null +++ b/2025-07/spring-16-view/spring-mvc-view-solution4/src/main/resources/templates/list.html @@ -0,0 +1,49 @@ + + + + + List of all persons + + + +

Persons:

+ + + + + + + + + + + + + + + + +
IDNameAction
1John Doe + Edit +
+ +