diff --git a/.github/dco.yml b/.github/dco.yml new file mode 100644 index 000000000..37e411e1b --- /dev/null +++ b/.github/dco.yml @@ -0,0 +1,2 @@ +require: + members: false \ No newline at end of file diff --git a/README.md b/README.md index e15a3247f..c865c3b51 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,8 @@ cd spring-petclinic java -jar target/*.jar ``` +(On Windows, or if your shell doesn't expand the glob, you might need to specify the JAR file name explicitly on the command line at the end there.) + You can then access the Petclinic at . petclinic-screenshot @@ -155,7 +157,8 @@ Here is a list of them: The [issue tracker](https://github.com/spring-projects/spring-petclinic/issues) is the preferred channel for bug reports, feature requests and submitting pull requests. -For pull requests, editor preferences are available in the [editor config](.editorconfig) for easy use in common text editors. Read more and download plugins at . If you have not previously done so, please fill out and submit the [Contributor License Agreement](https://cla.pivotal.io/sign/spring). +For pull requests, editor preferences are available in the [editor config](.editorconfig) for easy use in common text editors. Read more and download plugins at . All commits must include a __Signed-off-by__ trailer at the end of each commit message to indicate that the contributor agrees to the Developer Certificate of Origin. +For additional details, please refer to the blog post [Hello DCO, Goodbye CLA: Simplifying Contributions to Spring](https://spring.io/blog/2025/01/06/hello-dco-goodbye-cla-simplifying-contributions-to-spring). ## License diff --git a/build.gradle b/build.gradle index 17c3763e2..b52d8e185 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '3.4.0' + id 'org.springframework.boot' version '3.4.2' id 'io.spring.dependency-management' version '1.1.6' id 'org.graalvm.buildtools.native' version '0.10.3' id 'org.cyclonedx.bom' version '1.10.0' diff --git a/pom.xml b/pom.xml index 9b9b815df..27fb9a6bd 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 3.4.0 + 3.4.2 diff --git a/src/main/java/org/springframework/samples/petclinic/owner/Owner.java b/src/main/java/org/springframework/samples/petclinic/owner/Owner.java index 675b2140e..c5ae067dc 100644 --- a/src/main/java/org/springframework/samples/petclinic/owner/Owner.java +++ b/src/main/java/org/springframework/samples/petclinic/owner/Owner.java @@ -57,7 +57,7 @@ public class Owner extends Person { @Column(name = "telephone") @NotBlank - @Pattern(regexp = "\\d{10}", message = "Telephone must be a 10-digit number") + @Pattern(regexp = "\\d{10}", message = "{telephone.invalid}") private String telephone; @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) diff --git a/src/main/java/org/springframework/samples/petclinic/owner/OwnerRepository.java b/src/main/java/org/springframework/samples/petclinic/owner/OwnerRepository.java index 5d7a40fbb..ae4659114 100644 --- a/src/main/java/org/springframework/samples/petclinic/owner/OwnerRepository.java +++ b/src/main/java/org/springframework/samples/petclinic/owner/OwnerRepository.java @@ -23,7 +23,6 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; -import org.springframework.transaction.annotation.Transactional; /** * Repository class for Owner domain objects All method names are compliant @@ -70,9 +69,4 @@ public interface OwnerRepository extends JpaRepository { */ Optional findById(@Nonnull Integer id); - /** - * Returns all the owners from data store - **/ - Page findAll(Pageable pageable); - } diff --git a/src/main/java/org/springframework/samples/petclinic/owner/PetController.java b/src/main/java/org/springframework/samples/petclinic/owner/PetController.java index fcf431bff..3234e39d6 100644 --- a/src/main/java/org/springframework/samples/petclinic/owner/PetController.java +++ b/src/main/java/org/springframework/samples/petclinic/owner/PetController.java @@ -129,7 +129,7 @@ class PetController { String petName = pet.getName(); - // checking if the pet name already exist for the owner + // checking if the pet name already exists for the owner if (StringUtils.hasText(petName)) { Pet existingPet = owner.getPet(petName, false); if (existingPet != null && !existingPet.getId().equals(pet.getId())) { @@ -146,10 +146,28 @@ class PetController { return VIEWS_PETS_CREATE_OR_UPDATE_FORM; } - owner.addPet(pet); - this.owners.save(owner); + updatePetDetails(owner, pet); redirectAttributes.addFlashAttribute("message", "Pet details has been edited"); return "redirect:/owners/{ownerId}"; } + /** + * Updates the pet details if it exists or adds a new pet to the owner. + * @param owner The owner of the pet + * @param pet The pet with updated details + */ + private void updatePetDetails(Owner owner, Pet pet) { + Pet existingPet = owner.getPet(pet.getId()); + if (existingPet != null) { + // Update existing pet's properties + existingPet.setName(pet.getName()); + existingPet.setBirthDate(pet.getBirthDate()); + existingPet.setType(pet.getType()); + } + else { + owner.addPet(pet); + } + this.owners.save(owner); + } + } diff --git a/src/main/java/org/springframework/samples/petclinic/owner/PetTypeFormatter.java b/src/main/java/org/springframework/samples/petclinic/owner/PetTypeFormatter.java index 4fa18da91..73bfa1ae1 100644 --- a/src/main/java/org/springframework/samples/petclinic/owner/PetTypeFormatter.java +++ b/src/main/java/org/springframework/samples/petclinic/owner/PetTypeFormatter.java @@ -15,7 +15,6 @@ */ package org.springframework.samples.petclinic.owner; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.format.Formatter; import org.springframework.stereotype.Component; @@ -38,7 +37,6 @@ public class PetTypeFormatter implements Formatter { private final OwnerRepository owners; - @Autowired public PetTypeFormatter(OwnerRepository owners) { this.owners = owners; } diff --git a/src/main/java/org/springframework/samples/petclinic/system/WebConfiguration.java b/src/main/java/org/springframework/samples/petclinic/system/WebConfiguration.java new file mode 100644 index 000000000..1ef32e4dc --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/system/WebConfiguration.java @@ -0,0 +1,60 @@ +package org.springframework.samples.petclinic.system; + +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.LocaleChangeInterceptor; +import org.springframework.web.servlet.i18n.SessionLocaleResolver; + +import java.util.Locale; + +/** + * Configures internationalization (i18n) support for the application. + * + *

+ * Handles loading language-specific messages, tracking the user's language, and allowing + * language changes via the URL parameter (e.g., ?lang=de). + *

+ * + * @author Anuj Ashok Potdar + */ +@Configuration +@SuppressWarnings("unused") +public class WebConfiguration implements WebMvcConfigurer { + + /** + * Uses session storage to remember the user’s language setting across requests. + * Defaults to English if nothing is specified. + * @return session-based {@link LocaleResolver} + */ + @Bean + public LocaleResolver localeResolver() { + SessionLocaleResolver resolver = new SessionLocaleResolver(); + resolver.setDefaultLocale(Locale.ENGLISH); + return resolver; + } + + /** + * Allows the app to switch languages using a URL parameter like + * ?lang=es. + * @return a {@link LocaleChangeInterceptor} that handles the change + */ + @Bean + public LocaleChangeInterceptor localeChangeInterceptor() { + LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor(); + interceptor.setParamName("lang"); + return interceptor; + } + + /** + * Registers the locale change interceptor so it can run on each request. + * @param registry where interceptors are added + */ + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(localeChangeInterceptor()); + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/vet/Vet.java b/src/main/java/org/springframework/samples/petclinic/vet/Vet.java index d8a1fc84d..00c7ec1c8 100644 --- a/src/main/java/org/springframework/samples/petclinic/vet/Vet.java +++ b/src/main/java/org/springframework/samples/petclinic/vet/Vet.java @@ -15,14 +15,13 @@ */ package org.springframework.samples.petclinic.vet; -import java.util.ArrayList; -import java.util.Collections; +import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; -import org.springframework.beans.support.MutableSortDefinition; -import org.springframework.beans.support.PropertyComparator; +import org.springframework.samples.petclinic.model.NamedEntity; import org.springframework.samples.petclinic.model.Person; import jakarta.persistence.Entity; @@ -59,9 +58,9 @@ public class Vet extends Person { @XmlElement public List getSpecialties() { - List sortedSpecs = new ArrayList<>(getSpecialtiesInternal()); - PropertyComparator.sort(sortedSpecs, new MutableSortDefinition("name", true, true)); - return Collections.unmodifiableList(sortedSpecs); + return getSpecialtiesInternal().stream() + .sorted(Comparator.comparing(NamedEntity::getName)) + .collect(Collectors.toList()); } public int getNrOfSpecialties() { diff --git a/src/main/resources/messages/messages.properties b/src/main/resources/messages/messages.properties index 173417a10..7b8b5dfd8 100644 --- a/src/main/resources/messages/messages.properties +++ b/src/main/resources/messages/messages.properties @@ -6,3 +6,43 @@ nonNumeric=must be all numeric duplicateFormSubmission=Duplicate form submission is not allowed typeMismatch.date=invalid date typeMismatch.birthDate=invalid date +owner=Owner +firstName=First Name +lastName=Last Name +address=Address +city=City +telephone=Telephone +owners=Owners +addOwner=Add Owner +findOwner=Find Owner +findOwners=Find Owners +updateOwner=Update Owner +vets=Veterinarians +name=Name +specialties=Specialties +none=none +pages=pages +first=First +next=Next +previous=Previous +last=Last +somethingHappened=Something happened... +pets=Pets +home=Home +error=Error +telephone.invalid=Telephone must be a 10-digit number +layoutTitle=PetClinic :: a Spring Framework demonstration +pet=Pet +birthDate=Birth Date +type=Type +previousVisits=Previous Visits +date=Date +description=Description +new=New +addVisit=Add Visit +editPet=Edit Pet +ownerInformation=Owner Information +visitDate=Visit Date +editOwner=Edit Owner +addNewPet=Add New Pet +petsAndVisits=Pets and Visits diff --git a/src/main/resources/messages/messages_de.properties b/src/main/resources/messages/messages_de.properties index 4828d85fe..8d208410c 100644 --- a/src/main/resources/messages/messages_de.properties +++ b/src/main/resources/messages/messages_de.properties @@ -6,4 +6,43 @@ nonNumeric=darf nur numerisch sein duplicateFormSubmission=Wiederholtes Absenden des Formulars ist nicht erlaubt typeMismatch.date=ung�ltiges Datum typeMismatch.birthDate=ung�ltiges Datum - +owner=Besitzer +firstName=Vorname +lastName=Nachname +address=Adresse +city=Stadt +telephone=Telefon +owners=Besitzer +addOwner=Besitzer hinzufügen +findOwner=Besitzer finden +findOwners=Besitzer suchen +updateOwner=Besitzer aktualisieren +vets=Tierärzte +name=Name +specialties=Fachgebiete +none=keine +pages=Seiten +first=Erste +next=Nächste +previous=Vorherige +last=Letzte +somethingHappened=Etwas ist passiert... +pets=Haustiere +home=Startseite +error=Fehler +telephone.invalid=Telefonnummer muss aus 10 Ziffern bestehen +layoutTitle=PetClinic :: eine Demonstration des Spring Frameworks +pet=Haustier +birthDate=Geburtsdatum +type=Typ +previousVisits=Frühere Besuche +date=Datum +description=Beschreibung +new=Neu +addVisit=Besuch hinzufügen +editPet=Haustier bearbeiten +ownerInformation=Besitzerinformationen +visitDate=Besuchsdatum +editOwner=Besitzer bearbeiten +addNewPet=Neues Haustier hinzufügen +petsAndVisits=Haustiere und Besuche diff --git a/src/main/resources/messages/messages_es.properties b/src/main/resources/messages/messages_es.properties index 116016fa3..91d5c9ebd 100644 --- a/src/main/resources/messages/messages_es.properties +++ b/src/main/resources/messages/messages_es.properties @@ -6,4 +6,43 @@ nonNumeric=Sólo debe contener numeros duplicateFormSubmission=No se permite el envío de formularios duplicados typeMismatch.date=Fecha invalida typeMismatch.birthDate=Fecha invalida - +owner=Propietario +firstName=Nombre +lastName=Apellido +address=Dirección +city=Ciudad +telephone=Teléfono +owners=Propietarios +addOwner=Añadir propietario +findOwner=Buscar propietario +findOwners=Buscar propietarios +updateOwner=Actualizar propietario +vets=Veterinarios +name=Nombre +specialties=Especialidades +none=ninguno +pages=páginas +first=Primero +next=Siguiente +previous=Anterior +last=Último +somethingHappened=Algo pasó... +pets=Mascotas +home=Inicio +error=Error +telephone.invalid=El número de teléfono debe tener 10 dígitos +layoutTitle=PetClinic :: una demostración de Spring Framework +pet=Mascota +birthDate=Fecha de nacimiento +type=Tipo +previousVisits=Visitas anteriores +date=Fecha +description=Descripción +new=Nuevo +addVisit=Agregar visita +editPet=Editar mascota +ownerInformation=Información del propietario +visitDate=Fecha de visita +editOwner=Editar propietario +addNewPet=Agregar nueva mascota +petsAndVisits=Mascotas y visitas diff --git a/src/main/resources/messages/messages_fa.properties b/src/main/resources/messages/messages_fa.properties index a68a21c77..2566b8949 100644 --- a/src/main/resources/messages/messages_fa.properties +++ b/src/main/resources/messages/messages_fa.properties @@ -6,4 +6,43 @@ nonNumeric=باید عددی باشد duplicateFormSubmission=ارسال تکراری فرم مجاز نیست typeMismatch.date=تاریخ نامعتبر typeMismatch.birthDate=تاریخ تولد نامعتبر - +owner=مالک +firstName=نام +lastName=نام خانوادگی +address=آدرس +city=شهر +telephone=تلفن +owners=مالکان +addOwner=افزودن مالک +findOwner=یافتن مالک +findOwners=یافتن مالکان +updateOwner=ویرایش مالک +vets=دامپزشکان +name=نام +specialties=تخصص‌ها +none=هیچ‌کدام +pages=صفحات +first=اول +next=بعدی +previous=قبلی +last=آخر +somethingHappened=مشکلی پیش آمد... +pets=حیوانات خانگی +home=خانه +error=خطا +telephone.invalid=شماره تلفن باید ۱۰ رقمی باشد +layoutTitle=PetClinic :: یک نمایش از Spring Framework +pet=حیوان خانگی +birthDate=تاریخ تولد +type=نوع +previousVisits=ویزیت‌های قبلی +date=تاریخ +description=توضیحات +new=جدید +addVisit=افزودن ویزیت +editPet=ویرایش حیوان خانگی +ownerInformation=اطلاعات مالک +visitDate=تاریخ ویزیت +editOwner=ویرایش مالک +addNewPet=افزودن حیوان خانگی جدید +petsAndVisits=حیوانات و ویزیت‌ها diff --git a/src/main/resources/messages/messages_ko.properties b/src/main/resources/messages/messages_ko.properties index 6cd27bfff..ca3ae5a05 100644 --- a/src/main/resources/messages/messages_ko.properties +++ b/src/main/resources/messages/messages_ko.properties @@ -6,3 +6,43 @@ nonNumeric=모두 숫자로 입력해야 합니다 duplicateFormSubmission=중복 제출은 허용되지 않습니다 typeMismatch.date=잘못된 날짜입니다 typeMismatch.birthDate=잘못된 날짜입니다 +owner=소유자 +firstName=이름 +lastName=성 +address=주소 +city=도시 +telephone=전화번호 +owners=소유자 목록 +addOwner=소유자 추가 +findOwner=소유자 찾기 +findOwners=소유자들 찾기 +updateOwner=소유자 수정 +vets=수의사 +name=이름 +specialties=전문 분야 +none=없음 +pages=페이지 +first=첫 번째 +next=다음 +previous=이전 +last=마지막 +somethingHappened=문제가 발생했습니다... +pets=반려동물 +home=홈 +error=오류 +telephone.invalid=전화번호는 10자리 숫자여야 합니다 +layoutTitle=PetClinic :: Spring Framework 데모 +pet=반려동물 +birthDate=생년월일 +type=종류 +previousVisits=이전 방문 +date=날짜 +description=설명 +new=새로운 +addVisit=방문 추가 +editPet=반려동물 수정 +ownerInformation=소유자 정보 +visitDate=방문 날짜 +editOwner=소유자 수정 +addNewPet=새 반려동물 추가 +petsAndVisits=반려동물 및 방문 diff --git a/src/main/resources/messages/messages_pt.properties b/src/main/resources/messages/messages_pt.properties index e9bc35a39..03f5cd531 100644 --- a/src/main/resources/messages/messages_pt.properties +++ b/src/main/resources/messages/messages_pt.properties @@ -6,3 +6,43 @@ nonNumeric=Deve ser tudo numerico duplicateFormSubmission=O envio duplicado de formulario nao e permitido typeMismatch.date=Data invalida typeMismatch.birthDate=Data de nascimento invalida +owner=Proprietário +firstName=Primeiro Nome +lastName=Sobrenome +address=Endereço +city=Cidade +telephone=Telefone +owners=Proprietários +addOwner=Adicionar proprietário +findOwner=Encontrar proprietário +findOwners=Encontrar proprietários +updateOwner=Atualizar proprietário +vets=Veterinários +name=Nome +specialties=Especialidades +none=nenhum +pages=páginas +first=Primeiro +next=Próximo +previous=Anterior +last=Último +somethingHappened=Algo aconteceu... +pets=Animais de estimação +home=Início +error=Erro +telephone.invalid=O número de telefone deve conter 10 dígitos +layoutTitle=PetClinic :: uma demonstração do Spring Framework +pet=Animal de estimação +birthDate=Data de nascimento +type=Tipo +previousVisits=Visitas anteriores +date=Data +description=Descrição +new=Novo +addVisit=Adicionar visita +editPet=Editar animal +ownerInformation=Informações do proprietário +visitDate=Data da visita +editOwner=Editar proprietário +addNewPet=Adicionar novo animal +petsAndVisits=Animais e visitas diff --git a/src/main/resources/messages/messages_ru.properties b/src/main/resources/messages/messages_ru.properties index 7e8d54d2d..b9ed998be 100644 --- a/src/main/resources/messages/messages_ru.properties +++ b/src/main/resources/messages/messages_ru.properties @@ -6,4 +6,43 @@ nonNumeric=должно быть все числовое значение duplicateFormSubmission=Дублирование формы не допускается typeMismatch.date=неправильная даные typeMismatch.birthDate=неправильная дата - +owner=Владелец +firstName=Имя +lastName=Фамилия +address=Адрес +city=Город +telephone=Телефон +owners=Владельцы +addOwner=Добавить владельца +findOwner=Найти владельца +findOwners=Найти владельцев +updateOwner=Обновить владельца +vets=Ветеринары +name=Имя +specialties=Специальности +none=нет +pages=страницы +first=Первый +next=Следующий +previous=Предыдущий +last=Последний +somethingHappened=Что-то пошло не так... +pets=Питомцы +home=Главная +error=Ошибка +telephone.invalid=Телефон должен содержать 10 цифр +layoutTitle=PetClinic :: демонстрация Spring Framework +pet=Питомец +birthDate=Дата рождения +type=Тип +previousVisits=Предыдущие визиты +date=Дата +description=Описание +new=Новый +addVisit=Добавить визит +editPet=Редактировать питомца +ownerInformation=Информация о владельце +visitDate=Дата визита +editOwner=Редактировать владельца +addNewPet=Добавить нового питомца +petsAndVisits=Питомцы и визиты diff --git a/src/main/resources/messages/messages_tr.properties b/src/main/resources/messages/messages_tr.properties index 1020566aa..ff9ffdabd 100644 --- a/src/main/resources/messages/messages_tr.properties +++ b/src/main/resources/messages/messages_tr.properties @@ -6,4 +6,43 @@ nonNumeric=sadece sayısal olmalıdır duplicateFormSubmission=Formun tekrar gönderilmesine izin verilmez typeMismatch.date=geçersiz tarih typeMismatch.birthDate=geçersiz tarih - +owner=Sahip +firstName=Ad +lastName=Soyad +address=Adres +city=Şehir +telephone=Telefon +owners=Sahipler +addOwner=Sahip Ekle +findOwner=Sahip Bul +findOwners=Sahipleri Bul +updateOwner=Sahip Güncelle +vets=Veterinerler +name=İsim +specialties=Uzmanlıklar +none=yok +pages=sayfalar +first=İlk +next=Sonraki +previous=Önceki +last=Son +somethingHappened=Bir şey oldu... +pets=Evcil Hayvanlar +home=Ana Sayfa +error=Hata +telephone.invalid=Telefon numarası 10 basamaklı olmalıdır +layoutTitle=PetClinic :: bir Spring Framework demosu +pet=Evcil Hayvan +birthDate=Doğum Tarihi +type=Tür +previousVisits=Önceki Ziyaretler +date=Tarih +description=Açıklama +new=Yeni +addVisit=Ziyaret Ekle +editPet=Evcil Hayvanı Düzenle +ownerInformation=Sahip Bilgileri +visitDate=Ziyaret Tarihi +editOwner=Sahibi Düzenle +addNewPet=Yeni Evcil Hayvan Ekle +petsAndVisits=Evcil Hayvanlar ve Ziyaretler diff --git a/src/main/resources/templates/error.html b/src/main/resources/templates/error.html index b9026690e..070e1c770 100644 --- a/src/main/resources/templates/error.html +++ b/src/main/resources/templates/error.html @@ -4,8 +4,8 @@ -

Something happened...

+

Something happened...

Exception message

- \ No newline at end of file + diff --git a/src/main/resources/templates/fragments/inputField.html b/src/main/resources/templates/fragments/inputField.html index 5aeebc9fb..68afbec7a 100644 --- a/src/main/resources/templates/fragments/inputField.html +++ b/src/main/resources/templates/fragments/inputField.html @@ -1,11 +1,11 @@ - +
- +
@@ -18,7 +18,7 @@ - Error + Error
diff --git a/src/main/resources/templates/fragments/layout.html b/src/main/resources/templates/fragments/layout.html index eb54d28ae..34e0a5496 100644 --- a/src/main/resources/templates/fragments/layout.html +++ b/src/main/resources/templates/fragments/layout.html @@ -1,5 +1,6 @@ - + @@ -10,7 +11,7 @@ - PetClinic :: a Spring Framework demonstration + PetClinic :: a Spring Framework demonstration