diff --git a/src/main/java/org/springframework/samples/petclinic/owner/OwnerController.java b/src/main/java/org/springframework/samples/petclinic/owner/OwnerController.java index 199ca361190..ec3f38612a5 100644 --- a/src/main/java/org/springframework/samples/petclinic/owner/OwnerController.java +++ b/src/main/java/org/springframework/samples/petclinic/owner/OwnerController.java @@ -1,24 +1,8 @@ -/* - * Copyright 2012-2025 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ package org.springframework.samples.petclinic.owner; +import jakarta.validation.Valid; import java.util.List; import java.util.Objects; -import java.util.Optional; - import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; @@ -33,18 +17,8 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.ModelAndView; - -import jakarta.validation.Valid; - import org.springframework.web.servlet.mvc.support.RedirectAttributes; -/** - * @author Juergen Hoeller - * @author Ken Krebs - * @author Arjen Poutsma - * @author Michael Isvy - * @author Wick Dynex - */ @Controller class OwnerController { @@ -63,12 +37,11 @@ public void setAllowedFields(WebDataBinder dataBinder) { @ModelAttribute("owner") public Owner findOwner(@PathVariable(name = "ownerId", required = false) Integer ownerId) { - return ownerId == null ? new Owner() - : this.owners.findById(ownerId) - .orElseThrow(() -> new IllegalArgumentException("Owner not found with id: " + ownerId - + ". Please ensure the ID is correct " + "and the owner exists in the database.")); + return ownerId == null ? new Owner() : this.owners.findById(ownerId) + .orElseThrow(() -> new IllegalArgumentException("Owner not found with id: " + ownerId + ".")); } + // =================== CREACIÓN =================== @GetMapping("/owners/new") public String initCreationForm() { return VIEWS_OWNER_CREATE_OR_UPDATE_FORM; @@ -86,38 +59,67 @@ public String processCreationForm(@Valid Owner owner, BindingResult result, Redi return "redirect:/owners/" + owner.getId(); } + // =================== BÚSQUEDA =================== @GetMapping("/owners/find") - public String initFindForm() { + public String initFindForm(Model model) { + model.addAttribute("owner", new Owner()); return "owners/findOwners"; } @GetMapping("/owners") - public String processFindForm(@RequestParam(defaultValue = "1") int page, Owner owner, BindingResult result, + public String processFindForm(Owner owner, BindingResult result, @RequestParam(defaultValue = "1") int page, Model model) { - // allow parameterless GET request for /owners to return all records String lastName = owner.getLastName(); - if (lastName == null) { - lastName = ""; // empty string signifies broadest possible search + if (lastName == null) + lastName = ""; + + Page ownersResults = findPaginatedForOwnersLastName(page, lastName); + + if (ownersResults.isEmpty()) { + result.rejectValue("lastName", "notFound", "not found"); + return "owners/findOwners"; } - // find owners by last name + if (ownersResults.getTotalElements() == 1) { + Owner singleOwner = ownersResults.iterator().next(); + return "redirect:/owners/" + singleOwner.getId(); + } + + return addPaginationModel(page, model, ownersResults); + } + + // Nuevo endpoint para buscar por apellido (parámetro opcional) + @GetMapping("/owners/searchByLastName") + public String searchByLastName(@RequestParam(name = "lastName", required = false) String lastName, + @RequestParam(defaultValue = "1") int page, Owner owner, BindingResult result, Model model) { + if (lastName == null) + lastName = ""; + owner.setLastName(lastName); + Page ownersResults = findPaginatedForOwnersLastName(page, lastName); + if (ownersResults.isEmpty()) { - // no owners found result.rejectValue("lastName", "notFound", "not found"); return "owners/findOwners"; } if (ownersResults.getTotalElements() == 1) { - // 1 owner found - owner = ownersResults.iterator().next(); - return "redirect:/owners/" + owner.getId(); + Owner singleOwner = ownersResults.iterator().next(); + return "redirect:/owners/" + singleOwner.getId(); } - // multiple owners found return addPaginationModel(page, model, ownersResults); } + // Nuevo endpoint para mostrar todos los propietarios + @GetMapping("/owners/showAll") + public String showAllOwners(@RequestParam(defaultValue = "1") int page, Model model) { + Pageable pageable = PageRequest.of(page - 1, 5); + Page ownersResults = owners.findAll(pageable); + return addPaginationModel(page, model, ownersResults); + } + + // =================== UTILIDADES =================== private String addPaginationModel(int page, Model model, Page paginated) { List listOwners = paginated.getContent(); model.addAttribute("currentPage", page); @@ -128,11 +130,11 @@ private String addPaginationModel(int page, Model model, Page paginated) } private Page findPaginatedForOwnersLastName(int page, String lastname) { - int pageSize = 5; - Pageable pageable = PageRequest.of(page - 1, pageSize); + Pageable pageable = PageRequest.of(page - 1, 5); return owners.findByLastNameStartingWith(lastname, pageable); } + // =================== EDICIÓN =================== @GetMapping("/owners/{ownerId}/edit") public String initUpdateOwnerForm() { return VIEWS_OWNER_CREATE_OR_UPDATE_FORM; @@ -158,17 +160,12 @@ public String processUpdateOwnerForm(@Valid Owner owner, BindingResult result, @ return "redirect:/owners/{ownerId}"; } - /** - * Custom handler for displaying an owner. - * @param ownerId the ID of the owner to display - * @return a ModelMap with the model attributes for the view - */ + // =================== DETALLE =================== @GetMapping("/owners/{ownerId}") public ModelAndView showOwner(@PathVariable("ownerId") int ownerId) { ModelAndView mav = new ModelAndView("owners/ownerDetails"); - Optional optionalOwner = this.owners.findById(ownerId); - Owner owner = optionalOwner.orElseThrow(() -> new IllegalArgumentException( - "Owner not found with id: " + ownerId + ". Please ensure the ID is correct ")); + Owner owner = this.owners.findById(ownerId) + .orElseThrow(() -> new IllegalArgumentException("Owner not found with id: " + ownerId)); mav.addObject(owner); return mav; } diff --git a/src/main/resources/messages/messages.properties b/src/main/resources/messages/messages.properties index 19356589594..b59c29c34a0 100644 --- a/src/main/resources/messages/messages.properties +++ b/src/main/resources/messages/messages.properties @@ -16,6 +16,7 @@ owners=Owners addOwner=Add Owner findOwner=Find Owner findOwners=Find Owners +showAllOwners=Show All Owners updateOwner=Update Owner vets=Veterinarians name=Name @@ -38,7 +39,7 @@ type=Type previousVisits=Previous Visits date=Date description=Description -new=New +new=New addVisit=Add Visit editPet=Edit Pet ownerInformation=Owner Information diff --git a/src/main/resources/messages/messages_de.properties b/src/main/resources/messages/messages_de.properties index 89a08eaad26..492ce8e5050 100644 --- a/src/main/resources/messages/messages_de.properties +++ b/src/main/resources/messages/messages_de.properties @@ -16,6 +16,7 @@ owners=Besitzer addOwner=Besitzer hinzufügen findOwner=Besitzer finden findOwners=Besitzer suchen +showAllOwners=Alle anzeigen updateOwner=Besitzer aktualisieren vets=Tierärzte name=Name diff --git a/src/main/resources/messages/messages_es.properties b/src/main/resources/messages/messages_es.properties index 911d7337ff3..6a83f05d40b 100644 --- a/src/main/resources/messages/messages_es.properties +++ b/src/main/resources/messages/messages_es.properties @@ -16,6 +16,7 @@ owners=Propietarios addOwner=Añadir propietario findOwner=Buscar propietario findOwners=Buscar propietarios +showAllOwners=Mostrar Todos updateOwner=Actualizar propietario vets=Veterinarios name=Nombre diff --git a/src/main/resources/messages/messages_fa.properties b/src/main/resources/messages/messages_fa.properties index 6d0994a92e9..e03a768f08f 100644 --- a/src/main/resources/messages/messages_fa.properties +++ b/src/main/resources/messages/messages_fa.properties @@ -16,6 +16,7 @@ owners=مالکان addOwner=افزودن مالک findOwner=یافتن مالک findOwners=یافتن مالکان +showAllOwners=نمایش همه updateOwner=ویرایش مالک vets=دامپزشکان name=نام diff --git a/src/main/resources/messages/messages_ko.properties b/src/main/resources/messages/messages_ko.properties index 6e2f4880aff..e6702e2150f 100644 --- a/src/main/resources/messages/messages_ko.properties +++ b/src/main/resources/messages/messages_ko.properties @@ -16,6 +16,7 @@ owners=소유자 목록 addOwner=소유자 추가 findOwner=소유자 찾기 findOwners=소유자들 찾기 +showAllOwners=모두 보기 updateOwner=소유자 수정 vets=수의사 name=이름 diff --git a/src/main/resources/messages/messages_pt.properties b/src/main/resources/messages/messages_pt.properties index 7eea4b9d167..76fac25abc8 100644 --- a/src/main/resources/messages/messages_pt.properties +++ b/src/main/resources/messages/messages_pt.properties @@ -16,6 +16,7 @@ owners=Proprietários addOwner=Adicionar proprietário findOwner=Encontrar proprietário findOwners=Encontrar proprietários +showAllOwners=Mostrar Todos updateOwner=Atualizar proprietário vets=Veterinários name=Nome diff --git a/src/main/resources/messages/messages_ru.properties b/src/main/resources/messages/messages_ru.properties index f06d2cb6c03..f3da46db35d 100644 --- a/src/main/resources/messages/messages_ru.properties +++ b/src/main/resources/messages/messages_ru.properties @@ -16,6 +16,7 @@ owners=Владельцы addOwner=Добавить владельца findOwner=Найти владельца findOwners=Найти владельцев +showAllOwners=Показать всех updateOwner=Обновить владельца vets=Ветеринары name=Имя diff --git a/src/main/resources/messages/messages_tr.properties b/src/main/resources/messages/messages_tr.properties index 2c806f9e6c9..4085cf53f78 100644 --- a/src/main/resources/messages/messages_tr.properties +++ b/src/main/resources/messages/messages_tr.properties @@ -16,6 +16,7 @@ owners=Sahipler addOwner=Sahip Ekle findOwner=Sahip Bul findOwners=Sahipleri Bul +showAllOwners=Tümünü Göster updateOwner=Sahip Güncelle vets=Veterinerler name=İsim diff --git a/src/main/resources/templates/owners/findOwners.html b/src/main/resources/templates/owners/findOwners.html index 703351c7d6b..8188988b053 100644 --- a/src/main/resources/templates/owners/findOwners.html +++ b/src/main/resources/templates/owners/findOwners.html @@ -1,35 +1,56 @@ - - - - - - -

Find Owners

- -
-
-
- -
- - -
-

Error

-
-
+ + + +

+ + +
+
+ +
+ + +
+

+
+
+
-
-
-
- -
-
- Add Owner - - - - - - \ No newline at end of file +
+
+ + + +
+
+ + + diff --git a/src/test/java/org/springframework/samples/petclinic/owner/OwnerControllerTests.java b/src/test/java/org/springframework/samples/petclinic/owner/OwnerControllerTests.java index 558b9ae4a92..d7143944d82 100644 --- a/src/test/java/org/springframework/samples/petclinic/owner/OwnerControllerTests.java +++ b/src/test/java/org/springframework/samples/petclinic/owner/OwnerControllerTests.java @@ -16,23 +16,6 @@ package org.springframework.samples.petclinic.owner; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.DisabledInNativeImage; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.Pageable; -import org.springframework.test.context.aot.DisabledInAotMode; -import org.springframework.test.context.bean.override.mockito.MockitoBean; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; - -import java.time.LocalDate; -import java.util.List; -import java.util.Optional; - import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.hasItem; @@ -49,6 +32,22 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import java.time.LocalDate; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledInNativeImage; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; +import org.springframework.test.context.aot.DisabledInAotMode; +import org.springframework.test.context.bean.override.mockito.MockitoBean; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + /** * Test class for {@link OwnerController} * @@ -89,7 +88,6 @@ private Owner george() { @BeforeEach void setup() { - Owner george = george(); given(this.owners.findByLastNameStartingWith(eq("Franklin"), any(Pageable.class))) .willReturn(new PageImpl<>(List.of(george))); @@ -98,7 +96,6 @@ void setup() { Visit visit = new Visit(); visit.setDate(LocalDate.now()); george.getPet("Max").getVisits().add(visit); - } @Test @@ -164,7 +161,6 @@ void processFindFormNoOwnersFound() throws Exception { .andExpect(model().attributeHasFieldErrors("owner", "lastName")) .andExpect(model().attributeHasFieldErrorCode("owner", "lastName", "notFound")) .andExpect(view().name("owners/findOwners")); - } @Test @@ -248,4 +244,44 @@ void processUpdateOwnerFormWithIdMismatch() throws Exception { .andExpect(flash().attributeExists("error")); } + @Test + void processFindByLastNameEndpointSuccess() throws Exception { + Owner george = george(); + Page page = new PageImpl<>(List.of(george)); + + // Simula búsqueda solo por apellido + when(this.owners.findByLastNameStartingWith(eq("Franklin"), any(Pageable.class))).thenReturn(page); + + mockMvc.perform(get("/owners/searchByLastName").param("lastName", "Franklin")) + .andExpect(status().is3xxRedirection()) + .andExpect(view().name("redirect:/owners/" + TEST_OWNER_ID)); + } + + @Test + void processFindByLastNameEndpointNoResults() throws Exception { + Page emptyPage = new PageImpl<>(List.of()); + when(this.owners.findByLastNameStartingWith(eq("Unknown"), any(Pageable.class))).thenReturn(emptyPage); + + mockMvc.perform(get("/owners/searchByLastName").param("lastName", "Unknown")) + .andExpect(status().isOk()) + .andExpect(model().attributeHasFieldErrors("owner", "lastName")) + .andExpect(model().attributeHasFieldErrorCode("owner", "lastName", "notFound")) + .andExpect(view().name("owners/findOwners")); + } + + @Test + void showAllOwnersEndpointSuccess() throws Exception { + Owner george = george(); + Page page = new PageImpl<>(List.of(george, new Owner(), new Owner())); + + when(this.owners.findAll(any(Pageable.class))).thenReturn(page); + + mockMvc.perform(get("/owners/showAll").param("page", "1")) + .andExpect(status().isOk()) + .andExpect(model().attributeExists("listOwners")) + .andExpect(model().attribute("currentPage", 1)) + .andExpect(model().attribute("totalPages", page.getTotalPages())) + .andExpect(view().name("owners/ownersList")); + } + }