mirror of
https://github.com/spring-projects/spring-petclinic.git
synced 2025-07-20 23:05:49 +00:00
Merge branch 'main' of ssh://github.com/spring-projects/spring-petclinic into feature/upgrade_to_latest_petclinic
This commit is contained in:
commit
e430133d52
77 changed files with 2710 additions and 2041 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
|
||||||
|
|
8
.gitignore
vendored
8
.gitignore
vendored
|
@ -2,9 +2,17 @@ target/*
|
||||||
.settings/*
|
.settings/*
|
||||||
.classpath
|
.classpath
|
||||||
.project
|
.project
|
||||||
|
.factorypath
|
||||||
|
.attach_pid*
|
||||||
.idea
|
.idea
|
||||||
*.iml
|
*.iml
|
||||||
/target
|
/target
|
||||||
|
.sts4-cache/
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
_site/
|
_site/
|
||||||
|
|
||||||
# Created by https://www.gitignore.io/api/ansible
|
# Created by https://www.gitignore.io/api/ansible
|
||||||
|
|
117
.mvn/wrapper/MavenWrapperDownloader.java
vendored
Normal file
117
.mvn/wrapper/MavenWrapperDownloader.java
vendored
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2007-present the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0'
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
import java.net.*;
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.channels.*;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
public class MavenWrapperDownloader {
|
||||||
|
|
||||||
|
private static final String WRAPPER_VERSION = "0.5.6";
|
||||||
|
/**
|
||||||
|
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
|
||||||
|
*/
|
||||||
|
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
|
||||||
|
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
|
||||||
|
* use instead of the default one.
|
||||||
|
*/
|
||||||
|
private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
|
||||||
|
".mvn/wrapper/maven-wrapper.properties";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Path where the maven-wrapper.jar will be saved to.
|
||||||
|
*/
|
||||||
|
private static final String MAVEN_WRAPPER_JAR_PATH =
|
||||||
|
".mvn/wrapper/maven-wrapper.jar";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the property which should be used to override the default download url for the wrapper.
|
||||||
|
*/
|
||||||
|
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
|
||||||
|
|
||||||
|
public static void main(String args[]) {
|
||||||
|
System.out.println("- Downloader started");
|
||||||
|
File baseDirectory = new File(args[0]);
|
||||||
|
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
|
||||||
|
|
||||||
|
// If the maven-wrapper.properties exists, read it and check if it contains a custom
|
||||||
|
// wrapperUrl parameter.
|
||||||
|
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
|
||||||
|
String url = DEFAULT_DOWNLOAD_URL;
|
||||||
|
if(mavenWrapperPropertyFile.exists()) {
|
||||||
|
FileInputStream mavenWrapperPropertyFileInputStream = null;
|
||||||
|
try {
|
||||||
|
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
|
||||||
|
Properties mavenWrapperProperties = new Properties();
|
||||||
|
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
|
||||||
|
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if(mavenWrapperPropertyFileInputStream != null) {
|
||||||
|
mavenWrapperPropertyFileInputStream.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
// Ignore ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("- Downloading from: " + url);
|
||||||
|
|
||||||
|
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
|
||||||
|
if(!outputFile.getParentFile().exists()) {
|
||||||
|
if(!outputFile.getParentFile().mkdirs()) {
|
||||||
|
System.out.println(
|
||||||
|
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
|
||||||
|
try {
|
||||||
|
downloadFileFromURL(url, outputFile);
|
||||||
|
System.out.println("Done");
|
||||||
|
System.exit(0);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
System.out.println("- Error downloading");
|
||||||
|
e.printStackTrace();
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
|
||||||
|
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
|
||||||
|
String username = System.getenv("MVNW_USERNAME");
|
||||||
|
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
|
||||||
|
Authenticator.setDefault(new Authenticator() {
|
||||||
|
@Override
|
||||||
|
protected PasswordAuthentication getPasswordAuthentication() {
|
||||||
|
return new PasswordAuthentication(username, password);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
URL website = new URL(urlString);
|
||||||
|
ReadableByteChannel rbc;
|
||||||
|
rbc = Channels.newChannel(website.openStream());
|
||||||
|
FileOutputStream fos = new FileOutputStream(destination);
|
||||||
|
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
|
||||||
|
fos.close();
|
||||||
|
rbc.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
BIN
.mvn/wrapper/maven-wrapper.jar
vendored
BIN
.mvn/wrapper/maven-wrapper.jar
vendored
Binary file not shown.
4
.mvn/wrapper/maven-wrapper.properties
vendored
4
.mvn/wrapper/maven-wrapper.properties
vendored
|
@ -1 +1,3 @@
|
||||||
distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.3/apache-maven-3.3.3-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.6/maven-wrapper-0.5.6.jar
|
||||||
|
|
||||||
|
|
20
.springBeans
20
.springBeans
|
@ -1,20 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<beansProjectDescription>
|
|
||||||
<version>1</version>
|
|
||||||
<pluginVersion><![CDATA[3.5.0.201404011509-RELEASE]]></pluginVersion>
|
|
||||||
<configSuffixes>
|
|
||||||
<configSuffix><![CDATA[xml]]></configSuffix>
|
|
||||||
</configSuffixes>
|
|
||||||
<enableImports><![CDATA[false]]></enableImports>
|
|
||||||
<configs>
|
|
||||||
<config>src/main/resources/spring/datasource-config.xml</config>
|
|
||||||
<config>src/main/resources/spring/mvc-core-config.xml</config>
|
|
||||||
<config>src/main/resources/spring/mvc-view-config.xml</config>
|
|
||||||
<config>src/main/resources/spring/business-config.xml</config>
|
|
||||||
</configs>
|
|
||||||
<autoconfigs>
|
|
||||||
<config>src/main/resources/spring/tools-config.xml</config>
|
|
||||||
</autoconfigs>
|
|
||||||
<configSets>
|
|
||||||
</configSets>
|
|
||||||
</beansProjectDescription>
|
|
|
@ -1,2 +1,3 @@
|
||||||
|
dist: trusty
|
||||||
language: java
|
language: java
|
||||||
jdk: oraclejdk8
|
jdk: oraclejdk8
|
||||||
|
|
26
.vscode/launch.json
vendored
Normal file
26
.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
// 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
Normal file
3
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"java.configuration.updateBuildConfiguration": "interactive"
|
||||||
|
}
|
19
.vscode/tasks.json
vendored
Normal file
19
.vscode/tasks.json
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
// 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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -1,9 +1,12 @@
|
||||||
mysql:
|
mysql:
|
||||||
image: mysql
|
image: mysql:5.7
|
||||||
ports:
|
ports:
|
||||||
- "3306:3306"
|
- "3306:3306"
|
||||||
environment:
|
environment:
|
||||||
- MYSQL_ROOT_PASSWORD=root
|
- MYSQL_ROOT_PASSWORD=
|
||||||
- MYSQL_DATABASE=test
|
- MYSQL_ALLOW_EMPTY_PASSWORD=true
|
||||||
|
- MYSQL_USER=petclinic
|
||||||
|
- MYSQL_PASSWORD=petclinic
|
||||||
|
- MYSQL_DATABASE=petclinic
|
||||||
volumes:
|
volumes:
|
||||||
- "./conf.d:/etc/mysql/conf.d:ro"
|
- "./conf.d:/etc/mysql/conf.d:ro"
|
180
mvnw
vendored
180
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:
|
||||||
# ------------------
|
# ------------------
|
||||||
|
@ -54,38 +54,16 @@ case "`uname`" in
|
||||||
CYGWIN*) cygwin=true ;;
|
CYGWIN*) cygwin=true ;;
|
||||||
MINGW*) mingw=true;;
|
MINGW*) mingw=true;;
|
||||||
Darwin*) darwin=true
|
Darwin*) darwin=true
|
||||||
#
|
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
|
||||||
# Look for the Apple JDKs first to preserve the existing behaviour, and then look
|
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
|
||||||
# for the new JDKs provided by Oracle.
|
if [ -z "$JAVA_HOME" ]; then
|
||||||
#
|
if [ -x "/usr/libexec/java_home" ]; then
|
||||||
if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then
|
export JAVA_HOME="`/usr/libexec/java_home`"
|
||||||
#
|
else
|
||||||
# Apple JDKs
|
export JAVA_HOME="/Library/Java/Home"
|
||||||
#
|
fi
|
||||||
export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home
|
fi
|
||||||
fi
|
;;
|
||||||
|
|
||||||
if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then
|
|
||||||
#
|
|
||||||
# Apple JDKs
|
|
||||||
#
|
|
||||||
export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then
|
|
||||||
#
|
|
||||||
# Oracle JDKs
|
|
||||||
#
|
|
||||||
export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then
|
|
||||||
#
|
|
||||||
# Apple JDKs
|
|
||||||
#
|
|
||||||
export JAVA_HOME=`/usr/libexec/java_home`
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
if [ -z "$JAVA_HOME" ] ; then
|
if [ -z "$JAVA_HOME" ] ; then
|
||||||
|
@ -130,13 +108,12 @@ if $cygwin ; then
|
||||||
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
|
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# For Migwn, ensure paths are in UNIX format before anything is touched
|
# For Mingw, ensure paths are in UNIX format before anything is touched
|
||||||
if $mingw ; then
|
if $mingw ; then
|
||||||
[ -n "$M2_HOME" ] &&
|
[ -n "$M2_HOME" ] &&
|
||||||
M2_HOME="`(cd "$M2_HOME"; pwd)`"
|
M2_HOME="`(cd "$M2_HOME"; pwd)`"
|
||||||
[ -n "$JAVA_HOME" ] &&
|
[ -n "$JAVA_HOME" ] &&
|
||||||
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
|
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
|
||||||
# TODO classpath?
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$JAVA_HOME" ]; then
|
if [ -z "$JAVA_HOME" ]; then
|
||||||
|
@ -184,27 +161,28 @@ fi
|
||||||
|
|
||||||
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
|
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
|
||||||
|
|
||||||
# For Cygwin, switch paths to Windows format before running java
|
|
||||||
if $cygwin; then
|
|
||||||
[ -n "$M2_HOME" ] &&
|
|
||||||
M2_HOME=`cygpath --path --windows "$M2_HOME"`
|
|
||||||
[ -n "$JAVA_HOME" ] &&
|
|
||||||
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
|
|
||||||
[ -n "$CLASSPATH" ] &&
|
|
||||||
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
|
|
||||||
fi
|
|
||||||
|
|
||||||
# traverses directory structure from process work directory to filesystem root
|
# traverses directory structure from process work directory to filesystem root
|
||||||
# first directory with .mvn subdirectory is considered project base directory
|
# first directory with .mvn subdirectory is considered project base directory
|
||||||
find_maven_basedir() {
|
find_maven_basedir() {
|
||||||
local basedir=$(pwd)
|
|
||||||
local wdir=$(pwd)
|
if [ -z "$1" ]
|
||||||
|
then
|
||||||
|
echo "Path not specified to find_maven_basedir"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
basedir="$1"
|
||||||
|
wdir="$1"
|
||||||
while [ "$wdir" != '/' ] ; do
|
while [ "$wdir" != '/' ] ; do
|
||||||
if [ -d "$wdir"/.mvn ] ; then
|
if [ -d "$wdir"/.mvn ] ; then
|
||||||
basedir=$wdir
|
basedir=$wdir
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
wdir=$(cd "$wdir/.."; pwd)
|
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
|
||||||
|
if [ -d "${wdir}" ]; then
|
||||||
|
wdir=`cd "$wdir/.."; pwd`
|
||||||
|
fi
|
||||||
|
# end of workaround
|
||||||
done
|
done
|
||||||
echo "${basedir}"
|
echo "${basedir}"
|
||||||
}
|
}
|
||||||
|
@ -216,9 +194,108 @@ concat_lines() {
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)}
|
BASE_DIR=`find_maven_basedir "$(pwd)"`
|
||||||
|
if [ -z "$BASE_DIR" ]; then
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
##########################################################################################
|
||||||
|
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||||
|
# This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||||
|
##########################################################################################
|
||||||
|
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo "Found .mvn/wrapper/maven-wrapper.jar"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
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.6/maven-wrapper-0.5.6.jar"
|
||||||
|
else
|
||||||
|
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 ;;
|
||||||
|
esac
|
||||||
|
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo "Downloading from: $jarUrl"
|
||||||
|
fi
|
||||||
|
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
|
||||||
|
if $cygwin; then
|
||||||
|
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v wget > /dev/null; then
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo "Found wget ... using wget"
|
||||||
|
fi
|
||||||
|
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||||
|
wget "$jarUrl" -O "$wrapperJarPath"
|
||||||
|
else
|
||||||
|
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
|
||||||
|
fi
|
||||||
|
elif command -v curl > /dev/null; then
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo "Found curl ... using curl"
|
||||||
|
fi
|
||||||
|
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||||
|
curl -o "$wrapperJarPath" "$jarUrl" -f
|
||||||
|
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"
|
||||||
|
fi
|
||||||
|
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
|
||||||
|
# For Cygwin, switch paths to Windows format before running javac
|
||||||
|
if $cygwin; then
|
||||||
|
javaClass=`cygpath --path --windows "$javaClass"`
|
||||||
|
fi
|
||||||
|
if [ -e "$javaClass" ]; then
|
||||||
|
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo " - Compiling MavenWrapperDownloader.java ..."
|
||||||
|
fi
|
||||||
|
# Compiling the Java class
|
||||||
|
("$JAVA_HOME/bin/javac" "$javaClass")
|
||||||
|
fi
|
||||||
|
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||||
|
# Running the downloader
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo " - Running MavenWrapperDownloader.java ..."
|
||||||
|
fi
|
||||||
|
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
##########################################################################################
|
||||||
|
# End of extension
|
||||||
|
##########################################################################################
|
||||||
|
|
||||||
|
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo $MAVEN_PROJECTBASEDIR
|
||||||
|
fi
|
||||||
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
|
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
|
||||||
|
|
||||||
|
# For Cygwin, switch paths to Windows format before running java
|
||||||
|
if $cygwin; then
|
||||||
|
[ -n "$M2_HOME" ] &&
|
||||||
|
M2_HOME=`cygpath --path --windows "$M2_HOME"`
|
||||||
|
[ -n "$JAVA_HOME" ] &&
|
||||||
|
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
|
||||||
|
[ -n "$CLASSPATH" ] &&
|
||||||
|
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
|
||||||
|
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
|
||||||
|
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
|
||||||
|
fi
|
||||||
|
|
||||||
# Provide a "standardized" way to retrieve the CLI args that will
|
# Provide a "standardized" way to retrieve the CLI args that will
|
||||||
# work with both Windows and non-Windows executions.
|
# work with both Windows and non-Windows executions.
|
||||||
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
|
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
|
||||||
|
@ -230,5 +307,4 @@ exec "$JAVACMD" \
|
||||||
$MAVEN_OPTS \
|
$MAVEN_OPTS \
|
||||||
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
|
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
|
||||||
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
|
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
|
||||||
${WRAPPER_LAUNCHER} $MAVEN_CMD_LINE_ARGS
|
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
|
||||||
|
|
||||||
|
|
55
mvnw.cmd
vendored
55
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
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
@REM Optional ENV vars
|
@REM Optional ENV vars
|
||||||
@REM M2_HOME - location of maven2's installed home dir
|
@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_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 MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||||
@REM e.g. to debug Maven itself, use
|
@REM e.g. to debug Maven itself, use
|
||||||
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||||
|
@ -35,7 +35,9 @@
|
||||||
|
|
||||||
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
|
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
|
||||||
@echo off
|
@echo off
|
||||||
@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
|
@REM set title of command window
|
||||||
|
title %0
|
||||||
|
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
|
||||||
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
|
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
|
||||||
|
|
||||||
@REM set %HOME% to equivalent of $HOME
|
@REM set %HOME% to equivalent of $HOME
|
||||||
|
@ -80,8 +82,6 @@ goto error
|
||||||
|
|
||||||
:init
|
:init
|
||||||
|
|
||||||
set MAVEN_CMD_LINE_ARGS=%MAVEN_CONFIG% %*
|
|
||||||
|
|
||||||
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
|
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
|
||||||
@REM Fallback to current working directory if not found.
|
@REM Fallback to current working directory if not found.
|
||||||
|
|
||||||
|
@ -117,11 +117,48 @@ for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do s
|
||||||
:endReadAdditionalConfig
|
:endReadAdditionalConfig
|
||||||
|
|
||||||
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
|
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
|
||||||
|
|
||||||
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS%
|
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
|
||||||
|
)
|
||||||
|
|
||||||
|
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||||
|
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||||
|
if exist %WRAPPER_JAR% (
|
||||||
|
if "%MVNW_VERBOSE%" == "true" (
|
||||||
|
echo Found %WRAPPER_JAR%
|
||||||
|
)
|
||||||
|
) else (
|
||||||
|
if not "%MVNW_REPOURL%" == "" (
|
||||||
|
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 ...
|
||||||
|
echo Downloading from: %DOWNLOAD_URL%
|
||||||
|
)
|
||||||
|
|
||||||
|
powershell -Command "&{"^
|
||||||
|
"$webclient = new-object System.Net.WebClient;"^
|
||||||
|
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
|
||||||
|
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
|
||||||
|
"}"^
|
||||||
|
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
|
||||||
|
"}"
|
||||||
|
if "%MVNW_VERBOSE%" == "true" (
|
||||||
|
echo Finished downloading %WRAPPER_JAR%
|
||||||
|
)
|
||||||
|
)
|
||||||
|
@REM End of extension
|
||||||
|
|
||||||
|
@REM Provide a "standardized" way to retrieve the CLI args that will
|
||||||
|
@REM work with both Windows and non-Windows executions.
|
||||||
|
set MAVEN_CMD_LINE_ARGS=%*
|
||||||
|
|
||||||
|
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
|
||||||
if ERRORLEVEL 1 goto error
|
if ERRORLEVEL 1 goto error
|
||||||
goto end
|
goto end
|
||||||
|
|
||||||
|
|
587
pom.xml
587
pom.xml
|
@ -1,245 +1,384 @@
|
||||||
<?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 http://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>1.5.2-SNAPSHOT</version>
|
<version>2.3.0.BUILD-SNAPSHOT</version>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>2.3.3.RELEASE</version>
|
||||||
|
</parent>
|
||||||
|
<name>petclinic</name>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
|
||||||
|
<!-- Generic properties -->
|
||||||
|
<java.version>1.8</java.version>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
|
|
||||||
|
<!-- Web dependencies -->
|
||||||
|
<webjars-bootstrap.version>3.3.6</webjars-bootstrap.version>
|
||||||
|
<webjars-jquery-ui.version>1.11.4</webjars-jquery-ui.version>
|
||||||
|
<webjars-jquery.version>2.2.4</webjars-jquery.version>
|
||||||
|
<wro4j.version>1.8.0</wro4j.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>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- Spring and Spring Boot dependencies -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-cache</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-validation</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.junit.vintage</groupId>
|
||||||
|
<artifactId>junit-vintage-engine</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Databases - Uses H2 by default -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.h2database</groupId>
|
||||||
|
<artifactId>h2</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>mysql</groupId>
|
||||||
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- caching -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.cache</groupId>
|
||||||
|
<artifactId>cache-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.ehcache</groupId>
|
||||||
|
<artifactId>ehcache</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- webjars -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.webjars</groupId>
|
||||||
|
<artifactId>webjars-locator-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.webjars</groupId>
|
||||||
|
<artifactId>jquery</artifactId>
|
||||||
|
<version>${webjars-jquery.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.webjars</groupId>
|
||||||
|
<artifactId>jquery-ui</artifactId>
|
||||||
|
<version>${webjars-jquery-ui.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.webjars</groupId>
|
||||||
|
<artifactId>bootstrap</artifactId>
|
||||||
|
<version>${webjars-bootstrap.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- 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>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-devtools</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<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>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-parent</artifactId>
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
<version>1.5.4.RELEASE</version>
|
<executions>
|
||||||
</parent>
|
<execution>
|
||||||
<name>petclinic</name>
|
<!-- Spring Boot Actuator displays build-related information
|
||||||
|
if a META-INF/build-info.properties file is present -->
|
||||||
|
<goals>
|
||||||
|
<goal>build-info</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<additionalProperties>
|
||||||
|
<encoding.source>${project.build.sourceEncoding}</encoding.source>
|
||||||
|
<encoding.reporting>${project.reporting.outputEncoding}</encoding.reporting>
|
||||||
|
<java.source>${maven.compiler.source}</java.source>
|
||||||
|
<java.target>${maven.compiler.target}</java.target>
|
||||||
|
</additionalProperties>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.jacoco</groupId>
|
||||||
|
<artifactId>jacoco-maven-plugin</artifactId>
|
||||||
|
<version>${jacoco.version}</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>prepare-agent</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>report</id>
|
||||||
|
<phase>prepare-package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>report</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
<properties>
|
<!-- Spring Boot Actuator displays build-related information if a git.properties
|
||||||
|
file is present at the classpath -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>pl.project13.maven</groupId>
|
||||||
|
<artifactId>git-commit-id-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>revision</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
<configuration>
|
||||||
|
<verbose>true</verbose>
|
||||||
|
<dateFormat>yyyy-MM-dd'T'HH:mm:ssZ</dateFormat>
|
||||||
|
<generateGitPropertiesFile>true</generateGitPropertiesFile>
|
||||||
|
<generateGitPropertiesFilename>${project.build.outputDirectory}/git.properties
|
||||||
|
</generateGitPropertiesFilename>
|
||||||
|
<failOnNoGitDirectory>false</failOnNoGitDirectory>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
<!-- Generic properties -->
|
<plugin>
|
||||||
<java.version>1.8</java.version>
|
<groupId>ro.isdc.wro4j</groupId>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<artifactId>wro4j-maven-plugin</artifactId>
|
||||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
<version>${wro4j.version}</version>
|
||||||
|
<executions>
|
||||||
<!-- Web dependencies -->
|
<execution>
|
||||||
<webjars-bootstrap.version>3.3.6</webjars-bootstrap.version>
|
<phase>generate-resources</phase>
|
||||||
<webjars-jquery-ui.version>1.11.4</webjars-jquery-ui.version>
|
<goals>
|
||||||
<webjars-jquery.version>2.2.4</webjars-jquery.version>
|
<goal>run</goal>
|
||||||
<wro4j.version>1.8.0</wro4j.version>
|
</goals>
|
||||||
<thymeleaf.version>3.0.6.RELEASE</thymeleaf.version>
|
</execution>
|
||||||
|
</executions>
|
||||||
<cobertura.version>2.7</cobertura.version>
|
<configuration>
|
||||||
|
<wroManagerFactory>ro.isdc.wro.maven.plugin.manager.factory.ConfigurableWroManagerFactory</wroManagerFactory>
|
||||||
</properties>
|
<cssDestinationFolder>${project.build.directory}/classes/static/resources/css</cssDestinationFolder>
|
||||||
|
<wroFile>${basedir}/src/main/wro/wro.xml</wroFile>
|
||||||
<dependencies>
|
<extraConfigFile>${basedir}/src/main/wro/wro.properties</extraConfigFile>
|
||||||
<!-- Spring and Spring Boot dependencies -->
|
<contextFolder>${basedir}/src/main/less</contextFolder>
|
||||||
<dependency>
|
</configuration>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<dependencies>
|
||||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
<dependency>
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-cache</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>nz.net.ultraq.thymeleaf</groupId>
|
|
||||||
<artifactId>thymeleaf-layout-dialect</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- Databases - Uses HSQL by default -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.hsqldb</groupId>
|
|
||||||
<artifactId>hsqldb</artifactId>
|
|
||||||
<scope>runtime</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>mysql</groupId>
|
|
||||||
<artifactId>mysql-connector-java</artifactId>
|
|
||||||
<scope>runtime</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- caching -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>javax.cache</groupId>
|
|
||||||
<artifactId>cache-api</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.ehcache</groupId>
|
|
||||||
<artifactId>ehcache</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- webjars -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.webjars</groupId>
|
|
||||||
<artifactId>webjars-locator</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.webjars</groupId>
|
|
||||||
<artifactId>jquery</artifactId>
|
|
||||||
<version>${webjars-jquery.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.webjars</groupId>
|
|
||||||
<artifactId>jquery-ui</artifactId>
|
|
||||||
<version>${webjars-jquery-ui.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.webjars</groupId>
|
<groupId>org.webjars</groupId>
|
||||||
<artifactId>bootstrap</artifactId>
|
<artifactId>bootstrap</artifactId>
|
||||||
<version>${webjars-bootstrap.version}</version>
|
<version>${webjars-bootstrap.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- end of webjars -->
|
<dependency>
|
||||||
|
<groupId>org.mockito</groupId>
|
||||||
|
<artifactId>mockito-core</artifactId>
|
||||||
|
<version>${mockito.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
<dependency>
|
<licenses>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<license>
|
||||||
<artifactId>spring-boot-devtools</artifactId>
|
<name>Apache License, Version 2.0</name>
|
||||||
<scope>runtime</scope>
|
<url>https://www.apache.org/licenses/LICENSE-2.0</url>
|
||||||
</dependency>
|
</license>
|
||||||
</dependencies>
|
</licenses>
|
||||||
|
|
||||||
<build>
|
<repositories>
|
||||||
<finalName>spring-petclinic</finalName>
|
<repository>
|
||||||
<plugins>
|
<id>spring-snapshots</id>
|
||||||
<plugin>
|
<name>Spring Snapshots</name>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<url>https://repo.spring.io/snapshot</url>
|
||||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
<snapshots>
|
||||||
<executions>
|
<enabled>true</enabled>
|
||||||
<execution>
|
</snapshots>
|
||||||
<!-- Spring Boot Actuator displays build-related information
|
</repository>
|
||||||
if a META-INF/build-info.properties file is present -->
|
<repository>
|
||||||
<goals>
|
<id>spring-milestones</id>
|
||||||
<goal>build-info</goal>
|
<name>Spring Milestones</name>
|
||||||
</goals>
|
<url>https://repo.spring.io/milestone</url>
|
||||||
<configuration>
|
<snapshots>
|
||||||
<executable>true</executable>
|
<enabled>false</enabled>
|
||||||
<additionalProperties>
|
</snapshots>
|
||||||
<encoding.source>${project.build.sourceEncoding}</encoding.source>
|
</repository>
|
||||||
<encoding.reporting>${project.reporting.outputEncoding}</encoding.reporting>
|
</repositories>
|
||||||
<java.source>${maven.compiler.source}</java.source>
|
|
||||||
<java.target>${maven.compiler.target}</java.target>
|
|
||||||
</additionalProperties>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
<plugin>
|
<pluginRepositories>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<pluginRepository>
|
||||||
<artifactId>maven-failsafe-plugin</artifactId>
|
<id>spring-snapshots</id>
|
||||||
<executions>
|
<name>Spring Snapshots</name>
|
||||||
<execution>
|
<url>https://repo.spring.io/snapshot</url>
|
||||||
<phase>integration-test</phase>
|
<snapshots>
|
||||||
<goals>
|
<enabled>true</enabled>
|
||||||
<goal>integration-test</goal>
|
</snapshots>
|
||||||
<goal>verify</goal>
|
</pluginRepository>
|
||||||
</goals>
|
<pluginRepository>
|
||||||
</execution>
|
<id>spring-milestones</id>
|
||||||
</executions>
|
<name>Spring Milestones</name>
|
||||||
</plugin>
|
<url>https://repo.spring.io/milestone</url>
|
||||||
<plugin>
|
<snapshots>
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
<enabled>false</enabled>
|
||||||
<artifactId>cobertura-maven-plugin</artifactId>
|
</snapshots>
|
||||||
<version>${cobertura.version}</version>
|
</pluginRepository>
|
||||||
<configuration>
|
</pluginRepositories>
|
||||||
<check/>
|
|
||||||
</configuration>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<goals>
|
|
||||||
<goal>clean</goal>
|
|
||||||
<goal>check</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
<!-- Spring Boot Actuator displays build-related information if a git.properties
|
<profiles>
|
||||||
file is present at the classpath -->
|
<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>
|
<plugin>
|
||||||
<groupId>pl.project13.maven</groupId>
|
<groupId>org.eclipse.m2e</groupId>
|
||||||
<artifactId>git-commit-id-plugin</artifactId>
|
<artifactId>lifecycle-mapping</artifactId>
|
||||||
<executions>
|
<version>1.0.0</version>
|
||||||
<execution>
|
<configuration>
|
||||||
|
<lifecycleMappingMetadata>
|
||||||
|
<pluginExecutions>
|
||||||
|
<pluginExecution>
|
||||||
|
<pluginExecutionFilter>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||||
|
<versionRange>[1,)</versionRange>
|
||||||
<goals>
|
<goals>
|
||||||
<goal>revision</goal>
|
<goal>check</goal>
|
||||||
</goals>
|
</goals>
|
||||||
</execution>
|
</pluginExecutionFilter>
|
||||||
</executions>
|
<action>
|
||||||
<configuration>
|
<ignore/>
|
||||||
<verbose>true</verbose>
|
</action>
|
||||||
<dateFormat>yyyy-MM-dd'T'HH:mm:ssZ</dateFormat>
|
</pluginExecution>
|
||||||
<generateGitPropertiesFile>true</generateGitPropertiesFile>
|
<pluginExecution>
|
||||||
<generateGitPropertiesFilename>${project.build.outputDirectory}/git.properties
|
<pluginExecutionFilter>
|
||||||
</generateGitPropertiesFilename>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<failOnNoGitDirectory>false</failOnNoGitDirectory>
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
</configuration>
|
<versionRange>[1,)</versionRange>
|
||||||
</plugin>
|
|
||||||
|
|
||||||
<plugin>
|
|
||||||
<groupId>ro.isdc.wro4j</groupId>
|
|
||||||
<artifactId>wro4j-maven-plugin</artifactId>
|
|
||||||
<version>${wro4j.version}</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<phase>generate-resources</phase>
|
|
||||||
<goals>
|
<goals>
|
||||||
<goal>run</goal>
|
<goal>build-info</goal>
|
||||||
</goals>
|
</goals>
|
||||||
</execution>
|
</pluginExecutionFilter>
|
||||||
</executions>
|
<action>
|
||||||
<configuration>
|
<ignore/>
|
||||||
<wroManagerFactory>ro.isdc.wro.maven.plugin.manager.factory.ConfigurableWroManagerFactory
|
</action>
|
||||||
</wroManagerFactory>
|
</pluginExecution>
|
||||||
<cssDestinationFolder>${project.build.directory}/classes/static/resources/css</cssDestinationFolder>
|
</pluginExecutions>
|
||||||
<wroFile>${basedir}/src/main/wro/wro.xml</wroFile>
|
</lifecycleMappingMetadata>
|
||||||
<extraConfigFile>${basedir}/src/main/wro/wro.properties</extraConfigFile>
|
</configuration>
|
||||||
<contextFolder>${basedir}/src/main/less</contextFolder>
|
|
||||||
</configuration>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.webjars</groupId>
|
|
||||||
<artifactId>bootstrap</artifactId>
|
|
||||||
<version>${webjars-bootstrap.version}</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</pluginManagement>
|
||||||
<reporting>
|
</build>
|
||||||
<plugins>
|
</profile>
|
||||||
<!-- integrate maven-cobertura-plugin to project site -->
|
</profiles>
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>cobertura-maven-plugin</artifactId>
|
|
||||||
<version>${cobertura.version}</version>
|
|
||||||
<configuration>
|
|
||||||
<formats>
|
|
||||||
<format>html</format>
|
|
||||||
</formats>
|
|
||||||
<check/>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</reporting>
|
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -1,85 +1,102 @@
|
||||||
# Spring PetClinic Sample Application [](https://travis-ci.org/spring-projects/spring-petclinic/)
|
# Spring PetClinic Sample Application [](https://travis-ci.org/spring-projects/spring-petclinic/)
|
||||||
|
|
||||||
## 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>
|
||||||
|
|
||||||
## Running petclinic locally
|
## Running petclinic locally
|
||||||
|
Petclinic is a [Spring Boot](https://spring.io/guides/gs/spring-boot) application built using [Maven](https://spring.io/guides/gs/maven/). You can build a jar file and run it from the command line:
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
git clone https://github.com/spring-projects/spring-petclinic.git
|
git clone https://github.com/spring-projects/spring-petclinic.git
|
||||||
cd spring-petclinic
|
cd spring-petclinic
|
||||||
./mvnw spring-boot:run
|
./mvnw package
|
||||||
|
java -jar target/*.jar
|
||||||
```
|
```
|
||||||
|
|
||||||
You can then access petclinic here: http://localhost:8080/
|
You can then access petclinic here: http://localhost:8080/
|
||||||
|
|
||||||
<img width="1042" alt="petclinic-screenshot" src="https://cloud.githubusercontent.com/assets/838318/19727082/2aee6d6c-9b8e-11e6-81fe-e889a5ddfded.png">
|
<img width="1042" alt="petclinic-screenshot" src="https://cloud.githubusercontent.com/assets/838318/19727082/2aee6d6c-9b8e-11e6-81fe-e889a5ddfded.png">
|
||||||
|
|
||||||
|
Or you can run it from Maven directly using the Spring Boot Maven plugin. If you do this it will pick up changes that you make in the project immediately (changes to Java source files require a compile as well - most people use an IDE for this):
|
||||||
|
|
||||||
|
```
|
||||||
|
./mvnw spring-boot:run
|
||||||
|
```
|
||||||
|
|
||||||
## In case you find a bug/suggested improvement for Spring Petclinic
|
## In case you find a bug/suggested improvement for Spring Petclinic
|
||||||
Our issue tracker is available here: https://github.com/spring-projects/spring-petclinic/issues
|
Our issue tracker is available here: https://github.com/spring-projects/spring-petclinic/issues
|
||||||
|
|
||||||
|
|
||||||
## 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 data-access.properties file needs to be updated and the mysql-connector-java artifact from the pom.xml needs to be uncommented.
|
and it is possible to inspect the content of the database using the `jdbc:h2:mem:testdb` url.
|
||||||
|
|
||||||
You could start a MySql database with docker:
|
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
|
||||||
```
|
```
|
||||||
|
|
||||||
## Working with Petclinic in Eclipse/STS
|
Further documentation is provided [here](https://github.com/spring-projects/spring-petclinic/blob/main/src/main/resources/db/mysql/petclinic_db_setup_mysql.txt).
|
||||||
|
|
||||||
### prerequisites
|
## Working with Petclinic in your IDE
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
The following items should be installed in your system:
|
The following items should be installed in your system:
|
||||||
* Maven 3 (http://www.sonatype.com/books/mvnref-book/reference/installation.html)
|
* Java 8 or newer.
|
||||||
* git command line tool (https://help.github.com/articles/set-up-git)
|
* git command line tool (https://help.github.com/articles/set-up-git)
|
||||||
* Eclipse with the m2e plugin (m2e is installed by default when using the STS (http://www.springsource.org/sts) distribution of Eclipse)
|
* Your preferred IDE
|
||||||
|
* Eclipse with the m2e plugin. Note: when m2e is available, there is an m2 icon in `Help -> About` dialog. If m2e is
|
||||||
Note: when m2e is available, there is an m2 icon in Help -> About dialog.
|
not there, just follow the install process here: https://www.eclipse.org/m2e/
|
||||||
If m2e is not there, just follow the install process here: http://eclipse.org/m2e/download/
|
* [Spring Tools Suite](https://spring.io/tools) (STS)
|
||||||
|
* IntelliJ IDEA
|
||||||
|
* [VS Code](https://code.visualstudio.com)
|
||||||
|
|
||||||
### Steps:
|
### Steps:
|
||||||
|
|
||||||
1) In the command line
|
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
|
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`.
|
||||||
|
|
||||||
|
3) Inside IntelliJ IDEA
|
||||||
|
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`.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
|
||||||
## Looking for something in particular?
|
## Looking for something in particular?
|
||||||
|
|
||||||
|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 | [CacheConfig](https://github.com/spring-projects/spring-petclinic/blob/master/src/main/java/org/springframework/samples/petclinic/system/CacheConfig.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
|
The Spring Petclinic "main" branch in the [spring-projects](https://github.com/spring-projects/spring-petclinic)
|
||||||
[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
|
[quite a few forks](https://spring-petclinic.github.io/docs/forks.html) in a special GitHub org
|
||||||
Spring Boot and Thymeleaf. There are quite a few forks in a special
|
[spring-petclinic](https://github.com/spring-petclinic). If you have a special interest in a different technology stack
|
||||||
GitHub org [spring-petclinic](https://github.com/spring-petclinic). If
|
that could be used to implement the Pet Clinic then please join the community there.
|
||||||
you have a special interest in a different technology stack that could
|
|
||||||
be used to implement the Pet Clinic then please join the community
|
|
||||||
there.
|
|
||||||
|
|
||||||
| Link | Main technologies |
|
|
||||||
|----------------|-------------------|
|
|
||||||
| [spring-framework-petclinic](https://github.com/spring-petclinic/spring-framework-petclinic) | Spring Framework XML configuration, JSP pages, 3 persistence layers: JDBC, JPA and Spring Data JPA |
|
|
||||||
| [javaconfig branch](https://github.com/spring-petclinic/spring-framework-petclinic/tree/javaconfig) | Same frameworks as the [spring-framework-petclinic](https://github.com/spring-petclinic/spring-framework-petclinic) but with Java Configuration instead of XML |
|
|
||||||
| [spring-petclinic-angular](https://github.com/spring-petclinic/spring-petclinic-angularjs) | AngularJS 1.x, Spring Boot and Spring Data JPA |
|
|
||||||
| [spring-petclinic-microservices](https://github.com/spring-petclinic/spring-petclinic-microservices) | Distributed version of Spring Petclinic built with Spring Cloud |
|
|
||||||
| [spring-petclinic-reactjs](https://github.com/spring-petclinic/spring-petclinic-reactjs) | ReactJS (with TypeScript) and Spring Boot |
|
|
||||||
|
|
||||||
|
|
||||||
## Interaction with other open source projects
|
## Interaction with other open source projects
|
||||||
|
@ -98,8 +115,19 @@ Here is a list of them:
|
||||||
|
|
||||||
The [issue tracker](https://github.com/spring-projects/spring-petclinic/issues) is the preferred channel for bug reports, features requests and submitting pull requests.
|
The [issue tracker](https://github.com/spring-projects/spring-petclinic/issues) is the preferred channel for bug reports, features requests and submitting pull requests.
|
||||||
|
|
||||||
For pull requests, editor preferences are available in the [editor config](.editorconfig) for easy use in common text editors. Read more and download plugins at <http://editorconfig.org>.
|
For pull requests, editor preferences are available in the [editor config](.editorconfig) for easy use in common text editors. Read more and download plugins at <https://editorconfig.org>. If you have not previously done so, please fill out and submit the [Contributor License Agreement](https://cla.pivotal.io/sign/spring).
|
||||||
|
|
||||||
|
|
||||||
|
# License
|
||||||
|
|
||||||
|
The Spring PetClinic sample application is released under version 2.0 of the [Apache License](https://www.apache.org/licenses/LICENSE-2.0).
|
||||||
|
|
||||||
|
[spring-petclinic]: https://github.com/spring-projects/spring-petclinic
|
||||||
|
[spring-framework-petclinic]: https://github.com/spring-petclinic/spring-framework-petclinic
|
||||||
|
[spring-petclinic-angularjs]: https://github.com/spring-petclinic/spring-petclinic-angularjs
|
||||||
|
[javaconfig branch]: https://github.com/spring-petclinic/spring-framework-petclinic/tree/javaconfig
|
||||||
|
[spring-petclinic-angular]: https://github.com/spring-petclinic/spring-petclinic-angular
|
||||||
|
[spring-petclinic-microservices]: https://github.com/spring-petclinic/spring-petclinic-microservices
|
||||||
|
[spring-petclinic-reactjs]: https://github.com/spring-petclinic/spring-petclinic-reactjs
|
||||||
|
[spring-petclinic-graphql]: https://github.com/spring-petclinic/spring-petclinic-graphql
|
||||||
|
[spring-petclinic-kotlin]: https://github.com/spring-petclinic/spring-petclinic-kotlin
|
||||||
|
[spring-petclinic-rest]: https://github.com/spring-petclinic/spring-petclinic-rest
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
# Required metadata
|
|
||||||
sonar.projectKey=java-sonar-runner-simple
|
|
||||||
sonar.projectName=Simple Java project analyzed with the SonarQube Runner
|
|
||||||
sonar.projectVersion=1.0
|
|
||||||
|
|
||||||
# Comma-separated paths to directories with sources (required)
|
|
||||||
sonar.sources=src
|
|
||||||
|
|
||||||
# Language
|
|
||||||
sonar.language=java
|
|
||||||
|
|
||||||
# Encoding of the source files
|
|
||||||
sonar.sourceEncoding=UTF-8
|
|
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>
|
|
@ -1,11 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2014 the original author or authors.
|
* Copyright 2012-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* 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,
|
||||||
|
@ -25,11 +25,11 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@SpringBootApplication
|
@SpringBootApplication(proxyBeanMethods = false)
|
||||||
public class PetClinicApplication {
|
public class PetClinicApplication {
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(PetClinicApplication.class, args);
|
SpringApplication.run(PetClinicApplication.class, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2012-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* 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,
|
||||||
|
@ -31,20 +31,21 @@ import javax.persistence.MappedSuperclass;
|
||||||
*/
|
*/
|
||||||
@MappedSuperclass
|
@MappedSuperclass
|
||||||
public class BaseEntity implements Serializable {
|
public class BaseEntity implements Serializable {
|
||||||
@Id
|
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
|
||||||
private Integer id;
|
|
||||||
|
|
||||||
public Integer getId() {
|
@Id
|
||||||
return id;
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
}
|
private Integer id;
|
||||||
|
|
||||||
public void setId(Integer id) {
|
public Integer getId() {
|
||||||
this.id = id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isNew() {
|
public void setId(Integer id) {
|
||||||
return this.id == null;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isNew() {
|
||||||
|
return this.id == null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2012-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* 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,
|
||||||
|
@ -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
|
||||||
|
@ -29,20 +28,20 @@ import javax.persistence.MappedSuperclass;
|
||||||
@MappedSuperclass
|
@MappedSuperclass
|
||||||
public class NamedEntity extends BaseEntity {
|
public class NamedEntity extends BaseEntity {
|
||||||
|
|
||||||
@Column(name = "name")
|
@Column(name = "name")
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return this.name;
|
return this.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return this.getName();
|
return this.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2012-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* 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,
|
||||||
|
@ -17,8 +17,7 @@ package org.springframework.samples.petclinic.model;
|
||||||
|
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.MappedSuperclass;
|
import javax.persistence.MappedSuperclass;
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
import org.hibernate.validator.constraints.NotEmpty;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple JavaBean domain object representing an person.
|
* Simple JavaBean domain object representing an person.
|
||||||
|
@ -28,28 +27,28 @@ import org.hibernate.validator.constraints.NotEmpty;
|
||||||
@MappedSuperclass
|
@MappedSuperclass
|
||||||
public class Person extends BaseEntity {
|
public class Person extends BaseEntity {
|
||||||
|
|
||||||
@Column(name = "first_name")
|
@Column(name = "first_name")
|
||||||
@NotEmpty
|
@NotEmpty
|
||||||
private String firstName;
|
private String firstName;
|
||||||
|
|
||||||
@Column(name = "last_name")
|
@Column(name = "last_name")
|
||||||
@NotEmpty
|
@NotEmpty
|
||||||
private String lastName;
|
private String lastName;
|
||||||
|
|
||||||
public String getFirstName() {
|
public String getFirstName() {
|
||||||
return this.firstName;
|
return this.firstName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFirstName(String firstName) {
|
public void setFirstName(String firstName) {
|
||||||
this.firstName = firstName;
|
this.firstName = firstName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getLastName() {
|
public String getLastName() {
|
||||||
return this.lastName;
|
return this.lastName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLastName(String lastName) {
|
public void setLastName(String lastName) {
|
||||||
this.lastName = lastName;
|
this.lastName = lastName;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,20 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2019 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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;
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2012-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* 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,
|
||||||
|
@ -27,8 +27,8 @@ import javax.persistence.Entity;
|
||||||
import javax.persistence.OneToMany;
|
import javax.persistence.OneToMany;
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
import javax.validation.constraints.Digits;
|
import javax.validation.constraints.Digits;
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
|
||||||
import org.hibernate.validator.constraints.NotEmpty;
|
|
||||||
import org.springframework.beans.support.MutableSortDefinition;
|
import org.springframework.beans.support.MutableSortDefinition;
|
||||||
import org.springframework.beans.support.PropertyComparator;
|
import org.springframework.beans.support.PropertyComparator;
|
||||||
import org.springframework.core.style.ToStringCreator;
|
import org.springframework.core.style.ToStringCreator;
|
||||||
|
@ -45,112 +45,106 @@ 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")
|
|
||||||
@NotEmpty
|
|
||||||
private String address;
|
|
||||||
|
|
||||||
@Column(name = "city")
|
@Column(name = "address")
|
||||||
@NotEmpty
|
@NotEmpty
|
||||||
private String city;
|
private String address;
|
||||||
|
|
||||||
@Column(name = "telephone")
|
@Column(name = "city")
|
||||||
@NotEmpty
|
@NotEmpty
|
||||||
@Digits(fraction = 0, integer = 10)
|
private String city;
|
||||||
private String telephone;
|
|
||||||
|
|
||||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "owner")
|
@Column(name = "telephone")
|
||||||
private Set<Pet> pets;
|
@NotEmpty
|
||||||
|
@Digits(fraction = 0, integer = 10)
|
||||||
|
private String telephone;
|
||||||
|
|
||||||
|
@OneToMany(cascade = CascadeType.ALL, mappedBy = "owner")
|
||||||
|
private Set<Pet> pets;
|
||||||
|
|
||||||
public String getAddress() {
|
public String getAddress() {
|
||||||
return this.address;
|
return this.address;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAddress(String address) {
|
public void setAddress(String address) {
|
||||||
this.address = address;
|
this.address = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCity() {
|
public String getCity() {
|
||||||
return this.city;
|
return this.city;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCity(String city) {
|
public void setCity(String city) {
|
||||||
this.city = city;
|
this.city = city;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTelephone() {
|
public String getTelephone() {
|
||||||
return this.telephone;
|
return this.telephone;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTelephone(String telephone) {
|
public void setTelephone(String telephone) {
|
||||||
this.telephone = telephone;
|
this.telephone = telephone;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Set<Pet> getPetsInternal() {
|
protected Set<Pet> getPetsInternal() {
|
||||||
if (this.pets == null) {
|
if (this.pets == null) {
|
||||||
this.pets = new HashSet<>();
|
this.pets = new HashSet<>();
|
||||||
}
|
}
|
||||||
return this.pets;
|
return this.pets;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setPetsInternal(Set<Pet> pets) {
|
protected void setPetsInternal(Set<Pet> pets) {
|
||||||
this.pets = pets;
|
this.pets = pets;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Pet> getPets() {
|
public List<Pet> getPets() {
|
||||||
List<Pet> sortedPets = new ArrayList<>(getPetsInternal());
|
List<Pet> sortedPets = new ArrayList<>(getPetsInternal());
|
||||||
PropertyComparator.sort(sortedPets, new MutableSortDefinition("name", true, true));
|
PropertyComparator.sort(sortedPets, new MutableSortDefinition("name", true, true));
|
||||||
return Collections.unmodifiableList(sortedPets);
|
return Collections.unmodifiableList(sortedPets);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addPet(Pet pet) {
|
public void addPet(Pet pet) {
|
||||||
if (pet.isNew()) {
|
if (pet.isNew()) {
|
||||||
getPetsInternal().add(pet);
|
getPetsInternal().add(pet);
|
||||||
}
|
}
|
||||||
pet.setOwner(this);
|
pet.setOwner(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
*/
|
||||||
*/
|
public Pet getPet(String name) {
|
||||||
public Pet getPet(String name) {
|
return getPet(name, false);
|
||||||
return getPet(name, false);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
*/
|
||||||
*/
|
public Pet getPet(String name, boolean ignoreNew) {
|
||||||
public Pet getPet(String name, boolean ignoreNew) {
|
name = name.toLowerCase();
|
||||||
name = name.toLowerCase();
|
for (Pet pet : getPetsInternal()) {
|
||||||
for (Pet pet : getPetsInternal()) {
|
if (!ignoreNew || !pet.isNew()) {
|
||||||
if (!ignoreNew || !pet.isNew()) {
|
String compName = pet.getName();
|
||||||
String compName = pet.getName();
|
compName = compName.toLowerCase();
|
||||||
compName = compName.toLowerCase();
|
if (compName.equals(name)) {
|
||||||
if (compName.equals(name)) {
|
return pet;
|
||||||
return pet;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return null;
|
||||||
return null;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return new ToStringCreator(this)
|
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2012-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* 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,
|
||||||
|
@ -15,22 +15,21 @@
|
||||||
*/
|
*/
|
||||||
package org.springframework.samples.petclinic.owner;
|
package org.springframework.samples.petclinic.owner;
|
||||||
|
|
||||||
import java.util.Collection;
|
import org.springframework.samples.petclinic.visit.VisitRepository;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import javax.validation.Valid;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.validation.BindingResult;
|
import org.springframework.validation.BindingResult;
|
||||||
import org.springframework.web.bind.WebDataBinder;
|
import org.springframework.web.bind.WebDataBinder;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.InitBinder;
|
import org.springframework.web.bind.annotation.InitBinder;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
* @author Ken Krebs
|
* @author Ken Krebs
|
||||||
|
@ -40,97 +39,107 @@ import org.springframework.web.servlet.ModelAndView;
|
||||||
@Controller
|
@Controller
|
||||||
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 final OwnerRepository owners;
|
||||||
|
|
||||||
@Autowired
|
private VisitRepository visits;
|
||||||
public OwnerController(OwnerRepository clinicService) {
|
|
||||||
this.owners = clinicService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@InitBinder
|
public OwnerController(OwnerRepository clinicService, VisitRepository visits) {
|
||||||
public void setAllowedFields(WebDataBinder dataBinder) {
|
this.owners = clinicService;
|
||||||
dataBinder.setDisallowedFields("id");
|
this.visits = visits;
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(value = "/owners/new", method = RequestMethod.GET)
|
@InitBinder
|
||||||
public String initCreationForm(Map<String, Object> model) {
|
public void setAllowedFields(WebDataBinder dataBinder) {
|
||||||
Owner owner = new Owner();
|
dataBinder.setDisallowedFields("id");
|
||||||
model.put("owner", owner);
|
}
|
||||||
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequestMapping(value = "/owners/new", method = RequestMethod.POST)
|
@GetMapping("/owners/new")
|
||||||
public String processCreationForm(@Valid Owner owner, BindingResult result) {
|
public String initCreationForm(Map<String, Object> model) {
|
||||||
if (result.hasErrors()) {
|
Owner owner = new Owner();
|
||||||
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
|
model.put("owner", owner);
|
||||||
} else {
|
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
|
||||||
this.owners.save(owner);
|
}
|
||||||
return "redirect:/owners/" + owner.getId();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequestMapping(value = "/owners/find", method = RequestMethod.GET)
|
@PostMapping("/owners/new")
|
||||||
public String initFindForm(Map<String, Object> model) {
|
public String processCreationForm(@Valid Owner owner, BindingResult result) {
|
||||||
model.put("owner", new Owner());
|
if (result.hasErrors()) {
|
||||||
return "owners/findOwners";
|
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
this.owners.save(owner);
|
||||||
|
return "redirect:/owners/" + owner.getId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@RequestMapping(value = "/owners", method = RequestMethod.GET)
|
@GetMapping("/owners/find")
|
||||||
public String processFindForm(Owner owner, BindingResult result, Map<String, Object> model) {
|
public String initFindForm(Map<String, Object> model) {
|
||||||
|
model.put("owner", new Owner());
|
||||||
|
return "owners/findOwners";
|
||||||
|
}
|
||||||
|
|
||||||
// allow parameterless GET request for /owners to return all records
|
@GetMapping("/owners")
|
||||||
if (owner.getLastName() == null) {
|
public String processFindForm(Owner owner, BindingResult result, Map<String, Object> model) {
|
||||||
owner.setLastName(""); // empty string signifies broadest possible search
|
|
||||||
}
|
|
||||||
|
|
||||||
// find owners by last name
|
// allow parameterless GET request for /owners to return all records
|
||||||
Collection<Owner> results = this.owners.findByLastName(owner.getLastName());
|
if (owner.getLastName() == null) {
|
||||||
if (results.isEmpty()) {
|
owner.setLastName(""); // empty string signifies broadest possible search
|
||||||
// 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";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequestMapping(value = "/owners/{ownerId}/edit", method = RequestMethod.GET)
|
// find owners by last name
|
||||||
public String initUpdateOwnerForm(@PathVariable("ownerId") int ownerId, Model model) {
|
Collection<Owner> results = this.owners.findByLastName(owner.getLastName());
|
||||||
Owner owner = this.owners.findById(ownerId);
|
if (results.isEmpty()) {
|
||||||
model.addAttribute(owner);
|
// no owners found
|
||||||
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
|
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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@RequestMapping(value = "/owners/{ownerId}/edit", method = RequestMethod.POST)
|
@GetMapping("/owners/{ownerId}/edit")
|
||||||
public String processUpdateOwnerForm(@Valid Owner owner, BindingResult result, @PathVariable("ownerId") int ownerId) {
|
public String initUpdateOwnerForm(@PathVariable("ownerId") int ownerId, Model model) {
|
||||||
if (result.hasErrors()) {
|
Owner owner = this.owners.findById(ownerId);
|
||||||
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
|
model.addAttribute(owner);
|
||||||
} else {
|
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
|
||||||
owner.setId(ownerId);
|
}
|
||||||
this.owners.save(owner);
|
|
||||||
return "redirect:/owners/{ownerId}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
@PostMapping("/owners/{ownerId}/edit")
|
||||||
* Custom handler for displaying an owner.
|
public String processUpdateOwnerForm(@Valid Owner owner, BindingResult result,
|
||||||
*
|
@PathVariable("ownerId") int ownerId) {
|
||||||
* @param ownerId the ID of the owner to display
|
if (result.hasErrors()) {
|
||||||
* @return a ModelMap with the model attributes for the view
|
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
|
||||||
*/
|
}
|
||||||
@RequestMapping("/owners/{ownerId}")
|
else {
|
||||||
public ModelAndView showOwner(@PathVariable("ownerId") int ownerId) {
|
owner.setId(ownerId);
|
||||||
ModelAndView mav = new ModelAndView("owners/ownerDetails");
|
this.owners.save(owner);
|
||||||
mav.addObject(this.owners.findById(ownerId));
|
return "redirect:/owners/{ownerId}";
|
||||||
return mav;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2012-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* 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,
|
||||||
|
@ -23,8 +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 See here: http://static.springsource.org/spring-data/jpa/docs/current/reference/html/jpa.repositories.html#jpa.query-methods.query-creation
|
* 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 Ken Krebs
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
|
@ -33,31 +35,30 @@ import org.springframework.transaction.annotation.Transactional;
|
||||||
*/
|
*/
|
||||||
public interface OwnerRepository extends Repository<Owner, Integer> {
|
public interface OwnerRepository extends Repository<Owner, Integer> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve {@link Owner}s from the data store by last name, returning all owners
|
* Retrieve {@link Owner}s from the data store by last name, returning all owners
|
||||||
* whose last name <i>starts</i> with the given name.
|
* whose last name <i>starts</i> with the given name.
|
||||||
* @param lastName Value to search for
|
* @param lastName Value to search for
|
||||||
* @return a Collection of matching {@link Owner}s (or an empty Collection if none
|
* @return a Collection of matching {@link Owner}s (or an empty Collection if none
|
||||||
* found)
|
* found)
|
||||||
*/
|
*/
|
||||||
@Query("SELECT DISTINCT owner FROM Owner owner left join fetch owner.pets WHERE owner.lastName LIKE :lastName%")
|
@Query("SELECT DISTINCT owner FROM Owner owner left join fetch owner.pets WHERE owner.lastName LIKE :lastName%")
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
Collection<Owner> findByLastName(@Param("lastName") String lastName);
|
Collection<Owner> findByLastName(@Param("lastName") String lastName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve an {@link Owner} from the data store by id.
|
* Retrieve an {@link Owner} from the data store by id.
|
||||||
* @param id the id to search for
|
* @param id the id to search for
|
||||||
* @return the {@link Owner} if found
|
* @return the {@link Owner} if found
|
||||||
*/
|
*/
|
||||||
@Query("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:id")
|
@Query("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:id")
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
Owner findById(@Param("id") Integer id);
|
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);
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save an {@link Owner} to the data store, either inserting or updating it.
|
||||||
|
* @param owner the {@link Owner} to save
|
||||||
|
*/
|
||||||
|
void save(Owner owner);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
109
src/main/java/org/springframework/samples/petclinic/owner/Pet.java
Normal file → Executable file
109
src/main/java/org/springframework/samples/petclinic/owner/Pet.java
Normal file → Executable file
|
@ -1,11 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2012-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* 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,
|
||||||
|
@ -15,24 +15,21 @@
|
||||||
*/
|
*/
|
||||||
package org.springframework.samples.petclinic.owner;
|
package org.springframework.samples.petclinic.owner;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.persistence.CascadeType;
|
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
import javax.persistence.FetchType;
|
|
||||||
import javax.persistence.JoinColumn;
|
import javax.persistence.JoinColumn;
|
||||||
import javax.persistence.ManyToOne;
|
import javax.persistence.ManyToOne;
|
||||||
import javax.persistence.OneToMany;
|
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
import javax.persistence.Temporal;
|
import javax.persistence.Transient;
|
||||||
import javax.persistence.TemporalType;
|
|
||||||
|
|
||||||
import org.springframework.beans.support.MutableSortDefinition;
|
import org.springframework.beans.support.MutableSortDefinition;
|
||||||
import org.springframework.beans.support.PropertyComparator;
|
import org.springframework.beans.support.PropertyComparator;
|
||||||
|
@ -51,67 +48,65 @@ import org.springframework.samples.petclinic.visit.Visit;
|
||||||
@Table(name = "pets")
|
@Table(name = "pets")
|
||||||
public class Pet extends NamedEntity {
|
public class Pet extends NamedEntity {
|
||||||
|
|
||||||
@Column(name = "birth_date")
|
@Column(name = "birth_date")
|
||||||
@Temporal(TemporalType.DATE)
|
@DateTimeFormat(pattern = "yyyy-MM-dd")
|
||||||
@DateTimeFormat(pattern = "yyyy/MM/dd")
|
private LocalDate birthDate;
|
||||||
private Date birthDate;
|
|
||||||
|
|
||||||
@ManyToOne
|
@ManyToOne
|
||||||
@JoinColumn(name = "type_id")
|
@JoinColumn(name = "type_id")
|
||||||
private PetType type;
|
private PetType type;
|
||||||
|
|
||||||
@ManyToOne
|
@ManyToOne
|
||||||
@JoinColumn(name = "owner_id")
|
@JoinColumn(name = "owner_id")
|
||||||
private Owner owner;
|
private Owner owner;
|
||||||
|
|
||||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "petId", fetch = FetchType.EAGER)
|
@Transient
|
||||||
private Set<Visit> visits = new LinkedHashSet<>();
|
private Set<Visit> visits = new LinkedHashSet<>();
|
||||||
|
|
||||||
public void setBirthDate(Date birthDate) {
|
public void setBirthDate(LocalDate birthDate) {
|
||||||
this.birthDate = birthDate;
|
this.birthDate = birthDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Date getBirthDate() {
|
public LocalDate getBirthDate() {
|
||||||
return this.birthDate;
|
return this.birthDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PetType getType() {
|
public PetType getType() {
|
||||||
return this.type;
|
return this.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setType(PetType type) {
|
public void setType(PetType type) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Owner getOwner() {
|
public Owner getOwner() {
|
||||||
return this.owner;
|
return this.owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setOwner(Owner owner) {
|
protected void setOwner(Owner owner) {
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Set<Visit> getVisitsInternal() {
|
protected Set<Visit> getVisitsInternal() {
|
||||||
if (this.visits == null) {
|
if (this.visits == null) {
|
||||||
this.visits = new HashSet<>();
|
this.visits = new HashSet<>();
|
||||||
}
|
}
|
||||||
return this.visits;
|
return this.visits;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setVisitsInternal(Set<Visit> visits) {
|
protected void setVisitsInternal(Collection<Visit> visits) {
|
||||||
this.visits = visits;
|
this.visits = new LinkedHashSet<>(visits);
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void addVisit(Visit visit) {
|
public void addVisit(Visit visit) {
|
||||||
getVisitsInternal().add(visit);
|
getVisitsInternal().add(visit);
|
||||||
visit.setPetId(this.getId());
|
visit.setPetId(this.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2012-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* 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,
|
||||||
|
@ -15,21 +15,15 @@
|
||||||
*/
|
*/
|
||||||
package org.springframework.samples.petclinic.owner;
|
package org.springframework.samples.petclinic.owner;
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
import javax.validation.Valid;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.ModelMap;
|
import org.springframework.ui.ModelMap;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.validation.BindingResult;
|
import org.springframework.validation.BindingResult;
|
||||||
import org.springframework.web.bind.WebDataBinder;
|
import org.springframework.web.bind.WebDataBinder;
|
||||||
import org.springframework.web.bind.annotation.InitBinder;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import javax.validation.Valid;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import java.util.Collection;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
|
@ -40,77 +34,80 @@ import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
@RequestMapping("/owners/{ownerId}")
|
@RequestMapping("/owners/{ownerId}")
|
||||||
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 OwnerRepository owners;
|
|
||||||
|
|
||||||
@Autowired
|
private final PetRepository pets;
|
||||||
public PetController(PetRepository pets, OwnerRepository owners) {
|
|
||||||
this.pets = pets;
|
|
||||||
this.owners = owners;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ModelAttribute("types")
|
private final OwnerRepository owners;
|
||||||
public Collection<PetType> populatePetTypes() {
|
|
||||||
return this.pets.findPetTypes();
|
|
||||||
}
|
|
||||||
|
|
||||||
@ModelAttribute("owner")
|
public PetController(PetRepository pets, OwnerRepository owners) {
|
||||||
public Owner findOwner(@PathVariable("ownerId") int ownerId) {
|
this.pets = pets;
|
||||||
return this.owners.findById(ownerId);
|
this.owners = owners;
|
||||||
}
|
}
|
||||||
|
|
||||||
@InitBinder("owner")
|
@ModelAttribute("types")
|
||||||
public void initOwnerBinder(WebDataBinder dataBinder) {
|
public Collection<PetType> populatePetTypes() {
|
||||||
dataBinder.setDisallowedFields("id");
|
return this.pets.findPetTypes();
|
||||||
}
|
}
|
||||||
|
|
||||||
@InitBinder("pet")
|
@ModelAttribute("owner")
|
||||||
public void initPetBinder(WebDataBinder dataBinder) {
|
public Owner findOwner(@PathVariable("ownerId") int ownerId) {
|
||||||
dataBinder.setValidator(new PetValidator());
|
return this.owners.findById(ownerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(value = "/pets/new", method = RequestMethod.GET)
|
@InitBinder("owner")
|
||||||
public String initCreationForm(Owner owner, ModelMap model) {
|
public void initOwnerBinder(WebDataBinder dataBinder) {
|
||||||
Pet pet = new Pet();
|
dataBinder.setDisallowedFields("id");
|
||||||
owner.addPet(pet);
|
}
|
||||||
model.put("pet", pet);
|
|
||||||
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequestMapping(value = "/pets/new", method = RequestMethod.POST)
|
@InitBinder("pet")
|
||||||
public String processCreationForm(Owner owner, @Valid Pet pet, BindingResult result, ModelMap model) {
|
public void initPetBinder(WebDataBinder dataBinder) {
|
||||||
if (StringUtils.hasLength(pet.getName()) && pet.isNew() && owner.getPet(pet.getName(), true) != null){
|
dataBinder.setValidator(new PetValidator());
|
||||||
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}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequestMapping(value = "/pets/{petId}/edit", method = RequestMethod.GET)
|
@GetMapping("/pets/new")
|
||||||
public String initUpdateForm(@PathVariable("petId") int petId, ModelMap model) {
|
public String initCreationForm(Owner owner, ModelMap model) {
|
||||||
Pet pet = this.pets.findById(petId);
|
Pet pet = new Pet();
|
||||||
model.put("pet", pet);
|
owner.addPet(pet);
|
||||||
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
|
model.put("pet", pet);
|
||||||
}
|
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
|
||||||
|
}
|
||||||
|
|
||||||
@RequestMapping(value = "/pets/{petId}/edit", method = RequestMethod.POST)
|
@PostMapping("/pets/new")
|
||||||
public String processUpdateForm(@Valid Pet pet, BindingResult result, Owner owner, ModelMap model) {
|
public String processCreationForm(Owner owner, @Valid Pet pet, BindingResult result, ModelMap model) {
|
||||||
if (result.hasErrors()) {
|
if (StringUtils.hasLength(pet.getName()) && pet.isNew() && owner.getPet(pet.getName(), true) != null) {
|
||||||
pet.setOwner(owner);
|
result.rejectValue("name", "duplicate", "already exists");
|
||||||
model.put("pet", pet);
|
}
|
||||||
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
|
owner.addPet(pet);
|
||||||
} else {
|
if (result.hasErrors()) {
|
||||||
owner.addPet(pet);
|
model.put("pet", pet);
|
||||||
this.pets.save(pet);
|
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
|
||||||
return "redirect:/owners/{ownerId}";
|
}
|
||||||
}
|
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}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2012-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* 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,
|
||||||
|
@ -22,8 +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 See here: http://static.springsource.org/spring-data/jpa/docs/current/reference/html/jpa.repositories.html#jpa.query-methods.query-creation
|
* 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 Ken Krebs
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
|
@ -32,27 +34,26 @@ import org.springframework.transaction.annotation.Transactional;
|
||||||
*/
|
*/
|
||||||
public interface PetRepository extends Repository<Pet, Integer> {
|
public interface PetRepository extends Repository<Pet, Integer> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve all {@link PetType}s from the data store.
|
* Retrieve all {@link PetType}s from the data store.
|
||||||
* @return a Collection of {@link PetType}s.
|
* @return a Collection of {@link PetType}s.
|
||||||
*/
|
*/
|
||||||
@Query("SELECT ptype FROM PetType ptype ORDER BY ptype.name")
|
@Query("SELECT ptype FROM PetType ptype ORDER BY ptype.name")
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
List<PetType> findPetTypes();
|
List<PetType> findPetTypes();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve a {@link Pet} from the data store by id.
|
* Retrieve a {@link Pet} from the data store by id.
|
||||||
* @param id the id to search for
|
* @param id the id to search for
|
||||||
* @return the {@link Pet} if found
|
* @return the {@link Pet} if found
|
||||||
*/
|
*/
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
Pet findById(Integer id);
|
Pet findById(Integer id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save a {@link Pet} to the data store, either inserting or updating it.
|
* Save a {@link Pet} to the data store, either inserting or updating it.
|
||||||
* @param pet the {@link Pet} to save
|
* @param pet the {@link Pet} to save
|
||||||
*/
|
*/
|
||||||
void save(Pet pet);
|
void save(Pet pet);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2012-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* 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,
|
||||||
|
@ -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")
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2012-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* 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,
|
||||||
|
@ -15,7 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package org.springframework.samples.petclinic.owner;
|
package org.springframework.samples.petclinic.owner;
|
||||||
|
|
||||||
|
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
@ -25,11 +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: http://static.springsource.org/spring/docs/current/spring-framework-reference/html/validation.html#format-Formatter-SPI
|
* PropertyEditors. See the following links for more details: - The Spring ref doc:
|
||||||
* - A nice blog entry from Gordon Dickens: http://gordondickens.com/wordpress/2010/09/30/using-spring-3-0-custom-type-converter/
|
* https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#format
|
||||||
* <p/>
|
|
||||||
*
|
*
|
||||||
* @author Mark Fisher
|
* @author Mark Fisher
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
|
@ -38,28 +36,27 @@ import org.springframework.stereotype.Component;
|
||||||
@Component
|
@Component
|
||||||
public class PetTypeFormatter implements Formatter<PetType> {
|
public class PetTypeFormatter implements Formatter<PetType> {
|
||||||
|
|
||||||
private final PetRepository pets;
|
private final PetRepository pets;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public PetTypeFormatter(PetRepository pets) {
|
||||||
|
this.pets = pets;
|
||||||
|
}
|
||||||
|
|
||||||
@Autowired
|
@Override
|
||||||
public PetTypeFormatter(PetRepository pets) {
|
public String print(PetType petType, Locale locale) {
|
||||||
this.pets = pets;
|
return petType.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String print(PetType petType, Locale locale) {
|
public PetType parse(String text, Locale locale) throws ParseException {
|
||||||
return petType.getName();
|
Collection<PetType> findPetTypes = this.pets.findPetTypes();
|
||||||
}
|
for (PetType type : findPetTypes) {
|
||||||
|
if (type.getName().equals(text)) {
|
||||||
@Override
|
return type;
|
||||||
public PetType parse(String text, Locale locale) throws ParseException {
|
}
|
||||||
Collection<PetType> findPetTypes = this.pets.findPetTypes();
|
}
|
||||||
for (PetType type : findPetTypes) {
|
throw new ParseException("type not found: " + text, 0);
|
||||||
if (type.getName().equals(text)) {
|
}
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new ParseException("type not found: " + text, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2012-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* 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,
|
||||||
|
@ -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
|
||||||
|
@ -30,35 +31,34 @@ import org.springframework.validation.Validator;
|
||||||
*/
|
*/
|
||||||
public class PetValidator implements Validator {
|
public class PetValidator implements Validator {
|
||||||
|
|
||||||
private static final String REQUIRED = "required";
|
private static final String REQUIRED = "required";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validate(Object obj, Errors errors) {
|
public void validate(Object obj, Errors errors) {
|
||||||
Pet pet = (Pet) obj;
|
Pet pet = (Pet) obj;
|
||||||
String name = pet.getName();
|
String name = pet.getName();
|
||||||
// name validation
|
// name validation
|
||||||
if (!StringUtils.hasLength(name)) {
|
if (!StringUtils.hasLength(name)) {
|
||||||
errors.rejectValue("name", REQUIRED, REQUIRED);
|
errors.rejectValue("name", REQUIRED, REQUIRED);
|
||||||
}
|
}
|
||||||
|
|
||||||
// type validation
|
// type validation
|
||||||
if (pet.isNew() && pet.getType() == null) {
|
if (pet.isNew() && pet.getType() == null) {
|
||||||
errors.rejectValue("type", REQUIRED, REQUIRED);
|
errors.rejectValue("type", REQUIRED, REQUIRED);
|
||||||
}
|
}
|
||||||
|
|
||||||
// birth date validation
|
// birth date validation
|
||||||
if (pet.getBirthDate() == null) {
|
if (pet.getBirthDate() == null) {
|
||||||
errors.rejectValue("birthDate", REQUIRED, REQUIRED);
|
errors.rejectValue("birthDate", REQUIRED, REQUIRED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This Validator validates *just* Pet instances
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean supports(Class<?> clazz) {
|
|
||||||
return Pet.class.isAssignableFrom(clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This Validator validates *just* Pet instances
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean supports(Class<?> clazz) {
|
||||||
|
return Pet.class.isAssignableFrom(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2012-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* 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,
|
||||||
|
@ -19,17 +19,16 @@ import java.util.Map;
|
||||||
|
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.samples.petclinic.visit.Visit;
|
import org.springframework.samples.petclinic.visit.Visit;
|
||||||
import org.springframework.samples.petclinic.visit.VisitRepository;
|
import org.springframework.samples.petclinic.visit.VisitRepository;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.validation.BindingResult;
|
import org.springframework.validation.BindingResult;
|
||||||
import org.springframework.web.bind.WebDataBinder;
|
import org.springframework.web.bind.WebDataBinder;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.InitBinder;
|
import org.springframework.web.bind.annotation.InitBinder;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
|
@ -41,55 +40,53 @@ import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
@Controller
|
@Controller
|
||||||
class VisitController {
|
class VisitController {
|
||||||
|
|
||||||
private final VisitRepository visits;
|
private final VisitRepository visits;
|
||||||
private final PetRepository pets;
|
|
||||||
|
|
||||||
|
private final PetRepository pets;
|
||||||
|
|
||||||
@Autowired
|
public VisitController(VisitRepository visits, PetRepository pets) {
|
||||||
public VisitController(VisitRepository visits, PetRepository pets) {
|
this.visits = visits;
|
||||||
this.visits = visits;
|
this.pets = pets;
|
||||||
this.pets = pets;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@InitBinder
|
@InitBinder
|
||||||
public void setAllowedFields(WebDataBinder dataBinder) {
|
public void setAllowedFields(WebDataBinder dataBinder) {
|
||||||
dataBinder.setDisallowedFields("id");
|
dataBinder.setDisallowedFields("id");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
* @param petId
|
||||||
* (Even though id is not part of the form fields)
|
* @return Pet
|
||||||
*
|
*/
|
||||||
* @param petId
|
@ModelAttribute("visit")
|
||||||
* @return Pet
|
public Visit loadPetWithVisit(@PathVariable("petId") int petId, Map<String, Object> model) {
|
||||||
*/
|
Pet pet = this.pets.findById(petId);
|
||||||
@ModelAttribute("visit")
|
pet.setVisitsInternal(this.visits.findByPetId(petId));
|
||||||
public Visit loadPetWithVisit(@PathVariable("petId") int petId, Map<String, Object> model) {
|
model.put("pet", pet);
|
||||||
Pet pet = this.pets.findById(petId);
|
Visit visit = new Visit();
|
||||||
model.put("pet", pet);
|
pet.addVisit(visit);
|
||||||
Visit visit = new Visit();
|
return visit;
|
||||||
pet.addVisit(visit);
|
}
|
||||||
return visit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Spring MVC calls method loadPetWithVisit(...) before initNewVisitForm is called
|
// Spring MVC calls method loadPetWithVisit(...) before initNewVisitForm is called
|
||||||
@RequestMapping(value = "/owners/*/pets/{petId}/visits/new", method = RequestMethod.GET)
|
@GetMapping("/owners/*/pets/{petId}/visits/new")
|
||||||
public String initNewVisitForm(@PathVariable("petId") int petId, Map<String, Object> model) {
|
public String initNewVisitForm(@PathVariable("petId") int petId, Map<String, Object> model) {
|
||||||
return "pets/createOrUpdateVisitForm";
|
return "pets/createOrUpdateVisitForm";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spring MVC calls method loadPetWithVisit(...) before processNewVisitForm is called
|
// Spring MVC calls method loadPetWithVisit(...) before processNewVisitForm is called
|
||||||
@RequestMapping(value = "/owners/{ownerId}/pets/{petId}/visits/new", method = RequestMethod.POST)
|
@PostMapping("/owners/{ownerId}/pets/{petId}/visits/new")
|
||||||
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 {
|
}
|
||||||
this.visits.save(visit);
|
else {
|
||||||
return "redirect:/owners/{ownerId}";
|
this.visits.save(visit);
|
||||||
}
|
return "redirect:/owners/{ownerId}";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
package org.springframework.samples.petclinic.system;
|
|
||||||
|
|
||||||
import javax.cache.configuration.Configuration;
|
|
||||||
import javax.cache.configuration.MutableConfiguration;
|
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer;
|
|
||||||
import org.springframework.cache.annotation.EnableCaching;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Profile;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cache could be disabled in unit test.
|
|
||||||
*/
|
|
||||||
@org.springframework.context.annotation.Configuration
|
|
||||||
@EnableCaching
|
|
||||||
@Profile("production")
|
|
||||||
class CacheConfig {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public JCacheManagerCustomizer cacheManagerCustomizer() {
|
|
||||||
return cm -> {
|
|
||||||
Configuration<Object, Object> cacheConfiguration = createCacheConfiguration();
|
|
||||||
cm.createCache("vets", cacheConfiguration);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private Configuration<Object, Object> createCacheConfiguration() {
|
|
||||||
// Create a cache using infinite heap. A real application will want to use an
|
|
||||||
// implementation dependent configuration that will better fit your needs
|
|
||||||
return new MutableConfiguration<>().setStatisticsEnabled(true);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2019 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.samples.petclinic.system;
|
||||||
|
|
||||||
|
import javax.cache.configuration.MutableConfiguration;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer;
|
||||||
|
import org.springframework.cache.annotation.EnableCaching;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache configuration intended for caches providing the JCache API. This configuration
|
||||||
|
* creates the used cache for the application and enables statistics that become
|
||||||
|
* accessible via JMX.
|
||||||
|
*/
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
@EnableCaching
|
||||||
|
class CacheConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public JCacheManagerCustomizer petclinicCacheConfigurationCustomizer() {
|
||||||
|
return cm -> {
|
||||||
|
cm.createCache("vets", cacheConfiguration());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a simple configuration that enable statistics via the JCache programmatic
|
||||||
|
* configuration API.
|
||||||
|
* <p>
|
||||||
|
* 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<Object, Object> cacheConfiguration() {
|
||||||
|
return new MutableConfiguration<>().setStatisticsEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,11 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2012-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* 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,
|
||||||
|
@ -16,8 +16,7 @@
|
||||||
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.RequestMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller used to showcase what happens when an exception is thrown
|
* Controller used to showcase what happens when an exception is thrown
|
||||||
|
@ -29,10 +28,10 @@ import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
@Controller
|
@Controller
|
||||||
class CrashController {
|
class CrashController {
|
||||||
|
|
||||||
@RequestMapping(value = "/oups", method = RequestMethod.GET)
|
@GetMapping("/oups")
|
||||||
public String triggerException() {
|
public String triggerException() {
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
"Expected: controller used to showcase what " + "happens when an exception is thrown");
|
"Expected: controller used to showcase what " + "happens when an exception is thrown");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,30 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2019 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package org.springframework.samples.petclinic.system;
|
package org.springframework.samples.petclinic.system;
|
||||||
|
|
||||||
|
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
class WelcomeController {
|
class WelcomeController {
|
||||||
|
|
||||||
@RequestMapping("/")
|
@GetMapping("/")
|
||||||
public String welcome() {
|
public String welcome() {
|
||||||
return "welcome";
|
return "welcome";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2012-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* 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,
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2012-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* 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,
|
||||||
|
@ -45,35 +45,35 @@ import org.springframework.samples.petclinic.model.Person;
|
||||||
@Table(name = "vets")
|
@Table(name = "vets")
|
||||||
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"),
|
||||||
private Set<Specialty> specialties;
|
inverseJoinColumns = @JoinColumn(name = "specialty_id"))
|
||||||
|
private Set<Specialty> specialties;
|
||||||
|
|
||||||
protected Set<Specialty> getSpecialtiesInternal() {
|
protected Set<Specialty> getSpecialtiesInternal() {
|
||||||
if (this.specialties == null) {
|
if (this.specialties == null) {
|
||||||
this.specialties = new HashSet<>();
|
this.specialties = new HashSet<>();
|
||||||
}
|
}
|
||||||
return this.specialties;
|
return this.specialties;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setSpecialtiesInternal(Set<Specialty> specialties) {
|
protected void setSpecialtiesInternal(Set<Specialty> specialties) {
|
||||||
this.specialties = specialties;
|
this.specialties = specialties;
|
||||||
}
|
}
|
||||||
|
|
||||||
@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);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public int getNrOfSpecialties() {
|
public int getNrOfSpecialties() {
|
||||||
return getSpecialtiesInternal().size();
|
return getSpecialtiesInternal().size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addSpecialty(Specialty specialty) {
|
public void addSpecialty(Specialty specialty) {
|
||||||
getSpecialtiesInternal().add(specialty);
|
getSpecialtiesInternal().add(specialty);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2012-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* 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,
|
||||||
|
@ -15,13 +15,12 @@
|
||||||
*/
|
*/
|
||||||
package org.springframework.samples.petclinic.vet;
|
package org.springframework.samples.petclinic.vet;
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
* @author Mark Fisher
|
* @author Mark Fisher
|
||||||
|
@ -31,30 +30,29 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
@Controller
|
@Controller
|
||||||
class VetController {
|
class VetController {
|
||||||
|
|
||||||
private final VetRepository vets;
|
private final VetRepository vets;
|
||||||
|
|
||||||
@Autowired
|
public VetController(VetRepository clinicService) {
|
||||||
public VetController(VetRepository clinicService) {
|
this.vets = clinicService;
|
||||||
this.vets = clinicService;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@RequestMapping(value = { "/vets.html" })
|
@GetMapping("/vets.html")
|
||||||
public String showVetList(Map<String, Object> model) {
|
public String showVetList(Map<String, Object> model) {
|
||||||
// Here we are returning an object of type 'Vets' rather than a collection of Vet
|
// Here we are returning an object of type 'Vets' rather than a collection of Vet
|
||||||
// objects so it is simpler for Object-Xml mapping
|
// objects so it is simpler for Object-Xml mapping
|
||||||
Vets vets = new Vets();
|
Vets vets = new Vets();
|
||||||
vets.getVetList().addAll(this.vets.findAll());
|
vets.getVetList().addAll(this.vets.findAll());
|
||||||
model.put("vets", vets);
|
model.put("vets", vets);
|
||||||
return "vets/vetList";
|
return "vets/vetList";
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(value = { "/vets.json", "/vets.xml" })
|
@GetMapping({ "/vets" })
|
||||||
public @ResponseBody Vets showResourcesVetList() {
|
public @ResponseBody Vets showResourcesVetList() {
|
||||||
// Here we are returning an object of type 'Vets' rather than a collection of Vet
|
// Here we are returning an object of type 'Vets' rather than a collection of Vet
|
||||||
// objects so it is simpler for JSon/Object mapping
|
// objects so it is simpler for JSon/Object mapping
|
||||||
Vets vets = new Vets();
|
Vets vets = new Vets();
|
||||||
vets.getVetList().addAll(this.vets.findAll());
|
vets.getVetList().addAll(this.vets.findAll());
|
||||||
return vets;
|
return vets;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2012-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* 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,
|
||||||
|
@ -23,8 +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 See here: http://static.springsource.org/spring-data/jpa/docs/current/reference/html/jpa.repositories.html#jpa.query-methods.query-creation
|
* 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 Ken Krebs
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
|
@ -33,14 +35,12 @@ import org.springframework.transaction.annotation.Transactional;
|
||||||
*/
|
*/
|
||||||
public interface VetRepository extends Repository<Vet, Integer> {
|
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;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2012-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* 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,
|
||||||
|
@ -22,22 +22,22 @@ 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
|
||||||
*/
|
*/
|
||||||
@XmlRootElement
|
@XmlRootElement
|
||||||
public class Vets {
|
public class Vets {
|
||||||
|
|
||||||
private List<Vet> vets;
|
private List<Vet> vets;
|
||||||
|
|
||||||
@XmlElement
|
@XmlElement
|
||||||
public List<Vet> getVetList() {
|
public List<Vet> getVetList() {
|
||||||
if (vets == null) {
|
if (vets == null) {
|
||||||
vets = new ArrayList<>();
|
vets = new ArrayList<>();
|
||||||
}
|
}
|
||||||
return vets;
|
return vets;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2012-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* 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,
|
||||||
|
@ -15,15 +15,13 @@
|
||||||
*/
|
*/
|
||||||
package org.springframework.samples.petclinic.visit;
|
package org.springframework.samples.petclinic.visit;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.LocalDate;
|
||||||
|
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
import javax.persistence.Temporal;
|
import javax.validation.constraints.NotEmpty;
|
||||||
import javax.persistence.TemporalType;
|
|
||||||
|
|
||||||
import org.hibernate.validator.constraints.NotEmpty;
|
|
||||||
import org.springframework.format.annotation.DateTimeFormat;
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
import org.springframework.samples.petclinic.model.BaseEntity;
|
import org.springframework.samples.petclinic.model.BaseEntity;
|
||||||
|
|
||||||
|
@ -37,88 +35,46 @@ import org.springframework.samples.petclinic.model.BaseEntity;
|
||||||
@Table(name = "visits")
|
@Table(name = "visits")
|
||||||
public class Visit extends BaseEntity {
|
public class Visit extends BaseEntity {
|
||||||
|
|
||||||
/**
|
@Column(name = "visit_date")
|
||||||
* Holds value of property date.
|
@DateTimeFormat(pattern = "yyyy-MM-dd")
|
||||||
*/
|
private LocalDate date;
|
||||||
@Column(name = "visit_date")
|
|
||||||
@Temporal(TemporalType.TIMESTAMP)
|
|
||||||
@DateTimeFormat(pattern = "yyyy/MM/dd")
|
|
||||||
private Date date;
|
|
||||||
|
|
||||||
/**
|
@NotEmpty
|
||||||
* Holds value of property description.
|
@Column(name = "description")
|
||||||
*/
|
private String description;
|
||||||
@NotEmpty
|
|
||||||
@Column(name = "description")
|
|
||||||
private String description;
|
|
||||||
|
|
||||||
/**
|
@Column(name = "pet_id")
|
||||||
* Holds value of property pet.
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
public LocalDate getDate() {
|
||||||
* Creates a new instance of Visit for the current date
|
return this.date;
|
||||||
*/
|
}
|
||||||
public Visit() {
|
|
||||||
this.date = new Date();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public void setDate(LocalDate date) {
|
||||||
|
this.date = date;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
public String getDescription() {
|
||||||
* Getter for property date.
|
return this.description;
|
||||||
*
|
}
|
||||||
* @return Value of property date.
|
|
||||||
*/
|
|
||||||
public Date getDate() {
|
|
||||||
return this.date;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
public void setDescription(String description) {
|
||||||
* Setter for property date.
|
this.description = description;
|
||||||
*
|
}
|
||||||
* @param date New value of property date.
|
|
||||||
*/
|
|
||||||
public void setDate(Date date) {
|
|
||||||
this.date = date;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
public Integer getPetId() {
|
||||||
* Getter for property description.
|
return this.petId;
|
||||||
*
|
}
|
||||||
* @return Value of property description.
|
|
||||||
*/
|
|
||||||
public String getDescription() {
|
|
||||||
return this.description;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
public void setPetId(Integer petId) {
|
||||||
* Setter for property description.
|
this.petId = petId;
|
||||||
*
|
}
|
||||||
* @param description New value of property description.
|
|
||||||
*/
|
|
||||||
public void setDescription(String description) {
|
|
||||||
this.description = description;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Getter for property pet id.
|
|
||||||
*
|
|
||||||
* @return Value of property pet id.
|
|
||||||
*/
|
|
||||||
public Integer getPetId() {
|
|
||||||
return this.petId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Setter for property pet id.
|
|
||||||
*
|
|
||||||
* @param petId New value of property pet id.
|
|
||||||
*/
|
|
||||||
public void setPetId(Integer petId) {
|
|
||||||
this.petId = petId;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2012-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* 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,
|
||||||
|
@ -22,8 +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 See here: http://static.springsource.org/spring-data/jpa/docs/current/reference/html/jpa.repositories.html#jpa.query-methods.query-creation
|
* 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 Ken Krebs
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
|
@ -32,14 +34,13 @@ import org.springframework.samples.petclinic.model.BaseEntity;
|
||||||
*/
|
*/
|
||||||
public interface VisitRepository extends Repository<Visit, Integer> {
|
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
|
*/
|
||||||
*/
|
void save(Visit visit) throws DataAccessException;
|
||||||
void save(Visit visit) throws DataAccessException;
|
|
||||||
|
|
||||||
List<Visit> findByPetId(Integer petId);
|
List<Visit> findByPetId(Integer petId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* 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,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# database init, supports mysql too
|
# database init, supports mysql too
|
||||||
database=mysql
|
database=mysql
|
||||||
spring.datasource.url=jdbc:mysql://localhost/test
|
spring.datasource.url=${MYSQL_URL:jdbc:mysql://localhost/petclinic}
|
||||||
spring.datasource.username=root
|
spring.datasource.username=${MYSQL_USER:petclinic}
|
||||||
spring.datasource.password=root
|
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.initialize=true
|
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,19 +8,18 @@ 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.contextPath=/manage
|
management.endpoints.web.exposure.include=*
|
||||||
# Spring Boot 1.5 makes actuator secure by default
|
|
||||||
management.security.enabled=false
|
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
logging.level.org.springframework=INFO
|
logging.level.org.springframework=INFO
|
||||||
# logging.level.org.springframework.web=DEBUG
|
# logging.level.org.springframework.web=DEBUG
|
||||||
# logging.level.org.springframework.context.annotation=TRACE
|
# logging.level.org.springframework.context.annotation=TRACE
|
||||||
|
|
||||||
# Active Spring profiles
|
# Maximum time static resources should be cached
|
||||||
spring.profiles.active=production
|
spring.resources.cache.cachecontrol.max-age=12h
|
||||||
|
|
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);
|
|
@ -9,9 +9,24 @@
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
1) Download and install the MySQL database (e.g., MySQL Community Server 5.1.x),
|
1) Download and install the MySQL database (e.g., MySQL Community Server 5.1.x),
|
||||||
which can be found here: http://dev.mysql.com/downloads/. Or run the
|
which can be found here: https://dev.mysql.com/downloads/. Or run the
|
||||||
"docker-compose.yml" from the root of the project (if you have docker installed
|
"docker-compose.yml" from the root of the project (if you have docker installed
|
||||||
locally).
|
locally):
|
||||||
|
|
||||||
2) Create the PetClinic database and user by executing the "db/mysql/{schema,data}.sql"
|
$ docker-compose up
|
||||||
scripts (or set "spring.datasource.initialize=true" the first time you run the app).
|
...
|
||||||
|
mysql_1_eedb4818d817 | MySQL init process done. Ready for start up.
|
||||||
|
...
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
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 automatically by the
|
||||||
|
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
|
|
@ -1,6 +1,6 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
|
||||||
<html xmlns:th="http://www.thymeleaf.org" th:replace="~{fragments/layout :: layout (~{::body},'error')}">
|
<html xmlns:th="https://www.thymeleaf.org" th:replace="~{fragments/layout :: layout (~{::body},'error')}">
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<img src="../static/resources/images/pets.png" th:src="@{/resources/images/pets.png}"/>
|
<img src="../static/resources/images/pets.png" th:src="@{/resources/images/pets.png}"/>
|
||||||
|
|
|
@ -1,14 +1,18 @@
|
||||||
<html>
|
<html>
|
||||||
<body>
|
<body>
|
||||||
<form>
|
<form>
|
||||||
<th:block th:fragment="input (label, name)">
|
<th:block th:fragment="input (label, name, type)">
|
||||||
<div th:with="valid=${!#fields.hasErrors(name)}"
|
<div th:with="valid=${!#fields.hasErrors(name)}"
|
||||||
th:class="${'form-group' + (valid ? '' : ' has-error')}"
|
th:class="${'form-group' + (valid ? '' : ' has-error')}"
|
||||||
class="form-group">
|
class="form-group">
|
||||||
<label class="col-sm-2 control-label" th:text="${label}">Label</label>
|
<label class="col-sm-2 control-label" th:text="${label}">Label</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<input class="form-control" type="text"
|
<div th:switch="${type}">
|
||||||
th:field="*{__${name}__}" />
|
<input th:case="'text'" class="form-control" type="text" th:field="*{__${name}__}" />
|
||||||
|
<input th:case="'date'" class="form-control" type="text" th:field="*{__${name}__}"
|
||||||
|
placeholder="YYYY-MM-DD" title="Enter a date in this format: YYYY-MM-DD"
|
||||||
|
pattern="(?:19|20)[0-9]{2}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-9])|(?:(?!02)(?:0[1-9]|1[0-2])-(?:30))|(?:(?:0[13578]|1[02])-31))"/>
|
||||||
|
</div>
|
||||||
<span th:if="${valid}"
|
<span th:if="${valid}"
|
||||||
class="glyphicon glyphicon-ok form-control-feedback"
|
class="glyphicon glyphicon-ok form-control-feedback"
|
||||||
aria-hidden="true"></span>
|
aria-hidden="true"></span>
|
||||||
|
|
|
@ -1,88 +1,98 @@
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html th:fragment="layout (template, menu)">
|
<html th:fragment="layout (template, menu)">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
<link rel="shortcut icon" type="image/x-icon" th:href="@{/resources/images/favicon.png}">
|
<link rel="shortcut icon" type="image/x-icon" th:href="@{/resources/images/favicon.png}">
|
||||||
|
|
||||||
<title>PetClinic :: a Spring Framework demonstration</title>
|
<title>PetClinic :: a Spring Framework demonstration</title>
|
||||||
|
|
||||||
<!--[if lt IE 9]>
|
<!--[if lt IE 9]>
|
||||||
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
|
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
|
||||||
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
||||||
<![endif]-->
|
<![endif]-->
|
||||||
|
|
||||||
<link rel="stylesheet" th:href="@{/resources/css/petclinic.css}"/>
|
<link rel="stylesheet" th:href="@{/resources/css/petclinic.css}" />
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<nav class="navbar navbar-default" role="navigation">
|
<nav class="navbar navbar-default" role="navigation">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="navbar-header">
|
<div class="navbar-header">
|
||||||
<a class="navbar-brand" th:href="@{/}"><span></span></a>
|
<a class="navbar-brand" th:href="@{/}"><span></span></a>
|
||||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#main-navbar">
|
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#main-navbar">
|
||||||
<span class="sr-only"><os-p>Toggle navigation</os-p></span>
|
<span class="sr-only">
|
||||||
<span class="icon-bar"></span>
|
<os-p>Toggle navigation</os-p>
|
||||||
<span class="icon-bar"></span>
|
</span>
|
||||||
<span class="icon-bar"></span>
|
<span class="icon-bar"></span>
|
||||||
</button>
|
<span class="icon-bar"></span>
|
||||||
</div>
|
<span class="icon-bar"></span>
|
||||||
<div class="navbar-collapse collapse" id="main-navbar">
|
</button>
|
||||||
<ul class="nav navbar-nav navbar-right">
|
|
||||||
|
|
||||||
<li th:fragment="menuItem (path,active,title,glyph,text)" class="active" th:class="${active==menu ? 'active' : ''}">
|
|
||||||
<a th:href="@{__${path}__}" th:title="${title}">
|
|
||||||
<span th:class="'glyphicon glyphicon-'+${glyph}" class="glyphicon glyphicon-home" aria-hidden="true"></span>
|
|
||||||
<span th:text="${text}">Template</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li th:replace="::menuItem ('/','home','home page','home','Home')">
|
|
||||||
<span class="glyphicon glyphicon-home" aria-hidden="true"></span>
|
|
||||||
<span>Home</span>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li th:replace="::menuItem ('/owners/find','owners','find owners','search','Find owners')">
|
|
||||||
<span class="glyphicon glyphicon-search" aria-hidden="true"></span>
|
|
||||||
<span>Find owners</span>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li th:replace="::menuItem ('/vets.html','vets','veterinarians','th-list','Veterinarians')">
|
|
||||||
<span class="glyphicon glyphicon-th-list" aria-hidden="true"></span>
|
|
||||||
<span>Veterinarians</span>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li th:replace="::menuItem ('/oups','error','trigger a RuntimeException to see how it is handled','warning-sign','Error')">
|
|
||||||
<span class="glyphicon glyphicon-warning-sign" aria-hidden="true"></span>
|
|
||||||
<span>Error</span>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="navbar-collapse collapse" id="main-navbar">
|
||||||
|
|
||||||
|
<ul class="nav navbar-nav navbar-right" th:remove="all">
|
||||||
|
|
||||||
|
<li th:fragment="menuItem (link,active,title,glyph,text)" class="active"
|
||||||
|
th:class="${active==menu ? 'active' : ''}">
|
||||||
|
<a th:href="@{__${link}__}" th:title="${title}">
|
||||||
|
<span th:class="'glyphicon glyphicon-'+${glyph}" class="glyphicon glyphicon-home"
|
||||||
|
aria-hidden="true"></span>
|
||||||
|
<span th:text="${text}">Template</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<ul class="nav navbar-nav navbar-right">
|
||||||
|
|
||||||
|
<li th:replace="::menuItem ('/','home','home page','home','Home')">
|
||||||
|
<span class="glyphicon glyphicon-home" aria-hidden="true"></span>
|
||||||
|
<span>Home</span>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li th:replace="::menuItem ('/owners/find','owners','find owners','search','Find owners')">
|
||||||
|
<span class="glyphicon glyphicon-search" aria-hidden="true"></span>
|
||||||
|
<span>Find owners</span>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li th:replace="::menuItem ('/vets.html','vets','veterinarians','th-list','Veterinarians')">
|
||||||
|
<span class="glyphicon glyphicon-th-list" aria-hidden="true"></span>
|
||||||
|
<span>Veterinarians</span>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li
|
||||||
|
th:replace="::menuItem ('/oups','error','trigger a RuntimeException to see how it is handled','warning-sign','Error')">
|
||||||
|
<span class="glyphicon glyphicon-warning-sign" aria-hidden="true"></span>
|
||||||
|
<span>Error</span>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="container xd-container">
|
<div class="container xd-container">
|
||||||
|
|
||||||
<div th:replace="${template}"/>
|
<th:block th:include="${template}" />
|
||||||
|
|
||||||
<br/>
|
<br />
|
||||||
<br/>
|
<br />
|
||||||
<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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script th:src="@{/webjars/jquery/jquery.min.js}"></script>
|
<script th:src="@{/webjars/jquery/jquery.min.js}"></script>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<html xmlns:th="http://www.thymeleaf.org"
|
<html xmlns:th="https://www.thymeleaf.org"
|
||||||
th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
|
th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
@ -7,15 +7,15 @@
|
||||||
<form th:object="${owner}" class="form-horizontal" id="add-owner-form" method="post">
|
<form th:object="${owner}" class="form-horizontal" id="add-owner-form" method="post">
|
||||||
<div class="form-group has-feedback">
|
<div class="form-group has-feedback">
|
||||||
<input
|
<input
|
||||||
th:replace="~{fragments/inputField :: input ('First Name', 'firstName')}" />
|
th:replace="~{fragments/inputField :: input ('First Name', 'firstName', 'text')}" />
|
||||||
<input
|
<input
|
||||||
th:replace="~{fragments/inputField :: input ('Last Name', 'lastName')}" />
|
th:replace="~{fragments/inputField :: input ('Last Name', 'lastName', 'text')}" />
|
||||||
<input
|
<input
|
||||||
th:replace="~{fragments/inputField :: input ('Address', 'address')}" />
|
th:replace="~{fragments/inputField :: input ('Address', 'address', 'text')}" />
|
||||||
<input
|
<input
|
||||||
th:replace="~{fragments/inputField :: input ('City', 'city')}" />
|
th:replace="~{fragments/inputField :: input ('City', 'city', 'text')}" />
|
||||||
<input
|
<input
|
||||||
th:replace="~{fragments/inputField :: input ('Telephone', 'telephone')}" />
|
th:replace="~{fragments/inputField :: input ('Telephone', 'telephone', 'text')}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-sm-offset-2 col-sm-10">
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<html xmlns:th="http://www.thymeleaf.org"
|
<html xmlns:th="https://www.thymeleaf.org"
|
||||||
th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
|
th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
@ -8,7 +8,7 @@
|
||||||
<form th:object="${owner}" th:action="@{/owners}" method="get"
|
<form th:object="${owner}" th:action="@{/owners}" method="get"
|
||||||
class="form-horizontal" id="search-owner-form">
|
class="form-horizontal" id="search-owner-form">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="control-group" id="lastName">
|
<div class="control-group" id="lastNameGroup">
|
||||||
<label class="col-sm-2 control-label">Last name </label>
|
<label class="col-sm-2 control-label">Last name </label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<input class="form-control" th:field="*{lastName}" size="30"
|
<input class="form-control" th:field="*{lastName}" size="30"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
|
||||||
<html xmlns:th="http://www.thymeleaf.org"
|
<html xmlns:th="https://www.thymeleaf.org"
|
||||||
th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
|
th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
@ -16,15 +16,15 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Address</th>
|
<th>Address</th>
|
||||||
<td th:text="*{address}" /></td>
|
<td th:text="*{address}"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>City</th>
|
<th>City</th>
|
||||||
<td th:text="*{city}" /></td>
|
<td th:text="*{city}"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Telephone</th>
|
<th>Telephone</th>
|
||||||
<td th:text="*{telephone}" /></td>
|
<td th:text="*{telephone}"></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
@ -44,12 +44,12 @@
|
||||||
<td valign="top">
|
<td valign="top">
|
||||||
<dl class="dl-horizontal">
|
<dl class="dl-horizontal">
|
||||||
<dt>Name</dt>
|
<dt>Name</dt>
|
||||||
<dd th:text="${pet.name}" /></dd>
|
<dd th:text="${pet.name}"></dd>
|
||||||
<dt>Birth Date</dt>
|
<dt>Birth Date</dt>
|
||||||
<dd
|
<dd
|
||||||
th:text="${#calendars.format(pet.birthDate, 'yyyy-MM-dd')}" /></dd>
|
th:text="${#temporals.format(pet.birthDate, 'yyyy-MM-dd')}"></dd>
|
||||||
<dt>Type</dt>
|
<dt>Type</dt>
|
||||||
<dd th:text="${pet.type}" /></dd>
|
<dd th:text="${pet.type}"></dd>
|
||||||
</dl>
|
</dl>
|
||||||
</td>
|
</td>
|
||||||
<td valign="top">
|
<td valign="top">
|
||||||
|
@ -61,7 +61,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tr th:each="visit : ${pet.visits}">
|
<tr th:each="visit : ${pet.visits}">
|
||||||
<td th:text="${#calendars.format(visit.date, 'yyyy-MM-dd')}"></td>
|
<td th:text="${#temporals.format(visit.date, 'yyyy-MM-dd')}"></td>
|
||||||
<td th:text="${visit?.description}"></td>
|
<td th:text="${visit?.description}"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
|
||||||
<html xmlns:th="http://www.thymeleaf.org" th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
|
<html xmlns:th="https://www.thymeleaf.org" th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<h2>Owners</h2>
|
<h2>Owners</h2>
|
||||||
|
|
||||||
<table id="vets" class="table table-striped">
|
<table id="owners" class="table table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th style="width: 150px;">Name</th>
|
<th style="width: 150px;">Name</th>
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr th:each="owner : ${selections}">
|
<tr th:each="owner : ${selections}">
|
||||||
<td>
|
<td>
|
||||||
<a th:href="@{owners/__${owner.id}__}" th:text="${owner.firstName + ' ' + owner.lastName}"/></a>
|
<a th:href="@{/owners/__${owner.id}__}" th:text="${owner.firstName + ' ' + owner.lastName}"/></a>
|
||||||
</td>
|
</td>
|
||||||
<td th:text="${owner.address}"/>
|
<td th:text="${owner.address}"/>
|
||||||
<td th:text="${owner.city}"/>
|
<td th:text="${owner.city}"/>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<html xmlns:th="http://www.thymeleaf.org"
|
<html xmlns:th="https://www.thymeleaf.org"
|
||||||
th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
|
th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
@ -17,16 +17,16 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
th:replace="~{fragments/inputField :: input ('Name', 'name')}" />
|
th:replace="~{fragments/inputField :: input ('Name', 'name', 'text')}" />
|
||||||
<input
|
<input
|
||||||
th:replace="~{fragments/inputField :: input ('Birth Date', 'birthDate')}" />
|
th:replace="~{fragments/inputField :: input ('Birth Date', 'birthDate', 'date')}" />
|
||||||
<input
|
<input
|
||||||
th:replace="~{fragments/selectField :: select ('Type', 'type', ${types})}" />
|
th:replace="~{fragments/selectField :: select ('Type', 'type', ${types})}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-sm-offset-2 col-sm-10">
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
<button
|
<button
|
||||||
th:with="text=${owner['new']} ? 'Add Pet' : 'Update Pet'"
|
th:with="text=${pet['new']} ? 'Add Pet' : 'Update Pet'"
|
||||||
class="btn btn-default" type="submit" th:text="${text}">Add
|
class="btn btn-default" type="submit" th:text="${text}">Add
|
||||||
Pet</button>
|
Pet</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<html xmlns:th="http://www.thymeleaf.org"
|
<html xmlns:th="https://www.thymeleaf.org"
|
||||||
th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
|
th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
@ -19,21 +19,21 @@
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td th:text="${pet.name}" /></td>
|
<td th:text="${pet.name}"></td>
|
||||||
<td
|
<td
|
||||||
th:text="${#calendars.format(pet.birthDate, 'yyyy-MM-dd')}" /></td>
|
th:text="${#temporals.format(pet.birthDate, 'yyyy-MM-dd')}"></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>
|
||||||
|
|
||||||
<form th:object="${visit}" class="form-horizontal" method="post">
|
<form th:object="${visit}" class="form-horizontal" method="post">
|
||||||
<div class="form-group has-feedback">
|
<div class="form-group has-feedback">
|
||||||
<input
|
<input
|
||||||
th:replace="~{fragments/inputField :: input ('Date', 'date')}" />
|
th:replace="~{fragments/inputField :: input ('Date', 'date', 'date')}" />
|
||||||
<input
|
<input
|
||||||
th:replace="~{fragments/inputField :: input ('Description', 'description')}" />
|
th:replace="~{fragments/inputField :: input ('Description', 'description', 'text')}" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
@ -52,8 +52,8 @@
|
||||||
<th>Description</th>
|
<th>Description</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr th:if="${!visit['new']}" th:each="visit : ${pet.visits}">
|
<tr th:if="${!visit['new']}" th:each="visit : ${pet.visits}">
|
||||||
<td th:text="${#calendars.format(visit.date, 'yyyy-MM-dd')}" /></td>
|
<td th:text="${#temporals.format(visit.date, 'yyyy-MM-dd')}"></td>
|
||||||
<td th:text=" ${visit.description}" /></td>
|
<td th:text=" ${visit.description}"></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
|
||||||
<html xmlns:th="http://www.thymeleaf.org"
|
<html xmlns:th="https://www.thymeleaf.org"
|
||||||
th:replace="~{fragments/layout :: layout (~{::body},'vets')}">
|
th:replace="~{fragments/layout :: layout (~{::body},'vets')}">
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
@ -23,13 +23,5 @@
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<table class="table-buttons">
|
|
||||||
<tr>
|
|
||||||
<td><a th:href="@{/vets.xml}">View as XML</a></td>
|
|
||||||
<td><a th:href="@{/vets.json}">View as JSON</a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
|
||||||
<html xmlns:th="http://www.thymeleaf.org" th:replace="~{fragments/layout :: layout (~{::body},'home')}">
|
<html xmlns:th="https://www.thymeleaf.org" th:replace="~{fragments/layout :: layout (~{::body},'home')}">
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2019 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.samples.petclinic;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.samples.petclinic.vet.VetRepository;
|
||||||
|
|
||||||
|
@SpringBootTest
|
||||||
|
class PetclinicIntegrationTests {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private VetRepository vets;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFindAll() throws Exception {
|
||||||
|
vets.findAll();
|
||||||
|
vets.findAll(); // served from cache
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,6 +1,20 @@
|
||||||
package org.springframework.samples.petclinic.model;
|
/*
|
||||||
|
* Copyright 2012-2019 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
package org.springframework.samples.petclinic.model;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -8,38 +22,39 @@ import java.util.Set;
|
||||||
import javax.validation.ConstraintViolation;
|
import javax.validation.ConstraintViolation;
|
||||||
import javax.validation.Validator;
|
import javax.validation.Validator;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.context.i18n.LocaleContextHolder;
|
import org.springframework.context.i18n.LocaleContextHolder;
|
||||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Michael Isvy
|
* @author Michael Isvy Simple test to make sure that Bean Validation is working (useful
|
||||||
* Simple test to make sure that Bean Validation is working
|
* when upgrading to a new version of Hibernate Validator/ Bean Validation)
|
||||||
* (useful when upgrading to a new version of Hibernate Validator/ Bean Validation)
|
|
||||||
*/
|
*/
|
||||||
public class ValidatorTests {
|
class ValidatorTests {
|
||||||
|
|
||||||
private Validator createValidator() {
|
private Validator createValidator() {
|
||||||
LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
|
LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
|
||||||
localValidatorFactoryBean.afterPropertiesSet();
|
localValidatorFactoryBean.afterPropertiesSet();
|
||||||
return localValidatorFactoryBean;
|
return localValidatorFactoryBean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldNotValidateWhenFirstNameEmpty() {
|
void shouldNotValidateWhenFirstNameEmpty() {
|
||||||
|
|
||||||
LocaleContextHolder.setLocale(Locale.ENGLISH);
|
LocaleContextHolder.setLocale(Locale.ENGLISH);
|
||||||
Person person = new Person();
|
Person person = new Person();
|
||||||
person.setFirstName("");
|
person.setFirstName("");
|
||||||
person.setLastName("smith");
|
person.setLastName("smith");
|
||||||
|
|
||||||
Validator validator = createValidator();
|
Validator validator = createValidator();
|
||||||
Set<ConstraintViolation<Person>> constraintViolations = validator.validate(person);
|
Set<ConstraintViolation<Person>> constraintViolations = validator.validate(person);
|
||||||
|
|
||||||
assertThat(constraintViolations.size()).isEqualTo(1);
|
assertThat(constraintViolations).hasSize(1);
|
||||||
ConstraintViolation<Person> violation = constraintViolations.iterator().next();
|
ConstraintViolation<Person> violation = constraintViolations.iterator().next();
|
||||||
assertThat(violation.getPropertyPath().toString()).isEqualTo("firstName");
|
assertThat(violation.getPropertyPath().toString()).isEqualTo("firstName");
|
||||||
assertThat(violation.getMessage()).isEqualTo("may not be empty");
|
assertThat(violation.getMessage()).isEqualTo("must not be empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2019 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package org.springframework.samples.petclinic.owner;
|
package org.springframework.samples.petclinic.owner;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.assertj.core.util.Lists;
|
||||||
|
import org.hamcrest.BaseMatcher;
|
||||||
|
import org.hamcrest.Description;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||||
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
|
import org.springframework.samples.petclinic.visit.Visit;
|
||||||
|
import org.springframework.samples.petclinic.visit.VisitRepository;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.empty;
|
||||||
import static org.hamcrest.Matchers.hasProperty;
|
import static org.hamcrest.Matchers.hasProperty;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import static org.hamcrest.Matchers.not;
|
||||||
import static org.mockito.BDDMockito.given;
|
import static org.mockito.BDDMockito.given;
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||||
|
@ -9,171 +43,157 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
|
||||||
|
|
||||||
import org.assertj.core.util.Lists;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
|
||||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
|
||||||
import org.springframework.samples.petclinic.owner.Owner;
|
|
||||||
import org.springframework.samples.petclinic.owner.OwnerController;
|
|
||||||
import org.springframework.samples.petclinic.owner.OwnerRepository;
|
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test class for {@link OwnerController}
|
* Test class for {@link OwnerController}
|
||||||
*
|
*
|
||||||
* @author Colin But
|
* @author Colin But
|
||||||
*/
|
*/
|
||||||
@RunWith(SpringRunner.class)
|
|
||||||
@WebMvcTest(OwnerController.class)
|
@WebMvcTest(OwnerController.class)
|
||||||
public class OwnerControllerTests {
|
class OwnerControllerTests {
|
||||||
|
|
||||||
private static final int TEST_OWNER_ID = 1;
|
private static final int TEST_OWNER_ID = 1;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private MockMvc mockMvc;
|
private MockMvc mockMvc;
|
||||||
|
|
||||||
@MockBean
|
@MockBean
|
||||||
private OwnerRepository owners;
|
private OwnerRepository owners;
|
||||||
|
|
||||||
private Owner george;
|
@MockBean
|
||||||
|
private VisitRepository visits;
|
||||||
|
|
||||||
@Before
|
private Owner george;
|
||||||
public 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");
|
|
||||||
given(this.owners.findById(TEST_OWNER_ID)).willReturn(george);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@BeforeEach
|
||||||
public void testInitCreationForm() throws Exception {
|
void setup() {
|
||||||
mockMvc.perform(get("/owners/new"))
|
george = new Owner();
|
||||||
.andExpect(status().isOk())
|
george.setId(TEST_OWNER_ID);
|
||||||
.andExpect(model().attributeExists("owner"))
|
george.setFirstName("George");
|
||||||
.andExpect(view().name("owners/createOrUpdateOwnerForm"));
|
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
|
@Test
|
||||||
public void testProcessCreationFormSuccess() throws Exception {
|
void testInitCreationForm() throws Exception {
|
||||||
mockMvc.perform(post("/owners/new")
|
mockMvc.perform(get("/owners/new")).andExpect(status().isOk()).andExpect(model().attributeExists("owner"))
|
||||||
.param("firstName", "Joe")
|
.andExpect(view().name("owners/createOrUpdateOwnerForm"));
|
||||||
.param("lastName", "Bloggs")
|
}
|
||||||
.param("address", "123 Caramel Street")
|
|
||||||
.param("city", "London")
|
|
||||||
.param("telephone", "01316761638")
|
|
||||||
)
|
|
||||||
.andExpect(status().is3xxRedirection());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProcessCreationFormHasErrors() 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")
|
.andExpect(status().is3xxRedirection());
|
||||||
.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
|
@Test
|
||||||
public void testInitFindForm() throws Exception {
|
void testProcessCreationFormHasErrors() throws Exception {
|
||||||
mockMvc.perform(get("/owners/find"))
|
mockMvc.perform(
|
||||||
.andExpect(status().isOk())
|
post("/owners/new").param("firstName", "Joe").param("lastName", "Bloggs").param("city", "London"))
|
||||||
.andExpect(model().attributeExists("owner"))
|
.andExpect(status().isOk()).andExpect(model().attributeHasErrors("owner"))
|
||||||
.andExpect(view().name("owners/findOwners"));
|
.andExpect(model().attributeHasFieldErrors("owner", "address"))
|
||||||
}
|
.andExpect(model().attributeHasFieldErrors("owner", "telephone"))
|
||||||
|
.andExpect(view().name("owners/createOrUpdateOwnerForm"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProcessFindFormSuccess() throws Exception {
|
void testInitFindForm() throws Exception {
|
||||||
given(this.owners.findByLastName("")).willReturn(Lists.newArrayList(george, new Owner()));
|
mockMvc.perform(get("/owners/find")).andExpect(status().isOk()).andExpect(model().attributeExists("owner"))
|
||||||
mockMvc.perform(get("/owners"))
|
.andExpect(view().name("owners/findOwners"));
|
||||||
.andExpect(status().isOk())
|
}
|
||||||
.andExpect(view().name("owners/ownersList"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProcessFindFormByLastName() throws Exception {
|
void testProcessFindFormSuccess() throws Exception {
|
||||||
given(this.owners.findByLastName(george.getLastName())).willReturn(Lists.newArrayList(george));
|
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"));
|
||||||
.param("lastName", "Franklin")
|
}
|
||||||
)
|
|
||||||
.andExpect(status().is3xxRedirection())
|
|
||||||
.andExpect(view().name("redirect:/owners/" + TEST_OWNER_ID));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProcessFindFormNoOwnersFound() throws Exception {
|
void testProcessFindFormByLastName() throws Exception {
|
||||||
mockMvc.perform(get("/owners")
|
given(this.owners.findByLastName(george.getLastName())).willReturn(Lists.newArrayList(george));
|
||||||
.param("lastName", "Unknown Surname")
|
mockMvc.perform(get("/owners").param("lastName", "Franklin")).andExpect(status().is3xxRedirection())
|
||||||
)
|
.andExpect(view().name("redirect:/owners/" + TEST_OWNER_ID));
|
||||||
.andExpect(status().isOk())
|
}
|
||||||
.andExpect(model().attributeHasFieldErrors("owner", "lastName"))
|
|
||||||
.andExpect(model().attributeHasFieldErrorCode("owner", "lastName", "notFound"))
|
|
||||||
.andExpect(view().name("owners/findOwners"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInitUpdateOwnerForm() throws Exception {
|
void testProcessFindFormNoOwnersFound() throws Exception {
|
||||||
mockMvc.perform(get("/owners/{ownerId}/edit", TEST_OWNER_ID))
|
mockMvc.perform(get("/owners").param("lastName", "Unknown Surname")).andExpect(status().isOk())
|
||||||
.andExpect(status().isOk())
|
.andExpect(model().attributeHasFieldErrors("owner", "lastName"))
|
||||||
.andExpect(model().attributeExists("owner"))
|
.andExpect(model().attributeHasFieldErrorCode("owner", "lastName", "notFound"))
|
||||||
.andExpect(model().attribute("owner", hasProperty("lastName", is("Franklin"))))
|
.andExpect(view().name("owners/findOwners"));
|
||||||
.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
|
@Test
|
||||||
public void testProcessUpdateOwnerFormSuccess() throws Exception {
|
void testInitUpdateOwnerForm() throws Exception {
|
||||||
mockMvc.perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID)
|
mockMvc.perform(get("/owners/{ownerId}/edit", TEST_OWNER_ID)).andExpect(status().isOk())
|
||||||
.param("firstName", "Joe")
|
.andExpect(model().attributeExists("owner"))
|
||||||
.param("lastName", "Bloggs")
|
.andExpect(model().attribute("owner", hasProperty("lastName", is("Franklin"))))
|
||||||
.param("address", "123 Caramel Street")
|
.andExpect(model().attribute("owner", hasProperty("firstName", is("George"))))
|
||||||
.param("city", "London")
|
.andExpect(model().attribute("owner", hasProperty("address", is("110 W. Liberty St."))))
|
||||||
.param("telephone", "01616291589")
|
.andExpect(model().attribute("owner", hasProperty("city", is("Madison"))))
|
||||||
)
|
.andExpect(model().attribute("owner", hasProperty("telephone", is("6085551023"))))
|
||||||
.andExpect(status().is3xxRedirection())
|
.andExpect(view().name("owners/createOrUpdateOwnerForm"));
|
||||||
.andExpect(view().name("redirect:/owners/{ownerId}"));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProcessUpdateOwnerFormHasErrors() 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("city", "London")
|
.andExpect(view().name("redirect:/owners/{ownerId}"));
|
||||||
)
|
}
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(model().attributeHasErrors("owner"))
|
|
||||||
.andExpect(model().attributeHasFieldErrors("owner", "address"))
|
|
||||||
.andExpect(model().attributeHasFieldErrors("owner", "telephone"))
|
|
||||||
.andExpect(view().name("owners/createOrUpdateOwnerForm"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testShowOwner() throws Exception {
|
void testProcessUpdateOwnerFormHasErrors() throws Exception {
|
||||||
mockMvc.perform(get("/owners/{ownerId}", TEST_OWNER_ID))
|
mockMvc.perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID).param("firstName", "Joe")
|
||||||
.andExpect(status().isOk())
|
.param("lastName", "Bloggs").param("city", "London")).andExpect(status().isOk())
|
||||||
.andExpect(model().attribute("owner", hasProperty("lastName", is("Franklin"))))
|
.andExpect(model().attributeHasErrors("owner"))
|
||||||
.andExpect(model().attribute("owner", hasProperty("firstName", is("George"))))
|
.andExpect(model().attributeHasFieldErrors("owner", "address"))
|
||||||
.andExpect(model().attribute("owner", hasProperty("address", is("110 W. Liberty St."))))
|
.andExpect(model().attributeHasFieldErrors("owner", "telephone"))
|
||||||
.andExpect(model().attribute("owner", hasProperty("city", is("Madison"))))
|
.andExpect(view().name("owners/createOrUpdateOwnerForm"));
|
||||||
.andExpect(model().attribute("owner", hasProperty("telephone", is("6085551023"))))
|
}
|
||||||
.andExpect(view().name("owners/ownerDetails"));
|
|
||||||
}
|
@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<List<Pet>>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(Object item) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<Pet> pets = (List<Pet>) 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"));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
164
src/test/java/org/springframework/samples/petclinic/owner/PetControllerTests.java
Normal file → Executable file
164
src/test/java/org/springframework/samples/petclinic/owner/PetControllerTests.java
Normal file → Executable file
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2019 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package org.springframework.samples.petclinic.owner;
|
package org.springframework.samples.petclinic.owner;
|
||||||
|
|
||||||
import static org.mockito.BDDMockito.given;
|
import static org.mockito.BDDMockito.given;
|
||||||
|
@ -8,22 +24,13 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
|
||||||
|
|
||||||
import org.assertj.core.util.Lists;
|
import org.assertj.core.util.Lists;
|
||||||
import org.junit.Before;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
import org.springframework.context.annotation.ComponentScan;
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
import org.springframework.context.annotation.FilterType;
|
import org.springframework.context.annotation.FilterType;
|
||||||
import org.springframework.samples.petclinic.owner.Owner;
|
|
||||||
import org.springframework.samples.petclinic.owner.OwnerRepository;
|
|
||||||
import org.springframework.samples.petclinic.owner.Pet;
|
|
||||||
import org.springframework.samples.petclinic.owner.PetController;
|
|
||||||
import org.springframework.samples.petclinic.owner.PetRepository;
|
|
||||||
import org.springframework.samples.petclinic.owner.PetType;
|
|
||||||
import org.springframework.samples.petclinic.owner.PetTypeFormatter;
|
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,97 +38,76 @@ import org.springframework.test.web.servlet.MockMvc;
|
||||||
*
|
*
|
||||||
* @author Colin But
|
* @author Colin But
|
||||||
*/
|
*/
|
||||||
@RunWith(SpringRunner.class)
|
|
||||||
@WebMvcTest(value = PetController.class,
|
@WebMvcTest(value = PetController.class,
|
||||||
includeFilters = @ComponentScan.Filter(
|
includeFilters = @ComponentScan.Filter(value = PetTypeFormatter.class, type = FilterType.ASSIGNABLE_TYPE))
|
||||||
value = PetTypeFormatter.class,
|
class PetControllerTests {
|
||||||
type = FilterType.ASSIGNABLE_TYPE))
|
|
||||||
public 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;
|
||||||
|
|
||||||
@MockBean
|
@MockBean
|
||||||
private PetRepository pets;
|
private PetRepository pets;
|
||||||
|
|
||||||
@MockBean
|
@MockBean
|
||||||
private OwnerRepository owners;
|
private OwnerRepository owners;
|
||||||
|
|
||||||
@Before
|
@BeforeEach
|
||||||
public void setup() {
|
void setup() {
|
||||||
PetType cat = new PetType();
|
PetType cat = new PetType();
|
||||||
cat.setId(3);
|
cat.setId(3);
|
||||||
cat.setName("hamster");
|
cat.setName("hamster");
|
||||||
given(this.pets.findPetTypes()).willReturn(Lists.newArrayList(cat));
|
given(this.pets.findPetTypes()).willReturn(Lists.newArrayList(cat));
|
||||||
given(this.owners.findById(TEST_OWNER_ID)).willReturn(new Owner());
|
given(this.owners.findById(TEST_OWNER_ID)).willReturn(new Owner());
|
||||||
given(this.pets.findById(TEST_PET_ID)).willReturn(new Pet());
|
given(this.pets.findById(TEST_PET_ID)).willReturn(new Pet());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public 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
|
||||||
public 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")
|
.andExpect(view().name("redirect:/owners/{ownerId}"));
|
||||||
.param("birthDate", "2015/02/12")
|
}
|
||||||
)
|
|
||||||
.andExpect(status().is3xxRedirection())
|
|
||||||
.andExpect(view().name("redirect:/owners/{ownerId}"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProcessCreationFormHasErrors() throws Exception {
|
void testProcessCreationFormHasErrors() throws Exception {
|
||||||
mockMvc.perform(post("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_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(view().name("pets/createOrUpdatePetForm"));
|
||||||
.andExpect(model().attributeHasErrors("pet"))
|
}
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(view().name("pets/createOrUpdatePetForm"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public 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
|
||||||
public 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")
|
.andExpect(view().name("redirect:/owners/{ownerId}"));
|
||||||
.param("birthDate", "2015/02/12")
|
}
|
||||||
)
|
|
||||||
.andExpect(status().is3xxRedirection())
|
|
||||||
.andExpect(view().name("redirect:/owners/{ownerId}"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public 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(view().name("pets/createOrUpdatePetForm"));
|
||||||
.andExpect(model().attributeHasNoErrors("owner"))
|
}
|
||||||
.andExpect(model().attributeHasErrors("pet"))
|
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(view().name("pets/createOrUpdatePetForm"));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,20 @@
|
||||||
package org.springframework.samples.petclinic.owner;
|
/*
|
||||||
|
* Copyright 2012-2019 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
package org.springframework.samples.petclinic.owner;
|
||||||
|
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -8,73 +22,74 @@ import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
import org.mockito.runners.MockitoJUnitRunner;
|
|
||||||
import org.springframework.samples.petclinic.owner.PetRepository;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import org.springframework.samples.petclinic.owner.PetType;
|
import static org.mockito.BDDMockito.given;
|
||||||
import org.springframework.samples.petclinic.owner.PetTypeFormatter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test class for {@link PetTypeFormatter}
|
* Test class for {@link PetTypeFormatter}
|
||||||
*
|
*
|
||||||
* @author Colin But
|
* @author Colin But
|
||||||
*/
|
*/
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
public class PetTypeFormatterTests {
|
class PetTypeFormatterTests {
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private PetRepository pets;
|
private PetRepository pets;
|
||||||
|
|
||||||
private PetTypeFormatter petTypeFormatter;
|
private PetTypeFormatter petTypeFormatter;
|
||||||
|
|
||||||
@Before
|
@BeforeEach
|
||||||
public void setup() {
|
void setup() {
|
||||||
this.petTypeFormatter = new PetTypeFormatter(pets);
|
this.petTypeFormatter = new PetTypeFormatter(pets);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPrint() {
|
void testPrint() {
|
||||||
PetType petType = new PetType();
|
PetType petType = new PetType();
|
||||||
petType.setName("Hamster");
|
petType.setName("Hamster");
|
||||||
String petTypeName = this.petTypeFormatter.print(petType, Locale.ENGLISH);
|
String petTypeName = this.petTypeFormatter.print(petType, Locale.ENGLISH);
|
||||||
assertEquals("Hamster", petTypeName);
|
assertThat(petTypeName).isEqualTo("Hamster");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldParse() throws ParseException {
|
void shouldParse() throws ParseException {
|
||||||
Mockito.when(this.pets.findPetTypes()).thenReturn(makePetTypes());
|
given(this.pets.findPetTypes()).willReturn(makePetTypes());
|
||||||
PetType petType = petTypeFormatter.parse("Bird", Locale.ENGLISH);
|
PetType petType = petTypeFormatter.parse("Bird", Locale.ENGLISH);
|
||||||
assertEquals("Bird", petType.getName());
|
assertThat(petType.getName()).isEqualTo("Bird");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = ParseException.class)
|
@Test
|
||||||
public void shouldThrowParseException() throws ParseException {
|
void shouldThrowParseException() throws ParseException {
|
||||||
Mockito.when(this.pets.findPetTypes()).thenReturn(makePetTypes());
|
given(this.pets.findPetTypes()).willReturn(makePetTypes());
|
||||||
petTypeFormatter.parse("Fish", Locale.ENGLISH);
|
Assertions.assertThrows(ParseException.class, () -> {
|
||||||
}
|
petTypeFormatter.parse("Fish", Locale.ENGLISH);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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() {
|
List<PetType> petTypes = new ArrayList<>();
|
||||||
List<PetType> petTypes = new ArrayList<>();
|
petTypes.add(new PetType() {
|
||||||
petTypes.add(new PetType(){
|
{
|
||||||
{
|
setName("Dog");
|
||||||
setName("Dog");
|
}
|
||||||
}
|
});
|
||||||
});
|
petTypes.add(new PetType() {
|
||||||
petTypes.add(new PetType(){
|
{
|
||||||
{
|
setName("Bird");
|
||||||
setName("Bird");
|
}
|
||||||
}
|
});
|
||||||
});
|
return petTypes;
|
||||||
return petTypes;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2019 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package org.springframework.samples.petclinic.owner;
|
package org.springframework.samples.petclinic.owner;
|
||||||
|
|
||||||
import static org.mockito.BDDMockito.given;
|
import static org.mockito.BDDMockito.given;
|
||||||
|
@ -7,17 +23,12 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
import org.springframework.samples.petclinic.owner.Pet;
|
|
||||||
import org.springframework.samples.petclinic.owner.PetRepository;
|
|
||||||
import org.springframework.samples.petclinic.owner.VisitController;
|
|
||||||
import org.springframework.samples.petclinic.visit.VisitRepository;
|
import org.springframework.samples.petclinic.visit.VisitRepository;
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -25,51 +36,43 @@ import org.springframework.test.web.servlet.MockMvc;
|
||||||
*
|
*
|
||||||
* @author Colin But
|
* @author Colin But
|
||||||
*/
|
*/
|
||||||
@RunWith(SpringRunner.class)
|
|
||||||
@WebMvcTest(VisitController.class)
|
@WebMvcTest(VisitController.class)
|
||||||
public class VisitControllerTests {
|
class VisitControllerTests {
|
||||||
|
|
||||||
private static final int TEST_PET_ID = 1;
|
private static final int TEST_PET_ID = 1;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private MockMvc mockMvc;
|
private MockMvc mockMvc;
|
||||||
|
|
||||||
@MockBean
|
@MockBean
|
||||||
private VisitRepository visits;
|
private VisitRepository visits;
|
||||||
|
|
||||||
@MockBean
|
@MockBean
|
||||||
private PetRepository pets;
|
private PetRepository pets;
|
||||||
|
|
||||||
@Before
|
@BeforeEach
|
||||||
public void init() {
|
void init() {
|
||||||
given(this.pets.findById(TEST_PET_ID)).willReturn(new Pet());
|
given(this.pets.findById(TEST_PET_ID)).willReturn(new Pet());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public 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
|
||||||
public 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(view().name("redirect:/owners/{ownerId}"));
|
||||||
)
|
}
|
||||||
.andExpect(status().is3xxRedirection())
|
|
||||||
.andExpect(view().name("redirect:/owners/{ownerId}"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public 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(view().name("pets/createOrUpdateVisitForm"));
|
||||||
.andExpect(model().attributeHasErrors("visit"))
|
}
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(view().name("pets/createOrUpdateVisitForm"));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2019 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package org.springframework.samples.petclinic.service;
|
package org.springframework.samples.petclinic.service;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
||||||
import org.springframework.context.annotation.ComponentScan;
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
|
@ -20,21 +35,29 @@ import org.springframework.samples.petclinic.vet.VetRepository;
|
||||||
import org.springframework.samples.petclinic.visit.Visit;
|
import org.springframework.samples.petclinic.visit.Visit;
|
||||||
import org.springframework.samples.petclinic.visit.VisitRepository;
|
import org.springframework.samples.petclinic.visit.VisitRepository;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
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
|
||||||
|
@ -43,164 +66,162 @@ import org.springframework.transaction.annotation.Transactional;
|
||||||
* @author Michael Isvy
|
* @author Michael Isvy
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@RunWith(SpringRunner.class)
|
|
||||||
@DataJpaTest(includeFilters = @ComponentScan.Filter(Service.class))
|
@DataJpaTest(includeFilters = @ComponentScan.Filter(Service.class))
|
||||||
public class ClinicServiceTests {
|
class ClinicServiceTests {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
protected OwnerRepository owners;
|
protected OwnerRepository owners;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
protected PetRepository pets;
|
protected PetRepository pets;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
protected VisitRepository visits;
|
protected VisitRepository visits;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
protected VetRepository vets;
|
protected VetRepository vets;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldFindOwnersByLastName() {
|
void shouldFindOwnersByLastName() {
|
||||||
Collection<Owner> owners = this.owners.findByLastName("Davis");
|
Collection<Owner> owners = this.owners.findByLastName("Davis");
|
||||||
assertThat(owners.size()).isEqualTo(2);
|
assertThat(owners).hasSize(2);
|
||||||
|
|
||||||
owners = this.owners.findByLastName("Daviss");
|
owners = this.owners.findByLastName("Daviss");
|
||||||
assertThat(owners.isEmpty()).isTrue();
|
assertThat(owners).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldFindSingleOwnerWithPet() {
|
void shouldFindSingleOwnerWithPet() {
|
||||||
Owner owner = this.owners.findById(1);
|
Owner owner = this.owners.findById(1);
|
||||||
assertThat(owner.getLastName()).startsWith("Franklin");
|
assertThat(owner.getLastName()).startsWith("Franklin");
|
||||||
assertThat(owner.getPets().size()).isEqualTo(1);
|
assertThat(owner.getPets()).hasSize(1);
|
||||||
assertThat(owner.getPets().get(0).getType()).isNotNull();
|
assertThat(owner.getPets().get(0).getType()).isNotNull();
|
||||||
assertThat(owner.getPets().get(0).getType().getName()).isEqualTo("cat");
|
assertThat(owner.getPets().get(0).getType().getName()).isEqualTo("cat");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Transactional
|
@Transactional
|
||||||
public void shouldInsertOwner() {
|
void shouldInsertOwner() {
|
||||||
Collection<Owner> owners = this.owners.findByLastName("Schultz");
|
Collection<Owner> owners = this.owners.findByLastName("Schultz");
|
||||||
int found = owners.size();
|
int found = owners.size();
|
||||||
|
|
||||||
Owner owner = new Owner();
|
Owner owner = new Owner();
|
||||||
owner.setFirstName("Sam");
|
owner.setFirstName("Sam");
|
||||||
owner.setLastName("Schultz");
|
owner.setLastName("Schultz");
|
||||||
owner.setAddress("4, Evans Street");
|
owner.setAddress("4, Evans Street");
|
||||||
owner.setCity("Wollongong");
|
owner.setCity("Wollongong");
|
||||||
owner.setTelephone("4444444444");
|
owner.setTelephone("4444444444");
|
||||||
this.owners.save(owner);
|
this.owners.save(owner);
|
||||||
assertThat(owner.getId().longValue()).isNotEqualTo(0);
|
assertThat(owner.getId().longValue()).isNotEqualTo(0);
|
||||||
|
|
||||||
owners = this.owners.findByLastName("Schultz");
|
owners = this.owners.findByLastName("Schultz");
|
||||||
assertThat(owners.size()).isEqualTo(found + 1);
|
assertThat(owners.size()).isEqualTo(found + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Transactional
|
@Transactional
|
||||||
public void shouldUpdateOwner() {
|
void shouldUpdateOwner() {
|
||||||
Owner owner = this.owners.findById(1);
|
Owner owner = this.owners.findById(1);
|
||||||
String oldLastName = owner.getLastName();
|
String oldLastName = owner.getLastName();
|
||||||
String newLastName = oldLastName + "X";
|
String newLastName = oldLastName + "X";
|
||||||
|
|
||||||
owner.setLastName(newLastName);
|
owner.setLastName(newLastName);
|
||||||
this.owners.save(owner);
|
this.owners.save(owner);
|
||||||
|
|
||||||
// retrieving new name from database
|
// retrieving new name from database
|
||||||
owner = this.owners.findById(1);
|
owner = this.owners.findById(1);
|
||||||
assertThat(owner.getLastName()).isEqualTo(newLastName);
|
assertThat(owner.getLastName()).isEqualTo(newLastName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldFindPetWithCorrectId() {
|
void shouldFindPetWithCorrectId() {
|
||||||
Pet pet7 = this.pets.findById(7);
|
Pet pet7 = this.pets.findById(7);
|
||||||
assertThat(pet7.getName()).startsWith("Samantha");
|
assertThat(pet7.getName()).startsWith("Samantha");
|
||||||
assertThat(pet7.getOwner().getFirstName()).isEqualTo("Jean");
|
assertThat(pet7.getOwner().getFirstName()).isEqualTo("Jean");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldFindAllPetTypes() {
|
void shouldFindAllPetTypes() {
|
||||||
Collection<PetType> petTypes = this.pets.findPetTypes();
|
Collection<PetType> petTypes = this.pets.findPetTypes();
|
||||||
|
|
||||||
PetType petType1 = EntityUtils.getById(petTypes, PetType.class, 1);
|
PetType petType1 = EntityUtils.getById(petTypes, PetType.class, 1);
|
||||||
assertThat(petType1.getName()).isEqualTo("cat");
|
assertThat(petType1.getName()).isEqualTo("cat");
|
||||||
PetType petType4 = EntityUtils.getById(petTypes, PetType.class, 4);
|
PetType petType4 = EntityUtils.getById(petTypes, PetType.class, 4);
|
||||||
assertThat(petType4.getName()).isEqualTo("snake");
|
assertThat(petType4.getName()).isEqualTo("snake");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Transactional
|
@Transactional
|
||||||
public void shouldInsertPetIntoDatabaseAndGenerateId() {
|
void shouldInsertPetIntoDatabaseAndGenerateId() {
|
||||||
Owner owner6 = this.owners.findById(6);
|
Owner owner6 = this.owners.findById(6);
|
||||||
int found = owner6.getPets().size();
|
int found = owner6.getPets().size();
|
||||||
|
|
||||||
Pet pet = new Pet();
|
Pet pet = new Pet();
|
||||||
pet.setName("bowser");
|
pet.setName("bowser");
|
||||||
Collection<PetType> types = this.pets.findPetTypes();
|
Collection<PetType> types = this.pets.findPetTypes();
|
||||||
pet.setType(EntityUtils.getById(types, PetType.class, 2));
|
pet.setType(EntityUtils.getById(types, PetType.class, 2));
|
||||||
pet.setBirthDate(new Date());
|
pet.setBirthDate(LocalDate.now());
|
||||||
owner6.addPet(pet);
|
owner6.addPet(pet);
|
||||||
assertThat(owner6.getPets().size()).isEqualTo(found + 1);
|
assertThat(owner6.getPets().size()).isEqualTo(found + 1);
|
||||||
|
|
||||||
this.pets.save(pet);
|
this.pets.save(pet);
|
||||||
this.owners.save(owner6);
|
this.owners.save(owner6);
|
||||||
|
|
||||||
owner6 = this.owners.findById(6);
|
owner6 = this.owners.findById(6);
|
||||||
assertThat(owner6.getPets().size()).isEqualTo(found + 1);
|
assertThat(owner6.getPets().size()).isEqualTo(found + 1);
|
||||||
// checks that id has been generated
|
// checks that id has been generated
|
||||||
assertThat(pet.getId()).isNotNull();
|
assertThat(pet.getId()).isNotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Transactional
|
@Transactional
|
||||||
public void shouldUpdatePetName() throws Exception {
|
void shouldUpdatePetName() throws Exception {
|
||||||
Pet pet7 = this.pets.findById(7);
|
Pet pet7 = this.pets.findById(7);
|
||||||
String oldName = pet7.getName();
|
String oldName = pet7.getName();
|
||||||
|
|
||||||
String newName = oldName + "X";
|
String newName = oldName + "X";
|
||||||
pet7.setName(newName);
|
pet7.setName(newName);
|
||||||
this.pets.save(pet7);
|
this.pets.save(pet7);
|
||||||
|
|
||||||
pet7 = this.pets.findById(7);
|
pet7 = this.pets.findById(7);
|
||||||
assertThat(pet7.getName()).isEqualTo(newName);
|
assertThat(pet7.getName()).isEqualTo(newName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldFindVets() {
|
void shouldFindVets() {
|
||||||
Collection<Vet> vets = this.vets.findAll();
|
Collection<Vet> vets = this.vets.findAll();
|
||||||
|
|
||||||
Vet vet = EntityUtils.getById(vets, Vet.class, 3);
|
Vet vet = EntityUtils.getById(vets, Vet.class, 3);
|
||||||
assertThat(vet.getLastName()).isEqualTo("Douglas");
|
assertThat(vet.getLastName()).isEqualTo("Douglas");
|
||||||
assertThat(vet.getNrOfSpecialties()).isEqualTo(2);
|
assertThat(vet.getNrOfSpecialties()).isEqualTo(2);
|
||||||
assertThat(vet.getSpecialties().get(0).getName()).isEqualTo("dentistry");
|
assertThat(vet.getSpecialties().get(0).getName()).isEqualTo("dentistry");
|
||||||
assertThat(vet.getSpecialties().get(1).getName()).isEqualTo("surgery");
|
assertThat(vet.getSpecialties().get(1).getName()).isEqualTo("surgery");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Transactional
|
@Transactional
|
||||||
public void shouldAddNewVisitForPet() {
|
void shouldAddNewVisitForPet() {
|
||||||
Pet pet7 = this.pets.findById(7);
|
Pet pet7 = this.pets.findById(7);
|
||||||
int found = pet7.getVisits().size();
|
int found = pet7.getVisits().size();
|
||||||
Visit visit = new Visit();
|
Visit visit = new Visit();
|
||||||
pet7.addVisit(visit);
|
pet7.addVisit(visit);
|
||||||
visit.setDescription("test");
|
visit.setDescription("test");
|
||||||
this.visits.save(visit);
|
this.visits.save(visit);
|
||||||
this.pets.save(pet7);
|
this.pets.save(pet7);
|
||||||
|
|
||||||
pet7 = this.pets.findById(7);
|
pet7 = this.pets.findById(7);
|
||||||
assertThat(pet7.getVisits().size()).isEqualTo(found + 1);
|
assertThat(pet7.getVisits().size()).isEqualTo(found + 1);
|
||||||
assertThat(visit.getId()).isNotNull();
|
assertThat(visit.getId()).isNotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldFindVisitsByPetId() throws Exception {
|
void shouldFindVisitsByPetId() throws Exception {
|
||||||
Collection<Visit> visits = this.visits.findByPetId(7);
|
Collection<Visit> visits = this.visits.findByPetId(7);
|
||||||
assertThat(visits.size()).isEqualTo(2);
|
assertThat(visits).hasSize(2);
|
||||||
Visit[] visitArr = visits.toArray(new Visit[visits.size()]);
|
Visit[] visitArr = visits.toArray(new Visit[visits.size()]);
|
||||||
assertThat(visitArr[0].getDate()).isNotNull();
|
assertThat(visitArr[0].getDate()).isNotNull();
|
||||||
assertThat(visitArr[0].getPetId()).isEqualTo(7);
|
assertThat(visitArr[0].getPetId()).isEqualTo(7);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2012-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* 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,
|
||||||
|
@ -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
|
||||||
|
@ -32,23 +32,22 @@ import org.springframework.samples.petclinic.model.BaseEntity;
|
||||||
*/
|
*/
|
||||||
public abstract class EntityUtils {
|
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
|
* @return the found entity
|
||||||
* @return the found entity
|
* @throws ObjectRetrievalFailureException if the entity was not found
|
||||||
* @throws ObjectRetrievalFailureException if the entity was not found
|
*/
|
||||||
*/
|
public static <T extends BaseEntity> T getById(Collection<T> entities, Class<T> entityClass, int entityId)
|
||||||
public static <T extends BaseEntity> T getById(Collection<T> entities, Class<T> entityClass, int entityId)
|
throws ObjectRetrievalFailureException {
|
||||||
throws ObjectRetrievalFailureException {
|
for (T entity : entities) {
|
||||||
for (T entity : entities) {
|
if (entity.getId() == entityId && entityClass.isInstance(entity)) {
|
||||||
if (entity.getId() == entityId && entityClass.isInstance(entity)) {
|
return entity;
|
||||||
return entity;
|
}
|
||||||
}
|
}
|
||||||
}
|
throw new ObjectRetrievalFailureException(entityClass, entityId);
|
||||||
throw new ObjectRetrievalFailureException(entityClass, entityId);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2019 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package org.springframework.samples.petclinic.system;
|
package org.springframework.samples.petclinic.system;
|
||||||
|
|
||||||
import org.junit.Ignore;
|
import org.junit.jupiter.api.Disabled;
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
@ -20,19 +33,19 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||||
*
|
*
|
||||||
* @author Colin But
|
* @author Colin But
|
||||||
*/
|
*/
|
||||||
@RunWith(SpringRunner.class)
|
|
||||||
// Waiting https://github.com/spring-projects/spring-boot/issues/5574
|
// Waiting https://github.com/spring-projects/spring-boot/issues/5574
|
||||||
@Ignore
|
@Disabled
|
||||||
@WebMvcTest(controllers = CrashController.class)
|
@WebMvcTest(controllers = CrashController.class)
|
||||||
public class CrashControllerTests {
|
class CrashControllerTests {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private MockMvc mockMvc;
|
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
|
|
||||||
public void testTriggerException() throws Exception {
|
|
||||||
mockMvc.perform(get("/oups")).andExpect(view().name("exception"))
|
|
||||||
.andExpect(model().attributeExists("exception"))
|
|
||||||
.andExpect(forwardedUrl("exception")).andExpect(status().isOk());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
package org.springframework.samples.petclinic.system;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
|
||||||
import org.springframework.samples.petclinic.vet.VetRepository;
|
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
|
||||||
|
|
||||||
@RunWith(SpringRunner.class)
|
|
||||||
@SpringBootTest
|
|
||||||
public class ProductionConfigurationTests {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private VetRepository vets;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFindAll() throws Exception {
|
|
||||||
vets.findAll();
|
|
||||||
vets.findAll(); // served from cache
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,21 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2019 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package org.springframework.samples.petclinic.vet;
|
package org.springframework.samples.petclinic.vet;
|
||||||
|
|
||||||
import static org.hamcrest.xml.HasXPath.hasXPath;
|
|
||||||
import static org.mockito.BDDMockito.given;
|
import static org.mockito.BDDMockito.given;
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||||
|
@ -10,73 +25,56 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
|
||||||
|
|
||||||
import org.assertj.core.util.Lists;
|
import org.assertj.core.util.Lists;
|
||||||
import org.junit.Before;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.samples.petclinic.vet.Specialty;
|
|
||||||
import org.springframework.samples.petclinic.vet.Vet;
|
|
||||||
import org.springframework.samples.petclinic.vet.VetController;
|
|
||||||
import org.springframework.samples.petclinic.vet.VetRepository;
|
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
import org.springframework.test.web.servlet.ResultActions;
|
import org.springframework.test.web.servlet.ResultActions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test class for the {@link VetController}
|
* Test class for the {@link VetController}
|
||||||
*/
|
*/
|
||||||
@RunWith(SpringRunner.class)
|
|
||||||
@WebMvcTest(VetController.class)
|
@WebMvcTest(VetController.class)
|
||||||
public class VetControllerTests {
|
class VetControllerTests {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private MockMvc mockMvc;
|
private MockMvc mockMvc;
|
||||||
|
|
||||||
@MockBean
|
@MockBean
|
||||||
private VetRepository vets;
|
private VetRepository vets;
|
||||||
|
|
||||||
@Before
|
@BeforeEach
|
||||||
public void setup() {
|
void setup() {
|
||||||
Vet james = new Vet();
|
Vet james = new Vet();
|
||||||
james.setFirstName("James");
|
james.setFirstName("James");
|
||||||
james.setLastName("Carter");
|
james.setLastName("Carter");
|
||||||
james.setId(1);
|
james.setId(1);
|
||||||
Vet helen = new Vet();
|
Vet helen = new Vet();
|
||||||
helen.setFirstName("Helen");
|
helen.setFirstName("Helen");
|
||||||
helen.setLastName("Leary");
|
helen.setLastName("Leary");
|
||||||
helen.setId(2);
|
helen.setId(2);
|
||||||
Specialty radiology = new Specialty();
|
Specialty radiology = new Specialty();
|
||||||
radiology.setId(1);
|
radiology.setId(1);
|
||||||
radiology.setName("radiology");
|
radiology.setName("radiology");
|
||||||
helen.addSpecialty(radiology);
|
helen.addSpecialty(radiology);
|
||||||
given(this.vets.findAll()).willReturn(Lists.newArrayList(james, helen));
|
given(this.vets.findAll()).willReturn(Lists.newArrayList(james, helen));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public 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(view().name("vets/vetList"));
|
||||||
.andExpect(model().attributeExists("vets"))
|
}
|
||||||
.andExpect(view().name("vets/vetList"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testShowResourcesVetList() throws Exception {
|
void testShowResourcesVetList() throws Exception {
|
||||||
ResultActions actions = mockMvc.perform(get("/vets.json").accept(MediaType.APPLICATION_JSON))
|
ResultActions actions = mockMvc.perform(get("/vets").accept(MediaType.APPLICATION_JSON))
|
||||||
.andExpect(status().isOk());
|
.andExpect(status().isOk());
|
||||||
actions.andExpect(content().contentType("application/json;charset=UTF-8"))
|
actions.andExpect(content().contentType(MediaType.APPLICATION_JSON))
|
||||||
.andExpect(jsonPath("$.vetList[0].id").value(1));
|
.andExpect(jsonPath("$.vetList[0].id").value(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testShowVetListXml() throws Exception {
|
|
||||||
mockMvc.perform(get("/vets.xml").accept(MediaType.APPLICATION_XML))
|
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(content().contentType(MediaType.APPLICATION_XML_VALUE))
|
|
||||||
.andExpect(content().node(hasXPath("/vets/vetList[id=1]/id")));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2016-2017 the original author or authors.
|
* Copyright 2012-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* 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,
|
||||||
|
@ -15,29 +15,26 @@
|
||||||
*/
|
*/
|
||||||
package org.springframework.samples.petclinic.vet;
|
package org.springframework.samples.petclinic.vet;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import org.springframework.util.SerializationUtils;
|
import org.springframework.util.SerializationUtils;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class VetTests {
|
class VetTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSerialization() {
|
void testSerialization() {
|
||||||
Vet vet = new Vet();
|
Vet vet = new Vet();
|
||||||
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());
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,7 +135,7 @@
|
||||||
<stringProp name="HTTPSampler.response_timeout"></stringProp>
|
<stringProp name="HTTPSampler.response_timeout"></stringProp>
|
||||||
<stringProp name="HTTPSampler.protocol"></stringProp>
|
<stringProp name="HTTPSampler.protocol"></stringProp>
|
||||||
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
|
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
|
||||||
<stringProp name="HTTPSampler.path">${CONTEXT_WEB}/vendors/jquery/jquery.js</stringProp>
|
<stringProp name="HTTPSampler.path">${CONTEXT_WEB}/webjars/jquery/jquery.min.js</stringProp>
|
||||||
<stringProp name="HTTPSampler.method">GET</stringProp>
|
<stringProp name="HTTPSampler.method">GET</stringProp>
|
||||||
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
|
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
|
||||||
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
|
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
|
||||||
|
@ -175,7 +175,7 @@
|
||||||
<stringProp name="HTTPSampler.response_timeout"></stringProp>
|
<stringProp name="HTTPSampler.response_timeout"></stringProp>
|
||||||
<stringProp name="HTTPSampler.protocol"></stringProp>
|
<stringProp name="HTTPSampler.protocol"></stringProp>
|
||||||
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
|
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
|
||||||
<stringProp name="HTTPSampler.path">${CONTEXT_WEB}/owners/find.html</stringProp>
|
<stringProp name="HTTPSampler.path">${CONTEXT_WEB}/owners/find</stringProp>
|
||||||
<stringProp name="HTTPSampler.method">GET</stringProp>
|
<stringProp name="HTTPSampler.method">GET</stringProp>
|
||||||
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
|
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
|
||||||
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
|
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
|
||||||
|
@ -195,7 +195,7 @@
|
||||||
<stringProp name="HTTPSampler.response_timeout"></stringProp>
|
<stringProp name="HTTPSampler.response_timeout"></stringProp>
|
||||||
<stringProp name="HTTPSampler.protocol"></stringProp>
|
<stringProp name="HTTPSampler.protocol"></stringProp>
|
||||||
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
|
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
|
||||||
<stringProp name="HTTPSampler.path">${CONTEXT_WEB}/owners.html?lastName=</stringProp>
|
<stringProp name="HTTPSampler.path">${CONTEXT_WEB}/owners?lastName=</stringProp>
|
||||||
<stringProp name="HTTPSampler.method">GET</stringProp>
|
<stringProp name="HTTPSampler.method">GET</stringProp>
|
||||||
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
|
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
|
||||||
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
|
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
|
||||||
|
@ -215,7 +215,7 @@
|
||||||
<stringProp name="HTTPSampler.response_timeout"></stringProp>
|
<stringProp name="HTTPSampler.response_timeout"></stringProp>
|
||||||
<stringProp name="HTTPSampler.protocol"></stringProp>
|
<stringProp name="HTTPSampler.protocol"></stringProp>
|
||||||
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
|
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
|
||||||
<stringProp name="HTTPSampler.path">${CONTEXT_WEB}/owners/${count}.html</stringProp>
|
<stringProp name="HTTPSampler.path">${CONTEXT_WEB}/owners/${count}</stringProp>
|
||||||
<stringProp name="HTTPSampler.method">GET</stringProp>
|
<stringProp name="HTTPSampler.method">GET</stringProp>
|
||||||
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
|
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
|
||||||
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
|
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
|
||||||
|
@ -235,7 +235,7 @@
|
||||||
<stringProp name="HTTPSampler.response_timeout"></stringProp>
|
<stringProp name="HTTPSampler.response_timeout"></stringProp>
|
||||||
<stringProp name="HTTPSampler.protocol"></stringProp>
|
<stringProp name="HTTPSampler.protocol"></stringProp>
|
||||||
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
|
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
|
||||||
<stringProp name="HTTPSampler.path">${CONTEXT_WEB}/owners/${count}/edit.html</stringProp>
|
<stringProp name="HTTPSampler.path">${CONTEXT_WEB}/owners/${count}/edit</stringProp>
|
||||||
<stringProp name="HTTPSampler.method">GET</stringProp>
|
<stringProp name="HTTPSampler.method">GET</stringProp>
|
||||||
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
|
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
|
||||||
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
|
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
|
||||||
|
@ -262,7 +262,7 @@
|
||||||
<stringProp name="HTTPSampler.response_timeout"></stringProp>
|
<stringProp name="HTTPSampler.response_timeout"></stringProp>
|
||||||
<stringProp name="HTTPSampler.protocol"></stringProp>
|
<stringProp name="HTTPSampler.protocol"></stringProp>
|
||||||
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
|
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
|
||||||
<stringProp name="HTTPSampler.path">${CONTEXT_WEB}/owners/${count}/edit.html</stringProp>
|
<stringProp name="HTTPSampler.path">${CONTEXT_WEB}/owners/${count}/edit</stringProp>
|
||||||
<stringProp name="HTTPSampler.method">POST</stringProp>
|
<stringProp name="HTTPSampler.method">POST</stringProp>
|
||||||
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
|
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
|
||||||
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
|
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
|
||||||
|
@ -329,7 +329,7 @@
|
||||||
<stringProp name="HTTPSampler.response_timeout"></stringProp>
|
<stringProp name="HTTPSampler.response_timeout"></stringProp>
|
||||||
<stringProp name="HTTPSampler.protocol"></stringProp>
|
<stringProp name="HTTPSampler.protocol"></stringProp>
|
||||||
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
|
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
|
||||||
<stringProp name="HTTPSampler.path">${CONTEXT_WEB}/owners/${count}.html</stringProp>
|
<stringProp name="HTTPSampler.path">${CONTEXT_WEB}/owners/${count}</stringProp>
|
||||||
<stringProp name="HTTPSampler.method">GET</stringProp>
|
<stringProp name="HTTPSampler.method">GET</stringProp>
|
||||||
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
|
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
|
||||||
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
|
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
|
||||||
|
|
Loading…
Reference in a new issue