├── .gitignore ├── README.md ├── images ├── Architecture.png ├── Cloud9.png ├── c9attachrole.png ├── c9disableiam.png ├── c9instancerole.png ├── createrole.png ├── docker-local-run.png └── petclinic.png ├── petclinic ├── Dockerfile ├── docker-compose.yml ├── pom.xml ├── readme.md └── src │ ├── checkstyle │ ├── nohttp-checkstyle-suppressions.xml │ └── nohttp-checkstyle.xml │ ├── main │ ├── java │ │ └── org │ │ │ └── springframework │ │ │ └── samples │ │ │ └── petclinic │ │ │ ├── PetClinicApplication.java │ │ │ ├── model │ │ │ ├── BaseEntity.java │ │ │ ├── NamedEntity.java │ │ │ ├── Person.java │ │ │ └── package-info.java │ │ │ ├── owner │ │ │ ├── Owner.java │ │ │ ├── OwnerController.java │ │ │ ├── OwnerRepository.java │ │ │ ├── Pet.java │ │ │ ├── PetController.java │ │ │ ├── PetRepository.java │ │ │ ├── PetType.java │ │ │ ├── PetTypeFormatter.java │ │ │ ├── PetValidator.java │ │ │ └── VisitController.java │ │ │ ├── system │ │ │ ├── CacheConfiguration.java │ │ │ ├── CrashController.java │ │ │ └── WelcomeController.java │ │ │ ├── vet │ │ │ ├── Specialty.java │ │ │ ├── Vet.java │ │ │ ├── VetController.java │ │ │ ├── VetRepository.java │ │ │ └── Vets.java │ │ │ └── visit │ │ │ ├── Visit.java │ │ │ └── VisitRepository.java │ ├── less │ │ ├── header.less │ │ ├── petclinic.less │ │ ├── responsive.less │ │ └── typography.less │ ├── resources │ │ ├── application-mysql.properties │ │ ├── application.properties │ │ ├── banner.txt │ │ ├── db │ │ │ ├── h2 │ │ │ │ ├── data.sql │ │ │ │ └── schema.sql │ │ │ ├── hsqldb │ │ │ │ ├── data.sql │ │ │ │ └── schema.sql │ │ │ └── mysql │ │ │ │ ├── data.sql │ │ │ │ ├── petclinic_db_setup_mysql.txt │ │ │ │ ├── schema.sql │ │ │ │ └── user.sql │ │ ├── messages │ │ │ ├── messages.properties │ │ │ ├── messages_de.properties │ │ │ ├── messages_en.properties │ │ │ └── messages_es.properties │ │ ├── static │ │ │ └── resources │ │ │ │ ├── fonts │ │ │ │ ├── montserrat-webfont.eot │ │ │ │ ├── montserrat-webfont.svg │ │ │ │ ├── montserrat-webfont.ttf │ │ │ │ ├── montserrat-webfont.woff │ │ │ │ ├── varela_round-webfont.eot │ │ │ │ ├── varela_round-webfont.svg │ │ │ │ ├── varela_round-webfont.ttf │ │ │ │ └── varela_round-webfont.woff │ │ │ │ └── images │ │ │ │ ├── favicon.png │ │ │ │ ├── pets.png │ │ │ │ ├── platform-bg.png │ │ │ │ ├── spring-logo-dataflow-mobile.png │ │ │ │ ├── spring-logo-dataflow.png │ │ │ │ └── spring-pivotal-logo.png │ │ └── templates │ │ │ ├── error.html │ │ │ ├── fragments │ │ │ ├── inputField.html │ │ │ ├── layout.html │ │ │ └── selectField.html │ │ │ ├── owners │ │ │ ├── createOrUpdateOwnerForm.html │ │ │ ├── findOwners.html │ │ │ ├── ownerDetails.html │ │ │ └── ownersList.html │ │ │ ├── pets │ │ │ ├── createOrUpdatePetForm.html │ │ │ └── createOrUpdateVisitForm.html │ │ │ ├── vets │ │ │ └── vetList.html │ │ │ └── welcome.html │ └── wro │ │ ├── wro.properties │ │ └── wro.xml │ └── test │ ├── java │ └── org │ │ └── springframework │ │ └── samples │ │ └── petclinic │ │ ├── PetclinicIntegrationTests.java │ │ ├── model │ │ └── ValidatorTests.java │ │ ├── owner │ │ ├── OwnerControllerTests.java │ │ ├── PetControllerTests.java │ │ ├── PetTypeFormatterTests.java │ │ └── VisitControllerTests.java │ │ ├── service │ │ ├── ClinicServiceTests.java │ │ └── EntityUtils.java │ │ ├── system │ │ └── CrashControllerTests.java │ │ └── vet │ │ ├── VetControllerTests.java │ │ └── VetTests.java │ └── jmeter │ └── petclinic_test_plan.jmx └── terraform ├── appbuild.tf ├── autoscaling.tf ├── codebuild.tf ├── codecommit.tf ├── codepipeline.tf ├── ecr.tf ├── iam.tf ├── parameters.tf ├── provider.tf ├── push2codecommit.tf ├── rds.tf ├── security-groups.tf ├── services.tf ├── terraform.tfvars ├── variables.tf └── vpc.tf /.gitignore: -------------------------------------------------------------------------------- 1 | **/.terraform/** 2 | terraform.tfstate 3 | terraform.tfstate.backup 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /images/Architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-apprunner-terraform/f000687a298a05ec24581325d5325ed4e6e4c666/images/Architecture.png -------------------------------------------------------------------------------- /images/Cloud9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-apprunner-terraform/f000687a298a05ec24581325d5325ed4e6e4c666/images/Cloud9.png -------------------------------------------------------------------------------- /images/c9attachrole.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-apprunner-terraform/f000687a298a05ec24581325d5325ed4e6e4c666/images/c9attachrole.png -------------------------------------------------------------------------------- /images/c9disableiam.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-apprunner-terraform/f000687a298a05ec24581325d5325ed4e6e4c666/images/c9disableiam.png -------------------------------------------------------------------------------- /images/c9instancerole.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-apprunner-terraform/f000687a298a05ec24581325d5325ed4e6e4c666/images/c9instancerole.png -------------------------------------------------------------------------------- /images/createrole.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-apprunner-terraform/f000687a298a05ec24581325d5325ed4e6e4c666/images/createrole.png -------------------------------------------------------------------------------- /images/docker-local-run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-apprunner-terraform/f000687a298a05ec24581325d5325ed4e6e4c666/images/docker-local-run.png -------------------------------------------------------------------------------- /images/petclinic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-apprunner-terraform/f000687a298a05ec24581325d5325ed4e6e4c666/images/petclinic.png -------------------------------------------------------------------------------- /petclinic/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/bitnami/java:latest 2 | VOLUME /tmp 3 | ADD target/spring-petclinic-2.3.0.jar app.jar 4 | EXPOSE 80 5 | RUN apt-get update 6 | RUN apt-get -y install awscli 7 | ENTRYPOINT env spring.datasource.password=$(aws ssm get-parameter --name /database/password --with-decrypt --region $AWS_REGION | grep Value | cut -d '"' -f4) java -Djava.security.egd=file:/dev/./urandom -jar /app.jar 8 | -------------------------------------------------------------------------------- /petclinic/docker-compose.yml: -------------------------------------------------------------------------------- 1 | mysql: 2 | image: mysql:5.7 3 | ports: 4 | - "3306:3306" 5 | environment: 6 | - MYSQL_ROOT_PASSWORD=petclinic 7 | - MYSQL_ALLOW_EMPTY_PASSWORD=true 8 | - MYSQL_USER=petclinic 9 | - MYSQL_PASSWORD=petclinic 10 | - MYSQL_DATABASE=petclinic 11 | volumes: 12 | - "./conf.d:/etc/mysql/conf.d:ro" 13 | -------------------------------------------------------------------------------- /petclinic/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | org.springframework.samples 7 | spring-petclinic 8 | 2.3.0 9 | 10 | 11 | org.springframework.boot 12 | spring-boot-starter-parent 13 | 2.3.3.RELEASE 14 | 15 | petclinic 16 | 17 | 18 | 19 | 20 | 1.8 21 | UTF-8 22 | UTF-8 23 | 24 | 25 | 3.3.6 26 | 1.11.4 27 | 2.2.4 28 | 1.8.0 29 | 30 | 0.8.5 31 | 0.0.4.RELEASE 32 | 0.0.25 33 | 34 | 35 | 36 | 37 | 38 | org.springframework.boot 39 | spring-boot-starter-actuator 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-starter-cache 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-starter-data-jpa 48 | 49 | 50 | org.springframework.boot 51 | spring-boot-starter-web 52 | 53 | 54 | org.springframework.boot 55 | spring-boot-starter-validation 56 | 57 | 58 | org.springframework.boot 59 | spring-boot-starter-thymeleaf 60 | 61 | 62 | org.springframework.boot 63 | spring-boot-starter-test 64 | test 65 | 66 | 67 | org.junit.vintage 68 | junit-vintage-engine 69 | 70 | 71 | 72 | 73 | 74 | 75 | com.h2database 76 | h2 77 | runtime 78 | 79 | 80 | mysql 81 | mysql-connector-java 82 | runtime 83 | 84 | 85 | 86 | 87 | javax.cache 88 | cache-api 89 | 90 | 91 | org.ehcache 92 | ehcache 93 | 94 | 95 | 96 | 97 | org.webjars 98 | webjars-locator-core 99 | 100 | 101 | org.webjars 102 | jquery 103 | ${webjars-jquery.version} 104 | 105 | 106 | org.webjars 107 | jquery-ui 108 | ${webjars-jquery-ui.version} 109 | 110 | 111 | org.webjars 112 | bootstrap 113 | ${webjars-bootstrap.version} 114 | 115 | 116 | 117 | 118 | 119 | org.junit.jupiter 120 | junit-jupiter-engine 121 | test 122 | 123 | 124 | org.mockito 125 | mockito-junit-jupiter 126 | test 127 | 128 | 129 | 130 | org.springframework.boot 131 | spring-boot-devtools 132 | true 133 | 134 | 135 | 136 | 137 | 138 | 139 | io.spring.javaformat 140 | spring-javaformat-maven-plugin 141 | ${spring-format.version} 142 | 143 | 144 | validate 145 | 146 | validate 147 | 148 | 149 | 150 | 151 | 152 | org.apache.maven.plugins 153 | maven-checkstyle-plugin 154 | 3.1.1 155 | 156 | 157 | com.puppycrawl.tools 158 | checkstyle 159 | 8.32 160 | 161 | 162 | io.spring.nohttp 163 | nohttp-checkstyle 164 | ${nohttp-checkstyle.version} 165 | 166 | 167 | 168 | 169 | nohttp-checkstyle-validation 170 | validate 171 | 172 | src/checkstyle/nohttp-checkstyle.xml 173 | src/checkstyle/nohttp-checkstyle-suppressions.xml 174 | UTF-8 175 | ${basedir} 176 | **/* 177 | **/.git/**/*,**/.idea/**/*,**/target/**/,**/.flattened-pom.xml,**/*.class 178 | 179 | 180 | check 181 | 182 | 183 | 184 | 185 | 186 | org.springframework.boot 187 | spring-boot-maven-plugin 188 | 189 | 190 | 192 | 193 | build-info 194 | 195 | 196 | 197 | ${project.build.sourceEncoding} 198 | ${project.reporting.outputEncoding} 199 | ${maven.compiler.source} 200 | ${maven.compiler.target} 201 | 202 | 203 | 204 | 205 | 206 | 207 | org.jacoco 208 | jacoco-maven-plugin 209 | ${jacoco.version} 210 | 211 | 212 | 213 | prepare-agent 214 | 215 | 216 | 217 | report 218 | prepare-package 219 | 220 | report 221 | 222 | 223 | 224 | 225 | 226 | 228 | 229 | pl.project13.maven 230 | git-commit-id-plugin 231 | 232 | 233 | 234 | revision 235 | 236 | 237 | 238 | 239 | true 240 | yyyy-MM-dd'T'HH:mm:ssZ 241 | true 242 | ${project.build.outputDirectory}/git.properties 243 | 244 | false 245 | 246 | 247 | 248 | 249 | ro.isdc.wro4j 250 | wro4j-maven-plugin 251 | ${wro4j.version} 252 | 253 | 254 | generate-resources 255 | 256 | run 257 | 258 | 259 | 260 | 261 | ro.isdc.wro.maven.plugin.manager.factory.ConfigurableWroManagerFactory 262 | ${project.build.directory}/classes/static/resources/css 263 | ${basedir}/src/main/wro/wro.xml 264 | ${basedir}/src/main/wro/wro.properties 265 | ${basedir}/src/main/less 266 | 267 | 268 | 269 | org.webjars 270 | bootstrap 271 | ${webjars-bootstrap.version} 272 | 273 | 274 | org.mockito 275 | mockito-core 276 | ${mockito.version} 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | Apache License, Version 2.0 286 | https://www.apache.org/licenses/LICENSE-2.0 287 | 288 | 289 | 290 | 291 | 292 | spring-snapshots 293 | Spring Snapshots 294 | https://repo.spring.io/snapshot 295 | 296 | true 297 | 298 | 299 | 300 | spring-milestones 301 | Spring Milestones 302 | https://repo.spring.io/milestone 303 | 304 | false 305 | 306 | 307 | 308 | 309 | 310 | 311 | spring-snapshots 312 | Spring Snapshots 313 | https://repo.spring.io/snapshot 314 | 315 | true 316 | 317 | 318 | 319 | spring-milestones 320 | Spring Milestones 321 | https://repo.spring.io/milestone 322 | 323 | false 324 | 325 | 326 | 327 | 328 | 329 | 330 | m2e 331 | 332 | 333 | m2e.version 334 | 335 | 336 | 337 | 338 | 339 | 341 | 342 | org.eclipse.m2e 343 | lifecycle-mapping 344 | 1.0.0 345 | 346 | 347 | 348 | 349 | 350 | org.apache.maven.plugins 351 | maven-checkstyle-plugin 352 | [1,) 353 | 354 | check 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | org.springframework.boot 364 | spring-boot-maven-plugin 365 | [1,) 366 | 367 | build-info 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | -------------------------------------------------------------------------------- /petclinic/readme.md: -------------------------------------------------------------------------------- 1 | # Spring PetClinic Sample Application [![Build Status](https://travis-ci.org/spring-projects/spring-petclinic.png?branch=main)](https://travis-ci.org/spring-projects/spring-petclinic/) 2 | 3 | ## Understanding the Spring Petclinic application with a few diagrams 4 | See the presentation here 5 | 6 | ## Running petclinic locally 7 | 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: 8 | 9 | ``` 10 | git clone https://github.com/spring-projects/spring-petclinic.git 11 | cd spring-petclinic 12 | ./mvnw package 13 | java -jar target/*.jar 14 | ``` 15 | 16 | You can then access petclinic here: http://localhost:8080/ 17 | 18 | petclinic-screenshot 19 | 20 | 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): 21 | 22 | ``` 23 | ./mvnw spring-boot:run 24 | ``` 25 | 26 | ## In case you find a bug/suggested improvement for Spring Petclinic 27 | Our issue tracker is available here: https://github.com/spring-projects/spring-petclinic/issues 28 | 29 | 30 | ## Database configuration 31 | 32 | In its default configuration, Petclinic uses an in-memory database (H2) which 33 | gets populated at startup with data. The h2 console is automatically exposed at `http://localhost:8080/h2-console` 34 | and it is possible to inspect the content of the database using the `jdbc:h2:mem:testdb` url. 35 | 36 | 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. 37 | 38 | You could start MySql locally with whatever installer works for your OS, or with docker: 39 | 40 | ``` 41 | 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 42 | ``` 43 | 44 | Further documentation is provided [here](https://github.com/spring-projects/spring-petclinic/blob/main/src/main/resources/db/mysql/petclinic_db_setup_mysql.txt). 45 | 46 | ## Working with Petclinic in your IDE 47 | 48 | ### Prerequisites 49 | The following items should be installed in your system: 50 | * Java 8 or newer. 51 | * git command line tool (https://help.github.com/articles/set-up-git) 52 | * Your preferred IDE 53 | * Eclipse with the m2e plugin. Note: when m2e is available, there is an m2 icon in `Help -> About` dialog. If m2e is 54 | not there, just follow the install process here: https://www.eclipse.org/m2e/ 55 | * [Spring Tools Suite](https://spring.io/tools) (STS) 56 | * IntelliJ IDEA 57 | * [VS Code](https://code.visualstudio.com) 58 | 59 | ### Steps: 60 | 61 | 1) On the command line 62 | ``` 63 | git clone https://github.com/spring-projects/spring-petclinic.git 64 | ``` 65 | 2) Inside Eclipse or STS 66 | ``` 67 | File -> Import -> Maven -> Existing Maven project 68 | ``` 69 | 70 | 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`. 71 | 72 | 3) Inside IntelliJ IDEA 73 | In the main menu, choose `File -> Open` and select the Petclinic [pom.xml](pom.xml). Click on the `Open` button. 74 | 75 | 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`. 76 | 77 | 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'`. 78 | 79 | 4) Navigate to Petclinic 80 | 81 | Visit [http://localhost:8080](http://localhost:8080) in your browser. 82 | 83 | 84 | ## Looking for something in particular? 85 | 86 | |Spring Boot Configuration | Class or Java property files | 87 | |--------------------------|---| 88 | |The Main Class | [PetClinicApplication](https://github.com/spring-projects/spring-petclinic/blob/main/src/main/java/org/springframework/samples/petclinic/PetClinicApplication.java) | 89 | |Properties Files | [application.properties](https://github.com/spring-projects/spring-petclinic/blob/main/src/main/resources) | 90 | |Caching | [CacheConfiguration](https://github.com/spring-projects/spring-petclinic/blob/main/src/main/java/org/springframework/samples/petclinic/system/CacheConfiguration.java) | 91 | 92 | ## Interesting Spring Petclinic branches and forks 93 | 94 | The Spring Petclinic "main" branch in the [spring-projects](https://github.com/spring-projects/spring-petclinic) 95 | GitHub org is the "canonical" implementation, currently based on Spring Boot and Thymeleaf. There are 96 | [quite a few forks](https://spring-petclinic.github.io/docs/forks.html) in a special GitHub org 97 | [spring-petclinic](https://github.com/spring-petclinic). If you have a special interest in a different technology stack 98 | that could be used to implement the Pet Clinic then please join the community there. 99 | 100 | 101 | ## Interaction with other open source projects 102 | 103 | One of the best parts about working on the Spring Petclinic application is that we have the opportunity to work in direct contact with many Open Source projects. We found some bugs/suggested improvements on various topics such as Spring, Spring Data, Bean Validation and even Eclipse! In many cases, they've been fixed/implemented in just a few days. 104 | Here is a list of them: 105 | 106 | | Name | Issue | 107 | |------|-------| 108 | | Spring JDBC: simplify usage of NamedParameterJdbcTemplate | [SPR-10256](https://jira.springsource.org/browse/SPR-10256) and [SPR-10257](https://jira.springsource.org/browse/SPR-10257) | 109 | | Bean Validation / Hibernate Validator: simplify Maven dependencies and backward compatibility |[HV-790](https://hibernate.atlassian.net/browse/HV-790) and [HV-792](https://hibernate.atlassian.net/browse/HV-792) | 110 | | Spring Data: provide more flexibility when working with JPQL queries | [DATAJPA-292](https://jira.springsource.org/browse/DATAJPA-292) | 111 | 112 | 113 | # Contributing 114 | 115 | The [issue tracker](https://github.com/spring-projects/spring-petclinic/issues) is the preferred channel for bug reports, features requests and submitting pull requests. 116 | 117 | For pull requests, editor preferences are available in the [editor config](.editorconfig) for easy use in common text editors. Read more and download plugins at . If you have not previously done so, please fill out and submit the [Contributor License Agreement](https://cla.pivotal.io/sign/spring). 118 | 119 | # License 120 | 121 | The Spring PetClinic sample application is released under version 2.0 of the [Apache License](https://www.apache.org/licenses/LICENSE-2.0). 122 | 123 | [spring-petclinic]: https://github.com/spring-projects/spring-petclinic 124 | [spring-framework-petclinic]: https://github.com/spring-petclinic/spring-framework-petclinic 125 | [spring-petclinic-angularjs]: https://github.com/spring-petclinic/spring-petclinic-angularjs 126 | [javaconfig branch]: https://github.com/spring-petclinic/spring-framework-petclinic/tree/javaconfig 127 | [spring-petclinic-angular]: https://github.com/spring-petclinic/spring-petclinic-angular 128 | [spring-petclinic-microservices]: https://github.com/spring-petclinic/spring-petclinic-microservices 129 | [spring-petclinic-reactjs]: https://github.com/spring-petclinic/spring-petclinic-reactjs 130 | [spring-petclinic-graphql]: https://github.com/spring-petclinic/spring-petclinic-graphql 131 | [spring-petclinic-kotlin]: https://github.com/spring-petclinic/spring-petclinic-kotlin 132 | [spring-petclinic-rest]: https://github.com/spring-petclinic/spring-petclinic-rest 133 | -------------------------------------------------------------------------------- /petclinic/src/checkstyle/nohttp-checkstyle-suppressions.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /petclinic/src/checkstyle/nohttp-checkstyle.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /petclinic/src/main/java/org/springframework/samples/petclinic/PetClinicApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.samples.petclinic; 18 | 19 | import org.springframework.boot.SpringApplication; 20 | import org.springframework.boot.autoconfigure.SpringBootApplication; 21 | 22 | /** 23 | * PetClinic Spring Boot Application. 24 | * 25 | * @author Dave Syer 26 | * 27 | */ 28 | @SpringBootApplication(proxyBeanMethods = false) 29 | public class PetClinicApplication { 30 | 31 | public static void main(String[] args) { 32 | SpringApplication.run(PetClinicApplication.class, args); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /petclinic/src/main/java/org/springframework/samples/petclinic/model/BaseEntity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.samples.petclinic.model; 17 | 18 | import java.io.Serializable; 19 | 20 | import javax.persistence.GeneratedValue; 21 | import javax.persistence.GenerationType; 22 | import javax.persistence.Id; 23 | import javax.persistence.MappedSuperclass; 24 | 25 | /** 26 | * Simple JavaBean domain object with an id property. Used as a base class for objects 27 | * needing this property. 28 | * 29 | * @author Ken Krebs 30 | * @author Juergen Hoeller 31 | */ 32 | @MappedSuperclass 33 | public class BaseEntity implements Serializable { 34 | 35 | @Id 36 | @GeneratedValue(strategy = GenerationType.IDENTITY) 37 | private Integer id; 38 | 39 | public Integer getId() { 40 | return id; 41 | } 42 | 43 | public void setId(Integer id) { 44 | this.id = id; 45 | } 46 | 47 | public boolean isNew() { 48 | return this.id == null; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /petclinic/src/main/java/org/springframework/samples/petclinic/model/NamedEntity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.samples.petclinic.model; 17 | 18 | import javax.persistence.Column; 19 | import javax.persistence.MappedSuperclass; 20 | 21 | /** 22 | * Simple JavaBean domain object adds a name property to BaseEntity. Used as 23 | * a base class for objects needing these properties. 24 | * 25 | * @author Ken Krebs 26 | * @author Juergen Hoeller 27 | */ 28 | @MappedSuperclass 29 | public class NamedEntity extends BaseEntity { 30 | 31 | @Column(name = "name") 32 | private String name; 33 | 34 | public String getName() { 35 | return this.name; 36 | } 37 | 38 | public void setName(String name) { 39 | this.name = name; 40 | } 41 | 42 | @Override 43 | public String toString() { 44 | return this.getName(); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /petclinic/src/main/java/org/springframework/samples/petclinic/model/Person.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.samples.petclinic.model; 17 | 18 | import javax.persistence.Column; 19 | import javax.persistence.MappedSuperclass; 20 | import javax.validation.constraints.NotEmpty; 21 | 22 | /** 23 | * Simple JavaBean domain object representing an person. 24 | * 25 | * @author Ken Krebs 26 | */ 27 | @MappedSuperclass 28 | public class Person extends BaseEntity { 29 | 30 | @Column(name = "first_name") 31 | @NotEmpty 32 | private String firstName; 33 | 34 | @Column(name = "last_name") 35 | @NotEmpty 36 | private String lastName; 37 | 38 | public String getFirstName() { 39 | return this.firstName; 40 | } 41 | 42 | public void setFirstName(String firstName) { 43 | this.firstName = firstName; 44 | } 45 | 46 | public String getLastName() { 47 | return this.lastName; 48 | } 49 | 50 | public void setLastName(String lastName) { 51 | this.lastName = lastName; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /petclinic/src/main/java/org/springframework/samples/petclinic/model/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * The classes in this package represent utilities used by the domain. 19 | */ 20 | package org.springframework.samples.petclinic.model; 21 | -------------------------------------------------------------------------------- /petclinic/src/main/java/org/springframework/samples/petclinic/owner/Owner.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.samples.petclinic.owner; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Collections; 20 | import java.util.HashSet; 21 | import java.util.List; 22 | import java.util.Set; 23 | 24 | import javax.persistence.CascadeType; 25 | import javax.persistence.Column; 26 | import javax.persistence.Entity; 27 | import javax.persistence.OneToMany; 28 | import javax.persistence.Table; 29 | import javax.validation.constraints.Digits; 30 | import javax.validation.constraints.NotEmpty; 31 | 32 | import org.springframework.beans.support.MutableSortDefinition; 33 | import org.springframework.beans.support.PropertyComparator; 34 | import org.springframework.core.style.ToStringCreator; 35 | import org.springframework.samples.petclinic.model.Person; 36 | 37 | /** 38 | * Simple JavaBean domain object representing an owner. 39 | * 40 | * @author Ken Krebs 41 | * @author Juergen Hoeller 42 | * @author Sam Brannen 43 | * @author Michael Isvy 44 | */ 45 | @Entity 46 | @Table(name = "owners") 47 | public class Owner extends Person { 48 | 49 | @Column(name = "address") 50 | @NotEmpty 51 | private String address; 52 | 53 | @Column(name = "city") 54 | @NotEmpty 55 | private String city; 56 | 57 | @Column(name = "telephone") 58 | @NotEmpty 59 | @Digits(fraction = 0, integer = 10) 60 | private String telephone; 61 | 62 | @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner") 63 | private Set pets; 64 | 65 | public String getAddress() { 66 | return this.address; 67 | } 68 | 69 | public void setAddress(String address) { 70 | this.address = address; 71 | } 72 | 73 | public String getCity() { 74 | return this.city; 75 | } 76 | 77 | public void setCity(String city) { 78 | this.city = city; 79 | } 80 | 81 | public String getTelephone() { 82 | return this.telephone; 83 | } 84 | 85 | public void setTelephone(String telephone) { 86 | this.telephone = telephone; 87 | } 88 | 89 | protected Set getPetsInternal() { 90 | if (this.pets == null) { 91 | this.pets = new HashSet<>(); 92 | } 93 | return this.pets; 94 | } 95 | 96 | protected void setPetsInternal(Set pets) { 97 | this.pets = pets; 98 | } 99 | 100 | public List getPets() { 101 | List sortedPets = new ArrayList<>(getPetsInternal()); 102 | PropertyComparator.sort(sortedPets, new MutableSortDefinition("name", true, true)); 103 | return Collections.unmodifiableList(sortedPets); 104 | } 105 | 106 | public void addPet(Pet pet) { 107 | if (pet.isNew()) { 108 | getPetsInternal().add(pet); 109 | } 110 | pet.setOwner(this); 111 | } 112 | 113 | /** 114 | * Return the Pet with the given name, or null if none found for this Owner. 115 | * @param name to test 116 | * @return true if pet name is already in use 117 | */ 118 | public Pet getPet(String name) { 119 | return getPet(name, false); 120 | } 121 | 122 | /** 123 | * Return the Pet with the given name, or null if none found for this Owner. 124 | * @param name to test 125 | * @return true if pet name is already in use 126 | */ 127 | public Pet getPet(String name, boolean ignoreNew) { 128 | name = name.toLowerCase(); 129 | for (Pet pet : getPetsInternal()) { 130 | if (!ignoreNew || !pet.isNew()) { 131 | String compName = pet.getName(); 132 | compName = compName.toLowerCase(); 133 | if (compName.equals(name)) { 134 | return pet; 135 | } 136 | } 137 | } 138 | return null; 139 | } 140 | 141 | @Override 142 | public String toString() { 143 | return new ToStringCreator(this) 144 | 145 | .append("id", this.getId()).append("new", this.isNew()).append("lastName", this.getLastName()) 146 | .append("firstName", this.getFirstName()).append("address", this.address).append("city", this.city) 147 | .append("telephone", this.telephone).toString(); 148 | } 149 | 150 | } 151 | -------------------------------------------------------------------------------- /petclinic/src/main/java/org/springframework/samples/petclinic/owner/OwnerController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.samples.petclinic.owner; 17 | 18 | import org.springframework.samples.petclinic.visit.VisitRepository; 19 | import org.springframework.stereotype.Controller; 20 | import org.springframework.ui.Model; 21 | import org.springframework.validation.BindingResult; 22 | import org.springframework.web.bind.WebDataBinder; 23 | import org.springframework.web.bind.annotation.GetMapping; 24 | import org.springframework.web.bind.annotation.InitBinder; 25 | import org.springframework.web.bind.annotation.PathVariable; 26 | import org.springframework.web.bind.annotation.PostMapping; 27 | import org.springframework.web.servlet.ModelAndView; 28 | 29 | import javax.validation.Valid; 30 | import java.util.Collection; 31 | import java.util.Map; 32 | 33 | /** 34 | * @author Juergen Hoeller 35 | * @author Ken Krebs 36 | * @author Arjen Poutsma 37 | * @author Michael Isvy 38 | */ 39 | @Controller 40 | class OwnerController { 41 | 42 | private static final String VIEWS_OWNER_CREATE_OR_UPDATE_FORM = "owners/createOrUpdateOwnerForm"; 43 | 44 | private final OwnerRepository owners; 45 | 46 | private VisitRepository visits; 47 | 48 | public OwnerController(OwnerRepository clinicService, VisitRepository visits) { 49 | this.owners = clinicService; 50 | this.visits = visits; 51 | } 52 | 53 | @InitBinder 54 | public void setAllowedFields(WebDataBinder dataBinder) { 55 | dataBinder.setDisallowedFields("id"); 56 | } 57 | 58 | @GetMapping("/owners/new") 59 | public String initCreationForm(Map model) { 60 | Owner owner = new Owner(); 61 | model.put("owner", owner); 62 | return VIEWS_OWNER_CREATE_OR_UPDATE_FORM; 63 | } 64 | 65 | @PostMapping("/owners/new") 66 | public String processCreationForm(@Valid Owner owner, BindingResult result) { 67 | if (result.hasErrors()) { 68 | return VIEWS_OWNER_CREATE_OR_UPDATE_FORM; 69 | } 70 | else { 71 | this.owners.save(owner); 72 | return "redirect:/owners/" + owner.getId(); 73 | } 74 | } 75 | 76 | @GetMapping("/owners/find") 77 | public String initFindForm(Map model) { 78 | model.put("owner", new Owner()); 79 | return "owners/findOwners"; 80 | } 81 | 82 | @GetMapping("/owners") 83 | public String processFindForm(Owner owner, BindingResult result, Map model) { 84 | 85 | // allow parameterless GET request for /owners to return all records 86 | if (owner.getLastName() == null) { 87 | owner.setLastName(""); // empty string signifies broadest possible search 88 | } 89 | 90 | // find owners by last name 91 | Collection results = this.owners.findByLastName(owner.getLastName()); 92 | if (results.isEmpty()) { 93 | // no owners found 94 | result.rejectValue("lastName", "notFound", "not found"); 95 | return "owners/findOwners"; 96 | } 97 | else if (results.size() == 1) { 98 | // 1 owner found 99 | owner = results.iterator().next(); 100 | return "redirect:/owners/" + owner.getId(); 101 | } 102 | else { 103 | // multiple owners found 104 | model.put("selections", results); 105 | return "owners/ownersList"; 106 | } 107 | } 108 | 109 | @GetMapping("/owners/{ownerId}/edit") 110 | public String initUpdateOwnerForm(@PathVariable("ownerId") int ownerId, Model model) { 111 | Owner owner = this.owners.findById(ownerId); 112 | model.addAttribute(owner); 113 | return VIEWS_OWNER_CREATE_OR_UPDATE_FORM; 114 | } 115 | 116 | @PostMapping("/owners/{ownerId}/edit") 117 | public String processUpdateOwnerForm(@Valid Owner owner, BindingResult result, 118 | @PathVariable("ownerId") int ownerId) { 119 | if (result.hasErrors()) { 120 | return VIEWS_OWNER_CREATE_OR_UPDATE_FORM; 121 | } 122 | else { 123 | owner.setId(ownerId); 124 | this.owners.save(owner); 125 | return "redirect:/owners/{ownerId}"; 126 | } 127 | } 128 | 129 | /** 130 | * Custom handler for displaying an owner. 131 | * @param ownerId the ID of the owner to display 132 | * @return a ModelMap with the model attributes for the view 133 | */ 134 | @GetMapping("/owners/{ownerId}") 135 | public ModelAndView showOwner(@PathVariable("ownerId") int ownerId) { 136 | ModelAndView mav = new ModelAndView("owners/ownerDetails"); 137 | Owner owner = this.owners.findById(ownerId); 138 | for (Pet pet : owner.getPets()) { 139 | pet.setVisitsInternal(visits.findByPetId(pet.getId())); 140 | } 141 | mav.addObject(owner); 142 | return mav; 143 | } 144 | 145 | } 146 | -------------------------------------------------------------------------------- /petclinic/src/main/java/org/springframework/samples/petclinic/owner/OwnerRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.samples.petclinic.owner; 17 | 18 | import java.util.Collection; 19 | 20 | import org.springframework.data.jpa.repository.Query; 21 | import org.springframework.data.repository.Repository; 22 | import org.springframework.data.repository.query.Param; 23 | import org.springframework.transaction.annotation.Transactional; 24 | 25 | /** 26 | * Repository class for Owner domain objects All method names are compliant 27 | * with Spring Data naming conventions so this interface can easily be extended for Spring 28 | * Data. See: 29 | * https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation 30 | * 31 | * @author Ken Krebs 32 | * @author Juergen Hoeller 33 | * @author Sam Brannen 34 | * @author Michael Isvy 35 | */ 36 | public interface OwnerRepository extends Repository { 37 | 38 | /** 39 | * Retrieve {@link Owner}s from the data store by last name, returning all owners 40 | * whose last name starts with the given name. 41 | * @param lastName Value to search for 42 | * @return a Collection of matching {@link Owner}s (or an empty Collection if none 43 | * found) 44 | */ 45 | @Query("SELECT DISTINCT owner FROM Owner owner left join fetch owner.pets WHERE owner.lastName LIKE :lastName%") 46 | @Transactional(readOnly = true) 47 | Collection findByLastName(@Param("lastName") String lastName); 48 | 49 | /** 50 | * Retrieve an {@link Owner} from the data store by id. 51 | * @param id the id to search for 52 | * @return the {@link Owner} if found 53 | */ 54 | @Query("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:id") 55 | @Transactional(readOnly = true) 56 | Owner findById(@Param("id") Integer id); 57 | 58 | /** 59 | * Save an {@link Owner} to the data store, either inserting or updating it. 60 | * @param owner the {@link Owner} to save 61 | */ 62 | void save(Owner owner); 63 | 64 | } 65 | -------------------------------------------------------------------------------- /petclinic/src/main/java/org/springframework/samples/petclinic/owner/Pet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.samples.petclinic.owner; 17 | 18 | import java.time.LocalDate; 19 | import java.util.ArrayList; 20 | import java.util.Collection; 21 | import java.util.Collections; 22 | import java.util.HashSet; 23 | import java.util.LinkedHashSet; 24 | import java.util.List; 25 | import java.util.Set; 26 | 27 | import javax.persistence.Column; 28 | import javax.persistence.Entity; 29 | import javax.persistence.JoinColumn; 30 | import javax.persistence.ManyToOne; 31 | import javax.persistence.Table; 32 | import javax.persistence.Transient; 33 | 34 | import org.springframework.beans.support.MutableSortDefinition; 35 | import org.springframework.beans.support.PropertyComparator; 36 | import org.springframework.format.annotation.DateTimeFormat; 37 | import org.springframework.samples.petclinic.model.NamedEntity; 38 | import org.springframework.samples.petclinic.visit.Visit; 39 | 40 | /** 41 | * Simple business object representing a pet. 42 | * 43 | * @author Ken Krebs 44 | * @author Juergen Hoeller 45 | * @author Sam Brannen 46 | */ 47 | @Entity 48 | @Table(name = "pets") 49 | public class Pet extends NamedEntity { 50 | 51 | @Column(name = "birth_date") 52 | @DateTimeFormat(pattern = "yyyy-MM-dd") 53 | private LocalDate birthDate; 54 | 55 | @ManyToOne 56 | @JoinColumn(name = "type_id") 57 | private PetType type; 58 | 59 | @ManyToOne 60 | @JoinColumn(name = "owner_id") 61 | private Owner owner; 62 | 63 | @Transient 64 | private Set visits = new LinkedHashSet<>(); 65 | 66 | public void setBirthDate(LocalDate birthDate) { 67 | this.birthDate = birthDate; 68 | } 69 | 70 | public LocalDate getBirthDate() { 71 | return this.birthDate; 72 | } 73 | 74 | public PetType getType() { 75 | return this.type; 76 | } 77 | 78 | public void setType(PetType type) { 79 | this.type = type; 80 | } 81 | 82 | public Owner getOwner() { 83 | return this.owner; 84 | } 85 | 86 | protected void setOwner(Owner owner) { 87 | this.owner = owner; 88 | } 89 | 90 | protected Set getVisitsInternal() { 91 | if (this.visits == null) { 92 | this.visits = new HashSet<>(); 93 | } 94 | return this.visits; 95 | } 96 | 97 | protected void setVisitsInternal(Collection visits) { 98 | this.visits = new LinkedHashSet<>(visits); 99 | } 100 | 101 | public List getVisits() { 102 | List sortedVisits = new ArrayList<>(getVisitsInternal()); 103 | PropertyComparator.sort(sortedVisits, new MutableSortDefinition("date", false, false)); 104 | return Collections.unmodifiableList(sortedVisits); 105 | } 106 | 107 | public void addVisit(Visit visit) { 108 | getVisitsInternal().add(visit); 109 | visit.setPetId(this.getId()); 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /petclinic/src/main/java/org/springframework/samples/petclinic/owner/PetController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.samples.petclinic.owner; 17 | 18 | import org.springframework.stereotype.Controller; 19 | import org.springframework.ui.ModelMap; 20 | import org.springframework.util.StringUtils; 21 | import org.springframework.validation.BindingResult; 22 | import org.springframework.web.bind.WebDataBinder; 23 | import org.springframework.web.bind.annotation.*; 24 | 25 | import javax.validation.Valid; 26 | import java.util.Collection; 27 | 28 | /** 29 | * @author Juergen Hoeller 30 | * @author Ken Krebs 31 | * @author Arjen Poutsma 32 | */ 33 | @Controller 34 | @RequestMapping("/owners/{ownerId}") 35 | class PetController { 36 | 37 | private static final String VIEWS_PETS_CREATE_OR_UPDATE_FORM = "pets/createOrUpdatePetForm"; 38 | 39 | private final PetRepository pets; 40 | 41 | private final OwnerRepository owners; 42 | 43 | public PetController(PetRepository pets, OwnerRepository owners) { 44 | this.pets = pets; 45 | this.owners = owners; 46 | } 47 | 48 | @ModelAttribute("types") 49 | public Collection populatePetTypes() { 50 | return this.pets.findPetTypes(); 51 | } 52 | 53 | @ModelAttribute("owner") 54 | public Owner findOwner(@PathVariable("ownerId") int ownerId) { 55 | return this.owners.findById(ownerId); 56 | } 57 | 58 | @InitBinder("owner") 59 | public void initOwnerBinder(WebDataBinder dataBinder) { 60 | dataBinder.setDisallowedFields("id"); 61 | } 62 | 63 | @InitBinder("pet") 64 | public void initPetBinder(WebDataBinder dataBinder) { 65 | dataBinder.setValidator(new PetValidator()); 66 | } 67 | 68 | @GetMapping("/pets/new") 69 | public String initCreationForm(Owner owner, ModelMap model) { 70 | Pet pet = new Pet(); 71 | owner.addPet(pet); 72 | model.put("pet", pet); 73 | return VIEWS_PETS_CREATE_OR_UPDATE_FORM; 74 | } 75 | 76 | @PostMapping("/pets/new") 77 | public String processCreationForm(Owner owner, @Valid Pet pet, BindingResult result, ModelMap model) { 78 | if (StringUtils.hasLength(pet.getName()) && pet.isNew() && owner.getPet(pet.getName(), true) != null) { 79 | result.rejectValue("name", "duplicate", "already exists"); 80 | } 81 | owner.addPet(pet); 82 | if (result.hasErrors()) { 83 | model.put("pet", pet); 84 | return VIEWS_PETS_CREATE_OR_UPDATE_FORM; 85 | } 86 | else { 87 | this.pets.save(pet); 88 | return "redirect:/owners/{ownerId}"; 89 | } 90 | } 91 | 92 | @GetMapping("/pets/{petId}/edit") 93 | public String initUpdateForm(@PathVariable("petId") int petId, ModelMap model) { 94 | Pet pet = this.pets.findById(petId); 95 | model.put("pet", pet); 96 | return VIEWS_PETS_CREATE_OR_UPDATE_FORM; 97 | } 98 | 99 | @PostMapping("/pets/{petId}/edit") 100 | public String processUpdateForm(@Valid Pet pet, BindingResult result, Owner owner, ModelMap model) { 101 | if (result.hasErrors()) { 102 | pet.setOwner(owner); 103 | model.put("pet", pet); 104 | return VIEWS_PETS_CREATE_OR_UPDATE_FORM; 105 | } 106 | else { 107 | owner.addPet(pet); 108 | this.pets.save(pet); 109 | return "redirect:/owners/{ownerId}"; 110 | } 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /petclinic/src/main/java/org/springframework/samples/petclinic/owner/PetRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.samples.petclinic.owner; 17 | 18 | import java.util.List; 19 | 20 | import org.springframework.data.jpa.repository.Query; 21 | import org.springframework.data.repository.Repository; 22 | import org.springframework.transaction.annotation.Transactional; 23 | 24 | /** 25 | * Repository class for Pet domain objects All method names are compliant 26 | * with Spring Data naming conventions so this interface can easily be extended for Spring 27 | * Data. See: 28 | * https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation 29 | * 30 | * @author Ken Krebs 31 | * @author Juergen Hoeller 32 | * @author Sam Brannen 33 | * @author Michael Isvy 34 | */ 35 | public interface PetRepository extends Repository { 36 | 37 | /** 38 | * Retrieve all {@link PetType}s from the data store. 39 | * @return a Collection of {@link PetType}s. 40 | */ 41 | @Query("SELECT ptype FROM PetType ptype ORDER BY ptype.name") 42 | @Transactional(readOnly = true) 43 | List findPetTypes(); 44 | 45 | /** 46 | * Retrieve a {@link Pet} from the data store by id. 47 | * @param id the id to search for 48 | * @return the {@link Pet} if found 49 | */ 50 | @Transactional(readOnly = true) 51 | Pet findById(Integer id); 52 | 53 | /** 54 | * Save a {@link Pet} to the data store, either inserting or updating it. 55 | * @param pet the {@link Pet} to save 56 | */ 57 | void save(Pet pet); 58 | 59 | } 60 | -------------------------------------------------------------------------------- /petclinic/src/main/java/org/springframework/samples/petclinic/owner/PetType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.samples.petclinic.owner; 17 | 18 | import javax.persistence.Entity; 19 | import javax.persistence.Table; 20 | 21 | import org.springframework.samples.petclinic.model.NamedEntity; 22 | 23 | /** 24 | * @author Juergen Hoeller Can be Cat, Dog, Hamster... 25 | */ 26 | @Entity 27 | @Table(name = "types") 28 | public class PetType extends NamedEntity { 29 | 30 | } 31 | -------------------------------------------------------------------------------- /petclinic/src/main/java/org/springframework/samples/petclinic/owner/PetTypeFormatter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.samples.petclinic.owner; 17 | 18 | import java.text.ParseException; 19 | import java.util.Collection; 20 | import java.util.Locale; 21 | 22 | import org.springframework.beans.factory.annotation.Autowired; 23 | import org.springframework.format.Formatter; 24 | import org.springframework.stereotype.Component; 25 | 26 | /** 27 | * Instructs Spring MVC on how to parse and print elements of type 'PetType'. Starting 28 | * from Spring 3.0, Formatters have come as an improvement in comparison to legacy 29 | * PropertyEditors. See the following links for more details: - The Spring ref doc: 30 | * https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#format 31 | * 32 | * @author Mark Fisher 33 | * @author Juergen Hoeller 34 | * @author Michael Isvy 35 | */ 36 | @Component 37 | public class PetTypeFormatter implements Formatter { 38 | 39 | private final PetRepository pets; 40 | 41 | @Autowired 42 | public PetTypeFormatter(PetRepository pets) { 43 | this.pets = pets; 44 | } 45 | 46 | @Override 47 | public String print(PetType petType, Locale locale) { 48 | return petType.getName(); 49 | } 50 | 51 | @Override 52 | public PetType parse(String text, Locale locale) throws ParseException { 53 | Collection findPetTypes = this.pets.findPetTypes(); 54 | for (PetType type : findPetTypes) { 55 | if (type.getName().equals(text)) { 56 | return type; 57 | } 58 | } 59 | throw new ParseException("type not found: " + text, 0); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /petclinic/src/main/java/org/springframework/samples/petclinic/owner/PetValidator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.samples.petclinic.owner; 17 | 18 | import org.springframework.util.StringUtils; 19 | import org.springframework.validation.Errors; 20 | import org.springframework.validation.Validator; 21 | 22 | /** 23 | * Validator for Pet forms. 24 | *

25 | * We're not using Bean Validation annotations here because it is easier to define such 26 | * validation rule in Java. 27 | *

28 | * 29 | * @author Ken Krebs 30 | * @author Juergen Hoeller 31 | */ 32 | public class PetValidator implements Validator { 33 | 34 | private static final String REQUIRED = "required"; 35 | 36 | @Override 37 | public void validate(Object obj, Errors errors) { 38 | Pet pet = (Pet) obj; 39 | String name = pet.getName(); 40 | // name validation 41 | if (!StringUtils.hasLength(name)) { 42 | errors.rejectValue("name", REQUIRED, REQUIRED); 43 | } 44 | 45 | // type validation 46 | if (pet.isNew() && pet.getType() == null) { 47 | errors.rejectValue("type", REQUIRED, REQUIRED); 48 | } 49 | 50 | // birth date validation 51 | if (pet.getBirthDate() == null) { 52 | errors.rejectValue("birthDate", REQUIRED, REQUIRED); 53 | } 54 | } 55 | 56 | /** 57 | * This Validator validates *just* Pet instances 58 | */ 59 | @Override 60 | public boolean supports(Class clazz) { 61 | return Pet.class.isAssignableFrom(clazz); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /petclinic/src/main/java/org/springframework/samples/petclinic/owner/VisitController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.samples.petclinic.owner; 17 | 18 | import java.util.Map; 19 | 20 | import javax.validation.Valid; 21 | 22 | import org.springframework.samples.petclinic.visit.Visit; 23 | import org.springframework.samples.petclinic.visit.VisitRepository; 24 | import org.springframework.stereotype.Controller; 25 | import org.springframework.validation.BindingResult; 26 | import org.springframework.web.bind.WebDataBinder; 27 | import org.springframework.web.bind.annotation.GetMapping; 28 | import org.springframework.web.bind.annotation.InitBinder; 29 | import org.springframework.web.bind.annotation.ModelAttribute; 30 | import org.springframework.web.bind.annotation.PathVariable; 31 | import org.springframework.web.bind.annotation.PostMapping; 32 | 33 | /** 34 | * @author Juergen Hoeller 35 | * @author Ken Krebs 36 | * @author Arjen Poutsma 37 | * @author Michael Isvy 38 | * @author Dave Syer 39 | */ 40 | @Controller 41 | class VisitController { 42 | 43 | private final VisitRepository visits; 44 | 45 | private final PetRepository pets; 46 | 47 | public VisitController(VisitRepository visits, PetRepository pets) { 48 | this.visits = visits; 49 | this.pets = pets; 50 | } 51 | 52 | @InitBinder 53 | public void setAllowedFields(WebDataBinder dataBinder) { 54 | dataBinder.setDisallowedFields("id"); 55 | } 56 | 57 | /** 58 | * Called before each and every @RequestMapping annotated method. 2 goals: - Make sure 59 | * we always have fresh data - Since we do not use the session scope, make sure that 60 | * Pet object always has an id (Even though id is not part of the form fields) 61 | * @param petId 62 | * @return Pet 63 | */ 64 | @ModelAttribute("visit") 65 | public Visit loadPetWithVisit(@PathVariable("petId") int petId, Map model) { 66 | Pet pet = this.pets.findById(petId); 67 | pet.setVisitsInternal(this.visits.findByPetId(petId)); 68 | model.put("pet", pet); 69 | Visit visit = new Visit(); 70 | pet.addVisit(visit); 71 | return visit; 72 | } 73 | 74 | // Spring MVC calls method loadPetWithVisit(...) before initNewVisitForm is called 75 | @GetMapping("/owners/*/pets/{petId}/visits/new") 76 | public String initNewVisitForm(@PathVariable("petId") int petId, Map model) { 77 | return "pets/createOrUpdateVisitForm"; 78 | } 79 | 80 | // Spring MVC calls method loadPetWithVisit(...) before processNewVisitForm is called 81 | @PostMapping("/owners/{ownerId}/pets/{petId}/visits/new") 82 | public String processNewVisitForm(@Valid Visit visit, BindingResult result) { 83 | if (result.hasErrors()) { 84 | return "pets/createOrUpdateVisitForm"; 85 | } 86 | else { 87 | this.visits.save(visit); 88 | return "redirect:/owners/{ownerId}"; 89 | } 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /petclinic/src/main/java/org/springframework/samples/petclinic/system/CacheConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.samples.petclinic.system; 18 | 19 | import javax.cache.configuration.MutableConfiguration; 20 | 21 | import org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer; 22 | import org.springframework.cache.annotation.EnableCaching; 23 | import org.springframework.context.annotation.Bean; 24 | import org.springframework.context.annotation.Configuration; 25 | 26 | /** 27 | * Cache configuration intended for caches providing the JCache API. This configuration 28 | * creates the used cache for the application and enables statistics that become 29 | * accessible via JMX. 30 | */ 31 | @Configuration(proxyBeanMethods = false) 32 | @EnableCaching 33 | class CacheConfiguration { 34 | 35 | @Bean 36 | public JCacheManagerCustomizer petclinicCacheConfigurationCustomizer() { 37 | return cm -> { 38 | cm.createCache("vets", cacheConfiguration()); 39 | }; 40 | } 41 | 42 | /** 43 | * Create a simple configuration that enable statistics via the JCache programmatic 44 | * configuration API. 45 | *

46 | * Within the configuration object that is provided by the JCache API standard, there 47 | * is only a very limited set of configuration options. The really relevant 48 | * configuration options (like the size limit) must be set via a configuration 49 | * mechanism that is provided by the selected JCache implementation. 50 | */ 51 | private javax.cache.configuration.Configuration cacheConfiguration() { 52 | return new MutableConfiguration<>().setStatisticsEnabled(true); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /petclinic/src/main/java/org/springframework/samples/petclinic/system/CrashController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.samples.petclinic.system; 17 | 18 | import org.springframework.stereotype.Controller; 19 | import org.springframework.web.bind.annotation.GetMapping; 20 | 21 | /** 22 | * Controller used to showcase what happens when an exception is thrown 23 | * 24 | * @author Michael Isvy 25 | *

26 | * Also see how a view that resolves to "error" has been added ("error.html"). 27 | */ 28 | @Controller 29 | class CrashController { 30 | 31 | @GetMapping("/oups") 32 | public String triggerException() { 33 | throw new RuntimeException( 34 | "Expected: controller used to showcase what " + "happens when an exception is thrown"); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /petclinic/src/main/java/org/springframework/samples/petclinic/system/WelcomeController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.samples.petclinic.system; 18 | 19 | import org.springframework.stereotype.Controller; 20 | import org.springframework.web.bind.annotation.GetMapping; 21 | 22 | @Controller 23 | class WelcomeController { 24 | 25 | @GetMapping("/") 26 | public String welcome() { 27 | return "welcome"; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /petclinic/src/main/java/org/springframework/samples/petclinic/vet/Specialty.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.samples.petclinic.vet; 17 | 18 | import java.io.Serializable; 19 | 20 | import javax.persistence.Entity; 21 | import javax.persistence.Table; 22 | 23 | import org.springframework.samples.petclinic.model.NamedEntity; 24 | 25 | /** 26 | * Models a {@link Vet Vet's} specialty (for example, dentistry). 27 | * 28 | * @author Juergen Hoeller 29 | */ 30 | @Entity 31 | @Table(name = "specialties") 32 | public class Specialty extends NamedEntity implements Serializable { 33 | 34 | } 35 | -------------------------------------------------------------------------------- /petclinic/src/main/java/org/springframework/samples/petclinic/vet/Vet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.samples.petclinic.vet; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Collections; 20 | import java.util.HashSet; 21 | import java.util.List; 22 | import java.util.Set; 23 | 24 | import javax.persistence.Entity; 25 | import javax.persistence.FetchType; 26 | import javax.persistence.JoinColumn; 27 | import javax.persistence.JoinTable; 28 | import javax.persistence.ManyToMany; 29 | import javax.persistence.Table; 30 | import javax.xml.bind.annotation.XmlElement; 31 | 32 | import org.springframework.beans.support.MutableSortDefinition; 33 | import org.springframework.beans.support.PropertyComparator; 34 | import org.springframework.samples.petclinic.model.Person; 35 | 36 | /** 37 | * Simple JavaBean domain object representing a veterinarian. 38 | * 39 | * @author Ken Krebs 40 | * @author Juergen Hoeller 41 | * @author Sam Brannen 42 | * @author Arjen Poutsma 43 | */ 44 | @Entity 45 | @Table(name = "vets") 46 | public class Vet extends Person { 47 | 48 | @ManyToMany(fetch = FetchType.EAGER) 49 | @JoinTable(name = "vet_specialties", joinColumns = @JoinColumn(name = "vet_id"), 50 | inverseJoinColumns = @JoinColumn(name = "specialty_id")) 51 | private Set specialties; 52 | 53 | protected Set getSpecialtiesInternal() { 54 | if (this.specialties == null) { 55 | this.specialties = new HashSet<>(); 56 | } 57 | return this.specialties; 58 | } 59 | 60 | protected void setSpecialtiesInternal(Set specialties) { 61 | this.specialties = specialties; 62 | } 63 | 64 | @XmlElement 65 | public List getSpecialties() { 66 | List sortedSpecs = new ArrayList<>(getSpecialtiesInternal()); 67 | PropertyComparator.sort(sortedSpecs, new MutableSortDefinition("name", true, true)); 68 | return Collections.unmodifiableList(sortedSpecs); 69 | } 70 | 71 | public int getNrOfSpecialties() { 72 | return getSpecialtiesInternal().size(); 73 | } 74 | 75 | public void addSpecialty(Specialty specialty) { 76 | getSpecialtiesInternal().add(specialty); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /petclinic/src/main/java/org/springframework/samples/petclinic/vet/VetController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.samples.petclinic.vet; 17 | 18 | import org.springframework.stereotype.Controller; 19 | import org.springframework.web.bind.annotation.GetMapping; 20 | import org.springframework.web.bind.annotation.ResponseBody; 21 | 22 | import java.util.Map; 23 | 24 | /** 25 | * @author Juergen Hoeller 26 | * @author Mark Fisher 27 | * @author Ken Krebs 28 | * @author Arjen Poutsma 29 | */ 30 | @Controller 31 | class VetController { 32 | 33 | private final VetRepository vets; 34 | 35 | public VetController(VetRepository clinicService) { 36 | this.vets = clinicService; 37 | } 38 | 39 | @GetMapping("/vets.html") 40 | public String showVetList(Map model) { 41 | // Here we are returning an object of type 'Vets' rather than a collection of Vet 42 | // objects so it is simpler for Object-Xml mapping 43 | Vets vets = new Vets(); 44 | vets.getVetList().addAll(this.vets.findAll()); 45 | model.put("vets", vets); 46 | return "vets/vetList"; 47 | } 48 | 49 | @GetMapping({ "/vets" }) 50 | public @ResponseBody Vets showResourcesVetList() { 51 | // Here we are returning an object of type 'Vets' rather than a collection of Vet 52 | // objects so it is simpler for JSon/Object mapping 53 | Vets vets = new Vets(); 54 | vets.getVetList().addAll(this.vets.findAll()); 55 | return vets; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /petclinic/src/main/java/org/springframework/samples/petclinic/vet/VetRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.samples.petclinic.vet; 17 | 18 | import java.util.Collection; 19 | 20 | import org.springframework.cache.annotation.Cacheable; 21 | import org.springframework.dao.DataAccessException; 22 | import org.springframework.data.repository.Repository; 23 | import org.springframework.transaction.annotation.Transactional; 24 | 25 | /** 26 | * Repository class for Vet domain objects All method names are compliant 27 | * with Spring Data naming conventions so this interface can easily be extended for Spring 28 | * Data. See: 29 | * https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation 30 | * 31 | * @author Ken Krebs 32 | * @author Juergen Hoeller 33 | * @author Sam Brannen 34 | * @author Michael Isvy 35 | */ 36 | public interface VetRepository extends Repository { 37 | 38 | /** 39 | * Retrieve all Vets from the data store. 40 | * @return a Collection of Vets 41 | */ 42 | @Transactional(readOnly = true) 43 | @Cacheable("vets") 44 | Collection findAll() throws DataAccessException; 45 | 46 | } 47 | -------------------------------------------------------------------------------- /petclinic/src/main/java/org/springframework/samples/petclinic/vet/Vets.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.samples.petclinic.vet; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | import javax.xml.bind.annotation.XmlElement; 22 | import javax.xml.bind.annotation.XmlRootElement; 23 | 24 | /** 25 | * Simple domain object representing a list of veterinarians. Mostly here to be used for 26 | * the 'vets' {@link org.springframework.web.servlet.view.xml.MarshallingView}. 27 | * 28 | * @author Arjen Poutsma 29 | */ 30 | @XmlRootElement 31 | public class Vets { 32 | 33 | private List vets; 34 | 35 | @XmlElement 36 | public List getVetList() { 37 | if (vets == null) { 38 | vets = new ArrayList<>(); 39 | } 40 | return vets; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /petclinic/src/main/java/org/springframework/samples/petclinic/visit/Visit.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.samples.petclinic.visit; 17 | 18 | import java.time.LocalDate; 19 | 20 | import javax.persistence.Column; 21 | import javax.persistence.Entity; 22 | import javax.persistence.Table; 23 | import javax.validation.constraints.NotEmpty; 24 | 25 | import org.springframework.format.annotation.DateTimeFormat; 26 | import org.springframework.samples.petclinic.model.BaseEntity; 27 | 28 | /** 29 | * Simple JavaBean domain object representing a visit. 30 | * 31 | * @author Ken Krebs 32 | * @author Dave Syer 33 | */ 34 | @Entity 35 | @Table(name = "visits") 36 | public class Visit extends BaseEntity { 37 | 38 | @Column(name = "visit_date") 39 | @DateTimeFormat(pattern = "yyyy-MM-dd") 40 | private LocalDate date; 41 | 42 | @NotEmpty 43 | @Column(name = "description") 44 | private String description; 45 | 46 | @Column(name = "pet_id") 47 | private Integer petId; 48 | 49 | /** 50 | * Creates a new instance of Visit for the current date 51 | */ 52 | public Visit() { 53 | this.date = LocalDate.now(); 54 | } 55 | 56 | public LocalDate getDate() { 57 | return this.date; 58 | } 59 | 60 | public void setDate(LocalDate date) { 61 | this.date = date; 62 | } 63 | 64 | public String getDescription() { 65 | return this.description; 66 | } 67 | 68 | public void setDescription(String description) { 69 | this.description = description; 70 | } 71 | 72 | public Integer getPetId() { 73 | return this.petId; 74 | } 75 | 76 | public void setPetId(Integer petId) { 77 | this.petId = petId; 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /petclinic/src/main/java/org/springframework/samples/petclinic/visit/VisitRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.samples.petclinic.visit; 17 | 18 | import java.util.List; 19 | 20 | import org.springframework.dao.DataAccessException; 21 | import org.springframework.data.repository.Repository; 22 | import org.springframework.samples.petclinic.model.BaseEntity; 23 | 24 | /** 25 | * Repository class for Visit domain objects All method names are compliant 26 | * with Spring Data naming conventions so this interface can easily be extended for Spring 27 | * Data. See: 28 | * https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation 29 | * 30 | * @author Ken Krebs 31 | * @author Juergen Hoeller 32 | * @author Sam Brannen 33 | * @author Michael Isvy 34 | */ 35 | public interface VisitRepository extends Repository { 36 | 37 | /** 38 | * Save a Visit to the data store, either inserting or updating it. 39 | * @param visit the Visit to save 40 | * @see BaseEntity#isNew 41 | */ 42 | void save(Visit visit) throws DataAccessException; 43 | 44 | List findByPetId(Integer petId); 45 | 46 | } 47 | -------------------------------------------------------------------------------- /petclinic/src/main/less/header.less: -------------------------------------------------------------------------------- 1 | .navbar { 2 | border-top: 4px solid #6db33f; 3 | background-color: #34302d; 4 | margin-bottom: 0px; 5 | border-bottom: 0; 6 | border-left: 0; 7 | border-right: 0; 8 | } 9 | 10 | .navbar a.navbar-brand { 11 | background: url("../images/spring-logo-dataflow.png") -1px -1px no-repeat; 12 | margin: 12px 0 6px; 13 | width: 229px; 14 | height: 46px; 15 | display: inline-block; 16 | text-decoration: none; 17 | padding: 0; 18 | } 19 | 20 | .navbar a.navbar-brand span { 21 | display: block; 22 | width: 229px; 23 | height: 46px; 24 | background: url("../images/spring-logo-dataflow.png") -1px -48px no-repeat; 25 | opacity: 0; 26 | -moz-transition: opacity 0.12s ease-in-out; 27 | -webkit-transition: opacity 0.12s ease-in-out; 28 | -o-transition: opacity 0.12s ease-in-out; 29 | } 30 | 31 | .navbar a:hover.navbar-brand span { 32 | opacity: 1; 33 | } 34 | 35 | .navbar li > a, .navbar-text { 36 | font-family: "montserratregular", sans-serif; 37 | text-shadow: none; 38 | font-size: 14px; 39 | 40 | /* line-height: 14px; */ 41 | padding: 28px 20px; 42 | transition: all 0.15s; 43 | -webkit-transition: all 0.15s; 44 | -moz-transition: all 0.15s; 45 | -o-transition: all 0.15s; 46 | -ms-transition: all 0.15s; 47 | } 48 | 49 | .navbar li > a { 50 | text-transform: uppercase; 51 | } 52 | 53 | .navbar .navbar-text { 54 | margin-top: 0; 55 | margin-bottom: 0; 56 | } 57 | .navbar li:hover > a { 58 | color: #eeeeee; 59 | background-color: #6db33f; 60 | } 61 | 62 | .navbar-toggle { 63 | border-width: 0; 64 | 65 | .icon-bar + .icon-bar { 66 | margin-top: 3px; 67 | } 68 | .icon-bar { 69 | width: 19px; 70 | height: 3px; 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /petclinic/src/main/less/petclinic.less: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 the original author or authors. 3 | * 4 | * You may obtain a copy of the License at 5 | * 6 | * https://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | @icon-font-path: "../../webjars/bootstrap/fonts/"; 15 | 16 | @spring-green: #6db33f; 17 | @spring-dark-green: #5fa134; 18 | @spring-brown: #34302D; 19 | @spring-grey: #838789; 20 | @spring-light-grey: #f1f1f1; 21 | 22 | @body-bg: @spring-light-grey; 23 | @text-color: @spring-brown; 24 | @link-color: @spring-dark-green; 25 | @link-hover-color: @spring-dark-green; 26 | 27 | @navbar-default-link-color: @spring-light-grey; 28 | @navbar-default-link-active-color: @spring-light-grey; 29 | @navbar-default-link-hover-color: @spring-light-grey; 30 | @navbar-default-link-hover-bg: @spring-green; 31 | @navbar-default-toggle-icon-bar-bg: @spring-light-grey; 32 | @navbar-default-toggle-hover-bg: transparent; 33 | @navbar-default-link-active-bg: @spring-green; 34 | 35 | @border-radius-base: 0; 36 | @border-radius-large: 0; 37 | @border-radius-small: 0; 38 | 39 | @btn-default-color: @spring-light-grey; 40 | @btn-default-bg: @spring-brown; 41 | @btn-default-border: @spring-green; 42 | 43 | @nav-tabs-active-link-hover-color: @spring-light-grey; 44 | @nav-tabs-active-link-hover-bg: @spring-brown; 45 | @nav-tabs-active-link-hover-border-color: @spring-brown; 46 | @nav-tabs-border-color: @spring-brown; 47 | 48 | @pagination-active-bg: @spring-brown; 49 | @pagination-active-border: @spring-green; 50 | @table-border-color: @spring-brown; 51 | 52 | .table > thead > tr > th { 53 | background-color: lighten(@spring-brown, 3%); 54 | color: @spring-light-grey; 55 | } 56 | 57 | .table-filter { 58 | background-color: @spring-brown; 59 | padding: 9px 12px; 60 | } 61 | 62 | .nav > li > a { 63 | color: @spring-grey; 64 | } 65 | 66 | .btn-default { 67 | border-width: 2px; 68 | transition: border 0.15s; 69 | -webkit-transition: border 0.15s; 70 | -moz-transition: border 0.15s; 71 | -o-transition: border 0.15s; 72 | -ms-transition: border 0.15s; 73 | 74 | &:hover, 75 | &:focus, 76 | &:active, 77 | &.active, 78 | .open .dropdown-toggle& { 79 | background-color: @spring-brown; 80 | border-color: @spring-brown; 81 | } 82 | } 83 | 84 | 85 | .container .text-muted { 86 | margin: 20px 0; 87 | } 88 | 89 | code { 90 | font-size: 80%; 91 | } 92 | 93 | .xd-container { 94 | margin-top: 40px; 95 | margin-bottom: 100px; 96 | padding-left: 5px; 97 | padding-right: 5px; 98 | } 99 | 100 | h1 { 101 | margin-bottom: 15px 102 | } 103 | 104 | .index-page--subtitle { 105 | font-size: 16px; 106 | line-height: 24px; 107 | margin: 0 0 30px; 108 | } 109 | 110 | .form-horizontal button.btn-inverse { 111 | margin-left: 32px; 112 | } 113 | 114 | #job-params-modal .modal-dialog { 115 | width: 90%; 116 | margin-left:auto; 117 | margin-right:auto; 118 | } 119 | 120 | [ng-cloak].splash { 121 | display: block !important; 122 | } 123 | [ng-cloak] { 124 | display: none; 125 | } 126 | 127 | .splash { 128 | background: @spring-green; 129 | color: @spring-brown; 130 | display: none; 131 | } 132 | 133 | .error-page { 134 | margin-top: 100px; 135 | text-align: center; 136 | } 137 | 138 | .error-page .error-title { 139 | font-size: 24px; 140 | line-height: 24px; 141 | margin: 30px 0 0; 142 | } 143 | 144 | table td { 145 | vertical-align: middle; 146 | } 147 | 148 | table td .progress { 149 | margin-bottom: 0; 150 | } 151 | 152 | table td.action-column { 153 | width: 1px; 154 | } 155 | 156 | .help-block { 157 | color: lighten(@text-color, 50%); // lighten the text some for contrast 158 | } 159 | 160 | .xd-containers { 161 | font-size: 15px; 162 | } 163 | 164 | .cluster-view > table td { 165 | vertical-align: top; 166 | } 167 | 168 | .cluster-view .label, .cluster-view .column-block { 169 | display: block; 170 | } 171 | 172 | .cluster-view .input-group-addon { 173 | width: 0%; 174 | } 175 | 176 | .cluster-view { 177 | margin-bottom: 0; 178 | } 179 | 180 | .deployment-status-deployed { 181 | .label-success; 182 | } 183 | 184 | .deployment-status-incomplete { 185 | .label-warning; 186 | } 187 | 188 | .deployment-status-failed { 189 | .label-danger; 190 | } 191 | 192 | .deployment-status-deploying { 193 | .label-info 194 | } 195 | .deployment-status-na { 196 | } 197 | 198 | .container-details-table th { 199 | background-color: lighten(@spring-brown, 3%); 200 | color: @spring-light-grey; 201 | } 202 | 203 | .status-help-content-table td { 204 | color: @spring-brown; 205 | } 206 | 207 | .alert-success { 208 | .alert-variant(fade(@alert-success-bg, 70%); @alert-success-border; @alert-success-text); 209 | } 210 | .alert-info { 211 | .alert-variant(fade(@alert-info-bg, 70%); @alert-info-border; @alert-info-text); 212 | } 213 | .alert-warning { 214 | .alert-variant(fade(@alert-warning-bg, 70%); @alert-warning-border; @alert-warning-text); 215 | } 216 | .alert-danger { 217 | .alert-variant(fade(@alert-danger-bg, 70%); @alert-danger-border; @alert-danger-text); 218 | } 219 | 220 | .myspinner { 221 | animation-name: spinner; 222 | animation-duration: 2s; 223 | animation-iteration-count: infinite; 224 | animation-timing-function: linear; 225 | 226 | -webkit-transform-origin: 49% 50%; 227 | -webkit-animation-name: spinner; 228 | -webkit-animation-duration: 2s; 229 | -webkit-animation-iteration-count: infinite; 230 | -webkit-animation-timing-function: linear; 231 | } 232 | 233 | hr { 234 | border-top: 1px dotted @spring-brown; 235 | } 236 | 237 | @import "typography.less"; 238 | @import "header.less"; 239 | @import "responsive.less"; 240 | -------------------------------------------------------------------------------- /petclinic/src/main/less/responsive.less: -------------------------------------------------------------------------------- 1 | @media (max-width: 768px) { 2 | .navbar-toggle { 3 | position:absolute; 4 | z-index: 9999; 5 | left:0px; 6 | top:0px; 7 | } 8 | 9 | .navbar a.navbar-brand { 10 | display: block; 11 | margin: 0 auto 0 auto; 12 | width: 148px; 13 | height: 50px; 14 | float: none; 15 | background: url("../images/spring-logo-dataflow-mobile.png") 0 center no-repeat; 16 | } 17 | 18 | .homepage-billboard .homepage-subtitle { 19 | font-size: 21px; 20 | line-height: 21px; 21 | } 22 | 23 | .navbar a.navbar-brand span { 24 | display: none; 25 | } 26 | 27 | .navbar { 28 | border-top-width: 0; 29 | } 30 | 31 | .xd-container { 32 | margin-top: 20px; 33 | margin-bottom: 30px; 34 | } 35 | 36 | .index-page--subtitle { 37 | margin-top: 10px; 38 | margin-bottom: 30px; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /petclinic/src/main/less/typography.less: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'varela_roundregular'; 3 | 4 | src: url('../fonts/varela_round-webfont.eot'); 5 | src: url('../fonts/varela_round-webfont.eot?#iefix') format('embedded-opentype'), 6 | url('../fonts/varela_round-webfont.woff') format('woff'), 7 | url('../fonts/varela_round-webfont.ttf') format('truetype'), 8 | url('../fonts/varela_round-webfont.svg#varela_roundregular') format('svg'); 9 | font-weight: normal; 10 | font-style: normal; 11 | } 12 | 13 | @font-face { 14 | font-family: 'montserratregular'; 15 | src: url('../fonts/montserrat-webfont.eot'); 16 | src: url('../fonts/montserrat-webfont.eot?#iefix') format('embedded-opentype'), 17 | url('../fonts/montserrat-webfont.woff') format('woff'), 18 | url('../fonts/montserrat-webfont.ttf') format('truetype'), 19 | url('../fonts/montserrat-webfont.svg#montserratregular') format('svg'); 20 | font-weight: normal; 21 | font-style: normal; 22 | } 23 | 24 | body, h1, h2, h3, p, input { 25 | margin: 0; 26 | font-weight: 400; 27 | font-family: "varela_roundregular", sans-serif; 28 | color: #34302d; 29 | } 30 | 31 | h1 { 32 | font-size: 24px; 33 | line-height: 30px; 34 | font-family: "montserratregular", sans-serif; 35 | } 36 | 37 | h2 { 38 | font-size: 18px; 39 | font-weight: 700; 40 | line-height: 24px; 41 | margin-bottom: 10px; 42 | font-family: "montserratregular", sans-serif; 43 | } 44 | 45 | h3 { 46 | font-size: 16px; 47 | line-height: 24px; 48 | margin-bottom: 10px; 49 | font-weight: 700; 50 | } 51 | 52 | p { 53 | //font-size: 15px; 54 | //line-height: 24px; 55 | } 56 | 57 | strong { 58 | font-weight: 700; 59 | font-family: "montserratregular", sans-serif; 60 | } 61 | -------------------------------------------------------------------------------- /petclinic/src/main/resources/application-mysql.properties: -------------------------------------------------------------------------------- 1 | # database init, supports mysql too 2 | database=mysql 3 | spring.datasource.url=${MYSQL_URL:jdbc:mysql://localhost/petclinic} 4 | spring.datasource.username=${MYSQL_USER:petclinic} 5 | spring.datasource.password=${MYSQL_PASS:petclinic} 6 | # SQL is written to be idempotent so this is safe 7 | spring.datasource.initialization-mode=always 8 | -------------------------------------------------------------------------------- /petclinic/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # database init, supports mysql too 2 | database=h2 3 | spring.datasource.schema=classpath*:db/${database}/schema.sql 4 | spring.datasource.data=classpath*:db/${database}/data.sql 5 | 6 | # Web 7 | spring.thymeleaf.mode=HTML 8 | 9 | # JPA 10 | spring.jpa.hibernate.ddl-auto=none 11 | spring.jpa.open-in-view=false 12 | 13 | # Internationalization 14 | spring.messages.basename=messages/messages 15 | 16 | # Actuator 17 | management.endpoints.web.exposure.include=* 18 | 19 | # Logging 20 | logging.level.org.springframework=INFO 21 | # logging.level.org.springframework.web=DEBUG 22 | # logging.level.org.springframework.context.annotation=TRACE 23 | 24 | # Maximum time static resources should be cached 25 | spring.resources.cache.cachecontrol.max-age=12h 26 | 27 | server.port=80 -------------------------------------------------------------------------------- /petclinic/src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | |\ _,,,--,,_ 4 | /,`.-'`' ._ \-;;,_ 5 | _______ __|,4- ) )_ .;.(__`'-'__ ___ __ _ ___ _______ 6 | | | '---''(_/._)-'(_\_) | | | | | | | | | 7 | | _ | ___|_ _| | | | | |_| | | | __ _ _ 8 | | |_| | |___ | | | | | | | | | | \ \ \ \ 9 | | ___| ___| | | | _| |___| | _ | | _| \ \ \ \ 10 | | | | |___ | | | |_| | | | | | | |_ ) ) ) ) 11 | |___| |_______| |___| |_______|_______|___|_| |__|___|_______| / / / / 12 | ==================================================================/_/_/_/ 13 | 14 | :: Built with Spring Boot :: ${spring-boot.version} 15 | 16 | -------------------------------------------------------------------------------- /petclinic/src/main/resources/db/h2/data.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO vets VALUES (1, 'James', 'Carter'); 2 | INSERT INTO vets VALUES (2, 'Helen', 'Leary'); 3 | INSERT INTO vets VALUES (3, 'Linda', 'Douglas'); 4 | INSERT INTO vets VALUES (4, 'Rafael', 'Ortega'); 5 | INSERT INTO vets VALUES (5, 'Henry', 'Stevens'); 6 | INSERT INTO vets VALUES (6, 'Sharon', 'Jenkins'); 7 | 8 | INSERT INTO specialties VALUES (1, 'radiology'); 9 | INSERT INTO specialties VALUES (2, 'surgery'); 10 | INSERT INTO specialties VALUES (3, 'dentistry'); 11 | 12 | INSERT INTO vet_specialties VALUES (2, 1); 13 | INSERT INTO vet_specialties VALUES (3, 2); 14 | INSERT INTO vet_specialties VALUES (3, 3); 15 | INSERT INTO vet_specialties VALUES (4, 2); 16 | INSERT INTO vet_specialties VALUES (5, 1); 17 | 18 | INSERT INTO types VALUES (1, 'cat'); 19 | INSERT INTO types VALUES (2, 'dog'); 20 | INSERT INTO types VALUES (3, 'lizard'); 21 | INSERT INTO types VALUES (4, 'snake'); 22 | INSERT INTO types VALUES (5, 'bird'); 23 | INSERT INTO types VALUES (6, 'hamster'); 24 | 25 | INSERT INTO owners VALUES (1, 'George', 'Franklin', '110 W. Liberty St.', 'Madison', '6085551023'); 26 | INSERT INTO owners VALUES (2, 'Betty', 'Davis', '638 Cardinal Ave.', 'Sun Prairie', '6085551749'); 27 | INSERT INTO owners VALUES (3, 'Eduardo', 'Rodriquez', '2693 Commerce St.', 'McFarland', '6085558763'); 28 | INSERT INTO owners VALUES (4, 'Harold', 'Davis', '563 Friendly St.', 'Windsor', '6085553198'); 29 | INSERT INTO owners VALUES (5, 'Peter', 'McTavish', '2387 S. Fair Way', 'Madison', '6085552765'); 30 | INSERT INTO owners VALUES (6, 'Jean', 'Coleman', '105 N. Lake St.', 'Monona', '6085552654'); 31 | INSERT INTO owners VALUES (7, 'Jeff', 'Black', '1450 Oak Blvd.', 'Monona', '6085555387'); 32 | INSERT INTO owners VALUES (8, 'Maria', 'Escobito', '345 Maple St.', 'Madison', '6085557683'); 33 | INSERT INTO owners VALUES (9, 'David', 'Schroeder', '2749 Blackhawk Trail', 'Madison', '6085559435'); 34 | INSERT INTO owners VALUES (10, 'Carlos', 'Estaban', '2335 Independence La.', 'Waunakee', '6085555487'); 35 | 36 | INSERT INTO pets VALUES (1, 'Leo', '2010-09-07', 1, 1); 37 | INSERT INTO pets VALUES (2, 'Basil', '2012-08-06', 6, 2); 38 | INSERT INTO pets VALUES (3, 'Rosy', '2011-04-17', 2, 3); 39 | INSERT INTO pets VALUES (4, 'Jewel', '2010-03-07', 2, 3); 40 | INSERT INTO pets VALUES (5, 'Iggy', '2010-11-30', 3, 4); 41 | INSERT INTO pets VALUES (6, 'George', '2010-01-20', 4, 5); 42 | INSERT INTO pets VALUES (7, 'Samantha', '2012-09-04', 1, 6); 43 | INSERT INTO pets VALUES (8, 'Max', '2012-09-04', 1, 6); 44 | INSERT INTO pets VALUES (9, 'Lucky', '2011-08-06', 5, 7); 45 | INSERT INTO pets VALUES (10, 'Mulligan', '2007-02-24', 2, 8); 46 | INSERT INTO pets VALUES (11, 'Freddy', '2010-03-09', 5, 9); 47 | INSERT INTO pets VALUES (12, 'Lucky', '2010-06-24', 2, 10); 48 | INSERT INTO pets VALUES (13, 'Sly', '2012-06-08', 1, 10); 49 | 50 | INSERT INTO visits VALUES (1, 7, '2013-01-01', 'rabies shot'); 51 | INSERT INTO visits VALUES (2, 8, '2013-01-02', 'rabies shot'); 52 | INSERT INTO visits VALUES (3, 8, '2013-01-03', 'neutered'); 53 | INSERT INTO visits VALUES (4, 7, '2013-01-04', 'spayed'); 54 | -------------------------------------------------------------------------------- /petclinic/src/main/resources/db/h2/schema.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE vet_specialties IF EXISTS; 2 | DROP TABLE vets IF EXISTS; 3 | DROP TABLE specialties IF EXISTS; 4 | DROP TABLE visits IF EXISTS; 5 | DROP TABLE pets IF EXISTS; 6 | DROP TABLE types IF EXISTS; 7 | DROP TABLE owners IF EXISTS; 8 | 9 | 10 | CREATE TABLE vets ( 11 | id INTEGER IDENTITY PRIMARY KEY, 12 | first_name VARCHAR(30), 13 | last_name VARCHAR(30) 14 | ); 15 | CREATE INDEX vets_last_name ON vets (last_name); 16 | 17 | CREATE TABLE specialties ( 18 | id INTEGER IDENTITY PRIMARY KEY, 19 | name VARCHAR(80) 20 | ); 21 | CREATE INDEX specialties_name ON specialties (name); 22 | 23 | CREATE TABLE vet_specialties ( 24 | vet_id INTEGER NOT NULL, 25 | specialty_id INTEGER NOT NULL 26 | ); 27 | ALTER TABLE vet_specialties ADD CONSTRAINT fk_vet_specialties_vets FOREIGN KEY (vet_id) REFERENCES vets (id); 28 | ALTER TABLE vet_specialties ADD CONSTRAINT fk_vet_specialties_specialties FOREIGN KEY (specialty_id) REFERENCES specialties (id); 29 | 30 | CREATE TABLE types ( 31 | id INTEGER IDENTITY PRIMARY KEY, 32 | name VARCHAR(80) 33 | ); 34 | CREATE INDEX types_name ON types (name); 35 | 36 | CREATE TABLE owners ( 37 | id INTEGER IDENTITY PRIMARY KEY, 38 | first_name VARCHAR(30), 39 | last_name VARCHAR_IGNORECASE(30), 40 | address VARCHAR(255), 41 | city VARCHAR(80), 42 | telephone VARCHAR(20) 43 | ); 44 | CREATE INDEX owners_last_name ON owners (last_name); 45 | 46 | CREATE TABLE pets ( 47 | id INTEGER IDENTITY PRIMARY KEY, 48 | name VARCHAR(30), 49 | birth_date DATE, 50 | type_id INTEGER NOT NULL, 51 | owner_id INTEGER NOT NULL 52 | ); 53 | ALTER TABLE pets ADD CONSTRAINT fk_pets_owners FOREIGN KEY (owner_id) REFERENCES owners (id); 54 | ALTER TABLE pets ADD CONSTRAINT fk_pets_types FOREIGN KEY (type_id) REFERENCES types (id); 55 | CREATE INDEX pets_name ON pets (name); 56 | 57 | CREATE TABLE visits ( 58 | id INTEGER IDENTITY PRIMARY KEY, 59 | pet_id INTEGER NOT NULL, 60 | visit_date DATE, 61 | description VARCHAR(255) 62 | ); 63 | ALTER TABLE visits ADD CONSTRAINT fk_visits_pets FOREIGN KEY (pet_id) REFERENCES pets (id); 64 | CREATE INDEX visits_pet_id ON visits (pet_id); 65 | -------------------------------------------------------------------------------- /petclinic/src/main/resources/db/hsqldb/data.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO vets VALUES (1, 'James', 'Carter'); 2 | INSERT INTO vets VALUES (2, 'Helen', 'Leary'); 3 | INSERT INTO vets VALUES (3, 'Linda', 'Douglas'); 4 | INSERT INTO vets VALUES (4, 'Rafael', 'Ortega'); 5 | INSERT INTO vets VALUES (5, 'Henry', 'Stevens'); 6 | INSERT INTO vets VALUES (6, 'Sharon', 'Jenkins'); 7 | 8 | INSERT INTO specialties VALUES (1, 'radiology'); 9 | INSERT INTO specialties VALUES (2, 'surgery'); 10 | INSERT INTO specialties VALUES (3, 'dentistry'); 11 | 12 | INSERT INTO vet_specialties VALUES (2, 1); 13 | INSERT INTO vet_specialties VALUES (3, 2); 14 | INSERT INTO vet_specialties VALUES (3, 3); 15 | INSERT INTO vet_specialties VALUES (4, 2); 16 | INSERT INTO vet_specialties VALUES (5, 1); 17 | 18 | INSERT INTO types VALUES (1, 'cat'); 19 | INSERT INTO types VALUES (2, 'dog'); 20 | INSERT INTO types VALUES (3, 'lizard'); 21 | INSERT INTO types VALUES (4, 'snake'); 22 | INSERT INTO types VALUES (5, 'bird'); 23 | INSERT INTO types VALUES (6, 'hamster'); 24 | 25 | INSERT INTO owners VALUES (1, 'George', 'Franklin', '110 W. Liberty St.', 'Madison', '6085551023'); 26 | INSERT INTO owners VALUES (2, 'Betty', 'Davis', '638 Cardinal Ave.', 'Sun Prairie', '6085551749'); 27 | INSERT INTO owners VALUES (3, 'Eduardo', 'Rodriquez', '2693 Commerce St.', 'McFarland', '6085558763'); 28 | INSERT INTO owners VALUES (4, 'Harold', 'Davis', '563 Friendly St.', 'Windsor', '6085553198'); 29 | INSERT INTO owners VALUES (5, 'Peter', 'McTavish', '2387 S. Fair Way', 'Madison', '6085552765'); 30 | INSERT INTO owners VALUES (6, 'Jean', 'Coleman', '105 N. Lake St.', 'Monona', '6085552654'); 31 | INSERT INTO owners VALUES (7, 'Jeff', 'Black', '1450 Oak Blvd.', 'Monona', '6085555387'); 32 | INSERT INTO owners VALUES (8, 'Maria', 'Escobito', '345 Maple St.', 'Madison', '6085557683'); 33 | INSERT INTO owners VALUES (9, 'David', 'Schroeder', '2749 Blackhawk Trail', 'Madison', '6085559435'); 34 | INSERT INTO owners VALUES (10, 'Carlos', 'Estaban', '2335 Independence La.', 'Waunakee', '6085555487'); 35 | 36 | INSERT INTO pets VALUES (1, 'Leo', '2010-09-07', 1, 1); 37 | INSERT INTO pets VALUES (2, 'Basil', '2012-08-06', 6, 2); 38 | INSERT INTO pets VALUES (3, 'Rosy', '2011-04-17', 2, 3); 39 | INSERT INTO pets VALUES (4, 'Jewel', '2010-03-07', 2, 3); 40 | INSERT INTO pets VALUES (5, 'Iggy', '2010-11-30', 3, 4); 41 | INSERT INTO pets VALUES (6, 'George', '2010-01-20', 4, 5); 42 | INSERT INTO pets VALUES (7, 'Samantha', '2012-09-04', 1, 6); 43 | INSERT INTO pets VALUES (8, 'Max', '2012-09-04', 1, 6); 44 | INSERT INTO pets VALUES (9, 'Lucky', '2011-08-06', 5, 7); 45 | INSERT INTO pets VALUES (10, 'Mulligan', '2007-02-24', 2, 8); 46 | INSERT INTO pets VALUES (11, 'Freddy', '2010-03-09', 5, 9); 47 | INSERT INTO pets VALUES (12, 'Lucky', '2010-06-24', 2, 10); 48 | INSERT INTO pets VALUES (13, 'Sly', '2012-06-08', 1, 10); 49 | 50 | INSERT INTO visits VALUES (1, 7, '2013-01-01', 'rabies shot'); 51 | INSERT INTO visits VALUES (2, 8, '2013-01-02', 'rabies shot'); 52 | INSERT INTO visits VALUES (3, 8, '2013-01-03', 'neutered'); 53 | INSERT INTO visits VALUES (4, 7, '2013-01-04', 'spayed'); 54 | -------------------------------------------------------------------------------- /petclinic/src/main/resources/db/hsqldb/schema.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE vet_specialties IF EXISTS; 2 | DROP TABLE vets IF EXISTS; 3 | DROP TABLE specialties IF EXISTS; 4 | DROP TABLE visits IF EXISTS; 5 | DROP TABLE pets IF EXISTS; 6 | DROP TABLE types IF EXISTS; 7 | DROP TABLE owners IF EXISTS; 8 | 9 | 10 | CREATE TABLE vets ( 11 | id INTEGER IDENTITY PRIMARY KEY, 12 | first_name VARCHAR(30), 13 | last_name VARCHAR(30) 14 | ); 15 | CREATE INDEX vets_last_name ON vets (last_name); 16 | 17 | CREATE TABLE specialties ( 18 | id INTEGER IDENTITY PRIMARY KEY, 19 | name VARCHAR(80) 20 | ); 21 | CREATE INDEX specialties_name ON specialties (name); 22 | 23 | CREATE TABLE vet_specialties ( 24 | vet_id INTEGER NOT NULL, 25 | specialty_id INTEGER NOT NULL 26 | ); 27 | ALTER TABLE vet_specialties ADD CONSTRAINT fk_vet_specialties_vets FOREIGN KEY (vet_id) REFERENCES vets (id); 28 | ALTER TABLE vet_specialties ADD CONSTRAINT fk_vet_specialties_specialties FOREIGN KEY (specialty_id) REFERENCES specialties (id); 29 | 30 | CREATE TABLE types ( 31 | id INTEGER IDENTITY PRIMARY KEY, 32 | name VARCHAR(80) 33 | ); 34 | CREATE INDEX types_name ON types (name); 35 | 36 | CREATE TABLE owners ( 37 | id INTEGER IDENTITY PRIMARY KEY, 38 | first_name VARCHAR(30), 39 | last_name VARCHAR_IGNORECASE(30), 40 | address VARCHAR(255), 41 | city VARCHAR(80), 42 | telephone VARCHAR(20) 43 | ); 44 | CREATE INDEX owners_last_name ON owners (last_name); 45 | 46 | CREATE TABLE pets ( 47 | id INTEGER IDENTITY PRIMARY KEY, 48 | name VARCHAR(30), 49 | birth_date DATE, 50 | type_id INTEGER NOT NULL, 51 | owner_id INTEGER NOT NULL 52 | ); 53 | ALTER TABLE pets ADD CONSTRAINT fk_pets_owners FOREIGN KEY (owner_id) REFERENCES owners (id); 54 | ALTER TABLE pets ADD CONSTRAINT fk_pets_types FOREIGN KEY (type_id) REFERENCES types (id); 55 | CREATE INDEX pets_name ON pets (name); 56 | 57 | CREATE TABLE visits ( 58 | id INTEGER IDENTITY PRIMARY KEY, 59 | pet_id INTEGER NOT NULL, 60 | visit_date DATE, 61 | description VARCHAR(255) 62 | ); 63 | ALTER TABLE visits ADD CONSTRAINT fk_visits_pets FOREIGN KEY (pet_id) REFERENCES pets (id); 64 | CREATE INDEX visits_pet_id ON visits (pet_id); 65 | -------------------------------------------------------------------------------- /petclinic/src/main/resources/db/mysql/data.sql: -------------------------------------------------------------------------------- 1 | INSERT IGNORE INTO vets VALUES (1, 'James', 'Carter'); 2 | INSERT IGNORE INTO vets VALUES (2, 'Helen', 'Leary'); 3 | INSERT IGNORE INTO vets VALUES (3, 'Linda', 'Douglas'); 4 | INSERT IGNORE INTO vets VALUES (4, 'Rafael', 'Ortega'); 5 | INSERT IGNORE INTO vets VALUES (5, 'Henry', 'Stevens'); 6 | INSERT IGNORE INTO vets VALUES (6, 'Sharon', 'Jenkins'); 7 | 8 | INSERT IGNORE INTO specialties VALUES (1, 'radiology'); 9 | INSERT IGNORE INTO specialties VALUES (2, 'surgery'); 10 | INSERT IGNORE INTO specialties VALUES (3, 'dentistry'); 11 | 12 | INSERT IGNORE INTO vet_specialties VALUES (2, 1); 13 | INSERT IGNORE INTO vet_specialties VALUES (3, 2); 14 | INSERT IGNORE INTO vet_specialties VALUES (3, 3); 15 | INSERT IGNORE INTO vet_specialties VALUES (4, 2); 16 | INSERT IGNORE INTO vet_specialties VALUES (5, 1); 17 | 18 | INSERT IGNORE INTO types VALUES (1, 'cat'); 19 | INSERT IGNORE INTO types VALUES (2, 'dog'); 20 | INSERT IGNORE INTO types VALUES (3, 'lizard'); 21 | INSERT IGNORE INTO types VALUES (4, 'snake'); 22 | INSERT IGNORE INTO types VALUES (5, 'bird'); 23 | INSERT IGNORE INTO types VALUES (6, 'hamster'); 24 | 25 | INSERT IGNORE INTO owners VALUES (1, 'George', 'Franklin', '110 W. Liberty St.', 'Madison', '6085551023'); 26 | INSERT IGNORE INTO owners VALUES (2, 'Betty', 'Davis', '638 Cardinal Ave.', 'Sun Prairie', '6085551749'); 27 | INSERT IGNORE INTO owners VALUES (3, 'Eduardo', 'Rodriquez', '2693 Commerce St.', 'McFarland', '6085558763'); 28 | INSERT IGNORE INTO owners VALUES (4, 'Harold', 'Davis', '563 Friendly St.', 'Windsor', '6085553198'); 29 | INSERT IGNORE INTO owners VALUES (5, 'Peter', 'McTavish', '2387 S. Fair Way', 'Madison', '6085552765'); 30 | INSERT IGNORE INTO owners VALUES (6, 'Jean', 'Coleman', '105 N. Lake St.', 'Monona', '6085552654'); 31 | INSERT IGNORE INTO owners VALUES (7, 'Jeff', 'Black', '1450 Oak Blvd.', 'Monona', '6085555387'); 32 | INSERT IGNORE INTO owners VALUES (8, 'Maria', 'Escobito', '345 Maple St.', 'Madison', '6085557683'); 33 | INSERT IGNORE INTO owners VALUES (9, 'David', 'Schroeder', '2749 Blackhawk Trail', 'Madison', '6085559435'); 34 | INSERT IGNORE INTO owners VALUES (10, 'Carlos', 'Estaban', '2335 Independence La.', 'Waunakee', '6085555487'); 35 | 36 | INSERT IGNORE INTO pets VALUES (1, 'Leo', '2000-09-07', 1, 1); 37 | INSERT IGNORE INTO pets VALUES (2, 'Basil', '2002-08-06', 6, 2); 38 | INSERT IGNORE INTO pets VALUES (3, 'Rosy', '2001-04-17', 2, 3); 39 | INSERT IGNORE INTO pets VALUES (4, 'Jewel', '2000-03-07', 2, 3); 40 | INSERT IGNORE INTO pets VALUES (5, 'Iggy', '2000-11-30', 3, 4); 41 | INSERT IGNORE INTO pets VALUES (6, 'George', '2000-01-20', 4, 5); 42 | INSERT IGNORE INTO pets VALUES (7, 'Samantha', '1995-09-04', 1, 6); 43 | INSERT IGNORE INTO pets VALUES (8, 'Max', '1995-09-04', 1, 6); 44 | INSERT IGNORE INTO pets VALUES (9, 'Lucky', '1999-08-06', 5, 7); 45 | INSERT IGNORE INTO pets VALUES (10, 'Mulligan', '1997-02-24', 2, 8); 46 | INSERT IGNORE INTO pets VALUES (11, 'Freddy', '2000-03-09', 5, 9); 47 | INSERT IGNORE INTO pets VALUES (12, 'Lucky', '2000-06-24', 2, 10); 48 | INSERT IGNORE INTO pets VALUES (13, 'Sly', '2002-06-08', 1, 10); 49 | 50 | INSERT IGNORE INTO visits VALUES (1, 7, '2010-03-04', 'rabies shot'); 51 | INSERT IGNORE INTO visits VALUES (2, 8, '2011-03-04', 'rabies shot'); 52 | INSERT IGNORE INTO visits VALUES (3, 8, '2009-06-04', 'neutered'); 53 | INSERT IGNORE INTO visits VALUES (4, 7, '2008-09-04', 'spayed'); 54 | -------------------------------------------------------------------------------- /petclinic/src/main/resources/db/mysql/petclinic_db_setup_mysql.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | === Spring PetClinic sample application - MySQL Configuration === 3 | ================================================================================ 4 | 5 | @author Sam Brannen 6 | @author Costin Leau 7 | @author Dave Syer 8 | 9 | -------------------------------------------------------------------------------- 10 | 11 | 1) Download and install the MySQL database (e.g., MySQL Community Server 5.1.x), 12 | which can be found here: https://dev.mysql.com/downloads/. Or run the 13 | "docker-compose.yml" from the root of the project (if you have docker installed 14 | locally): 15 | 16 | $ docker-compose up 17 | ... 18 | mysql_1_eedb4818d817 | MySQL init process done. Ready for start up. 19 | ... 20 | 21 | 2) (Once only) create the PetClinic database and user by executing the "db/mysql/user.sql" 22 | scripts. You can connect to the database running in the docker container using 23 | `mysql -u root -h localhost --protocol tcp`, but you don't need to run the script there 24 | because the petclinic user is already set up if you use the provided `docker-compose.yaml`. 25 | 26 | 3) Run the app with `spring.profiles.active=mysql` (e.g. as a System property via the command 27 | line, but any way that sets that property in a Spring Boot app should work). 28 | 29 | N.B. the "petclinic" database has to exist for the app to work with the JDBC URL value 30 | as it is configured by default. This condition is taken care of automatically by the 31 | docker-compose configuration provided, or by the `user.sql` script if you run that as 32 | root. 33 | -------------------------------------------------------------------------------- /petclinic/src/main/resources/db/mysql/schema.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS vets ( 2 | id INT(4) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 3 | first_name VARCHAR(30), 4 | last_name VARCHAR(30), 5 | INDEX(last_name) 6 | ) engine=InnoDB; 7 | 8 | CREATE TABLE IF NOT EXISTS specialties ( 9 | id INT(4) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 10 | name VARCHAR(80), 11 | INDEX(name) 12 | ) engine=InnoDB; 13 | 14 | CREATE TABLE IF NOT EXISTS vet_specialties ( 15 | vet_id INT(4) UNSIGNED NOT NULL, 16 | specialty_id INT(4) UNSIGNED NOT NULL, 17 | FOREIGN KEY (vet_id) REFERENCES vets(id), 18 | FOREIGN KEY (specialty_id) REFERENCES specialties(id), 19 | UNIQUE (vet_id,specialty_id) 20 | ) engine=InnoDB; 21 | 22 | CREATE TABLE IF NOT EXISTS types ( 23 | id INT(4) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 24 | name VARCHAR(80), 25 | INDEX(name) 26 | ) engine=InnoDB; 27 | 28 | CREATE TABLE IF NOT EXISTS owners ( 29 | id INT(4) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 30 | first_name VARCHAR(30), 31 | last_name VARCHAR(30), 32 | address VARCHAR(255), 33 | city VARCHAR(80), 34 | telephone VARCHAR(20), 35 | INDEX(last_name) 36 | ) engine=InnoDB; 37 | 38 | CREATE TABLE IF NOT EXISTS pets ( 39 | id INT(4) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 40 | name VARCHAR(30), 41 | birth_date DATE, 42 | type_id INT(4) UNSIGNED NOT NULL, 43 | owner_id INT(4) UNSIGNED NOT NULL, 44 | INDEX(name), 45 | FOREIGN KEY (owner_id) REFERENCES owners(id), 46 | FOREIGN KEY (type_id) REFERENCES types(id) 47 | ) engine=InnoDB; 48 | 49 | CREATE TABLE IF NOT EXISTS visits ( 50 | id INT(4) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 51 | pet_id INT(4) UNSIGNED NOT NULL, 52 | visit_date DATE, 53 | description VARCHAR(255), 54 | FOREIGN KEY (pet_id) REFERENCES pets(id) 55 | ) engine=InnoDB; 56 | -------------------------------------------------------------------------------- /petclinic/src/main/resources/db/mysql/user.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS petclinic; 2 | 3 | ALTER DATABASE petclinic 4 | DEFAULT CHARACTER SET utf8 5 | DEFAULT COLLATE utf8_general_ci; 6 | 7 | GRANT ALL PRIVILEGES ON petclinic.* TO 'petclinic@%' IDENTIFIED BY 'petclinic'; 8 | -------------------------------------------------------------------------------- /petclinic/src/main/resources/messages/messages.properties: -------------------------------------------------------------------------------- 1 | welcome=Welcome 2 | required=is required 3 | notFound=has not been found 4 | duplicate=is already in use 5 | nonNumeric=must be all numeric 6 | duplicateFormSubmission=Duplicate form submission is not allowed 7 | typeMismatch.date=invalid date 8 | typeMismatch.birthDate=invalid date 9 | -------------------------------------------------------------------------------- /petclinic/src/main/resources/messages/messages_de.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-apprunner-terraform/f000687a298a05ec24581325d5325ed4e6e4c666/petclinic/src/main/resources/messages/messages_de.properties -------------------------------------------------------------------------------- /petclinic/src/main/resources/messages/messages_en.properties: -------------------------------------------------------------------------------- 1 | # This file is intentionally empty. Message look-ups will fall back to the default "messages.properties" file. -------------------------------------------------------------------------------- /petclinic/src/main/resources/messages/messages_es.properties: -------------------------------------------------------------------------------- 1 | welcome=Bienvenido 2 | required=Es requerido 3 | notFound=No ha sido encontrado 4 | duplicate=Ya se encuentra en uso 5 | nonNumeric=Sólo debe contener numeros 6 | duplicateFormSubmission=No se permite el envío de formularios duplicados 7 | typeMismatch.date=Fecha invalida 8 | typeMismatch.birthDate=Fecha invalida 9 | -------------------------------------------------------------------------------- /petclinic/src/main/resources/static/resources/fonts/montserrat-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-apprunner-terraform/f000687a298a05ec24581325d5325ed4e6e4c666/petclinic/src/main/resources/static/resources/fonts/montserrat-webfont.eot -------------------------------------------------------------------------------- /petclinic/src/main/resources/static/resources/fonts/montserrat-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-apprunner-terraform/f000687a298a05ec24581325d5325ed4e6e4c666/petclinic/src/main/resources/static/resources/fonts/montserrat-webfont.ttf -------------------------------------------------------------------------------- /petclinic/src/main/resources/static/resources/fonts/montserrat-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-apprunner-terraform/f000687a298a05ec24581325d5325ed4e6e4c666/petclinic/src/main/resources/static/resources/fonts/montserrat-webfont.woff -------------------------------------------------------------------------------- /petclinic/src/main/resources/static/resources/fonts/varela_round-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-apprunner-terraform/f000687a298a05ec24581325d5325ed4e6e4c666/petclinic/src/main/resources/static/resources/fonts/varela_round-webfont.eot -------------------------------------------------------------------------------- /petclinic/src/main/resources/static/resources/fonts/varela_round-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-apprunner-terraform/f000687a298a05ec24581325d5325ed4e6e4c666/petclinic/src/main/resources/static/resources/fonts/varela_round-webfont.ttf -------------------------------------------------------------------------------- /petclinic/src/main/resources/static/resources/fonts/varela_round-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-apprunner-terraform/f000687a298a05ec24581325d5325ed4e6e4c666/petclinic/src/main/resources/static/resources/fonts/varela_round-webfont.woff -------------------------------------------------------------------------------- /petclinic/src/main/resources/static/resources/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-apprunner-terraform/f000687a298a05ec24581325d5325ed4e6e4c666/petclinic/src/main/resources/static/resources/images/favicon.png -------------------------------------------------------------------------------- /petclinic/src/main/resources/static/resources/images/pets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-apprunner-terraform/f000687a298a05ec24581325d5325ed4e6e4c666/petclinic/src/main/resources/static/resources/images/pets.png -------------------------------------------------------------------------------- /petclinic/src/main/resources/static/resources/images/platform-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-apprunner-terraform/f000687a298a05ec24581325d5325ed4e6e4c666/petclinic/src/main/resources/static/resources/images/platform-bg.png -------------------------------------------------------------------------------- /petclinic/src/main/resources/static/resources/images/spring-logo-dataflow-mobile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-apprunner-terraform/f000687a298a05ec24581325d5325ed4e6e4c666/petclinic/src/main/resources/static/resources/images/spring-logo-dataflow-mobile.png -------------------------------------------------------------------------------- /petclinic/src/main/resources/static/resources/images/spring-logo-dataflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-apprunner-terraform/f000687a298a05ec24581325d5325ed4e6e4c666/petclinic/src/main/resources/static/resources/images/spring-logo-dataflow.png -------------------------------------------------------------------------------- /petclinic/src/main/resources/static/resources/images/spring-pivotal-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-apprunner-terraform/f000687a298a05ec24581325d5325ed4e6e4c666/petclinic/src/main/resources/static/resources/images/spring-pivotal-logo.png -------------------------------------------------------------------------------- /petclinic/src/main/resources/templates/error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |

Something happened...

8 |

Exception message

9 | 10 | 11 | -------------------------------------------------------------------------------- /petclinic/src/main/resources/templates/fragments/inputField.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |
8 | 9 |
10 |
11 | 12 | 15 |
16 | 19 | 20 | 23 | Error 24 | 25 |
26 |
27 |
28 |
29 | 30 | 31 | -------------------------------------------------------------------------------- /petclinic/src/main/resources/templates/fragments/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | PetClinic :: a Spring Framework demonstration 14 | 15 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 81 |
82 |
83 | 84 | 85 | 86 |
87 |
88 |
89 |
90 |
91 | Sponsored by Pivotal
93 |
94 |
95 |
96 |
97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /petclinic/src/main/resources/templates/fragments/selectField.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |
8 | 9 | 10 |
11 | 15 | 18 | 19 | 22 | Error 23 | 24 |
25 |
26 |
27 |
28 | 29 | -------------------------------------------------------------------------------- /petclinic/src/main/resources/templates/owners/createOrUpdateOwnerForm.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 |

Owner

7 |
8 |
9 | 11 | 13 | 15 | 17 | 19 |
20 |
21 |
22 | 26 |
27 |
28 |
29 | 30 | 31 | -------------------------------------------------------------------------------- /petclinic/src/main/resources/templates/owners/findOwners.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 |

Find Owners

7 | 8 |
10 |
11 |
12 | 13 |
14 |
17 |

Error

18 |
19 |
20 |
21 |
22 |
23 |
24 | 26 |
27 |
28 | 29 |
30 | 31 |
32 | Add Owner 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /petclinic/src/main/resources/templates/owners/ownerDetails.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 |

Owner Information

10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
Name
Address
City
Telephone
30 | 31 | Edit 32 | Owner 33 | Add 34 | New Pet 35 | 36 |
37 |
38 |
39 |

Pets and Visits

40 | 41 | 42 | 43 | 44 | 55 | 77 | 78 | 79 |
45 |
46 |
Name
47 |
48 |
Birth Date
49 |
51 |
Type
52 |
53 |
54 |
56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 71 | 74 | 75 |
Visit DateDescription
Edit 70 | PetAdd 73 | Visit
76 |
80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /petclinic/src/main/resources/templates/owners/ownersList.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |

Owners

8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 24 | 28 | 29 | 30 |
NameAddressCityTelephonePets
22 | 23 | 25 | 26 | 27 |
31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /petclinic/src/main/resources/templates/pets/createOrUpdatePetForm.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 |

7 | New 8 | Pet 9 |

10 |
11 | 12 |
13 |
14 | 15 |
16 | 17 |
18 |
19 | 21 | 23 | 25 |
26 |
27 |
28 | 32 |
33 |
34 |
35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /petclinic/src/main/resources/templates/pets/createOrUpdateVisitForm.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 |

7 | New 8 | Visit 9 |

10 | 11 | Pet 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 25 | 26 | 28 | 29 |
NameBirth DateTypeOwner
30 | 31 |
32 |
33 | 35 | 37 |
38 | 39 |
40 |
41 | 42 | 43 |
44 |
45 |
46 | 47 |
48 | Previous Visits 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 |
DateDescription
59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /petclinic/src/main/resources/templates/vets/vetList.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 |

Veterinarians

9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 |
NameSpecialties
none
26 | 27 | 28 | -------------------------------------------------------------------------------- /petclinic/src/main/resources/templates/welcome.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |

Welcome

8 |
9 |
10 | 11 |
12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /petclinic/src/main/wro/wro.properties: -------------------------------------------------------------------------------- 1 | #List of preProcessors 2 | preProcessors=lessCssImport 3 | #List of postProcessors 4 | postProcessors=less4j -------------------------------------------------------------------------------- /petclinic/src/main/wro/wro.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | classpath:META-INF/resources/webjars/bootstrap/3.3.6/less/bootstrap.less 4 | /petclinic.less 5 | 6 | 7 | -------------------------------------------------------------------------------- /petclinic/src/test/java/org/springframework/samples/petclinic/PetclinicIntegrationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.samples.petclinic; 18 | 19 | import org.junit.jupiter.api.Test; 20 | import org.springframework.beans.factory.annotation.Autowired; 21 | import org.springframework.boot.test.context.SpringBootTest; 22 | import org.springframework.samples.petclinic.vet.VetRepository; 23 | 24 | @SpringBootTest 25 | class PetclinicIntegrationTests { 26 | 27 | @Autowired 28 | private VetRepository vets; 29 | 30 | @Test 31 | void testFindAll() throws Exception { 32 | vets.findAll(); 33 | vets.findAll(); // served from cache 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /petclinic/src/test/java/org/springframework/samples/petclinic/model/ValidatorTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.samples.petclinic.model; 18 | 19 | import java.util.Locale; 20 | import java.util.Set; 21 | 22 | import javax.validation.ConstraintViolation; 23 | import javax.validation.Validator; 24 | 25 | import org.junit.jupiter.api.Test; 26 | import org.springframework.context.i18n.LocaleContextHolder; 27 | import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; 28 | 29 | import static org.assertj.core.api.Assertions.assertThat; 30 | 31 | /** 32 | * @author Michael Isvy Simple test to make sure that Bean Validation is working (useful 33 | * when upgrading to a new version of Hibernate Validator/ Bean Validation) 34 | */ 35 | class ValidatorTests { 36 | 37 | private Validator createValidator() { 38 | LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean(); 39 | localValidatorFactoryBean.afterPropertiesSet(); 40 | return localValidatorFactoryBean; 41 | } 42 | 43 | @Test 44 | void shouldNotValidateWhenFirstNameEmpty() { 45 | 46 | LocaleContextHolder.setLocale(Locale.ENGLISH); 47 | Person person = new Person(); 48 | person.setFirstName(""); 49 | person.setLastName("smith"); 50 | 51 | Validator validator = createValidator(); 52 | Set> constraintViolations = validator.validate(person); 53 | 54 | assertThat(constraintViolations).hasSize(1); 55 | ConstraintViolation violation = constraintViolations.iterator().next(); 56 | assertThat(violation.getPropertyPath().toString()).isEqualTo("firstName"); 57 | assertThat(violation.getMessage()).isEqualTo("must not be empty"); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /petclinic/src/test/java/org/springframework/samples/petclinic/owner/OwnerControllerTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.samples.petclinic.owner; 18 | 19 | import java.time.LocalDate; 20 | import java.util.Collections; 21 | import java.util.List; 22 | 23 | import org.assertj.core.util.Lists; 24 | import org.hamcrest.BaseMatcher; 25 | import org.hamcrest.Description; 26 | import org.junit.jupiter.api.BeforeEach; 27 | import org.junit.jupiter.api.Test; 28 | import org.springframework.beans.factory.annotation.Autowired; 29 | import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; 30 | import org.springframework.boot.test.mock.mockito.MockBean; 31 | import org.springframework.samples.petclinic.visit.Visit; 32 | import org.springframework.samples.petclinic.visit.VisitRepository; 33 | import org.springframework.test.web.servlet.MockMvc; 34 | 35 | import static org.hamcrest.Matchers.empty; 36 | import static org.hamcrest.Matchers.hasProperty; 37 | import static org.hamcrest.Matchers.is; 38 | import static org.hamcrest.Matchers.not; 39 | import static org.mockito.BDDMockito.given; 40 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 41 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; 42 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; 43 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 44 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; 45 | 46 | /** 47 | * Test class for {@link OwnerController} 48 | * 49 | * @author Colin But 50 | */ 51 | @WebMvcTest(OwnerController.class) 52 | class OwnerControllerTests { 53 | 54 | private static final int TEST_OWNER_ID = 1; 55 | 56 | @Autowired 57 | private MockMvc mockMvc; 58 | 59 | @MockBean 60 | private OwnerRepository owners; 61 | 62 | @MockBean 63 | private VisitRepository visits; 64 | 65 | private Owner george; 66 | 67 | @BeforeEach 68 | void setup() { 69 | george = new Owner(); 70 | george.setId(TEST_OWNER_ID); 71 | george.setFirstName("George"); 72 | george.setLastName("Franklin"); 73 | george.setAddress("110 W. Liberty St."); 74 | george.setCity("Madison"); 75 | george.setTelephone("6085551023"); 76 | Pet max = new Pet(); 77 | PetType dog = new PetType(); 78 | dog.setName("dog"); 79 | max.setId(1); 80 | max.setType(dog); 81 | max.setName("Max"); 82 | max.setBirthDate(LocalDate.now()); 83 | george.setPetsInternal(Collections.singleton(max)); 84 | given(this.owners.findById(TEST_OWNER_ID)).willReturn(george); 85 | Visit visit = new Visit(); 86 | visit.setDate(LocalDate.now()); 87 | given(this.visits.findByPetId(max.getId())).willReturn(Collections.singletonList(visit)); 88 | } 89 | 90 | @Test 91 | void testInitCreationForm() throws Exception { 92 | mockMvc.perform(get("/owners/new")).andExpect(status().isOk()).andExpect(model().attributeExists("owner")) 93 | .andExpect(view().name("owners/createOrUpdateOwnerForm")); 94 | } 95 | 96 | @Test 97 | void testProcessCreationFormSuccess() throws Exception { 98 | mockMvc.perform(post("/owners/new").param("firstName", "Joe").param("lastName", "Bloggs") 99 | .param("address", "123 Caramel Street").param("city", "London").param("telephone", "01316761638")) 100 | .andExpect(status().is3xxRedirection()); 101 | } 102 | 103 | @Test 104 | void testProcessCreationFormHasErrors() throws Exception { 105 | mockMvc.perform( 106 | post("/owners/new").param("firstName", "Joe").param("lastName", "Bloggs").param("city", "London")) 107 | .andExpect(status().isOk()).andExpect(model().attributeHasErrors("owner")) 108 | .andExpect(model().attributeHasFieldErrors("owner", "address")) 109 | .andExpect(model().attributeHasFieldErrors("owner", "telephone")) 110 | .andExpect(view().name("owners/createOrUpdateOwnerForm")); 111 | } 112 | 113 | @Test 114 | void testInitFindForm() throws Exception { 115 | mockMvc.perform(get("/owners/find")).andExpect(status().isOk()).andExpect(model().attributeExists("owner")) 116 | .andExpect(view().name("owners/findOwners")); 117 | } 118 | 119 | @Test 120 | void testProcessFindFormSuccess() throws Exception { 121 | given(this.owners.findByLastName("")).willReturn(Lists.newArrayList(george, new Owner())); 122 | mockMvc.perform(get("/owners")).andExpect(status().isOk()).andExpect(view().name("owners/ownersList")); 123 | } 124 | 125 | @Test 126 | void testProcessFindFormByLastName() throws Exception { 127 | given(this.owners.findByLastName(george.getLastName())).willReturn(Lists.newArrayList(george)); 128 | mockMvc.perform(get("/owners").param("lastName", "Franklin")).andExpect(status().is3xxRedirection()) 129 | .andExpect(view().name("redirect:/owners/" + TEST_OWNER_ID)); 130 | } 131 | 132 | @Test 133 | void testProcessFindFormNoOwnersFound() throws Exception { 134 | mockMvc.perform(get("/owners").param("lastName", "Unknown Surname")).andExpect(status().isOk()) 135 | .andExpect(model().attributeHasFieldErrors("owner", "lastName")) 136 | .andExpect(model().attributeHasFieldErrorCode("owner", "lastName", "notFound")) 137 | .andExpect(view().name("owners/findOwners")); 138 | } 139 | 140 | @Test 141 | void testInitUpdateOwnerForm() throws Exception { 142 | mockMvc.perform(get("/owners/{ownerId}/edit", TEST_OWNER_ID)).andExpect(status().isOk()) 143 | .andExpect(model().attributeExists("owner")) 144 | .andExpect(model().attribute("owner", hasProperty("lastName", is("Franklin")))) 145 | .andExpect(model().attribute("owner", hasProperty("firstName", is("George")))) 146 | .andExpect(model().attribute("owner", hasProperty("address", is("110 W. Liberty St.")))) 147 | .andExpect(model().attribute("owner", hasProperty("city", is("Madison")))) 148 | .andExpect(model().attribute("owner", hasProperty("telephone", is("6085551023")))) 149 | .andExpect(view().name("owners/createOrUpdateOwnerForm")); 150 | } 151 | 152 | @Test 153 | void testProcessUpdateOwnerFormSuccess() throws Exception { 154 | mockMvc.perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID).param("firstName", "Joe") 155 | .param("lastName", "Bloggs").param("address", "123 Caramel Street").param("city", "London") 156 | .param("telephone", "01616291589")).andExpect(status().is3xxRedirection()) 157 | .andExpect(view().name("redirect:/owners/{ownerId}")); 158 | } 159 | 160 | @Test 161 | void testProcessUpdateOwnerFormHasErrors() throws Exception { 162 | mockMvc.perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID).param("firstName", "Joe") 163 | .param("lastName", "Bloggs").param("city", "London")).andExpect(status().isOk()) 164 | .andExpect(model().attributeHasErrors("owner")) 165 | .andExpect(model().attributeHasFieldErrors("owner", "address")) 166 | .andExpect(model().attributeHasFieldErrors("owner", "telephone")) 167 | .andExpect(view().name("owners/createOrUpdateOwnerForm")); 168 | } 169 | 170 | @Test 171 | void testShowOwner() throws Exception { 172 | mockMvc.perform(get("/owners/{ownerId}", TEST_OWNER_ID)).andExpect(status().isOk()) 173 | .andExpect(model().attribute("owner", hasProperty("lastName", is("Franklin")))) 174 | .andExpect(model().attribute("owner", hasProperty("firstName", is("George")))) 175 | .andExpect(model().attribute("owner", hasProperty("address", is("110 W. Liberty St.")))) 176 | .andExpect(model().attribute("owner", hasProperty("city", is("Madison")))) 177 | .andExpect(model().attribute("owner", hasProperty("telephone", is("6085551023")))) 178 | .andExpect(model().attribute("owner", hasProperty("pets", not(empty())))) 179 | .andExpect(model().attribute("owner", hasProperty("pets", new BaseMatcher>() { 180 | 181 | @Override 182 | public boolean matches(Object item) { 183 | @SuppressWarnings("unchecked") 184 | List pets = (List) item; 185 | Pet pet = pets.get(0); 186 | if (pet.getVisits().isEmpty()) { 187 | return false; 188 | } 189 | return true; 190 | } 191 | 192 | @Override 193 | public void describeTo(Description description) { 194 | description.appendText("Max did not have any visits"); 195 | } 196 | }))).andExpect(view().name("owners/ownerDetails")); 197 | } 198 | 199 | } 200 | -------------------------------------------------------------------------------- /petclinic/src/test/java/org/springframework/samples/petclinic/owner/PetControllerTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.samples.petclinic.owner; 18 | 19 | import static org.mockito.BDDMockito.given; 20 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 21 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; 22 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; 23 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 24 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; 25 | 26 | import org.assertj.core.util.Lists; 27 | import org.junit.jupiter.api.BeforeEach; 28 | import org.junit.jupiter.api.Test; 29 | import org.springframework.beans.factory.annotation.Autowired; 30 | import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; 31 | import org.springframework.boot.test.mock.mockito.MockBean; 32 | import org.springframework.context.annotation.ComponentScan; 33 | import org.springframework.context.annotation.FilterType; 34 | import org.springframework.test.web.servlet.MockMvc; 35 | 36 | /** 37 | * Test class for the {@link PetController} 38 | * 39 | * @author Colin But 40 | */ 41 | @WebMvcTest(value = PetController.class, 42 | includeFilters = @ComponentScan.Filter(value = PetTypeFormatter.class, type = FilterType.ASSIGNABLE_TYPE)) 43 | class PetControllerTests { 44 | 45 | private static final int TEST_OWNER_ID = 1; 46 | 47 | private static final int TEST_PET_ID = 1; 48 | 49 | @Autowired 50 | private MockMvc mockMvc; 51 | 52 | @MockBean 53 | private PetRepository pets; 54 | 55 | @MockBean 56 | private OwnerRepository owners; 57 | 58 | @BeforeEach 59 | void setup() { 60 | PetType cat = new PetType(); 61 | cat.setId(3); 62 | cat.setName("hamster"); 63 | given(this.pets.findPetTypes()).willReturn(Lists.newArrayList(cat)); 64 | given(this.owners.findById(TEST_OWNER_ID)).willReturn(new Owner()); 65 | given(this.pets.findById(TEST_PET_ID)).willReturn(new Pet()); 66 | 67 | } 68 | 69 | @Test 70 | void testInitCreationForm() throws Exception { 71 | mockMvc.perform(get("/owners/{ownerId}/pets/new", TEST_OWNER_ID)).andExpect(status().isOk()) 72 | .andExpect(view().name("pets/createOrUpdatePetForm")).andExpect(model().attributeExists("pet")); 73 | } 74 | 75 | @Test 76 | void testProcessCreationFormSuccess() throws Exception { 77 | mockMvc.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID).param("name", "Betty") 78 | .param("type", "hamster").param("birthDate", "2015-02-12")).andExpect(status().is3xxRedirection()) 79 | .andExpect(view().name("redirect:/owners/{ownerId}")); 80 | } 81 | 82 | @Test 83 | void testProcessCreationFormHasErrors() throws Exception { 84 | mockMvc.perform(post("/owners/{ownerId}/pets/new", TEST_OWNER_ID).param("name", "Betty").param("birthDate", 85 | "2015-02-12")).andExpect(model().attributeHasNoErrors("owner")) 86 | .andExpect(model().attributeHasErrors("pet")).andExpect(model().attributeHasFieldErrors("pet", "type")) 87 | .andExpect(model().attributeHasFieldErrorCode("pet", "type", "required")).andExpect(status().isOk()) 88 | .andExpect(view().name("pets/createOrUpdatePetForm")); 89 | } 90 | 91 | @Test 92 | void testInitUpdateForm() throws Exception { 93 | mockMvc.perform(get("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID)) 94 | .andExpect(status().isOk()).andExpect(model().attributeExists("pet")) 95 | .andExpect(view().name("pets/createOrUpdatePetForm")); 96 | } 97 | 98 | @Test 99 | void testProcessUpdateFormSuccess() throws Exception { 100 | mockMvc.perform(post("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID).param("name", "Betty") 101 | .param("type", "hamster").param("birthDate", "2015-02-12")).andExpect(status().is3xxRedirection()) 102 | .andExpect(view().name("redirect:/owners/{ownerId}")); 103 | } 104 | 105 | @Test 106 | void testProcessUpdateFormHasErrors() throws Exception { 107 | mockMvc.perform(post("/owners/{ownerId}/pets/{petId}/edit", TEST_OWNER_ID, TEST_PET_ID).param("name", "Betty") 108 | .param("birthDate", "2015/02/12")).andExpect(model().attributeHasNoErrors("owner")) 109 | .andExpect(model().attributeHasErrors("pet")).andExpect(status().isOk()) 110 | .andExpect(view().name("pets/createOrUpdatePetForm")); 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /petclinic/src/test/java/org/springframework/samples/petclinic/owner/PetTypeFormatterTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.samples.petclinic.owner; 18 | 19 | import java.text.ParseException; 20 | import java.util.ArrayList; 21 | import java.util.Collection; 22 | import java.util.List; 23 | import java.util.Locale; 24 | 25 | import org.junit.jupiter.api.Assertions; 26 | import org.junit.jupiter.api.BeforeEach; 27 | import org.junit.jupiter.api.Test; 28 | import org.junit.jupiter.api.extension.ExtendWith; 29 | import org.mockito.Mock; 30 | import org.mockito.junit.jupiter.MockitoExtension; 31 | 32 | import static org.assertj.core.api.Assertions.assertThat; 33 | import static org.mockito.BDDMockito.given; 34 | 35 | /** 36 | * Test class for {@link PetTypeFormatter} 37 | * 38 | * @author Colin But 39 | */ 40 | @ExtendWith(MockitoExtension.class) 41 | class PetTypeFormatterTests { 42 | 43 | @Mock 44 | private PetRepository pets; 45 | 46 | private PetTypeFormatter petTypeFormatter; 47 | 48 | @BeforeEach 49 | void setup() { 50 | this.petTypeFormatter = new PetTypeFormatter(pets); 51 | } 52 | 53 | @Test 54 | void testPrint() { 55 | PetType petType = new PetType(); 56 | petType.setName("Hamster"); 57 | String petTypeName = this.petTypeFormatter.print(petType, Locale.ENGLISH); 58 | assertThat(petTypeName).isEqualTo("Hamster"); 59 | } 60 | 61 | @Test 62 | void shouldParse() throws ParseException { 63 | given(this.pets.findPetTypes()).willReturn(makePetTypes()); 64 | PetType petType = petTypeFormatter.parse("Bird", Locale.ENGLISH); 65 | assertThat(petType.getName()).isEqualTo("Bird"); 66 | } 67 | 68 | @Test 69 | void shouldThrowParseException() throws ParseException { 70 | given(this.pets.findPetTypes()).willReturn(makePetTypes()); 71 | Assertions.assertThrows(ParseException.class, () -> { 72 | petTypeFormatter.parse("Fish", Locale.ENGLISH); 73 | }); 74 | } 75 | 76 | /** 77 | * Helper method to produce some sample pet types just for test purpose 78 | * @return {@link Collection} of {@link PetType} 79 | */ 80 | private List makePetTypes() { 81 | List petTypes = new ArrayList<>(); 82 | petTypes.add(new PetType() { 83 | { 84 | setName("Dog"); 85 | } 86 | }); 87 | petTypes.add(new PetType() { 88 | { 89 | setName("Bird"); 90 | } 91 | }); 92 | return petTypes; 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /petclinic/src/test/java/org/springframework/samples/petclinic/owner/VisitControllerTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.samples.petclinic.owner; 18 | 19 | import static org.mockito.BDDMockito.given; 20 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 21 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; 22 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; 23 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 24 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; 25 | 26 | import org.junit.jupiter.api.BeforeEach; 27 | import org.junit.jupiter.api.Test; 28 | import org.springframework.beans.factory.annotation.Autowired; 29 | import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; 30 | import org.springframework.boot.test.mock.mockito.MockBean; 31 | import org.springframework.samples.petclinic.visit.VisitRepository; 32 | import org.springframework.test.web.servlet.MockMvc; 33 | 34 | /** 35 | * Test class for {@link VisitController} 36 | * 37 | * @author Colin But 38 | */ 39 | @WebMvcTest(VisitController.class) 40 | class VisitControllerTests { 41 | 42 | private static final int TEST_PET_ID = 1; 43 | 44 | @Autowired 45 | private MockMvc mockMvc; 46 | 47 | @MockBean 48 | private VisitRepository visits; 49 | 50 | @MockBean 51 | private PetRepository pets; 52 | 53 | @BeforeEach 54 | void init() { 55 | given(this.pets.findById(TEST_PET_ID)).willReturn(new Pet()); 56 | } 57 | 58 | @Test 59 | void testInitNewVisitForm() throws Exception { 60 | mockMvc.perform(get("/owners/*/pets/{petId}/visits/new", TEST_PET_ID)).andExpect(status().isOk()) 61 | .andExpect(view().name("pets/createOrUpdateVisitForm")); 62 | } 63 | 64 | @Test 65 | void testProcessNewVisitFormSuccess() throws Exception { 66 | mockMvc.perform(post("/owners/*/pets/{petId}/visits/new", TEST_PET_ID).param("name", "George") 67 | .param("description", "Visit Description")).andExpect(status().is3xxRedirection()) 68 | .andExpect(view().name("redirect:/owners/{ownerId}")); 69 | } 70 | 71 | @Test 72 | void testProcessNewVisitFormHasErrors() throws Exception { 73 | mockMvc.perform(post("/owners/*/pets/{petId}/visits/new", TEST_PET_ID).param("name", "George")) 74 | .andExpect(model().attributeHasErrors("visit")).andExpect(status().isOk()) 75 | .andExpect(view().name("pets/createOrUpdateVisitForm")); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /petclinic/src/test/java/org/springframework/samples/petclinic/service/ClinicServiceTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.samples.petclinic.service; 18 | 19 | import static org.assertj.core.api.Assertions.assertThat; 20 | 21 | import java.time.LocalDate; 22 | import java.util.Collection; 23 | 24 | import org.junit.jupiter.api.Test; 25 | import org.springframework.beans.factory.annotation.Autowired; 26 | import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; 27 | import org.springframework.context.annotation.ComponentScan; 28 | import org.springframework.samples.petclinic.owner.Owner; 29 | import org.springframework.samples.petclinic.owner.OwnerRepository; 30 | import org.springframework.samples.petclinic.owner.Pet; 31 | import org.springframework.samples.petclinic.owner.PetRepository; 32 | import org.springframework.samples.petclinic.owner.PetType; 33 | import org.springframework.samples.petclinic.vet.Vet; 34 | import org.springframework.samples.petclinic.vet.VetRepository; 35 | import org.springframework.samples.petclinic.visit.Visit; 36 | import org.springframework.samples.petclinic.visit.VisitRepository; 37 | import org.springframework.stereotype.Service; 38 | import org.springframework.transaction.annotation.Transactional; 39 | 40 | /** 41 | * Integration test of the Service and the Repository layer. 42 | *

43 | * ClinicServiceSpringDataJpaTests subclasses benefit from the following services provided 44 | * by the Spring TestContext Framework: 45 | *

46 | *
    47 | *
  • Spring IoC container caching which spares us unnecessary set up 48 | * time between test execution.
  • 49 | *
  • Dependency Injection of test fixture instances, meaning that we 50 | * don't need to perform application context lookups. See the use of 51 | * {@link Autowired @Autowired} on the {@link 52 | * ClinicServiceTests#clinicService clinicService} instance variable, which uses 53 | * autowiring by type. 54 | *
  • Transaction management, meaning each test method is executed in 55 | * its own transaction, which is automatically rolled back by default. Thus, even if tests 56 | * insert or otherwise change database state, there is no need for a teardown or cleanup 57 | * script. 58 | *
  • An {@link org.springframework.context.ApplicationContext ApplicationContext} is 59 | * also inherited and can be used for explicit bean lookup if necessary.
  • 60 | *
61 | * 62 | * @author Ken Krebs 63 | * @author Rod Johnson 64 | * @author Juergen Hoeller 65 | * @author Sam Brannen 66 | * @author Michael Isvy 67 | * @author Dave Syer 68 | */ 69 | @DataJpaTest(includeFilters = @ComponentScan.Filter(Service.class)) 70 | class ClinicServiceTests { 71 | 72 | @Autowired 73 | protected OwnerRepository owners; 74 | 75 | @Autowired 76 | protected PetRepository pets; 77 | 78 | @Autowired 79 | protected VisitRepository visits; 80 | 81 | @Autowired 82 | protected VetRepository vets; 83 | 84 | @Test 85 | void shouldFindOwnersByLastName() { 86 | Collection owners = this.owners.findByLastName("Davis"); 87 | assertThat(owners).hasSize(2); 88 | 89 | owners = this.owners.findByLastName("Daviss"); 90 | assertThat(owners).isEmpty(); 91 | } 92 | 93 | @Test 94 | void shouldFindSingleOwnerWithPet() { 95 | Owner owner = this.owners.findById(1); 96 | assertThat(owner.getLastName()).startsWith("Franklin"); 97 | assertThat(owner.getPets()).hasSize(1); 98 | assertThat(owner.getPets().get(0).getType()).isNotNull(); 99 | assertThat(owner.getPets().get(0).getType().getName()).isEqualTo("cat"); 100 | } 101 | 102 | @Test 103 | @Transactional 104 | void shouldInsertOwner() { 105 | Collection owners = this.owners.findByLastName("Schultz"); 106 | int found = owners.size(); 107 | 108 | Owner owner = new Owner(); 109 | owner.setFirstName("Sam"); 110 | owner.setLastName("Schultz"); 111 | owner.setAddress("4, Evans Street"); 112 | owner.setCity("Wollongong"); 113 | owner.setTelephone("4444444444"); 114 | this.owners.save(owner); 115 | assertThat(owner.getId().longValue()).isNotEqualTo(0); 116 | 117 | owners = this.owners.findByLastName("Schultz"); 118 | assertThat(owners.size()).isEqualTo(found + 1); 119 | } 120 | 121 | @Test 122 | @Transactional 123 | void shouldUpdateOwner() { 124 | Owner owner = this.owners.findById(1); 125 | String oldLastName = owner.getLastName(); 126 | String newLastName = oldLastName + "X"; 127 | 128 | owner.setLastName(newLastName); 129 | this.owners.save(owner); 130 | 131 | // retrieving new name from database 132 | owner = this.owners.findById(1); 133 | assertThat(owner.getLastName()).isEqualTo(newLastName); 134 | } 135 | 136 | @Test 137 | void shouldFindPetWithCorrectId() { 138 | Pet pet7 = this.pets.findById(7); 139 | assertThat(pet7.getName()).startsWith("Samantha"); 140 | assertThat(pet7.getOwner().getFirstName()).isEqualTo("Jean"); 141 | 142 | } 143 | 144 | @Test 145 | void shouldFindAllPetTypes() { 146 | Collection petTypes = this.pets.findPetTypes(); 147 | 148 | PetType petType1 = EntityUtils.getById(petTypes, PetType.class, 1); 149 | assertThat(petType1.getName()).isEqualTo("cat"); 150 | PetType petType4 = EntityUtils.getById(petTypes, PetType.class, 4); 151 | assertThat(petType4.getName()).isEqualTo("snake"); 152 | } 153 | 154 | @Test 155 | @Transactional 156 | void shouldInsertPetIntoDatabaseAndGenerateId() { 157 | Owner owner6 = this.owners.findById(6); 158 | int found = owner6.getPets().size(); 159 | 160 | Pet pet = new Pet(); 161 | pet.setName("bowser"); 162 | Collection types = this.pets.findPetTypes(); 163 | pet.setType(EntityUtils.getById(types, PetType.class, 2)); 164 | pet.setBirthDate(LocalDate.now()); 165 | owner6.addPet(pet); 166 | assertThat(owner6.getPets().size()).isEqualTo(found + 1); 167 | 168 | this.pets.save(pet); 169 | this.owners.save(owner6); 170 | 171 | owner6 = this.owners.findById(6); 172 | assertThat(owner6.getPets().size()).isEqualTo(found + 1); 173 | // checks that id has been generated 174 | assertThat(pet.getId()).isNotNull(); 175 | } 176 | 177 | @Test 178 | @Transactional 179 | void shouldUpdatePetName() throws Exception { 180 | Pet pet7 = this.pets.findById(7); 181 | String oldName = pet7.getName(); 182 | 183 | String newName = oldName + "X"; 184 | pet7.setName(newName); 185 | this.pets.save(pet7); 186 | 187 | pet7 = this.pets.findById(7); 188 | assertThat(pet7.getName()).isEqualTo(newName); 189 | } 190 | 191 | @Test 192 | void shouldFindVets() { 193 | Collection vets = this.vets.findAll(); 194 | 195 | Vet vet = EntityUtils.getById(vets, Vet.class, 3); 196 | assertThat(vet.getLastName()).isEqualTo("Douglas"); 197 | assertThat(vet.getNrOfSpecialties()).isEqualTo(2); 198 | assertThat(vet.getSpecialties().get(0).getName()).isEqualTo("dentistry"); 199 | assertThat(vet.getSpecialties().get(1).getName()).isEqualTo("surgery"); 200 | } 201 | 202 | @Test 203 | @Transactional 204 | void shouldAddNewVisitForPet() { 205 | Pet pet7 = this.pets.findById(7); 206 | int found = pet7.getVisits().size(); 207 | Visit visit = new Visit(); 208 | pet7.addVisit(visit); 209 | visit.setDescription("test"); 210 | this.visits.save(visit); 211 | this.pets.save(pet7); 212 | 213 | pet7 = this.pets.findById(7); 214 | assertThat(pet7.getVisits().size()).isEqualTo(found + 1); 215 | assertThat(visit.getId()).isNotNull(); 216 | } 217 | 218 | @Test 219 | void shouldFindVisitsByPetId() throws Exception { 220 | Collection visits = this.visits.findByPetId(7); 221 | assertThat(visits).hasSize(2); 222 | Visit[] visitArr = visits.toArray(new Visit[visits.size()]); 223 | assertThat(visitArr[0].getDate()).isNotNull(); 224 | assertThat(visitArr[0].getPetId()).isEqualTo(7); 225 | } 226 | 227 | } 228 | -------------------------------------------------------------------------------- /petclinic/src/test/java/org/springframework/samples/petclinic/service/EntityUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.samples.petclinic.service; 18 | 19 | import java.util.Collection; 20 | 21 | import org.springframework.orm.ObjectRetrievalFailureException; 22 | import org.springframework.samples.petclinic.model.BaseEntity; 23 | 24 | /** 25 | * Utility methods for handling entities. Separate from the BaseEntity class mainly 26 | * because of dependency on the ORM-associated ObjectRetrievalFailureException. 27 | * 28 | * @author Juergen Hoeller 29 | * @author Sam Brannen 30 | * @see org.springframework.samples.petclinic.model.BaseEntity 31 | * @since 29.10.2003 32 | */ 33 | public abstract class EntityUtils { 34 | 35 | /** 36 | * Look up the entity of the given class with the given id in the given collection. 37 | * @param entities the collection to search 38 | * @param entityClass the entity class to look up 39 | * @param entityId the entity id to look up 40 | * @return the found entity 41 | * @throws ObjectRetrievalFailureException if the entity was not found 42 | */ 43 | public static T getById(Collection entities, Class entityClass, int entityId) 44 | throws ObjectRetrievalFailureException { 45 | for (T entity : entities) { 46 | if (entity.getId() == entityId && entityClass.isInstance(entity)) { 47 | return entity; 48 | } 49 | } 50 | throw new ObjectRetrievalFailureException(entityClass, entityId); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /petclinic/src/test/java/org/springframework/samples/petclinic/system/CrashControllerTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.samples.petclinic.system; 18 | 19 | import org.junit.jupiter.api.Disabled; 20 | import org.junit.jupiter.api.Test; 21 | import org.springframework.beans.factory.annotation.Autowired; 22 | import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; 23 | import org.springframework.test.web.servlet.MockMvc; 24 | 25 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 26 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl; 27 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; 28 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 29 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; 30 | 31 | /** 32 | * Test class for {@link CrashController} 33 | * 34 | * @author Colin But 35 | */ 36 | // Waiting https://github.com/spring-projects/spring-boot/issues/5574 37 | @Disabled 38 | @WebMvcTest(controllers = CrashController.class) 39 | class CrashControllerTests { 40 | 41 | @Autowired 42 | private MockMvc mockMvc; 43 | 44 | @Test 45 | void testTriggerException() throws Exception { 46 | mockMvc.perform(get("/oups")).andExpect(view().name("exception")) 47 | .andExpect(model().attributeExists("exception")).andExpect(forwardedUrl("exception")) 48 | .andExpect(status().isOk()); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /petclinic/src/test/java/org/springframework/samples/petclinic/vet/VetControllerTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.samples.petclinic.vet; 18 | 19 | import static org.mockito.BDDMockito.given; 20 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 21 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; 22 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; 23 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; 24 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 25 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; 26 | 27 | import org.assertj.core.util.Lists; 28 | import org.junit.jupiter.api.BeforeEach; 29 | import org.junit.jupiter.api.Test; 30 | import org.springframework.beans.factory.annotation.Autowired; 31 | import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; 32 | import org.springframework.boot.test.mock.mockito.MockBean; 33 | import org.springframework.http.MediaType; 34 | import org.springframework.test.web.servlet.MockMvc; 35 | import org.springframework.test.web.servlet.ResultActions; 36 | 37 | /** 38 | * Test class for the {@link VetController} 39 | */ 40 | @WebMvcTest(VetController.class) 41 | class VetControllerTests { 42 | 43 | @Autowired 44 | private MockMvc mockMvc; 45 | 46 | @MockBean 47 | private VetRepository vets; 48 | 49 | @BeforeEach 50 | void setup() { 51 | Vet james = new Vet(); 52 | james.setFirstName("James"); 53 | james.setLastName("Carter"); 54 | james.setId(1); 55 | Vet helen = new Vet(); 56 | helen.setFirstName("Helen"); 57 | helen.setLastName("Leary"); 58 | helen.setId(2); 59 | Specialty radiology = new Specialty(); 60 | radiology.setId(1); 61 | radiology.setName("radiology"); 62 | helen.addSpecialty(radiology); 63 | given(this.vets.findAll()).willReturn(Lists.newArrayList(james, helen)); 64 | } 65 | 66 | @Test 67 | void testShowVetListHtml() throws Exception { 68 | mockMvc.perform(get("/vets.html")).andExpect(status().isOk()).andExpect(model().attributeExists("vets")) 69 | .andExpect(view().name("vets/vetList")); 70 | } 71 | 72 | @Test 73 | void testShowResourcesVetList() throws Exception { 74 | ResultActions actions = mockMvc.perform(get("/vets").accept(MediaType.APPLICATION_JSON)) 75 | .andExpect(status().isOk()); 76 | actions.andExpect(content().contentType(MediaType.APPLICATION_JSON)) 77 | .andExpect(jsonPath("$.vetList[0].id").value(1)); 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /petclinic/src/test/java/org/springframework/samples/petclinic/vet/VetTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.samples.petclinic.vet; 17 | 18 | import org.junit.jupiter.api.Test; 19 | import org.springframework.util.SerializationUtils; 20 | 21 | import static org.assertj.core.api.Assertions.assertThat; 22 | 23 | /** 24 | * @author Dave Syer 25 | */ 26 | class VetTests { 27 | 28 | @Test 29 | void testSerialization() { 30 | Vet vet = new Vet(); 31 | vet.setFirstName("Zaphod"); 32 | vet.setLastName("Beeblebrox"); 33 | vet.setId(123); 34 | Vet other = (Vet) SerializationUtils.deserialize(SerializationUtils.serialize(vet)); 35 | assertThat(other.getFirstName()).isEqualTo(vet.getFirstName()); 36 | assertThat(other.getLastName()).isEqualTo(vet.getLastName()); 37 | assertThat(other.getId()).isEqualTo(vet.getId()); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /terraform/appbuild.tf: -------------------------------------------------------------------------------- 1 | #data "aws_caller_identity" "current" {} 2 | resource "null_resource" "petclinic_springboot" { 3 | provisioner "local-exec" { 4 | command = < imagedefinitions.json 153 | cache: 154 | paths: 155 | - '/root/.m2/**/*' 156 | artifacts: 157 | files: imagedefinitions.json 158 | BUILDSPEC 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /terraform/codecommit.tf: -------------------------------------------------------------------------------- 1 | # --------------------------------------------------------------------------------------------------------------------- 2 | # Code Commit 3 | # --------------------------------------------------------------------------------------------------------------------- 4 | 5 | # Code Commit repo 6 | 7 | resource "aws_codecommit_repository" "source_repo" { 8 | repository_name = var.source_repo_name 9 | description = "This is the app source repository" 10 | } 11 | 12 | 13 | # Trigger role and event rule to trigger pipeline 14 | 15 | resource "aws_iam_role" "trigger_role" { 16 | assume_role_policy = <