mirror of
https://github.com/spring-projects/spring-petclinic.git
synced 2025-07-23 07:45:49 +00:00
FIX CONFLICT I18N
This commit is contained in:
commit
f0eb91826f
61 changed files with 1463 additions and 1329 deletions
|
@ -10,3 +10,12 @@ indent_style = space
|
||||||
[*.{java,xml}]
|
[*.{java,xml}]
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
trim_trailing_whitespace = true
|
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
|
||||||
|
|
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -8,9 +8,5 @@ target/*
|
||||||
*.iml
|
*.iml
|
||||||
/target
|
/target
|
||||||
.sts4-cache/
|
.sts4-cache/
|
||||||
.vscode/*
|
.vscode
|
||||||
!.vscode/settings.json
|
|
||||||
!.vscode/tasks.json
|
|
||||||
!.vscode/launch.json
|
|
||||||
!.vscode/extensions.json
|
|
||||||
_site/
|
_site/
|
||||||
|
|
4
.mvn/wrapper/MavenWrapperDownloader.java
vendored
4
.mvn/wrapper/MavenWrapperDownloader.java
vendored
|
@ -5,7 +5,7 @@
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* 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
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
@ -20,7 +20,7 @@ import java.util.Properties;
|
||||||
|
|
||||||
public class MavenWrapperDownloader {
|
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.
|
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
|
||||||
*/
|
*/
|
||||||
|
|
BIN
.mvn/wrapper/maven-wrapper.jar
vendored
BIN
.mvn/wrapper/maven-wrapper.jar
vendored
Binary file not shown.
5
.mvn/wrapper/maven-wrapper.properties
vendored
5
.mvn/wrapper/maven-wrapper.properties
vendored
|
@ -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
|
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.5/maven-wrapper-0.5.5.jar
|
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
|
||||||
|
|
||||||
|
|
26
.vscode/launch.json
vendored
26
.vscode/launch.json
vendored
|
@ -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<spring-petclinic>",
|
|
||||||
"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
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
@ -1,3 +0,0 @@
|
||||||
{
|
|
||||||
"java.configuration.updateBuildConfiguration": "interactive"
|
|
||||||
}
|
|
19
.vscode/tasks.json
vendored
19
.vscode/tasks.json
vendored
|
@ -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"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -3,7 +3,10 @@ mysql:
|
||||||
ports:
|
ports:
|
||||||
- "3306:3306"
|
- "3306:3306"
|
||||||
environment:
|
environment:
|
||||||
- MYSQL_ROOT_PASSWORD=petclinic
|
- MYSQL_ROOT_PASSWORD=
|
||||||
|
- MYSQL_ALLOW_EMPTY_PASSWORD=true
|
||||||
|
- MYSQL_USER=petclinic
|
||||||
|
- MYSQL_PASSWORD=petclinic
|
||||||
- MYSQL_DATABASE=petclinic
|
- MYSQL_DATABASE=petclinic
|
||||||
volumes:
|
volumes:
|
||||||
- "./conf.d:/etc/mysql/conf.d:ro"
|
- "./conf.d:/etc/mysql/conf.d:ro"
|
||||||
|
|
8
mvnw
vendored
8
mvnw
vendored
|
@ -8,7 +8,7 @@
|
||||||
# "License"); you may not use this file except in compliance
|
# "License"); you may not use this file except in compliance
|
||||||
# with the License. You may obtain a copy of the License at
|
# 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,
|
# Unless required by applicable law or agreed to in writing,
|
||||||
# software distributed under the License is distributed on an
|
# 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:
|
# Required ENV vars:
|
||||||
# ------------------
|
# ------------------
|
||||||
|
@ -212,9 +212,9 @@ else
|
||||||
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
|
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
|
||||||
fi
|
fi
|
||||||
if [ -n "$MVNW_REPOURL" ]; then
|
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
|
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
|
fi
|
||||||
while IFS="=" read key value; do
|
while IFS="=" read key value; do
|
||||||
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
|
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
|
||||||
|
|
8
mvnw.cmd
vendored
8
mvnw.cmd
vendored
|
@ -7,7 +7,7 @@
|
||||||
@REM "License"); you may not use this file except in compliance
|
@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 with the License. You may obtain a copy of the License at
|
||||||
@REM
|
@REM
|
||||||
@REM http://www.apache.org/licenses/LICENSE-2.0
|
@REM https://www.apache.org/licenses/LICENSE-2.0'
|
||||||
@REM
|
@REM
|
||||||
@REM Unless required by applicable law or agreed to in writing,
|
@REM Unless required by applicable law or agreed to in writing,
|
||||||
@REM software distributed under the License is distributed on an
|
@REM software distributed under the License is distributed on an
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
@REM ----------------------------------------------------------------------------
|
@REM ----------------------------------------------------------------------------
|
||||||
|
|
||||||
@REM ----------------------------------------------------------------------------
|
@REM ----------------------------------------------------------------------------
|
||||||
@REM Maven2 Start Up Batch script
|
@REM Maven Start Up Batch script
|
||||||
@REM
|
@REM
|
||||||
@REM Required ENV vars:
|
@REM Required ENV vars:
|
||||||
@REM JAVA_HOME - location of a JDK home dir
|
@REM JAVA_HOME - location of a JDK home dir
|
||||||
|
@ -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_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
|
||||||
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
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 (
|
FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
|
||||||
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
|
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
|
||||||
|
@ -134,7 +134,7 @@ if exist %WRAPPER_JAR% (
|
||||||
)
|
)
|
||||||
) else (
|
) else (
|
||||||
if not "%MVNW_REPOURL%" == "" (
|
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" (
|
if "%MVNW_VERBOSE%" == "true" (
|
||||||
echo Couldn't find %WRAPPER_JAR%, downloading it ...
|
echo Couldn't find %WRAPPER_JAR%, downloading it ...
|
||||||
|
|
135
pom.xml
135
pom.xml
|
@ -1,16 +1,16 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>org.springframework.samples</groupId>
|
<groupId>org.springframework.samples</groupId>
|
||||||
<artifactId>spring-petclinic</artifactId>
|
<artifactId>spring-petclinic</artifactId>
|
||||||
<version>2.2.0.BUILD-SNAPSHOT</version>
|
<version>2.4.0.BUILD-SNAPSHOT</version>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-parent</artifactId>
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
<version>2.2.1.RELEASE</version>
|
<version>2.4.1</version>
|
||||||
</parent>
|
</parent>
|
||||||
<name>petclinic</name>
|
<name>petclinic</name>
|
||||||
|
|
||||||
|
@ -28,7 +28,8 @@
|
||||||
<wro4j.version>1.8.0</wro4j.version>
|
<wro4j.version>1.8.0</wro4j.version>
|
||||||
|
|
||||||
<jacoco.version>0.8.5</jacoco.version>
|
<jacoco.version>0.8.5</jacoco.version>
|
||||||
|
<nohttp-checkstyle.version>0.0.4.RELEASE</nohttp-checkstyle.version>
|
||||||
|
<spring-format.version>0.0.25</spring-format.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
@ -49,6 +50,10 @@
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-validation</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||||
|
@ -65,10 +70,10 @@
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Databases - Uses HSQL by default -->
|
<!-- Databases - Uses H2 by default -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hsqldb</groupId>
|
<groupId>com.h2database</groupId>
|
||||||
<artifactId>hsqldb</artifactId>
|
<artifactId>h2</artifactId>
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -109,18 +114,6 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- end of webjars -->
|
<!-- end of webjars -->
|
||||||
|
|
||||||
<!-- Testing -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.junit.jupiter</groupId>
|
|
||||||
<artifactId>junit-jupiter-engine</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.mockito</groupId>
|
|
||||||
<artifactId>mockito-junit-jupiter</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-devtools</artifactId>
|
<artifactId>spring-boot-devtools</artifactId>
|
||||||
|
@ -130,6 +123,53 @@
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>io.spring.javaformat</groupId>
|
||||||
|
<artifactId>spring-javaformat-maven-plugin</artifactId>
|
||||||
|
<version>${spring-format.version}</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>validate</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>validate</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||||
|
<version>3.1.1</version>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.puppycrawl.tools</groupId>
|
||||||
|
<artifactId>checkstyle</artifactId>
|
||||||
|
<version>8.32</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.spring.nohttp</groupId>
|
||||||
|
<artifactId>nohttp-checkstyle</artifactId>
|
||||||
|
<version>${nohttp-checkstyle.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>nohttp-checkstyle-validation</id>
|
||||||
|
<phase>validate</phase>
|
||||||
|
<configuration>
|
||||||
|
<configLocation>src/checkstyle/nohttp-checkstyle.xml</configLocation>
|
||||||
|
<suppressionsLocation>src/checkstyle/nohttp-checkstyle-suppressions.xml</suppressionsLocation>
|
||||||
|
<encoding>UTF-8</encoding>
|
||||||
|
<sourceDirectories>${basedir}</sourceDirectories>
|
||||||
|
<includes>**/*</includes>
|
||||||
|
<excludes>**/.git/**/*,**/.idea/**/*,**/target/**/,**/.flattened-pom.xml,**/*.class</excludes>
|
||||||
|
</configuration>
|
||||||
|
<goals>
|
||||||
|
<goal>check</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
@ -228,7 +268,6 @@
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
<!-- Apache 2 license -->
|
|
||||||
<licenses>
|
<licenses>
|
||||||
<license>
|
<license>
|
||||||
<name>Apache License, Version 2.0</name>
|
<name>Apache License, Version 2.0</name>
|
||||||
|
@ -274,4 +313,60 @@
|
||||||
</pluginRepository>
|
</pluginRepository>
|
||||||
</pluginRepositories>
|
</pluginRepositories>
|
||||||
|
|
||||||
|
<profiles>
|
||||||
|
<profile>
|
||||||
|
<id>m2e</id>
|
||||||
|
<activation>
|
||||||
|
<property>
|
||||||
|
<name>m2e.version</name>
|
||||||
|
</property>
|
||||||
|
</activation>
|
||||||
|
<build>
|
||||||
|
<pluginManagement>
|
||||||
|
<plugins>
|
||||||
|
<!-- This plugin's configuration is used to store Eclipse m2e settings
|
||||||
|
only. It has no influence on the Maven build itself. -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.eclipse.m2e</groupId>
|
||||||
|
<artifactId>lifecycle-mapping</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
<configuration>
|
||||||
|
<lifecycleMappingMetadata>
|
||||||
|
<pluginExecutions>
|
||||||
|
<pluginExecution>
|
||||||
|
<pluginExecutionFilter>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||||
|
<versionRange>[1,)</versionRange>
|
||||||
|
<goals>
|
||||||
|
<goal>check</goal>
|
||||||
|
</goals>
|
||||||
|
</pluginExecutionFilter>
|
||||||
|
<action>
|
||||||
|
<ignore/>
|
||||||
|
</action>
|
||||||
|
</pluginExecution>
|
||||||
|
<pluginExecution>
|
||||||
|
<pluginExecutionFilter>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
<versionRange>[1,)</versionRange>
|
||||||
|
<goals>
|
||||||
|
<goal>build-info</goal>
|
||||||
|
</goals>
|
||||||
|
</pluginExecutionFilter>
|
||||||
|
<action>
|
||||||
|
<ignore/>
|
||||||
|
</action>
|
||||||
|
</pluginExecution>
|
||||||
|
</pluginExecutions>
|
||||||
|
</lifecycleMappingMetadata>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</pluginManagement>
|
||||||
|
</build>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
repo: https://github.com/spring-projects/spring-petclinic.git
|
|
35
readme.md
35
readme.md
|
@ -1,9 +1,4 @@
|
||||||
# Spring PetClinic Sample Application [](https://travis-ci.org/spring-projects/spring-petclinic/)
|
# Spring PetClinic Sample Application [](https://travis-ci.org/spring-projects/spring-petclinic/)
|
||||||
Deploy this sample application to Pivotal Web Services:
|
|
||||||
|
|
||||||
<a href="https://push-to.cfapps.io?repo=https%3A%2F%2Fgithub.com%2Fspring-projects%2Fspring-petclinic.git">
|
|
||||||
<img src="https://push-to.cfapps.io/ui/assets/images/Push-to-Pivotal-Light-with-Shadow.svg" width="180" alt="Push" align="center">
|
|
||||||
</a>
|
|
||||||
|
|
||||||
## Understanding the Spring Petclinic application with a few diagrams
|
## Understanding the Spring Petclinic application with a few diagrams
|
||||||
<a href="https://speakerdeck.com/michaelisvy/spring-petclinic-sample-application">See the presentation here</a>
|
<a href="https://speakerdeck.com/michaelisvy/spring-petclinic-sample-application">See the presentation here</a>
|
||||||
|
@ -35,17 +30,19 @@ Our issue tracker is available here: https://github.com/spring-projects/spring-p
|
||||||
|
|
||||||
## Database configuration
|
## Database configuration
|
||||||
|
|
||||||
In its default configuration, Petclinic uses an in-memory database (HSQLDB) which
|
In its default configuration, Petclinic uses an in-memory database (H2) which
|
||||||
gets populated at startup with data. A similar setup is provided for MySql in case a persistent database configuration is needed.
|
gets populated at startup with data. The h2 console is automatically exposed at `http://localhost:8080/h2-console`
|
||||||
Note that whenever the database type is changed, the app needs to be run with a different profile: `spring.profiles.active=mysql` for MySql.
|
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:
|
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
|
## Working with Petclinic in your IDE
|
||||||
|
|
||||||
|
@ -74,15 +71,11 @@ 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
|
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`
|
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`.
|
||||||
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
|
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'`.
|
||||||
version. Otherwise, run the application by right clicking on the `PetClinicApplication` main class and choosing
|
|
||||||
`Run 'PetClinicApplication'`.
|
|
||||||
|
|
||||||
4) Navigate to Petclinic
|
4) Navigate to Petclinic
|
||||||
|
|
||||||
|
@ -93,13 +86,13 @@ Visit [http://localhost:8080](http://localhost:8080) in your browser.
|
||||||
|
|
||||||
|Spring Boot Configuration | Class or Java property files |
|
|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) |
|
|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/master/src/main/resources) |
|
|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/master/src/main/java/org/springframework/samples/petclinic/system/CacheConfiguration.java) |
|
|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
|
## 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
|
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
|
[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
|
[spring-petclinic](https://github.com/spring-petclinic). If you have a special interest in a different technology stack
|
||||||
|
|
8
src/checkstyle/nohttp-checkstyle-suppressions.xml
Normal file
8
src/checkstyle/nohttp-checkstyle-suppressions.xml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<!DOCTYPE suppressions PUBLIC
|
||||||
|
"-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN"
|
||||||
|
"https://checkstyle.org/dtds/suppressions_1_2.dtd">
|
||||||
|
<suppressions>
|
||||||
|
<suppress files="[\\/]build.log" checks="NoHttp"/>
|
||||||
|
<suppress files=".+\.(jar|git|ico|p12|gif|jks|jpg|svg)" checks="NoHttp"/>
|
||||||
|
</suppressions>
|
7
src/checkstyle/nohttp-checkstyle.xml
Normal file
7
src/checkstyle/nohttp-checkstyle.xml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<!DOCTYPE module PUBLIC
|
||||||
|
"-//Puppy Crawl//DTD Check Configuration 1.2//EN"
|
||||||
|
"https://checkstyle.org/dtds/configuration_1_2.dtd">
|
||||||
|
<module name="com.puppycrawl.tools.checkstyle.Checker">
|
||||||
|
<module name="io.spring.nohttp.checkstyle.check.NoHttpCheck"/>
|
||||||
|
</module>
|
|
@ -31,6 +31,7 @@ import javax.persistence.MappedSuperclass;
|
||||||
*/
|
*/
|
||||||
@MappedSuperclass
|
@MappedSuperclass
|
||||||
public class BaseEntity implements Serializable {
|
public class BaseEntity implements Serializable {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
private Integer id;
|
private Integer id;
|
||||||
|
|
|
@ -18,10 +18,9 @@ package org.springframework.samples.petclinic.model;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.MappedSuperclass;
|
import javax.persistence.MappedSuperclass;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple JavaBean domain object adds a name property to <code>BaseEntity</code>. Used as a base class for objects
|
* Simple JavaBean domain object adds a name property to <code>BaseEntity</code>. Used as
|
||||||
* needing these properties.
|
* a base class for objects needing these properties.
|
||||||
*
|
*
|
||||||
* @author Ken Krebs
|
* @author Ken Krebs
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
|
|
|
@ -18,4 +18,3 @@
|
||||||
* The classes in this package represent utilities used by the domain.
|
* The classes in this package represent utilities used by the domain.
|
||||||
*/
|
*/
|
||||||
package org.springframework.samples.petclinic.model;
|
package org.springframework.samples.petclinic.model;
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@ import org.springframework.samples.petclinic.model.Person;
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "owners")
|
@Table(name = "owners")
|
||||||
public class Owner extends Person {
|
public class Owner extends Person {
|
||||||
|
|
||||||
@Column(name = "address")
|
@Column(name = "address")
|
||||||
@NotEmpty
|
@NotEmpty
|
||||||
private String address;
|
private String address;
|
||||||
|
@ -98,8 +99,7 @@ public class Owner extends Person {
|
||||||
|
|
||||||
public List<Pet> getPets() {
|
public List<Pet> getPets() {
|
||||||
List<Pet> sortedPets = new ArrayList<>(getPetsInternal());
|
List<Pet> sortedPets = new ArrayList<>(getPetsInternal());
|
||||||
PropertyComparator.sort(sortedPets,
|
PropertyComparator.sort(sortedPets, new MutableSortDefinition("name", true, true));
|
||||||
new MutableSortDefinition("name", true, true));
|
|
||||||
return Collections.unmodifiableList(sortedPets);
|
return Collections.unmodifiableList(sortedPets);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +112,6 @@ public class Owner extends Person {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the Pet with the given name, or null if none found for this Owner.
|
* Return the Pet with the given name, or null if none found for this Owner.
|
||||||
*
|
|
||||||
* @param name to test
|
* @param name to test
|
||||||
* @return true if pet name is already in use
|
* @return true if pet name is already in use
|
||||||
*/
|
*/
|
||||||
|
@ -122,7 +121,6 @@ public class Owner extends Person {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the Pet with the given name, or null if none found for this Owner.
|
* Return the Pet with the given name, or null if none found for this Owner.
|
||||||
*
|
|
||||||
* @param name to test
|
* @param name to test
|
||||||
* @return true if pet name is already in use
|
* @return true if pet name is already in use
|
||||||
*/
|
*/
|
||||||
|
@ -144,9 +142,9 @@ public class Owner extends Person {
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return new ToStringCreator(this)
|
return new ToStringCreator(this)
|
||||||
|
|
||||||
.append("id", this.getId()).append("new", this.isNew())
|
.append("id", this.getId()).append("new", this.isNew()).append("lastName", this.getLastName())
|
||||||
.append("lastName", this.getLastName())
|
.append("firstName", this.getFirstName()).append("address", this.address).append("city", this.city)
|
||||||
.append("firstName", this.getFirstName()).append("address", this.address)
|
.append("telephone", this.telephone).toString();
|
||||||
.append("city", this.city).append("telephone", this.telephone).toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,9 +40,10 @@ import java.util.Map;
|
||||||
class OwnerController {
|
class OwnerController {
|
||||||
|
|
||||||
private static final String VIEWS_OWNER_CREATE_OR_UPDATE_FORM = "owners/createOrUpdateOwnerForm";
|
private static final String VIEWS_OWNER_CREATE_OR_UPDATE_FORM = "owners/createOrUpdateOwnerForm";
|
||||||
private final OwnerRepository owners;
|
|
||||||
private VisitRepository visits;
|
|
||||||
|
|
||||||
|
private final OwnerRepository owners;
|
||||||
|
|
||||||
|
private VisitRepository visits;
|
||||||
|
|
||||||
public OwnerController(OwnerRepository clinicService, VisitRepository visits) {
|
public OwnerController(OwnerRepository clinicService, VisitRepository visits) {
|
||||||
this.owners = clinicService;
|
this.owners = clinicService;
|
||||||
|
@ -65,7 +66,8 @@ class OwnerController {
|
||||||
public String processCreationForm(@Valid Owner owner, BindingResult result) {
|
public String processCreationForm(@Valid Owner owner, BindingResult result) {
|
||||||
if (result.hasErrors()) {
|
if (result.hasErrors()) {
|
||||||
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
|
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
this.owners.save(owner);
|
this.owners.save(owner);
|
||||||
return "redirect:/owners/" + owner.getId();
|
return "redirect:/owners/" + owner.getId();
|
||||||
}
|
}
|
||||||
|
@ -91,11 +93,13 @@ class OwnerController {
|
||||||
// no owners found
|
// no owners found
|
||||||
result.rejectValue("lastName", "notFound", "not found");
|
result.rejectValue("lastName", "notFound", "not found");
|
||||||
return "owners/findOwners";
|
return "owners/findOwners";
|
||||||
} else if (results.size() == 1) {
|
}
|
||||||
|
else if (results.size() == 1) {
|
||||||
// 1 owner found
|
// 1 owner found
|
||||||
owner = results.iterator().next();
|
owner = results.iterator().next();
|
||||||
return "redirect:/owners/" + owner.getId();
|
return "redirect:/owners/" + owner.getId();
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
// multiple owners found
|
// multiple owners found
|
||||||
model.put("selections", results);
|
model.put("selections", results);
|
||||||
return "owners/ownersList";
|
return "owners/ownersList";
|
||||||
|
@ -110,10 +114,12 @@ class OwnerController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/owners/{ownerId}/edit")
|
@PostMapping("/owners/{ownerId}/edit")
|
||||||
public String processUpdateOwnerForm(@Valid Owner owner, BindingResult result, @PathVariable("ownerId") int ownerId) {
|
public String processUpdateOwnerForm(@Valid Owner owner, BindingResult result,
|
||||||
|
@PathVariable("ownerId") int ownerId) {
|
||||||
if (result.hasErrors()) {
|
if (result.hasErrors()) {
|
||||||
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
|
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
owner.setId(ownerId);
|
owner.setId(ownerId);
|
||||||
this.owners.save(owner);
|
this.owners.save(owner);
|
||||||
return "redirect:/owners/{ownerId}";
|
return "redirect:/owners/{ownerId}";
|
||||||
|
@ -122,7 +128,6 @@ class OwnerController {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom handler for displaying an owner.
|
* Custom handler for displaying an owner.
|
||||||
*
|
|
||||||
* @param ownerId the ID of the owner to display
|
* @param ownerId the ID of the owner to display
|
||||||
* @return a ModelMap with the model attributes for the view
|
* @return a ModelMap with the model attributes for the view
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -23,9 +23,10 @@ import org.springframework.data.repository.query.Param;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Repository class for <code>Owner</code> domain objects All method names are compliant with Spring Data naming
|
* Repository class for <code>Owner</code> domain objects All method names are compliant
|
||||||
* conventions so this interface can easily be extended for Spring Data.
|
* with Spring Data naming conventions so this interface can easily be extended for Spring
|
||||||
* See: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation
|
* Data. See:
|
||||||
|
* https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation
|
||||||
*
|
*
|
||||||
* @author Ken Krebs
|
* @author Ken Krebs
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
|
@ -60,5 +61,4 @@ public interface OwnerRepository extends Repository<Owner, Integer> {
|
||||||
*/
|
*/
|
||||||
void save(Owner owner);
|
void save(Owner owner);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,8 +100,7 @@ public class Pet extends NamedEntity {
|
||||||
|
|
||||||
public List<Visit> getVisits() {
|
public List<Visit> getVisits() {
|
||||||
List<Visit> sortedVisits = new ArrayList<>(getVisitsInternal());
|
List<Visit> sortedVisits = new ArrayList<>(getVisitsInternal());
|
||||||
PropertyComparator.sort(sortedVisits,
|
PropertyComparator.sort(sortedVisits, new MutableSortDefinition("date", false, false));
|
||||||
new MutableSortDefinition("date", false, false));
|
|
||||||
return Collections.unmodifiableList(sortedVisits);
|
return Collections.unmodifiableList(sortedVisits);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,9 @@ import java.util.Collection;
|
||||||
class PetController {
|
class PetController {
|
||||||
|
|
||||||
private static final String VIEWS_PETS_CREATE_OR_UPDATE_FORM = "pets/createOrUpdatePetForm";
|
private static final String VIEWS_PETS_CREATE_OR_UPDATE_FORM = "pets/createOrUpdatePetForm";
|
||||||
|
|
||||||
private final PetRepository pets;
|
private final PetRepository pets;
|
||||||
|
|
||||||
private final OwnerRepository owners;
|
private final OwnerRepository owners;
|
||||||
|
|
||||||
public PetController(PetRepository pets, OwnerRepository owners) {
|
public PetController(PetRepository pets, OwnerRepository owners) {
|
||||||
|
@ -80,7 +82,8 @@ class PetController {
|
||||||
if (result.hasErrors()) {
|
if (result.hasErrors()) {
|
||||||
model.put("pet", pet);
|
model.put("pet", pet);
|
||||||
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
|
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
this.pets.save(pet);
|
this.pets.save(pet);
|
||||||
return "redirect:/owners/{ownerId}";
|
return "redirect:/owners/{ownerId}";
|
||||||
}
|
}
|
||||||
|
@ -99,7 +102,8 @@ class PetController {
|
||||||
pet.setOwner(owner);
|
pet.setOwner(owner);
|
||||||
model.put("pet", pet);
|
model.put("pet", pet);
|
||||||
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
|
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
owner.addPet(pet);
|
owner.addPet(pet);
|
||||||
this.pets.save(pet);
|
this.pets.save(pet);
|
||||||
return "redirect:/owners/{ownerId}";
|
return "redirect:/owners/{ownerId}";
|
||||||
|
|
|
@ -22,9 +22,10 @@ import org.springframework.data.repository.Repository;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Repository class for <code>Pet</code> domain objects All method names are compliant with Spring Data naming
|
* Repository class for <code>Pet</code> domain objects All method names are compliant
|
||||||
* conventions so this interface can easily be extended for Spring Data.
|
* with Spring Data naming conventions so this interface can easily be extended for Spring
|
||||||
* See: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation
|
* Data. See:
|
||||||
|
* https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation
|
||||||
*
|
*
|
||||||
* @author Ken Krebs
|
* @author Ken Krebs
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
|
@ -56,4 +57,3 @@ public interface PetRepository extends Repository<Pet, Integer> {
|
||||||
void save(Pet pet);
|
void save(Pet pet);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,8 +21,7 @@ import javax.persistence.Table;
|
||||||
import org.springframework.samples.petclinic.model.NamedEntity;
|
import org.springframework.samples.petclinic.model.NamedEntity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller Can be Cat, Dog, Hamster...
|
||||||
* Can be Cat, Dog, Hamster...
|
|
||||||
*/
|
*/
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "types")
|
@Table(name = "types")
|
||||||
|
|
|
@ -24,9 +24,10 @@ import org.springframework.format.Formatter;
|
||||||
import org.springframework.stereotype.Component;
|
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
|
* Instructs Spring MVC on how to parse and print elements of type 'PetType'. Starting
|
||||||
* come as an improvement in comparison to legacy PropertyEditors. See the following links for more details: - The
|
* from Spring 3.0, Formatters have come as an improvement in comparison to legacy
|
||||||
* Spring ref doc: https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#format
|
* 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 Mark Fisher
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
|
@ -37,7 +38,6 @@ public class PetTypeFormatter implements Formatter<PetType> {
|
||||||
|
|
||||||
private final PetRepository pets;
|
private final PetRepository pets;
|
||||||
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public PetTypeFormatter(PetRepository pets) {
|
public PetTypeFormatter(PetRepository pets) {
|
||||||
this.pets = pets;
|
this.pets = pets;
|
||||||
|
|
|
@ -22,7 +22,8 @@ import org.springframework.validation.Validator;
|
||||||
/**
|
/**
|
||||||
* <code>Validator</code> for <code>Pet</code> forms.
|
* <code>Validator</code> for <code>Pet</code> forms.
|
||||||
* <p>
|
* <p>
|
||||||
* 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.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @author Ken Krebs
|
* @author Ken Krebs
|
||||||
|
@ -60,5 +61,4 @@ public class PetValidator implements Validator {
|
||||||
return Pet.class.isAssignableFrom(clazz);
|
return Pet.class.isAssignableFrom(clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,8 +41,8 @@ import org.springframework.web.bind.annotation.PostMapping;
|
||||||
class VisitController {
|
class VisitController {
|
||||||
|
|
||||||
private final VisitRepository visits;
|
private final VisitRepository visits;
|
||||||
private final PetRepository pets;
|
|
||||||
|
|
||||||
|
private final PetRepository pets;
|
||||||
|
|
||||||
public VisitController(VisitRepository visits, PetRepository pets) {
|
public VisitController(VisitRepository visits, PetRepository pets) {
|
||||||
this.visits = visits;
|
this.visits = visits;
|
||||||
|
@ -55,12 +55,9 @@ class VisitController {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called before each and every @RequestMapping annotated method.
|
* Called before each and every @RequestMapping annotated method. 2 goals: - Make sure
|
||||||
* 2 goals:
|
* we always have fresh data - Since we do not use the session scope, make sure that
|
||||||
* - Make sure we always have fresh data
|
* Pet object always has an id (Even though id is not part of the form fields)
|
||||||
* - 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
|
* @param petId
|
||||||
* @return Pet
|
* @return Pet
|
||||||
*/
|
*/
|
||||||
|
@ -85,7 +82,8 @@ class VisitController {
|
||||||
public String processNewVisitForm(@Valid Visit visit, BindingResult result) {
|
public String processNewVisitForm(@Valid Visit visit, BindingResult result) {
|
||||||
if (result.hasErrors()) {
|
if (result.hasErrors()) {
|
||||||
return "pets/createOrUpdateVisitForm";
|
return "pets/createOrUpdateVisitForm";
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
this.visits.save(visit);
|
this.visits.save(visit);
|
||||||
return "redirect:/owners/{ownerId}";
|
return "redirect:/owners/{ownerId}";
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,8 +30,8 @@ class CrashController {
|
||||||
|
|
||||||
@GetMapping("/oups")
|
@GetMapping("/oups")
|
||||||
public String triggerException() {
|
public String triggerException() {
|
||||||
throw new RuntimeException("Expected: controller used to showcase what "
|
throw new RuntimeException(
|
||||||
+ "happens when an exception is thrown");
|
"Expected: controller used to showcase what " + "happens when an exception is thrown");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.samples.petclinic.system;
|
package org.springframework.samples.petclinic.system;
|
||||||
|
|
||||||
|
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
|
||||||
|
@ -27,4 +26,5 @@ class WelcomeController {
|
||||||
public String welcome() {
|
public String welcome() {
|
||||||
return "welcome";
|
return "welcome";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,8 @@ import org.springframework.samples.petclinic.model.Person;
|
||||||
public class Vet extends Person {
|
public class Vet extends Person {
|
||||||
|
|
||||||
@ManyToMany(fetch = FetchType.EAGER)
|
@ManyToMany(fetch = FetchType.EAGER)
|
||||||
@JoinTable(name = "vet_specialties", joinColumns = @JoinColumn(name = "vet_id"), inverseJoinColumns = @JoinColumn(name = "specialty_id"))
|
@JoinTable(name = "vet_specialties", joinColumns = @JoinColumn(name = "vet_id"),
|
||||||
|
inverseJoinColumns = @JoinColumn(name = "specialty_id"))
|
||||||
private Set<Specialty> specialties;
|
private Set<Specialty> specialties;
|
||||||
|
|
||||||
protected Set<Specialty> getSpecialtiesInternal() {
|
protected Set<Specialty> getSpecialtiesInternal() {
|
||||||
|
@ -63,8 +64,7 @@ public class Vet extends Person {
|
||||||
@XmlElement
|
@XmlElement
|
||||||
public List<Specialty> getSpecialties() {
|
public List<Specialty> getSpecialties() {
|
||||||
List<Specialty> sortedSpecs = new ArrayList<>(getSpecialtiesInternal());
|
List<Specialty> sortedSpecs = new ArrayList<>(getSpecialtiesInternal());
|
||||||
PropertyComparator.sort(sortedSpecs,
|
PropertyComparator.sort(sortedSpecs, new MutableSortDefinition("name", true, true));
|
||||||
new MutableSortDefinition("name", true, true));
|
|
||||||
return Collections.unmodifiableList(sortedSpecs);
|
return Collections.unmodifiableList(sortedSpecs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,9 +23,10 @@ import org.springframework.data.repository.Repository;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Repository class for <code>Vet</code> domain objects All method names are compliant with Spring Data naming
|
* Repository class for <code>Vet</code> domain objects All method names are compliant
|
||||||
* conventions so this interface can easily be extended for Spring Data.
|
* with Spring Data naming conventions so this interface can easily be extended for Spring
|
||||||
* See: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation
|
* Data. See:
|
||||||
|
* https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation
|
||||||
*
|
*
|
||||||
* @author Ken Krebs
|
* @author Ken Krebs
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
|
@ -36,12 +37,10 @@ public interface VetRepository extends Repository<Vet, Integer> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve all <code>Vet</code>s from the data store.
|
* Retrieve all <code>Vet</code>s from the data store.
|
||||||
*
|
|
||||||
* @return a <code>Collection</code> of <code>Vet</code>s
|
* @return a <code>Collection</code> of <code>Vet</code>s
|
||||||
*/
|
*/
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
@Cacheable("vets")
|
@Cacheable("vets")
|
||||||
Collection<Vet> findAll() throws DataAccessException;
|
Collection<Vet> findAll() throws DataAccessException;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,8 +22,8 @@ import javax.xml.bind.annotation.XmlElement;
|
||||||
import javax.xml.bind.annotation.XmlRootElement;
|
import javax.xml.bind.annotation.XmlRootElement;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple domain object representing a list of veterinarians. Mostly here to be used for the 'vets' {@link
|
* Simple domain object representing a list of veterinarians. Mostly here to be used for
|
||||||
* org.springframework.web.servlet.view.xml.MarshallingView}.
|
* the 'vets' {@link org.springframework.web.servlet.view.xml.MarshallingView}.
|
||||||
*
|
*
|
||||||
* @author Arjen Poutsma
|
* @author Arjen Poutsma
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -22,9 +22,10 @@ import org.springframework.data.repository.Repository;
|
||||||
import org.springframework.samples.petclinic.model.BaseEntity;
|
import org.springframework.samples.petclinic.model.BaseEntity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Repository class for <code>Visit</code> domain objects All method names are compliant with Spring Data naming
|
* Repository class for <code>Visit</code> domain objects All method names are compliant
|
||||||
* conventions so this interface can easily be extended for Spring Data.
|
* with Spring Data naming conventions so this interface can easily be extended for Spring
|
||||||
* See: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation
|
* Data. See:
|
||||||
|
* https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation
|
||||||
*
|
*
|
||||||
* @author Ken Krebs
|
* @author Ken Krebs
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
|
@ -35,7 +36,6 @@ public interface VisitRepository extends Repository<Visit, Integer> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save a <code>Visit</code> to the data store, either inserting or updating it.
|
* Save a <code>Visit</code> to the data store, either inserting or updating it.
|
||||||
*
|
|
||||||
* @param visit the <code>Visit</code> to save
|
* @param visit the <code>Visit</code> to save
|
||||||
* @see BaseEntity#isNew
|
* @see BaseEntity#isNew
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# database init, supports mysql too
|
# database init, supports mysql too
|
||||||
database=mysql
|
database=mysql
|
||||||
spring.datasource.url=${MYSQL_DB:jdbc:mysql://localhost/petclinic}
|
spring.datasource.url=${MYSQL_URL:jdbc:mysql://localhost/petclinic}
|
||||||
spring.datasource.username=${MYSQL_USER:petclinic@petclinicdb2}
|
spring.datasource.username=${MYSQL_USER:petclinic}
|
||||||
spring.datasource.password=${MYSQL_PASS:petclinic}
|
spring.datasource.password=${MYSQL_PASS:petclinic}
|
||||||
# Uncomment this the first time the app runs
|
# SQL is written to be idempotent so this is safe
|
||||||
spring.datasource.initialization-mode=always
|
spring.datasource.initialization-mode=always
|
|
@ -1,5 +1,5 @@
|
||||||
# database init, supports mysql too
|
# database init, supports mysql too
|
||||||
database=hsqldb
|
database=h2
|
||||||
spring.datasource.schema=classpath*:db/${database}/schema.sql
|
spring.datasource.schema=classpath*:db/${database}/schema.sql
|
||||||
spring.datasource.data=classpath*:db/${database}/data.sql
|
spring.datasource.data=classpath*:db/${database}/data.sql
|
||||||
|
|
||||||
|
@ -8,12 +8,12 @@ spring.thymeleaf.mode=HTML
|
||||||
|
|
||||||
# JPA
|
# JPA
|
||||||
spring.jpa.hibernate.ddl-auto=none
|
spring.jpa.hibernate.ddl-auto=none
|
||||||
|
spring.jpa.open-in-view=false
|
||||||
|
|
||||||
# Internationalization
|
# Internationalization
|
||||||
spring.messages.basename=messages/messages
|
spring.messages.basename=messages/messages
|
||||||
|
|
||||||
# Actuator / Management
|
# Actuator
|
||||||
management.endpoints.web.base-path=/manage
|
|
||||||
management.endpoints.web.exposure.include=*
|
management.endpoints.web.exposure.include=*
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
|
|
53
src/main/resources/db/h2/data.sql
Normal file
53
src/main/resources/db/h2/data.sql
Normal file
|
@ -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');
|
64
src/main/resources/db/h2/schema.sql
Normal file
64
src/main/resources/db/h2/schema.sql
Normal file
|
@ -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);
|
|
@ -18,8 +18,10 @@
|
||||||
mysql_1_eedb4818d817 | MySQL init process done. Ready for start up.
|
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"
|
2) (Once only) create the PetClinic database and user by executing the "db/mysql/user.sql"
|
||||||
scripts (or set "spring.datasource.initialization-mode=always" the first time you run the app).
|
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
|
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).
|
line, but any way that sets that property in a Spring Boot app should work).
|
||||||
|
@ -33,5 +35,6 @@
|
||||||
To set profiles & properties.
|
To set profiles & properties.
|
||||||
|
|
||||||
N.B. the "petclinic" database has to exist for the app to work with the JDBC URL value
|
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
|
as it is configured by default. This condition is taken care of automatically by the
|
||||||
configuration provided, or by the `schema.sql` if you can run that as root.
|
docker-compose configuration provided, or by the `user.sql` script if you run that as
|
||||||
|
root.
|
||||||
|
|
|
@ -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 (
|
CREATE TABLE IF NOT EXISTS vets (
|
||||||
id INT(4) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
id INT(4) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
first_name VARCHAR(30),
|
first_name VARCHAR(30),
|
||||||
|
|
7
src/main/resources/db/mysql/user.sql
Normal file
7
src/main/resources/db/mysql/user.sql
Normal file
|
@ -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';
|
8
src/main/resources/messages/messages_es.properties
Normal file
8
src/main/resources/messages/messages_es.properties
Normal file
|
@ -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
|
|
@ -67,6 +67,7 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="container xd-container">
|
<div class="container xd-container">
|
||||||
|
@ -78,8 +79,8 @@
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 text-center">
|
<div class="col-12 text-center">
|
||||||
<img src="../static/resources/images/spring-pivotal-logo.png" th:src="@{/resources/images/spring-pivotal-logo.png}"
|
<img src="../static/resources/images/spring-pivotal-logo.png"
|
||||||
alt="Sponsored by Pivotal"/></div>
|
th:src="@{/resources/images/spring-pivotal-logo.png}" alt="Sponsored by Pivotal" /></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
th:text="${#temporals.format(pet.birthDate, dateFormat)}" /></td>
|
th:text="${#temporals.format(pet.birthDate, dateFormat)}" /></td>
|
||||||
<td th:text="${pet.type}" /></td>
|
<td th:text="${pet.type}" /></td>
|
||||||
<td
|
<td
|
||||||
th:text="${pet.owner?.firstName + ' ' + pet.owner?.lastName}" /></td>
|
th:text="${pet.owner?.firstName + ' ' + pet.owner?.lastName}"></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|
|
@ -32,4 +32,5 @@ class PetclinicIntegrationTests {
|
||||||
vets.findAll();
|
vets.findAll();
|
||||||
vets.findAll(); // served from cache
|
vets.findAll(); // served from cache
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,8 +49,7 @@ class ValidatorTests {
|
||||||
person.setLastName("smith");
|
person.setLastName("smith");
|
||||||
|
|
||||||
Validator validator = createValidator();
|
Validator validator = createValidator();
|
||||||
Set<ConstraintViolation<Person>> constraintViolations = validator
|
Set<ConstraintViolation<Person>> constraintViolations = validator.validate(person);
|
||||||
.validate(person);
|
|
||||||
|
|
||||||
assertThat(constraintViolations).hasSize(1);
|
assertThat(constraintViolations).hasSize(1);
|
||||||
ConstraintViolation<Person> violation = constraintViolations.iterator().next();
|
ConstraintViolation<Person> violation = constraintViolations.iterator().next();
|
||||||
|
|
|
@ -89,33 +89,22 @@ class OwnerControllerTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testInitCreationForm() throws Exception {
|
void testInitCreationForm() throws Exception {
|
||||||
mockMvc.perform(get("/owners/new"))
|
mockMvc.perform(get("/owners/new")).andExpect(status().isOk()).andExpect(model().attributeExists("owner"))
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(model().attributeExists("owner"))
|
|
||||||
.andExpect(view().name("owners/createOrUpdateOwnerForm"));
|
.andExpect(view().name("owners/createOrUpdateOwnerForm"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testProcessCreationFormSuccess() throws Exception {
|
void testProcessCreationFormSuccess() throws Exception {
|
||||||
mockMvc.perform(post("/owners/new")
|
mockMvc.perform(post("/owners/new").param("firstName", "Joe").param("lastName", "Bloggs")
|
||||||
.param("firstName", "Joe")
|
.param("address", "123 Caramel Street").param("city", "London").param("telephone", "01316761638"))
|
||||||
.param("lastName", "Bloggs")
|
|
||||||
.param("address", "123 Caramel Street")
|
|
||||||
.param("city", "London")
|
|
||||||
.param("telephone", "01316761638")
|
|
||||||
)
|
|
||||||
.andExpect(status().is3xxRedirection());
|
.andExpect(status().is3xxRedirection());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testProcessCreationFormHasErrors() throws Exception {
|
void testProcessCreationFormHasErrors() throws Exception {
|
||||||
mockMvc.perform(post("/owners/new")
|
mockMvc.perform(
|
||||||
.param("firstName", "Joe")
|
post("/owners/new").param("firstName", "Joe").param("lastName", "Bloggs").param("city", "London"))
|
||||||
.param("lastName", "Bloggs")
|
.andExpect(status().isOk()).andExpect(model().attributeHasErrors("owner"))
|
||||||
.param("city", "London")
|
|
||||||
)
|
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(model().attributeHasErrors("owner"))
|
|
||||||
.andExpect(model().attributeHasFieldErrors("owner", "address"))
|
.andExpect(model().attributeHasFieldErrors("owner", "address"))
|
||||||
.andExpect(model().attributeHasFieldErrors("owner", "telephone"))
|
.andExpect(model().attributeHasFieldErrors("owner", "telephone"))
|
||||||
.andExpect(view().name("owners/createOrUpdateOwnerForm"));
|
.andExpect(view().name("owners/createOrUpdateOwnerForm"));
|
||||||
|
@ -123,36 +112,26 @@ class OwnerControllerTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testInitFindForm() throws Exception {
|
void testInitFindForm() throws Exception {
|
||||||
mockMvc.perform(get("/owners/find"))
|
mockMvc.perform(get("/owners/find")).andExpect(status().isOk()).andExpect(model().attributeExists("owner"))
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(model().attributeExists("owner"))
|
|
||||||
.andExpect(view().name("owners/findOwners"));
|
.andExpect(view().name("owners/findOwners"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testProcessFindFormSuccess() throws Exception {
|
void testProcessFindFormSuccess() throws Exception {
|
||||||
given(this.owners.findByLastName("")).willReturn(Lists.newArrayList(george, new Owner()));
|
given(this.owners.findByLastName("")).willReturn(Lists.newArrayList(george, new Owner()));
|
||||||
mockMvc.perform(get("/owners"))
|
mockMvc.perform(get("/owners")).andExpect(status().isOk()).andExpect(view().name("owners/ownersList"));
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(view().name("owners/ownersList"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testProcessFindFormByLastName() throws Exception {
|
void testProcessFindFormByLastName() throws Exception {
|
||||||
given(this.owners.findByLastName(george.getLastName())).willReturn(Lists.newArrayList(george));
|
given(this.owners.findByLastName(george.getLastName())).willReturn(Lists.newArrayList(george));
|
||||||
mockMvc.perform(get("/owners")
|
mockMvc.perform(get("/owners").param("lastName", "Franklin")).andExpect(status().is3xxRedirection())
|
||||||
.param("lastName", "Franklin")
|
|
||||||
)
|
|
||||||
.andExpect(status().is3xxRedirection())
|
|
||||||
.andExpect(view().name("redirect:/owners/" + TEST_OWNER_ID));
|
.andExpect(view().name("redirect:/owners/" + TEST_OWNER_ID));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testProcessFindFormNoOwnersFound() throws Exception {
|
void testProcessFindFormNoOwnersFound() throws Exception {
|
||||||
mockMvc.perform(get("/owners")
|
mockMvc.perform(get("/owners").param("lastName", "Unknown Surname")).andExpect(status().isOk())
|
||||||
.param("lastName", "Unknown Surname")
|
|
||||||
)
|
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(model().attributeHasFieldErrors("owner", "lastName"))
|
.andExpect(model().attributeHasFieldErrors("owner", "lastName"))
|
||||||
.andExpect(model().attributeHasFieldErrorCode("owner", "lastName", "notFound"))
|
.andExpect(model().attributeHasFieldErrorCode("owner", "lastName", "notFound"))
|
||||||
.andExpect(view().name("owners/findOwners"));
|
.andExpect(view().name("owners/findOwners"));
|
||||||
|
@ -160,8 +139,7 @@ class OwnerControllerTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testInitUpdateOwnerForm() throws Exception {
|
void testInitUpdateOwnerForm() throws Exception {
|
||||||
mockMvc.perform(get("/owners/{ownerId}/edit", TEST_OWNER_ID))
|
mockMvc.perform(get("/owners/{ownerId}/edit", TEST_OWNER_ID)).andExpect(status().isOk())
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(model().attributeExists("owner"))
|
.andExpect(model().attributeExists("owner"))
|
||||||
.andExpect(model().attribute("owner", hasProperty("lastName", is("Franklin"))))
|
.andExpect(model().attribute("owner", hasProperty("lastName", is("Franklin"))))
|
||||||
.andExpect(model().attribute("owner", hasProperty("firstName", is("George"))))
|
.andExpect(model().attribute("owner", hasProperty("firstName", is("George"))))
|
||||||
|
@ -173,25 +151,16 @@ class OwnerControllerTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testProcessUpdateOwnerFormSuccess() throws Exception {
|
void testProcessUpdateOwnerFormSuccess() throws Exception {
|
||||||
mockMvc.perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID)
|
mockMvc.perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID).param("firstName", "Joe")
|
||||||
.param("firstName", "Joe")
|
.param("lastName", "Bloggs").param("address", "123 Caramel Street").param("city", "London")
|
||||||
.param("lastName", "Bloggs")
|
.param("telephone", "01616291589")).andExpect(status().is3xxRedirection())
|
||||||
.param("address", "123 Caramel Street")
|
|
||||||
.param("city", "London")
|
|
||||||
.param("telephone", "01616291589")
|
|
||||||
)
|
|
||||||
.andExpect(status().is3xxRedirection())
|
|
||||||
.andExpect(view().name("redirect:/owners/{ownerId}"));
|
.andExpect(view().name("redirect:/owners/{ownerId}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testProcessUpdateOwnerFormHasErrors() throws Exception {
|
void testProcessUpdateOwnerFormHasErrors() throws Exception {
|
||||||
mockMvc.perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID)
|
mockMvc.perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID).param("firstName", "Joe")
|
||||||
.param("firstName", "Joe")
|
.param("lastName", "Bloggs").param("city", "London")).andExpect(status().isOk())
|
||||||
.param("lastName", "Bloggs")
|
|
||||||
.param("city", "London")
|
|
||||||
)
|
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(model().attributeHasErrors("owner"))
|
.andExpect(model().attributeHasErrors("owner"))
|
||||||
.andExpect(model().attributeHasFieldErrors("owner", "address"))
|
.andExpect(model().attributeHasFieldErrors("owner", "address"))
|
||||||
.andExpect(model().attributeHasFieldErrors("owner", "telephone"))
|
.andExpect(model().attributeHasFieldErrors("owner", "telephone"))
|
||||||
|
@ -200,8 +169,7 @@ class OwnerControllerTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testShowOwner() throws Exception {
|
void testShowOwner() throws Exception {
|
||||||
mockMvc.perform(get("/owners/{ownerId}", TEST_OWNER_ID))
|
mockMvc.perform(get("/owners/{ownerId}", TEST_OWNER_ID)).andExpect(status().isOk())
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(model().attribute("owner", hasProperty("lastName", is("Franklin"))))
|
.andExpect(model().attribute("owner", hasProperty("lastName", is("Franklin"))))
|
||||||
.andExpect(model().attribute("owner", hasProperty("firstName", is("George"))))
|
.andExpect(model().attribute("owner", hasProperty("firstName", is("George"))))
|
||||||
.andExpect(model().attribute("owner", hasProperty("address", is("110 W. Liberty St."))))
|
.andExpect(model().attribute("owner", hasProperty("address", is("110 W. Liberty St."))))
|
||||||
|
@ -224,8 +192,8 @@ class OwnerControllerTests {
|
||||||
@Override
|
@Override
|
||||||
public void describeTo(Description description) {
|
public void describeTo(Description description) {
|
||||||
description.appendText("Max did not have any visits");
|
description.appendText("Max did not have any visits");
|
||||||
}})))
|
}
|
||||||
.andExpect(view().name("owners/ownerDetails"));
|
}))).andExpect(view().name("owners/ownerDetails"));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,14 +39,12 @@ import org.springframework.test.web.servlet.MockMvc;
|
||||||
* @author Colin But
|
* @author Colin But
|
||||||
*/
|
*/
|
||||||
@WebMvcTest(value = PetController.class,
|
@WebMvcTest(value = PetController.class,
|
||||||
includeFilters = @ComponentScan.Filter(
|
includeFilters = @ComponentScan.Filter(value = PetTypeFormatter.class, type = FilterType.ASSIGNABLE_TYPE))
|
||||||
value = PetTypeFormatter.class,
|
|
||||||
type = FilterType.ASSIGNABLE_TYPE))
|
|
||||||
class PetControllerTests {
|
class PetControllerTests {
|
||||||
|
|
||||||
private static final int TEST_OWNER_ID = 1;
|
private static final int TEST_OWNER_ID = 1;
|
||||||
private static final int TEST_PET_ID = 1;
|
|
||||||
|
|
||||||
|
private static final int TEST_PET_ID = 1;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private MockMvc mockMvc;
|
private MockMvc mockMvc;
|
||||||
|
@ -70,65 +68,45 @@ class PetControllerTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testInitCreationForm() throws Exception {
|
void testInitCreationForm() throws Exception {
|
||||||
mockMvc.perform(get("/owners/{ownerId}/pets/new", TEST_OWNER_ID))
|
mockMvc.perform(get("/owners/{ownerId}/pets/new", TEST_OWNER_ID)).andExpect(status().isOk())
|
||||||
.andExpect(status().isOk())
|
.andExpect(view().name("pets/createOrUpdatePetForm")).andExpect(model().attributeExists("pet"));
|
||||||
.andExpect(view().name("pets/createOrUpdatePetForm"))
|
|
||||||
.andExpect(model().attributeExists("pet"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testProcessCreationFormSuccess() throws Exception {
|
void testProcessCreationFormSuccess() throws Exception {
|
||||||
mockMvc.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID)
|
mockMvc.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID).param("name", "Betty")
|
||||||
.param("name", "Betty")
|
.param("type", "hamster").param("birthDate", "2015-02-12")).andExpect(status().is3xxRedirection())
|
||||||
.param("type", "hamster")
|
|
||||||
.param("birthDate", "2015-02-12")
|
|
||||||
)
|
|
||||||
.andExpect(status().is3xxRedirection())
|
|
||||||
.andExpect(view().name("redirect:/owners/{ownerId}"));
|
.andExpect(view().name("redirect:/owners/{ownerId}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testProcessCreationFormHasErrors() throws Exception {
|
void testProcessCreationFormHasErrors() throws Exception {
|
||||||
mockMvc.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID)
|
mockMvc.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID).param("name", "Betty").param("birthDate",
|
||||||
.param("name", "Betty")
|
"2015-02-12")).andExpect(model().attributeHasNoErrors("owner"))
|
||||||
.param("birthDate", "2015-02-12")
|
.andExpect(model().attributeHasErrors("pet")).andExpect(model().attributeHasFieldErrors("pet", "type"))
|
||||||
)
|
.andExpect(model().attributeHasFieldErrorCode("pet", "type", "required")).andExpect(status().isOk())
|
||||||
.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"));
|
.andExpect(view().name("pets/createOrUpdatePetForm"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testInitUpdateForm() throws Exception {
|
void testInitUpdateForm() throws Exception {
|
||||||
mockMvc.perform(get("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID))
|
mockMvc.perform(get("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk()).andExpect(model().attributeExists("pet"))
|
||||||
.andExpect(model().attributeExists("pet"))
|
|
||||||
.andExpect(view().name("pets/createOrUpdatePetForm"));
|
.andExpect(view().name("pets/createOrUpdatePetForm"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testProcessUpdateFormSuccess() throws Exception {
|
void testProcessUpdateFormSuccess() throws Exception {
|
||||||
mockMvc.perform(post("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID)
|
mockMvc.perform(post("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID).param("name", "Betty")
|
||||||
.param("name", "Betty")
|
.param("type", "hamster").param("birthDate", "2015-02-12")).andExpect(status().is3xxRedirection())
|
||||||
.param("type", "hamster")
|
|
||||||
.param("birthDate", "2015-02-12")
|
|
||||||
)
|
|
||||||
.andExpect(status().is3xxRedirection())
|
|
||||||
.andExpect(view().name("redirect:/owners/{ownerId}"));
|
.andExpect(view().name("redirect:/owners/{ownerId}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testProcessUpdateFormHasErrors() throws Exception {
|
void testProcessUpdateFormHasErrors() throws Exception {
|
||||||
mockMvc.perform(post("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID)
|
mockMvc.perform(post("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID).param("name", "Betty")
|
||||||
.param("name", "Betty")
|
.param("birthDate", "2015/02/12")).andExpect(model().attributeHasNoErrors("owner"))
|
||||||
.param("birthDate", "2015/02/12")
|
.andExpect(model().attributeHasErrors("pet")).andExpect(status().isOk())
|
||||||
)
|
|
||||||
.andExpect(model().attributeHasNoErrors("owner"))
|
|
||||||
.andExpect(model().attributeHasErrors("pet"))
|
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(view().name("pets/createOrUpdatePetForm"));
|
.andExpect(view().name("pets/createOrUpdatePetForm"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,6 @@ class PetTypeFormatterTests {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method to produce some sample pet types just for test purpose
|
* Helper method to produce some sample pet types just for test purpose
|
||||||
*
|
|
||||||
* @return {@link Collection} of {@link PetType}
|
* @return {@link Collection} of {@link PetType}
|
||||||
*/
|
*/
|
||||||
private List<PetType> makePetTypes() {
|
private List<PetType> makePetTypes() {
|
||||||
|
|
|
@ -57,28 +57,21 @@ class VisitControllerTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testInitNewVisitForm() throws Exception {
|
void testInitNewVisitForm() throws Exception {
|
||||||
mockMvc.perform(get("/owners/*/pets/{petId}/visits/new", TEST_PET_ID))
|
mockMvc.perform(get("/owners/*/pets/{petId}/visits/new", TEST_PET_ID)).andExpect(status().isOk())
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(view().name("pets/createOrUpdateVisitForm"));
|
.andExpect(view().name("pets/createOrUpdateVisitForm"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testProcessNewVisitFormSuccess() throws Exception {
|
void testProcessNewVisitFormSuccess() throws Exception {
|
||||||
mockMvc.perform(post("/owners/*/pets/{petId}/visits/new", TEST_PET_ID)
|
mockMvc.perform(post("/owners/*/pets/{petId}/visits/new", TEST_PET_ID).param("name", "George")
|
||||||
.param("name", "George")
|
.param("description", "Visit Description")).andExpect(status().is3xxRedirection())
|
||||||
.param("description", "Visit Description")
|
|
||||||
)
|
|
||||||
.andExpect(status().is3xxRedirection())
|
|
||||||
.andExpect(view().name("redirect:/owners/{ownerId}"));
|
.andExpect(view().name("redirect:/owners/{ownerId}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testProcessNewVisitFormHasErrors() throws Exception {
|
void testProcessNewVisitFormHasErrors() throws Exception {
|
||||||
mockMvc.perform(post("/owners/*/pets/{petId}/visits/new", TEST_PET_ID)
|
mockMvc.perform(post("/owners/*/pets/{petId}/visits/new", TEST_PET_ID).param("name", "George"))
|
||||||
.param("name", "George")
|
.andExpect(model().attributeHasErrors("visit")).andExpect(status().isOk())
|
||||||
)
|
|
||||||
.andExpect(model().attributeHasErrors("visit"))
|
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(view().name("pets/createOrUpdateVisitForm"));
|
.andExpect(view().name("pets/createOrUpdateVisitForm"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,15 +40,24 @@ import org.springframework.transaction.annotation.Transactional;
|
||||||
/**
|
/**
|
||||||
* Integration test of the Service and the Repository layer.
|
* Integration test of the Service and the Repository layer.
|
||||||
* <p>
|
* <p>
|
||||||
* ClinicServiceSpringDataJpaTests subclasses benefit from the following services provided by the Spring
|
* ClinicServiceSpringDataJpaTests subclasses benefit from the following services provided
|
||||||
* TestContext Framework: </p> <ul> <li><strong>Spring IoC container caching</strong> which spares us unnecessary set up
|
* by the Spring TestContext Framework:
|
||||||
* time between test execution.</li> <li><strong>Dependency Injection</strong> of test fixture instances, meaning that
|
* </p>
|
||||||
* we don't need to perform application context lookups. See the use of {@link Autowired @Autowired} on the <code>{@link
|
* <ul>
|
||||||
* ClinicServiceTests#clinicService clinicService}</code> instance variable, which uses autowiring <em>by
|
* <li><strong>Spring IoC container caching</strong> which spares us unnecessary set up
|
||||||
* type</em>. <li><strong>Transaction management</strong>, meaning each test method is executed in its own transaction,
|
* time between test execution.</li>
|
||||||
* which is automatically rolled back by default. Thus, even if tests insert or otherwise change database state, there
|
* <li><strong>Dependency Injection</strong> of test fixture instances, meaning that we
|
||||||
* is no need for a teardown or cleanup script. <li> An {@link org.springframework.context.ApplicationContext
|
* don't need to perform application context lookups. See the use of
|
||||||
* ApplicationContext} is also inherited and can be used for explicit bean lookup if necessary. </li> </ul>
|
* {@link Autowired @Autowired} on the <code>{@link
|
||||||
|
* ClinicServiceTests#clinicService clinicService}</code> instance variable, which uses
|
||||||
|
* autowiring <em>by type</em>.
|
||||||
|
* <li><strong>Transaction management</strong>, 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.
|
||||||
|
* <li>An {@link org.springframework.context.ApplicationContext ApplicationContext} is
|
||||||
|
* also inherited and can be used for explicit bean lookup if necessary.</li>
|
||||||
|
* </ul>
|
||||||
*
|
*
|
||||||
* @author Ken Krebs
|
* @author Ken Krebs
|
||||||
* @author Rod Johnson
|
* @author Rod Johnson
|
||||||
|
|
|
@ -22,8 +22,8 @@ import org.springframework.orm.ObjectRetrievalFailureException;
|
||||||
import org.springframework.samples.petclinic.model.BaseEntity;
|
import org.springframework.samples.petclinic.model.BaseEntity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility methods for handling entities. Separate from the BaseEntity class mainly because of dependency on the
|
* Utility methods for handling entities. Separate from the BaseEntity class mainly
|
||||||
* ORM-associated ObjectRetrievalFailureException.
|
* because of dependency on the ORM-associated ObjectRetrievalFailureException.
|
||||||
*
|
*
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
* @author Sam Brannen
|
* @author Sam Brannen
|
||||||
|
@ -34,7 +34,6 @@ public abstract class EntityUtils {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Look up the entity of the given class with the given id in the given collection.
|
* Look up the entity of the given class with the given id in the given collection.
|
||||||
*
|
|
||||||
* @param entities the collection to search
|
* @param entities the collection to search
|
||||||
* @param entityClass the entity class to look up
|
* @param entityClass the entity class to look up
|
||||||
* @param entityId the entity id to look up
|
* @param entityId the entity id to look up
|
||||||
|
|
|
@ -44,7 +44,8 @@ class CrashControllerTests {
|
||||||
@Test
|
@Test
|
||||||
void testTriggerException() throws Exception {
|
void testTriggerException() throws Exception {
|
||||||
mockMvc.perform(get("/oups")).andExpect(view().name("exception"))
|
mockMvc.perform(get("/oups")).andExpect(view().name("exception"))
|
||||||
.andExpect(model().attributeExists("exception"))
|
.andExpect(model().attributeExists("exception")).andExpect(forwardedUrl("exception"))
|
||||||
.andExpect(forwardedUrl("exception")).andExpect(status().isOk());
|
.andExpect(status().isOk());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,16 +65,14 @@ class VetControllerTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testShowVetListHtml() throws Exception {
|
void testShowVetListHtml() throws Exception {
|
||||||
mockMvc.perform(get("/vets.html"))
|
mockMvc.perform(get("/vets.html")).andExpect(status().isOk()).andExpect(model().attributeExists("vets"))
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(model().attributeExists("vets"))
|
|
||||||
.andExpect(view().name("vets/vetList"));
|
.andExpect(view().name("vets/vetList"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testShowResourcesVetList() throws Exception {
|
void testShowResourcesVetList() throws Exception {
|
||||||
ResultActions actions = mockMvc.perform(get("/vets")
|
ResultActions actions = mockMvc.perform(get("/vets").accept(MediaType.APPLICATION_JSON))
|
||||||
.accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk());
|
.andExpect(status().isOk());
|
||||||
actions.andExpect(content().contentType(MediaType.APPLICATION_JSON))
|
actions.andExpect(content().contentType(MediaType.APPLICATION_JSON))
|
||||||
.andExpect(jsonPath("$.vetList[0].id").value(1));
|
.andExpect(jsonPath("$.vetList[0].id").value(1));
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,8 +31,7 @@ class VetTests {
|
||||||
vet.setFirstName("Zaphod");
|
vet.setFirstName("Zaphod");
|
||||||
vet.setLastName("Beeblebrox");
|
vet.setLastName("Beeblebrox");
|
||||||
vet.setId(123);
|
vet.setId(123);
|
||||||
Vet other = (Vet) SerializationUtils
|
Vet other = (Vet) SerializationUtils.deserialize(SerializationUtils.serialize(vet));
|
||||||
.deserialize(SerializationUtils.serialize(vet));
|
|
||||||
assertThat(other.getFirstName()).isEqualTo(vet.getFirstName());
|
assertThat(other.getFirstName()).isEqualTo(vet.getFirstName());
|
||||||
assertThat(other.getLastName()).isEqualTo(vet.getLastName());
|
assertThat(other.getLastName()).isEqualTo(vet.getLastName());
|
||||||
assertThat(other.getId()).isEqualTo(vet.getId());
|
assertThat(other.getId()).isEqualTo(vet.getId());
|
||||||
|
|
Loading…
Reference in a new issue