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

805
pom.xml
View file

@ -1,458 +1,413 @@
<?xml version="1.0" encoding="UTF-8"?> <?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"> <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
<modelVersion>4.0.0</modelVersion> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<groupId>org.springframework.samples</groupId> <modelVersion>4.0.0</modelVersion>
<artifactId>spring-petclinic</artifactId> <groupId>org.springframework.samples</groupId>
<version>1.0.0-SNAPSHOT</version> <artifactId>spring-petclinic</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>petclinic</name> <name>petclinic</name>
<packaging>war</packaging> <packaging>war</packaging>
<properties> <properties>
<!-- Generic properties --> <!-- Generic properties -->
<java.version>1.6</java.version> <java.version>1.7</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- Spring --> <!-- Spring -->
<spring-framework.version>4.0.1.RELEASE</spring-framework.version> <spring-io-platform.version>1.1.3.RELEASE</spring-io-platform.version>
<spring-data-jpa.version>1.4.3.RELEASE</spring-data-jpa.version> <spring-data-jdbc.version>1.1.0.RELEASE</spring-data-jdbc.version>
<!-- Java EE / Java SE dependencies --> <!-- Java EE / Java SE dependencies -->
<jsp.version>2.2</jsp.version> <tomcat.version>7.0.59</tomcat.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>
<!-- Hibernate / JPA --> <!-- Test -->
<hibernate.version>4.3.1.Final</hibernate.version> <assertj.version>2.2.0</assertj.version>
<!-- Bean validation --> <!-- Dates -->
<hibernate-validator.version>4.3.1.Final</hibernate-validator.version> <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 --> <!-- MySql -->
<tomcat-jdbc.version>7.0.42</tomcat-jdbc.version> <mysql-driver.version>5.1.36</mysql-driver.version>
<ehcache.version>2.6.8</ehcache.version>
<hsqldb.version>2.3.1</hsqldb.version>
<!-- AOP --> <!-- Web dependencies -->
<aspectj.version>1.7.4</aspectj.version> <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 --> <cobertura.version>2.7</cobertura.version>
<logback.version>1.1.0</logback.version>
<slf4j.version>1.7.5</slf4j.version>
<!-- RSS --> </properties>
<rome.version>1.0</rome.version>
<!-- Test --> <dependencyManagement>
<junit.version>4.11</junit.version> <!-- Import the maven Spring IO Platform Bill Of Materials (BOM) -->
<hamcrest.version>1.3</hamcrest.version> <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 --> <dependencies>
<jodatime-hibernate.version>1.3</jodatime-hibernate.version> <dependency>
<jodatime-jsptags.version>1.1.1</jodatime-jsptags.version> <groupId>org.jadira.usertype</groupId>
<jodatime.version>2.3</jodatime.version> <artifactId>usertype.core</artifactId>
<jadira-usertype-core.version>3.1.0.CR10</jadira-usertype-core.version> <version>${jadira-usertype-core.version}</version>
</dependency>
<dependency>
<!-- Web dependencies --> <groupId>org.apache.tomcat</groupId>
<webjars-bootstrap.version>2.3.0</webjars-bootstrap.version> <artifactId>tomcat-servlet-api</artifactId>
<webjars-jquery-ui.version>1.10.3</webjars-jquery-ui.version> <version>${tomcat.version}</version>
<webjars-jquery.version>2.0.3-1</webjars-jquery.version> <scope>provided</scope>
<dandelion.datatables.version>0.9.3</dandelion.datatables.version> </dependency>
<dependency>
<mysql.version>5.1.22</mysql.version> <groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
</properties> <scope>provided</scope>
</dependency>
<dependencies> <dependency>
<dependency> <groupId>org.apache.tomcat</groupId>
<groupId>org.jadira.usertype</groupId> <artifactId>tomcat-jasper-el</artifactId>
<artifactId>usertype.core</artifactId> <version>${tomcat.version}</version>
<version>${jadira-usertype-core.version}</version> <scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-servlet-api</artifactId>
<version>${tomcat.servlet.version}</version>
<scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<dependency> <dependency>
<groupId>org.glassfish.web</groupId> <groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl-impl</artifactId> <artifactId>javax.servlet.jsp.jstl-api</artifactId>
<version>1.2</version> </dependency>
<exclusions> <dependency>
<exclusion> <groupId>org.apache.taglibs</groupId>
<groupId>javax.servlet</groupId> <artifactId>taglibs-standard-jstlel</artifactId>
<artifactId>servlet-api</artifactId> </dependency>
</exclusion> <!-- JSon -->
</exclusions> <dependency>
</dependency> <groupId>com.jayway.jsonpath</groupId>
<dependency> <artifactId>json-path</artifactId>
<groupId>com.sun.xml.bind</groupId> <scope>test</scope>
<artifactId>jaxb-impl</artifactId> </dependency>
<version>${jaxb-impl.version}</version> <!-- SPRING, SPRING, SPRINGITY SPRING -->
<scope>provided</scope> <dependency>
</dependency> <groupId>org.springframework.boot</groupId>
<!-- SPRING, SPRING, SPRINGITY SPRING --> <artifactId>spring-boot-starter</artifactId>
<dependency> </dependency>
<groupId>org.springframework.data</groupId> <dependency>
<artifactId>spring-data-jpa</artifactId> <groupId>org.springframework.boot</groupId>
<version>${spring-data-jpa.version}</version> <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework</groupId> <groupId>org.springframework.data</groupId>
<artifactId>spring-jdbc</artifactId> <artifactId>spring-data-jdbc-core</artifactId>
<version>${spring-framework.version}</version> <version>${spring-data-jdbc.version}</version>
</dependency> <exclusions>
<dependency> <exclusion>
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId> <artifactId>*</artifactId>
<version>${spring-framework.version}</version> </exclusion>
</dependency> <!-- because Spring Data usually comes with a slightly older version of Spring -->
<dependency> </exclusions>
<groupId>org.springframework</groupId> </dependency>
<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</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 <dependency>
See here for more details on commons-dbcp versus tomcat-jdbc: <groupId>org.aspectj</groupId>
http://blog.ippon.fr/2013/03/13/improving-the-performance-of-the-spring-petclinic-sample-application-part-3-of-5/ <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> <dependency>
<groupId>org.apache.tomcat</groupId> <groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId> <artifactId>tomcat-jdbc</artifactId>
<version>${tomcat-jdbc.version}</version> <scope>runtime</scope>
<scope>runtime</scope> </dependency>
</dependency>
<!-- Logging with SLF4J & LogBack --> <!-- Logging with SLF4J & LogBack -->
<dependency> <dependency>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId> <artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version> </dependency>
<scope>compile</scope> <dependency>
</dependency> <groupId>ch.qos.logback</groupId>
<dependency> <artifactId>logback-classic</artifactId>
<groupId>ch.qos.logback</groupId> <scope>runtime</scope>
<artifactId>logback-classic</artifactId> </dependency>
<version>${logback.version}</version>
<scope>runtime</scope>
</dependency>
<!-- used for Atom --> <!-- Date and Time -->
<dependency> <dependency>
<groupId>rome</groupId> <groupId>joda-time</groupId>
<artifactId>rome</artifactId> <artifactId>joda-time</artifactId>
<version>${rome.version}</version> </dependency>
</dependency> <dependency>
<groupId>joda-time</groupId>
<!-- Date and Time --> <artifactId>joda-time-hibernate</artifactId>
<dependency> <version>${jodatime-hibernate.version}</version>
<groupId>joda-time</groupId> </dependency>
<artifactId>joda-time</artifactId> <dependency>
<version>${jodatime.version}</version> <groupId>joda-time</groupId>
</dependency> <artifactId>joda-time-jsptags</artifactId>
<dependency> <version>${jodatime-jsptags.version}</version>
<groupId>joda-time</groupId> </dependency>
<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 --> <!-- Databases - Uses HSQL by default -->
<!-- <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> --> <dependency>
<dependency> <groupId>org.hsqldb</groupId>
<groupId>org.hsqldb</groupId> <artifactId>hsqldb</artifactId>
<artifactId>hsqldb</artifactId> <scope>runtime</scope>
<version>${hsqldb.version}</version> </dependency>
<scope>runtime</scope>
</dependency>
<!-- For MySql only --> <!-- For MySql only -->
<!-- <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> --> <!--dependency>
<!-- HIBERNATE --> <groupId>mysql</groupId>
<dependency> <artifactId>mysql-connector-java</artifactId>
<groupId>org.hibernate</groupId> <version>${mysql-driver.version}</version>
<artifactId>hibernate-entitymanager</artifactId> </dependency-->
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>${hibernate-validator.version}</version>
</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>
<!-- 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>
<dependency> <!-- HIBERNATE -->
<groupId>org.aspectj</groupId> <dependency>
<artifactId>aspectjrt</artifactId> <groupId>org.hibernate</groupId>
<version>${aspectj.version}</version> <artifactId>hibernate-entitymanager</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.aspectj</groupId> <groupId>org.hibernate</groupId>
<artifactId>aspectjweaver</artifactId> <artifactId>hibernate-validator</artifactId>
<version>${aspectj.version}</version> </dependency>
<scope>runtime</scope>
</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>
<!-- Dandelion --> <!-- Test Artifacts -->
<dependency> <dependency>
<groupId>com.github.dandelion</groupId> <groupId>org.springframework</groupId>
<artifactId>datatables-jsp</artifactId> <artifactId>spring-test</artifactId>
<version>${dandelion.datatables.version}</version> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.github.dandelion</groupId> <groupId>junit</groupId>
<artifactId>datatables-export-itext</artifactId> <artifactId>junit</artifactId>
<version>${dandelion.datatables.version}</version> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.github.dandelion</groupId> <groupId>org.assertj</groupId>
<artifactId>datatables-servlet2</artifactId> <artifactId>assertj-core</artifactId>
<version>${dandelion.datatables.version}</version> <version>${assertj.version}</version>
</dependency> <scope>test</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>
</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>
<dependencyManagement> <!-- integrate maven-cobertura-plugin to project site -->
<dependencies> <plugin>
<!-- <groupId>org.codehaus.mojo</groupId>
Force the version of all the spring jars (core, beans, context, ...) <artifactId>cobertura-maven-plugin</artifactId>
pulled by spring-data-jpa:1.3.4.RELEASE to 3.2.x when spring-data pulls <version>${cobertura.version}</version>
the 3.1.x versions to prevent some misbehaviors of maven which sometimes <configuration>
pulls both 3.2.x and 3.1.x versions of spring-core, spring-beans and spring-context <formats>
--> <format>html</format>
<dependency> </formats>
<groupId>org.springframework</groupId> <check/>
<artifactId>spring-core</artifactId> </configuration>
<version>${spring-framework.version}</version> </plugin>
</dependency> </plugins>
<dependency> </reporting>
<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>
<url>demopetclinic</url>
</project> </project>

View file

@ -1,22 +1,32 @@
# Spring PetClinic Sample Application # 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 ## Understanding the Spring Petclinic application with a few diagrams
<a href="https://speakerdeck.com/michaelisvy/spring-petclinic-sample-application">See the presentation here</a> <a href="https://speakerdeck.com/michaelisvy/spring-petclinic-sample-application">See the presentation here</a>
## Running petclinic locally ## Running petclinic locally
``` ```
git clone https://github.com/SpringSource/spring-petclinic.git git clone https://github.com/spring-projects/spring-petclinic.git
mvn tomcat7:run mvn tomcat7:run
``` ```
You can then access petclinic here: http://localhost:9966/petclinic/ You can then access petclinic here: http://localhost:9966/petclinic/
## In case you find a bug/suggested improvement for Spring Petclinic ## In case you find a bug/suggested improvement for Spring Petclinic
Our issue tracker is available here: https://github.com/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 ## 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 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 2) Inside Eclipse
``` ```
@ -46,15 +56,17 @@ File -> Import -> Maven -> Existing Maven project
<table> <table>
<tr> <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>
<tr> <tr>
<td>Spring MVC- Atom integration</td> <td>Java Config branch</td>
<td> <td>
<a href="/src/main/java/org/springframework/samples/petclinic/web/VetsAtomView.java">VetsAtomView.java</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.
<a href="/src/main/resources/spring/mvc-view-config.xml">mvc-view-config.xml</a>
</td> </td>
</tr> </tr>
<tr>
<th width="300px">Inside the 'Web' layer</th><th width="300px">Files</th>
</tr>
<tr> <tr>
<td>Spring MVC - XML integration</td> <td>Spring MVC - XML integration</td>
<td><a href="/src/main/resources/spring/mvc-view-config.xml">mvc-view-config.xml</a></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>Spring MVC - ContentNegotiatingViewResolver</td>
<td><a href="/src/main/resources/spring/mvc-view-config.xml">mvc-view-config.xml</a></td> <td><a href="/src/main/resources/spring/mvc-view-config.xml">mvc-view-config.xml</a></td>
</tr> </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> <tr>
<td>JSP custom tags</td> <td>JSP custom tags</td>
<td> <td>
@ -78,7 +86,7 @@ File -> Import -> Maven -> Existing Maven project
<td> <td>
<a href="/pom.xml">webjars declaration inside pom.xml</a> <br /> <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/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> </td>
</tr> </tr>
<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/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/jsp/vets/vetList.jsp">vetList.jsp</a>
<a href="/src/main/webapp/WEB-INF/web.xml">web.xml</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> </td>
</tr> </tr>
<tr> <tr>
@ -195,5 +204,12 @@ Here is a list of them:
</table> </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; package org.springframework.samples.petclinic.model;
import java.io.Serializable;
import javax.persistence.GeneratedValue; import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType; import javax.persistence.GenerationType;
import javax.persistence.Id; import javax.persistence.Id;
@ -34,15 +32,14 @@ public class BaseEntity {
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
protected Integer id; protected Integer id;
public Integer getId() {
return id;
}
public void setId(Integer id) { public void setId(Integer id) {
this.id = id; this.id = id;
} }
public Integer getId() {
return id;
}
public boolean isNew() { public boolean isNew() {
return (this.id == null); return (this.id == null);
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,8 +1,5 @@
/** /**
*
* The classes in this package represent PetClinic's business layer. * The classes in this package represent PetClinic's business layer.
*
*/ */
package org.springframework.samples.petclinic.model; 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. * Copyright 2002-2013 the original author or authors.
* *
@ -53,7 +38,7 @@ public interface OwnerRepository {
* *
* @param lastName Value to search for * @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 * @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; Collection<Owner> findByLastName(String lastName) throws DataAccessException;
@ -62,8 +47,7 @@ public interface OwnerRepository {
* *
* @param id the id to search for * @param id the id to search for
* @return the <code>Owner</code> if found * @return the <code>Owner</code> if found
* @throws org.springframework.dao.DataRetrievalFailureException * @throws org.springframework.dao.DataRetrievalFailureException if not found
* if not found
*/ */
Owner findById(int id) throws DataAccessException; Owner findById(int id) throws DataAccessException;

View file

@ -45,8 +45,7 @@ public interface PetRepository {
* *
* @param id the id to search for * @param id the id to search for
* @return the <code>Pet</code> if found * @return the <code>Pet</code> if found
* @throws org.springframework.dao.DataRetrievalFailureException * @throws org.springframework.dao.DataRetrievalFailureException if not found
* if not found
*/ */
Pet findById(int id) throws DataAccessException; 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.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource; import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.simple.ParameterizedBeanPropertyRowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert; import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.orm.ObjectRetrievalFailureException; import org.springframework.orm.ObjectRetrievalFailureException;
import org.springframework.samples.petclinic.model.Owner; 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.PetType;
import org.springframework.samples.petclinic.model.Visit; import org.springframework.samples.petclinic.model.Visit;
import org.springframework.samples.petclinic.repository.OwnerRepository; import org.springframework.samples.petclinic.repository.OwnerRepository;
import org.springframework.samples.petclinic.repository.VisitRepository;
import org.springframework.samples.petclinic.util.EntityUtils; import org.springframework.samples.petclinic.util.EntityUtils;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
@ -52,23 +51,19 @@ import org.springframework.stereotype.Repository;
@Repository @Repository
public class JdbcOwnerRepositoryImpl implements OwnerRepository { public class JdbcOwnerRepositoryImpl implements OwnerRepository {
private VisitRepository visitRepository;
private NamedParameterJdbcTemplate namedParameterJdbcTemplate; private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
private SimpleJdbcInsert insertOwner; private SimpleJdbcInsert insertOwner;
@Autowired @Autowired
public JdbcOwnerRepositoryImpl(DataSource dataSource, NamedParameterJdbcTemplate namedParameterJdbcTemplate, public JdbcOwnerRepositoryImpl(DataSource dataSource, NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
VisitRepository visitRepository) {
this.insertOwner = new SimpleJdbcInsert(dataSource) this.insertOwner = new SimpleJdbcInsert(dataSource)
.withTableName("owners") .withTableName("owners")
.usingGeneratedKeyColumns("id"); .usingGeneratedKeyColumns("id");
this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource); this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
this.visitRepository = visitRepository;
} }
@ -79,12 +74,12 @@ public class JdbcOwnerRepositoryImpl implements OwnerRepository {
*/ */
@Override @Override
public Collection<Owner> findByLastName(String lastName) throws DataAccessException { 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 + "%"); params.put("lastName", lastName + "%");
List<Owner> owners = this.namedParameterJdbcTemplate.query( List<Owner> owners = this.namedParameterJdbcTemplate.query(
"SELECT id, first_name, last_name, address, city, telephone FROM owners WHERE last_name like :lastName", "SELECT id, first_name, last_name, address, city, telephone FROM owners WHERE last_name like :lastName",
params, params,
ParameterizedBeanPropertyRowMapper.newInstance(Owner.class) BeanPropertyRowMapper.newInstance(Owner.class)
); );
loadOwnersPetsAndVisits(owners); loadOwnersPetsAndVisits(owners);
return owners; return owners;
@ -98,12 +93,12 @@ public class JdbcOwnerRepositoryImpl implements OwnerRepository {
public Owner findById(int id) throws DataAccessException { public Owner findById(int id) throws DataAccessException {
Owner owner; Owner owner;
try { try {
Map<String, Object> params = new HashMap<String, Object>(); Map<String, Object> params = new HashMap<>();
params.put("id", id); params.put("id", id);
owner = this.namedParameterJdbcTemplate.queryForObject( owner = this.namedParameterJdbcTemplate.queryForObject(
"SELECT id, first_name, last_name, address, city, telephone FROM owners WHERE id= :id", "SELECT id, first_name, last_name, address, city, telephone FROM owners WHERE id= :id",
params, params,
ParameterizedBeanPropertyRowMapper.newInstance(Owner.class) BeanPropertyRowMapper.newInstance(Owner.class)
); );
} catch (EmptyResultDataAccessException ex) { } catch (EmptyResultDataAccessException ex) {
throw new ObjectRetrievalFailureException(Owner.class, id); throw new ObjectRetrievalFailureException(Owner.class, id);
@ -113,20 +108,17 @@ public class JdbcOwnerRepositoryImpl implements OwnerRepository {
} }
public void loadPetsAndVisits(final Owner owner) { public void loadPetsAndVisits(final Owner owner) {
Map<String, Object> params = new HashMap<String, Object>(); Map<String, Object> params = new HashMap<>();
params.put("id", owner.getId().intValue()); params.put("id", owner.getId());
final List<JdbcPet> pets = this.namedParameterJdbcTemplate.query( final List<JdbcPet> pets = this.namedParameterJdbcTemplate.query(
"SELECT id, name, birth_date, type_id, owner_id FROM pets WHERE owner_id=:id", "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, params,
new JdbcPetRowMapper() new JdbcPetVisitExtractor()
); );
Collection<PetType> petTypes = getPetTypes();
for (JdbcPet pet : pets) { for (JdbcPet pet : pets) {
pet.setType(EntityUtils.getById(petTypes, PetType.class, pet.getTypeId()));
owner.addPet(pet); 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()); owner.setId(newKey.intValue());
} else { } else {
this.namedParameterJdbcTemplate.update( this.namedParameterJdbcTemplate.update(
"UPDATE owners SET first_name=:firstName, last_name=:lastName, address=:address, " + "UPDATE owners SET first_name=:firstName, last_name=:lastName, address=:address, " +
"city=:city, telephone=:telephone WHERE id=:id", "city=:city, telephone=:telephone WHERE id=:id",
parameterSource); parameterSource);
} }
} }
public Collection<PetType> getPetTypes() throws DataAccessException { public Collection<PetType> getPetTypes() throws DataAccessException {
return this.namedParameterJdbcTemplate.query( return this.namedParameterJdbcTemplate.query(
"SELECT id, name FROM types ORDER BY name", new HashMap<String, Object>(), "SELECT id, name FROM types ORDER BY name", new HashMap<String, Object>(),
ParameterizedBeanPropertyRowMapper.newInstance(PetType.class)); BeanPropertyRowMapper.newInstance(PetType.class));
} }
/** /**

View file

@ -18,11 +18,10 @@ package org.springframework.samples.petclinic.repository.jdbc;
import org.springframework.samples.petclinic.model.Pet; 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 * Subclass of Pet that carries temporary id properties which are only relevant for a JDBC implementation of the
* ClinicService. * PetRepository.
* *
* @author Juergen Hoeller * @author Juergen Hoeller
* @see JdbcClinicImpl
*/ */
class JdbcPet extends Pet { class JdbcPet extends Pet {
@ -30,21 +29,20 @@ class JdbcPet extends Pet {
private int ownerId; private int ownerId;
public void setTypeId(int typeId) {
this.typeId = typeId;
}
public int getTypeId() { public int getTypeId() {
return this.typeId; return this.typeId;
} }
public void setOwnerId(int ownerId) { public void setTypeId(int typeId) {
this.ownerId = ownerId; this.typeId = typeId;
} }
public int getOwnerId() { public int getOwnerId() {
return this.ownerId; 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.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.simple.ParameterizedBeanPropertyRowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert; import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.orm.ObjectRetrievalFailureException; import org.springframework.orm.ObjectRetrievalFailureException;
import org.springframework.samples.petclinic.model.Owner; import org.springframework.samples.petclinic.model.Owner;
@ -64,8 +64,8 @@ public class JdbcPetRepositoryImpl implements PetRepository {
this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource); this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
this.insertPet = new SimpleJdbcInsert(dataSource) this.insertPet = new SimpleJdbcInsert(dataSource)
.withTableName("pets") .withTableName("pets")
.usingGeneratedKeyColumns("id"); .usingGeneratedKeyColumns("id");
this.ownerRepository = ownerRepository; this.ownerRepository = ownerRepository;
this.visitRepository = visitRepository; this.visitRepository = visitRepository;
@ -73,25 +73,25 @@ public class JdbcPetRepositoryImpl implements PetRepository {
@Override @Override
public List<PetType> findPetTypes() throws DataAccessException { public List<PetType> findPetTypes() throws DataAccessException {
Map<String, Object> params = new HashMap<String, Object>(); Map<String, Object> params = new HashMap<>();
return this.namedParameterJdbcTemplate.query( return this.namedParameterJdbcTemplate.query(
"SELECT id, name FROM types ORDER BY name", "SELECT id, name FROM types ORDER BY name",
params, params,
ParameterizedBeanPropertyRowMapper.newInstance(PetType.class)); BeanPropertyRowMapper.newInstance(PetType.class));
} }
@Override @Override
public Pet findById(int id) throws DataAccessException { public Pet findById(int id) throws DataAccessException {
JdbcPet pet; JdbcPet pet;
try { try {
Map<String, Object> params = new HashMap<String, Object>(); Map<String, Object> params = new HashMap<>();
params.put("id", id); params.put("id", id);
pet = this.namedParameterJdbcTemplate.queryForObject( pet = this.namedParameterJdbcTemplate.queryForObject(
"SELECT id, name, birth_date, type_id, owner_id FROM pets WHERE id=:id", "SELECT id, name, birth_date, type_id, owner_id FROM pets WHERE id=:id",
params, params,
new JdbcPetRowMapper()); new JdbcPetRowMapper());
} catch (EmptyResultDataAccessException ex) { } 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 owner = this.ownerRepository.findById(pet.getOwnerId());
owner.addPet(pet); owner.addPet(pet);
@ -108,13 +108,13 @@ public class JdbcPetRepositoryImpl implements PetRepository {
public void save(Pet pet) throws DataAccessException { public void save(Pet pet) throws DataAccessException {
if (pet.isNew()) { if (pet.isNew()) {
Number newKey = this.insertPet.executeAndReturnKey( Number newKey = this.insertPet.executeAndReturnKey(
createPetParameterSource(pet)); createPetParameterSource(pet));
pet.setId(newKey.intValue()); pet.setId(newKey.intValue());
} else { } else {
this.namedParameterJdbcTemplate.update( this.namedParameterJdbcTemplate.update(
"UPDATE pets SET name=:name, birth_date=:birth_date, type_id=:type_id, " + "UPDATE pets SET name=:name, birth_date=:birth_date, type_id=:type_id, " +
"owner_id=:owner_id WHERE id=:id", "owner_id=:owner_id WHERE id=:id",
createPetParameterSource(pet)); createPetParameterSource(pet));
} }
} }
@ -123,11 +123,11 @@ public class JdbcPetRepositoryImpl implements PetRepository {
*/ */
private MapSqlParameterSource createPetParameterSource(Pet pet) { private MapSqlParameterSource createPetParameterSource(Pet pet) {
return new MapSqlParameterSource() return new MapSqlParameterSource()
.addValue("id", pet.getId()) .addValue("id", pet.getId())
.addValue("name", pet.getName()) .addValue("name", pet.getName())
.addValue("birth_date", pet.getBirthDate().toDate()) .addValue("birth_date", pet.getBirthDate().toDate())
.addValue("type_id", pet.getType().getId()) .addValue("type_id", pet.getType().getId())
.addValue("owner_id", pet.getOwner().getId()); .addValue("owner_id", pet.getOwner().getId());
} }
} }

View file

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

View file

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

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 * The classes in this package represent the JDBC implementation
* of PetClinic's persistence layer. * of PetClinic's persistence layer.
*
*/ */
package org.springframework.samples.petclinic.repository.jdbc; package org.springframework.samples.petclinic.repository.jdbc;

View file

@ -43,7 +43,7 @@ public class JpaOwnerRepositoryImpl implements OwnerRepository {
/** /**
* Important: in the current version of this method, we load Owners with all their Pets and Visits while * Important: in the current version of this method, we load Owners with all their Pets and Visits while
* we do not need Visits at all and we only need one property from the Pet objects (the 'name' property). * we do not need Visits at all and we only need one property from the Pet objects (the 'name' property).
* There are some ways to improve it such as: * There are some ways to improve it such as:
* - creating a Ligtweight class (example here: https://community.jboss.org/wiki/LightweightClass) * - creating a Ligtweight class (example here: https://community.jboss.org/wiki/LightweightClass)
@ -70,12 +70,11 @@ public class JpaOwnerRepositoryImpl implements OwnerRepository {
@Override @Override
public void save(Owner owner) { public void save(Owner owner) {
if (owner.getId() == null) { if (owner.getId() == null) {
this.em.persist(owner); this.em.persist(owner);
} } else {
else { this.em.merge(owner);
this.em.merge(owner); }
}
} }

View file

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

View file

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

View file

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

View file

@ -30,12 +30,12 @@ import org.springframework.samples.petclinic.repository.OwnerRepository;
* @since 15.1.2013 * @since 15.1.2013
*/ */
public interface SpringDataOwnerRepository extends OwnerRepository, Repository<Owner, Integer> { public interface SpringDataOwnerRepository extends OwnerRepository, Repository<Owner, Integer> {
@Override @Override
@Query("SELECT DISTINCT owner FROM Owner owner left join fetch owner.pets WHERE owner.lastName LIKE :lastName%") @Query("SELECT DISTINCT owner FROM Owner owner left join fetch owner.pets WHERE owner.lastName LIKE :lastName%")
public Collection<Owner> findByLastName(@Param("lastName") String lastName); public Collection<Owner> findByLastName(@Param("lastName") String lastName);
@Override @Override
@Query("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:id") @Query("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:id")
public Owner findById(@Param("id") int 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 * @author Michael Isvy
*/ */
public interface ClinicService { 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; 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 * 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 * 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 Rob Harrop
* @author Juergen Hoeller * @author Juergen Hoeller
@ -42,17 +44,16 @@ public class CallMonitoringAspect {
private long accumulatedCallTime = 0; private long accumulatedCallTime = 0;
@ManagedAttribute
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
@ManagedAttribute @ManagedAttribute
public boolean isEnabled() { public boolean isEnabled() {
return enabled; return enabled;
} }
@ManagedAttribute
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
@ManagedOperation @ManagedOperation
public void reset() { public void reset() {
this.callCount = 0; this.callCount = 0;
@ -66,7 +67,10 @@ public class CallMonitoringAspect {
@ManagedAttribute @ManagedAttribute
public long getCallTime() { 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 entityClass the entity class to look up
* @param entityId the entity id to look up * @param entityId the entity id to look up
* @return the found entity * @return the found entity
* @throws ObjectRetrievalFailureException * @throws ObjectRetrievalFailureException if the entity was not found
* if the entity was not found
*/ */
public static <T extends BaseEntity> T getById(Collection<T> entities, Class<T> entityClass, int entityId) public static <T extends BaseEntity> T getById(Collection<T> entities, Class<T> entityClass, int entityId)
throws ObjectRetrievalFailureException { throws ObjectRetrievalFailureException {
for (T entity : entities) { for (T entity : entities) {
if (entity.getId().intValue() == entityId && entityClass.isInstance(entity)) { if (entity.getId() == entityId && entityClass.isInstance(entity)) {
return entity; return entity;
} }
} }

View file

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

View file

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

View file

@ -22,6 +22,7 @@ import org.springframework.samples.petclinic.model.Vets;
import org.springframework.samples.petclinic.service.ClinicService; import org.springframework.samples.petclinic.service.ClinicService;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/** /**
* @author Juergen Hoeller * @author Juergen Hoeller
@ -40,9 +41,9 @@ public class VetController {
this.clinicService = clinicService; this.clinicService = clinicService;
} }
@RequestMapping("/vets") @RequestMapping(value = {"/vets.xml", "/vets.html"})
public String showVetList(Map<String, Object> model) { public String showVetList(Map<String, Object> model) {
// Here we are returning an object of type 'Vets' rather than a collection of Vet objects // Here we are returning an object of type 'Vets' rather than a collection of Vet objects
// so it is simpler for Object-Xml mapping // so it is simpler for Object-Xml mapping
Vets vets = new Vets(); Vets vets = new Vets();
vets.getVetList().addAll(this.clinicService.findVets()); vets.getVetList().addAll(this.clinicService.findVets());
@ -50,5 +51,16 @@ public class VetController {
return "vets/vetList"; 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.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; 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 * @author Juergen Hoeller
@ -41,7 +39,6 @@ import org.springframework.web.servlet.ModelAndView;
* @author Michael Isvy * @author Michael Isvy
*/ */
@Controller @Controller
@SessionAttributes("visit")
public class VisitController { public class VisitController {
private final ClinicService clinicService; private final ClinicService clinicService;
@ -57,31 +54,45 @@ public class VisitController {
dataBinder.setDisallowedFields("id"); 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); Pet pet = this.clinicService.findPetById(petId);
Visit visit = new Visit(); Visit visit = new Visit();
pet.addVisit(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"; return "pets/createOrUpdateVisitForm";
} }
// Spring MVC calls method loadPetWithVisit(...) before processNewVisitForm is called
@RequestMapping(value = "/owners/{ownerId}/pets/{petId}/visits/new", method = RequestMethod.POST) @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()) { if (result.hasErrors()) {
return "pets/createOrUpdateVisitForm"; return "pets/createOrUpdateVisitForm";
} else { } else {
this.clinicService.saveVisit(visit); this.clinicService.saveVisit(visit);
status.setComplete();
return "redirect:/owners/{ownerId}"; return "redirect:/owners/{ownerId}";
} }
} }
@RequestMapping(value = "/owners/*/pets/{petId}/visits", method = RequestMethod.GET) @RequestMapping(value = "/owners/*/pets/{petId}/visits", method = RequestMethod.GET)
public ModelAndView showVisits(@PathVariable int petId) { public String showVisits(@PathVariable int petId, Map<String, Object> model) {
ModelAndView mav = new ModelAndView("visitList"); model.put("visits", this.clinicService.findPetById(petId).getVisits());
mav.addObject("visits", this.clinicService.findPetById(petId).getVisits()); return "visitList";
return mav;
} }
} }

View file

@ -1,8 +1,5 @@
/** /**
*
* The classes in this package represent PetClinic's web presentation layer. * The classes in this package represent PetClinic's web presentation layer.
*
*/ */
package org.springframework.samples.petclinic.web; 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" 3) Create the PetClinic database and user by executing the "db/mysql/createDB.txt"
script. 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" "HSQL Settings" section; uncomment all properties in the "MySQL Settings"
section. 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"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xml>
<configuration scan="true" scanPeriod="30 seconds"> <configuration scan="true" scanPeriod="30 seconds">
<contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator"> <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
@ -14,9 +16,9 @@
</encoder> </encoder>
</appender> </appender>
<!--<logger name="org.hibernate" level="debug"/> --> <!--<logger name="org.hibernate" level="debug"/> -->
<logger name="org.springframework.samples.petclinic" level="debug"/> <logger name="org.springframework.samples.petclinic" level="debug"/>
<root level="info"> <root level="info">
<appender-ref ref="console"/> <appender-ref ref="console"/>
</root> </root>

View file

@ -2,36 +2,36 @@
<!-- <!--
Repository and Service layers Repository and Service layers
--> -->
<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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa" 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 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/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/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"> http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- ========================= RESOURCE DEFINITIONS ========================= --> <!-- ========================= RESOURCE DEFINITIONS ========================= -->
<!-- import the dataSource definition --> <!-- import the dataSource definition -->
<import resource="datasource-config.xml"/> <import resource="datasource-config.xml"/>
<context:component-scan <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 --> <!-- Configurer that replaces ${...} placeholders with values from a properties file -->
<!-- (in this case, JDBC-related settings for the JPA EntityManager definition below) --> <!-- (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"/> <context:property-placeholder location="classpath:spring/data-access.properties" system-properties-mode="OVERRIDE"/>
<!-- enables scanning for @Transactional annotations --> <!-- enables scanning for @Transactional annotations -->
<tx:annotation-driven /> <tx:annotation-driven/>
<!-- ================== 3 Profiles to choose from =================== <!-- ================== 3 Profiles to choose from ===================
- jdbc (uses Spring" JdbcTemplate) - jdbc (uses Spring" JdbcTemplate)
- jpa - jpa
- spring-data-jpa - spring-data-jpa
=============================================================================--> =============================================================================-->
<beans profile="jpa,spring-data-jpa"> <beans profile="jpa,spring-data-jpa">
<!-- JPA EntityManagerFactory --> <!-- JPA EntityManagerFactory -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
@ -42,7 +42,7 @@
<!-- the 'database' parameter refers to the database dialect being used. <!-- the 'database' parameter refers to the database dialect being used.
By default, Hibernate will use a 'HSQL' dialect because 'jpa.database' has been set to 'HSQL' By default, Hibernate will use a 'HSQL' dialect because 'jpa.database' has been set to 'HSQL'
inside file spring/data-access.properties inside file spring/data-access.properties
--> -->
</property> </property>
<!-- gDickens: BOTH Persistence Unit and Packages to Scan are NOT compatible, persistenceUnit will win --> <!-- gDickens: BOTH Persistence Unit and Packages to Scan are NOT compatible, persistenceUnit will win -->
@ -93,4 +93,4 @@
<beans profile="spring-data-jpa"> <beans profile="spring-data-jpa">
<jpa:repositories base-package="org.springframework.samples.petclinic.repository.springdatajpa"/> <jpa:repositories base-package="org.springframework.samples.petclinic.repository.springdatajpa"/>
</beans> </beans>
</beans> </beans>

View file

@ -4,6 +4,12 @@
# various application context XML files (e.g., "applicationContext-*.xml"). # various application context XML files (e.g., "applicationContext-*.xml").
# Targeted at system administrators, to avoid touching the context XML files. # 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 # HSQL Settings
@ -12,14 +18,9 @@ jdbc.url=jdbc:hsqldb:mem:petclinic
jdbc.username=sa jdbc.username=sa
jdbc.password= 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 # Property that determines which database to use with an AbstractJpaVendorAdapter
jpa.database=HSQL jpa.database=HSQL
jpa.showSql=true
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# MySQL Settings # MySQL Settings
@ -27,15 +28,7 @@ jpa.showSql=true
#jdbc.driverClassName=com.mysql.jdbc.Driver #jdbc.driverClassName=com.mysql.jdbc.Driver
#jdbc.url=jdbc:mysql://localhost:3306/petclinic #jdbc.url=jdbc:mysql://localhost:3306/petclinic
#jdbc.username=root #jdbc.username=root
#jdbc.password= #jdbc.password=petclinic
# 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
# Property that determines which database to use with an AbstractJpaVendorAdapter # Property that determines which database to use with an AbstractJpaVendorAdapter
#jpa.database=MYSQL #jpa.database=MYSQL

View file

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

View file

@ -2,11 +2,11 @@
<!-- <!--
- DispatcherServlet application context for PetClinic's web tier. - DispatcherServlet application context for PetClinic's web tier.
--> -->
<beans xmlns="http://www.springframework.org/schema/beans" <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context" xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/mvc xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans
@ -20,7 +20,7 @@
- POJOs labeled with the @Controller and @Service annotations are auto-detected. - POJOs labeled with the @Controller and @Service annotations are auto-detected.
--> -->
<context:component-scan <context:component-scan
base-package="org.springframework.samples.petclinic.web"/> base-package="org.springframework.samples.petclinic.web"/>
<mvc:annotation-driven conversion-service="conversionService"/> <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...) --> <!-- 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: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/> <mvc:default-servlet-handler/>
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
@ -52,7 +53,7 @@
p:basename="messages/messages"/> p:basename="messages/messages"/>
<!-- <!--
- This bean resolves specific types of exceptions to corresponding logical - This bean resolves specific types of exceptions to corresponding logical
- view names for error views. - view names for error views.
--> -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">

View file

@ -2,54 +2,30 @@
<!-- <!--
- DispatcherServlet application context for PetClinic's web tier. - DispatcherServlet application context for PetClinic's web tier.
--> -->
<beans xmlns="http://www.springframework.org/schema/beans" <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:oxm="http://www.springframework.org/schema/oxm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns="http://www.springframework.org/schema/beans"
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
xsi:schemaLocation="http://www.springframework.org/schema/oxm http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/oxm/spring-oxm.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- <!--
- The ContentNegotiatingViewResolver delegates to the InternalResourceViewResolver and BeanNameViewResolver, - The ContentNegotiatingViewResolver delegates to the InternalResourceViewResolver and BeanNameViewResolver,
- and uses the requested media type (determined by the path extension) to pick a matching view. - 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, - When the media type is 'text/html', it will delegate to the InternalResourceViewResolver's JstlView,
- otherwise to the BeanNameViewResolver. - otherwise to the BeanNameViewResolver.
--> -->
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"> <mvc:view-resolvers>
<property name="contentNegotiationManager" ref="cnManager"/> <mvc:content-negotiation use-not-acceptable="true">
<mvc:default-views>
<property name="viewResolvers"> <bean class="org.springframework.web.servlet.view.JstlView">
<list> <property name="url" value=""/>
<!-- Default viewClass: JSTL view (JSP with html output) --> </bean>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> </mvc:default-views>
<!-- Example: a logical view name of 'vets' is mapped to '/WEB-INF/jsp/vets.jsp' --> </mvc:content-negotiation>
<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 --> <!-- Registering BeanNameViewResolver and InternalViewResolver -->
<bean id="cnManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean"> <mvc:bean-name/>
<property name="favorPathExtension" value="true"/> <mvc:jsp prefix="/WEB-INF/jsp/" suffix=".jsp"/>
<property name="ignoreAcceptHeader" value="true"/> </mvc:view-resolvers>
<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"/>
<!-- Renders an XML view. Used by the BeanNameViewResolver --> <!-- Renders an XML view. Used by the BeanNameViewResolver -->
<bean id="vets/vetList.xml" class="org.springframework.web.servlet.view.xml.MarshallingView"> <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. Application context definition for PetClinic on JPA.
--> -->
<beans xmlns="http://www.springframework.org/schema/beans" <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context" xmlns:context="http://www.springframework.org/schema/context"
xmlns:cache="http://www.springframework.org/schema/cache" xmlns:cache="http://www.springframework.org/schema/cache"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/aop xsi:schemaLocation="http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans
@ -46,4 +46,4 @@
</bean> </bean>
</beans> </beans>

View file

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

View file

@ -7,17 +7,15 @@
<div class="navbar" style="width: 601px;"> <div class="navbar" style="width: 601px;">
<div class="navbar-inner"> <div class="navbar-inner">
<ul class="nav"> <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> 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> 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> class="icon-th-list"></i> Veterinarians</a></li>
<li style="width: 90px;"><a href="<spring:url value="/oups.html" htmlEscape="true" />" <li style="width: 110px;"><a href="<spring:url value="/oups.html" htmlEscape="true" />"
title="trigger a RuntimeException to see how it is handled"><i title="trigger a RuntimeException to see how it is handled"><i
class="icon-warning-sign"></i> Error</a></li> 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> </ul>
</div> </div>
</div> </div>

View file

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

View file

@ -18,13 +18,13 @@ PetClinic :: a Spring Framework demonstration
<spring:url value="/webjars/jquery/2.0.3/jquery.js" var="jQuery"/> <spring:url value="/webjars/jquery/2.0.3/jquery.js" var="jQuery"/>
<script src="${jQuery}"></script> <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"/> <spring:url value="/webjars/jquery-ui/1.10.3/ui/jquery.ui.core.js" var="jQueryUiCore"/>
<script src="${jQueryUiCore}"></script> <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> <script src="${jQueryUiDatePicker}"></script>
<!-- jquery-ui.css file is not that big so we can afford to load it --> <!-- jquery-ui.css file is not that big so we can afford to load it -->
<spring:url value="/webjars/jquery-ui/1.10.3/themes/base/jquery-ui.css" var="jQueryUiCss"/> <spring:url value="/webjars/jquery-ui/1.10.3/themes/base/jquery-ui.css" var="jQueryUiCss"/>
<link href="${jQueryUiCss}" rel="stylesheet"></link> <link href="${jQueryUiCss}" rel="stylesheet"></link>

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,5 +1,6 @@
<!DOCTYPE html> <!DOCTYPE html>
<%@ page session="false" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> <%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
@ -8,7 +9,7 @@
<html lang="en"> <html lang="en">
<jsp:include page="../fragments/headTag.jsp"/> <jsp:include page="../fragments/staticFiles.jsp"/>
<body> <body>
<div class="container"> <div class="container">
@ -16,7 +17,8 @@
<h2>Veterinarians</h2> <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"> <datatables:column title="Name">
<c:out value="${vet.firstName} ${vet.lastName}"></c:out> <c:out value="${vet.firstName} ${vet.lastName}"></c:out>
</datatables:column> </datatables:column>
@ -27,14 +29,14 @@
<c:if test="${vet.nrOfSpecialties == 0}">none</c:if> <c:if test="${vet.nrOfSpecialties == 0}">none</c:if>
</datatables:column> </datatables:column>
</datatables:table> </datatables:table>
<table class="table-buttons"> <table class="table-buttons">
<tr> <tr>
<td> <td>
<a href="<spring:url value="/vets.xml" htmlEscape="true" />">View as XML</a> <a href="<spring:url value="/vets.xml" htmlEscape="true" />">View as XML</a>
</td> </td>
<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> </td>
</tr> </tr>
</table> </table>

View file

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

View file

@ -2,30 +2,32 @@
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="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" http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="2.5"> version="3.0" metadata-complete="true">
<display-name>Spring PetClinic</display-name> <display-name>Spring PetClinic</display-name>
<description>Spring PetClinic sample application</description> <description>Spring PetClinic sample application</description>
<!-- When using Spring jpa, use the following: -->
<context-param> <context-param>
<param-name>spring.profiles.active</param-name> <param-name>spring.profiles.active</param-name>
<param-value>jpa</param-value> <param-value>jpa</param-value>
</context-param> </context-param>
<!-- When using Spring JDBC, use the following: --> <!-- When using Spring JDBC, use the following: -->
<!-- <context-param> <!-- <context-param>
<param-name>spring.profiles.active</param-name> <param-name>spring.profiles.active</param-name>
<param-value>jdbc</param-value> <param-value>jdbc</param-value>
</context-param> --> </context-param> -->
<!-- When using Spring Data JPA, uncomment the following: --> <!-- 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> <context-param>
<param-value>spring-data-jpa</param-value> <param-name>spring.profiles.active</param-name>
</context-param> <param-value>spring-data-jpa</param-value>
--> </context-param>
-->
<!-- <!--
- Location of the XML file that defines the root application context. - Location of the XML file that defines the root application context.
@ -58,65 +60,59 @@ http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
<url-pattern>/</url-pattern> <url-pattern>/</url-pattern>
</servlet-mapping> </servlet-mapping>
<!-- Dandelion-Datatables servlet definition --> <!-- Dandelion servlet definition and mapping -->
<servlet> <servlet>
<servlet-name>datatablesController</servlet-name> <servlet-name>dandelionServlet</servlet-name>
<servlet-class>com.github.dandelion.datatables.extras.servlet2.servlet.DatatablesServlet</servlet-class> <servlet-class>com.github.dandelion.core.web.DandelionServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet> </servlet>
<!-- Dandelion-Datatables servlet mapping -->
<servlet-mapping> <servlet-mapping>
<servlet-name>datatablesController</servlet-name> <servlet-name>dandelionServlet</servlet-name>
<url-pattern>/datatablesController/*</url-pattern> <url-pattern>/dandelion-assets/*</url-pattern>
</servlet-mapping> </servlet-mapping>
<!-- used so we can use forms of method type 'PUT' and 'DELETE' (such as in the Pet form) <!-- used to provide the ability to enter Chinese characters inside the Owner Form -->
see here: http://static.springsource.org/spring/docs/current/spring-framework-reference/html/view.html#rest-method-conversion
-->
<filter> <filter>
<filter-name>httpMethodFilter</filter-name> <filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> <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>
<filter-mapping> <filter-mapping>
<filter-name>httpMethodFilter</filter-name> <filter-name>encodingFilter</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>
<!-- Dandelion-Datatables filter mapping -->
<filter-mapping>
<filter-name>datatablesFilter</filter-name>
<url-pattern>/*</url-pattern> <url-pattern>/*</url-pattern>
</filter-mapping> </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>
<!-- No need for welcome-file declaration here. <!-- No need for welcome-file declaration here.
See inside spring/mvc-core-config.xml : See inside spring/mvc-core-config.xml :
<mvc:view-controller path="/" view-name="welcome" /> <mvc:view-controller path="/" view-name="welcome" />
--> -->
</web-app> </web-app>

View file

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

View file

@ -15,14 +15,12 @@
*/ */
package org.springframework.samples.petclinic.service; package org.springframework.samples.petclinic.service;
import static org.junit.Assert.assertEquals; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.Collection; import java.util.Collection;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.junit.Assert; import org.joda.time.LocalDate;
import org.junit.Test; import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.samples.petclinic.model.Owner; 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 * 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 * 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 * 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, * 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 * 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 * 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; protected ClinicService clinicService;
@Test @Test
@Transactional public void shouldFindOwnersByLastName() {
public void findOwners() {
Collection<Owner> owners = this.clinicService.findOwnerByLastName("Davis"); Collection<Owner> owners = this.clinicService.findOwnerByLastName("Davis");
assertEquals(2, owners.size()); assertThat(owners.size()).isEqualTo(2);
owners = this.clinicService.findOwnerByLastName("Daviss"); owners = this.clinicService.findOwnerByLastName("Daviss");
assertEquals(0, owners.size()); assertThat(owners.isEmpty());
} }
@Test @Test
public void findSingleOwner() { public void shouldFindSingleOwnerWithPet() {
Owner owner1 = this.clinicService.findOwnerById(1); Owner owner = this.clinicService.findOwnerById(1);
assertTrue(owner1.getLastName().startsWith("Franklin")); assertThat(owner.getLastName()).startsWith("Franklin");
Owner owner10 = this.clinicService.findOwnerById(10); assertThat(owner.getPets().size()).isEqualTo(1);
assertEquals("Carlos", owner10.getFirstName()); assertThat(owner.getPets().get(0).getType()).isNotNull();
assertThat(owner.getPets().get(0).getType().getName()).isEqualTo("cat");
assertEquals(owner1.getPets().size(), 1);
} }
@Test @Test
@Transactional @Transactional
public void insertOwner() { public void shouldInsertOwner() {
Collection<Owner> owners = this.clinicService.findOwnerByLastName("Schultz"); Collection<Owner> owners = this.clinicService.findOwnerByLastName("Schultz");
int found = owners.size(); int found = owners.size();
Owner owner = new Owner(); Owner owner = new Owner();
owner.setFirstName("Sam"); owner.setFirstName("Sam");
owner.setLastName("Schultz"); owner.setLastName("Schultz");
@ -89,106 +87,108 @@ public abstract class AbstractClinicServiceTests {
owner.setCity("Wollongong"); owner.setCity("Wollongong");
owner.setTelephone("4444444444"); owner.setTelephone("4444444444");
this.clinicService.saveOwner(owner); 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"); 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 @Test
@Transactional @Transactional
public void updateOwner() throws Exception { public void shouldUpdateOwner() {
Owner o1 = this.clinicService.findOwnerById(1); Owner owner = this.clinicService.findOwnerById(1);
String old = o1.getLastName(); String oldLastName = owner.getLastName();
o1.setLastName(old + "X"); String newLastName = oldLastName + "X";
this.clinicService.saveOwner(o1);
o1 = this.clinicService.findOwnerById(1); owner.setLastName(newLastName);
assertEquals(old + "X", o1.getLastName()); this.clinicService.saveOwner(owner);
// retrieving new name from database
owner = this.clinicService.findOwnerById(1);
assertThat(owner.getLastName()).isEqualTo(newLastName);
} }
@Test @Test
public void findPet() { public void shouldFindPetWithCorrectId() {
Collection<PetType> types = this.clinicService.findPetTypes(); Pet pet7 = this.clinicService.findPetById(7);
Pet pet7 = this.clinicService.findPetById(7); assertThat(pet7.getName()).startsWith("Samantha");
assertTrue(pet7.getName().startsWith("Samantha")); assertThat(pet7.getOwner().getFirstName()).isEqualTo("Jean");
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 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 @Test
@Transactional public void shouldFindAllPetTypes() {
public void insertPet() { Collection<PetType> petTypes = this.clinicService.findPetTypes();
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());
}
@Test PetType petType1 = EntityUtils.getById(petTypes, PetType.class, 1);
@Transactional assertThat(petType1.getName()).isEqualTo("cat");
public void updatePet() throws Exception { PetType petType4 = EntityUtils.getById(petTypes, PetType.class, 4);
Pet pet7 = this.clinicService.findPetById(7); assertThat(petType4.getName()).isEqualTo("snake");
String old = pet7.getName(); }
pet7.setName(old + "X");
this.clinicService.savePet(pet7);
pet7 = this.clinicService.findPetById(7);
assertEquals(old + "X", pet7.getName());
}
@Test @Test
public void findVets() { @Transactional
Collection<Vet> vets = this.clinicService.findVets(); public void shouldInsertPetIntoDatabaseAndGenerateId() {
Owner owner6 = this.clinicService.findOwnerById(6);
Vet v1 = EntityUtils.getById(vets, Vet.class, 2); int found = owner6.getPets().size();
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());
}
@Test Pet pet = new Pet();
@Transactional pet.setName("bowser");
public void insertVisit() { Collection<PetType> types = this.clinicService.findPetTypes();
Pet pet7 = this.clinicService.findPetById(7); pet.setType(EntityUtils.getById(types, PetType.class, 2));
int found = pet7.getVisits().size(); pet.setBirthDate(new LocalDate());
Visit visit = new Visit(); owner6.addPet(pet);
pet7.addVisit(visit); assertThat(owner6.getPets().size()).isEqualTo(found + 1);
visit.setDescription("test");
// both storeVisit and storePet are necessary to cover all ORM tools this.clinicService.savePet(pet);
this.clinicService.saveVisit(visit); this.clinicService.saveOwner(owner6);
this.clinicService.savePet(pet7);
pet7 = this.clinicService.findPetById(7); owner6 = this.clinicService.findOwnerById(6);
assertEquals(found + 1, pet7.getVisits().size()); assertThat(owner6.getPets().size()).isEqualTo(found + 1);
assertNotNull("Visit Id should have been generated", visit.getId()); // 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

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

View file

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

View file

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

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>