forked from DevFW-CICD/spring-petclinic
Compare commits
33 commits
Author | SHA1 | Date | |
---|---|---|---|
2c6b644330 | |||
34ef850730 | |||
![]() |
22caee3d03 | ||
![]() |
42e2c74b0b | ||
![]() |
3b90fac983 | ||
![]() |
300597fc6c | ||
![]() |
40a41375e6 | ||
![]() |
214a8fb87f | ||
![]() |
a0ba075bd8 | ||
![]() |
91f55a4f71 | ||
![]() |
9f1cda1c08 | ||
![]() |
317562a170 | ||
![]() |
1cad4124b7 | ||
![]() |
668629d5bd | ||
![]() |
a3026bddbb | ||
![]() |
50866def72 | ||
![]() |
14af47d4e5 | ||
![]() |
fdc40a7048 | ||
![]() |
a50bfb65bb | ||
![]() |
dff45cf70c | ||
![]() |
90bbb98ea6 | ||
![]() |
bbb237928f | ||
![]() |
912de1648e | ||
![]() |
62dbfa8e9a | ||
![]() |
ae1bb8228c | ||
![]() |
fc442120ce | ||
![]() |
f8001e0add | ||
![]() |
608e2b6142 | ||
![]() |
6fffe61b93 | ||
![]() |
2daa3993ee | ||
![]() |
d90e284621 | ||
![]() |
f6f923bd39 | ||
![]() |
cabb74ed53 |
46 changed files with 739 additions and 243 deletions
11
.devcontainer/Dockerfile
Normal file
11
.devcontainer/Dockerfile
Normal file
|
@ -0,0 +1,11 @@
|
|||
# Not actually used by the devcontainer, but it is used by gitpod
|
||||
ARG VARIANT=17-bullseye
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/java:0-${VARIANT}
|
||||
ARG NODE_VERSION="none"
|
||||
RUN if [ "${NODE_VERSION}" != "none" ]; then su vscode -c "umask 0002 && . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi
|
||||
ARG USER=vscode
|
||||
VOLUME /home/$USER/.m2
|
||||
VOLUME /home/$USER/.gradle
|
||||
ARG JAVA_VERSION=17.0.7-ms
|
||||
RUN sudo mkdir /home/$USER/.m2 /home/$USER/.gradle && sudo chown $USER:$USER /home/$USER/.m2 /home/$USER/.gradle
|
||||
RUN bash -lc '. /usr/local/sdkman/bin/sdkman-init.sh && sdk install java $JAVA_VERSION && sdk use java $JAVA_VERSION'
|
4
.github/workflows/maven-build.yml
vendored
4
.github/workflows/maven-build.yml
vendored
|
@ -1,5 +1,5 @@
|
|||
# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
|
||||
# For more information see: https://docs.github.com/en/actions/use-cases-and-examples/building-and-testing/building-and-testing-java-with-maven
|
||||
|
||||
name: Java CI with Maven
|
||||
|
||||
|
@ -26,4 +26,4 @@ jobs:
|
|||
distribution: 'adopt'
|
||||
cache: maven
|
||||
- name: Build with Maven Wrapper
|
||||
run: ./mvnw -B package
|
||||
run: ./mvnw -B verify
|
||||
|
|
56
.gitignore
vendored
56
.gitignore
vendored
|
@ -1,17 +1,51 @@
|
|||
target/*
|
||||
bin/*
|
||||
build/*
|
||||
.gradle/*
|
||||
.settings/*
|
||||
.classpath
|
||||
.project
|
||||
.factorypath
|
||||
HELP.md
|
||||
pom.xml.bak
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
.gradle
|
||||
build/
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### STS ###
|
||||
.attach_pid*
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
bin/
|
||||
!**/src/main/**/bin/
|
||||
!**/src/test/**/bin/
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
/target
|
||||
.sts4-cache/
|
||||
.vscode
|
||||
*.ipr
|
||||
out/
|
||||
!**/src/main/**/out/
|
||||
!**/src/test/**/out/
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
### SDK Man ###
|
||||
.sdkmanrc
|
||||
|
||||
### CSS ###
|
||||
_site/
|
||||
*.css
|
||||
!petclinic.css
|
||||
|
|
18
.mvn/wrapper/maven-wrapper.properties
vendored
18
.mvn/wrapper/maven-wrapper.properties
vendored
|
@ -1,3 +1,19 @@
|
|||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
wrapperVersion=3.3.2
|
||||
distributionType=only-script
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.7/apache-maven-3.9.7-bin.zip
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Spring PetClinic Sample Application [](https://github.com/spring-projects/spring-petclinic/actions/workflows/maven-build.yml)
|
||||
# Spring PetClinic Sample Application [](https://github.com/spring-projects/spring-petclinic/actions/workflows/maven-build.yml)[](https://github.com/spring-projects/spring-petclinic/actions/workflows/gradle-build.yml)
|
||||
|
||||
[](https://gitpod.io/#https://github.com/spring-projects/spring-petclinic) [](https://github.com/codespaces/new?hide_repo_select=true&ref=main&repo=7517918)
|
||||
|
||||
|
@ -52,28 +52,28 @@ A similar setup is provided for MySQL and PostgreSQL if a persistent database co
|
|||
You can start MySQL or PostgreSQL locally with whatever installer works for your OS or use docker:
|
||||
|
||||
```bash
|
||||
docker run -e MYSQL_USER=petclinic -e MYSQL_PASSWORD=petclinic -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=petclinic -p 3306:3306 mysql:8.4
|
||||
docker run -e MYSQL_USER=petclinic -e MYSQL_PASSWORD=petclinic -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=petclinic -p 3306:3306 mysql:9.1
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```bash
|
||||
docker run -e POSTGRES_USER=petclinic -e POSTGRES_PASSWORD=petclinic -e POSTGRES_DB=petclinic -p 5432:5432 postgres:16.3
|
||||
docker run -e POSTGRES_USER=petclinic -e POSTGRES_PASSWORD=petclinic -e POSTGRES_DB=petclinic -p 5432:5432 postgres:17.0
|
||||
```
|
||||
|
||||
Further documentation is provided for [MySQL](https://github.com/spring-projects/spring-petclinic/blob/main/src/main/resources/db/mysql/petclinic_db_setup_mysql.txt)
|
||||
and [PostgreSQL](https://github.com/spring-projects/spring-petclinic/blob/main/src/main/resources/db/postgres/petclinic_db_setup_postgres.txt).
|
||||
|
||||
Instead of vanilla `docker` you can also use the provided `docker-compose.yml` file to start the database containers. Each one has a profile just like the Spring profile:
|
||||
Instead of vanilla `docker` you can also use the provided `docker-compose.yml` file to start the database containers. Each one has a service named after the Spring profile:
|
||||
|
||||
```bash
|
||||
docker-compose --profile mysql up
|
||||
docker compose up mysql
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```bash
|
||||
docker-compose --profile postgres up
|
||||
docker compose up postgres
|
||||
```
|
||||
|
||||
## Test Applications
|
24
build.gradle
24
build.gradle
|
@ -1,10 +1,10 @@
|
|||
plugins {
|
||||
id 'java'
|
||||
id 'org.springframework.boot' version '3.3.2'
|
||||
id 'io.spring.dependency-management' version '1.1.5'
|
||||
id 'org.graalvm.buildtools.native' version '0.10.2'
|
||||
id 'org.cyclonedx.bom' version '1.8.2'
|
||||
id 'io.spring.javaformat' version '0.0.41'
|
||||
id 'org.springframework.boot' version '3.4.0'
|
||||
id 'io.spring.dependency-management' version '1.1.6'
|
||||
id 'org.graalvm.buildtools.native' version '0.10.3'
|
||||
id 'org.cyclonedx.bom' version '1.10.0'
|
||||
id 'io.spring.javaformat' version '0.0.43'
|
||||
id "io.spring.nohttp" version "0.0.11"
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ apply plugin: 'io.spring.javaformat'
|
|||
gradle.startParameter.excludedTaskNames += [ "checkFormatAot", "checkFormatAotTest" ]
|
||||
|
||||
group = 'org.springframework.samples'
|
||||
version = '3.3.0'
|
||||
version = '3.4.0'
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
|
@ -25,18 +25,26 @@ repositories {
|
|||
mavenCentral()
|
||||
}
|
||||
|
||||
ext.checkstyleVersion = "10.20.1"
|
||||
ext.springJavaformatCheckstyleVersion = "0.0.43"
|
||||
ext.webjarsLocatorLiteVersion = "1.0.1"
|
||||
ext.webjarsFontawesomeVersion = "4.7.0"
|
||||
ext.webjarsBootstrapVersion = "5.3.3"
|
||||
|
||||
dependencies {
|
||||
// Workaround for AOT issue (https://github.com/spring-projects/spring-framework/pull/33949) -->
|
||||
implementation 'io.projectreactor:reactor-core'
|
||||
|
||||
implementation 'org.springframework.boot:spring-boot-starter-cache'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-web'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-validation'
|
||||
implementation 'io.micrometer:micrometer-registry-prometheus'
|
||||
implementation 'javax.cache:cache-api'
|
||||
implementation 'jakarta.xml.bind:jakarta.xml.bind-api'
|
||||
runtimeOnly 'org.springframework.boot:spring-boot-starter-actuator'
|
||||
runtimeOnly "org.webjars:webjars-locator-lite:${webjarsLocatorLiteVersion}"
|
||||
runtimeOnly "org.webjars.npm:bootstrap:${webjarsBootstrapVersion}"
|
||||
runtimeOnly "org.webjars.npm:font-awesome:${webjarsFontawesomeVersion}"
|
||||
runtimeOnly 'com.github.ben-manes.caffeine:caffeine'
|
||||
|
@ -49,8 +57,8 @@ dependencies {
|
|||
testImplementation 'org.springframework.boot:spring-boot-docker-compose'
|
||||
testImplementation 'org.testcontainers:junit-jupiter'
|
||||
testImplementation 'org.testcontainers:mysql'
|
||||
checkstyle 'io.spring.javaformat:spring-javaformat-checkstyle:0.0.41'
|
||||
checkstyle 'com.puppycrawl.tools:checkstyle:10.16.0'
|
||||
checkstyle "io.spring.javaformat:spring-javaformat-checkstyle:${springJavaformatCheckstyleVersion}"
|
||||
checkstyle "com.puppycrawl.tools:checkstyle:${checkstyleVersion}"
|
||||
}
|
||||
|
||||
tasks.named('test') {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
services:
|
||||
mysql:
|
||||
image: mysql:8.4
|
||||
image: mysql:9.1
|
||||
ports:
|
||||
- "3306:3306"
|
||||
environment:
|
||||
|
@ -11,15 +11,11 @@ services:
|
|||
- MYSQL_DATABASE=petclinic
|
||||
volumes:
|
||||
- "./conf.d:/etc/mysql/conf.d:ro"
|
||||
profiles:
|
||||
- mysql
|
||||
postgres:
|
||||
image: postgres:16.3
|
||||
image: postgres:17.0
|
||||
ports:
|
||||
- "5432:5432"
|
||||
environment:
|
||||
- POSTGRES_PASSWORD=petclinic
|
||||
- POSTGRES_USER=petclinic
|
||||
- POSTGRES_DB=petclinic
|
||||
profiles:
|
||||
- postgres
|
||||
|
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,6 +1,6 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
|
7
gradlew
vendored
7
gradlew
vendored
|
@ -15,6 +15,8 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
|
@ -55,7 +57,7 @@
|
|||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
|
@ -84,7 +86,8 @@ done
|
|||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
||||
' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
|
2
gradlew.bat
vendored
2
gradlew.bat
vendored
|
@ -13,6 +13,8 @@
|
|||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
|
|
73
k8s/db.yml
Normal file
73
k8s/db.yml
Normal file
|
@ -0,0 +1,73 @@
|
|||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: demo-db
|
||||
type: servicebinding.io/postgresql
|
||||
stringData:
|
||||
type: "postgresql"
|
||||
provider: "postgresql"
|
||||
host: "demo-db"
|
||||
port: "5432"
|
||||
database: "petclinic"
|
||||
username: "user"
|
||||
password: "pass"
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: demo-db
|
||||
spec:
|
||||
ports:
|
||||
- port: 5432
|
||||
selector:
|
||||
app: demo-db
|
||||
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: demo-db
|
||||
labels:
|
||||
app: demo-db
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: demo-db
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: demo-db
|
||||
spec:
|
||||
containers:
|
||||
- image: postgres:17
|
||||
name: postgresql
|
||||
env:
|
||||
- name: POSTGRES_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: demo-db
|
||||
key: username
|
||||
- name: POSTGRES_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: demo-db
|
||||
key: password
|
||||
- name: POSTGRES_DB
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: demo-db
|
||||
key: database
|
||||
ports:
|
||||
- containerPort: 5432
|
||||
name: postgresql
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
port: postgresql
|
||||
readinessProbe:
|
||||
tcpSocket:
|
||||
port: postgresql
|
||||
startupProbe:
|
||||
tcpSocket:
|
||||
port: postgresql
|
64
k8s/petclinic.yml
Normal file
64
k8s/petclinic.yml
Normal file
|
@ -0,0 +1,64 @@
|
|||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: petclinic
|
||||
spec:
|
||||
type: NodePort
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: petclinic
|
||||
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: petclinic
|
||||
labels:
|
||||
app: petclinic
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: petclinic
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: petclinic
|
||||
spec:
|
||||
containers:
|
||||
- name: workload
|
||||
image: dsyer/petclinic
|
||||
env:
|
||||
- name: SPRING_PROFILES_ACTIVE
|
||||
value: postgres
|
||||
- name: SERVICE_BINDING_ROOT
|
||||
value: /bindings
|
||||
- name: SPRING_APPLICATION_JSON
|
||||
value: |
|
||||
{
|
||||
"management.endpoint.health.probes.add-additional-paths": true
|
||||
}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 8080
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /livez
|
||||
port: http
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /readyz
|
||||
port: http
|
||||
volumeMounts:
|
||||
- mountPath: /bindings/secret
|
||||
name: binding
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: binding
|
||||
projected:
|
||||
sources:
|
||||
- secret:
|
||||
name: demo-db
|
112
pom.xml
112
pom.xml
|
@ -1,17 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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>
|
||||
<groupId>org.springframework.samples</groupId>
|
||||
<artifactId>spring-petclinic</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.3.2</version>
|
||||
<version>3.4.0</version>
|
||||
<relativePath></relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>org.springframework.samples</groupId>
|
||||
<artifactId>spring-petclinic</artifactId>
|
||||
<version>3.4.0-SNAPSHOT</version>
|
||||
|
||||
<name>petclinic</name>
|
||||
|
||||
<properties>
|
||||
|
@ -20,20 +21,22 @@
|
|||
<java.version>17</java.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<!-- Important for reproducible builds. Update using e.g. ./mvnw versions:set -DnewVersion=... -->
|
||||
<project.build.outputTimestamp>2023-05-10T07:42:50Z</project.build.outputTimestamp>
|
||||
<!-- Important for reproducible builds. Update using e.g. ./mvnw versions:set
|
||||
-DnewVersion=... -->
|
||||
<project.build.outputTimestamp>2024-11-28T14:37:52Z</project.build.outputTimestamp>
|
||||
|
||||
<!-- Web dependencies -->
|
||||
<webjars-locator.version>1.0.1</webjars-locator.version>
|
||||
<webjars-bootstrap.version>5.3.3</webjars-bootstrap.version>
|
||||
<webjars-font-awesome.version>4.7.0</webjars-font-awesome.version>
|
||||
|
||||
<checkstyle.version>10.16.0</checkstyle.version>
|
||||
<checkstyle.version>10.20.1</checkstyle.version>
|
||||
<jacoco.version>0.8.12</jacoco.version>
|
||||
<libsass.version>0.2.29</libsass.version>
|
||||
<lifecycle-mapping>1.0.0</lifecycle-mapping>
|
||||
<maven-checkstyle.version>3.3.1</maven-checkstyle.version>
|
||||
<maven-checkstyle.version>3.6.0</maven-checkstyle.version>
|
||||
<nohttp-checkstyle.version>0.0.11</nohttp-checkstyle.version>
|
||||
<spring-format.version>0.0.41</spring-format.version>
|
||||
<spring-format.version>0.0.43</spring-format.version>
|
||||
|
||||
</properties>
|
||||
|
||||
|
@ -68,6 +71,11 @@
|
|||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<!-- Workaround for AOT issue (https://github.com/spring-projects/spring-framework/pull/33949) -->
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Databases - Uses H2 by default -->
|
||||
<dependency>
|
||||
|
@ -97,6 +105,11 @@
|
|||
</dependency>
|
||||
|
||||
<!-- Webjars -->
|
||||
<dependency>
|
||||
<groupId>org.webjars</groupId>
|
||||
<artifactId>webjars-locator-lite</artifactId>
|
||||
<version>${webjars-locator.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.webjars.npm</groupId>
|
||||
<artifactId>bootstrap</artifactId>
|
||||
|
@ -139,6 +152,11 @@
|
|||
<artifactId>jakarta.xml.bind-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.micrometer</groupId>
|
||||
<artifactId>micrometer-registry-prometheus</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -155,8 +173,9 @@
|
|||
<configuration>
|
||||
<rules>
|
||||
<requireJavaVersion>
|
||||
<message>This build requires at least Java ${java.version}, update your JVM, and
|
||||
run the build again</message>
|
||||
<message>This build requires at least Java ${java.version},
|
||||
update your JVM, and
|
||||
run the build again</message>
|
||||
<version>${java.version}</version>
|
||||
</requireJavaVersion>
|
||||
</rules>
|
||||
|
@ -170,10 +189,10 @@
|
|||
<version>${spring-format.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>validate</phase>
|
||||
<goals>
|
||||
<goal>validate</goal>
|
||||
</goals>
|
||||
<phase>validate</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
@ -196,19 +215,17 @@
|
|||
<executions>
|
||||
<execution>
|
||||
<id>nohttp-checkstyle-validation</id>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
<phase>validate</phase>
|
||||
<configuration>
|
||||
<configLocation>src/checkstyle/nohttp-checkstyle.xml</configLocation>
|
||||
<sourceDirectories>${basedir}</sourceDirectories>
|
||||
<includes>**/*</includes>
|
||||
<excludes>**/.git/**/*,**/.idea/**/*,**/target/**/,**/.flattened-pom.xml,**/*.class</excludes>
|
||||
<propertyExpansion>
|
||||
config_loc=${basedir}/src/checkstyle/
|
||||
</propertyExpansion>
|
||||
<propertyExpansion>config_loc=${basedir}/src/checkstyle/</propertyExpansion>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
@ -249,10 +266,10 @@
|
|||
</execution>
|
||||
<execution>
|
||||
<id>report</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>report</goal>
|
||||
</goals>
|
||||
<phase>prepare-package</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
@ -270,13 +287,13 @@
|
|||
<!-- Spring Boot Actuator displays sbom-related information if a CycloneDX SBOM file is
|
||||
present at the classpath -->
|
||||
<plugin>
|
||||
<?m2e ignore?>
|
||||
<groupId>org.cyclonedx</groupId>
|
||||
<artifactId>cyclonedx-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>Apache License, Version 2.0</name>
|
||||
|
@ -286,39 +303,38 @@
|
|||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
</pluginRepository>
|
||||
<pluginRepository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
|
@ -333,11 +349,11 @@
|
|||
<executions>
|
||||
<execution>
|
||||
<id>unpack</id>
|
||||
<?m2e execute onConfiguration,onIncremental?>
|
||||
<phase>generate-resources</phase>
|
||||
<goals>
|
||||
<goal>unpack</goal>
|
||||
</goals>
|
||||
<?m2e execute onConfiguration,onIncremental?>
|
||||
<phase>generate-resources</phase>
|
||||
<configuration>
|
||||
<artifactItems>
|
||||
<artifactItem>
|
||||
|
@ -356,21 +372,20 @@
|
|||
<groupId>com.gitlab.haynes</groupId>
|
||||
<artifactId>libsass-maven-plugin</artifactId>
|
||||
<version>${libsass.version}</version>
|
||||
<configuration>
|
||||
<inputPath>${basedir}/src/main/scss/</inputPath>
|
||||
<outputPath>${basedir}/src/main/resources/static/resources/css/</outputPath>
|
||||
<includePath>${project.build.directory}/webjars/META-INF/resources/webjars/bootstrap/${webjars-bootstrap.version}/scss/</includePath>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>generate-resources</phase>
|
||||
<?m2e execute onConfiguration,onIncremental?>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
</goals>
|
||||
<phase>generate-resources</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<inputPath>${basedir}/src/main/scss/</inputPath>
|
||||
<outputPath>${basedir}/src/main/resources/static/resources/css/</outputPath>
|
||||
<includePath>
|
||||
${project.build.directory}/webjars/META-INF/resources/webjars/bootstrap/${webjars-bootstrap.version}/scss/</includePath>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
@ -404,7 +419,7 @@
|
|||
</goals>
|
||||
</pluginExecutionFilter>
|
||||
<action>
|
||||
<ignore />
|
||||
<ignore></ignore>
|
||||
</action>
|
||||
</pluginExecution>
|
||||
<pluginExecution>
|
||||
|
@ -417,7 +432,7 @@
|
|||
</goals>
|
||||
</pluginExecutionFilter>
|
||||
<action>
|
||||
<ignore />
|
||||
<ignore></ignore>
|
||||
</action>
|
||||
</pluginExecution>
|
||||
<pluginExecution>
|
||||
|
@ -430,7 +445,7 @@
|
|||
</goals>
|
||||
</pluginExecutionFilter>
|
||||
<action>
|
||||
<ignore />
|
||||
<ignore></ignore>
|
||||
</action>
|
||||
</pluginExecution>
|
||||
</pluginExecutions>
|
||||
|
@ -442,5 +457,4 @@
|
|||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -18,11 +18,7 @@ package org.springframework.samples.petclinic;
|
|||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ImportRuntimeHints;
|
||||
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* PetClinic Spring Boot Application.
|
||||
|
|
|
@ -28,7 +28,6 @@ public class PetClinicRuntimeHints implements RuntimeHintsRegistrar {
|
|||
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
|
||||
hints.resources().registerPattern("db/*"); // https://github.com/spring-projects/spring-boot/issues/32654
|
||||
hints.resources().registerPattern("messages/*");
|
||||
hints.resources().registerPattern("META-INF/resources/webjars/*");
|
||||
hints.resources().registerPattern("mysql-default-conf");
|
||||
hints.serialization().registerType(BaseEntity.class);
|
||||
hints.serialization().registerType(Person.class);
|
||||
|
|
|
@ -17,6 +17,7 @@ package org.springframework.samples.petclinic.model;
|
|||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.MappedSuperclass;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* Simple JavaBean domain object adds a name property to <code>BaseEntity</code>. Used as
|
||||
|
@ -24,11 +25,13 @@ import jakarta.persistence.MappedSuperclass;
|
|||
*
|
||||
* @author Ken Krebs
|
||||
* @author Juergen Hoeller
|
||||
* @author Wick Dynex
|
||||
*/
|
||||
@MappedSuperclass
|
||||
public class NamedEntity extends BaseEntity {
|
||||
|
||||
@Column(name = "name")
|
||||
@NotBlank
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
|
|
|
@ -41,6 +41,7 @@ import jakarta.validation.constraints.NotBlank;
|
|||
* @author Sam Brannen
|
||||
* @author Michael Isvy
|
||||
* @author Oliver Drotbohm
|
||||
* @author Wick Dynex
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "owners")
|
||||
|
@ -62,7 +63,7 @@ public class Owner extends Person {
|
|||
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "owner_id")
|
||||
@OrderBy("name")
|
||||
private List<Pet> pets = new ArrayList<>();
|
||||
private final List<Pet> pets = new ArrayList<>();
|
||||
|
||||
public String getAddress() {
|
||||
return this.address;
|
||||
|
@ -101,7 +102,7 @@ public class Owner extends Person {
|
|||
/**
|
||||
* Return the Pet with the given name, or null if none found for this Owner.
|
||||
* @param name to test
|
||||
* @return a pet if pet name is already in use
|
||||
* @return the Pet with the given name, or null if no such Pet exists for this Owner
|
||||
*/
|
||||
public Pet getPet(String name) {
|
||||
return getPet(name, false);
|
||||
|
@ -110,7 +111,7 @@ public class Owner extends Person {
|
|||
/**
|
||||
* Return the Pet with the given id, or null if none found for this Owner.
|
||||
* @param id to test
|
||||
* @return a pet if pet id is already in use
|
||||
* @return the Pet with the given id, or null if no such Pet exists for this Owner
|
||||
*/
|
||||
public Pet getPet(Integer id) {
|
||||
for (Pet pet : getPets()) {
|
||||
|
@ -127,10 +128,10 @@ public class Owner extends Person {
|
|||
/**
|
||||
* Return the Pet with the given name, or null if none found for this Owner.
|
||||
* @param name to test
|
||||
* @return a pet if pet name is already in use
|
||||
* @param ignoreNew whether to ignore new pets (pets that are not saved yet)
|
||||
* @return the Pet with the given name, or null if no such Pet exists for this Owner
|
||||
*/
|
||||
public Pet getPet(String name, boolean ignoreNew) {
|
||||
name = name.toLowerCase();
|
||||
for (Pet pet : getPets()) {
|
||||
String compName = pet.getName();
|
||||
if (compName != null && compName.equalsIgnoreCase(name)) {
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
package org.springframework.samples.petclinic.owner;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
@ -41,6 +41,7 @@ import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
|||
* @author Ken Krebs
|
||||
* @author Arjen Poutsma
|
||||
* @author Michael Isvy
|
||||
* @author Wick Dynex
|
||||
*/
|
||||
@Controller
|
||||
class OwnerController {
|
||||
|
@ -49,8 +50,8 @@ class OwnerController {
|
|||
|
||||
private final OwnerRepository owners;
|
||||
|
||||
public OwnerController(OwnerRepository clinicService) {
|
||||
this.owners = clinicService;
|
||||
public OwnerController(OwnerRepository owners) {
|
||||
this.owners = owners;
|
||||
}
|
||||
|
||||
@InitBinder
|
||||
|
@ -60,13 +61,14 @@ class OwnerController {
|
|||
|
||||
@ModelAttribute("owner")
|
||||
public Owner findOwner(@PathVariable(name = "ownerId", required = false) Integer ownerId) {
|
||||
return ownerId == null ? new Owner() : this.owners.findById(ownerId);
|
||||
return ownerId == null ? new Owner()
|
||||
: this.owners.findById(ownerId)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Owner not found with id: " + ownerId
|
||||
+ ". Please ensure the ID is correct " + "and the owner exists in the database."));
|
||||
}
|
||||
|
||||
@GetMapping("/owners/new")
|
||||
public String initCreationForm(Map<String, Object> model) {
|
||||
Owner owner = new Owner();
|
||||
model.put("owner", owner);
|
||||
public String initCreationForm() {
|
||||
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
|
||||
}
|
||||
|
||||
|
@ -125,13 +127,11 @@ class OwnerController {
|
|||
private Page<Owner> findPaginatedForOwnersLastName(int page, String lastname) {
|
||||
int pageSize = 5;
|
||||
Pageable pageable = PageRequest.of(page - 1, pageSize);
|
||||
return owners.findByLastName(lastname, pageable);
|
||||
return owners.findByLastNameStartingWith(lastname, pageable);
|
||||
}
|
||||
|
||||
@GetMapping("/owners/{ownerId}/edit")
|
||||
public String initUpdateOwnerForm(@PathVariable("ownerId") int ownerId, Model model) {
|
||||
Owner owner = this.owners.findById(ownerId);
|
||||
model.addAttribute(owner);
|
||||
public String initUpdateOwnerForm() {
|
||||
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
|
||||
}
|
||||
|
||||
|
@ -143,6 +143,12 @@ class OwnerController {
|
|||
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
|
||||
}
|
||||
|
||||
if (owner.getId() != ownerId) {
|
||||
result.rejectValue("id", "mismatch", "The owner ID in the form does not match the URL.");
|
||||
redirectAttributes.addFlashAttribute("error", "Owner ID mismatch. Please try again.");
|
||||
return "redirect:/owners/{ownerId}/edit";
|
||||
}
|
||||
|
||||
owner.setId(ownerId);
|
||||
this.owners.save(owner);
|
||||
redirectAttributes.addFlashAttribute("message", "Owner Values Updated");
|
||||
|
@ -157,7 +163,9 @@ class OwnerController {
|
|||
@GetMapping("/owners/{ownerId}")
|
||||
public ModelAndView showOwner(@PathVariable("ownerId") int ownerId) {
|
||||
ModelAndView mav = new ModelAndView("owners/ownerDetails");
|
||||
Owner owner = this.owners.findById(ownerId);
|
||||
Optional<Owner> optionalOwner = this.owners.findById(ownerId);
|
||||
Owner owner = optionalOwner.orElseThrow(() -> new IllegalArgumentException(
|
||||
"Owner not found with id: " + ownerId + ". Please ensure the ID is correct "));
|
||||
mav.addObject(owner);
|
||||
return mav;
|
||||
}
|
||||
|
|
|
@ -16,12 +16,13 @@
|
|||
package org.springframework.samples.petclinic.owner;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.Repository;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
|
@ -34,15 +35,15 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @author Michael Isvy
|
||||
* @author Wick Dynex
|
||||
*/
|
||||
public interface OwnerRepository extends Repository<Owner, Integer> {
|
||||
public interface OwnerRepository extends JpaRepository<Owner, Integer> {
|
||||
|
||||
/**
|
||||
* Retrieve all {@link PetType}s from the data store.
|
||||
* @return a Collection of {@link PetType}s.
|
||||
*/
|
||||
@Query("SELECT ptype FROM PetType ptype ORDER BY ptype.name")
|
||||
@Transactional(readOnly = true)
|
||||
List<PetType> findPetTypes();
|
||||
|
||||
/**
|
||||
|
@ -52,31 +53,26 @@ public interface OwnerRepository extends Repository<Owner, Integer> {
|
|||
* @return a Collection of matching {@link Owner}s (or an empty Collection if none
|
||||
* found)
|
||||
*/
|
||||
|
||||
@Query("SELECT DISTINCT owner FROM Owner owner left join owner.pets WHERE owner.lastName LIKE :lastName% ")
|
||||
@Transactional(readOnly = true)
|
||||
Page<Owner> findByLastName(@Param("lastName") String lastName, Pageable pageable);
|
||||
Page<Owner> findByLastNameStartingWith(String lastName, Pageable pageable);
|
||||
|
||||
/**
|
||||
* Retrieve an {@link Owner} from the data store by id.
|
||||
* <p>
|
||||
* This method returns an {@link Optional} containing the {@link Owner} if found. If
|
||||
* no {@link Owner} is found with the provided id, it will return an empty
|
||||
* {@link Optional}.
|
||||
* </p>
|
||||
* @param id the id to search for
|
||||
* @return the {@link Owner} if found
|
||||
* @return an {@link Optional} containing the {@link Owner} if found, or an empty
|
||||
* {@link Optional} if not found.
|
||||
* @throws IllegalArgumentException if the id is null (assuming null is not a valid
|
||||
* input for id)
|
||||
*/
|
||||
@Query("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:id")
|
||||
@Transactional(readOnly = true)
|
||||
Owner findById(@Param("id") Integer id);
|
||||
|
||||
/**
|
||||
* Save an {@link Owner} to the data store, either inserting or updating it.
|
||||
* @param owner the {@link Owner} to save
|
||||
*/
|
||||
void save(Owner owner);
|
||||
Optional<Owner> findById(@Nonnull Integer id);
|
||||
|
||||
/**
|
||||
* Returns all the owners from data store
|
||||
**/
|
||||
@Query("SELECT owner FROM Owner owner")
|
||||
@Transactional(readOnly = true)
|
||||
Page<Owner> findAll(Pageable pageable);
|
||||
|
||||
}
|
||||
|
|
3
src/main/java/org/springframework/samples/petclinic/owner/Pet.java
Executable file → Normal file
3
src/main/java/org/springframework/samples/petclinic/owner/Pet.java
Executable file → Normal file
|
@ -39,6 +39,7 @@ import jakarta.persistence.Table;
|
|||
* @author Ken Krebs
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @author Wick Dynex
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "pets")
|
||||
|
@ -55,7 +56,7 @@ public class Pet extends NamedEntity {
|
|||
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "pet_id")
|
||||
@OrderBy("visit_date ASC")
|
||||
private Set<Visit> visits = new LinkedHashSet<>();
|
||||
private final Set<Visit> visits = new LinkedHashSet<>();
|
||||
|
||||
public void setBirthDate(LocalDate birthDate) {
|
||||
this.birthDate = birthDate;
|
||||
|
|
|
@ -17,6 +17,7 @@ package org.springframework.samples.petclinic.owner;
|
|||
|
||||
import java.time.LocalDate;
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.ModelMap;
|
||||
|
@ -37,6 +38,7 @@ import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
|||
* @author Juergen Hoeller
|
||||
* @author Ken Krebs
|
||||
* @author Arjen Poutsma
|
||||
* @author Wick Dynex
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/owners/{ownerId}")
|
||||
|
@ -57,11 +59,9 @@ class PetController {
|
|||
|
||||
@ModelAttribute("owner")
|
||||
public Owner findOwner(@PathVariable("ownerId") int ownerId) {
|
||||
|
||||
Owner owner = this.owners.findById(ownerId);
|
||||
if (owner == null) {
|
||||
throw new IllegalArgumentException("Owner ID not found: " + ownerId);
|
||||
}
|
||||
Optional<Owner> optionalOwner = this.owners.findById(ownerId);
|
||||
Owner owner = optionalOwner.orElseThrow(() -> new IllegalArgumentException(
|
||||
"Owner not found with id: " + ownerId + ". Please ensure the ID is correct "));
|
||||
return owner;
|
||||
}
|
||||
|
||||
|
@ -73,10 +73,9 @@ class PetController {
|
|||
return new Pet();
|
||||
}
|
||||
|
||||
Owner owner = this.owners.findById(ownerId);
|
||||
if (owner == null) {
|
||||
throw new IllegalArgumentException("Owner ID not found: " + ownerId);
|
||||
}
|
||||
Optional<Owner> optionalOwner = this.owners.findById(ownerId);
|
||||
Owner owner = optionalOwner.orElseThrow(() -> new IllegalArgumentException(
|
||||
"Owner not found with id: " + ownerId + ". Please ensure the ID is correct "));
|
||||
return owner.getPet(petId);
|
||||
}
|
||||
|
||||
|
@ -94,51 +93,46 @@ class PetController {
|
|||
public String initCreationForm(Owner owner, ModelMap model) {
|
||||
Pet pet = new Pet();
|
||||
owner.addPet(pet);
|
||||
model.put("pet", pet);
|
||||
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
|
||||
}
|
||||
|
||||
@PostMapping("/pets/new")
|
||||
public String processCreationForm(Owner owner, @Valid Pet pet, BindingResult result, ModelMap model,
|
||||
public String processCreationForm(Owner owner, @Valid Pet pet, BindingResult result,
|
||||
RedirectAttributes redirectAttributes) {
|
||||
if (StringUtils.hasText(pet.getName()) && pet.isNew() && owner.getPet(pet.getName(), true) != null) {
|
||||
|
||||
if (StringUtils.hasText(pet.getName()) && pet.isNew() && owner.getPet(pet.getName(), true) != null)
|
||||
result.rejectValue("name", "duplicate", "already exists");
|
||||
}
|
||||
|
||||
LocalDate currentDate = LocalDate.now();
|
||||
if (pet.getBirthDate() != null && pet.getBirthDate().isAfter(currentDate)) {
|
||||
result.rejectValue("birthDate", "typeMismatch.birthDate");
|
||||
}
|
||||
|
||||
owner.addPet(pet);
|
||||
if (result.hasErrors()) {
|
||||
model.put("pet", pet);
|
||||
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
|
||||
}
|
||||
|
||||
owner.addPet(pet);
|
||||
this.owners.save(owner);
|
||||
redirectAttributes.addFlashAttribute("message", "New Pet has been Added");
|
||||
return "redirect:/owners/{ownerId}";
|
||||
}
|
||||
|
||||
@GetMapping("/pets/{petId}/edit")
|
||||
public String initUpdateForm(Owner owner, @PathVariable("petId") int petId, ModelMap model,
|
||||
RedirectAttributes redirectAttributes) {
|
||||
Pet pet = owner.getPet(petId);
|
||||
model.put("pet", pet);
|
||||
public String initUpdateForm() {
|
||||
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
|
||||
}
|
||||
|
||||
@PostMapping("/pets/{petId}/edit")
|
||||
public String processUpdateForm(@Valid Pet pet, BindingResult result, Owner owner, ModelMap model,
|
||||
public String processUpdateForm(Owner owner, @Valid Pet pet, BindingResult result,
|
||||
RedirectAttributes redirectAttributes) {
|
||||
|
||||
String petName = pet.getName();
|
||||
|
||||
// checking if the pet name already exist for the owner
|
||||
if (StringUtils.hasText(petName)) {
|
||||
Pet existingPet = owner.getPet(petName.toLowerCase(), false);
|
||||
if (existingPet != null && existingPet.getId() != pet.getId()) {
|
||||
Pet existingPet = owner.getPet(petName, false);
|
||||
if (existingPet != null && !existingPet.getId().equals(pet.getId())) {
|
||||
result.rejectValue("name", "duplicate", "already exists");
|
||||
}
|
||||
}
|
||||
|
@ -149,7 +143,6 @@ class PetController {
|
|||
}
|
||||
|
||||
if (result.hasErrors()) {
|
||||
model.put("pet", pet);
|
||||
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
|
||||
}
|
||||
|
||||
|
|
0
src/main/java/org/springframework/samples/petclinic/owner/Visit.java
Executable file → Normal file
0
src/main/java/org/springframework/samples/petclinic/owner/Visit.java
Executable file → Normal file
|
@ -16,6 +16,7 @@
|
|||
package org.springframework.samples.petclinic.owner;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.validation.BindingResult;
|
||||
|
@ -35,6 +36,7 @@ import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
|||
* @author Arjen Poutsma
|
||||
* @author Michael Isvy
|
||||
* @author Dave Syer
|
||||
* @author Wick Dynex
|
||||
*/
|
||||
@Controller
|
||||
class VisitController {
|
||||
|
@ -60,7 +62,9 @@ class VisitController {
|
|||
@ModelAttribute("visit")
|
||||
public Visit loadPetWithVisit(@PathVariable("ownerId") int ownerId, @PathVariable("petId") int petId,
|
||||
Map<String, Object> model) {
|
||||
Owner owner = this.owners.findById(ownerId);
|
||||
Optional<Owner> optionalOwner = owners.findById(ownerId);
|
||||
Owner owner = optionalOwner.orElseThrow(() -> new IllegalArgumentException(
|
||||
"Owner not found with id: " + ownerId + ". Please ensure the ID is correct "));
|
||||
|
||||
Pet pet = owner.getPet(petId);
|
||||
model.put("pet", pet);
|
||||
|
|
0
src/main/java/org/springframework/samples/petclinic/system/CacheConfiguration.java
Executable file → Normal file
0
src/main/java/org/springframework/samples/petclinic/system/CacheConfiguration.java
Executable file → Normal file
|
@ -57,10 +57,6 @@ public class Vet extends Person {
|
|||
return this.specialties;
|
||||
}
|
||||
|
||||
protected void setSpecialtiesInternal(Set<Specialty> specialties) {
|
||||
this.specialties = specialties;
|
||||
}
|
||||
|
||||
@XmlElement
|
||||
public List<Specialty> getSpecialties() {
|
||||
List<Specialty> sortedSpecs = new ArrayList<>(getSpecialtiesInternal());
|
||||
|
|
|
@ -37,8 +37,8 @@ class VetController {
|
|||
|
||||
private final VetRepository vetRepository;
|
||||
|
||||
public VetController(VetRepository clinicService) {
|
||||
this.vetRepository = clinicService;
|
||||
public VetController(VetRepository vetRepository) {
|
||||
this.vetRepository = vetRepository;
|
||||
}
|
||||
|
||||
@GetMapping("/vets.html")
|
||||
|
|
|
@ -8,7 +8,7 @@ spring.thymeleaf.mode=HTML
|
|||
|
||||
# JPA
|
||||
spring.jpa.hibernate.ddl-auto=none
|
||||
spring.jpa.open-in-view=true
|
||||
spring.jpa.open-in-view=false
|
||||
|
||||
# Internationalization
|
||||
spring.messages.basename=messages/messages
|
||||
|
|
9
src/main/resources/messages/messages_fa.properties
Normal file
9
src/main/resources/messages/messages_fa.properties
Normal file
|
@ -0,0 +1,9 @@
|
|||
welcome=خوش آمدید
|
||||
required=الزامی
|
||||
notFound=یافت نشد
|
||||
duplicate=قبلا استفاده شده
|
||||
nonNumeric=باید عددی باشد
|
||||
duplicateFormSubmission=ارسال تکراری فرم مجاز نیست
|
||||
typeMismatch.date=تاریخ نامعتبر
|
||||
typeMismatch.birthDate=تاریخ تولد نامعتبر
|
||||
|
8
src/main/resources/messages/messages_pt.properties
Normal file
8
src/main/resources/messages/messages_pt.properties
Normal file
|
@ -0,0 +1,8 @@
|
|||
welcome=Bem-vindo
|
||||
required=E necessario
|
||||
notFound=Nao foi encontrado
|
||||
duplicate=Ja esta em uso
|
||||
nonNumeric=Deve ser tudo numerico
|
||||
duplicateFormSubmission=O envio duplicado de formulario nao e permitido
|
||||
typeMismatch.date=Data invalida
|
||||
typeMismatch.birthDate=Data de nascimento invalida
|
9
src/main/resources/messages/messages_ru.properties
Normal file
9
src/main/resources/messages/messages_ru.properties
Normal file
|
@ -0,0 +1,9 @@
|
|||
welcome=Добро пожаловать
|
||||
required=необходимо
|
||||
notFound=не найдено
|
||||
duplicate=уже используется
|
||||
nonNumeric=должно быть все числовое значение
|
||||
duplicateFormSubmission=Дублирование формы не допускается
|
||||
typeMismatch.date=неправильная даные
|
||||
typeMismatch.birthDate=неправильная дата
|
||||
|
9
src/main/resources/messages/messages_tr.properties
Normal file
9
src/main/resources/messages/messages_tr.properties
Normal file
|
@ -0,0 +1,9 @@
|
|||
welcome=hoş geldiniz
|
||||
required=gerekli
|
||||
notFound=bulunamadı
|
||||
duplicate=zaten kullanılıyor
|
||||
nonNumeric=sadece sayısal olmalıdır
|
||||
duplicateFormSubmission=Formun tekrar gönderilmesine izin verilmez
|
||||
typeMismatch.date=geçersiz tarih
|
||||
typeMismatch.birthDate=geçersiz tarih
|
||||
|
4
src/main/resources/templates/fragments/layout.html
Executable file → Normal file
4
src/main/resources/templates/fragments/layout.html
Executable file → Normal file
|
@ -17,7 +17,7 @@
|
|||
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
||||
<![endif]-->
|
||||
|
||||
<link th:href="@{/webjars/font-awesome/4.7.0/css/font-awesome.min.css}" rel="stylesheet">
|
||||
<link th:href="@{/webjars/font-awesome/css/font-awesome.min.css}" rel="stylesheet">
|
||||
<link rel="stylesheet" th:href="@{/resources/css/petclinic.css}" />
|
||||
|
||||
</head>
|
||||
|
@ -87,7 +87,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<script th:src="@{/webjars/bootstrap/5.3.3/dist/js/bootstrap.bundle.min.js}"></script>
|
||||
<script th:src="@{/webjars/bootstrap/dist/js/bootstrap.bundle.min.js}"></script>
|
||||
|
||||
</body>
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ class MySqlIntegrationTests {
|
|||
|
||||
@ServiceConnection
|
||||
@Container
|
||||
static MySQLContainer<?> container = new MySQLContainer<>("mysql:8.4");
|
||||
static MySQLContainer<?> container = new MySQLContainer<>("mysql:9.1");
|
||||
|
||||
@LocalServerPort
|
||||
int port;
|
||||
|
@ -58,7 +58,7 @@ class MySqlIntegrationTests {
|
|||
private RestTemplateBuilder builder;
|
||||
|
||||
@Test
|
||||
void testFindAll() throws Exception {
|
||||
void testFindAll() {
|
||||
vets.findAll();
|
||||
vets.findAll(); // served from cache
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ public class MysqlTestApplication {
|
|||
@Profile("mysql")
|
||||
@Bean
|
||||
static MySQLContainer<?> container() {
|
||||
return new MySQLContainer<>("mysql:8.4");
|
||||
return new MySQLContainer<>("mysql:9.1");
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
|
|
@ -44,7 +44,7 @@ public class PetClinicIntegrationTests {
|
|||
private RestTemplateBuilder builder;
|
||||
|
||||
@Test
|
||||
void testFindAll() throws Exception {
|
||||
void testFindAll() {
|
||||
vets.findAll();
|
||||
vets.findAll(); // served from cache
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package org.springframework.samples.petclinic;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
@ -48,7 +49,7 @@ import org.springframework.web.client.RestTemplate;
|
|||
import org.testcontainers.DockerClientFactory;
|
||||
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = { "spring.docker.compose.skip.in-tests=false", //
|
||||
"spring.docker.compose.profiles.active=postgres" })
|
||||
"spring.docker.compose.start.arguments=--force-recreate,--renew-anon-volumes,postgres" })
|
||||
@ActiveProfiles("postgres")
|
||||
@DisabledInNativeImage
|
||||
public class PostgresIntegrationTests {
|
||||
|
@ -71,7 +72,7 @@ public class PostgresIntegrationTests {
|
|||
new SpringApplicationBuilder(PetClinicApplication.class) //
|
||||
.profiles("postgres") //
|
||||
.properties( //
|
||||
"spring.docker.compose.profiles.active=postgres" //
|
||||
"spring.docker.compose.start.arguments=postgres" //
|
||||
) //
|
||||
.listeners(new PropertiesLogger()) //
|
||||
.run(args);
|
||||
|
@ -114,7 +115,16 @@ public class PostgresIntegrationTests {
|
|||
Arrays.sort(names);
|
||||
for (String name : names) {
|
||||
String resolved = environment.getProperty(name);
|
||||
String value = source.getProperty(name).toString();
|
||||
|
||||
assertNotNull(resolved, "resolved environment property: " + name + " is null.");
|
||||
|
||||
Object sourceProperty = source.getProperty(name);
|
||||
|
||||
assertNotNull(sourceProperty, "source property was expecting an object but is null.");
|
||||
|
||||
assertNotNull(sourceProperty.toString(), "source property toString() returned null.");
|
||||
|
||||
String value = sourceProperty.toString();
|
||||
if (resolved.equals(value)) {
|
||||
log.info(name + "=" + resolved);
|
||||
}
|
||||
|
|
|
@ -20,17 +20,18 @@ import org.assertj.core.util.Lists;
|
|||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.DisabledInNativeImage;
|
||||
import org.mockito.Mockito;
|
||||
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.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.test.context.aot.DisabledInAotMode;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
|
@ -43,16 +44,16 @@ import static org.mockito.ArgumentMatchers.any;
|
|||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.when;
|
||||
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.result.MockMvcResultMatchers.model;
|
||||
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.*;
|
||||
|
||||
/**
|
||||
* Test class for {@link OwnerController}
|
||||
*
|
||||
* @author Colin But
|
||||
* @author Wick Dynex
|
||||
*/
|
||||
@WebMvcTest(OwnerController.class)
|
||||
@DisabledInNativeImage
|
||||
|
@ -64,7 +65,7 @@ class OwnerControllerTests {
|
|||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@MockBean
|
||||
@MockitoBean
|
||||
private OwnerRepository owners;
|
||||
|
||||
private Owner george() {
|
||||
|
@ -90,12 +91,12 @@ class OwnerControllerTests {
|
|||
void setup() {
|
||||
|
||||
Owner george = george();
|
||||
given(this.owners.findByLastName(eq("Franklin"), any(Pageable.class)))
|
||||
given(this.owners.findByLastNameStartingWith(eq("Franklin"), any(Pageable.class)))
|
||||
.willReturn(new PageImpl<>(Lists.newArrayList(george)));
|
||||
|
||||
given(this.owners.findAll(any(Pageable.class))).willReturn(new PageImpl<>(Lists.newArrayList(george)));
|
||||
|
||||
given(this.owners.findById(TEST_OWNER_ID)).willReturn(george);
|
||||
given(this.owners.findById(TEST_OWNER_ID)).willReturn(Optional.of(george));
|
||||
Visit visit = new Visit();
|
||||
visit.setDate(LocalDate.now());
|
||||
george.getPet("Max").getVisits().add(visit);
|
||||
|
@ -143,14 +144,14 @@ class OwnerControllerTests {
|
|||
@Test
|
||||
void testProcessFindFormSuccess() throws Exception {
|
||||
Page<Owner> tasks = new PageImpl<>(Lists.newArrayList(george(), new Owner()));
|
||||
Mockito.when(this.owners.findByLastName(anyString(), any(Pageable.class))).thenReturn(tasks);
|
||||
when(this.owners.findByLastNameStartingWith(anyString(), any(Pageable.class))).thenReturn(tasks);
|
||||
mockMvc.perform(get("/owners?page=1")).andExpect(status().isOk()).andExpect(view().name("owners/ownersList"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testProcessFindFormByLastName() throws Exception {
|
||||
Page<Owner> tasks = new PageImpl<>(Lists.newArrayList(george()));
|
||||
Mockito.when(this.owners.findByLastName(eq("Franklin"), any(Pageable.class))).thenReturn(tasks);
|
||||
when(this.owners.findByLastNameStartingWith(eq("Franklin"), any(Pageable.class))).thenReturn(tasks);
|
||||
mockMvc.perform(get("/owners?page=1").param("lastName", "Franklin"))
|
||||
.andExpect(status().is3xxRedirection())
|
||||
.andExpect(view().name("redirect:/owners/" + TEST_OWNER_ID));
|
||||
|
@ -159,7 +160,7 @@ class OwnerControllerTests {
|
|||
@Test
|
||||
void testProcessFindFormNoOwnersFound() throws Exception {
|
||||
Page<Owner> tasks = new PageImpl<>(Lists.newArrayList());
|
||||
Mockito.when(this.owners.findByLastName(eq("Unknown Surname"), any(Pageable.class))).thenReturn(tasks);
|
||||
when(this.owners.findByLastNameStartingWith(eq("Unknown Surname"), any(Pageable.class))).thenReturn(tasks);
|
||||
mockMvc.perform(get("/owners?page=1").param("lastName", "Unknown Surname"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(model().attributeHasFieldErrors("owner", "lastName"))
|
||||
|
@ -229,4 +230,24 @@ class OwnerControllerTests {
|
|||
.andExpect(view().name("owners/ownerDetails"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcessUpdateOwnerFormWithIdMismatch() throws Exception {
|
||||
int pathOwnerId = 1;
|
||||
|
||||
Owner owner = new Owner();
|
||||
owner.setId(2);
|
||||
owner.setFirstName("John");
|
||||
owner.setLastName("Doe");
|
||||
owner.setAddress("Center Street");
|
||||
owner.setCity("New York");
|
||||
owner.setTelephone("0123456789");
|
||||
|
||||
when(owners.findById(pathOwnerId)).thenReturn(Optional.of(owner));
|
||||
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/owners/{ownerId}/edit", pathOwnerId).flashAttr("owner", owner))
|
||||
.andExpect(status().is3xxRedirection())
|
||||
.andExpect(redirectedUrl("/owners/" + pathOwnerId + "/edit"))
|
||||
.andExpect(flash().attributeExists("error"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
136
src/test/java/org/springframework/samples/petclinic/owner/PetControllerTests.java
Executable file → Normal file
136
src/test/java/org/springframework/samples/petclinic/owner/PetControllerTests.java
Executable file → Normal file
|
@ -18,16 +18,20 @@ package org.springframework.samples.petclinic.owner;
|
|||
|
||||
import org.assertj.core.util.Lists;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.DisabledInNativeImage;
|
||||
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.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.FilterType;
|
||||
import org.springframework.test.context.aot.DisabledInAotMode;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.Optional;
|
||||
|
||||
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.post;
|
||||
|
@ -39,6 +43,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
|||
* Test class for the {@link PetController}
|
||||
*
|
||||
* @author Colin But
|
||||
* @author Wick Dynex
|
||||
*/
|
||||
@WebMvcTest(value = PetController.class,
|
||||
includeFilters = @ComponentScan.Filter(value = PetTypeFormatter.class, type = FilterType.ASSIGNABLE_TYPE))
|
||||
|
@ -53,7 +58,7 @@ class PetControllerTests {
|
|||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@MockBean
|
||||
@MockitoBean
|
||||
private OwnerRepository owners;
|
||||
|
||||
@BeforeEach
|
||||
|
@ -62,11 +67,17 @@ class PetControllerTests {
|
|||
cat.setId(3);
|
||||
cat.setName("hamster");
|
||||
given(this.owners.findPetTypes()).willReturn(Lists.newArrayList(cat));
|
||||
|
||||
Owner owner = new Owner();
|
||||
Pet pet = new Pet();
|
||||
Pet dog = new Pet();
|
||||
owner.addPet(pet);
|
||||
owner.addPet(dog);
|
||||
pet.setId(TEST_PET_ID);
|
||||
given(this.owners.findById(TEST_OWNER_ID)).willReturn(owner);
|
||||
dog.setId(TEST_PET_ID + 1);
|
||||
pet.setName("petty");
|
||||
dog.setName("doggy");
|
||||
given(this.owners.findById(TEST_OWNER_ID)).willReturn(Optional.of(owner));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -87,25 +98,72 @@ class PetControllerTests {
|
|||
.andExpect(view().name("redirect:/owners/{ownerId}"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testProcessCreationFormHasErrors() throws Exception {
|
||||
mockMvc
|
||||
.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID).param("name", "Betty")
|
||||
.param("birthDate", "2015-02-12"))
|
||||
.andExpect(model().attributeHasNoErrors("owner"))
|
||||
.andExpect(model().attributeHasErrors("pet"))
|
||||
.andExpect(model().attributeHasFieldErrors("pet", "type"))
|
||||
.andExpect(model().attributeHasFieldErrorCode("pet", "type", "required"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(view().name("pets/createOrUpdatePetForm"));
|
||||
}
|
||||
@Nested
|
||||
class ProcessCreationFormHasErrors {
|
||||
|
||||
@Test
|
||||
void testProcessCreationFormWithBlankName() throws Exception {
|
||||
mockMvc
|
||||
.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID).param("name", "\t \n")
|
||||
.param("birthDate", "2015-02-12"))
|
||||
.andExpect(model().attributeHasNoErrors("owner"))
|
||||
.andExpect(model().attributeHasErrors("pet"))
|
||||
.andExpect(model().attributeHasFieldErrors("pet", "name"))
|
||||
.andExpect(model().attributeHasFieldErrorCode("pet", "name", "required"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(view().name("pets/createOrUpdatePetForm"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testProcessCreationFormWithDuplicateName() throws Exception {
|
||||
mockMvc
|
||||
.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID).param("name", "petty")
|
||||
.param("birthDate", "2015-02-12"))
|
||||
.andExpect(model().attributeHasNoErrors("owner"))
|
||||
.andExpect(model().attributeHasErrors("pet"))
|
||||
.andExpect(model().attributeHasFieldErrors("pet", "name"))
|
||||
.andExpect(model().attributeHasFieldErrorCode("pet", "name", "duplicate"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(view().name("pets/createOrUpdatePetForm"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testProcessCreationFormWithMissingPetType() throws Exception {
|
||||
mockMvc
|
||||
.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID).param("name", "Betty")
|
||||
.param("birthDate", "2015-02-12"))
|
||||
.andExpect(model().attributeHasNoErrors("owner"))
|
||||
.andExpect(model().attributeHasErrors("pet"))
|
||||
.andExpect(model().attributeHasFieldErrors("pet", "type"))
|
||||
.andExpect(model().attributeHasFieldErrorCode("pet", "type", "required"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(view().name("pets/createOrUpdatePetForm"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testProcessCreationFormWithInvalidBirthDate() throws Exception {
|
||||
LocalDate currentDate = LocalDate.now();
|
||||
String futureBirthDate = currentDate.plusMonths(1).toString();
|
||||
|
||||
mockMvc
|
||||
.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID).param("name", "Betty")
|
||||
.param("birthDate", futureBirthDate))
|
||||
.andExpect(model().attributeHasNoErrors("owner"))
|
||||
.andExpect(model().attributeHasErrors("pet"))
|
||||
.andExpect(model().attributeHasFieldErrors("pet", "birthDate"))
|
||||
.andExpect(model().attributeHasFieldErrorCode("pet", "birthDate", "typeMismatch.birthDate"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(view().name("pets/createOrUpdatePetForm"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitUpdateForm() throws Exception {
|
||||
mockMvc.perform(get("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(model().attributeExists("pet"))
|
||||
.andExpect(view().name("pets/createOrUpdatePetForm"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitUpdateForm() throws Exception {
|
||||
mockMvc.perform(get("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(model().attributeExists("pet"))
|
||||
.andExpect(view().name("pets/createOrUpdatePetForm"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -118,15 +176,33 @@ class PetControllerTests {
|
|||
.andExpect(view().name("redirect:/owners/{ownerId}"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testProcessUpdateFormHasErrors() throws Exception {
|
||||
mockMvc
|
||||
.perform(post("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID).param("name", "Betty")
|
||||
.param("birthDate", "2015/02/12"))
|
||||
.andExpect(model().attributeHasNoErrors("owner"))
|
||||
.andExpect(model().attributeHasErrors("pet"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(view().name("pets/createOrUpdatePetForm"));
|
||||
@Nested
|
||||
class ProcessUpdateFormHasErrors {
|
||||
|
||||
@Test
|
||||
void testProcessUpdateFormWithInvalidBirthDate() throws Exception {
|
||||
mockMvc
|
||||
.perform(post("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID).param("name", " ")
|
||||
.param("birthDate", "2015/02/12"))
|
||||
.andExpect(model().attributeHasNoErrors("owner"))
|
||||
.andExpect(model().attributeHasErrors("pet"))
|
||||
.andExpect(model().attributeHasFieldErrors("pet", "birthDate"))
|
||||
.andExpect(model().attributeHasFieldErrorCode("pet", "birthDate", "typeMismatch"))
|
||||
.andExpect(view().name("pets/createOrUpdatePetForm"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testProcessUpdateFormWithBlankName() throws Exception {
|
||||
mockMvc
|
||||
.perform(post("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID).param("name", " ")
|
||||
.param("birthDate", "2015-02-12"))
|
||||
.andExpect(model().attributeHasNoErrors("owner"))
|
||||
.andExpect(model().attributeHasErrors("pet"))
|
||||
.andExpect(model().attributeHasFieldErrors("pet", "name"))
|
||||
.andExpect(model().attributeHasFieldErrorCode("pet", "name", "required"))
|
||||
.andExpect(view().name("pets/createOrUpdatePetForm"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ class PetTypeFormatterTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowParseException() throws ParseException {
|
||||
void shouldThrowParseException() {
|
||||
given(this.pets.findPetTypes()).willReturn(makePetTypes());
|
||||
Assertions.assertThrows(ParseException.class, () -> {
|
||||
petTypeFormatter.parse("Fish", Locale.ENGLISH);
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.samples.petclinic.owner;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.DisabledInNativeImage;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.MapBindingResult;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.HashMap;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* Test class for {@link PetValidator}
|
||||
*
|
||||
* @author Wick Dynex
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@DisabledInNativeImage
|
||||
public class PetValidatorTests {
|
||||
|
||||
private PetValidator petValidator;
|
||||
|
||||
private Pet pet;
|
||||
|
||||
private PetType petType;
|
||||
|
||||
private Errors errors;
|
||||
|
||||
private static final String petName = "Buddy";
|
||||
|
||||
private static final String petTypeName = "Dog";
|
||||
|
||||
private static final LocalDate petBirthDate = LocalDate.of(1990, 1, 1);
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
petValidator = new PetValidator();
|
||||
pet = new Pet();
|
||||
petType = new PetType();
|
||||
errors = new MapBindingResult(new HashMap<>(), "pet");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidate() {
|
||||
petType.setName(petTypeName);
|
||||
pet.setName(petName);
|
||||
pet.setType(petType);
|
||||
pet.setBirthDate(petBirthDate);
|
||||
|
||||
petValidator.validate(pet, errors);
|
||||
|
||||
assertFalse(errors.hasErrors());
|
||||
}
|
||||
|
||||
@Nested
|
||||
class ValidateHasErrors {
|
||||
|
||||
@Test
|
||||
void testValidateWithInvalidPetName() {
|
||||
petType.setName(petTypeName);
|
||||
pet.setName("");
|
||||
pet.setType(petType);
|
||||
pet.setBirthDate(petBirthDate);
|
||||
|
||||
petValidator.validate(pet, errors);
|
||||
|
||||
assertTrue(errors.hasFieldErrors("name"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidateWithInvalidPetType() {
|
||||
pet.setName(petName);
|
||||
pet.setType(null);
|
||||
pet.setBirthDate(petBirthDate);
|
||||
|
||||
petValidator.validate(pet, errors);
|
||||
|
||||
assertTrue(errors.hasFieldErrors("type"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidateWithInvalidBirthDate() {
|
||||
petType.setName(petTypeName);
|
||||
pet.setName(petName);
|
||||
pet.setType(petType);
|
||||
pet.setBirthDate(null);
|
||||
|
||||
petValidator.validate(pet, errors);
|
||||
|
||||
assertTrue(errors.hasFieldErrors("birthDate"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -28,14 +28,17 @@ import org.junit.jupiter.api.Test;
|
|||
import org.junit.jupiter.api.condition.DisabledInNativeImage;
|
||||
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.test.context.aot.DisabledInAotMode;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Test class for {@link VisitController}
|
||||
*
|
||||
* @author Colin But
|
||||
* @author Wick Dynex
|
||||
*/
|
||||
@WebMvcTest(VisitController.class)
|
||||
@DisabledInNativeImage
|
||||
|
@ -49,7 +52,7 @@ class VisitControllerTests {
|
|||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@MockBean
|
||||
@MockitoBean
|
||||
private OwnerRepository owners;
|
||||
|
||||
@BeforeEach
|
||||
|
@ -58,7 +61,7 @@ class VisitControllerTests {
|
|||
Pet pet = new Pet();
|
||||
owner.addPet(pet);
|
||||
pet.setId(TEST_PET_ID);
|
||||
given(this.owners.findById(TEST_OWNER_ID)).willReturn(owner);
|
||||
given(this.owners.findById(TEST_OWNER_ID)).willReturn(Optional.of(owner));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -20,13 +20,13 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
|
||||
import java.time.LocalDate;
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
|
||||
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace;
|
||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.samples.petclinic.owner.Owner;
|
||||
|
@ -36,7 +36,6 @@ import org.springframework.samples.petclinic.owner.PetType;
|
|||
import org.springframework.samples.petclinic.owner.Visit;
|
||||
import org.springframework.samples.petclinic.vet.Vet;
|
||||
import org.springframework.samples.petclinic.vet.VetRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
|
@ -67,7 +66,7 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
* @author Michael Isvy
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@DataJpaTest(includeFilters = @ComponentScan.Filter(Service.class))
|
||||
@DataJpaTest
|
||||
// Ensure that if the mysql profile is active we connect to the real database:
|
||||
@AutoConfigureTestDatabase(replace = Replace.NONE)
|
||||
// @TestPropertySource("/application-postgres.properties")
|
||||
|
@ -83,16 +82,18 @@ class ClinicServiceTests {
|
|||
|
||||
@Test
|
||||
void shouldFindOwnersByLastName() {
|
||||
Page<Owner> owners = this.owners.findByLastName("Davis", pageable);
|
||||
Page<Owner> owners = this.owners.findByLastNameStartingWith("Davis", pageable);
|
||||
assertThat(owners).hasSize(2);
|
||||
|
||||
owners = this.owners.findByLastName("Daviss", pageable);
|
||||
owners = this.owners.findByLastNameStartingWith("Daviss", pageable);
|
||||
assertThat(owners).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldFindSingleOwnerWithPet() {
|
||||
Owner owner = this.owners.findById(1);
|
||||
Optional<Owner> optionalOwner = this.owners.findById(1);
|
||||
assertThat(optionalOwner).isPresent();
|
||||
Owner owner = optionalOwner.get();
|
||||
assertThat(owner.getLastName()).startsWith("Franklin");
|
||||
assertThat(owner.getPets()).hasSize(1);
|
||||
assertThat(owner.getPets().get(0).getType()).isNotNull();
|
||||
|
@ -102,7 +103,7 @@ class ClinicServiceTests {
|
|||
@Test
|
||||
@Transactional
|
||||
void shouldInsertOwner() {
|
||||
Page<Owner> owners = this.owners.findByLastName("Schultz", pageable);
|
||||
Page<Owner> owners = this.owners.findByLastNameStartingWith("Schultz", pageable);
|
||||
int found = (int) owners.getTotalElements();
|
||||
|
||||
Owner owner = new Owner();
|
||||
|
@ -114,14 +115,16 @@ class ClinicServiceTests {
|
|||
this.owners.save(owner);
|
||||
assertThat(owner.getId()).isNotZero();
|
||||
|
||||
owners = this.owners.findByLastName("Schultz", pageable);
|
||||
owners = this.owners.findByLastNameStartingWith("Schultz", pageable);
|
||||
assertThat(owners.getTotalElements()).isEqualTo(found + 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Transactional
|
||||
void shouldUpdateOwner() {
|
||||
Owner owner = this.owners.findById(1);
|
||||
Optional<Owner> optionalOwner = this.owners.findById(1);
|
||||
assertThat(optionalOwner).isPresent();
|
||||
Owner owner = optionalOwner.get();
|
||||
String oldLastName = owner.getLastName();
|
||||
String newLastName = oldLastName + "X";
|
||||
|
||||
|
@ -129,7 +132,9 @@ class ClinicServiceTests {
|
|||
this.owners.save(owner);
|
||||
|
||||
// retrieving new name from database
|
||||
owner = this.owners.findById(1);
|
||||
optionalOwner = this.owners.findById(1);
|
||||
assertThat(optionalOwner).isPresent();
|
||||
owner = optionalOwner.get();
|
||||
assertThat(owner.getLastName()).isEqualTo(newLastName);
|
||||
}
|
||||
|
||||
|
@ -146,7 +151,10 @@ class ClinicServiceTests {
|
|||
@Test
|
||||
@Transactional
|
||||
void shouldInsertPetIntoDatabaseAndGenerateId() {
|
||||
Owner owner6 = this.owners.findById(6);
|
||||
Optional<Owner> optionalOwner = this.owners.findById(6);
|
||||
assertThat(optionalOwner).isPresent();
|
||||
Owner owner6 = optionalOwner.get();
|
||||
|
||||
int found = owner6.getPets().size();
|
||||
|
||||
Pet pet = new Pet();
|
||||
|
@ -159,7 +167,9 @@ class ClinicServiceTests {
|
|||
|
||||
this.owners.save(owner6);
|
||||
|
||||
owner6 = this.owners.findById(6);
|
||||
optionalOwner = this.owners.findById(6);
|
||||
assertThat(optionalOwner).isPresent();
|
||||
owner6 = optionalOwner.get();
|
||||
assertThat(owner6.getPets()).hasSize(found + 1);
|
||||
// checks that id has been generated
|
||||
pet = owner6.getPet("bowser");
|
||||
|
@ -169,7 +179,10 @@ class ClinicServiceTests {
|
|||
@Test
|
||||
@Transactional
|
||||
void shouldUpdatePetName() {
|
||||
Owner owner6 = this.owners.findById(6);
|
||||
Optional<Owner> optionalOwner = this.owners.findById(6);
|
||||
assertThat(optionalOwner).isPresent();
|
||||
Owner owner6 = optionalOwner.get();
|
||||
|
||||
Pet pet7 = owner6.getPet(7);
|
||||
String oldName = pet7.getName();
|
||||
|
||||
|
@ -177,7 +190,9 @@ class ClinicServiceTests {
|
|||
pet7.setName(newName);
|
||||
this.owners.save(owner6);
|
||||
|
||||
owner6 = this.owners.findById(6);
|
||||
optionalOwner = this.owners.findById(6);
|
||||
assertThat(optionalOwner).isPresent();
|
||||
owner6 = optionalOwner.get();
|
||||
pet7 = owner6.getPet(7);
|
||||
assertThat(pet7.getName()).isEqualTo(newName);
|
||||
}
|
||||
|
@ -196,7 +211,10 @@ class ClinicServiceTests {
|
|||
@Test
|
||||
@Transactional
|
||||
void shouldAddNewVisitForPet() {
|
||||
Owner owner6 = this.owners.findById(6);
|
||||
Optional<Owner> optionalOwner = this.owners.findById(6);
|
||||
assertThat(optionalOwner).isPresent();
|
||||
Owner owner6 = optionalOwner.get();
|
||||
|
||||
Pet pet7 = owner6.getPet(7);
|
||||
int found = pet7.getVisits().size();
|
||||
Visit visit = new Visit();
|
||||
|
@ -205,8 +223,6 @@ class ClinicServiceTests {
|
|||
owner6.addVisit(pet7.getId(), visit);
|
||||
this.owners.save(owner6);
|
||||
|
||||
owner6 = this.owners.findById(6);
|
||||
|
||||
assertThat(pet7.getVisits()) //
|
||||
.hasSize(found + 1) //
|
||||
.allMatch(value -> value.getId() != null);
|
||||
|
@ -214,7 +230,10 @@ class ClinicServiceTests {
|
|||
|
||||
@Test
|
||||
void shouldFindVisitsByPetId() {
|
||||
Owner owner6 = this.owners.findById(6);
|
||||
Optional<Owner> optionalOwner = this.owners.findById(6);
|
||||
assertThat(optionalOwner).isPresent();
|
||||
Owner owner6 = optionalOwner.get();
|
||||
|
||||
Pet pet7 = owner6.getPet(7);
|
||||
Collection<Visit> visits = pet7.getVisits();
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
|||
// luck ((plain(st) UNIT test)! :)
|
||||
class CrashControllerTests {
|
||||
|
||||
CrashController testee = new CrashController();
|
||||
final CrashController testee = new CrashController();
|
||||
|
||||
@Test
|
||||
void testTriggerException() {
|
||||
|
|
|
@ -22,11 +22,11 @@ import org.junit.jupiter.api.Test;
|
|||
import org.junit.jupiter.api.condition.DisabledInNativeImage;
|
||||
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.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.aot.DisabledInAotMode;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
|
@ -48,7 +48,7 @@ class VetControllerTests {
|
|||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@MockBean
|
||||
@MockitoBean
|
||||
private VetRepository vets;
|
||||
|
||||
private Vet james() {
|
||||
|
|
|
@ -156,8 +156,7 @@
|
|||
<stringProp name="HTTPSampler.response_timeout"></stringProp>
|
||||
<stringProp name="HTTPSampler.protocol"></stringProp>
|
||||
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
|
||||
<stringProp name="HTTPSampler.path">
|
||||
${CONTEXT_WEB}/webjars/bootstrap/5.3.3/dist/js/bootstrap.bundle.min.js</stringProp>
|
||||
<stringProp name="HTTPSampler.path">${CONTEXT_WEB}/webjars/bootstrap/dist/js/bootstrap.bundle.min.js</stringProp>
|
||||
<stringProp name="HTTPSampler.method">GET</stringProp>
|
||||
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
|
||||
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
|
||||
|
@ -420,8 +419,7 @@
|
|||
<stringProp name="HTTPSampler.port"></stringProp>
|
||||
<stringProp name="HTTPSampler.protocol"></stringProp>
|
||||
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
|
||||
<stringProp name="HTTPSampler.path">
|
||||
${CONTEXT_WEB}/owners/${count}/pets/${petCount}/visits/new</stringProp>
|
||||
<stringProp name="HTTPSampler.path">${CONTEXT_WEB}/owners/${count}/pets/${petCount}/visits/new</stringProp>
|
||||
<stringProp name="HTTPSampler.method">GET</stringProp>
|
||||
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
|
||||
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
|
||||
|
@ -458,8 +456,7 @@
|
|||
<stringProp name="HTTPSampler.port"></stringProp>
|
||||
<stringProp name="HTTPSampler.protocol"></stringProp>
|
||||
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
|
||||
<stringProp name="HTTPSampler.path">
|
||||
${CONTEXT_WEB}/owners/${count}/pets/${petCount}/visits/new</stringProp>
|
||||
<stringProp name="HTTPSampler.path">${CONTEXT_WEB}/owners/${count}/pets/${petCount}/visits/new</stringProp>
|
||||
<stringProp name="HTTPSampler.method">POST</stringProp>
|
||||
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
|
||||
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
|
||||
|
@ -540,4 +537,4 @@
|
|||
</hashTree>
|
||||
</hashTree>
|
||||
</hashTree>
|
||||
</jmeterTestPlan>
|
||||
</jmeterTestPlan>
|
||||
|
|
Loading…
Reference in a new issue