Merge remote-tracking branch 'refs/remotes/spring-projects/master'

This commit is contained in:
Wei Ding 2016-05-19 13:47:35 +08:00
commit 9d8becea3e
77 changed files with 1676 additions and 1358 deletions

12
.editorconfig Normal file
View file

@ -0,0 +1,12 @@
# top-most EditorConfig file
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
[*.{java,xml}]
indent_size = 4
trim_trailing_whitespace = true

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<beansProjectDescription>
<version>1</version>
<pluginVersion><![CDATA[3.2.0.201301251408-M2]]></pluginVersion>
<pluginVersion><![CDATA[3.5.0.201404011509-RELEASE]]></pluginVersion>
<configSuffixes>
<configSuffix><![CDATA[xml]]></configSuffix>
</configSuffixes>
@ -12,6 +12,9 @@
<config>src/main/resources/spring/mvc-view-config.xml</config>
<config>src/main/resources/spring/business-config.xml</config>
</configs>
<autoconfigs>
<config>src/main/resources/spring/tools-config.xml</config>
</autoconfigs>
<configSets>
</configSets>
</beansProjectDescription>

805
pom.xml
View file

@ -1,458 +1,413 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.samples</groupId>
<artifactId>spring-petclinic</artifactId>
<version>1.0.0-SNAPSHOT</version>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.samples</groupId>
<artifactId>spring-petclinic</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>petclinic</name>
<packaging>war</packaging>
<name>petclinic</name>
<packaging>war</packaging>
<properties>
<properties>
<!-- Generic properties -->
<java.version>1.6</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- Generic properties -->
<java.version>1.7</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- Spring -->
<spring-framework.version>4.0.1.RELEASE</spring-framework.version>
<spring-data-jpa.version>1.4.3.RELEASE</spring-data-jpa.version>
<!-- Spring -->
<spring-io-platform.version>1.1.3.RELEASE</spring-io-platform.version>
<spring-data-jdbc.version>1.1.0.RELEASE</spring-data-jdbc.version>
<!-- Java EE / Java SE dependencies -->
<jsp.version>2.2</jsp.version>
<jstl.version>1.2</jstl.version>
<tomcat.servlet.version>7.0.30</tomcat.servlet.version>
<jaxb-impl.version>2.2.7</jaxb-impl.version>
<!-- Java EE / Java SE dependencies -->
<tomcat.version>7.0.59</tomcat.version>
<!-- Hibernate / JPA -->
<hibernate.version>4.3.1.Final</hibernate.version>
<!-- Test -->
<assertj.version>2.2.0</assertj.version>
<!-- Bean validation -->
<hibernate-validator.version>4.3.1.Final</hibernate-validator.version>
<!-- Dates -->
<jodatime-hibernate.version>1.3</jodatime-hibernate.version>
<jodatime-jsptags.version>1.1.1</jodatime-jsptags.version>
<jadira-usertype-core.version>3.2.0.GA</jadira-usertype-core.version>
<!-- Database access -->
<tomcat-jdbc.version>7.0.42</tomcat-jdbc.version>
<ehcache.version>2.6.8</ehcache.version>
<hsqldb.version>2.3.1</hsqldb.version>
<!-- MySql -->
<mysql-driver.version>5.1.36</mysql-driver.version>
<!-- AOP -->
<aspectj.version>1.7.4</aspectj.version>
<!-- Web dependencies -->
<webjars-bootstrap.version>2.3.0</webjars-bootstrap.version>
<webjars-jquery-ui.version>1.10.3</webjars-jquery-ui.version>
<webjars-jquery.version>2.0.3-1</webjars-jquery.version>
<dandelion.version>1.1.1</dandelion.version>
<dandelion.datatables.version>1.1.0</dandelion.datatables.version>
<!-- Logging -->
<logback.version>1.1.0</logback.version>
<slf4j.version>1.7.5</slf4j.version>
<cobertura.version>2.7</cobertura.version>
<!-- RSS -->
<rome.version>1.0</rome.version>
</properties>
<!-- Test -->
<junit.version>4.11</junit.version>
<hamcrest.version>1.3</hamcrest.version>
<dependencyManagement>
<!-- Import the maven Spring IO Platform Bill Of Materials (BOM) -->
<dependencies>
<dependency>
<groupId>io.spring.platform</groupId>
<artifactId>platform-bom</artifactId>
<version>${spring-io-platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!-- Dates -->
<jodatime-hibernate.version>1.3</jodatime-hibernate.version>
<jodatime-jsptags.version>1.1.1</jodatime-jsptags.version>
<jodatime.version>2.3</jodatime.version>
<jadira-usertype-core.version>3.1.0.CR10</jadira-usertype-core.version>
<!-- Web dependencies -->
<webjars-bootstrap.version>2.3.0</webjars-bootstrap.version>
<webjars-jquery-ui.version>1.10.3</webjars-jquery-ui.version>
<webjars-jquery.version>2.0.3-1</webjars-jquery.version>
<dandelion.datatables.version>0.9.3</dandelion.datatables.version>
<mysql.version>5.1.22</mysql.version>
</properties>
<dependencies>
<dependency>
<groupId>org.jadira.usertype</groupId>
<artifactId>usertype.core</artifactId>
<version>${jadira-usertype-core.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-servlet-api</artifactId>
<version>${tomcat.servlet.version}</version>
<scope>provided</scope>
<dependencies>
<dependency>
<groupId>org.jadira.usertype</groupId>
<artifactId>usertype.core</artifactId>
<version>${jadira-usertype-core.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-servlet-api</artifactId>
<version>${tomcat.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jasper-el</artifactId>
<version>${tomcat.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>jstl-impl</artifactId>
<version>1.2</version>
<exclusions>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>${jaxb-impl.version}</version>
<scope>provided</scope>
</dependency>
<!-- SPRING, SPRING, SPRINGITY SPRING -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>${spring-data-jpa.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>javax.servlet.jsp.jstl-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.taglibs</groupId>
<artifactId>taglibs-standard-jstlel</artifactId>
</dependency>
<!-- JSon -->
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<scope>test</scope>
</dependency>
<!-- SPRING, SPRING, SPRINGITY SPRING -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<!-- used for EhCacheCacheManager -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${spring-framework.version}</version>
<exclusions>
<exclusion>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jdbc-core</artifactId>
<version>${spring-data-jdbc.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>*</artifactId>
</exclusion>
<!-- because Spring Data usually comes with a slightly older version of Spring -->
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<!-- used for EhCacheCacheManager -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
</dependency>
<!-- Database connection pool
See here for more details on commons-dbcp versus tomcat-jdbc:
http://blog.ippon.fr/2013/03/13/improving-the-performance-of-the-spring-petclinic-sample-application-part-3-of-5/
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Database connection pool
See here for more details on commons-dbcp versus tomcat-jdbc:
http://blog.ippon.fr/2013/03/13/improving-the-performance-of-the-spring-petclinic-sample-application-part-3-of-5/
-->
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
<version>${tomcat-jdbc.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Logging with SLF4J & LogBack -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
<scope>runtime</scope>
</dependency>
<!-- Logging with SLF4J & LogBack -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>runtime</scope>
</dependency>
<!-- used for Atom -->
<dependency>
<groupId>rome</groupId>
<artifactId>rome</artifactId>
<version>${rome.version}</version>
</dependency>
<!-- Date and Time -->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time-hibernate</artifactId>
<version>${jodatime-hibernate.version}</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time-jsptags</artifactId>
<version>${jodatime-jsptags.version}</version>
</dependency>
<!-- Date and Time -->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>${jodatime.version}</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time-hibernate</artifactId>
<version>${jodatime-hibernate.version}</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time-jsptags</artifactId>
<version>${jodatime-jsptags.version}</version>
</dependency>
<!-- Databases - Uses HSQL by default -->
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Databases - Uses HSQL by default -->
<!-- <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> -->
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>${hsqldb.version}</version>
<scope>runtime</scope>
</dependency>
<!-- For MySql only -->
<!--dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-driver.version}</version>
</dependency-->
<!-- For MySql only -->
<!-- <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> -->
<!-- HIBERNATE -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>${hibernate-validator.version}</version>
</dependency>
<!-- HIBERNATE -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>${ehcache.version}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Webjars (static dependencies distributed as JAR files) -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>${webjars-bootstrap.version}</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery-ui</artifactId>
<version>${webjars-jquery-ui.version}</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>${webjars-jquery.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Webjars (static dependencies distributed as JAR files) -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>${webjars-bootstrap.version}</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery-ui</artifactId>
<version>${webjars-jquery-ui.version}</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>${webjars-jquery.version}</version>
</dependency>
<!-- Test Artifacts -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring-framework.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- used by Spring MVC Test framework -->
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>${hamcrest.version}</version>
<scope>test</scope>
</dependency>
<!-- Test Artifacts -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${assertj.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
<scope>runtime</scope>
</dependency>
<!-- Dandelion -->
<dependency>
<groupId>com.github.dandelion</groupId>
<artifactId>dandelion-jsp</artifactId>
<version>${dandelion.version}</version>
</dependency>
<dependency>
<groupId>com.github.dandelion</groupId>
<artifactId>datatables-jsp</artifactId>
<version>${dandelion.datatables.version}</version>
</dependency>
<dependency>
<groupId>com.github.dandelion</groupId>
<artifactId>datatables-export-itext</artifactId>
<version>${dandelion.datatables.version}</version>
</dependency>
<!-- temporary fix: below dependency should not be necessary as it is a transitive dependency.
For some reason we can't build the app unless it is a first level dependency -->
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
</dependency>
</dependencies>
<!-- Maven plugin versions are mentioned in order to guarantee the build reproducibility in the long term -->
<build>
<defaultGoal>install</defaultGoal>
<testResources>
<testResource>
<!-- declared explicitly so Spring config files can be placed next to their corresponding JUnit test class -->
<directory>${project.basedir}/src/test/java</directory>
</testResource>
<testResource>
<directory>${project.basedir}/src/test/resources</directory>
</testResource>
</testResources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<compilerArguments>
<Xlint/>
</compilerArguments>
<verbose>true</verbose>
<source>${java.version}</source>
<target>${java.version}</target>
<showWarnings>true</showWarnings>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.13</version>
<configuration>
<includes>
<include>**/*Tests.java</include>
</includes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<warName>petclinic</warName>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.9</version>
<configuration>
<downloadSources>true</downloadSources>
<downloadJavadocs>true</downloadJavadocs>
<wtpversion>2.0</wtpversion>
<sourceIncludes>
<sourceInclude>**/*.*</sourceInclude>
</sourceIncludes>
<additionalBuildcommands>
<buildCommand>
<name>org.springframework.ide.eclipse.core.springbuilder</name>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
</buildCommand>
</additionalBuildcommands>
<additionalProjectnatures>
<projectnature>org.eclipse.jdt.core.javanature</projectnature>
<projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
<projectnature>org.eclipse.m2e.core.maven2Nature</projectnature>
</additionalProjectnatures>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<server>tomcat-development-server</server>
<port>9966</port>
<path>/petclinic</path>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>${cobertura.version}</version>
<configuration>
<check/>
</configuration>
<executions>
<execution>
<goals>
<goal>clean</goal>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<!-- Dandelion -->
<dependency>
<groupId>com.github.dandelion</groupId>
<artifactId>datatables-jsp</artifactId>
<version>${dandelion.datatables.version}</version>
</dependency>
<dependency>
<groupId>com.github.dandelion</groupId>
<artifactId>datatables-export-itext</artifactId>
<version>${dandelion.datatables.version}</version>
</dependency>
<dependency>
<groupId>com.github.dandelion</groupId>
<artifactId>datatables-servlet2</artifactId>
<version>${dandelion.datatables.version}</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<!--
Force the version of all the spring jars (core, beans, context, ...)
pulled by spring-data-jpa:1.3.4.RELEASE to 3.2.x when spring-data pulls
the 3.1.x versions to prevent some misbehaviors of maven which sometimes
pulls both 3.2.x and 3.1.x versions of spring-core, spring-beans and spring-context
-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring-framework.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<!-- Maven plugin versions are mentioned in order to guarantee the build reproducibility in the long term -->
<build>
<defaultGoal>install</defaultGoal>
<testResources>
<testResource>
<!-- declared explicitly so Spring config files can be placed next to their corresponding JUnit test class
(see example with ValidatorTests) -->
<directory>${project.basedir}/src/test/java</directory>
</testResource>
<testResource>
<directory>${project.basedir}/src/test/resources</directory>
</testResource>
</testResources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<compilerArguments>
<Xlint />
</compilerArguments>
<verbose>true</verbose>
<source>${java.version}</source>
<target>${java.version}</target>
<showWarnings>true</showWarnings>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.13</version>
<configuration>
<includes>
<include>**/*Tests.java</include>
</includes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<warName>petclinic</warName>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.9</version>
<configuration>
<downloadSources>true</downloadSources>
<downloadJavadocs>true</downloadJavadocs>
<wtpversion>2.0</wtpversion>
<sourceIncludes>
<sourceInclude>**/*.*</sourceInclude>
</sourceIncludes>
<additionalBuildcommands>
<buildCommand>
<name>org.springframework.ide.eclipse.core.springbuilder</name>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
</buildCommand>
</additionalBuildcommands>
<additionalProjectnatures>
<projectnature>org.eclipse.jdt.core.javanature</projectnature>
<projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
<projectnature>org.eclipse.m2e.core.maven2Nature</projectnature>
</additionalProjectnatures>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.0</version>
<configuration>
<server>tomcat-development-server</server>
<port>9966</port>
<path>/petclinic</path>
</configuration>
</plugin>
</plugins>
</build>
<!-- integrate maven-cobertura-plugin to project site -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>${cobertura.version}</version>
<configuration>
<formats>
<format>html</format>
</formats>
<check/>
</configuration>
</plugin>
</plugins>
</reporting>
<url>demopetclinic</url>
</project>

View file

@ -1,22 +1,32 @@
# Spring PetClinic Sample Application
## What does it look like?
-spring-petclinic has been deployed here on cloudfoundry: http://gopetclinic.cfapps.io/
## Understanding the Spring Petclinic application with a few diagrams
<a href="https://speakerdeck.com/michaelisvy/spring-petclinic-sample-application">See the presentation here</a>
## Running petclinic locally
```
git clone https://github.com/SpringSource/spring-petclinic.git
git clone https://github.com/spring-projects/spring-petclinic.git
mvn tomcat7:run
```
You can then access petclinic here: http://localhost:9966/petclinic/
## In case you find a bug/suggested improvement for Spring Petclinic
Our issue tracker is available here: https://github.com/SpringSource/spring-petclinic/issues
Our issue tracker is available here: https://github.com/spring-projects/spring-petclinic/issues
## Database configuration
In its default configuration, Petclinic uses an in-memory database (HSQLDB) which
gets populated at startup with data. A similar setup is provided for MySql in case a persistent database configuration is needed.
Note that whenever the database type is changed, the data-access.properties file needs to be updated and the mysql-connector-java artifact from the pom.xml needs to be uncommented.
You may start a MySql database with docker:
```
docker run -e MYSQL_ROOT_PASSWORD=petclinic -e MYSQL_DATABASE=petclinic -p 3306:3306 mysql:5.7.8
```
## Working with Petclinic in Eclipse/STS
@ -34,7 +44,7 @@ If m2e is not there, just follow the install process here: http://eclipse.org/m2
1) In the command line
```
git clone https://github.com/SpringSource/spring-petclinic.git
git clone https://github.com/spring-projects/spring-petclinic.git
```
2) Inside Eclipse
```
@ -46,15 +56,17 @@ File -> Import -> Maven -> Existing Maven project
<table>
<tr>
<th width="300px">Inside the 'Web' layer</th><th width="300px">Files</th>
<th width="300px">Java Config</th><th width="300px"></th>
</tr>
<tr>
<td>Spring MVC- Atom integration</td>
<td>Java Config branch</td>
<td>
<a href="/src/main/java/org/springframework/samples/petclinic/web/VetsAtomView.java">VetsAtomView.java</a>
<a href="/src/main/resources/spring/mvc-view-config.xml">mvc-view-config.xml</a>
Petclinic uses XML configuration by default. In case you'd like to use Java Config instead, there is a Java Config branch available <a href="https://github.com/spring-projects/spring-petclinic/tree/javaconfig">here</a>. Thanks to Antoine Rey for his contribution.
</td>
</tr>
<tr>
<th width="300px">Inside the 'Web' layer</th><th width="300px">Files</th>
</tr>
<tr>
<td>Spring MVC - XML integration</td>
<td><a href="/src/main/resources/spring/mvc-view-config.xml">mvc-view-config.xml</a></td>
@ -63,10 +75,6 @@ File -> Import -> Maven -> Existing Maven project
<td>Spring MVC - ContentNegotiatingViewResolver</td>
<td><a href="/src/main/resources/spring/mvc-view-config.xml">mvc-view-config.xml</a></td>
</tr>
<tr>
<td>Spring MVC Test Framework</td>
<td><a href="/src/test/java/org/springframework/samples/petclinic/web/VisitsViewTests.java">VisitsViewTest.java</a></td>
</tr>
<tr>
<td>JSP custom tags</td>
<td>
@ -78,7 +86,7 @@ File -> Import -> Maven -> Existing Maven project
<td>
<a href="/pom.xml">webjars declaration inside pom.xml</a> <br />
<a href="/src/main/resources/spring/mvc-core-config.xml#L24">Resource mapping in Spring configuration</a> <br />
<a href="/src/main/webapp/WEB-INF/jsp/fragments/headTag.jsp#L12">sample usage in JSP</a></td>
<a href="/src/main/webapp/WEB-INF/jsp/fragments/staticFiles.jsp#L12">sample usage in JSP</a></td>
</td>
</tr>
<tr>
@ -87,6 +95,7 @@ File -> Import -> Maven -> Existing Maven project
<a href="/src/main/webapp/WEB-INF/jsp/owners/ownersList.jsp">ownersList.jsp</a>
<a href="/src/main/webapp/WEB-INF/jsp/vets/vetList.jsp">vetList.jsp</a>
<a href="/src/main/webapp/WEB-INF/web.xml">web.xml</a>
<a href="/src/main/resources/dandelion/datatables/datatables.properties">datatables.properties</a>
</td>
</tr>
<tr>
@ -195,5 +204,12 @@ Here is a list of them:
</table>
# Contributing
The [issue tracker](https://github.com/spring-projects/spring-petclinic/issues) is the preferred channel for bug reports, features requests and submitting pull requests.
For pull requests, editor preferences are available in the [editor config](https://github.com/spring-projects/spring-petclinic/blob/master/.editorconfig) for easy use in common text editors. Read more and download plugins at <http://editorconfig.org>.

13
sonar-project.properties Executable file
View file

@ -0,0 +1,13 @@
# Required metadata
sonar.projectKey=java-sonar-runner-simple
sonar.projectName=Simple Java project analyzed with the SonarQube Runner
sonar.projectVersion=1.0
# Comma-separated paths to directories with sources (required)
sonar.sources=src
# Language
sonar.language=java
# Encoding of the source files
sonar.sourceEncoding=UTF-8

View file

@ -15,8 +15,6 @@
*/
package org.springframework.samples.petclinic.model;
import java.io.Serializable;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@ -34,15 +32,14 @@ public class BaseEntity {
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected Integer id;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getId() {
return id;
}
public boolean isNew() {
return (this.id == null);
}

View file

@ -32,15 +32,14 @@ public class NamedEntity extends BaseEntity {
@Column(name = "name")
private String name;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
@Override
public String toString() {
return this.getName();

View file

@ -85,19 +85,19 @@ public class Owner extends Person {
this.telephone = telephone;
}
protected void setPetsInternal(Set<Pet> pets) {
this.pets = pets;
}
protected Set<Pet> getPetsInternal() {
if (this.pets == null) {
this.pets = new HashSet<Pet>();
this.pets = new HashSet<>();
}
return this.pets;
}
protected void setPetsInternal(Set<Pet> pets) {
this.pets = pets;
}
public List<Pet> getPets() {
List<Pet> sortedPets = new ArrayList<Pet>(getPetsInternal());
List<Pet> sortedPets = new ArrayList<>(getPetsInternal());
PropertyComparator.sort(sortedPets, new MutableSortDefinition("name", true, true));
return Collections.unmodifiableList(sortedPets);
}
@ -141,13 +141,13 @@ public class Owner extends Person {
public String toString() {
return new ToStringCreator(this)
.append("id", this.getId())
.append("new", this.isNew())
.append("lastName", this.getLastName())
.append("firstName", this.getFirstName())
.append("address", this.address)
.append("city", this.city)
.append("telephone", this.telephone)
.toString();
.append("id", this.getId())
.append("new", this.isNew())
.append("lastName", this.getLastName())
.append("firstName", this.getFirstName())
.append("address", this.address)
.append("city", this.city)
.append("telephone", this.telephone)
.toString();
}
}

View file

@ -32,6 +32,7 @@ import javax.persistence.Table;
import org.hibernate.annotations.Type;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.springframework.beans.support.MutableSortDefinition;
import org.springframework.beans.support.PropertyComparator;
import org.springframework.format.annotation.DateTimeFormat;
@ -48,9 +49,9 @@ import org.springframework.format.annotation.DateTimeFormat;
public class Pet extends NamedEntity {
@Column(name = "birth_date")
@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDate")
@DateTimeFormat(pattern = "yyyy/MM/dd")
private DateTime birthDate;
private LocalDate birthDate;
@ManyToOne
@JoinColumn(name = "type_id")
@ -63,44 +64,43 @@ public class Pet extends NamedEntity {
@OneToMany(cascade = CascadeType.ALL, mappedBy = "pet", fetch = FetchType.EAGER)
private Set<Visit> visits;
public void setBirthDate(DateTime birthDate) {
this.birthDate = birthDate;
}
public DateTime getBirthDate() {
public LocalDate getBirthDate() {
return this.birthDate;
}
public void setType(PetType type) {
this.type = type;
public void setBirthDate(LocalDate birthDate) {
this.birthDate = birthDate;
}
public PetType getType() {
return this.type;
}
protected void setOwner(Owner owner) {
this.owner = owner;
public void setType(PetType type) {
this.type = type;
}
public Owner getOwner() {
return this.owner;
}
protected void setVisitsInternal(Set<Visit> visits) {
this.visits = visits;
protected void setOwner(Owner owner) {
this.owner = owner;
}
protected Set<Visit> getVisitsInternal() {
if (this.visits == null) {
this.visits = new HashSet<Visit>();
this.visits = new HashSet<>();
}
return this.visits;
}
protected void setVisitsInternal(Set<Visit> visits) {
this.visits = visits;
}
public List<Visit> getVisits() {
List<Visit> sortedVisits = new ArrayList<Visit>(getVisitsInternal());
List<Visit> sortedVisits = new ArrayList<>(getVisitsInternal());
PropertyComparator.sort(sortedVisits, new MutableSortDefinition("date", false, false));
return Collections.unmodifiableList(sortedVisits);
}

View file

@ -20,6 +20,7 @@ import javax.persistence.Table;
/**
* @author Juergen Hoeller
* Can be Cat, Dog, Hamster...
*/
@Entity
@Table(name = "types")

View file

@ -46,24 +46,23 @@ public class Vet extends Person {
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "vet_specialties", joinColumns = @JoinColumn(name = "vet_id"),
inverseJoinColumns = @JoinColumn(name = "specialty_id"))
inverseJoinColumns = @JoinColumn(name = "specialty_id"))
private Set<Specialty> specialties;
protected Set<Specialty> getSpecialtiesInternal() {
if (this.specialties == null) {
this.specialties = new HashSet<>();
}
return this.specialties;
}
protected void setSpecialtiesInternal(Set<Specialty> specialties) {
this.specialties = specialties;
}
protected Set<Specialty> getSpecialtiesInternal() {
if (this.specialties == null) {
this.specialties = new HashSet<Specialty>();
}
return this.specialties;
}
@XmlElement
public List<Specialty> getSpecialties() {
List<Specialty> sortedSpecs = new ArrayList<Specialty>(getSpecialtiesInternal());
List<Specialty> sortedSpecs = new ArrayList<>(getSpecialtiesInternal());
PropertyComparator.sort(sortedSpecs, new MutableSortDefinition("name", true, true));
return Collections.unmodifiableList(sortedSpecs);
}

View file

@ -1,4 +1,3 @@
/*
/*
* Copyright 2002-2013 the original author or authors.
*
@ -36,7 +35,7 @@ public class Vets {
@XmlElement
public List<Vet> getVetList() {
if (vets == null) {
vets = new ArrayList<Vet>();
vets = new ArrayList<>();
}
return vets;
}

View file

@ -23,7 +23,7 @@ import javax.persistence.Table;
import org.hibernate.annotations.Type;
import org.hibernate.validator.constraints.NotEmpty;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.springframework.format.annotation.DateTimeFormat;
/**
@ -39,9 +39,9 @@ public class Visit extends BaseEntity {
* Holds value of property date.
*/
@Column(name = "visit_date")
@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDate")
@DateTimeFormat(pattern = "yyyy/MM/dd")
private DateTime date;
private LocalDate date;
/**
* Holds value of property description.
@ -62,7 +62,7 @@ public class Visit extends BaseEntity {
* Creates a new instance of Visit for the current date
*/
public Visit() {
this.date = new DateTime();
this.date = new LocalDate();
}
@ -71,7 +71,7 @@ public class Visit extends BaseEntity {
*
* @return Value of property date.
*/
public DateTime getDate() {
public LocalDate getDate() {
return this.date;
}
@ -80,7 +80,7 @@ public class Visit extends BaseEntity {
*
* @param date New value of property date.
*/
public void setDate(DateTime date) {
public void setDate(LocalDate date) {
this.date = date;
}

View file

@ -1,8 +1,5 @@
/**
*
* The classes in this package represent PetClinic's business layer.
*
*/
package org.springframework.samples.petclinic.model;

View file

@ -1,18 +1,3 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Copyright 2002-2013 the original author or authors.
*
@ -53,7 +38,7 @@ public interface OwnerRepository {
*
* @param lastName Value to search for
* @return a <code>Collection</code> of matching <code>Owner</code>s (or an empty <code>Collection</code> if none
* found)
* found)
*/
Collection<Owner> findByLastName(String lastName) throws DataAccessException;
@ -62,8 +47,7 @@ public interface OwnerRepository {
*
* @param id the id to search for
* @return the <code>Owner</code> if found
* @throws org.springframework.dao.DataRetrievalFailureException
* if not found
* @throws org.springframework.dao.DataRetrievalFailureException if not found
*/
Owner findById(int id) throws DataAccessException;

View file

@ -45,8 +45,7 @@ public interface PetRepository {
*
* @param id the id to search for
* @return the <code>Pet</code> if found
* @throws org.springframework.dao.DataRetrievalFailureException
* if not found
* @throws org.springframework.dao.DataRetrievalFailureException if not found
*/
Pet findById(int id) throws DataAccessException;

View file

@ -25,9 +25,9 @@ import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.simple.ParameterizedBeanPropertyRowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.orm.ObjectRetrievalFailureException;
import org.springframework.samples.petclinic.model.Owner;
@ -35,7 +35,6 @@ import org.springframework.samples.petclinic.model.Pet;
import org.springframework.samples.petclinic.model.PetType;
import org.springframework.samples.petclinic.model.Visit;
import org.springframework.samples.petclinic.repository.OwnerRepository;
import org.springframework.samples.petclinic.repository.VisitRepository;
import org.springframework.samples.petclinic.util.EntityUtils;
import org.springframework.stereotype.Repository;
@ -52,23 +51,19 @@ import org.springframework.stereotype.Repository;
@Repository
public class JdbcOwnerRepositoryImpl implements OwnerRepository {
private VisitRepository visitRepository;
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
private SimpleJdbcInsert insertOwner;
@Autowired
public JdbcOwnerRepositoryImpl(DataSource dataSource, NamedParameterJdbcTemplate namedParameterJdbcTemplate,
VisitRepository visitRepository) {
public JdbcOwnerRepositoryImpl(DataSource dataSource, NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
this.insertOwner = new SimpleJdbcInsert(dataSource)
.withTableName("owners")
.usingGeneratedKeyColumns("id");
.withTableName("owners")
.usingGeneratedKeyColumns("id");
this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
this.visitRepository = visitRepository;
}
@ -79,12 +74,12 @@ public class JdbcOwnerRepositoryImpl implements OwnerRepository {
*/
@Override
public Collection<Owner> findByLastName(String lastName) throws DataAccessException {
Map<String, Object> params = new HashMap<String, Object>();
Map<String, Object> params = new HashMap<>();
params.put("lastName", lastName + "%");
List<Owner> owners = this.namedParameterJdbcTemplate.query(
"SELECT id, first_name, last_name, address, city, telephone FROM owners WHERE last_name like :lastName",
params,
ParameterizedBeanPropertyRowMapper.newInstance(Owner.class)
"SELECT id, first_name, last_name, address, city, telephone FROM owners WHERE last_name like :lastName",
params,
BeanPropertyRowMapper.newInstance(Owner.class)
);
loadOwnersPetsAndVisits(owners);
return owners;
@ -98,12 +93,12 @@ public class JdbcOwnerRepositoryImpl implements OwnerRepository {
public Owner findById(int id) throws DataAccessException {
Owner owner;
try {
Map<String, Object> params = new HashMap<String, Object>();
Map<String, Object> params = new HashMap<>();
params.put("id", id);
owner = this.namedParameterJdbcTemplate.queryForObject(
"SELECT id, first_name, last_name, address, city, telephone FROM owners WHERE id= :id",
params,
ParameterizedBeanPropertyRowMapper.newInstance(Owner.class)
"SELECT id, first_name, last_name, address, city, telephone FROM owners WHERE id= :id",
params,
BeanPropertyRowMapper.newInstance(Owner.class)
);
} catch (EmptyResultDataAccessException ex) {
throw new ObjectRetrievalFailureException(Owner.class, id);
@ -113,20 +108,17 @@ public class JdbcOwnerRepositoryImpl implements OwnerRepository {
}
public void loadPetsAndVisits(final Owner owner) {
Map<String, Object> params = new HashMap<String, Object>();
params.put("id", owner.getId().intValue());
Map<String, Object> params = new HashMap<>();
params.put("id", owner.getId());
final List<JdbcPet> pets = this.namedParameterJdbcTemplate.query(
"SELECT id, name, birth_date, type_id, owner_id FROM pets WHERE owner_id=:id",
params,
new JdbcPetRowMapper()
"SELECT pets.id, name, birth_date, type_id, owner_id, visits.id as visit_id, visit_date, description, pet_id FROM pets LEFT OUTER JOIN visits ON pets.id = pet_id WHERE owner_id=:id",
params,
new JdbcPetVisitExtractor()
);
Collection<PetType> petTypes = getPetTypes();
for (JdbcPet pet : pets) {
pet.setType(EntityUtils.getById(petTypes, PetType.class, pet.getTypeId()));
owner.addPet(pet);
pet.setType(EntityUtils.getById(getPetTypes(), PetType.class, pet.getTypeId()));
List<Visit> visits = this.visitRepository.findByPetId(pet.getId());
for (Visit visit : visits) {
pet.addVisit(visit);
}
}
}
@ -138,16 +130,16 @@ public class JdbcOwnerRepositoryImpl implements OwnerRepository {
owner.setId(newKey.intValue());
} else {
this.namedParameterJdbcTemplate.update(
"UPDATE owners SET first_name=:firstName, last_name=:lastName, address=:address, " +
"city=:city, telephone=:telephone WHERE id=:id",
parameterSource);
"UPDATE owners SET first_name=:firstName, last_name=:lastName, address=:address, " +
"city=:city, telephone=:telephone WHERE id=:id",
parameterSource);
}
}
public Collection<PetType> getPetTypes() throws DataAccessException {
return this.namedParameterJdbcTemplate.query(
"SELECT id, name FROM types ORDER BY name", new HashMap<String, Object>(),
ParameterizedBeanPropertyRowMapper.newInstance(PetType.class));
"SELECT id, name FROM types ORDER BY name", new HashMap<String, Object>(),
BeanPropertyRowMapper.newInstance(PetType.class));
}
/**

View file

@ -18,11 +18,10 @@ package org.springframework.samples.petclinic.repository.jdbc;
import org.springframework.samples.petclinic.model.Pet;
/**
* Subclass of Pet that carries temporary id properties which are only relevant for a JDBC implmentation of the
* ClinicService.
* Subclass of Pet that carries temporary id properties which are only relevant for a JDBC implementation of the
* PetRepository.
*
* @author Juergen Hoeller
* @see JdbcClinicImpl
*/
class JdbcPet extends Pet {
@ -30,21 +29,20 @@ class JdbcPet extends Pet {
private int ownerId;
public void setTypeId(int typeId) {
this.typeId = typeId;
}
public int getTypeId() {
return this.typeId;
}
public void setOwnerId(int ownerId) {
this.ownerId = ownerId;
public void setTypeId(int typeId) {
this.typeId = typeId;
}
public int getOwnerId() {
return this.ownerId;
}
public void setOwnerId(int ownerId) {
this.ownerId = ownerId;
}
}

View file

@ -24,9 +24,9 @@ import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.simple.ParameterizedBeanPropertyRowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.orm.ObjectRetrievalFailureException;
import org.springframework.samples.petclinic.model.Owner;
@ -64,8 +64,8 @@ public class JdbcPetRepositoryImpl implements PetRepository {
this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
this.insertPet = new SimpleJdbcInsert(dataSource)
.withTableName("pets")
.usingGeneratedKeyColumns("id");
.withTableName("pets")
.usingGeneratedKeyColumns("id");
this.ownerRepository = ownerRepository;
this.visitRepository = visitRepository;
@ -73,25 +73,25 @@ public class JdbcPetRepositoryImpl implements PetRepository {
@Override
public List<PetType> findPetTypes() throws DataAccessException {
Map<String, Object> params = new HashMap<String, Object>();
Map<String, Object> params = new HashMap<>();
return this.namedParameterJdbcTemplate.query(
"SELECT id, name FROM types ORDER BY name",
params,
ParameterizedBeanPropertyRowMapper.newInstance(PetType.class));
"SELECT id, name FROM types ORDER BY name",
params,
BeanPropertyRowMapper.newInstance(PetType.class));
}
@Override
public Pet findById(int id) throws DataAccessException {
JdbcPet pet;
try {
Map<String, Object> params = new HashMap<String, Object>();
Map<String, Object> params = new HashMap<>();
params.put("id", id);
pet = this.namedParameterJdbcTemplate.queryForObject(
"SELECT id, name, birth_date, type_id, owner_id FROM pets WHERE id=:id",
params,
new JdbcPetRowMapper());
"SELECT id, name, birth_date, type_id, owner_id FROM pets WHERE id=:id",
params,
new JdbcPetRowMapper());
} catch (EmptyResultDataAccessException ex) {
throw new ObjectRetrievalFailureException(Pet.class, new Integer(id));
throw new ObjectRetrievalFailureException(Pet.class, id);
}
Owner owner = this.ownerRepository.findById(pet.getOwnerId());
owner.addPet(pet);
@ -108,13 +108,13 @@ public class JdbcPetRepositoryImpl implements PetRepository {
public void save(Pet pet) throws DataAccessException {
if (pet.isNew()) {
Number newKey = this.insertPet.executeAndReturnKey(
createPetParameterSource(pet));
createPetParameterSource(pet));
pet.setId(newKey.intValue());
} else {
this.namedParameterJdbcTemplate.update(
"UPDATE pets SET name=:name, birth_date=:birth_date, type_id=:type_id, " +
"owner_id=:owner_id WHERE id=:id",
createPetParameterSource(pet));
"UPDATE pets SET name=:name, birth_date=:birth_date, type_id=:type_id, " +
"owner_id=:owner_id WHERE id=:id",
createPetParameterSource(pet));
}
}
@ -123,11 +123,11 @@ public class JdbcPetRepositoryImpl implements PetRepository {
*/
private MapSqlParameterSource createPetParameterSource(Pet pet) {
return new MapSqlParameterSource()
.addValue("id", pet.getId())
.addValue("name", pet.getName())
.addValue("birth_date", pet.getBirthDate().toDate())
.addValue("type_id", pet.getType().getId())
.addValue("owner_id", pet.getOwner().getId());
.addValue("id", pet.getId())
.addValue("name", pet.getName())
.addValue("birth_date", pet.getBirthDate().toDate())
.addValue("type_id", pet.getType().getId())
.addValue("owner_id", pet.getOwner().getId());
}
}

View file

@ -20,21 +20,22 @@ import java.sql.SQLException;
import java.util.Date;
import org.joda.time.DateTime;
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
import org.joda.time.LocalDate;
import org.springframework.jdbc.core.RowMapper;
/**
* {@link ParameterizedRowMapper} implementation mapping data from a {@link ResultSet} to the corresponding properties
* {@link RowMapper} implementation mapping data from a {@link ResultSet} to the corresponding properties
* of the {@link JdbcPet} class.
*/
class JdbcPetRowMapper implements ParameterizedRowMapper<JdbcPet> {
class JdbcPetRowMapper implements RowMapper<JdbcPet> {
@Override
public JdbcPet mapRow(ResultSet rs, int rownum) throws SQLException {
JdbcPet pet = new JdbcPet();
pet.setId(rs.getInt("id"));
pet.setId(rs.getInt("pets.id"));
pet.setName(rs.getString("name"));
Date birthDate = rs.getDate("birth_date");
pet.setBirthDate(new DateTime(birthDate));
pet.setBirthDate(new LocalDate(birthDate));
pet.setTypeId(rs.getInt("type_id"));
pet.setOwnerId(rs.getInt("owner_id"));
return pet;

View file

@ -0,0 +1,54 @@
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.samples.petclinic.repository.jdbc;
import org.springframework.data.jdbc.core.OneToManyResultSetExtractor;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.samples.petclinic.model.Visit;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* {@link ResultSetExtractor} implementation by using the
* {@link OneToManyResultSetExtractor} of Spring Data Core JDBC Extensions.
*/
public class JdbcPetVisitExtractor extends
OneToManyResultSetExtractor<JdbcPet, Visit, Integer> {
public JdbcPetVisitExtractor() {
super(new JdbcPetRowMapper(), new JdbcVisitRowMapper());
}
@Override
protected Integer mapPrimaryKey(ResultSet rs) throws SQLException {
return rs.getInt("pets.id");
}
@Override
protected Integer mapForeignKey(ResultSet rs) throws SQLException {
if (rs.getObject("visits.pet_id") == null) {
return null;
} else {
return rs.getInt("visits.pet_id");
}
}
@Override
protected void addChild(JdbcPet root, Visit child) {
root.addVisit(child);
}
}

View file

@ -23,9 +23,8 @@ import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.simple.ParameterizedBeanPropertyRowMapper;
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
import org.springframework.samples.petclinic.model.Specialty;
import org.springframework.samples.petclinic.model.Vet;
import org.springframework.samples.petclinic.repository.VetRepository;
@ -33,8 +32,7 @@ import org.springframework.samples.petclinic.util.EntityUtils;
import org.springframework.stereotype.Repository;
/**
* A simple JDBC-based implementation of the {@link VetRepository} interface. Uses @Cacheable to cache the result of the
* {@link findAll} method
* A simple JDBC-based implementation of the {@link VetRepository} interface.
*
* @author Ken Krebs
* @author Juergen Hoeller
@ -56,33 +54,31 @@ public class JdbcVetRepositoryImpl implements VetRepository {
/**
* Refresh the cache of Vets that the ClinicService is holding.
*
* @see org.springframework.samples.petclinic.model.service.ClinicService#findVets()
*/
@Override
public Collection<Vet> findAll() throws DataAccessException {
List<Vet> vets = new ArrayList<Vet>();
List<Vet> vets = new ArrayList<>();
// Retrieve the list of all vets.
vets.addAll(this.jdbcTemplate.query(
"SELECT id, first_name, last_name FROM vets ORDER BY last_name,first_name",
ParameterizedBeanPropertyRowMapper.newInstance(Vet.class)));
"SELECT id, first_name, last_name FROM vets ORDER BY last_name,first_name",
BeanPropertyRowMapper.newInstance(Vet.class)));
// Retrieve the list of all possible specialties.
final List<Specialty> specialties = this.jdbcTemplate.query(
"SELECT id, name FROM specialties",
ParameterizedBeanPropertyRowMapper.newInstance(Specialty.class));
"SELECT id, name FROM specialties",
BeanPropertyRowMapper.newInstance(Specialty.class));
// Build each vet's list of specialties.
for (Vet vet : vets) {
final List<Integer> vetSpecialtiesIds = this.jdbcTemplate.query(
"SELECT specialty_id FROM vet_specialties WHERE vet_id=?",
new ParameterizedRowMapper<Integer>() {
@Override
public Integer mapRow(ResultSet rs, int row) throws SQLException {
return Integer.valueOf(rs.getInt(1));
}
},
vet.getId().intValue());
"SELECT specialty_id FROM vet_specialties WHERE vet_id=?",
new BeanPropertyRowMapper<Integer>() {
@Override
public Integer mapRow(ResultSet rs, int row) throws SQLException {
return rs.getInt(1);
}
},
vet.getId());
for (int specialtyId : vetSpecialtiesIds) {
Specialty specialty = EntityUtils.getById(specialties, Specialty.class, specialtyId);
vet.addSpecialty(specialty);

View file

@ -15,24 +15,18 @@
*/
package org.springframework.samples.petclinic.repository.jdbc;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;
import javax.sql.DataSource;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.samples.petclinic.model.Visit;
import org.springframework.samples.petclinic.repository.VisitRepository;
import org.springframework.stereotype.Repository;
import javax.sql.DataSource;
import java.util.List;
/**
* A simple JDBC-based implementation of the {@link VisitRepository} interface.
*
@ -56,8 +50,8 @@ public class JdbcVisitRepositoryImpl implements VisitRepository {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.insertVisit = new SimpleJdbcInsert(dataSource)
.withTableName("visits")
.usingGeneratedKeyColumns("id");
.withTableName("visits")
.usingGeneratedKeyColumns("id");
}
@ -65,46 +59,30 @@ public class JdbcVisitRepositoryImpl implements VisitRepository {
public void save(Visit visit) throws DataAccessException {
if (visit.isNew()) {
Number newKey = this.insertVisit.executeAndReturnKey(
createVisitParameterSource(visit));
createVisitParameterSource(visit));
visit.setId(newKey.intValue());
} else {
throw new UnsupportedOperationException("Visit update not supported");
}
}
public void deletePet(int id) throws DataAccessException {
this.jdbcTemplate.update("DELETE FROM pets WHERE id=?", id);
}
/**
* Creates a {@link MapSqlParameterSource} based on data values from the supplied {@link Visit} instance.
*/
private MapSqlParameterSource createVisitParameterSource(Visit visit) {
return new MapSqlParameterSource()
.addValue("id", visit.getId())
.addValue("visit_date", visit.getDate().toDate())
.addValue("description", visit.getDescription())
.addValue("pet_id", visit.getPet().getId());
.addValue("id", visit.getId())
.addValue("visit_date", visit.getDate().toDate())
.addValue("description", visit.getDescription())
.addValue("pet_id", visit.getPet().getId());
}
@Override
public List<Visit> findByPetId(Integer petId) {
final List<Visit> visits = this.jdbcTemplate.query(
"SELECT id, visit_date, description FROM visits WHERE pet_id=?",
new ParameterizedRowMapper<Visit>() {
@Override
public Visit mapRow(ResultSet rs, int row) throws SQLException {
Visit visit = new Visit();
visit.setId(rs.getInt("id"));
Date visitDate = rs.getDate("visit_date");
visit.setDate(new DateTime(visitDate));
visit.setDescription(rs.getString("description"));
return visit;
}
},
petId);
return visits;
return this.jdbcTemplate.query(
"SELECT id as visit_id, visit_date, description FROM visits WHERE pet_id=?",
new JdbcVisitRowMapper(), petId);
}
}

View file

@ -0,0 +1,42 @@
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.samples.petclinic.repository.jdbc;
import org.joda.time.LocalDate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.samples.petclinic.model.Visit;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
/**
* {@link RowMapper} implementation mapping data from a {@link ResultSet} to the corresponding properties
* of the {@link Visit} class.
*/
class JdbcVisitRowMapper implements RowMapper<Visit> {
@Override
public Visit mapRow(ResultSet rs, int row) throws SQLException {
Visit visit = new Visit();
visit.setId(rs.getInt("visit_id"));
Date visitDate = rs.getDate("visit_date");
visit.setDate(new LocalDate(visitDate));
visit.setDescription(rs.getString("description"));
return visit;
}
}

View file

@ -1,9 +1,6 @@
/**
*
* The classes in this package represent the JDBC implementation
* of PetClinic's persistence layer.
*
*/
package org.springframework.samples.petclinic.repository.jdbc;

View file

@ -70,12 +70,11 @@ public class JpaOwnerRepositoryImpl implements OwnerRepository {
@Override
public void save(Owner owner) {
if (owner.getId() == null) {
this.em.persist(owner);
}
else {
this.em.merge(owner);
}
if (owner.getId() == null) {
this.em.persist(owner);
} else {
this.em.merge(owner);
}
}

View file

@ -53,12 +53,11 @@ public class JpaPetRepositoryImpl implements PetRepository {
@Override
public void save(Pet pet) {
if (pet.getId() == null) {
this.em.persist(pet);
}
else {
this.em.merge(pet);
}
if (pet.getId() == null) {
this.em.persist(pet);
} else {
this.em.merge(pet);
}
}
}

View file

@ -45,12 +45,11 @@ public class JpaVisitRepositoryImpl implements VisitRepository {
@Override
public void save(Visit visit) {
if (visit.getId() == null) {
this.em.persist(visit);
}
else {
this.em.merge(visit);
}
if (visit.getId() == null) {
this.em.persist(visit);
} else {
this.em.merge(visit);
}
}

View file

@ -1,9 +1,6 @@
/**
*
* The classes in this package represent the JPA implementation
* of PetClinic's persistence layer.
*
*/
package org.springframework.samples.petclinic.repository.jpa;

View file

@ -31,11 +31,11 @@ import org.springframework.samples.petclinic.repository.OwnerRepository;
*/
public interface SpringDataOwnerRepository extends OwnerRepository, Repository<Owner, Integer> {
@Override
@Query("SELECT DISTINCT owner FROM Owner owner left join fetch owner.pets WHERE owner.lastName LIKE :lastName%")
public Collection<Owner> findByLastName(@Param("lastName") String lastName);
@Override
@Query("SELECT DISTINCT owner FROM Owner owner left join fetch owner.pets WHERE owner.lastName LIKE :lastName%")
public Collection<Owner> findByLastName(@Param("lastName") String lastName);
@Override
@Query("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:id")
public Owner findById(@Param("id") int id);
@Override
@Query("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:id")
public Owner findById(@Param("id") int id);
}

View file

@ -26,25 +26,25 @@ import org.springframework.samples.petclinic.model.Visit;
/**
* Mostly used as a facade for all Petclinic controllers
* Mostly used as a facade so all controllers have a single point of entry
*
* @author Michael Isvy
*/
public interface ClinicService {
public Collection<PetType> findPetTypes() throws DataAccessException;
Collection<PetType> findPetTypes() throws DataAccessException;
public Owner findOwnerById(int id) throws DataAccessException;
Owner findOwnerById(int id) throws DataAccessException;
public Pet findPetById(int id) throws DataAccessException;
Pet findPetById(int id) throws DataAccessException;
public void savePet(Pet pet) throws DataAccessException;
void savePet(Pet pet) throws DataAccessException;
public void saveVisit(Visit visit) throws DataAccessException;
void saveVisit(Visit visit) throws DataAccessException;
public Collection<Vet> findVets() throws DataAccessException;
Collection<Vet> findVets() throws DataAccessException;
public void saveOwner(Owner owner) throws DataAccessException;
void saveOwner(Owner owner) throws DataAccessException;
Collection<Owner> findOwnerByLastName(String lastName) throws DataAccessException;

View file

@ -26,6 +26,8 @@ import org.springframework.util.StopWatch;
/**
* Simple aspect that monitors call count and call invocation time. It uses JMX annotations and therefore can be
* monitored using any JMX console such as the jConsole
* <p/>
* This is only useful if you use JPA or JDBC. Spring-data-jpa doesn't have any correctly annotated classes to join on
*
* @author Rob Harrop
* @author Juergen Hoeller
@ -42,17 +44,16 @@ public class CallMonitoringAspect {
private long accumulatedCallTime = 0;
@ManagedAttribute
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
@ManagedAttribute
public boolean isEnabled() {
return enabled;
}
@ManagedAttribute
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
@ManagedOperation
public void reset() {
this.callCount = 0;
@ -66,7 +67,10 @@ public class CallMonitoringAspect {
@ManagedAttribute
public long getCallTime() {
return (this.callCount > 0 ? this.accumulatedCallTime / this.callCount : 0);
if (this.callCount > 0)
return this.accumulatedCallTime / this.callCount;
else
return 0;
}

View file

@ -39,13 +39,12 @@ public abstract class EntityUtils {
* @param entityClass the entity class to look up
* @param entityId the entity id to look up
* @return the found entity
* @throws ObjectRetrievalFailureException
* if the entity was not found
* @throws ObjectRetrievalFailureException if the entity was not found
*/
public static <T extends BaseEntity> T getById(Collection<T> entities, Class<T> entityClass, int entityId)
throws ObjectRetrievalFailureException {
throws ObjectRetrievalFailureException {
for (T entity : entities) {
if (entity.getId().intValue() == entityId && entityClass.isInstance(entity)) {
if (entity.getId() == entityId && entityClass.isInstance(entity)) {
return entity;
}
}

View file

@ -33,7 +33,7 @@ public class CrashController {
@RequestMapping(value = "/oups", method = RequestMethod.GET)
public String triggerException() {
throw new RuntimeException("Expected: controller used to showcase what " +
"happens when an exception is thrown");
"happens when an exception is thrown");
}

View file

@ -31,8 +31,6 @@ import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.servlet.ModelAndView;
/**
@ -42,7 +40,6 @@ import org.springframework.web.servlet.ModelAndView;
* @author Michael Isvy
*/
@Controller
@SessionAttributes(types = Owner.class)
public class OwnerController {
private final ClinicService clinicService;
@ -66,12 +63,11 @@ public class OwnerController {
}
@RequestMapping(value = "/owners/new", method = RequestMethod.POST)
public String processCreationForm(@Valid Owner owner, BindingResult result, SessionStatus status) {
public String processCreationForm(@Valid Owner owner, BindingResult result) {
if (result.hasErrors()) {
return "owners/createOrUpdateOwnerForm";
} else {
this.clinicService.saveOwner(owner);
status.setComplete();
return "redirect:/owners/" + owner.getId();
}
}
@ -92,19 +88,18 @@ public class OwnerController {
// find owners by last name
Collection<Owner> results = this.clinicService.findOwnerByLastName(owner.getLastName());
if (results.size() < 1) {
if (results.isEmpty()) {
// no owners found
result.rejectValue("lastName", "notFound", "not found");
return "owners/findOwners";
}
if (results.size() > 1) {
// multiple owners found
model.put("selections", results);
return "owners/ownersList";
} else {
} else if (results.size() == 1) {
// 1 owner found
owner = results.iterator().next();
return "redirect:/owners/" + owner.getId();
} else {
// multiple owners found
model.put("selections", results);
return "owners/ownersList";
}
}
@ -115,13 +110,13 @@ public class OwnerController {
return "owners/createOrUpdateOwnerForm";
}
@RequestMapping(value = "/owners/{ownerId}/edit", method = RequestMethod.PUT)
public String processUpdateOwnerForm(@Valid Owner owner, BindingResult result, SessionStatus status) {
@RequestMapping(value = "/owners/{ownerId}/edit", method = RequestMethod.POST)
public String processUpdateOwnerForm(@Valid Owner owner, BindingResult result, @PathVariable("ownerId") int ownerId) {
if (result.hasErrors()) {
return "owners/createOrUpdateOwnerForm";
} else {
owner.setId(ownerId);
this.clinicService.saveOwner(owner);
status.setComplete();
return "redirect:/owners/{ownerId}";
}
}

View file

@ -15,24 +15,20 @@
*/
package org.springframework.samples.petclinic.web;
import java.util.Collection;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.samples.petclinic.model.Owner;
import org.springframework.samples.petclinic.model.Pet;
import org.springframework.samples.petclinic.model.PetType;
import org.springframework.samples.petclinic.service.ClinicService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.Collection;
/**
* @author Juergen Hoeller
@ -40,12 +36,11 @@ import org.springframework.web.bind.support.SessionStatus;
* @author Arjen Poutsma
*/
@Controller
@SessionAttributes("pet")
@RequestMapping("/owners/{ownerId}")
public class PetController {
private final ClinicService clinicService;
@Autowired
public PetController(ClinicService clinicService) {
this.clinicService = clinicService;
@ -56,48 +51,60 @@ public class PetController {
return this.clinicService.findPetTypes();
}
@InitBinder
public void setAllowedFields(WebDataBinder dataBinder) {
@ModelAttribute("owner")
public Owner findOwner(@PathVariable("ownerId") int ownerId) {
Owner owner = this.clinicService.findOwnerById(ownerId);
return owner;
}
@InitBinder("owner")
public void initOwnerBinder(WebDataBinder dataBinder) {
dataBinder.setDisallowedFields("id");
}
@RequestMapping(value = "/owners/{ownerId}/pets/new", method = RequestMethod.GET)
public String initCreationForm(@PathVariable("ownerId") int ownerId, Map<String, Object> model) {
Owner owner = this.clinicService.findOwnerById(ownerId);
@InitBinder("pet")
public void initPetBinder(WebDataBinder dataBinder) {
dataBinder.setValidator(new PetValidator());
}
@RequestMapping(value = "/pets/new", method = RequestMethod.GET)
public String initCreationForm(Owner owner, ModelMap model) {
Pet pet = new Pet();
owner.addPet(pet);
model.put("pet", pet);
return "pets/createOrUpdatePetForm";
}
@RequestMapping(value = "/owners/{ownerId}/pets/new", method = RequestMethod.POST)
public String processCreationForm(@ModelAttribute("pet") Pet pet, BindingResult result, SessionStatus status) {
new PetValidator().validate(pet, result);
@RequestMapping(value = "/pets/new", method = RequestMethod.POST)
public String processCreationForm(Owner owner, @Valid Pet pet, BindingResult result, ModelMap model) {
if (StringUtils.hasLength(pet.getName()) && pet.isNew() && owner.getPet(pet.getName(), true) != null){
result.rejectValue("name", "duplicate", "already exists");
}
if (result.hasErrors()) {
model.put("pet", pet);
return "pets/createOrUpdatePetForm";
} else {
owner.addPet(pet);
this.clinicService.savePet(pet);
status.setComplete();
return "redirect:/owners/{ownerId}";
}
}
@RequestMapping(value = "/owners/*/pets/{petId}/edit", method = RequestMethod.GET)
public String initUpdateForm(@PathVariable("petId") int petId, Map<String, Object> model) {
@RequestMapping(value = "/pets/{petId}/edit", method = RequestMethod.GET)
public String initUpdateForm(@PathVariable("petId") int petId, ModelMap model) {
Pet pet = this.clinicService.findPetById(petId);
model.put("pet", pet);
return "pets/createOrUpdatePetForm";
}
@RequestMapping(value = "/owners/{ownerId}/pets/{petId}/edit", method = {RequestMethod.PUT, RequestMethod.POST})
public String processUpdateForm(@ModelAttribute("pet") Pet pet, BindingResult result, SessionStatus status) {
// we're not using @Valid annotation here because it is easier to define such validation rule in Java
new PetValidator().validate(pet, result);
@RequestMapping(value = "/pets/{petId}/edit", method = RequestMethod.POST)
public String processUpdateForm(@Valid Pet pet, BindingResult result, Owner owner, ModelMap model) {
if (result.hasErrors()) {
model.put("pet", pet);
return "pets/createOrUpdatePetForm";
} else {
owner.addPet(pet);
this.clinicService.savePet(pet);
status.setComplete();
return "redirect:/owners/{ownerId}";
}
}

View file

@ -18,33 +18,46 @@ package org.springframework.samples.petclinic.web;
import org.springframework.samples.petclinic.model.Pet;
import org.springframework.util.StringUtils;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
/**
* <code>Validator</code> for <code>Pet</code> forms.
* <p>
* We're not using Bean Validation annotations here because it is easier to define such validation rule in Java.
* </p>
*
* @author Ken Krebs
* @author Juergen Hoeller
*/
public class PetValidator {
public class PetValidator implements Validator {
public void validate(Pet pet, Errors errors) {
@Override
public void validate(Object obj, Errors errors) {
Pet pet = (Pet) obj;
String name = pet.getName();
// name validaation
// name validation
if (!StringUtils.hasLength(name)) {
errors.rejectValue("name", "required", "required");
} else if (pet.isNew() && pet.getOwner().getPet(name, true) != null) {
errors.rejectValue("name", "duplicate", "already exists");
}
// type valication
// type validation
if (pet.isNew() && pet.getType() == null) {
errors.rejectValue("type", "required", "required");
}
// type valication
if (pet.getBirthDate()==null) {
// birth date validation
if (pet.getBirthDate() == null) {
errors.rejectValue("birthDate", "required", "required");
}
}
/**
* This Validator validates *just* Pet instances
*/
@Override
public boolean supports(Class<?> clazz) {
return Pet.class.isAssignableFrom(clazz);
}
}

View file

@ -22,6 +22,7 @@ import org.springframework.samples.petclinic.model.Vets;
import org.springframework.samples.petclinic.service.ClinicService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @author Juergen Hoeller
@ -40,7 +41,7 @@ public class VetController {
this.clinicService = clinicService;
}
@RequestMapping("/vets")
@RequestMapping(value = {"/vets.xml", "/vets.html"})
public String showVetList(Map<String, Object> model) {
// Here we are returning an object of type 'Vets' rather than a collection of Vet objects
// so it is simpler for Object-Xml mapping
@ -50,5 +51,16 @@ public class VetController {
return "vets/vetList";
}
@RequestMapping("/vets.json")
public
@ResponseBody
Vets showResourcesVetList() {
// Here we are returning an object of type 'Vets' rather than a collection of Vet objects
// so it is simpler for JSon/Object mapping
Vets vets = new Vets();
vets.getVetList().addAll(this.clinicService.findVets());
return vets;
}
}

View file

@ -1,74 +0,0 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.samples.petclinic.web;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.samples.petclinic.model.Vet;
import org.springframework.samples.petclinic.model.Vets;
import org.springframework.web.servlet.view.feed.AbstractAtomFeedView;
import com.sun.syndication.feed.atom.Content;
import com.sun.syndication.feed.atom.Entry;
import com.sun.syndication.feed.atom.Feed;
/**
* A view creating a Atom representation from a list of Visit objects.
*
* @author Alef Arendsen
* @author Arjen Poutsma
*/
public class VetsAtomView extends AbstractAtomFeedView {
@Override
protected void buildFeedMetadata(Map<String, Object> model, Feed feed, HttpServletRequest request) {
feed.setId("tag:springsource.org");
feed.setTitle("Veterinarians");
//feed.setUpdated(date);
}
@Override
protected List<Entry> buildFeedEntries(Map<String, Object> model,
HttpServletRequest request, HttpServletResponse response) throws Exception {
Vets vets = (Vets) model.get("vets");
List<Vet> vetList = vets.getVetList();
List<Entry> entries = new ArrayList<Entry>(vetList.size());
for (Vet vet : vetList) {
Entry entry = new Entry();
// see http://diveintomark.org/archives/2004/05/28/howto-atom-id#other
entry.setId(String.format("tag:springsource.org,%s", vet.getId()));
entry.setTitle(String.format("Vet: %s %s", vet.getFirstName(), vet.getLastName()));
//entry.setUpdated(visit.getDate().toDate());
Content summary = new Content();
summary.setValue(vet.getSpecialties().toString());
entry.setSummary(summary);
entries.add(entry);
}
response.setContentType("blabla");
return entries;
}
}

View file

@ -27,12 +27,10 @@ import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.servlet.ModelAndView;
/**
* @author Juergen Hoeller
@ -41,7 +39,6 @@ import org.springframework.web.servlet.ModelAndView;
* @author Michael Isvy
*/
@Controller
@SessionAttributes("visit")
public class VisitController {
private final ClinicService clinicService;
@ -57,31 +54,45 @@ public class VisitController {
dataBinder.setDisallowedFields("id");
}
@RequestMapping(value = "/owners/*/pets/{petId}/visits/new", method = RequestMethod.GET)
public String initNewVisitForm(@PathVariable("petId") int petId, Map<String, Object> model) {
/**
* Called before each and every @RequestMapping annotated method.
* 2 goals:
* - Make sure we always have fresh data
* - Since we do not use the session scope, make sure that Pet object always has an id
* (Even though id is not part of the form fields)
*
* @param petId
* @return Pet
*/
@ModelAttribute("visit")
public Visit loadPetWithVisit(@PathVariable("petId") int petId) {
Pet pet = this.clinicService.findPetById(petId);
Visit visit = new Visit();
pet.addVisit(visit);
model.put("visit", visit);
return visit;
}
// Spring MVC calls method loadPetWithVisit(...) before initNewVisitForm is called
@RequestMapping(value = "/owners/*/pets/{petId}/visits/new", method = RequestMethod.GET)
public String initNewVisitForm(@PathVariable("petId") int petId, Map<String, Object> model) {
return "pets/createOrUpdateVisitForm";
}
// Spring MVC calls method loadPetWithVisit(...) before processNewVisitForm is called
@RequestMapping(value = "/owners/{ownerId}/pets/{petId}/visits/new", method = RequestMethod.POST)
public String processNewVisitForm(@Valid Visit visit, BindingResult result, SessionStatus status) {
public String processNewVisitForm(@Valid Visit visit, BindingResult result) {
if (result.hasErrors()) {
return "pets/createOrUpdateVisitForm";
} else {
this.clinicService.saveVisit(visit);
status.setComplete();
return "redirect:/owners/{ownerId}";
}
}
@RequestMapping(value = "/owners/*/pets/{petId}/visits", method = RequestMethod.GET)
public ModelAndView showVisits(@PathVariable int petId) {
ModelAndView mav = new ModelAndView("visitList");
mav.addObject("visits", this.clinicService.findPetById(petId).getVisits());
return mav;
public String showVisits(@PathVariable int petId, Map<String, Object> model) {
model.put("visits", this.clinicService.findPetById(petId).getVisits());
return "visitList";
}
}

View file

@ -1,8 +1,5 @@
/**
*
* The classes in this package represent PetClinic's web presentation layer.
*
*/
package org.springframework.samples.petclinic.web;

53
src/main/java/test.html Normal file
View file

@ -0,0 +1,53 @@
<head>
<style type="text/css">
table.speakersTable {
width: 70%;
padding: 10;
spacing: 10;
}
img.speakerPic {
float: right;
padding: 10;
width: 90;
}
</style>
</head>
<h1>Organisation</h1>
<h1>Speakers</h1>
<table class="speakersTable">
<tbody>
<tr>
<td>
<img class="speakerPic" alt="Sergiu Bodiu"
src="http://m.c.lnkd.licdn.com/mpr/mpr/shrink_200_200/p/4/000/16a/2ba/0ba653e.jpg"/>
<h2>Sergiu Bodiu </h2>
<h3> Java Consultant at Bank of America </h3>
<font size="5">S</font>easoned consultant experienced in large-scale e-commerce projects, passionate about
providing innovative technology solutions to solve complex business problems, have extensive knowledge and
experience delivering enterprise wide applications. He is skilled in software design, data modeling,
stakeholder management, IT strategic planning, technical know-how and security. Able to design, implement,
test and maintain software product components with strong focus on design elegance and software reuse.
</td>
</tr>
<tr>
<td>
<img alt="Sergiu Bodiu" src="http://m.c.lnkd.licdn.com/mpr/mpr/shrink_200_200/p/4/000/16a/2ba/0ba653e.jpg"
width="84" height="84" align="right" hspace="10"/>
<h2>Sergiu Bodiu </h2>
<h3> Java Consultant at Bank of America </h3>
<font size="5">S</font>easoned consultant experienced in large-scale e-commerce projects, passionate about
providing innovative technology solutions to solve complex business problems, have extensive knowledge and
experience delivering enterprise wide applications. He is skilled in software design, data modeling,
stakeholder management, IT strategic planning, technical know-how and security. Able to design, implement,
test and maintain software product components with strong focus on design elegance and software reuse.
</td>
</tr>
</tbody>
</table>

View file

@ -0,0 +1,6 @@
# ==================================
# Dandelion-Datatables configuration
# ==================================
# Disable the asset management of Dandelion-Core for all non-DataTable-related assets
main.standalone=true

View file

@ -19,6 +19,6 @@
3) Create the PetClinic database and user by executing the "db/mysql/createDB.txt"
script.
4) Open "src/main/resources/spring/jdbc.properties"; comment out all properties in the
4) Open "src/main/resources/spring/data-access.properties"; comment out all properties in the
"HSQL Settings" section; uncomment all properties in the "MySQL Settings"
section.

View file

@ -1,13 +0,0 @@
================================================================================
=== Spring PetClinic sample application - Database Configuration ===
================================================================================
@author Costin Leau
--------------------------------------------------------------------------------
In its default configuration, Petclinic uses an in-memory database (HSQLDB) which
gets populated at startup with data. A similar setup is provided for Mysql in case
a persistent database configuration is needed.
Note that whenever the database type is changed, the jdbc.properties file needs to
be updated.

View file

@ -1,4 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xml>
<configuration scan="true" scanPeriod="30 seconds">
<contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
@ -14,7 +16,7 @@
</encoder>
</appender>
<!--<logger name="org.hibernate" level="debug"/> -->
<!--<logger name="org.hibernate" level="debug"/> -->
<logger name="org.springframework.samples.petclinic" level="debug"/>
<root level="info">

View file

@ -2,10 +2,10 @@
<!--
Repository and Service layers
-->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
@ -16,21 +16,21 @@
<import resource="datasource-config.xml"/>
<context:component-scan
base-package="org.springframework.samples.petclinic.service"/>
base-package="org.springframework.samples.petclinic.service"/>
<!-- Configurer that replaces ${...} placeholders with values from a properties file -->
<!-- (in this case, JDBC-related settings for the JPA EntityManager definition below) -->
<context:property-placeholder location="classpath:spring/data-access.properties" system-properties-mode="OVERRIDE"/>
<!-- enables scanning for @Transactional annotations -->
<tx:annotation-driven />
<!-- enables scanning for @Transactional annotations -->
<tx:annotation-driven/>
<!-- ================== 3 Profiles to choose from ===================
- jdbc (uses Spring" JdbcTemplate)
- jpa
- spring-data-jpa
=============================================================================-->
<!-- ================== 3 Profiles to choose from ===================
- jdbc (uses Spring" JdbcTemplate)
- jpa
- spring-data-jpa
=============================================================================-->
<beans profile="jpa,spring-data-jpa">
<!-- JPA EntityManagerFactory -->

View file

@ -4,6 +4,12 @@
# various application context XML files (e.g., "applicationContext-*.xml").
# Targeted at system administrators, to avoid touching the context XML files.
# Properties that control the population of schema and data for a new data source
jdbc.initLocation=classpath:db/hsqldb/initDB.sql
jdbc.dataLocation=classpath:db/hsqldb/populateDB.sql
jpa.showSql=true
#-------------------------------------------------------------------------------
# HSQL Settings
@ -12,14 +18,9 @@ jdbc.url=jdbc:hsqldb:mem:petclinic
jdbc.username=sa
jdbc.password=
# Properties that control the population of schema and data for a new data source
jdbc.initLocation=classpath:db/hsqldb/initDB.sql
jdbc.dataLocation=classpath:db/hsqldb/populateDB.sql
# Property that determines which database to use with an AbstractJpaVendorAdapter
jpa.database=HSQL
jpa.showSql=true
#-------------------------------------------------------------------------------
# MySQL Settings
@ -27,15 +28,7 @@ jpa.showSql=true
#jdbc.driverClassName=com.mysql.jdbc.Driver
#jdbc.url=jdbc:mysql://localhost:3306/petclinic
#jdbc.username=root
#jdbc.password=
# Properties that control the population of schema and data for a new data source
#jdbc.initLocation=classpath:db/mysql/initDB.sql
#jdbc.dataLocation=classpath:db/mysql/populateDB.sql
# Property that determines which Hibernate dialect to use
# (only applied with "applicationContext-hibernate.xml")
#hibernate.dialect=org.hibernate.dialect.MySQLDialect
#jdbc.password=petclinic
# Property that determines which database to use with an AbstractJpaVendorAdapter
#jpa.database=MYSQL

View file

@ -2,11 +2,11 @@
<!--
Application context definition for PetClinic Datasource.
-->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
@ -36,7 +36,7 @@
<jdbc:script location="${jdbc.dataLocation}"/>
</jdbc:initialize-database>
<beans profile="javaee" >
<beans profile="javaee">
<!-- JNDI DataSource for JEE environments -->
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/petclinic"/>
</beans>

View file

@ -2,11 +2,11 @@
<!--
- DispatcherServlet application context for PetClinic's web tier.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans
@ -20,7 +20,7 @@
- POJOs labeled with the @Controller and @Service annotations are auto-detected.
-->
<context:component-scan
base-package="org.springframework.samples.petclinic.web"/>
base-package="org.springframework.samples.petclinic.web"/>
<mvc:annotation-driven conversion-service="conversionService"/>
@ -31,9 +31,10 @@
<!-- uses WebJars so Javascript and CSS libs can be declared as Maven dependencies (Bootstrap, jQuery...) -->
<mvc:resources mapping="/webjars/**" location="classpath:/META-INF/resources/webjars/"/>
<mvc:view-controller path="/" view-name="welcome" />
<mvc:view-controller path="/" view-name="welcome"/>
<!-- serve static resources (*.html, ...) from src/main/webapp/ -->
<!-- serve static resources (*.html, ...) from src/main/webapp/
Required when both servlet-mapping is '/' and static resources need to be served -->
<mvc:default-servlet-handler/>
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">

View file

@ -2,54 +2,30 @@
<!--
- DispatcherServlet application context for PetClinic's web tier.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:oxm="http://www.springframework.org/schema/oxm"
xsi:schemaLocation="http://www.springframework.org/schema/oxm
http://www.springframework.org/schema/oxm/spring-oxm.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:oxm="http://www.springframework.org/schema/oxm"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
- The ContentNegotiatingViewResolver delegates to the InternalResourceViewResolver and BeanNameViewResolver,
- and uses the requested media type (determined by the path extension) to pick a matching view.
- When the media type is 'text/html', it will delegate to the InternalResourceViewResolver's JstlView,
- otherwise to the BeanNameViewResolver.
-->
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="contentNegotiationManager" ref="cnManager"/>
<mvc:view-resolvers>
<mvc:content-negotiation use-not-acceptable="true">
<mvc:default-views>
<bean class="org.springframework.web.servlet.view.JstlView">
<property name="url" value=""/>
</bean>
</mvc:default-views>
</mvc:content-negotiation>
<property name="viewResolvers">
<list>
<!-- Default viewClass: JSTL view (JSP with html output) -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- Example: a logical view name of 'vets' is mapped to '/WEB-INF/jsp/vets.jsp' -->
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- Used here for 'xml' and 'atom' views -->
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
</list>
</property>
</bean>
<!-- Simple strategy: only path extension is taken into account -->
<bean id="cnManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="true"/>
<property name="ignoreAcceptHeader" value="true"/>
<property name="defaultContentType" value="text/html"/>
<property name="mediaTypes">
<map>
<entry key="html" value="text/html" />
<entry key="xml" value="application/xml" />
<entry key="atom" value="application/atom+xml" />
</map>
</property>
</bean>
<!-- Renders an Atom feed of the visits. Used by the BeanNameViewResolver -->
<bean id="vets/vetList.atom" class="org.springframework.samples.petclinic.web.VetsAtomView"/>
<!-- Registering BeanNameViewResolver and InternalViewResolver -->
<mvc:bean-name/>
<mvc:jsp prefix="/WEB-INF/jsp/" suffix=".jsp"/>
</mvc:view-resolvers>
<!-- Renders an XML view. Used by the BeanNameViewResolver -->
<bean id="vets/vetList.xml" class="org.springframework.web.servlet.view.xml.MarshallingView">

View file

@ -2,11 +2,11 @@
<!--
Application context definition for PetClinic on JPA.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/beans

View file

@ -1,10 +1,11 @@
<!DOCTYPE html>
<%@ page session="false" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html lang="en">
<jsp:include page="fragments/headTag.jsp"/>
<jsp:include page="fragments/staticFiles.jsp"/>
<body>
<div class="container">

View file

@ -7,17 +7,15 @@
<div class="navbar" style="width: 601px;">
<div class="navbar-inner">
<ul class="nav">
<li style="width: 100px;"><a href="<spring:url value="/" htmlEscape="true" />"><i class="icon-home"></i>
<li style="width: 120px;"><a href="<spring:url value="/" htmlEscape="true" />"><i class="icon-home"></i>
Home</a></li>
<li style="width: 130px;"><a href="<spring:url value="/owners/find.html" htmlEscape="true" />"><i
<li style="width: 150px;"><a href="<spring:url value="/owners/find.html" htmlEscape="true" />"><i
class="icon-search"></i> Find owners</a></li>
<li style="width: 140px;"><a href="<spring:url value="/vets.html" htmlEscape="true" />"><i
<li style="width: 160px;"><a href="<spring:url value="/vets.html" htmlEscape="true" />"><i
class="icon-th-list"></i> Veterinarians</a></li>
<li style="width: 90px;"><a href="<spring:url value="/oups.html" htmlEscape="true" />"
title="trigger a RuntimeException to see how it is handled"><i
<li style="width: 110px;"><a href="<spring:url value="/oups.html" htmlEscape="true" />"
title="trigger a RuntimeException to see how it is handled"><i
class="icon-warning-sign"></i> Error</a></li>
<li style="width: 80px;"><a href="#" title="not available yet. Work in progress!!"><i
class=" icon-question-sign"></i> Help</a></li>
</ul>
</div>
</div>

View file

@ -2,9 +2,9 @@
<table class="footer">
<tr>
<td></td>
<td align="right"><img src="<spring:url value="/resources/images/springsource-logo.png" htmlEscape="true" />"
alt="Sponsored by SpringSource"/></td>
<td width="70%"></td>
<td align="right"><img src="<spring:url value="/resources/images/spring-pivotal-logo.png" htmlEscape="true" />"
alt="Sponsored by Pivotal"/></td>
</tr>
</table>

View file

@ -18,11 +18,11 @@ PetClinic :: a Spring Framework demonstration
<spring:url value="/webjars/jquery/2.0.3/jquery.js" var="jQuery"/>
<script src="${jQuery}"></script>
<!-- jquery-ui.js file is really big so we only load what we need instead of loading everything -->
<!-- jquery-ui.js file is really big so we only load what we need instead of loading everything -->
<spring:url value="/webjars/jquery-ui/1.10.3/ui/jquery.ui.core.js" var="jQueryUiCore"/>
<script src="${jQueryUiCore}"></script>
<spring:url value="/webjars/jquery-ui/1.10.3/ui/jquery.ui.datepicker.js" var="jQueryUiDatePicker"/>
<spring:url value="/webjars/jquery-ui/1.10.3/ui/jquery.ui.datepicker.js" var="jQueryUiDatePicker"/>
<script src="${jQueryUiDatePicker}"></script>
<!-- jquery-ui.css file is not that big so we can afford to load it -->

View file

@ -1,5 +1,6 @@
<!DOCTYPE html>
<%@ page session="false" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
@ -10,20 +11,16 @@
<html lang="en">
<jsp:include page="../fragments/headTag.jsp"/>
<jsp:include page="../fragments/staticFiles.jsp"/>
<body>
<div class="container">
<jsp:include page="../fragments/bodyHeader.jsp"/>
<c:choose>
<c:when test="${owner['new']}"><c:set var="method" value="post"/></c:when>
<c:otherwise><c:set var="method" value="put"/></c:otherwise>
</c:choose>
<h2>
<c:if test="${owner['new']}">New </c:if> Owner
</h2>
<form:form modelAttribute="owner" method="${method}" class="form-horizontal" id="add-owner-form">
<form:form modelAttribute="owner" class="form-horizontal" id="add-owner-form">
<petclinic:inputField label="First Name" name="firstName"/>
<petclinic:inputField label="Last Name" name="lastName"/>
<petclinic:inputField label="Address" name="address"/>

View file

@ -1,5 +1,6 @@
<!DOCTYPE html>
<%@ page session="false" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
@ -7,7 +8,7 @@
<html lang="en">
<jsp:include page="../fragments/headTag.jsp"/>
<jsp:include page="../fragments/staticFiles.jsp"/>
<body>
<div class="container">

View file

@ -1,5 +1,6 @@
<!DOCTYPE html>
<%@ page session="false" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
@ -8,7 +9,7 @@
<html lang="en">
<jsp:include page="../fragments/headTag.jsp"/>
<jsp:include page="../fragments/staticFiles.jsp"/>
<body>
<div class="container">
@ -33,17 +34,17 @@
<th>Telephone</th>
<td><c:out value="${owner.telephone}"/></td>
</tr>
<tr>
<tr>
<td>
<spring:url value="{ownerId}/edit.html" var="editUrl">
<spring:url value="{ownerId}/edit.html" var="editUrl">
<spring:param name="ownerId" value="${owner.id}"/>
</spring:url>
<a href="${fn:escapeXml(editUrl)}" class="btn btn-info">Edit Owner</a></td>
<td>
<spring:url value="{ownerId}/pets/new.html" var="addUrl">
<spring:url value="{ownerId}/pets/new.html" var="addUrl">
<spring:param name="ownerId" value="${owner.id}"/>
</spring:url>
<a href="${fn:escapeXml(addUrl)}" class="btn btn-success">Add New Pet</a></td>
<a href="${fn:escapeXml(addUrl)}" class="btn btn-success">Add New Pet</a></td>
</tr>
</table>
@ -78,20 +79,20 @@
</c:forEach>
<tr>
<td>
<spring:url value="/owners/{ownerId}/pets/{petId}/edit" var="petUrl">
<spring:param name="ownerId" value="${owner.id}"/>
<spring:param name="petId" value="${pet.id}"/>
</spring:url>
<a href="${fn:escapeXml(petUrl)}">Edit Pet</a>
</td>
<td>
<spring:url value="/owners/{ownerId}/pets/{petId}/visits/new" var="visitUrl">
<spring:param name="ownerId" value="${owner.id}"/>
<spring:param name="petId" value="${pet.id}"/>
</spring:url>
<a href="${fn:escapeXml(visitUrl)}">Add Visit</a>
<spring:url value="/owners/{ownerId}/pets/{petId}/edit" var="petUrl">
<spring:param name="ownerId" value="${owner.id}"/>
<spring:param name="petId" value="${pet.id}"/>
</spring:url>
<a href="${fn:escapeXml(petUrl)}">Edit Pet</a>
</td>
</tr>
<td>
<spring:url value="/owners/{ownerId}/pets/{petId}/visits/new" var="visitUrl">
<spring:param name="ownerId" value="${owner.id}"/>
<spring:param name="petId" value="${pet.id}"/>
</spring:url>
<a href="${fn:escapeXml(visitUrl)}">Add Visit</a>
</td>
</tr>
</table>
</td>
</tr>

View file

@ -1,5 +1,6 @@
<!DOCTYPE html>
<%@ page session="false" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
@ -8,15 +9,15 @@
<html lang="en">
<jsp:include page="../fragments/headTag.jsp"/>
<jsp:include page="../fragments/staticFiles.jsp"/>
<body>
<div class="container">
<jsp:include page="../fragments/bodyHeader.jsp"/>
<h2>Owners</h2>
<datatables:table id="owners" data="${selections}" cdn="true" row="owner" theme="bootstrap2"
cssClass="table table-striped" paginate="false" info="false" export="pdf">
<datatables:table id="owners" data="${selections}" row="owner" theme="bootstrap2"
cssClass="table table-striped" pageable="false" info="false" export="pdf">
<datatables:column title="Name" cssStyle="width: 150px;" display="html">
<spring:url value="/owners/{ownerId}.html" var="ownerUrl">
<spring:param name="ownerId" value="${owner.id}"/>
@ -34,7 +35,7 @@
<c:out value="${pet.name}"/>
</c:forEach>
</datatables:column>
<datatables:export type="pdf" cssClass="btn btn-small" />
<datatables:export type="pdf" cssClass="btn" cssStyle="height: 25px;"/>
</datatables:table>
<jsp:include page="../fragments/footer.jsp"/>

View file

@ -1,5 +1,6 @@
<!DOCTYPE html>
<%@ page session="false" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
@ -8,32 +9,25 @@
<html lang="en">
<jsp:include page="../fragments/headTag.jsp"/>
<jsp:include page="../fragments/staticFiles.jsp"/>
<body>
<script>
$(function () {
$("#birthDate").datepicker({ dateFormat: 'yy/mm/dd'});
$("#birthDate").datepicker({dateFormat: 'yy/mm/dd'});
});
</script>
<div class="container">
<jsp:include page="../fragments/bodyHeader.jsp"/>
<c:choose>
<c:when test="${pet['new']}">
<c:set var="method" value="post"/>
</c:when>
<c:otherwise>
<c:set var="method" value="put"/>
</c:otherwise>
</c:choose>
<h2>
<c:if test="${pet['new']}">New </c:if>
Pet
</h2>
<form:form modelAttribute="pet" method="${method}"
<form:form modelAttribute="pet"
class="form-horizontal">
<input type="hidden" name="id" value="${pet.id}"/>
<div class="control-group" id="owner">
<label class="control-label">Owner </label>

View file

@ -1,20 +1,23 @@
<!DOCTYPE html>
<%@ page session="false" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="joda" uri="http://www.joda.org/joda/time/tags" %>
<%@ taglib prefix="petclinic" tagdir="/WEB-INF/tags" %>
<html lang="en">
<jsp:include page="../fragments/headTag.jsp"/>
<jsp:include page="../fragments/staticFiles.jsp"/>
<body>
<script>
$(function () {
$("#date").datepicker({ dateFormat: 'yy/mm/dd'});
$("#date").datepicker({dateFormat: 'yy/mm/dd'});
});
</script>
<div class="container">
@ -40,22 +43,10 @@
</table>
<form:form modelAttribute="visit">
<div class="control-group">
<label class="control-label">Date </label>
<div class="controls">
<form:input path="date"/>
<span class="help-inline"><form:errors path="date"/></span>
</div>
</div>
<div class="control-group">
<label class="control-label">Description </label>
<petclinic:inputField label="date" name="date"/>
<petclinic:inputField label="description" name="description"/>
<div class="controls">
<form:input path="description"/>
<span class="help-inline"><form:errors path="description"/></span>
</div>
</div>
<div class="form-actions">
<input type="hidden" name="petId" value="${visit.pet.id}"/>
<button type="submit">Add Visit</button>

View file

@ -1,5 +1,6 @@
<!DOCTYPE html>
<%@ page session="false" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
@ -8,7 +9,7 @@
<html lang="en">
<jsp:include page="../fragments/headTag.jsp"/>
<jsp:include page="../fragments/staticFiles.jsp"/>
<body>
<div class="container">
@ -16,7 +17,8 @@
<h2>Veterinarians</h2>
<datatables:table id="vets" data="${vets.vetList}" cdn="true" row="vet" theme="bootstrap2" cssClass="table table-striped" paginate="false" info="false">
<datatables:table id="vets" data="${vets.vetList}" row="vet" theme="bootstrap2" cssClass="table table-striped"
pageable="false" info="false">
<datatables:column title="Name">
<c:out value="${vet.firstName} ${vet.lastName}"></c:out>
</datatables:column>
@ -34,7 +36,7 @@
<a href="<spring:url value="/vets.xml" htmlEscape="true" />">View as XML</a>
</td>
<td>
<a href="<spring:url value="/vets.atom" htmlEscape="true" />">Subscribe to Atom feed</a>
<a href="<spring:url value="/vets.json" htmlEscape="true" />">View as JSon</a>
</td>
</tr>
</table>

View file

@ -1,12 +1,13 @@
<!DOCTYPE html>
<%@ page session="false" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<html lang="en">
<jsp:include page="fragments/headTag.jsp"/>
<jsp:include page="fragments/staticFiles.jsp"/>
<body>
<div class="container">

View file

@ -2,30 +2,32 @@
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0" metadata-complete="true">
<display-name>Spring PetClinic</display-name>
<description>Spring PetClinic sample application</description>
<!-- When using Spring jpa, use the following: -->
<context-param>
<param-name>spring.profiles.active</param-name>
<param-value>jpa</param-value>
</context-param>
<!-- When using Spring JDBC, use the following: -->
<!-- <context-param>
<param-name>spring.profiles.active</param-name>
<param-value>jdbc</param-value>
</context-param> -->
<!-- When using Spring JDBC, use the following: -->
<!-- <context-param>
<param-name>spring.profiles.active</param-name>
<param-value>jdbc</param-value>
</context-param> -->
<!-- When using Spring Data JPA, uncomment the following: -->
<!--
<context-param>
<param-name>spring.profiles.active</param-name>
<param-value>spring-data-jpa</param-value>
</context-param>
-->
<!-- the CallMonitoringAspect counts invocations on classes with @Repository on them. Classes in spring-data-jpa don't have that annotation -->
<!-- When using Spring Data JPA, uncomment the following: -->
<!--
<context-param>
<param-name>spring.profiles.active</param-name>
<param-value>spring-data-jpa</param-value>
</context-param>
-->
<!--
- Location of the XML file that defines the root application context.
@ -58,59 +60,53 @@ http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- Dandelion-Datatables servlet definition -->
<!-- Dandelion servlet definition and mapping -->
<servlet>
<servlet-name>datatablesController</servlet-name>
<servlet-class>com.github.dandelion.datatables.extras.servlet2.servlet.DatatablesServlet</servlet-class>
<servlet-name>dandelionServlet</servlet-name>
<servlet-class>com.github.dandelion.core.web.DandelionServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<!-- Dandelion-Datatables servlet mapping -->
<servlet-mapping>
<servlet-name>datatablesController</servlet-name>
<url-pattern>/datatablesController/*</url-pattern>
<servlet-name>dandelionServlet</servlet-name>
<url-pattern>/dandelion-assets/*</url-pattern>
</servlet-mapping>
<!-- used so we can use forms of method type 'PUT' and 'DELETE' (such as in the Pet form)
see here: http://static.springsource.org/spring/docs/current/spring-framework-reference/html/view.html#rest-method-conversion
-->
<filter>
<filter-name>httpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>httpMethodFilter</filter-name>
<servlet-name>petclinic</servlet-name>
</filter-mapping>
<!-- used to provide the ability to enter Chinese characters inside the Owner Form -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Dandelion-Datatables filter definition -->
<filter>
<filter-name>datatablesFilter</filter-name>
<filter-class>com.github.dandelion.datatables.extras.servlet2.filter.DatatablesFilter</filter-class>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<!-- Dandelion-Datatables filter mapping -->
<filter-mapping>
<filter-name>datatablesFilter</filter-name>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Dandelion filter definition and mapping -->
<filter>
<filter-name>dandelionFilter</filter-name>
<filter-class>com.github.dandelion.core.web.DandelionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>dandelionFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Dandelion-Datatables filter, used for basic export -->
<filter>
<filter-name>datatables</filter-name>
<filter-class>com.github.dandelion.datatables.core.web.filter.DatatablesFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>datatables</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

View file

@ -1,6 +1,5 @@
.container {
padding-top: 10px;
margin-left: 50px;
width: 700px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -1,44 +0,0 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.samples.petclinic.model;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import org.junit.Test;
import org.springframework.transaction.annotation.Transactional;
/**
* JUnit test for the {@link Owner} class.
*
* @author Ken Krebs
*/
public class OwnerTests {
@Test
@Transactional
public void testHasPet() {
Owner owner = new Owner();
Pet fido = new Pet();
fido.setName("Fido");
assertNull(owner.getPet("Fido"));
assertNull(owner.getPet("fido"));
owner.addPet(fido);
assertEquals(fido, owner.getPet("Fido"));
assertEquals(fido, owner.getPet("fido"));
}
}

View file

@ -1,37 +1,34 @@
package org.springframework.samples.petclinic.model;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Locale;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
/**
*
* @author Michael Isvy
* Simple test to make sure that Bean Validation is working
* (useful when upgrading to a new version of Hibernate Validator/ Bean Validation)
*
* Simple test to make sure that Bean Validation is working
* (useful when upgrading to a new version of Hibernate Validator/ Bean Validation)
*/
public class ValidatorTests {
private Validator createValidator() {
LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
localValidatorFactoryBean.afterPropertiesSet();
return localValidatorFactoryBean;
}
private Validator createValidator() {
LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
localValidatorFactoryBean.afterPropertiesSet();
return localValidatorFactoryBean;
}
@Test
public void emptyFirstName() {
@Test
public void shouldNotValidateWhenFirstNameEmpty() {
LocaleContextHolder.setLocale(Locale.ENGLISH);
Person person = new Person();
person.setFirstName("");
person.setLastName("smith");
@ -39,10 +36,10 @@ public class ValidatorTests {
Validator validator = createValidator();
Set<ConstraintViolation<Person>> constraintViolations = validator.validate(person);
Assert.assertEquals(1, constraintViolations.size());
ConstraintViolation<Person> violation = constraintViolations.iterator().next();
Assert.assertEquals(violation.getPropertyPath().toString(), "firstName");
Assert.assertEquals(violation.getMessage(), "may not be empty");
assertThat(constraintViolations.size()).isEqualTo(1);
ConstraintViolation<Person> violation = constraintViolations.iterator().next();
assertThat(violation.getPropertyPath().toString()).isEqualTo("firstName");
assertThat(violation.getMessage()).isEqualTo("may not be empty");
}
}

View file

@ -15,14 +15,12 @@
*/
package org.springframework.samples.petclinic.service;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Collection;
import org.joda.time.DateTime;
import org.junit.Assert;
import org.joda.time.LocalDate;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.samples.petclinic.model.Owner;
@ -41,7 +39,7 @@ import org.springframework.transaction.annotation.Transactional;
* TestContext Framework: </p> <ul> <li><strong>Spring IoC container caching</strong> which spares us unnecessary set up
* time between test execution.</li> <li><strong>Dependency Injection</strong> of test fixture instances, meaning that
* we don't need to perform application context lookups. See the use of {@link Autowired @Autowired} on the <code>{@link
* AbstractclinicServiceTests#clinicService clinicService}</code> instance variable, which uses autowiring <em>by
* AbstractClinicServiceTests#clinicService clinicService}</code> instance variable, which uses autowiring <em>by
* type</em>. <li><strong>Transaction management</strong>, meaning each test method is executed in its own transaction,
* which is automatically rolled back by default. Thus, even if tests insert or otherwise change database state, there
* is no need for a teardown or cleanup script. <li> An {@link org.springframework.context.ApplicationContext
@ -59,29 +57,29 @@ public abstract class AbstractClinicServiceTests {
protected ClinicService clinicService;
@Test
@Transactional
public void findOwners() {
public void shouldFindOwnersByLastName() {
Collection<Owner> owners = this.clinicService.findOwnerByLastName("Davis");
assertEquals(2, owners.size());
assertThat(owners.size()).isEqualTo(2);
owners = this.clinicService.findOwnerByLastName("Daviss");
assertEquals(0, owners.size());
assertThat(owners.isEmpty());
}
@Test
public void findSingleOwner() {
Owner owner1 = this.clinicService.findOwnerById(1);
assertTrue(owner1.getLastName().startsWith("Franklin"));
Owner owner10 = this.clinicService.findOwnerById(10);
assertEquals("Carlos", owner10.getFirstName());
assertEquals(owner1.getPets().size(), 1);
public void shouldFindSingleOwnerWithPet() {
Owner owner = this.clinicService.findOwnerById(1);
assertThat(owner.getLastName()).startsWith("Franklin");
assertThat(owner.getPets().size()).isEqualTo(1);
assertThat(owner.getPets().get(0).getType()).isNotNull();
assertThat(owner.getPets().get(0).getType().getName()).isEqualTo("cat");
}
@Test
@Transactional
public void insertOwner() {
public void shouldInsertOwner() {
Collection<Owner> owners = this.clinicService.findOwnerByLastName("Schultz");
int found = owners.size();
Owner owner = new Owner();
owner.setFirstName("Sam");
owner.setLastName("Schultz");
@ -89,106 +87,108 @@ public abstract class AbstractClinicServiceTests {
owner.setCity("Wollongong");
owner.setTelephone("4444444444");
this.clinicService.saveOwner(owner);
Assert.assertNotEquals("Owner Id should have been generated", owner.getId().longValue(), 0);
assertThat(owner.getId().longValue()).isNotEqualTo(0);
owners = this.clinicService.findOwnerByLastName("Schultz");
assertEquals("Verifying number of owners after inserting a new one.", found + 1, owners.size());
assertThat(owners.size()).isEqualTo(found + 1);
}
@Test
@Transactional
public void updateOwner() throws Exception {
Owner o1 = this.clinicService.findOwnerById(1);
String old = o1.getLastName();
o1.setLastName(old + "X");
this.clinicService.saveOwner(o1);
o1 = this.clinicService.findOwnerById(1);
assertEquals(old + "X", o1.getLastName());
public void shouldUpdateOwner() {
Owner owner = this.clinicService.findOwnerById(1);
String oldLastName = owner.getLastName();
String newLastName = oldLastName + "X";
owner.setLastName(newLastName);
this.clinicService.saveOwner(owner);
// retrieving new name from database
owner = this.clinicService.findOwnerById(1);
assertThat(owner.getLastName()).isEqualTo(newLastName);
}
@Test
public void findPet() {
Collection<PetType> types = this.clinicService.findPetTypes();
Pet pet7 = this.clinicService.findPetById(7);
assertTrue(pet7.getName().startsWith("Samantha"));
assertEquals(EntityUtils.getById(types, PetType.class, 1).getId(), pet7.getType().getId());
assertEquals("Jean", pet7.getOwner().getFirstName());
Pet pet6 = this.clinicService.findPetById(6);
assertEquals("George", pet6.getName());
assertEquals(EntityUtils.getById(types, PetType.class, 4).getId(), pet6.getType().getId());
assertEquals("Peter", pet6.getOwner().getFirstName());
}
@Test
public void shouldFindPetWithCorrectId() {
Pet pet7 = this.clinicService.findPetById(7);
assertThat(pet7.getName()).startsWith("Samantha");
assertThat(pet7.getOwner().getFirstName()).isEqualTo("Jean");
@Test
public void getPetTypes() {
Collection<PetType> petTypes = this.clinicService.findPetTypes();
}
PetType petType1 = EntityUtils.getById(petTypes, PetType.class, 1);
assertEquals("cat", petType1.getName());
PetType petType4 = EntityUtils.getById(petTypes, PetType.class, 4);
assertEquals("snake", petType4.getName());
}
@Test
public void shouldFindAllPetTypes() {
Collection<PetType> petTypes = this.clinicService.findPetTypes();
@Test
@Transactional
public void insertPet() {
Owner owner6 = this.clinicService.findOwnerById(6);
int found = owner6.getPets().size();
Pet pet = new Pet();
pet.setName("bowser");
Collection<PetType> types = this.clinicService.findPetTypes();
pet.setType(EntityUtils.getById(types, PetType.class, 2));
pet.setBirthDate(new DateTime());
owner6.addPet(pet);
assertEquals(found + 1, owner6.getPets().size());
// both storePet and storeOwner are necessary to cover all ORM tools
this.clinicService.savePet(pet);
this.clinicService.saveOwner(owner6);
owner6 = this.clinicService.findOwnerById(6);
assertEquals(found + 1, owner6.getPets().size());
assertNotNull("Pet Id should have been generated", pet.getId());
}
PetType petType1 = EntityUtils.getById(petTypes, PetType.class, 1);
assertThat(petType1.getName()).isEqualTo("cat");
PetType petType4 = EntityUtils.getById(petTypes, PetType.class, 4);
assertThat(petType4.getName()).isEqualTo("snake");
}
@Test
@Transactional
public void updatePet() throws Exception {
Pet pet7 = this.clinicService.findPetById(7);
String old = pet7.getName();
pet7.setName(old + "X");
this.clinicService.savePet(pet7);
pet7 = this.clinicService.findPetById(7);
assertEquals(old + "X", pet7.getName());
}
@Test
@Transactional
public void shouldInsertPetIntoDatabaseAndGenerateId() {
Owner owner6 = this.clinicService.findOwnerById(6);
int found = owner6.getPets().size();
@Test
public void findVets() {
Collection<Vet> vets = this.clinicService.findVets();
Pet pet = new Pet();
pet.setName("bowser");
Collection<PetType> types = this.clinicService.findPetTypes();
pet.setType(EntityUtils.getById(types, PetType.class, 2));
pet.setBirthDate(new LocalDate());
owner6.addPet(pet);
assertThat(owner6.getPets().size()).isEqualTo(found + 1);
Vet v1 = EntityUtils.getById(vets, Vet.class, 2);
assertEquals("Leary", v1.getLastName());
assertEquals(1, v1.getNrOfSpecialties());
assertEquals("radiology", (v1.getSpecialties().get(0)).getName());
Vet v2 = EntityUtils.getById(vets, Vet.class, 3);
assertEquals("Douglas", v2.getLastName());
assertEquals(2, v2.getNrOfSpecialties());
assertEquals("dentistry", (v2.getSpecialties().get(0)).getName());
assertEquals("surgery", (v2.getSpecialties().get(1)).getName());
}
this.clinicService.savePet(pet);
this.clinicService.saveOwner(owner6);
@Test
@Transactional
public void insertVisit() {
Pet pet7 = this.clinicService.findPetById(7);
int found = pet7.getVisits().size();
Visit visit = new Visit();
pet7.addVisit(visit);
visit.setDescription("test");
// both storeVisit and storePet are necessary to cover all ORM tools
this.clinicService.saveVisit(visit);
this.clinicService.savePet(pet7);
pet7 = this.clinicService.findPetById(7);
assertEquals(found + 1, pet7.getVisits().size());
assertNotNull("Visit Id should have been generated", visit.getId());
}
owner6 = this.clinicService.findOwnerById(6);
assertThat(owner6.getPets().size()).isEqualTo(found + 1);
// checks that id has been generated
assertThat(pet.getId()).isNotNull();
}
@Test
@Transactional
public void shouldUpdatePetName() throws Exception {
Pet pet7 = this.clinicService.findPetById(7);
String oldName = pet7.getName();
String newName = oldName + "X";
pet7.setName(newName);
this.clinicService.savePet(pet7);
pet7 = this.clinicService.findPetById(7);
assertThat(pet7.getName()).isEqualTo(newName);
}
@Test
public void shouldFindVets() {
Collection<Vet> vets = this.clinicService.findVets();
Vet vet = EntityUtils.getById(vets, Vet.class, 3);
assertThat(vet.getLastName()).isEqualTo("Douglas");
assertThat(vet.getNrOfSpecialties()).isEqualTo(2);
assertThat(vet.getSpecialties().get(0).getName()).isEqualTo("dentistry");
assertThat(vet.getSpecialties().get(1).getName()).isEqualTo("surgery");
}
@Test
@Transactional
public void shouldAddNewVisitForPet() {
Pet pet7 = this.clinicService.findPetById(7);
int found = pet7.getVisits().size();
Visit visit = new Visit();
pet7.addVisit(visit);
visit.setDescription("test");
this.clinicService.saveVisit(visit);
this.clinicService.savePet(pet7);
pet7 = this.clinicService.findPetById(7);
assertThat(pet7.getVisits().size()).isEqualTo(found + 1);
assertThat(visit.getId()).isNotNull();
}
}

View file

@ -22,10 +22,10 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* <p> Integration test using the jdbc profile.
* @see AbstractClinicServiceTests AbstractClinicServiceTests for more details. </p>
*
* @author Thomas Risberg
* @author Michael Isvy
* @see AbstractClinicServiceTests AbstractClinicServiceTests for more details. </p>
*/
@ContextConfiguration(locations = {"classpath:spring/business-config.xml"})
@RunWith(SpringJUnit4ClassRunner.class)

View file

@ -1,4 +1,3 @@
package org.springframework.samples.petclinic.service;
import org.junit.runner.RunWith;
@ -8,11 +7,11 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* <p> Integration test using the jpa profile.
* @see AbstractClinicServiceTests AbstractClinicServiceTests for more details. </p>
*
* @author Rod Johnson
* @author Sam Brannen
* @author Michael Isvy
* @see AbstractClinicServiceTests AbstractClinicServiceTests for more details. </p>
*/
@ContextConfiguration(locations = {"classpath:spring/business-config.xml"})

View file

@ -1,4 +1,3 @@
package org.springframework.samples.petclinic.service;
import org.junit.runner.RunWith;
@ -8,8 +7,9 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* <p> Integration test using the 'Spring Data' profile.
* @see AbstractClinicServiceTests AbstractClinicServiceTests for more details. </p>
*
* @author Michael Isvy
* @see AbstractClinicServiceTests AbstractClinicServiceTests for more details. </p>
*/
@ContextConfiguration(locations = {"classpath:spring/business-config.xml"})

View file

@ -0,0 +1,48 @@
package org.springframework.samples.petclinic.web;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
/**
* Test class for the UserResource REST controller.
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:spring/business-config.xml", "classpath:spring/tools-config.xml", "classpath:spring/mvc-core-config.xml"})
@WebAppConfiguration
@ActiveProfiles("spring-data-jpa")
public class VetControllerTests {
@Autowired
private VetController vetController;
private MockMvc mockMvc;
@Before
public void setup() {
this.mockMvc = MockMvcBuilders.standaloneSetup(vetController).build();
}
@Test
public void testGetExistingUser() throws Exception {
ResultActions actions = mockMvc.perform(get("/vets.json").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
actions.andExpect(content().contentType("application/json;charset=UTF-8"))
.andExpect(jsonPath("$.vetList[0].id").value(1));
}
}

View file

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- DispatcherServlet application context for PetClinic's web tier.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="classpath:spring/business-config.xml"/>
<import resource="classpath:spring/mvc-core-config.xml"/>
</beans>

View file

@ -1,70 +0,0 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.samples.petclinic.web;
import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.xpath;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
/**
* @author Arjen Poutsma
* @author Michael Isvy
*/
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("VisitsViewTests-config.xml")
@ActiveProfiles("jdbc")
public class VisitsViewTests {
@Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
@Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext).build();
}
@Test
public void getVisitsXml() throws Exception {
ResultActions actions = this.mockMvc.perform(get("/vets.xml").accept(MediaType.APPLICATION_XML));
actions.andDo(print()); // action is logged into the console
actions.andExpect(status().isOk());
actions.andExpect(content().contentType("application/xml"));
actions.andExpect(xpath("/vets/vetList[id=1]/firstName").string(containsString("James")));
}
}

View file

@ -0,0 +1,411 @@
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="2.8" jmeter="2.13 r1665067">
<hashTree>
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan" enabled="true">
<stringProp name="TestPlan.comments"></stringProp>
<boolProp name="TestPlan.functional_mode">false</boolProp>
<boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
<elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="Variables pr<70>-d<>finies" enabled="true">
<collectionProp name="Arguments.arguments">
<elementProp name="PETCLINIC_HOST" elementType="Argument">
<stringProp name="Argument.name">PETCLINIC_HOST</stringProp>
<stringProp name="Argument.value">localhost</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="PETCLINIC_PORT" elementType="Argument">
<stringProp name="Argument.name">PETCLINIC_PORT</stringProp>
<stringProp name="Argument.value">8080</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="CONTEXT_WEB" elementType="Argument">
<stringProp name="Argument.name">CONTEXT_WEB</stringProp>
<stringProp name="Argument.value"></stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
</collectionProp>
</elementProp>
<stringProp name="TestPlan.user_define_classpath"></stringProp>
</TestPlan>
<hashTree>
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="User threads" enabled="true">
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Contr<74>leur Boucle" enabled="true">
<boolProp name="LoopController.continue_forever">false</boolProp>
<stringProp name="LoopController.loops">10</stringProp>
</elementProp>
<stringProp name="ThreadGroup.num_threads">500</stringProp>
<stringProp name="ThreadGroup.ramp_time">10</stringProp>
<longProp name="ThreadGroup.start_time">1361531541000</longProp>
<longProp name="ThreadGroup.end_time">1361531541000</longProp>
<boolProp name="ThreadGroup.scheduler">false</boolProp>
<stringProp name="ThreadGroup.duration"></stringProp>
<stringProp name="ThreadGroup.delay"></stringProp>
<boolProp name="ThreadGroup.delayedStart">true</boolProp>
<stringProp name="TestPlan.comments">Original : 500 - 10 - 10</stringProp>
</ThreadGroup>
<hashTree>
<ConstantTimer guiclass="ConstantTimerGui" testclass="ConstantTimer" testname="Fixed time counter" enabled="true">
<stringProp name="ConstantTimer.delay">300</stringProp>
</ConstantTimer>
<hashTree/>
<ConfigTestElement guiclass="HttpDefaultsGui" testclass="ConfigTestElement" testname="Default HTTP parameters" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="Variables pr<70>-d<>finies" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain">${PETCLINIC_HOST}</stringProp>
<stringProp name="HTTPSampler.port">${PETCLINIC_PORT}</stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
<stringProp name="HTTPSampler.protocol"></stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path"></stringProp>
<stringProp name="HTTPSampler.concurrentPool">4</stringProp>
</ConfigTestElement>
<hashTree/>
<CookieManager guiclass="CookiePanel" testclass="CookieManager" testname="HTTP cookie manager" enabled="true">
<collectionProp name="CookieManager.cookies"/>
<boolProp name="CookieManager.clearEachIteration">true</boolProp>
</CookieManager>
<hashTree/>
<CounterConfig guiclass="CounterConfigGui" testclass="CounterConfig" testname="User Count" enabled="true">
<stringProp name="CounterConfig.start">1</stringProp>
<stringProp name="CounterConfig.end">10</stringProp>
<stringProp name="CounterConfig.incr">1</stringProp>
<stringProp name="CounterConfig.name">count</stringProp>
<stringProp name="CounterConfig.format"></stringProp>
<boolProp name="CounterConfig.per_user">false</boolProp>
</CounterConfig>
<hashTree/>
<CounterConfig guiclass="CounterConfigGui" testclass="CounterConfig" testname="Pet Count" enabled="true">
<stringProp name="CounterConfig.start">1</stringProp>
<stringProp name="CounterConfig.end">13</stringProp>
<stringProp name="CounterConfig.incr">1</stringProp>
<stringProp name="CounterConfig.name">petCount</stringProp>
<stringProp name="CounterConfig.format"></stringProp>
<boolProp name="CounterConfig.per_user">false</boolProp>
</CounterConfig>
<hashTree/>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Home page" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="Variables pr<70>-d<>finies" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain"></stringProp>
<stringProp name="HTTPSampler.port"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
<stringProp name="HTTPSampler.protocol"></stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">${CONTEXT_WEB}/</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<boolProp name="HTTPSampler.monitor">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
</HTTPSamplerProxy>
<hashTree/>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="CSS" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="Variables pr<70>-d<>finies" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain"></stringProp>
<stringProp name="HTTPSampler.port"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
<stringProp name="HTTPSampler.protocol"></stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">${CONTEXT_WEB}/resources/css/petclinic.css</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<boolProp name="HTTPSampler.monitor">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
</HTTPSamplerProxy>
<hashTree/>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="JS" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="Variables pr<70>-d<>finies" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain"></stringProp>
<stringProp name="HTTPSampler.port"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
<stringProp name="HTTPSampler.protocol"></stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">${CONTEXT_WEB}/webjars/jquery/2.0.3/jquery.js</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<boolProp name="HTTPSampler.monitor">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
</HTTPSamplerProxy>
<hashTree/>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Vets" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="Variables pr<70>-d<>finies" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain"></stringProp>
<stringProp name="HTTPSampler.port"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
<stringProp name="HTTPSampler.protocol"></stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">${CONTEXT_WEB}/vets.html</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<boolProp name="HTTPSampler.monitor">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
</HTTPSamplerProxy>
<hashTree/>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Find owner" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="Variables pr<70>-d<>finies" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain"></stringProp>
<stringProp name="HTTPSampler.port"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
<stringProp name="HTTPSampler.protocol"></stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">${CONTEXT_WEB}/owners/find.html</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<boolProp name="HTTPSampler.monitor">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
</HTTPSamplerProxy>
<hashTree/>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Find owner with lastname=&quot;&quot;" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="Variables pr<70>-d<>finies" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain"></stringProp>
<stringProp name="HTTPSampler.port"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
<stringProp name="HTTPSampler.protocol"></stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">${CONTEXT_WEB}/owners.html?lastName=</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<boolProp name="HTTPSampler.monitor">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
</HTTPSamplerProxy>
<hashTree/>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Owner" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="Variables pr<70>-d<>finies" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain"></stringProp>
<stringProp name="HTTPSampler.port"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
<stringProp name="HTTPSampler.protocol"></stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">${CONTEXT_WEB}/owners/${count}.html</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<boolProp name="HTTPSampler.monitor">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
</HTTPSamplerProxy>
<hashTree/>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Edit Owner" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="Variables pr<70>-d<>finies" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain"></stringProp>
<stringProp name="HTTPSampler.port"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
<stringProp name="HTTPSampler.protocol"></stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">${CONTEXT_WEB}/owners/${count}/edit.html</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<boolProp name="HTTPSampler.monitor">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
</HTTPSamplerProxy>
<hashTree/>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="POST Edit Owner" enabled="true">
<boolProp name="HTTPSampler.postBodyRaw">true</boolProp>
<elementProp name="HTTPsampler.Arguments" elementType="Arguments">
<collectionProp name="Arguments.arguments">
<elementProp name="" elementType="HTTPArgument">
<boolProp name="HTTPArgument.always_encode">false</boolProp>
<stringProp name="Argument.value">firstName=Test&amp;lastName=${count}&amp;address=1234+Test+St.&amp;city=TestCity&amp;telephone=612345678</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
</collectionProp>
</elementProp>
<stringProp name="HTTPSampler.domain"></stringProp>
<stringProp name="HTTPSampler.port"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
<stringProp name="HTTPSampler.protocol"></stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">${CONTEXT_WEB}/owners/${count}/edit.html</stringProp>
<stringProp name="HTTPSampler.method">POST</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<boolProp name="HTTPSampler.monitor">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
</HTTPSamplerProxy>
<hashTree/>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="New visit" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="Variables pr<70>-d<>finies" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain"></stringProp>
<stringProp name="HTTPSampler.port"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
<stringProp name="HTTPSampler.protocol"></stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">${CONTEXT_WEB}/owners/${count}/pets/${petCount}/visits/new</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<boolProp name="HTTPSampler.monitor">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
</HTTPSamplerProxy>
<hashTree/>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="POST new visit" enabled="true">
<boolProp name="HTTPSampler.postBodyRaw">true</boolProp>
<elementProp name="HTTPsampler.Arguments" elementType="Arguments">
<collectionProp name="Arguments.arguments">
<elementProp name="" elementType="HTTPArgument">
<boolProp name="HTTPArgument.always_encode">false</boolProp>
<stringProp name="Argument.value">date=2013%2F02%2F22&amp;description=visit</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
</collectionProp>
</elementProp>
<stringProp name="HTTPSampler.domain"></stringProp>
<stringProp name="HTTPSampler.port"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
<stringProp name="HTTPSampler.protocol"></stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">${CONTEXT_WEB}/owners/${count}/pets/${petCount}/visits/new</stringProp>
<stringProp name="HTTPSampler.method">POST</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<boolProp name="HTTPSampler.monitor">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
</HTTPSamplerProxy>
<hashTree/>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Owner" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="Variables pr<70>-d<>finies" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain"></stringProp>
<stringProp name="HTTPSampler.port"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
<stringProp name="HTTPSampler.protocol"></stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">${CONTEXT_WEB}/owners/${count}.html</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<boolProp name="HTTPSampler.monitor">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
</HTTPSamplerProxy>
<hashTree/>
<ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="Results" enabled="false">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<threadCounts>true</threadCounts>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
<ResultCollector guiclass="StatVisualizer" testclass="ResultCollector" testname="Aggregated report" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<threadCounts>true</threadCounts>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
</hashTree>
</hashTree>
</hashTree>
</jmeterTestPlan>