diff --git a/.editorconfig b/.editorconfig index 8d67bc7a5..2513d2a34 100644 --- a/.editorconfig +++ b/.editorconfig @@ -10,3 +10,12 @@ indent_style = space [*.{java,xml}] indent_size = 4 trim_trailing_whitespace = true +indent_style = tab +tab_width = 4 + +[{pom,wro}.xml] +indent_size = 2 +indent_style = space + +[*.{html,sql,less}] +indent_size = 2 diff --git a/.gitignore b/.gitignore index 559982f3d..191769767 100644 --- a/.gitignore +++ b/.gitignore @@ -8,9 +8,5 @@ target/* *.iml /target .sts4-cache/ -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json +.vscode _site/ diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java index c32394f14..89964d141 100644 --- a/.mvn/wrapper/MavenWrapperDownloader.java +++ b/.mvn/wrapper/MavenWrapperDownloader.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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, @@ -20,7 +20,7 @@ import java.util.Properties; public class MavenWrapperDownloader { - private static final String WRAPPER_VERSION = "0.5.5"; + private static final String WRAPPER_VERSION = "0.5.6"; /** * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. */ diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar index 0d5e64988..2cc7d4a55 100644 Binary files a/.mvn/wrapper/maven-wrapper.jar and b/.mvn/wrapper/maven-wrapper.jar differ diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index 7d59a01f2..2743cab67 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1,2 +1,3 @@ -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.2/apache-maven-3.6.2-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar + diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 559c53805..000000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "java", - "name": "Debug (Launch)-PetClinicApplication", - "request": "launch", - "cwd": "${workspaceFolder}", - "console": "internalConsole", - "stopOnEntry": false, - "mainClass": "org.springframework.samples.petclinic.PetClinicApplication", - "projectName": "spring-petclinic", - "args": "" - }, - { - "type": "java", - "name": "Debug (Attach)", - "request": "attach", - "hostName": "localhost", - "port": 0 - } - ] -} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index c5f3f6b9c..000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "java.configuration.updateBuildConfiguration": "interactive" -} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index fabd5c416..000000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - // See https://go.microsoft.com/fwlink/?LinkId=733558 - // for the documentation about the tasks.json format - "version": "2.0.0", - "tasks": [ - { - "label": "verify", - "type": "shell", - "command": "mvn -B verify", - "group": "build" - }, - { - "label": "test", - "type": "shell", - "command": "mvn -B test", - "group": "test" - } - ] -} diff --git a/docker-compose.yml b/docker-compose.yml index 0f4a7fc30..5166fe90f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,7 +3,10 @@ mysql: ports: - "3306:3306" environment: - - MYSQL_ROOT_PASSWORD=petclinic + - MYSQL_ROOT_PASSWORD= + - MYSQL_ALLOW_EMPTY_PASSWORD=true + - MYSQL_USER=petclinic + - MYSQL_PASSWORD=petclinic - MYSQL_DATABASE=petclinic volumes: - "./conf.d:/etc/mysql/conf.d:ro" diff --git a/mvnw b/mvnw index d2f0ea380..2c90d17e4 100755 --- a/mvnw +++ b/mvnw @@ -8,7 +8,7 @@ # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# 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 @@ -19,7 +19,7 @@ # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- -# Maven2 Start Up Batch script +# Maven Start Up Batch script # # Required ENV vars: # ------------------ @@ -212,9 +212,9 @@ else echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." fi if [ -n "$MVNW_REPOURL" ]; then - jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar" + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" else - jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar" + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" fi while IFS="=" read key value; do case "$key" in (wrapperUrl) jarUrl="$value"; break ;; @@ -246,7 +246,7 @@ else else curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f fi - + else if [ "$MVNW_VERBOSE" = true ]; then echo "Falling back to using Java to download" diff --git a/mvnw.cmd b/mvnw.cmd index b26ab24f0..0d34af450 100644 --- a/mvnw.cmd +++ b/mvnw.cmd @@ -7,7 +7,7 @@ @REM "License"); you may not use this file except in compliance @REM with the License. You may obtain a copy of the License at @REM -@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM https://www.apache.org/licenses/LICENSE-2.0' @REM @REM Unless required by applicable law or agreed to in writing, @REM software distributed under the License is distributed on an @@ -18,7 +18,7 @@ @REM ---------------------------------------------------------------------------- @REM ---------------------------------------------------------------------------- -@REM Maven2 Start Up Batch script +@REM Maven Start Up Batch script @REM @REM Required ENV vars: @REM JAVA_HOME - location of a JDK home dir @@ -26,7 +26,7 @@ @REM Optional ENV vars @REM M2_HOME - location of maven2's installed home dir @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven @REM e.g. to debug Maven itself, use @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 @@ -120,7 +120,7 @@ SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar" +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B @@ -134,7 +134,7 @@ if exist %WRAPPER_JAR% ( ) ) else ( if not "%MVNW_REPOURL%" == "" ( - SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar" + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" ) if "%MVNW_VERBOSE%" == "true" ( echo Couldn't find %WRAPPER_JAR%, downloading it ... diff --git a/pom.xml b/pom.xml index aab683b24..4941843ad 100644 --- a/pom.xml +++ b/pom.xml @@ -1,16 +1,16 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 org.springframework.samples spring-petclinic - 2.2.0.BUILD-SNAPSHOT + 2.4.0.BUILD-SNAPSHOT org.springframework.boot spring-boot-starter-parent - 2.2.1.RELEASE + 2.4.1 petclinic @@ -28,7 +28,8 @@ 1.8.0 0.8.5 - + 0.0.4.RELEASE + 0.0.25 @@ -49,6 +50,10 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.boot + spring-boot-starter-validation + org.springframework.boot spring-boot-starter-thymeleaf @@ -65,10 +70,10 @@ - + - org.hsqldb - hsqldb + com.h2database + h2 runtime @@ -109,18 +114,6 @@ - - - org.junit.jupiter - junit-jupiter-engine - test - - - org.mockito - mockito-junit-jupiter - test - - org.springframework.boot spring-boot-devtools @@ -130,6 +123,53 @@ + + io.spring.javaformat + spring-javaformat-maven-plugin + ${spring-format.version} + + + validate + + validate + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + 3.1.1 + + + com.puppycrawl.tools + checkstyle + 8.32 + + + io.spring.nohttp + nohttp-checkstyle + ${nohttp-checkstyle.version} + + + + + nohttp-checkstyle-validation + validate + + src/checkstyle/nohttp-checkstyle.xml + src/checkstyle/nohttp-checkstyle-suppressions.xml + UTF-8 + ${basedir} + **/* + **/.git/**/*,**/.idea/**/*,**/target/**/,**/.flattened-pom.xml,**/*.class + + + check + + + + org.springframework.boot spring-boot-maven-plugin @@ -228,7 +268,6 @@ - Apache License, Version 2.0 @@ -274,4 +313,60 @@ + + + m2e + + + m2e.version + + + + + + + + org.eclipse.m2e + lifecycle-mapping + 1.0.0 + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + [1,) + + check + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + [1,) + + build-info + + + + + + + + + + + + + + + + diff --git a/push-to-pws/button.yml b/push-to-pws/button.yml deleted file mode 100644 index e85329d59..000000000 --- a/push-to-pws/button.yml +++ /dev/null @@ -1 +0,0 @@ -repo: https://github.com/spring-projects/spring-petclinic.git diff --git a/readme.md b/readme.md index 34c8e8b84..ff6d2be15 100644 --- a/readme.md +++ b/readme.md @@ -1,9 +1,4 @@ -# Spring PetClinic Sample Application [![Build Status](https://travis-ci.org/spring-projects/spring-petclinic.png?branch=master)](https://travis-ci.org/spring-projects/spring-petclinic/) -Deploy this sample application to Pivotal Web Services: - - - Push - +# Spring PetClinic Sample Application [![Build Status](https://travis-ci.org/spring-projects/spring-petclinic.png?branch=main)](https://travis-ci.org/spring-projects/spring-petclinic/) ## Understanding the Spring Petclinic application with a few diagrams See the presentation here @@ -35,17 +30,19 @@ Our issue tracker is available here: https://github.com/spring-projects/spring-p ## Database configuration -In its default configuration, Petclinic uses an in-memory database (HSQLDB) which -gets populated at startup with data. A similar setup is provided for MySql in case a persistent database configuration is needed. -Note that whenever the database type is changed, the app needs to be run with a different profile: `spring.profiles.active=mysql` for MySql. +In its default configuration, Petclinic uses an in-memory database (H2) which +gets populated at startup with data. The h2 console is automatically exposed at `http://localhost:8080/h2-console` +and it is possible to inspect the content of the database using the `jdbc:h2:mem:testdb` url. + +A similar setup is provided for MySql in case a persistent database configuration is needed. Note that whenever the database type is changed, the app needs to be run with a different profile: `spring.profiles.active=mysql` for MySql. You could start MySql locally with whatever installer works for your OS, or with docker: ``` -docker run -e MYSQL_ROOT_PASSWORD=petclinic -e MYSQL_DATABASE=petclinic -p 3306:3306 mysql:5.7.8 +docker run -e MYSQL_USER=petclinic -e MYSQL_PASSWORD=petclinic -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=petclinic -p 3306:3306 mysql:5.7.8 ``` -Further documentation is provided [here](https://github.com/spring-projects/spring-petclinic/blob/master/src/main/resources/db/mysql/petclinic_db_setup_mysql.txt). +Further documentation is provided [here](https://github.com/spring-projects/spring-petclinic/blob/main/src/main/resources/db/mysql/petclinic_db_setup_mysql.txt). ## Working with Petclinic in your IDE @@ -63,43 +60,39 @@ The following items should be installed in your system: ### Steps: 1) On the command line -``` -git clone https://github.com/spring-projects/spring-petclinic.git -``` + ``` + git clone https://github.com/spring-projects/spring-petclinic.git + ``` 2) Inside Eclipse or STS -``` -File -> Import -> Maven -> Existing Maven project -``` + ``` + File -> Import -> Maven -> Existing Maven project + ``` -Then either build on the command line `./mvnw generate-resources` or using the Eclipse launcher (right click on project and `Run As -> Maven install`) to generate the css. Run the application main method by right clicking on it and choosing `Run As -> Java Application`. + Then either build on the command line `./mvnw generate-resources` or using the Eclipse launcher (right click on project and `Run As -> Maven install`) to generate the css. Run the application main method by right clicking on it and choosing `Run As -> Java Application`. 3) Inside IntelliJ IDEA + In the main menu, choose `File -> Open` and select the Petclinic [pom.xml](pom.xml). Click on the `Open` button. -In the main menu, choose `File -> Open` and select the Petclinic [pom.xml](pom.xml). Click on the `Open` button. + CSS files are generated from the Maven build. You can either build them on the command line `./mvnw generate-resources` or right click on the `spring-petclinic` project then `Maven -> Generates sources and Update Folders`. -CSS files are generated from the Maven build. You can either build them on the command line `./mvnw generate-resources` -or right click on the `spring-petclinic` project then `Maven -> Generates sources and Update Folders`. - -A run configuration named `PetClinicApplication` should have been created for you if you're using a recent Ultimate -version. Otherwise, run the application by right clicking on the `PetClinicApplication` main class and choosing -`Run 'PetClinicApplication'`. + A run configuration named `PetClinicApplication` should have been created for you if you're using a recent Ultimate version. Otherwise, run the application by right clicking on the `PetClinicApplication` main class and choosing `Run 'PetClinicApplication'`. 4) Navigate to Petclinic -Visit [http://localhost:8080](http://localhost:8080) in your browser. + Visit [http://localhost:8080](http://localhost:8080) in your browser. ## Looking for something in particular? |Spring Boot Configuration | Class or Java property files | |--------------------------|---| -|The Main Class | [PetClinicApplication](https://github.com/spring-projects/spring-petclinic/blob/master/src/main/java/org/springframework/samples/petclinic/PetClinicApplication.java) | -|Properties Files | [application.properties](https://github.com/spring-projects/spring-petclinic/blob/master/src/main/resources) | -|Caching | [CacheConfiguration](https://github.com/spring-projects/spring-petclinic/blob/master/src/main/java/org/springframework/samples/petclinic/system/CacheConfiguration.java) | +|The Main Class | [PetClinicApplication](https://github.com/spring-projects/spring-petclinic/blob/main/src/main/java/org/springframework/samples/petclinic/PetClinicApplication.java) | +|Properties Files | [application.properties](https://github.com/spring-projects/spring-petclinic/blob/main/src/main/resources) | +|Caching | [CacheConfiguration](https://github.com/spring-projects/spring-petclinic/blob/main/src/main/java/org/springframework/samples/petclinic/system/CacheConfiguration.java) | ## Interesting Spring Petclinic branches and forks -The Spring Petclinic master branch in the main [spring-projects](https://github.com/spring-projects/spring-petclinic) +The Spring Petclinic "main" branch in the [spring-projects](https://github.com/spring-projects/spring-petclinic) GitHub org is the "canonical" implementation, currently based on Spring Boot and Thymeleaf. There are [quite a few forks](https://spring-petclinic.github.io/docs/forks.html) in a special GitHub org [spring-petclinic](https://github.com/spring-petclinic). If you have a special interest in a different technology stack diff --git a/src/checkstyle/nohttp-checkstyle-suppressions.xml b/src/checkstyle/nohttp-checkstyle-suppressions.xml new file mode 100644 index 000000000..1b40e8b3f --- /dev/null +++ b/src/checkstyle/nohttp-checkstyle-suppressions.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/src/checkstyle/nohttp-checkstyle.xml b/src/checkstyle/nohttp-checkstyle.xml new file mode 100644 index 000000000..e6205127b --- /dev/null +++ b/src/checkstyle/nohttp-checkstyle.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/src/main/java/org/springframework/samples/petclinic/PetClinicApplication.java b/src/main/java/org/springframework/samples/petclinic/PetClinicApplication.java index e09f0bdeb..191253587 100644 --- a/src/main/java/org/springframework/samples/petclinic/PetClinicApplication.java +++ b/src/main/java/org/springframework/samples/petclinic/PetClinicApplication.java @@ -28,8 +28,8 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication(proxyBeanMethods = false) public class PetClinicApplication { - public static void main(String[] args) { - SpringApplication.run(PetClinicApplication.class, args); - } + public static void main(String[] args) { + SpringApplication.run(PetClinicApplication.class, args); + } } diff --git a/src/main/java/org/springframework/samples/petclinic/model/BaseEntity.java b/src/main/java/org/springframework/samples/petclinic/model/BaseEntity.java index 8350eb744..4cb9ffc0c 100644 --- a/src/main/java/org/springframework/samples/petclinic/model/BaseEntity.java +++ b/src/main/java/org/springframework/samples/petclinic/model/BaseEntity.java @@ -31,20 +31,21 @@ import javax.persistence.MappedSuperclass; */ @MappedSuperclass public class BaseEntity implements Serializable { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Integer id; - public Integer getId() { - return id; - } + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; - public void setId(Integer id) { - this.id = id; - } + public Integer getId() { + return id; + } - public boolean isNew() { - return this.id == null; - } + public void setId(Integer id) { + this.id = id; + } + + public boolean isNew() { + return this.id == null; + } } diff --git a/src/main/java/org/springframework/samples/petclinic/model/NamedEntity.java b/src/main/java/org/springframework/samples/petclinic/model/NamedEntity.java index cc596a194..088e52e81 100644 --- a/src/main/java/org/springframework/samples/petclinic/model/NamedEntity.java +++ b/src/main/java/org/springframework/samples/petclinic/model/NamedEntity.java @@ -18,10 +18,9 @@ package org.springframework.samples.petclinic.model; import javax.persistence.Column; import javax.persistence.MappedSuperclass; - /** - * Simple JavaBean domain object adds a name property to BaseEntity. Used as a base class for objects - * needing these properties. + * Simple JavaBean domain object adds a name property to BaseEntity. Used as + * a base class for objects needing these properties. * * @author Ken Krebs * @author Juergen Hoeller @@ -29,20 +28,20 @@ import javax.persistence.MappedSuperclass; @MappedSuperclass public class NamedEntity extends BaseEntity { - @Column(name = "name") - private String name; + @Column(name = "name") + private String name; - public String getName() { - return this.name; - } + public String getName() { + return this.name; + } - public void setName(String name) { - this.name = name; - } + public void setName(String name) { + this.name = name; + } - @Override - public String toString() { - return this.getName(); - } + @Override + public String toString() { + return this.getName(); + } } diff --git a/src/main/java/org/springframework/samples/petclinic/model/Person.java b/src/main/java/org/springframework/samples/petclinic/model/Person.java index 883376fbc..15fabacc3 100644 --- a/src/main/java/org/springframework/samples/petclinic/model/Person.java +++ b/src/main/java/org/springframework/samples/petclinic/model/Person.java @@ -27,28 +27,28 @@ import javax.validation.constraints.NotEmpty; @MappedSuperclass public class Person extends BaseEntity { - @Column(name = "first_name") - @NotEmpty - private String firstName; + @Column(name = "first_name") + @NotEmpty + private String firstName; - @Column(name = "last_name") - @NotEmpty - private String lastName; + @Column(name = "last_name") + @NotEmpty + private String lastName; - public String getFirstName() { - return this.firstName; - } + public String getFirstName() { + return this.firstName; + } - public void setFirstName(String firstName) { - this.firstName = firstName; - } + public void setFirstName(String firstName) { + this.firstName = firstName; + } - public String getLastName() { - return this.lastName; - } + public String getLastName() { + return this.lastName; + } - public void setLastName(String lastName) { - this.lastName = lastName; - } + public void setLastName(String lastName) { + this.lastName = lastName; + } } diff --git a/src/main/java/org/springframework/samples/petclinic/model/package-info.java b/src/main/java/org/springframework/samples/petclinic/model/package-info.java index 13c1673d5..37d6295e8 100644 --- a/src/main/java/org/springframework/samples/petclinic/model/package-info.java +++ b/src/main/java/org/springframework/samples/petclinic/model/package-info.java @@ -18,4 +18,3 @@ * The classes in this package represent utilities used by the domain. */ package org.springframework.samples.petclinic.model; - 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 5b1b7fb36..61083bc8d 100644 --- a/src/main/java/org/springframework/samples/petclinic/owner/Owner.java +++ b/src/main/java/org/springframework/samples/petclinic/owner/Owner.java @@ -45,108 +45,106 @@ import org.springframework.samples.petclinic.model.Person; @Entity @Table(name = "owners") public class Owner extends Person { - @Column(name = "address") - @NotEmpty - private String address; - @Column(name = "city") - @NotEmpty - private String city; + @Column(name = "address") + @NotEmpty + private String address; - @Column(name = "telephone") - @NotEmpty - @Digits(fraction = 0, integer = 10) - private String telephone; + @Column(name = "city") + @NotEmpty + private String city; - @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner") - private Set pets; + @Column(name = "telephone") + @NotEmpty + @Digits(fraction = 0, integer = 10) + private String telephone; - public String getAddress() { - return this.address; - } + @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner") + private Set pets; - public void setAddress(String address) { - this.address = address; - } + public String getAddress() { + return this.address; + } - public String getCity() { - return this.city; - } + public void setAddress(String address) { + this.address = address; + } - public void setCity(String city) { - this.city = city; - } + public String getCity() { + return this.city; + } - public String getTelephone() { - return this.telephone; - } + public void setCity(String city) { + this.city = city; + } - public void setTelephone(String telephone) { - this.telephone = telephone; - } + public String getTelephone() { + return this.telephone; + } - protected Set getPetsInternal() { - if (this.pets == null) { - this.pets = new HashSet<>(); - } - return this.pets; - } + public void setTelephone(String telephone) { + this.telephone = telephone; + } - protected void setPetsInternal(Set pets) { - this.pets = pets; - } + protected Set getPetsInternal() { + if (this.pets == null) { + this.pets = new HashSet<>(); + } + return this.pets; + } - public List getPets() { - List sortedPets = new ArrayList<>(getPetsInternal()); - PropertyComparator.sort(sortedPets, - new MutableSortDefinition("name", true, true)); - return Collections.unmodifiableList(sortedPets); - } + protected void setPetsInternal(Set pets) { + this.pets = pets; + } - public void addPet(Pet pet) { - if (pet.isNew()) { - getPetsInternal().add(pet); - } - pet.setOwner(this); - } + public List getPets() { + List sortedPets = new ArrayList<>(getPetsInternal()); + PropertyComparator.sort(sortedPets, new MutableSortDefinition("name", true, true)); + return Collections.unmodifiableList(sortedPets); + } - /** - * Return the Pet with the given name, or null if none found for this Owner. - * - * @param name to test - * @return true if pet name is already in use - */ - public Pet getPet(String name) { - return getPet(name, false); - } + public void addPet(Pet pet) { + if (pet.isNew()) { + getPetsInternal().add(pet); + } + pet.setOwner(this); + } - /** - * Return the Pet with the given name, or null if none found for this Owner. - * - * @param name to test - * @return true if pet name is already in use - */ - public Pet getPet(String name, boolean ignoreNew) { - name = name.toLowerCase(); - for (Pet pet : getPetsInternal()) { - if (!ignoreNew || !pet.isNew()) { - String compName = pet.getName(); - compName = compName.toLowerCase(); - if (compName.equals(name)) { - return pet; - } - } - } - return null; - } + /** + * Return the Pet with the given name, or null if none found for this Owner. + * @param name to test + * @return true if pet name is already in use + */ + public Pet getPet(String name) { + return getPet(name, false); + } - @Override - public String toString() { - return new ToStringCreator(this) + /** + * Return the Pet with the given name, or null if none found for this Owner. + * @param name to test + * @return true if pet name is already in use + */ + public Pet getPet(String name, boolean ignoreNew) { + name = name.toLowerCase(); + for (Pet pet : getPetsInternal()) { + if (!ignoreNew || !pet.isNew()) { + String compName = pet.getName(); + compName = compName.toLowerCase(); + if (compName.equals(name)) { + return pet; + } + } + } + return null; + } + + @Override + public String toString() { + return new ToStringCreator(this) + + .append("id", this.getId()).append("new", this.isNew()).append("lastName", this.getLastName()) + .append("firstName", this.getFirstName()).append("address", this.address).append("city", this.city) + .append("telephone", this.telephone).toString(); + } - .append("id", this.getId()).append("new", this.isNew()) - .append("lastName", this.getLastName()) - .append("firstName", this.getFirstName()).append("address", this.address) - .append("city", this.city).append("telephone", this.telephone).toString(); - } } 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 afc2c937e..79aa4cd9b 100644 --- a/src/main/java/org/springframework/samples/petclinic/owner/OwnerController.java +++ b/src/main/java/org/springframework/samples/petclinic/owner/OwnerController.java @@ -39,102 +39,107 @@ import java.util.Map; @Controller class OwnerController { - private static final String VIEWS_OWNER_CREATE_OR_UPDATE_FORM = "owners/createOrUpdateOwnerForm"; - private final OwnerRepository owners; - private VisitRepository visits; + private static final String VIEWS_OWNER_CREATE_OR_UPDATE_FORM = "owners/createOrUpdateOwnerForm"; + private final OwnerRepository owners; - public OwnerController(OwnerRepository clinicService, VisitRepository visits) { - this.owners = clinicService; - this.visits = visits; - } + private VisitRepository visits; - @InitBinder - public void setAllowedFields(WebDataBinder dataBinder) { - dataBinder.setDisallowedFields("id"); - } + public OwnerController(OwnerRepository clinicService, VisitRepository visits) { + this.owners = clinicService; + this.visits = visits; + } - @GetMapping("/owners/new") - public String initCreationForm(Map model) { - Owner owner = new Owner(); - model.put("owner", owner); - return VIEWS_OWNER_CREATE_OR_UPDATE_FORM; - } + @InitBinder + public void setAllowedFields(WebDataBinder dataBinder) { + dataBinder.setDisallowedFields("id"); + } - @PostMapping("/owners/new") - public String processCreationForm(@Valid Owner owner, BindingResult result) { - if (result.hasErrors()) { - return VIEWS_OWNER_CREATE_OR_UPDATE_FORM; - } else { - this.owners.save(owner); - return "redirect:/owners/" + owner.getId(); - } - } + @GetMapping("/owners/new") + public String initCreationForm(Map model) { + Owner owner = new Owner(); + model.put("owner", owner); + return VIEWS_OWNER_CREATE_OR_UPDATE_FORM; + } - @GetMapping("/owners/find") - public String initFindForm(Map model) { - model.put("owner", new Owner()); - return "owners/findOwners"; - } + @PostMapping("/owners/new") + public String processCreationForm(@Valid Owner owner, BindingResult result) { + if (result.hasErrors()) { + return VIEWS_OWNER_CREATE_OR_UPDATE_FORM; + } + else { + this.owners.save(owner); + return "redirect:/owners/" + owner.getId(); + } + } - @GetMapping("/owners") - public String processFindForm(Owner owner, BindingResult result, Map model) { + @GetMapping("/owners/find") + public String initFindForm(Map model) { + model.put("owner", new Owner()); + return "owners/findOwners"; + } - // allow parameterless GET request for /owners to return all records - if (owner.getLastName() == null) { - owner.setLastName(""); // empty string signifies broadest possible search - } + @GetMapping("/owners") + public String processFindForm(Owner owner, BindingResult result, Map model) { - // find owners by last name - Collection results = this.owners.findByLastName(owner.getLastName()); - if (results.isEmpty()) { - // no owners found - result.rejectValue("lastName", "notFound", "not found"); - return "owners/findOwners"; - } else if (results.size() == 1) { - // 1 owner found - owner = results.iterator().next(); - return "redirect:/owners/" + owner.getId(); - } else { - // multiple owners found - model.put("selections", results); - return "owners/ownersList"; - } - } + // allow parameterless GET request for /owners to return all records + if (owner.getLastName() == null) { + owner.setLastName(""); // empty string signifies broadest possible search + } - @GetMapping("/owners/{ownerId}/edit") - public String initUpdateOwnerForm(@PathVariable("ownerId") int ownerId, Model model) { - Owner owner = this.owners.findById(ownerId); - model.addAttribute(owner); - return VIEWS_OWNER_CREATE_OR_UPDATE_FORM; - } + // find owners by last name + Collection results = this.owners.findByLastName(owner.getLastName()); + if (results.isEmpty()) { + // no owners found + result.rejectValue("lastName", "notFound", "not found"); + return "owners/findOwners"; + } + else if (results.size() == 1) { + // 1 owner found + owner = results.iterator().next(); + return "redirect:/owners/" + owner.getId(); + } + else { + // multiple owners found + model.put("selections", results); + return "owners/ownersList"; + } + } - @PostMapping("/owners/{ownerId}/edit") - public String processUpdateOwnerForm(@Valid Owner owner, BindingResult result, @PathVariable("ownerId") int ownerId) { - if (result.hasErrors()) { - return VIEWS_OWNER_CREATE_OR_UPDATE_FORM; - } else { - owner.setId(ownerId); - this.owners.save(owner); - return "redirect:/owners/{ownerId}"; - } - } + @GetMapping("/owners/{ownerId}/edit") + public String initUpdateOwnerForm(@PathVariable("ownerId") int ownerId, Model model) { + Owner owner = this.owners.findById(ownerId); + model.addAttribute(owner); + return VIEWS_OWNER_CREATE_OR_UPDATE_FORM; + } - /** - * 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 - */ - @GetMapping("/owners/{ownerId}") - public ModelAndView showOwner(@PathVariable("ownerId") int ownerId) { - ModelAndView mav = new ModelAndView("owners/ownerDetails"); - Owner owner = this.owners.findById(ownerId); - for (Pet pet : owner.getPets()) { - pet.setVisitsInternal(visits.findByPetId(pet.getId())); - } - mav.addObject(owner); - return mav; - } + @PostMapping("/owners/{ownerId}/edit") + public String processUpdateOwnerForm(@Valid Owner owner, BindingResult result, + @PathVariable("ownerId") int ownerId) { + if (result.hasErrors()) { + return VIEWS_OWNER_CREATE_OR_UPDATE_FORM; + } + else { + owner.setId(ownerId); + this.owners.save(owner); + 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 + */ + @GetMapping("/owners/{ownerId}") + public ModelAndView showOwner(@PathVariable("ownerId") int ownerId) { + ModelAndView mav = new ModelAndView("owners/ownerDetails"); + Owner owner = this.owners.findById(ownerId); + for (Pet pet : owner.getPets()) { + pet.setVisitsInternal(visits.findByPetId(pet.getId())); + } + mav.addObject(owner); + return mav; + } } 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 a5803f36a..0613e928a 100644 --- a/src/main/java/org/springframework/samples/petclinic/owner/OwnerRepository.java +++ b/src/main/java/org/springframework/samples/petclinic/owner/OwnerRepository.java @@ -23,9 +23,10 @@ import org.springframework.data.repository.query.Param; import org.springframework.transaction.annotation.Transactional; /** - * Repository class for Owner domain objects All method names are compliant with Spring Data naming - * conventions so this interface can easily be extended for Spring Data. - * See: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation + * Repository class for Owner domain objects All method names are compliant + * with Spring Data naming conventions so this interface can easily be extended for Spring + * Data. See: + * https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation * * @author Ken Krebs * @author Juergen Hoeller @@ -34,31 +35,30 @@ import org.springframework.transaction.annotation.Transactional; */ public interface OwnerRepository extends Repository { - /** - * Retrieve {@link Owner}s from the data store by last name, returning all owners - * whose last name starts with the given name. - * @param lastName Value to search for - * @return a Collection of matching {@link Owner}s (or an empty Collection if none - * found) - */ - @Query("SELECT DISTINCT owner FROM Owner owner left join fetch owner.pets WHERE owner.lastName LIKE :lastName%") - @Transactional(readOnly = true) - Collection findByLastName(@Param("lastName") String lastName); + /** + * Retrieve {@link Owner}s from the data store by last name, returning all owners + * whose last name starts with the given name. + * @param lastName Value to search for + * @return a Collection of matching {@link Owner}s (or an empty Collection if none + * found) + */ + @Query("SELECT DISTINCT owner FROM Owner owner left join fetch owner.pets WHERE owner.lastName LIKE :lastName%") + @Transactional(readOnly = true) + Collection findByLastName(@Param("lastName") String lastName); - /** - * Retrieve an {@link Owner} from the data store by id. - * @param id the id to search for - * @return the {@link Owner} if found - */ - @Query("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:id") - @Transactional(readOnly = true) - Owner findById(@Param("id") Integer id); - - /** - * Save an {@link Owner} to the data store, either inserting or updating it. - * @param owner the {@link Owner} to save - */ - void save(Owner owner); + /** + * Retrieve an {@link Owner} from the data store by id. + * @param id the id to search for + * @return the {@link Owner} if found + */ + @Query("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:id") + @Transactional(readOnly = true) + Owner findById(@Param("id") Integer id); + /** + * Save an {@link Owner} to the data store, either inserting or updating it. + * @param owner the {@link Owner} to save + */ + void save(Owner owner); } diff --git a/src/main/java/org/springframework/samples/petclinic/owner/Pet.java b/src/main/java/org/springframework/samples/petclinic/owner/Pet.java index 0bd04b772..2b68005fd 100755 --- a/src/main/java/org/springframework/samples/petclinic/owner/Pet.java +++ b/src/main/java/org/springframework/samples/petclinic/owner/Pet.java @@ -48,66 +48,65 @@ import org.springframework.samples.petclinic.visit.Visit; @Table(name = "pets") public class Pet extends NamedEntity { - @Column(name = "birth_date") - @DateTimeFormat(pattern = "yyyy-MM-dd") - private LocalDate birthDate; + @Column(name = "birth_date") + @DateTimeFormat(pattern = "yyyy-MM-dd") + private LocalDate birthDate; - @ManyToOne - @JoinColumn(name = "type_id") - private PetType type; + @ManyToOne + @JoinColumn(name = "type_id") + private PetType type; - @ManyToOne - @JoinColumn(name = "owner_id") - private Owner owner; + @ManyToOne + @JoinColumn(name = "owner_id") + private Owner owner; - @Transient - private Set visits = new LinkedHashSet<>(); + @Transient + private Set visits = new LinkedHashSet<>(); - public void setBirthDate(LocalDate birthDate) { - this.birthDate = birthDate; - } + public void setBirthDate(LocalDate birthDate) { + this.birthDate = birthDate; + } - public LocalDate getBirthDate() { - return this.birthDate; - } + public LocalDate getBirthDate() { + return this.birthDate; + } - public PetType getType() { - return this.type; - } + public PetType getType() { + return this.type; + } - public void setType(PetType type) { - this.type = type; - } + public void setType(PetType type) { + this.type = type; + } - public Owner getOwner() { - return this.owner; - } + public Owner getOwner() { + return this.owner; + } - protected void setOwner(Owner owner) { - this.owner = owner; - } + protected void setOwner(Owner owner) { + this.owner = owner; + } - protected Set getVisitsInternal() { - if (this.visits == null) { - this.visits = new HashSet<>(); - } - return this.visits; - } + protected Set getVisitsInternal() { + if (this.visits == null) { + this.visits = new HashSet<>(); + } + return this.visits; + } - protected void setVisitsInternal(Collection visits) { - this.visits = new LinkedHashSet<>(visits); - } + protected void setVisitsInternal(Collection visits) { + this.visits = new LinkedHashSet<>(visits); + } - public List getVisits() { - List sortedVisits = new ArrayList<>(getVisitsInternal()); - PropertyComparator.sort(sortedVisits, - new MutableSortDefinition("date", false, false)); - return Collections.unmodifiableList(sortedVisits); - } + public List getVisits() { + List sortedVisits = new ArrayList<>(getVisitsInternal()); + PropertyComparator.sort(sortedVisits, new MutableSortDefinition("date", false, false)); + return Collections.unmodifiableList(sortedVisits); + } - public void addVisit(Visit visit) { - getVisitsInternal().add(visit); - visit.setPetId(this.getId()); - } + public void addVisit(Visit visit) { + getVisitsInternal().add(visit); + visit.setPetId(this.getId()); + } } 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 0107aa8a9..a55e599af 100644 --- a/src/main/java/org/springframework/samples/petclinic/owner/PetController.java +++ b/src/main/java/org/springframework/samples/petclinic/owner/PetController.java @@ -34,76 +34,80 @@ import java.util.Collection; @RequestMapping("/owners/{ownerId}") class PetController { - private static final String VIEWS_PETS_CREATE_OR_UPDATE_FORM = "pets/createOrUpdatePetForm"; - private final PetRepository pets; - private final OwnerRepository owners; + private static final String VIEWS_PETS_CREATE_OR_UPDATE_FORM = "pets/createOrUpdatePetForm"; - public PetController(PetRepository pets, OwnerRepository owners) { - this.pets = pets; - this.owners = owners; - } + private final PetRepository pets; - @ModelAttribute("types") - public Collection populatePetTypes() { - return this.pets.findPetTypes(); - } + private final OwnerRepository owners; - @ModelAttribute("owner") - public Owner findOwner(@PathVariable("ownerId") int ownerId) { - return this.owners.findById(ownerId); - } + public PetController(PetRepository pets, OwnerRepository owners) { + this.pets = pets; + this.owners = owners; + } - @InitBinder("owner") - public void initOwnerBinder(WebDataBinder dataBinder) { - dataBinder.setDisallowedFields("id"); - } + @ModelAttribute("types") + public Collection populatePetTypes() { + return this.pets.findPetTypes(); + } - @InitBinder("pet") - public void initPetBinder(WebDataBinder dataBinder) { - dataBinder.setValidator(new PetValidator()); - } + @ModelAttribute("owner") + public Owner findOwner(@PathVariable("ownerId") int ownerId) { + return this.owners.findById(ownerId); + } - @GetMapping("/pets/new") - public String initCreationForm(Owner owner, ModelMap model) { - Pet pet = new Pet(); - owner.addPet(pet); - model.put("pet", pet); - return VIEWS_PETS_CREATE_OR_UPDATE_FORM; - } + @InitBinder("owner") + public void initOwnerBinder(WebDataBinder dataBinder) { + dataBinder.setDisallowedFields("id"); + } - @PostMapping("/pets/new") - public String processCreationForm(Owner owner, @Valid Pet pet, BindingResult result, ModelMap model) { - if (StringUtils.hasLength(pet.getName()) && pet.isNew() && owner.getPet(pet.getName(), true) != null){ - result.rejectValue("name", "duplicate", "already exists"); - } - owner.addPet(pet); - if (result.hasErrors()) { - model.put("pet", pet); - return VIEWS_PETS_CREATE_OR_UPDATE_FORM; - } else { - this.pets.save(pet); - return "redirect:/owners/{ownerId}"; - } - } + @InitBinder("pet") + public void initPetBinder(WebDataBinder dataBinder) { + dataBinder.setValidator(new PetValidator()); + } - @GetMapping("/pets/{petId}/edit") - public String initUpdateForm(@PathVariable("petId") int petId, ModelMap model) { - Pet pet = this.pets.findById(petId); - model.put("pet", pet); - return VIEWS_PETS_CREATE_OR_UPDATE_FORM; - } + @GetMapping("/pets/new") + public String initCreationForm(Owner owner, ModelMap model) { + Pet pet = new Pet(); + owner.addPet(pet); + model.put("pet", pet); + return VIEWS_PETS_CREATE_OR_UPDATE_FORM; + } - @PostMapping("/pets/{petId}/edit") - public String processUpdateForm(@Valid Pet pet, BindingResult result, Owner owner, ModelMap model) { - if (result.hasErrors()) { - pet.setOwner(owner); - model.put("pet", pet); - return VIEWS_PETS_CREATE_OR_UPDATE_FORM; - } else { - owner.addPet(pet); - this.pets.save(pet); - return "redirect:/owners/{ownerId}"; - } - } + @PostMapping("/pets/new") + public String processCreationForm(Owner owner, @Valid Pet pet, BindingResult result, ModelMap model) { + if (StringUtils.hasLength(pet.getName()) && pet.isNew() && owner.getPet(pet.getName(), true) != null) { + result.rejectValue("name", "duplicate", "already exists"); + } + owner.addPet(pet); + if (result.hasErrors()) { + model.put("pet", pet); + return VIEWS_PETS_CREATE_OR_UPDATE_FORM; + } + else { + this.pets.save(pet); + return "redirect:/owners/{ownerId}"; + } + } + + @GetMapping("/pets/{petId}/edit") + public String initUpdateForm(@PathVariable("petId") int petId, ModelMap model) { + Pet pet = this.pets.findById(petId); + model.put("pet", pet); + return VIEWS_PETS_CREATE_OR_UPDATE_FORM; + } + + @PostMapping("/pets/{petId}/edit") + public String processUpdateForm(@Valid Pet pet, BindingResult result, Owner owner, ModelMap model) { + if (result.hasErrors()) { + pet.setOwner(owner); + model.put("pet", pet); + return VIEWS_PETS_CREATE_OR_UPDATE_FORM; + } + else { + owner.addPet(pet); + this.pets.save(pet); + return "redirect:/owners/{ownerId}"; + } + } } diff --git a/src/main/java/org/springframework/samples/petclinic/owner/PetRepository.java b/src/main/java/org/springframework/samples/petclinic/owner/PetRepository.java index 0d483b7ad..9d25b095b 100644 --- a/src/main/java/org/springframework/samples/petclinic/owner/PetRepository.java +++ b/src/main/java/org/springframework/samples/petclinic/owner/PetRepository.java @@ -22,9 +22,10 @@ import org.springframework.data.repository.Repository; import org.springframework.transaction.annotation.Transactional; /** - * Repository class for Pet domain objects All method names are compliant with Spring Data naming - * conventions so this interface can easily be extended for Spring Data. - * See: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation + * Repository class for Pet domain objects All method names are compliant + * with Spring Data naming conventions so this interface can easily be extended for Spring + * Data. See: + * https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation * * @author Ken Krebs * @author Juergen Hoeller @@ -33,27 +34,26 @@ import org.springframework.transaction.annotation.Transactional; */ public interface PetRepository extends Repository { - /** - * Retrieve all {@link PetType}s from the data store. - * @return a Collection of {@link PetType}s. - */ - @Query("SELECT ptype FROM PetType ptype ORDER BY ptype.name") - @Transactional(readOnly = true) - List findPetTypes(); + /** + * Retrieve all {@link PetType}s from the data store. + * @return a Collection of {@link PetType}s. + */ + @Query("SELECT ptype FROM PetType ptype ORDER BY ptype.name") + @Transactional(readOnly = true) + List findPetTypes(); - /** - * Retrieve a {@link Pet} from the data store by id. - * @param id the id to search for - * @return the {@link Pet} if found - */ - @Transactional(readOnly = true) - Pet findById(Integer id); + /** + * Retrieve a {@link Pet} from the data store by id. + * @param id the id to search for + * @return the {@link Pet} if found + */ + @Transactional(readOnly = true) + Pet findById(Integer id); - /** - * Save a {@link Pet} to the data store, either inserting or updating it. - * @param pet the {@link Pet} to save - */ - void save(Pet pet); + /** + * Save a {@link Pet} to the data store, either inserting or updating it. + * @param pet the {@link Pet} to save + */ + void save(Pet pet); } - diff --git a/src/main/java/org/springframework/samples/petclinic/owner/PetType.java b/src/main/java/org/springframework/samples/petclinic/owner/PetType.java index 19c27bee3..6f0aa58d3 100644 --- a/src/main/java/org/springframework/samples/petclinic/owner/PetType.java +++ b/src/main/java/org/springframework/samples/petclinic/owner/PetType.java @@ -21,8 +21,7 @@ import javax.persistence.Table; import org.springframework.samples.petclinic.model.NamedEntity; /** - * @author Juergen Hoeller - * Can be Cat, Dog, Hamster... + * @author Juergen Hoeller Can be Cat, Dog, Hamster... */ @Entity @Table(name = "types") 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 4423482a3..4940bcb38 100644 --- a/src/main/java/org/springframework/samples/petclinic/owner/PetTypeFormatter.java +++ b/src/main/java/org/springframework/samples/petclinic/owner/PetTypeFormatter.java @@ -24,9 +24,10 @@ import org.springframework.format.Formatter; import org.springframework.stereotype.Component; /** - * Instructs Spring MVC on how to parse and print elements of type 'PetType'. Starting from Spring 3.0, Formatters have - * come as an improvement in comparison to legacy PropertyEditors. See the following links for more details: - The - * Spring ref doc: https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#format + * Instructs Spring MVC on how to parse and print elements of type 'PetType'. Starting + * from Spring 3.0, Formatters have come as an improvement in comparison to legacy + * PropertyEditors. See the following links for more details: - The Spring ref doc: + * https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#format * * @author Mark Fisher * @author Juergen Hoeller @@ -35,28 +36,27 @@ import org.springframework.stereotype.Component; @Component public class PetTypeFormatter implements Formatter { - private final PetRepository pets; + private final PetRepository pets; + @Autowired + public PetTypeFormatter(PetRepository pets) { + this.pets = pets; + } - @Autowired - public PetTypeFormatter(PetRepository pets) { - this.pets = pets; - } + @Override + public String print(PetType petType, Locale locale) { + return petType.getName(); + } - @Override - public String print(PetType petType, Locale locale) { - return petType.getName(); - } - - @Override - public PetType parse(String text, Locale locale) throws ParseException { - Collection findPetTypes = this.pets.findPetTypes(); - for (PetType type : findPetTypes) { - if (type.getName().equals(text)) { - return type; - } - } - throw new ParseException("type not found: " + text, 0); - } + @Override + public PetType parse(String text, Locale locale) throws ParseException { + Collection findPetTypes = this.pets.findPetTypes(); + for (PetType type : findPetTypes) { + if (type.getName().equals(text)) { + return type; + } + } + throw new ParseException("type not found: " + text, 0); + } } diff --git a/src/main/java/org/springframework/samples/petclinic/owner/PetValidator.java b/src/main/java/org/springframework/samples/petclinic/owner/PetValidator.java index 3e8438b33..e1370b428 100644 --- a/src/main/java/org/springframework/samples/petclinic/owner/PetValidator.java +++ b/src/main/java/org/springframework/samples/petclinic/owner/PetValidator.java @@ -22,7 +22,8 @@ import org.springframework.validation.Validator; /** * Validator for Pet forms. *

- * We're not using Bean Validation annotations here because it is easier to define such validation rule in Java. + * We're not using Bean Validation annotations here because it is easier to define such + * validation rule in Java. *

* * @author Ken Krebs @@ -30,35 +31,34 @@ import org.springframework.validation.Validator; */ public class PetValidator implements Validator { - private static final String REQUIRED = "required"; + private static final String REQUIRED = "required"; - @Override - public void validate(Object obj, Errors errors) { - Pet pet = (Pet) obj; - String name = pet.getName(); - // name validation - if (!StringUtils.hasLength(name)) { - errors.rejectValue("name", REQUIRED, REQUIRED); - } + @Override + public void validate(Object obj, Errors errors) { + Pet pet = (Pet) obj; + String name = pet.getName(); + // name validation + if (!StringUtils.hasLength(name)) { + errors.rejectValue("name", REQUIRED, REQUIRED); + } - // type validation - if (pet.isNew() && pet.getType() == null) { - errors.rejectValue("type", REQUIRED, REQUIRED); - } + // type validation + if (pet.isNew() && pet.getType() == null) { + errors.rejectValue("type", REQUIRED, REQUIRED); + } - // birth date validation - if (pet.getBirthDate() == null) { - errors.rejectValue("birthDate", REQUIRED, REQUIRED); - } - } - - /** - * This Validator validates *just* Pet instances - */ - @Override - public boolean supports(Class clazz) { - return Pet.class.isAssignableFrom(clazz); - } + // birth date validation + if (pet.getBirthDate() == null) { + errors.rejectValue("birthDate", REQUIRED, REQUIRED); + } + } + /** + * This Validator validates *just* Pet instances + */ + @Override + public boolean supports(Class clazz) { + return Pet.class.isAssignableFrom(clazz); + } } diff --git a/src/main/java/org/springframework/samples/petclinic/owner/VisitController.java b/src/main/java/org/springframework/samples/petclinic/owner/VisitController.java index c6dfc7fc7..375980312 100644 --- a/src/main/java/org/springframework/samples/petclinic/owner/VisitController.java +++ b/src/main/java/org/springframework/samples/petclinic/owner/VisitController.java @@ -40,55 +40,53 @@ import org.springframework.web.bind.annotation.PostMapping; @Controller class VisitController { - private final VisitRepository visits; - private final PetRepository pets; + private final VisitRepository visits; + private final PetRepository pets; - public VisitController(VisitRepository visits, PetRepository pets) { - this.visits = visits; - this.pets = pets; - } + public VisitController(VisitRepository visits, PetRepository pets) { + this.visits = visits; + this.pets = pets; + } - @InitBinder - public void setAllowedFields(WebDataBinder dataBinder) { - dataBinder.setDisallowedFields("id"); - } + @InitBinder + public void setAllowedFields(WebDataBinder dataBinder) { + dataBinder.setDisallowedFields("id"); + } - /** - * Called before each and every @RequestMapping annotated method. - * 2 goals: - * - Make sure we always have fresh data - * - Since we do not use the session scope, make sure that Pet object always has an id - * (Even though id is not part of the form fields) - * - * @param petId - * @return Pet - */ - @ModelAttribute("visit") - public Visit loadPetWithVisit(@PathVariable("petId") int petId, Map model) { - Pet pet = this.pets.findById(petId); - pet.setVisitsInternal(this.visits.findByPetId(petId)); - model.put("pet", pet); - Visit visit = new Visit(); - pet.addVisit(visit); - return visit; - } + /** + * Called before each and every @RequestMapping annotated method. 2 goals: - Make sure + * we always have fresh data - Since we do not use the session scope, make sure that + * Pet object always has an id (Even though id is not part of the form fields) + * @param petId + * @return Pet + */ + @ModelAttribute("visit") + public Visit loadPetWithVisit(@PathVariable("petId") int petId, Map model) { + Pet pet = this.pets.findById(petId); + pet.setVisitsInternal(this.visits.findByPetId(petId)); + model.put("pet", pet); + Visit visit = new Visit(); + pet.addVisit(visit); + return visit; + } - // Spring MVC calls method loadPetWithVisit(...) before initNewVisitForm is called - @GetMapping("/owners/*/pets/{petId}/visits/new") - public String initNewVisitForm(@PathVariable("petId") int petId, Map model) { - return "pets/createOrUpdateVisitForm"; - } + // Spring MVC calls method loadPetWithVisit(...) before initNewVisitForm is called + @GetMapping("/owners/*/pets/{petId}/visits/new") + public String initNewVisitForm(@PathVariable("petId") int petId, Map model) { + return "pets/createOrUpdateVisitForm"; + } - // Spring MVC calls method loadPetWithVisit(...) before processNewVisitForm is called - @PostMapping("/owners/{ownerId}/pets/{petId}/visits/new") - public String processNewVisitForm(@Valid Visit visit, BindingResult result) { - if (result.hasErrors()) { - return "pets/createOrUpdateVisitForm"; - } else { - this.visits.save(visit); - return "redirect:/owners/{ownerId}"; - } - } + // Spring MVC calls method loadPetWithVisit(...) before processNewVisitForm is called + @PostMapping("/owners/{ownerId}/pets/{petId}/visits/new") + public String processNewVisitForm(@Valid Visit visit, BindingResult result) { + if (result.hasErrors()) { + return "pets/createOrUpdateVisitForm"; + } + else { + this.visits.save(visit); + return "redirect:/owners/{ownerId}"; + } + } } diff --git a/src/main/java/org/springframework/samples/petclinic/system/CacheConfiguration.java b/src/main/java/org/springframework/samples/petclinic/system/CacheConfiguration.java index 4c083a41b..0a96582c9 100755 --- a/src/main/java/org/springframework/samples/petclinic/system/CacheConfiguration.java +++ b/src/main/java/org/springframework/samples/petclinic/system/CacheConfiguration.java @@ -32,24 +32,24 @@ import org.springframework.context.annotation.Configuration; @EnableCaching class CacheConfiguration { - @Bean - public JCacheManagerCustomizer petclinicCacheConfigurationCustomizer() { - return cm -> { - cm.createCache("vets", cacheConfiguration()); - }; - } + @Bean + public JCacheManagerCustomizer petclinicCacheConfigurationCustomizer() { + return cm -> { + cm.createCache("vets", cacheConfiguration()); + }; + } - /** - * Create a simple configuration that enable statistics via the JCache programmatic - * configuration API. - *

- * Within the configuration object that is provided by the JCache API standard, there - * is only a very limited set of configuration options. The really relevant - * configuration options (like the size limit) must be set via a configuration - * mechanism that is provided by the selected JCache implementation. - */ - private javax.cache.configuration.Configuration cacheConfiguration() { - return new MutableConfiguration<>().setStatisticsEnabled(true); - } + /** + * Create a simple configuration that enable statistics via the JCache programmatic + * configuration API. + *

+ * Within the configuration object that is provided by the JCache API standard, there + * is only a very limited set of configuration options. The really relevant + * configuration options (like the size limit) must be set via a configuration + * mechanism that is provided by the selected JCache implementation. + */ + private javax.cache.configuration.Configuration cacheConfiguration() { + return new MutableConfiguration<>().setStatisticsEnabled(true); + } } diff --git a/src/main/java/org/springframework/samples/petclinic/system/CrashController.java b/src/main/java/org/springframework/samples/petclinic/system/CrashController.java index 05be70429..2b28600fd 100644 --- a/src/main/java/org/springframework/samples/petclinic/system/CrashController.java +++ b/src/main/java/org/springframework/samples/petclinic/system/CrashController.java @@ -28,10 +28,10 @@ import org.springframework.web.bind.annotation.GetMapping; @Controller class CrashController { - @GetMapping("/oups") - public String triggerException() { - throw new RuntimeException("Expected: controller used to showcase what " - + "happens when an exception is thrown"); - } + @GetMapping("/oups") + public String triggerException() { + throw new RuntimeException( + "Expected: controller used to showcase what " + "happens when an exception is thrown"); + } } diff --git a/src/main/java/org/springframework/samples/petclinic/system/WelcomeController.java b/src/main/java/org/springframework/samples/petclinic/system/WelcomeController.java index 7e96848b6..9224015bc 100644 --- a/src/main/java/org/springframework/samples/petclinic/system/WelcomeController.java +++ b/src/main/java/org/springframework/samples/petclinic/system/WelcomeController.java @@ -16,15 +16,15 @@ package org.springframework.samples.petclinic.system; - import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @Controller class WelcomeController { - @GetMapping("/") - public String welcome() { - return "welcome"; - } + @GetMapping("/") + public String welcome() { + return "welcome"; + } + } 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 33b449129..014becfce 100644 --- a/src/main/java/org/springframework/samples/petclinic/vet/Vet.java +++ b/src/main/java/org/springframework/samples/petclinic/vet/Vet.java @@ -45,35 +45,35 @@ import org.springframework.samples.petclinic.model.Person; @Table(name = "vets") public class Vet extends Person { - @ManyToMany(fetch = FetchType.EAGER) - @JoinTable(name = "vet_specialties", joinColumns = @JoinColumn(name = "vet_id"), inverseJoinColumns = @JoinColumn(name = "specialty_id")) - private Set specialties; + @ManyToMany(fetch = FetchType.EAGER) + @JoinTable(name = "vet_specialties", joinColumns = @JoinColumn(name = "vet_id"), + inverseJoinColumns = @JoinColumn(name = "specialty_id")) + private Set specialties; - protected Set getSpecialtiesInternal() { - if (this.specialties == null) { - this.specialties = new HashSet<>(); - } - return this.specialties; - } + protected Set getSpecialtiesInternal() { + if (this.specialties == null) { + this.specialties = new HashSet<>(); + } + return this.specialties; + } - protected void setSpecialtiesInternal(Set specialties) { - this.specialties = specialties; - } + protected void setSpecialtiesInternal(Set specialties) { + this.specialties = specialties; + } - @XmlElement - public List getSpecialties() { - List sortedSpecs = new ArrayList<>(getSpecialtiesInternal()); - PropertyComparator.sort(sortedSpecs, - new MutableSortDefinition("name", true, true)); - return Collections.unmodifiableList(sortedSpecs); - } + @XmlElement + public List getSpecialties() { + List sortedSpecs = new ArrayList<>(getSpecialtiesInternal()); + PropertyComparator.sort(sortedSpecs, new MutableSortDefinition("name", true, true)); + return Collections.unmodifiableList(sortedSpecs); + } - public int getNrOfSpecialties() { - return getSpecialtiesInternal().size(); - } + public int getNrOfSpecialties() { + return getSpecialtiesInternal().size(); + } - public void addSpecialty(Specialty specialty) { - getSpecialtiesInternal().add(specialty); - } + public void addSpecialty(Specialty specialty) { + getSpecialtiesInternal().add(specialty); + } } diff --git a/src/main/java/org/springframework/samples/petclinic/vet/VetController.java b/src/main/java/org/springframework/samples/petclinic/vet/VetController.java index f15f40b2c..fb5e321ba 100644 --- a/src/main/java/org/springframework/samples/petclinic/vet/VetController.java +++ b/src/main/java/org/springframework/samples/petclinic/vet/VetController.java @@ -30,29 +30,29 @@ import java.util.Map; @Controller class VetController { - private final VetRepository vets; + private final VetRepository vets; - public VetController(VetRepository clinicService) { - this.vets = clinicService; - } + public VetController(VetRepository clinicService) { + this.vets = clinicService; + } - @GetMapping("/vets.html") - public String showVetList(Map model) { - // Here we are returning an object of type 'Vets' rather than a collection of Vet - // objects so it is simpler for Object-Xml mapping - Vets vets = new Vets(); - vets.getVetList().addAll(this.vets.findAll()); - model.put("vets", vets); - return "vets/vetList"; - } + @GetMapping("/vets.html") + public String showVetList(Map model) { + // Here we are returning an object of type 'Vets' rather than a collection of Vet + // objects so it is simpler for Object-Xml mapping + Vets vets = new Vets(); + vets.getVetList().addAll(this.vets.findAll()); + model.put("vets", vets); + return "vets/vetList"; + } - @GetMapping({ "/vets" }) - public @ResponseBody Vets showResourcesVetList() { - // Here we are returning an object of type 'Vets' rather than a collection of Vet - // objects so it is simpler for JSon/Object mapping - Vets vets = new Vets(); - vets.getVetList().addAll(this.vets.findAll()); - return vets; - } + @GetMapping({ "/vets" }) + public @ResponseBody Vets showResourcesVetList() { + // Here we are returning an object of type 'Vets' rather than a collection of Vet + // objects so it is simpler for JSon/Object mapping + Vets vets = new Vets(); + vets.getVetList().addAll(this.vets.findAll()); + return vets; + } } diff --git a/src/main/java/org/springframework/samples/petclinic/vet/VetRepository.java b/src/main/java/org/springframework/samples/petclinic/vet/VetRepository.java index 1f70182fd..549b1c229 100644 --- a/src/main/java/org/springframework/samples/petclinic/vet/VetRepository.java +++ b/src/main/java/org/springframework/samples/petclinic/vet/VetRepository.java @@ -23,9 +23,10 @@ import org.springframework.data.repository.Repository; import org.springframework.transaction.annotation.Transactional; /** - * Repository class for Vet domain objects All method names are compliant with Spring Data naming - * conventions so this interface can easily be extended for Spring Data. - * See: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation + * Repository class for Vet domain objects All method names are compliant + * with Spring Data naming conventions so this interface can easily be extended for Spring + * Data. See: + * https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation * * @author Ken Krebs * @author Juergen Hoeller @@ -34,14 +35,12 @@ import org.springframework.transaction.annotation.Transactional; */ public interface VetRepository extends Repository { - /** - * Retrieve all Vets from the data store. - * - * @return a Collection of Vets - */ - @Transactional(readOnly = true) - @Cacheable("vets") - Collection findAll() throws DataAccessException; - + /** + * Retrieve all Vets from the data store. + * @return a Collection of Vets + */ + @Transactional(readOnly = true) + @Cacheable("vets") + Collection findAll() throws DataAccessException; } diff --git a/src/main/java/org/springframework/samples/petclinic/vet/Vets.java b/src/main/java/org/springframework/samples/petclinic/vet/Vets.java index ab29f7a54..cea665629 100644 --- a/src/main/java/org/springframework/samples/petclinic/vet/Vets.java +++ b/src/main/java/org/springframework/samples/petclinic/vet/Vets.java @@ -22,22 +22,22 @@ import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; /** - * Simple domain object representing a list of veterinarians. Mostly here to be used for the 'vets' {@link - * org.springframework.web.servlet.view.xml.MarshallingView}. + * Simple domain object representing a list of veterinarians. Mostly here to be used for + * the 'vets' {@link org.springframework.web.servlet.view.xml.MarshallingView}. * * @author Arjen Poutsma */ @XmlRootElement public class Vets { - private List vets; + private List vets; - @XmlElement - public List getVetList() { - if (vets == null) { - vets = new ArrayList<>(); - } - return vets; - } + @XmlElement + public List getVetList() { + if (vets == null) { + vets = new ArrayList<>(); + } + return vets; + } } diff --git a/src/main/java/org/springframework/samples/petclinic/visit/Visit.java b/src/main/java/org/springframework/samples/petclinic/visit/Visit.java index 03c9deedf..df9f25fe0 100755 --- a/src/main/java/org/springframework/samples/petclinic/visit/Visit.java +++ b/src/main/java/org/springframework/samples/petclinic/visit/Visit.java @@ -35,46 +35,46 @@ import org.springframework.samples.petclinic.model.BaseEntity; @Table(name = "visits") public class Visit extends BaseEntity { - @Column(name = "visit_date") - @DateTimeFormat(pattern = "yyyy-MM-dd") - private LocalDate date; + @Column(name = "visit_date") + @DateTimeFormat(pattern = "yyyy-MM-dd") + private LocalDate date; - @NotEmpty - @Column(name = "description") - private String description; + @NotEmpty + @Column(name = "description") + private String description; - @Column(name = "pet_id") - private Integer petId; + @Column(name = "pet_id") + private Integer petId; - /** - * Creates a new instance of Visit for the current date - */ - public Visit() { - this.date = LocalDate.now(); - } + /** + * Creates a new instance of Visit for the current date + */ + public Visit() { + this.date = LocalDate.now(); + } - public LocalDate getDate() { - return this.date; - } + public LocalDate getDate() { + return this.date; + } - public void setDate(LocalDate date) { - this.date = date; - } + public void setDate(LocalDate date) { + this.date = date; + } - public String getDescription() { - return this.description; - } + public String getDescription() { + return this.description; + } - public void setDescription(String description) { - this.description = description; - } + public void setDescription(String description) { + this.description = description; + } - public Integer getPetId() { - return this.petId; - } + public Integer getPetId() { + return this.petId; + } - public void setPetId(Integer petId) { - this.petId = petId; - } + public void setPetId(Integer petId) { + this.petId = petId; + } } diff --git a/src/main/java/org/springframework/samples/petclinic/visit/VisitRepository.java b/src/main/java/org/springframework/samples/petclinic/visit/VisitRepository.java index 42b58618b..d5a3334c6 100644 --- a/src/main/java/org/springframework/samples/petclinic/visit/VisitRepository.java +++ b/src/main/java/org/springframework/samples/petclinic/visit/VisitRepository.java @@ -22,9 +22,10 @@ import org.springframework.data.repository.Repository; import org.springframework.samples.petclinic.model.BaseEntity; /** - * Repository class for Visit domain objects All method names are compliant with Spring Data naming - * conventions so this interface can easily be extended for Spring Data. - * See: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation + * Repository class for Visit domain objects All method names are compliant + * with Spring Data naming conventions so this interface can easily be extended for Spring + * Data. See: + * https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation * * @author Ken Krebs * @author Juergen Hoeller @@ -33,14 +34,13 @@ import org.springframework.samples.petclinic.model.BaseEntity; */ public interface VisitRepository extends Repository { - /** - * Save a Visit to the data store, either inserting or updating it. - * - * @param visit the Visit to save - * @see BaseEntity#isNew - */ - void save(Visit visit) throws DataAccessException; + /** + * Save a Visit to the data store, either inserting or updating it. + * @param visit the Visit to save + * @see BaseEntity#isNew + */ + void save(Visit visit) throws DataAccessException; - List findByPetId(Integer petId); + List findByPetId(Integer petId); } diff --git a/src/main/resources/application-mysql.properties b/src/main/resources/application-mysql.properties index 6a11a4f02..d388c9e6d 100644 --- a/src/main/resources/application-mysql.properties +++ b/src/main/resources/application-mysql.properties @@ -1,7 +1,7 @@ # database init, supports mysql too database=mysql -spring.datasource.url=${MYSQL_DB:jdbc:mysql://localhost/petclinic} -spring.datasource.username=${MYSQL_USER:petclinic@petclinicdb2} +spring.datasource.url=${MYSQL_URL:jdbc:mysql://localhost/petclinic} +spring.datasource.username=${MYSQL_USER:petclinic} spring.datasource.password=${MYSQL_PASS:petclinic} -# Uncomment this the first time the app runs -spring.datasource.initialization-mode=always \ No newline at end of file +# SQL is written to be idempotent so this is safe +spring.datasource.initialization-mode=always diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index b93ff4de3..4d4784e36 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,5 +1,5 @@ # database init, supports mysql too -database=hsqldb +database=h2 spring.datasource.schema=classpath*:db/${database}/schema.sql spring.datasource.data=classpath*:db/${database}/data.sql @@ -8,12 +8,12 @@ spring.thymeleaf.mode=HTML # JPA spring.jpa.hibernate.ddl-auto=none +spring.jpa.open-in-view=false # Internationalization spring.messages.basename=messages/messages -# Actuator / Management -management.endpoints.web.base-path=/manage +# Actuator management.endpoints.web.exposure.include=* # Logging diff --git a/src/main/resources/db/h2/data.sql b/src/main/resources/db/h2/data.sql new file mode 100644 index 000000000..16dda3e84 --- /dev/null +++ b/src/main/resources/db/h2/data.sql @@ -0,0 +1,53 @@ +INSERT INTO vets VALUES (1, 'James', 'Carter'); +INSERT INTO vets VALUES (2, 'Helen', 'Leary'); +INSERT INTO vets VALUES (3, 'Linda', 'Douglas'); +INSERT INTO vets VALUES (4, 'Rafael', 'Ortega'); +INSERT INTO vets VALUES (5, 'Henry', 'Stevens'); +INSERT INTO vets VALUES (6, 'Sharon', 'Jenkins'); + +INSERT INTO specialties VALUES (1, 'radiology'); +INSERT INTO specialties VALUES (2, 'surgery'); +INSERT INTO specialties VALUES (3, 'dentistry'); + +INSERT INTO vet_specialties VALUES (2, 1); +INSERT INTO vet_specialties VALUES (3, 2); +INSERT INTO vet_specialties VALUES (3, 3); +INSERT INTO vet_specialties VALUES (4, 2); +INSERT INTO vet_specialties VALUES (5, 1); + +INSERT INTO types VALUES (1, 'cat'); +INSERT INTO types VALUES (2, 'dog'); +INSERT INTO types VALUES (3, 'lizard'); +INSERT INTO types VALUES (4, 'snake'); +INSERT INTO types VALUES (5, 'bird'); +INSERT INTO types VALUES (6, 'hamster'); + +INSERT INTO owners VALUES (1, 'George', 'Franklin', '110 W. Liberty St.', 'Madison', '6085551023'); +INSERT INTO owners VALUES (2, 'Betty', 'Davis', '638 Cardinal Ave.', 'Sun Prairie', '6085551749'); +INSERT INTO owners VALUES (3, 'Eduardo', 'Rodriquez', '2693 Commerce St.', 'McFarland', '6085558763'); +INSERT INTO owners VALUES (4, 'Harold', 'Davis', '563 Friendly St.', 'Windsor', '6085553198'); +INSERT INTO owners VALUES (5, 'Peter', 'McTavish', '2387 S. Fair Way', 'Madison', '6085552765'); +INSERT INTO owners VALUES (6, 'Jean', 'Coleman', '105 N. Lake St.', 'Monona', '6085552654'); +INSERT INTO owners VALUES (7, 'Jeff', 'Black', '1450 Oak Blvd.', 'Monona', '6085555387'); +INSERT INTO owners VALUES (8, 'Maria', 'Escobito', '345 Maple St.', 'Madison', '6085557683'); +INSERT INTO owners VALUES (9, 'David', 'Schroeder', '2749 Blackhawk Trail', 'Madison', '6085559435'); +INSERT INTO owners VALUES (10, 'Carlos', 'Estaban', '2335 Independence La.', 'Waunakee', '6085555487'); + +INSERT INTO pets VALUES (1, 'Leo', '2010-09-07', 1, 1); +INSERT INTO pets VALUES (2, 'Basil', '2012-08-06', 6, 2); +INSERT INTO pets VALUES (3, 'Rosy', '2011-04-17', 2, 3); +INSERT INTO pets VALUES (4, 'Jewel', '2010-03-07', 2, 3); +INSERT INTO pets VALUES (5, 'Iggy', '2010-11-30', 3, 4); +INSERT INTO pets VALUES (6, 'George', '2010-01-20', 4, 5); +INSERT INTO pets VALUES (7, 'Samantha', '2012-09-04', 1, 6); +INSERT INTO pets VALUES (8, 'Max', '2012-09-04', 1, 6); +INSERT INTO pets VALUES (9, 'Lucky', '2011-08-06', 5, 7); +INSERT INTO pets VALUES (10, 'Mulligan', '2007-02-24', 2, 8); +INSERT INTO pets VALUES (11, 'Freddy', '2010-03-09', 5, 9); +INSERT INTO pets VALUES (12, 'Lucky', '2010-06-24', 2, 10); +INSERT INTO pets VALUES (13, 'Sly', '2012-06-08', 1, 10); + +INSERT INTO visits VALUES (1, 7, '2013-01-01', 'rabies shot'); +INSERT INTO visits VALUES (2, 8, '2013-01-02', 'rabies shot'); +INSERT INTO visits VALUES (3, 8, '2013-01-03', 'neutered'); +INSERT INTO visits VALUES (4, 7, '2013-01-04', 'spayed'); diff --git a/src/main/resources/db/h2/schema.sql b/src/main/resources/db/h2/schema.sql new file mode 100644 index 000000000..f3c6947b7 --- /dev/null +++ b/src/main/resources/db/h2/schema.sql @@ -0,0 +1,64 @@ +DROP TABLE vet_specialties IF EXISTS; +DROP TABLE vets IF EXISTS; +DROP TABLE specialties IF EXISTS; +DROP TABLE visits IF EXISTS; +DROP TABLE pets IF EXISTS; +DROP TABLE types IF EXISTS; +DROP TABLE owners IF EXISTS; + + +CREATE TABLE vets ( + id INTEGER IDENTITY PRIMARY KEY, + first_name VARCHAR(30), + last_name VARCHAR(30) +); +CREATE INDEX vets_last_name ON vets (last_name); + +CREATE TABLE specialties ( + id INTEGER IDENTITY PRIMARY KEY, + name VARCHAR(80) +); +CREATE INDEX specialties_name ON specialties (name); + +CREATE TABLE vet_specialties ( + vet_id INTEGER NOT NULL, + specialty_id INTEGER NOT NULL +); +ALTER TABLE vet_specialties ADD CONSTRAINT fk_vet_specialties_vets FOREIGN KEY (vet_id) REFERENCES vets (id); +ALTER TABLE vet_specialties ADD CONSTRAINT fk_vet_specialties_specialties FOREIGN KEY (specialty_id) REFERENCES specialties (id); + +CREATE TABLE types ( + id INTEGER IDENTITY PRIMARY KEY, + name VARCHAR(80) +); +CREATE INDEX types_name ON types (name); + +CREATE TABLE owners ( + id INTEGER IDENTITY PRIMARY KEY, + first_name VARCHAR(30), + last_name VARCHAR_IGNORECASE(30), + address VARCHAR(255), + city VARCHAR(80), + telephone VARCHAR(20) +); +CREATE INDEX owners_last_name ON owners (last_name); + +CREATE TABLE pets ( + id INTEGER IDENTITY PRIMARY KEY, + name VARCHAR(30), + birth_date DATE, + type_id INTEGER NOT NULL, + owner_id INTEGER NOT NULL +); +ALTER TABLE pets ADD CONSTRAINT fk_pets_owners FOREIGN KEY (owner_id) REFERENCES owners (id); +ALTER TABLE pets ADD CONSTRAINT fk_pets_types FOREIGN KEY (type_id) REFERENCES types (id); +CREATE INDEX pets_name ON pets (name); + +CREATE TABLE visits ( + id INTEGER IDENTITY PRIMARY KEY, + pet_id INTEGER NOT NULL, + visit_date DATE, + description VARCHAR(255) +); +ALTER TABLE visits ADD CONSTRAINT fk_visits_pets FOREIGN KEY (pet_id) REFERENCES pets (id); +CREATE INDEX visits_pet_id ON visits (pet_id); diff --git a/src/main/resources/db/mysql/petclinic_db_setup_mysql.txt b/src/main/resources/db/mysql/petclinic_db_setup_mysql.txt index 2afcd64b1..fea6b07b6 100644 --- a/src/main/resources/db/mysql/petclinic_db_setup_mysql.txt +++ b/src/main/resources/db/mysql/petclinic_db_setup_mysql.txt @@ -18,8 +18,10 @@ mysql_1_eedb4818d817 | MySQL init process done. Ready for start up. ... -2) Create the PetClinic database and user by executing the "db/mysql/{schema,data}.sql" - scripts (or set "spring.datasource.initialization-mode=always" the first time you run the app). +2) (Once only) create the PetClinic database and user by executing the "db/mysql/user.sql" + scripts. You can connect to the database running in the docker container using + `mysql -u root -h localhost --protocol tcp`, but you don't need to run the script there + because the petclinic user is already set up if you use the provided `docker-compose.yaml`. 3) Run the app with `spring.profiles.active=mysql` (e.g. as a System property via the command line, but any way that sets that property in a Spring Boot app should work). @@ -33,5 +35,6 @@ To set profiles & properties. N.B. the "petclinic" database has to exist for the app to work with the JDBC URL value -as it is configured by default. This condition is taken care of by the docker-compose -configuration provided, or by the `schema.sql` if you can run that as root. \ No newline at end of file +as it is configured by default. This condition is taken care of automatically by the +docker-compose configuration provided, or by the `user.sql` script if you run that as +root. diff --git a/src/main/resources/db/mysql/schema.sql b/src/main/resources/db/mysql/schema.sql index 6a9825983..eb5d7d5d0 100644 --- a/src/main/resources/db/mysql/schema.sql +++ b/src/main/resources/db/mysql/schema.sql @@ -1,13 +1,3 @@ -CREATE DATABASE IF NOT EXISTS petclinic; - -ALTER DATABASE petclinic - DEFAULT CHARACTER SET utf8 - DEFAULT COLLATE utf8_general_ci; - -GRANT ALL PRIVILEGES ON petclinic.* TO pc@localhost IDENTIFIED BY 'pc'; - -USE petclinic; - CREATE TABLE IF NOT EXISTS vets ( id INT(4) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, first_name VARCHAR(30), diff --git a/src/main/resources/db/mysql/user.sql b/src/main/resources/db/mysql/user.sql new file mode 100644 index 000000000..d2c7b88a0 --- /dev/null +++ b/src/main/resources/db/mysql/user.sql @@ -0,0 +1,7 @@ +CREATE DATABASE IF NOT EXISTS petclinic; + +ALTER DATABASE petclinic + DEFAULT CHARACTER SET utf8 + DEFAULT COLLATE utf8_general_ci; + +GRANT ALL PRIVILEGES ON petclinic.* TO 'petclinic'@'%' IDENTIFIED BY 'petclinic'; diff --git a/src/main/resources/messages/messages_es.properties b/src/main/resources/messages/messages_es.properties new file mode 100644 index 000000000..33ee867b5 --- /dev/null +++ b/src/main/resources/messages/messages_es.properties @@ -0,0 +1,8 @@ +welcome=Bienvenido +required=Es requerido +notFound=No ha sido encontrado +duplicate=Ya se encuentra en uso +nonNumeric=Sólo debe contener numeros +duplicateFormSubmission=No se permite el envío de formularios duplicados +typeMismatch.date=Fecha invalida +typeMismatch.birthDate=Fecha invalida diff --git a/src/main/resources/templates/fragments/layout.html b/src/main/resources/templates/fragments/layout.html index c97d35936..eed0e6727 100755 --- a/src/main/resources/templates/fragments/layout.html +++ b/src/main/resources/templates/fragments/layout.html @@ -1,25 +1,25 @@ - + - - - - + + + + - + PetClinic :: a Spring Framework demonstration - - + - + @@ -67,22 +67,23 @@ +

-
- - +
-
-
-
-
-
- Sponsored by Pivotal
-
+ + +
+
+
+
+
+ Sponsored by Pivotal
+
diff --git a/src/main/resources/templates/pets/createOrUpdateVisitForm.html b/src/main/resources/templates/pets/createOrUpdateVisitForm.html index f90b533bf..00a24577f 100644 --- a/src/main/resources/templates/pets/createOrUpdateVisitForm.html +++ b/src/main/resources/templates/pets/createOrUpdateVisitForm.html @@ -24,7 +24,7 @@ th:text="${#temporals.format(pet.birthDate, dateFormat)}" /> + th:text="${pet.owner?.firstName + ' ' + pet.owner?.lastName}"> diff --git a/src/test/java/org/springframework/samples/petclinic/PetclinicIntegrationTests.java b/src/test/java/org/springframework/samples/petclinic/PetclinicIntegrationTests.java index 217d552f4..226db01fe 100644 --- a/src/test/java/org/springframework/samples/petclinic/PetclinicIntegrationTests.java +++ b/src/test/java/org/springframework/samples/petclinic/PetclinicIntegrationTests.java @@ -24,12 +24,13 @@ import org.springframework.samples.petclinic.vet.VetRepository; @SpringBootTest class PetclinicIntegrationTests { - @Autowired - private VetRepository vets; + @Autowired + private VetRepository vets; + + @Test + void testFindAll() throws Exception { + vets.findAll(); + vets.findAll(); // served from cache + } - @Test - void testFindAll() throws Exception { - vets.findAll(); - vets.findAll(); // served from cache - } } diff --git a/src/test/java/org/springframework/samples/petclinic/model/ValidatorTests.java b/src/test/java/org/springframework/samples/petclinic/model/ValidatorTests.java index 4be38f714..8d754900d 100644 --- a/src/test/java/org/springframework/samples/petclinic/model/ValidatorTests.java +++ b/src/test/java/org/springframework/samples/petclinic/model/ValidatorTests.java @@ -34,28 +34,27 @@ import static org.assertj.core.api.Assertions.assertThat; */ class ValidatorTests { - private Validator createValidator() { - LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean(); - localValidatorFactoryBean.afterPropertiesSet(); - return localValidatorFactoryBean; - } + private Validator createValidator() { + LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean(); + localValidatorFactoryBean.afterPropertiesSet(); + return localValidatorFactoryBean; + } - @Test - void shouldNotValidateWhenFirstNameEmpty() { + @Test + void shouldNotValidateWhenFirstNameEmpty() { - LocaleContextHolder.setLocale(Locale.ENGLISH); - Person person = new Person(); - person.setFirstName(""); - person.setLastName("smith"); + LocaleContextHolder.setLocale(Locale.ENGLISH); + Person person = new Person(); + person.setFirstName(""); + person.setLastName("smith"); - Validator validator = createValidator(); - Set> constraintViolations = validator - .validate(person); + Validator validator = createValidator(); + Set> constraintViolations = validator.validate(person); - assertThat(constraintViolations).hasSize(1); - ConstraintViolation violation = constraintViolations.iterator().next(); - assertThat(violation.getPropertyPath().toString()).isEqualTo("firstName"); - assertThat(violation.getMessage()).isEqualTo("must not be empty"); - } + assertThat(constraintViolations).hasSize(1); + ConstraintViolation violation = constraintViolations.iterator().next(); + assertThat(violation.getPropertyPath().toString()).isEqualTo("firstName"); + assertThat(violation.getMessage()).isEqualTo("must not be empty"); + } } 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 1956e2a24..1d6249c5d 100644 --- a/src/test/java/org/springframework/samples/petclinic/owner/OwnerControllerTests.java +++ b/src/test/java/org/springframework/samples/petclinic/owner/OwnerControllerTests.java @@ -51,181 +51,149 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @WebMvcTest(OwnerController.class) class OwnerControllerTests { - private static final int TEST_OWNER_ID = 1; + private static final int TEST_OWNER_ID = 1; - @Autowired - private MockMvc mockMvc; + @Autowired + private MockMvc mockMvc; - @MockBean - private OwnerRepository owners; + @MockBean + private OwnerRepository owners; - @MockBean - private VisitRepository visits; + @MockBean + private VisitRepository visits; - private Owner george; + private Owner george; - @BeforeEach - void setup() { - george = new Owner(); - george.setId(TEST_OWNER_ID); - george.setFirstName("George"); - george.setLastName("Franklin"); - george.setAddress("110 W. Liberty St."); - george.setCity("Madison"); - george.setTelephone("6085551023"); - Pet max = new Pet(); - PetType dog = new PetType(); - dog.setName("dog"); - max.setId(1); - max.setType(dog); - max.setName("Max"); - max.setBirthDate(LocalDate.now()); - george.setPetsInternal(Collections.singleton(max)); - given(this.owners.findById(TEST_OWNER_ID)).willReturn(george); - Visit visit = new Visit(); - visit.setDate(LocalDate.now()); - given(this.visits.findByPetId(max.getId())).willReturn(Collections.singletonList(visit)); - } + @BeforeEach + void setup() { + george = new Owner(); + george.setId(TEST_OWNER_ID); + george.setFirstName("George"); + george.setLastName("Franklin"); + george.setAddress("110 W. Liberty St."); + george.setCity("Madison"); + george.setTelephone("6085551023"); + Pet max = new Pet(); + PetType dog = new PetType(); + dog.setName("dog"); + max.setId(1); + max.setType(dog); + max.setName("Max"); + max.setBirthDate(LocalDate.now()); + george.setPetsInternal(Collections.singleton(max)); + given(this.owners.findById(TEST_OWNER_ID)).willReturn(george); + Visit visit = new Visit(); + visit.setDate(LocalDate.now()); + given(this.visits.findByPetId(max.getId())).willReturn(Collections.singletonList(visit)); + } - @Test - void testInitCreationForm() throws Exception { - mockMvc.perform(get("/owners/new")) - .andExpect(status().isOk()) - .andExpect(model().attributeExists("owner")) - .andExpect(view().name("owners/createOrUpdateOwnerForm")); - } + @Test + void testInitCreationForm() throws Exception { + mockMvc.perform(get("/owners/new")).andExpect(status().isOk()).andExpect(model().attributeExists("owner")) + .andExpect(view().name("owners/createOrUpdateOwnerForm")); + } - @Test - void testProcessCreationFormSuccess() throws Exception { - mockMvc.perform(post("/owners/new") - .param("firstName", "Joe") - .param("lastName", "Bloggs") - .param("address", "123 Caramel Street") - .param("city", "London") - .param("telephone", "01316761638") - ) - .andExpect(status().is3xxRedirection()); - } + @Test + void testProcessCreationFormSuccess() throws Exception { + mockMvc.perform(post("/owners/new").param("firstName", "Joe").param("lastName", "Bloggs") + .param("address", "123 Caramel Street").param("city", "London").param("telephone", "01316761638")) + .andExpect(status().is3xxRedirection()); + } - @Test - void testProcessCreationFormHasErrors() throws Exception { - mockMvc.perform(post("/owners/new") - .param("firstName", "Joe") - .param("lastName", "Bloggs") - .param("city", "London") - ) - .andExpect(status().isOk()) - .andExpect(model().attributeHasErrors("owner")) - .andExpect(model().attributeHasFieldErrors("owner", "address")) - .andExpect(model().attributeHasFieldErrors("owner", "telephone")) - .andExpect(view().name("owners/createOrUpdateOwnerForm")); - } + @Test + void testProcessCreationFormHasErrors() throws Exception { + mockMvc.perform( + post("/owners/new").param("firstName", "Joe").param("lastName", "Bloggs").param("city", "London")) + .andExpect(status().isOk()).andExpect(model().attributeHasErrors("owner")) + .andExpect(model().attributeHasFieldErrors("owner", "address")) + .andExpect(model().attributeHasFieldErrors("owner", "telephone")) + .andExpect(view().name("owners/createOrUpdateOwnerForm")); + } - @Test - void testInitFindForm() throws Exception { - mockMvc.perform(get("/owners/find")) - .andExpect(status().isOk()) - .andExpect(model().attributeExists("owner")) - .andExpect(view().name("owners/findOwners")); - } + @Test + void testInitFindForm() throws Exception { + mockMvc.perform(get("/owners/find")).andExpect(status().isOk()).andExpect(model().attributeExists("owner")) + .andExpect(view().name("owners/findOwners")); + } - @Test - void testProcessFindFormSuccess() throws Exception { - given(this.owners.findByLastName("")).willReturn(Lists.newArrayList(george, new Owner())); - mockMvc.perform(get("/owners")) - .andExpect(status().isOk()) - .andExpect(view().name("owners/ownersList")); - } + @Test + void testProcessFindFormSuccess() throws Exception { + given(this.owners.findByLastName("")).willReturn(Lists.newArrayList(george, new Owner())); + mockMvc.perform(get("/owners")).andExpect(status().isOk()).andExpect(view().name("owners/ownersList")); + } - @Test - void testProcessFindFormByLastName() throws Exception { - given(this.owners.findByLastName(george.getLastName())).willReturn(Lists.newArrayList(george)); - mockMvc.perform(get("/owners") - .param("lastName", "Franklin") - ) - .andExpect(status().is3xxRedirection()) - .andExpect(view().name("redirect:/owners/" + TEST_OWNER_ID)); - } + @Test + void testProcessFindFormByLastName() throws Exception { + given(this.owners.findByLastName(george.getLastName())).willReturn(Lists.newArrayList(george)); + mockMvc.perform(get("/owners").param("lastName", "Franklin")).andExpect(status().is3xxRedirection()) + .andExpect(view().name("redirect:/owners/" + TEST_OWNER_ID)); + } - @Test - void testProcessFindFormNoOwnersFound() throws Exception { - mockMvc.perform(get("/owners") - .param("lastName", "Unknown Surname") - ) - .andExpect(status().isOk()) - .andExpect(model().attributeHasFieldErrors("owner", "lastName")) - .andExpect(model().attributeHasFieldErrorCode("owner", "lastName", "notFound")) - .andExpect(view().name("owners/findOwners")); - } + @Test + void testProcessFindFormNoOwnersFound() throws Exception { + mockMvc.perform(get("/owners").param("lastName", "Unknown Surname")).andExpect(status().isOk()) + .andExpect(model().attributeHasFieldErrors("owner", "lastName")) + .andExpect(model().attributeHasFieldErrorCode("owner", "lastName", "notFound")) + .andExpect(view().name("owners/findOwners")); + } - @Test - void testInitUpdateOwnerForm() throws Exception { - mockMvc.perform(get("/owners/{ownerId}/edit", TEST_OWNER_ID)) - .andExpect(status().isOk()) - .andExpect(model().attributeExists("owner")) - .andExpect(model().attribute("owner", hasProperty("lastName", is("Franklin")))) - .andExpect(model().attribute("owner", hasProperty("firstName", is("George")))) - .andExpect(model().attribute("owner", hasProperty("address", is("110 W. Liberty St.")))) - .andExpect(model().attribute("owner", hasProperty("city", is("Madison")))) - .andExpect(model().attribute("owner", hasProperty("telephone", is("6085551023")))) - .andExpect(view().name("owners/createOrUpdateOwnerForm")); - } + @Test + void testInitUpdateOwnerForm() throws Exception { + mockMvc.perform(get("/owners/{ownerId}/edit", TEST_OWNER_ID)).andExpect(status().isOk()) + .andExpect(model().attributeExists("owner")) + .andExpect(model().attribute("owner", hasProperty("lastName", is("Franklin")))) + .andExpect(model().attribute("owner", hasProperty("firstName", is("George")))) + .andExpect(model().attribute("owner", hasProperty("address", is("110 W. Liberty St.")))) + .andExpect(model().attribute("owner", hasProperty("city", is("Madison")))) + .andExpect(model().attribute("owner", hasProperty("telephone", is("6085551023")))) + .andExpect(view().name("owners/createOrUpdateOwnerForm")); + } - @Test - void testProcessUpdateOwnerFormSuccess() throws Exception { - mockMvc.perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID) - .param("firstName", "Joe") - .param("lastName", "Bloggs") - .param("address", "123 Caramel Street") - .param("city", "London") - .param("telephone", "01616291589") - ) - .andExpect(status().is3xxRedirection()) - .andExpect(view().name("redirect:/owners/{ownerId}")); - } + @Test + void testProcessUpdateOwnerFormSuccess() throws Exception { + mockMvc.perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID).param("firstName", "Joe") + .param("lastName", "Bloggs").param("address", "123 Caramel Street").param("city", "London") + .param("telephone", "01616291589")).andExpect(status().is3xxRedirection()) + .andExpect(view().name("redirect:/owners/{ownerId}")); + } - @Test - void testProcessUpdateOwnerFormHasErrors() throws Exception { - mockMvc.perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID) - .param("firstName", "Joe") - .param("lastName", "Bloggs") - .param("city", "London") - ) - .andExpect(status().isOk()) - .andExpect(model().attributeHasErrors("owner")) - .andExpect(model().attributeHasFieldErrors("owner", "address")) - .andExpect(model().attributeHasFieldErrors("owner", "telephone")) - .andExpect(view().name("owners/createOrUpdateOwnerForm")); - } + @Test + void testProcessUpdateOwnerFormHasErrors() throws Exception { + mockMvc.perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID).param("firstName", "Joe") + .param("lastName", "Bloggs").param("city", "London")).andExpect(status().isOk()) + .andExpect(model().attributeHasErrors("owner")) + .andExpect(model().attributeHasFieldErrors("owner", "address")) + .andExpect(model().attributeHasFieldErrors("owner", "telephone")) + .andExpect(view().name("owners/createOrUpdateOwnerForm")); + } - @Test - void testShowOwner() throws Exception { - mockMvc.perform(get("/owners/{ownerId}", TEST_OWNER_ID)) - .andExpect(status().isOk()) - .andExpect(model().attribute("owner", hasProperty("lastName", is("Franklin")))) - .andExpect(model().attribute("owner", hasProperty("firstName", is("George")))) - .andExpect(model().attribute("owner", hasProperty("address", is("110 W. Liberty St.")))) - .andExpect(model().attribute("owner", hasProperty("city", is("Madison")))) - .andExpect(model().attribute("owner", hasProperty("telephone", is("6085551023")))) - .andExpect(model().attribute("owner", hasProperty("pets", not(empty())))) - .andExpect(model().attribute("owner", hasProperty("pets", new BaseMatcher>() { + @Test + void testShowOwner() throws Exception { + mockMvc.perform(get("/owners/{ownerId}", TEST_OWNER_ID)).andExpect(status().isOk()) + .andExpect(model().attribute("owner", hasProperty("lastName", is("Franklin")))) + .andExpect(model().attribute("owner", hasProperty("firstName", is("George")))) + .andExpect(model().attribute("owner", hasProperty("address", is("110 W. Liberty St.")))) + .andExpect(model().attribute("owner", hasProperty("city", is("Madison")))) + .andExpect(model().attribute("owner", hasProperty("telephone", is("6085551023")))) + .andExpect(model().attribute("owner", hasProperty("pets", not(empty())))) + .andExpect(model().attribute("owner", hasProperty("pets", new BaseMatcher>() { - @Override - public boolean matches(Object item) { - @SuppressWarnings("unchecked") - List pets = (List) item; - Pet pet = pets.get(0); - if (pet.getVisits().isEmpty()) { - return false; - } - return true; - } + @Override + public boolean matches(Object item) { + @SuppressWarnings("unchecked") + List pets = (List) item; + Pet pet = pets.get(0); + if (pet.getVisits().isEmpty()) { + return false; + } + return true; + } - @Override - public void describeTo(Description description) { - description.appendText("Max did not have any visits"); - }}))) - .andExpect(view().name("owners/ownerDetails")); - } + @Override + public void describeTo(Description description) { + description.appendText("Max did not have any visits"); + } + }))).andExpect(view().name("owners/ownerDetails")); + } } diff --git a/src/test/java/org/springframework/samples/petclinic/owner/PetControllerTests.java b/src/test/java/org/springframework/samples/petclinic/owner/PetControllerTests.java index f7c8fe726..47c444a78 100755 --- a/src/test/java/org/springframework/samples/petclinic/owner/PetControllerTests.java +++ b/src/test/java/org/springframework/samples/petclinic/owner/PetControllerTests.java @@ -39,97 +39,75 @@ import org.springframework.test.web.servlet.MockMvc; * @author Colin But */ @WebMvcTest(value = PetController.class, - includeFilters = @ComponentScan.Filter( - value = PetTypeFormatter.class, - type = FilterType.ASSIGNABLE_TYPE)) + includeFilters = @ComponentScan.Filter(value = PetTypeFormatter.class, type = FilterType.ASSIGNABLE_TYPE)) class PetControllerTests { - private static final int TEST_OWNER_ID = 1; - private static final int TEST_PET_ID = 1; + private static final int TEST_OWNER_ID = 1; + private static final int TEST_PET_ID = 1; - @Autowired - private MockMvc mockMvc; + @Autowired + private MockMvc mockMvc; - @MockBean - private PetRepository pets; + @MockBean + private PetRepository pets; - @MockBean - private OwnerRepository owners; + @MockBean + private OwnerRepository owners; - @BeforeEach - void setup() { - PetType cat = new PetType(); - cat.setId(3); - cat.setName("hamster"); - given(this.pets.findPetTypes()).willReturn(Lists.newArrayList(cat)); - given(this.owners.findById(TEST_OWNER_ID)).willReturn(new Owner()); - given(this.pets.findById(TEST_PET_ID)).willReturn(new Pet()); + @BeforeEach + void setup() { + PetType cat = new PetType(); + cat.setId(3); + cat.setName("hamster"); + given(this.pets.findPetTypes()).willReturn(Lists.newArrayList(cat)); + given(this.owners.findById(TEST_OWNER_ID)).willReturn(new Owner()); + given(this.pets.findById(TEST_PET_ID)).willReturn(new Pet()); - } + } - @Test - void testInitCreationForm() throws Exception { - mockMvc.perform(get("/owners/{ownerId}/pets/new", TEST_OWNER_ID)) - .andExpect(status().isOk()) - .andExpect(view().name("pets/createOrUpdatePetForm")) - .andExpect(model().attributeExists("pet")); - } + @Test + void testInitCreationForm() throws Exception { + mockMvc.perform(get("/owners/{ownerId}/pets/new", TEST_OWNER_ID)).andExpect(status().isOk()) + .andExpect(view().name("pets/createOrUpdatePetForm")).andExpect(model().attributeExists("pet")); + } - @Test - void testProcessCreationFormSuccess() throws Exception { - mockMvc.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID) - .param("name", "Betty") - .param("type", "hamster") - .param("birthDate", "2015-02-12") - ) - .andExpect(status().is3xxRedirection()) - .andExpect(view().name("redirect:/owners/{ownerId}")); - } + @Test + void testProcessCreationFormSuccess() throws Exception { + mockMvc.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID).param("name", "Betty") + .param("type", "hamster").param("birthDate", "2015-02-12")).andExpect(status().is3xxRedirection()) + .andExpect(view().name("redirect:/owners/{ownerId}")); + } - @Test - void testProcessCreationFormHasErrors() throws Exception { - mockMvc.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID) - .param("name", "Betty") - .param("birthDate", "2015-02-12") - ) - .andExpect(model().attributeHasNoErrors("owner")) - .andExpect(model().attributeHasErrors("pet")) - .andExpect(model().attributeHasFieldErrors("pet", "type")) - .andExpect(model().attributeHasFieldErrorCode("pet", "type", "required")) - .andExpect(status().isOk()) - .andExpect(view().name("pets/createOrUpdatePetForm")); - } + @Test + void testProcessCreationFormHasErrors() throws Exception { + mockMvc.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID).param("name", "Betty").param("birthDate", + "2015-02-12")).andExpect(model().attributeHasNoErrors("owner")) + .andExpect(model().attributeHasErrors("pet")).andExpect(model().attributeHasFieldErrors("pet", "type")) + .andExpect(model().attributeHasFieldErrorCode("pet", "type", "required")).andExpect(status().isOk()) + .andExpect(view().name("pets/createOrUpdatePetForm")); + } - @Test - void testInitUpdateForm() throws Exception { - mockMvc.perform(get("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID)) - .andExpect(status().isOk()) - .andExpect(model().attributeExists("pet")) - .andExpect(view().name("pets/createOrUpdatePetForm")); - } + @Test + void testInitUpdateForm() throws Exception { + mockMvc.perform(get("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID)) + .andExpect(status().isOk()).andExpect(model().attributeExists("pet")) + .andExpect(view().name("pets/createOrUpdatePetForm")); + } - @Test - void testProcessUpdateFormSuccess() throws Exception { - mockMvc.perform(post("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID) - .param("name", "Betty") - .param("type", "hamster") - .param("birthDate", "2015-02-12") - ) - .andExpect(status().is3xxRedirection()) - .andExpect(view().name("redirect:/owners/{ownerId}")); - } + @Test + void testProcessUpdateFormSuccess() throws Exception { + mockMvc.perform(post("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID).param("name", "Betty") + .param("type", "hamster").param("birthDate", "2015-02-12")).andExpect(status().is3xxRedirection()) + .andExpect(view().name("redirect:/owners/{ownerId}")); + } - @Test - void testProcessUpdateFormHasErrors() throws Exception { - mockMvc.perform(post("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID) - .param("name", "Betty") - .param("birthDate", "2015/02/12") - ) - .andExpect(model().attributeHasNoErrors("owner")) - .andExpect(model().attributeHasErrors("pet")) - .andExpect(status().isOk()) - .andExpect(view().name("pets/createOrUpdatePetForm")); - } + @Test + void testProcessUpdateFormHasErrors() throws Exception { + mockMvc.perform(post("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID).param("name", "Betty") + .param("birthDate", "2015/02/12")).andExpect(model().attributeHasNoErrors("owner")) + .andExpect(model().attributeHasErrors("pet")).andExpect(status().isOk()) + .andExpect(view().name("pets/createOrUpdatePetForm")); + } } diff --git a/src/test/java/org/springframework/samples/petclinic/owner/PetTypeFormatterTests.java b/src/test/java/org/springframework/samples/petclinic/owner/PetTypeFormatterTests.java index e27fce21e..adb96b69d 100644 --- a/src/test/java/org/springframework/samples/petclinic/owner/PetTypeFormatterTests.java +++ b/src/test/java/org/springframework/samples/petclinic/owner/PetTypeFormatterTests.java @@ -40,57 +40,56 @@ import static org.mockito.BDDMockito.given; @ExtendWith(MockitoExtension.class) class PetTypeFormatterTests { - @Mock - private PetRepository pets; + @Mock + private PetRepository pets; - private PetTypeFormatter petTypeFormatter; + private PetTypeFormatter petTypeFormatter; - @BeforeEach - void setup() { - this.petTypeFormatter = new PetTypeFormatter(pets); - } + @BeforeEach + void setup() { + this.petTypeFormatter = new PetTypeFormatter(pets); + } - @Test - void testPrint() { - PetType petType = new PetType(); - petType.setName("Hamster"); - String petTypeName = this.petTypeFormatter.print(petType, Locale.ENGLISH); - assertThat(petTypeName).isEqualTo("Hamster"); - } + @Test + void testPrint() { + PetType petType = new PetType(); + petType.setName("Hamster"); + String petTypeName = this.petTypeFormatter.print(petType, Locale.ENGLISH); + assertThat(petTypeName).isEqualTo("Hamster"); + } - @Test - void shouldParse() throws ParseException { - given(this.pets.findPetTypes()).willReturn(makePetTypes()); - PetType petType = petTypeFormatter.parse("Bird", Locale.ENGLISH); - assertThat(petType.getName()).isEqualTo("Bird"); - } + @Test + void shouldParse() throws ParseException { + given(this.pets.findPetTypes()).willReturn(makePetTypes()); + PetType petType = petTypeFormatter.parse("Bird", Locale.ENGLISH); + assertThat(petType.getName()).isEqualTo("Bird"); + } - @Test - void shouldThrowParseException() throws ParseException { - given(this.pets.findPetTypes()).willReturn(makePetTypes()); - Assertions.assertThrows(ParseException.class, () -> { - petTypeFormatter.parse("Fish", Locale.ENGLISH); - }); - } + @Test + void shouldThrowParseException() throws ParseException { + given(this.pets.findPetTypes()).willReturn(makePetTypes()); + Assertions.assertThrows(ParseException.class, () -> { + petTypeFormatter.parse("Fish", Locale.ENGLISH); + }); + } - /** - * Helper method to produce some sample pet types just for test purpose - * - * @return {@link Collection} of {@link PetType} - */ - private List makePetTypes() { - List petTypes = new ArrayList<>(); - petTypes.add(new PetType() { - { - setName("Dog"); - } - }); - petTypes.add(new PetType() { - { - setName("Bird"); - } - }); - return petTypes; - } + /** + * Helper method to produce some sample pet types just for test purpose + * @return {@link Collection} of {@link PetType} + */ + private List makePetTypes() { + List petTypes = new ArrayList<>(); + petTypes.add(new PetType() { + { + setName("Dog"); + } + }); + petTypes.add(new PetType() { + { + setName("Bird"); + } + }); + return petTypes; + } } diff --git a/src/test/java/org/springframework/samples/petclinic/owner/VisitControllerTests.java b/src/test/java/org/springframework/samples/petclinic/owner/VisitControllerTests.java index f61d34c9c..84bee72df 100644 --- a/src/test/java/org/springframework/samples/petclinic/owner/VisitControllerTests.java +++ b/src/test/java/org/springframework/samples/petclinic/owner/VisitControllerTests.java @@ -39,47 +39,40 @@ import org.springframework.test.web.servlet.MockMvc; @WebMvcTest(VisitController.class) class VisitControllerTests { - private static final int TEST_PET_ID = 1; + private static final int TEST_PET_ID = 1; - @Autowired - private MockMvc mockMvc; + @Autowired + private MockMvc mockMvc; - @MockBean - private VisitRepository visits; + @MockBean + private VisitRepository visits; - @MockBean - private PetRepository pets; + @MockBean + private PetRepository pets; - @BeforeEach - void init() { - given(this.pets.findById(TEST_PET_ID)).willReturn(new Pet()); - } + @BeforeEach + void init() { + given(this.pets.findById(TEST_PET_ID)).willReturn(new Pet()); + } - @Test - void testInitNewVisitForm() throws Exception { - mockMvc.perform(get("/owners/*/pets/{petId}/visits/new", TEST_PET_ID)) - .andExpect(status().isOk()) - .andExpect(view().name("pets/createOrUpdateVisitForm")); - } + @Test + void testInitNewVisitForm() throws Exception { + mockMvc.perform(get("/owners/*/pets/{petId}/visits/new", TEST_PET_ID)).andExpect(status().isOk()) + .andExpect(view().name("pets/createOrUpdateVisitForm")); + } - @Test - void testProcessNewVisitFormSuccess() throws Exception { - mockMvc.perform(post("/owners/*/pets/{petId}/visits/new", TEST_PET_ID) - .param("name", "George") - .param("description", "Visit Description") - ) - .andExpect(status().is3xxRedirection()) - .andExpect(view().name("redirect:/owners/{ownerId}")); - } + @Test + void testProcessNewVisitFormSuccess() throws Exception { + mockMvc.perform(post("/owners/*/pets/{petId}/visits/new", TEST_PET_ID).param("name", "George") + .param("description", "Visit Description")).andExpect(status().is3xxRedirection()) + .andExpect(view().name("redirect:/owners/{ownerId}")); + } - @Test - void testProcessNewVisitFormHasErrors() throws Exception { - mockMvc.perform(post("/owners/*/pets/{petId}/visits/new", TEST_PET_ID) - .param("name", "George") - ) - .andExpect(model().attributeHasErrors("visit")) - .andExpect(status().isOk()) - .andExpect(view().name("pets/createOrUpdateVisitForm")); - } + @Test + void testProcessNewVisitFormHasErrors() throws Exception { + mockMvc.perform(post("/owners/*/pets/{petId}/visits/new", TEST_PET_ID).param("name", "George")) + .andExpect(model().attributeHasErrors("visit")).andExpect(status().isOk()) + .andExpect(view().name("pets/createOrUpdateVisitForm")); + } } diff --git a/src/test/java/org/springframework/samples/petclinic/service/ClinicServiceTests.java b/src/test/java/org/springframework/samples/petclinic/service/ClinicServiceTests.java index f11f98373..a7f3d9d24 100644 --- a/src/test/java/org/springframework/samples/petclinic/service/ClinicServiceTests.java +++ b/src/test/java/org/springframework/samples/petclinic/service/ClinicServiceTests.java @@ -40,15 +40,24 @@ import org.springframework.transaction.annotation.Transactional; /** * Integration test of the Service and the Repository layer. *

- * ClinicServiceSpringDataJpaTests subclasses benefit from the following services provided by the Spring - * TestContext Framework:

  • Spring IoC container caching which spares us unnecessary set up - * time between test execution.
  • Dependency Injection of test fixture instances, meaning that - * we don't need to perform application context lookups. See the use of {@link Autowired @Autowired} on the {@link - * ClinicServiceTests#clinicService clinicService} instance variable, which uses autowiring by - * type.
  • Transaction management, meaning each test method is executed in its own transaction, - * which is automatically rolled back by default. Thus, even if tests insert or otherwise change database state, there - * is no need for a teardown or cleanup script.
  • An {@link org.springframework.context.ApplicationContext - * ApplicationContext} is also inherited and can be used for explicit bean lookup if necessary.
+ * ClinicServiceSpringDataJpaTests subclasses benefit from the following services provided + * by the Spring TestContext Framework: + *

+ *
    + *
  • Spring IoC container caching which spares us unnecessary set up + * time between test execution.
  • + *
  • Dependency Injection of test fixture instances, meaning that we + * don't need to perform application context lookups. See the use of + * {@link Autowired @Autowired} on the {@link + * ClinicServiceTests#clinicService clinicService} instance variable, which uses + * autowiring by type. + *
  • Transaction management, meaning each test method is executed in + * its own transaction, which is automatically rolled back by default. Thus, even if tests + * insert or otherwise change database state, there is no need for a teardown or cleanup + * script. + *
  • An {@link org.springframework.context.ApplicationContext ApplicationContext} is + * also inherited and can be used for explicit bean lookup if necessary.
  • + *
* * @author Ken Krebs * @author Rod Johnson @@ -60,159 +69,159 @@ import org.springframework.transaction.annotation.Transactional; @DataJpaTest(includeFilters = @ComponentScan.Filter(Service.class)) class ClinicServiceTests { - @Autowired - protected OwnerRepository owners; + @Autowired + protected OwnerRepository owners; - @Autowired - protected PetRepository pets; + @Autowired + protected PetRepository pets; - @Autowired - protected VisitRepository visits; + @Autowired + protected VisitRepository visits; - @Autowired - protected VetRepository vets; + @Autowired + protected VetRepository vets; - @Test - void shouldFindOwnersByLastName() { - Collection owners = this.owners.findByLastName("Davis"); - assertThat(owners).hasSize(2); + @Test + void shouldFindOwnersByLastName() { + Collection owners = this.owners.findByLastName("Davis"); + assertThat(owners).hasSize(2); - owners = this.owners.findByLastName("Daviss"); - assertThat(owners).isEmpty(); - } + owners = this.owners.findByLastName("Daviss"); + assertThat(owners).isEmpty(); + } - @Test - void shouldFindSingleOwnerWithPet() { - Owner owner = this.owners.findById(1); - assertThat(owner.getLastName()).startsWith("Franklin"); - assertThat(owner.getPets()).hasSize(1); - assertThat(owner.getPets().get(0).getType()).isNotNull(); - assertThat(owner.getPets().get(0).getType().getName()).isEqualTo("cat"); - } + @Test + void shouldFindSingleOwnerWithPet() { + Owner owner = this.owners.findById(1); + assertThat(owner.getLastName()).startsWith("Franklin"); + assertThat(owner.getPets()).hasSize(1); + assertThat(owner.getPets().get(0).getType()).isNotNull(); + assertThat(owner.getPets().get(0).getType().getName()).isEqualTo("cat"); + } - @Test - @Transactional - void shouldInsertOwner() { - Collection owners = this.owners.findByLastName("Schultz"); - int found = owners.size(); + @Test + @Transactional + void shouldInsertOwner() { + Collection owners = this.owners.findByLastName("Schultz"); + int found = owners.size(); - Owner owner = new Owner(); - owner.setFirstName("Sam"); - owner.setLastName("Schultz"); - owner.setAddress("4, Evans Street"); - owner.setCity("Wollongong"); - owner.setTelephone("4444444444"); - this.owners.save(owner); - assertThat(owner.getId().longValue()).isNotEqualTo(0); + Owner owner = new Owner(); + owner.setFirstName("Sam"); + owner.setLastName("Schultz"); + owner.setAddress("4, Evans Street"); + owner.setCity("Wollongong"); + owner.setTelephone("4444444444"); + this.owners.save(owner); + assertThat(owner.getId().longValue()).isNotEqualTo(0); - owners = this.owners.findByLastName("Schultz"); - assertThat(owners.size()).isEqualTo(found + 1); - } + owners = this.owners.findByLastName("Schultz"); + assertThat(owners.size()).isEqualTo(found + 1); + } - @Test - @Transactional - void shouldUpdateOwner() { - Owner owner = this.owners.findById(1); - String oldLastName = owner.getLastName(); - String newLastName = oldLastName + "X"; + @Test + @Transactional + void shouldUpdateOwner() { + Owner owner = this.owners.findById(1); + String oldLastName = owner.getLastName(); + String newLastName = oldLastName + "X"; - owner.setLastName(newLastName); - this.owners.save(owner); + owner.setLastName(newLastName); + this.owners.save(owner); - // retrieving new name from database - owner = this.owners.findById(1); - assertThat(owner.getLastName()).isEqualTo(newLastName); - } + // retrieving new name from database + owner = this.owners.findById(1); + assertThat(owner.getLastName()).isEqualTo(newLastName); + } - @Test - void shouldFindPetWithCorrectId() { - Pet pet7 = this.pets.findById(7); - assertThat(pet7.getName()).startsWith("Samantha"); - assertThat(pet7.getOwner().getFirstName()).isEqualTo("Jean"); + @Test + void shouldFindPetWithCorrectId() { + Pet pet7 = this.pets.findById(7); + assertThat(pet7.getName()).startsWith("Samantha"); + assertThat(pet7.getOwner().getFirstName()).isEqualTo("Jean"); - } + } - @Test - void shouldFindAllPetTypes() { - Collection petTypes = this.pets.findPetTypes(); + @Test + void shouldFindAllPetTypes() { + Collection petTypes = this.pets.findPetTypes(); - PetType petType1 = EntityUtils.getById(petTypes, PetType.class, 1); - assertThat(petType1.getName()).isEqualTo("cat"); - PetType petType4 = EntityUtils.getById(petTypes, PetType.class, 4); - assertThat(petType4.getName()).isEqualTo("snake"); - } + PetType petType1 = EntityUtils.getById(petTypes, PetType.class, 1); + assertThat(petType1.getName()).isEqualTo("cat"); + PetType petType4 = EntityUtils.getById(petTypes, PetType.class, 4); + assertThat(petType4.getName()).isEqualTo("snake"); + } - @Test - @Transactional - void shouldInsertPetIntoDatabaseAndGenerateId() { - Owner owner6 = this.owners.findById(6); - int found = owner6.getPets().size(); + @Test + @Transactional + void shouldInsertPetIntoDatabaseAndGenerateId() { + Owner owner6 = this.owners.findById(6); + int found = owner6.getPets().size(); - Pet pet = new Pet(); - pet.setName("bowser"); - Collection types = this.pets.findPetTypes(); - pet.setType(EntityUtils.getById(types, PetType.class, 2)); - pet.setBirthDate(LocalDate.now()); - owner6.addPet(pet); - assertThat(owner6.getPets().size()).isEqualTo(found + 1); + Pet pet = new Pet(); + pet.setName("bowser"); + Collection types = this.pets.findPetTypes(); + pet.setType(EntityUtils.getById(types, PetType.class, 2)); + pet.setBirthDate(LocalDate.now()); + owner6.addPet(pet); + assertThat(owner6.getPets().size()).isEqualTo(found + 1); - this.pets.save(pet); - this.owners.save(owner6); + this.pets.save(pet); + this.owners.save(owner6); - owner6 = this.owners.findById(6); - assertThat(owner6.getPets().size()).isEqualTo(found + 1); - // checks that id has been generated - assertThat(pet.getId()).isNotNull(); - } + owner6 = this.owners.findById(6); + assertThat(owner6.getPets().size()).isEqualTo(found + 1); + // checks that id has been generated + assertThat(pet.getId()).isNotNull(); + } - @Test - @Transactional - void shouldUpdatePetName() throws Exception { - Pet pet7 = this.pets.findById(7); - String oldName = pet7.getName(); + @Test + @Transactional + void shouldUpdatePetName() throws Exception { + Pet pet7 = this.pets.findById(7); + String oldName = pet7.getName(); - String newName = oldName + "X"; - pet7.setName(newName); - this.pets.save(pet7); + String newName = oldName + "X"; + pet7.setName(newName); + this.pets.save(pet7); - pet7 = this.pets.findById(7); - assertThat(pet7.getName()).isEqualTo(newName); - } + pet7 = this.pets.findById(7); + assertThat(pet7.getName()).isEqualTo(newName); + } - @Test - void shouldFindVets() { - Collection vets = this.vets.findAll(); + @Test + void shouldFindVets() { + Collection vets = this.vets.findAll(); - Vet vet = EntityUtils.getById(vets, Vet.class, 3); - assertThat(vet.getLastName()).isEqualTo("Douglas"); - assertThat(vet.getNrOfSpecialties()).isEqualTo(2); - assertThat(vet.getSpecialties().get(0).getName()).isEqualTo("dentistry"); - assertThat(vet.getSpecialties().get(1).getName()).isEqualTo("surgery"); - } + Vet vet = EntityUtils.getById(vets, Vet.class, 3); + assertThat(vet.getLastName()).isEqualTo("Douglas"); + assertThat(vet.getNrOfSpecialties()).isEqualTo(2); + assertThat(vet.getSpecialties().get(0).getName()).isEqualTo("dentistry"); + assertThat(vet.getSpecialties().get(1).getName()).isEqualTo("surgery"); + } - @Test - @Transactional - void shouldAddNewVisitForPet() { - Pet pet7 = this.pets.findById(7); - int found = pet7.getVisits().size(); - Visit visit = new Visit(); - pet7.addVisit(visit); - visit.setDescription("test"); - this.visits.save(visit); - this.pets.save(pet7); + @Test + @Transactional + void shouldAddNewVisitForPet() { + Pet pet7 = this.pets.findById(7); + int found = pet7.getVisits().size(); + Visit visit = new Visit(); + pet7.addVisit(visit); + visit.setDescription("test"); + this.visits.save(visit); + this.pets.save(pet7); - pet7 = this.pets.findById(7); - assertThat(pet7.getVisits().size()).isEqualTo(found + 1); - assertThat(visit.getId()).isNotNull(); - } + pet7 = this.pets.findById(7); + assertThat(pet7.getVisits().size()).isEqualTo(found + 1); + assertThat(visit.getId()).isNotNull(); + } - @Test - void shouldFindVisitsByPetId() throws Exception { - Collection visits = this.visits.findByPetId(7); - assertThat(visits).hasSize(2); - Visit[] visitArr = visits.toArray(new Visit[visits.size()]); - assertThat(visitArr[0].getDate()).isNotNull(); - assertThat(visitArr[0].getPetId()).isEqualTo(7); - } + @Test + void shouldFindVisitsByPetId() throws Exception { + Collection visits = this.visits.findByPetId(7); + assertThat(visits).hasSize(2); + Visit[] visitArr = visits.toArray(new Visit[visits.size()]); + assertThat(visitArr[0].getDate()).isNotNull(); + assertThat(visitArr[0].getPetId()).isEqualTo(7); + } } diff --git a/src/test/java/org/springframework/samples/petclinic/service/EntityUtils.java b/src/test/java/org/springframework/samples/petclinic/service/EntityUtils.java index 8890cc59a..ca8bc41fc 100644 --- a/src/test/java/org/springframework/samples/petclinic/service/EntityUtils.java +++ b/src/test/java/org/springframework/samples/petclinic/service/EntityUtils.java @@ -22,8 +22,8 @@ import org.springframework.orm.ObjectRetrievalFailureException; import org.springframework.samples.petclinic.model.BaseEntity; /** - * Utility methods for handling entities. Separate from the BaseEntity class mainly because of dependency on the - * ORM-associated ObjectRetrievalFailureException. + * Utility methods for handling entities. Separate from the BaseEntity class mainly + * because of dependency on the ORM-associated ObjectRetrievalFailureException. * * @author Juergen Hoeller * @author Sam Brannen @@ -32,23 +32,22 @@ import org.springframework.samples.petclinic.model.BaseEntity; */ public abstract class EntityUtils { - /** - * Look up the entity of the given class with the given id in the given collection. - * - * @param entities the collection to search - * @param entityClass the entity class to look up - * @param entityId the entity id to look up - * @return the found entity - * @throws ObjectRetrievalFailureException if the entity was not found - */ - public static T getById(Collection entities, Class entityClass, int entityId) - throws ObjectRetrievalFailureException { - for (T entity : entities) { - if (entity.getId() == entityId && entityClass.isInstance(entity)) { - return entity; - } - } - throw new ObjectRetrievalFailureException(entityClass, entityId); - } + /** + * Look up the entity of the given class with the given id in the given collection. + * @param entities the collection to search + * @param entityClass the entity class to look up + * @param entityId the entity id to look up + * @return the found entity + * @throws ObjectRetrievalFailureException if the entity was not found + */ + public static T getById(Collection entities, Class entityClass, int entityId) + throws ObjectRetrievalFailureException { + for (T entity : entities) { + if (entity.getId() == entityId && entityClass.isInstance(entity)) { + return entity; + } + } + throw new ObjectRetrievalFailureException(entityClass, entityId); + } } diff --git a/src/test/java/org/springframework/samples/petclinic/system/CrashControllerTests.java b/src/test/java/org/springframework/samples/petclinic/system/CrashControllerTests.java index f15689ce2..6bafc7499 100644 --- a/src/test/java/org/springframework/samples/petclinic/system/CrashControllerTests.java +++ b/src/test/java/org/springframework/samples/petclinic/system/CrashControllerTests.java @@ -38,13 +38,14 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @WebMvcTest(controllers = CrashController.class) class CrashControllerTests { - @Autowired - private MockMvc mockMvc; + @Autowired + private MockMvc mockMvc; + + @Test + void testTriggerException() throws Exception { + mockMvc.perform(get("/oups")).andExpect(view().name("exception")) + .andExpect(model().attributeExists("exception")).andExpect(forwardedUrl("exception")) + .andExpect(status().isOk()); + } - @Test - void testTriggerException() throws Exception { - mockMvc.perform(get("/oups")).andExpect(view().name("exception")) - .andExpect(model().attributeExists("exception")) - .andExpect(forwardedUrl("exception")).andExpect(status().isOk()); - } } diff --git a/src/test/java/org/springframework/samples/petclinic/vet/VetControllerTests.java b/src/test/java/org/springframework/samples/petclinic/vet/VetControllerTests.java index 5b6d387e7..fd537bee2 100644 --- a/src/test/java/org/springframework/samples/petclinic/vet/VetControllerTests.java +++ b/src/test/java/org/springframework/samples/petclinic/vet/VetControllerTests.java @@ -40,43 +40,41 @@ import org.springframework.test.web.servlet.ResultActions; @WebMvcTest(VetController.class) class VetControllerTests { - @Autowired - private MockMvc mockMvc; + @Autowired + private MockMvc mockMvc; - @MockBean - private VetRepository vets; + @MockBean + private VetRepository vets; - @BeforeEach - void setup() { - Vet james = new Vet(); - james.setFirstName("James"); - james.setLastName("Carter"); - james.setId(1); - Vet helen = new Vet(); - helen.setFirstName("Helen"); - helen.setLastName("Leary"); - helen.setId(2); - Specialty radiology = new Specialty(); - radiology.setId(1); - radiology.setName("radiology"); - helen.addSpecialty(radiology); - given(this.vets.findAll()).willReturn(Lists.newArrayList(james, helen)); - } + @BeforeEach + void setup() { + Vet james = new Vet(); + james.setFirstName("James"); + james.setLastName("Carter"); + james.setId(1); + Vet helen = new Vet(); + helen.setFirstName("Helen"); + helen.setLastName("Leary"); + helen.setId(2); + Specialty radiology = new Specialty(); + radiology.setId(1); + radiology.setName("radiology"); + helen.addSpecialty(radiology); + given(this.vets.findAll()).willReturn(Lists.newArrayList(james, helen)); + } - @Test - void testShowVetListHtml() throws Exception { - mockMvc.perform(get("/vets.html")) - .andExpect(status().isOk()) - .andExpect(model().attributeExists("vets")) - .andExpect(view().name("vets/vetList")); - } + @Test + void testShowVetListHtml() throws Exception { + mockMvc.perform(get("/vets.html")).andExpect(status().isOk()).andExpect(model().attributeExists("vets")) + .andExpect(view().name("vets/vetList")); + } - @Test - void testShowResourcesVetList() throws Exception { - ResultActions actions = mockMvc.perform(get("/vets") - .accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk()); - actions.andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.vetList[0].id").value(1)); - } + @Test + void testShowResourcesVetList() throws Exception { + ResultActions actions = mockMvc.perform(get("/vets").accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + actions.andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$.vetList[0].id").value(1)); + } } diff --git a/src/test/java/org/springframework/samples/petclinic/vet/VetTests.java b/src/test/java/org/springframework/samples/petclinic/vet/VetTests.java index 82163eb14..d8df78b85 100644 --- a/src/test/java/org/springframework/samples/petclinic/vet/VetTests.java +++ b/src/test/java/org/springframework/samples/petclinic/vet/VetTests.java @@ -25,17 +25,16 @@ import static org.assertj.core.api.Assertions.assertThat; */ class VetTests { - @Test - void testSerialization() { - Vet vet = new Vet(); - vet.setFirstName("Zaphod"); - vet.setLastName("Beeblebrox"); - vet.setId(123); - Vet other = (Vet) SerializationUtils - .deserialize(SerializationUtils.serialize(vet)); - assertThat(other.getFirstName()).isEqualTo(vet.getFirstName()); - assertThat(other.getLastName()).isEqualTo(vet.getLastName()); - assertThat(other.getId()).isEqualTo(vet.getId()); - } + @Test + void testSerialization() { + Vet vet = new Vet(); + vet.setFirstName("Zaphod"); + vet.setLastName("Beeblebrox"); + vet.setId(123); + Vet other = (Vet) SerializationUtils.deserialize(SerializationUtils.serialize(vet)); + assertThat(other.getFirstName()).isEqualTo(vet.getFirstName()); + assertThat(other.getLastName()).isEqualTo(vet.getLastName()); + assertThat(other.getId()).isEqualTo(vet.getId()); + } }