mirror of
https://github.com/spring-projects/spring-petclinic.git
synced 2025-04-24 19:32:48 +00:00
SPR-6447
SPR-6448 + commit the gross of the files + added maven pom
This commit is contained in:
parent
9dd07f05f3
commit
521d01db95
117 changed files with 6945 additions and 10 deletions
85
db/build.xml
Normal file
85
db/build.xml
Normal file
|
@ -0,0 +1,85 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<project name="setupDB" basedir="." default="all">
|
||||
|
||||
<target name="dropHSQLTables" if="useHSQL">
|
||||
<echo message="Drop tables using: ${db.driver} ${db.url}" />
|
||||
<sql driver="${db.driver}" url="${db.url}" userid="${db.user}" password="${db.pw}" onerror="continue">
|
||||
<classpath>
|
||||
<fileset dir="${spring.root}/lib">
|
||||
<include name="hsqldb/hsqldb.jar" />
|
||||
</fileset>
|
||||
</classpath>
|
||||
<transaction src="${db.dir}/dropTables.txt" />
|
||||
</sql>
|
||||
</target>
|
||||
|
||||
<target name="createHSQLTables" if="useHSQL">
|
||||
<echo message="Create tables using: ${db.driver} ${db.url}" />
|
||||
<sql driver="${db.driver}" url="${db.url}" userid="${db.user}" password="${db.pw}" onerror="continue">
|
||||
<classpath>
|
||||
<fileset dir="${spring.root}/lib">
|
||||
<include name="hsqldb/hsqldb.jar" />
|
||||
</fileset>
|
||||
</classpath>
|
||||
<transaction src="${db.dir}/hsqldb/initDB.txt" />
|
||||
</sql>
|
||||
</target>
|
||||
|
||||
<target name="dropMYSQLTables" if="useMYSQL">
|
||||
<echo message="Dropping tables using: ${db.driver} ${db.url}" />
|
||||
<sql driver="${db.driver}" url="${db.url}" userid="${db.user}" password="${db.pw}" onerror="continue">
|
||||
<classpath>
|
||||
<fileset dir="${db.dir}/mysql">
|
||||
<include name="mysql*.jar" />
|
||||
</fileset>
|
||||
</classpath>
|
||||
<transaction src="${db.dir}/dropTables.txt" />
|
||||
</sql>
|
||||
</target>
|
||||
|
||||
<target name="createMYSQLTables" if="useMYSQL">
|
||||
<echo message="Creating tables using: ${db.driver} ${db.url}" />
|
||||
<sql driver="${db.driver}" url="${db.url}" userid="${db.user}" password="${db.pw}" onerror="continue">
|
||||
<classpath>
|
||||
<fileset dir="${db.dir}/mysql">
|
||||
<include name="mysql*.jar" />
|
||||
</fileset>
|
||||
</classpath>
|
||||
<transaction src="${db.dir}/mysql/initDB.txt" />
|
||||
</sql>
|
||||
</target>
|
||||
|
||||
<target name="emptyTables">
|
||||
<echo message="Emptying tables using: ${db.driver} ${db.url}" />
|
||||
<sql driver="${db.driver}" url="${db.url}" userid="${db.user}" password="${db.pw}">
|
||||
<classpath>
|
||||
<fileset dir="${spring.root}/lib">
|
||||
<include name="hsqldb/hsqldb.jar" />
|
||||
</fileset>
|
||||
<fileset dir="${db.dir}/mysql">
|
||||
<include name="mysql*.jar" />
|
||||
</fileset>
|
||||
</classpath>
|
||||
<transaction src="${db.dir}/emptyDB.txt" />
|
||||
</sql>
|
||||
</target>
|
||||
|
||||
<target name="populateTables">
|
||||
<echo message="Populating tables using: ${db.driver} ${db.url}" />
|
||||
<sql driver="${db.driver}" url="${db.url}" userid="${db.user}" password="${db.pw}">
|
||||
<classpath>
|
||||
<fileset dir="${spring.root}/lib">
|
||||
<include name="hsqldb/hsqldb.jar" />
|
||||
</fileset>
|
||||
<fileset dir="${db.dir}/mysql">
|
||||
<include name="mysql*.jar" />
|
||||
</fileset>
|
||||
</classpath>
|
||||
<transaction src="${db.dir}/populateDB.txt" />
|
||||
</sql>
|
||||
</target>
|
||||
|
||||
<target name="all" depends="dropHSQLTables,createHSQLTables,dropMYSQLTables,createMYSQLTables,emptyTables,populateTables" />
|
||||
|
||||
</project>
|
7
db/dropTables.txt
Normal file
7
db/dropTables.txt
Normal file
|
@ -0,0 +1,7 @@
|
|||
DROP TABLE visits;
|
||||
DROP TABLE pets;
|
||||
DROP TABLE owners;
|
||||
DROP TABLE types;
|
||||
DROP TABLE vet_specialties;
|
||||
DROP TABLE specialties;
|
||||
DROP TABLE vets;
|
7
db/emptyDB.txt
Normal file
7
db/emptyDB.txt
Normal file
|
@ -0,0 +1,7 @@
|
|||
DELETE FROM vets;
|
||||
DELETE FROM specialties;
|
||||
DELETE FROM vet_specialties;
|
||||
DELETE FROM types;
|
||||
DELETE FROM owners;
|
||||
DELETE FROM pets;
|
||||
DELETE FROM visits;
|
3
db/mysql/createDB.txt
Normal file
3
db/mysql/createDB.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
CREATE DATABASE petclinic;
|
||||
|
||||
GRANT ALL PRIVILEGES ON petclinic.* TO pc@localhost IDENTIFIED BY 'pc';
|
1
db/mysql/dropDB.txt
Normal file
1
db/mysql/dropDB.txt
Normal file
|
@ -0,0 +1 @@
|
|||
DROP DATABASE petclinic;
|
58
db/mysql/initDB.txt
Normal file
58
db/mysql/initDB.txt
Normal file
|
@ -0,0 +1,58 @@
|
|||
USE petclinic;
|
||||
|
||||
CREATE TABLE vets (
|
||||
id INT(4) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
first_name VARCHAR(30),
|
||||
last_name VARCHAR(30),
|
||||
INDEX(last_name)
|
||||
) engine=InnoDB;
|
||||
|
||||
CREATE TABLE specialties (
|
||||
id INT(4) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(80),
|
||||
INDEX(name)
|
||||
) engine=InnoDB;
|
||||
|
||||
CREATE TABLE vet_specialties (
|
||||
vet_id INT(4) UNSIGNED NOT NULL,
|
||||
specialty_id INT(4) UNSIGNED NOT NULL
|
||||
) engine=InnoDB;
|
||||
ALTER TABLE vet_specialties ADD CONSTRAINT fk_vet_specialties_vets FOREIGN KEY (vet_id) REFERENCES vets(id);
|
||||
ALTER TABLE vet_specialties ADD CONSTRAINT fk_vet_specialties_specialties FOREIGN KEY (specialty_id) REFERENCES specialties(id);
|
||||
|
||||
CREATE TABLE types (
|
||||
id INT(4) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(80),
|
||||
INDEX(name)
|
||||
) engine=InnoDB;
|
||||
|
||||
CREATE TABLE owners (
|
||||
id INT(4) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
first_name VARCHAR(30),
|
||||
last_name VARCHAR(30),
|
||||
address VARCHAR(255),
|
||||
city VARCHAR(80),
|
||||
telephone VARCHAR(20),
|
||||
INDEX(last_name)
|
||||
) engine=InnoDB;
|
||||
|
||||
CREATE TABLE pets (
|
||||
id INT(4) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(30),
|
||||
birth_date DATE,
|
||||
type_id INT(4) UNSIGNED NOT NULL,
|
||||
owner_id INT(4) UNSIGNED NOT NULL,
|
||||
INDEX(name)
|
||||
) engine=InnoDB;
|
||||
ALTER TABLE pets ADD CONSTRAINT fk_pets_owners FOREIGN KEY (owner_id) REFERENCES owners(id);
|
||||
ALTER TABLE pets ADD CONSTRAINT fk_pets_types FOREIGN KEY (type_id) REFERENCES types(id);
|
||||
CREATE INDEX pets_name ON pets(name);
|
||||
|
||||
CREATE TABLE visits (
|
||||
id INT(4) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
pet_id INT(4) UNSIGNED NOT NULL,
|
||||
visit_date DATE,
|
||||
description VARCHAR(255),
|
||||
INDEX(pet_id)
|
||||
) engine=InnoDB;
|
||||
ALTER TABLE visits ADD CONSTRAINT fk_visits_pets FOREIGN KEY (pet_id) REFERENCES pets(id);
|
22
db/mysql/petclinic_db_setup_mysql.txt
Normal file
22
db/mysql/petclinic_db_setup_mysql.txt
Normal file
|
@ -0,0 +1,22 @@
|
|||
================================================================================
|
||||
=== Spring PetClinic sample application - MySQL Configuration ===
|
||||
================================================================================
|
||||
|
||||
@author Sam Brannen
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
1) Download and install the MySQL database (e.g., MySQL Community Server 5.1.x),
|
||||
which can be found here: http://dev.mysql.com/downloads/
|
||||
|
||||
2) Download Connector/J, the MySQL JDBC driver (e.g., Connector/J 5.1.x), which
|
||||
can be found here: http://dev.mysql.com/downloads/connector/j/
|
||||
Copy the Connector/J JAR file (e.g., mysql-connector-java-5.1.5-bin.jar) into
|
||||
the db/mysql directory.
|
||||
|
||||
3) Create the PetClinic database and user by executing the "db/mysql/createDB.txt"
|
||||
script.
|
||||
|
||||
4) Open "src/main/resources/jdbc.properties"; comment out all properties in the
|
||||
"HSQL Settings" section; uncomment all properties in the "MySQL Settings"
|
||||
section.
|
64
db/mysql/petclinic_tomcat_mysql.xml
Normal file
64
db/mysql/petclinic_tomcat_mysql.xml
Normal file
|
@ -0,0 +1,64 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Context path="/petclinic" docBase="petclinic" debug="4" reloadable="true">
|
||||
<Logger className="org.apache.catalina.logger.FileLogger" prefix="localhost_petclinic_log." suffix=".txt" timestamp="true"/>
|
||||
|
||||
<!-- Define a database connection pool for MYSQL -->
|
||||
<Resource name="jdbc/petclinicMYSQL" auth="Container" type="javax.sql.DataSource"/>
|
||||
<ResourceParams name="jdbc/petclinicMYSQL">
|
||||
<parameter>
|
||||
<name>factory</name>
|
||||
<value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
|
||||
</parameter>
|
||||
|
||||
<parameter>
|
||||
<name>driverClassName</name>
|
||||
<value>org.gjt.mm.mysql.Driver</value>
|
||||
</parameter>
|
||||
<!--
|
||||
The JDBC connection url for connecting to your MySQL dB.
|
||||
The autoReconnect=true argument to the url makes sure that the
|
||||
mm.mysql JDBC Driver will automatically reconnect if mysqld closed the
|
||||
connection. mysqld by default closes idle connections after 8 hours.
|
||||
-->
|
||||
<parameter>
|
||||
<name>url</name>
|
||||
<value>jdbc:mysql://localhost:3306/petclinic?autoReconnect=true</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<name>username</name>
|
||||
<value>pc</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<name>password</name>
|
||||
<value>pc</value>
|
||||
</parameter>
|
||||
|
||||
<parameter>
|
||||
<name>maxActive</name>
|
||||
<value>50</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<name>maxIdle</name>
|
||||
<value>10</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<name>maxWait</name>
|
||||
<value>10000</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<name>removeAbandoned</name>
|
||||
<value>true</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<name>removeAbandonedTimeout</name>
|
||||
<value>60</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<name>logAbandoned</name>
|
||||
<value>true</value>
|
||||
</parameter>
|
||||
</ResourceParams>
|
||||
|
||||
|
||||
</Context>
|
112
db/petclinic_tomcat_all.xml
Normal file
112
db/petclinic_tomcat_all.xml
Normal file
|
@ -0,0 +1,112 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Context path="/petclinic" docBase="petclinic" debug="4" reloadable="true">
|
||||
<Logger className="org.apache.catalina.logger.FileLogger" prefix="localhost_petclinic_log." suffix=".txt" timestamp="true"/>
|
||||
|
||||
<!-- Define a database connection pool for HSQL -->
|
||||
<!-- NOTE: make sure that a copy of hsqldb.jar is in the TOMCAT common/lib directory -->
|
||||
<Resource name="jdbc/petclinicHSQL" auth="Container" type="javax.sql.DataSource"/>
|
||||
<ResourceParams name="jdbc/petclinicHSQL">
|
||||
<parameter>
|
||||
<name>factory</name>
|
||||
<value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
|
||||
</parameter>
|
||||
|
||||
<parameter>
|
||||
<name>driverClassName</name>
|
||||
<value>org.hsqldb.jdbcDriver</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<name>url</name>
|
||||
<value>jdbc:hsqldb:hsql://localhost:9001</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<name>username</name>
|
||||
<value>sa</value>
|
||||
</parameter>
|
||||
|
||||
<parameter>
|
||||
<name>maxActive</name>
|
||||
<value>50</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<name>maxIdle</name>
|
||||
<value>10</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<name>maxWait</name>
|
||||
<value>10000</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<name>removeAbandoned</name>
|
||||
<value>true</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<name>removeAbandonedTimeout</name>
|
||||
<value>60</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<name>logAbandoned</name>
|
||||
<value>true</value>
|
||||
</parameter>
|
||||
</ResourceParams>
|
||||
|
||||
<!-- Define a database connection pool for MYSQL -->
|
||||
<Resource name="jdbc/petclinicMYSQL" auth="Container" type="javax.sql.DataSource"/>
|
||||
<ResourceParams name="jdbc/petclinicMYSQL">
|
||||
<parameter>
|
||||
<name>factory</name>
|
||||
<value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
|
||||
</parameter>
|
||||
|
||||
<parameter>
|
||||
<name>driverClassName</name>
|
||||
<value>org.gjt.mm.mysql.Driver</value>
|
||||
</parameter>
|
||||
<!--
|
||||
The JDBC connection url for connecting to your MySQL dB.
|
||||
The autoReconnect=true argument to the url makes sure that the
|
||||
mm.mysql JDBC Driver will automatically reconnect if mysqld closed the
|
||||
connection. mysqld by default closes idle connections after 8 hours.
|
||||
-->
|
||||
<parameter>
|
||||
<name>url</name>
|
||||
<value>jdbc:mysql://localhost:3306/petclinic?autoReconnect=true</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<name>username</name>
|
||||
<value>pc</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<name>password</name>
|
||||
<value>pc</value>
|
||||
</parameter>
|
||||
|
||||
<parameter>
|
||||
<name>maxActive</name>
|
||||
<value>50</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<name>maxIdle</name>
|
||||
<value>10</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<name>maxWait</name>
|
||||
<value>10000</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<name>removeAbandoned</name>
|
||||
<value>true</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<name>removeAbandonedTimeout</name>
|
||||
<value>60</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<name>logAbandoned</name>
|
||||
<value>true</value>
|
||||
</parameter>
|
||||
</ResourceParams>
|
||||
|
||||
|
||||
</Context>
|
53
db/populateDB.txt
Normal file
53
db/populateDB.txt
Normal file
|
@ -0,0 +1,53 @@
|
|||
INSERT INTO vets VALUES (1, 'James', 'Carter');
|
||||
INSERT INTO vets VALUES (2, 'Helen', 'Leary');
|
||||
INSERT INTO vets VALUES (3, 'Linda', 'Douglas');
|
||||
INSERT INTO vets VALUES (4, 'Rafael', 'Ortega');
|
||||
INSERT INTO vets VALUES (5, 'Henry', 'Stevens');
|
||||
INSERT INTO vets VALUES (6, 'Sharon', 'Jenkins');
|
||||
|
||||
INSERT INTO specialties VALUES (1, 'radiology');
|
||||
INSERT INTO specialties VALUES (2, 'surgery');
|
||||
INSERT INTO specialties VALUES (3, 'dentistry');
|
||||
|
||||
INSERT INTO vet_specialties VALUES (2, 1);
|
||||
INSERT INTO vet_specialties VALUES (3, 2);
|
||||
INSERT INTO vet_specialties VALUES (3, 3);
|
||||
INSERT INTO vet_specialties VALUES (4, 2);
|
||||
INSERT INTO vet_specialties VALUES (5, 1);
|
||||
|
||||
INSERT INTO types VALUES (1, 'cat');
|
||||
INSERT INTO types VALUES (2, 'dog');
|
||||
INSERT INTO types VALUES (3, 'lizard');
|
||||
INSERT INTO types VALUES (4, 'snake');
|
||||
INSERT INTO types VALUES (5, 'bird');
|
||||
INSERT INTO types VALUES (6, 'hamster');
|
||||
|
||||
INSERT INTO owners VALUES (1, 'George', 'Franklin', '110 W. Liberty St.', 'Madison', '6085551023');
|
||||
INSERT INTO owners VALUES (2, 'Betty', 'Davis', '638 Cardinal Ave.', 'Sun Prairie', '6085551749');
|
||||
INSERT INTO owners VALUES (3, 'Eduardo', 'Rodriquez', '2693 Commerce St.', 'McFarland', '6085558763');
|
||||
INSERT INTO owners VALUES (4, 'Harold', 'Davis', '563 Friendly St.', 'Windsor', '6085553198');
|
||||
INSERT INTO owners VALUES (5, 'Peter', 'McTavish', '2387 S. Fair Way', 'Madison', '6085552765');
|
||||
INSERT INTO owners VALUES (6, 'Jean', 'Coleman', '105 N. Lake St.', 'Monona', '6085552654');
|
||||
INSERT INTO owners VALUES (7, 'Jeff', 'Black', '1450 Oak Blvd.', 'Monona', '6085555387');
|
||||
INSERT INTO owners VALUES (8, 'Maria', 'Escobito', '345 Maple St.', 'Madison', '6085557683');
|
||||
INSERT INTO owners VALUES (9, 'David', 'Schroeder', '2749 Blackhawk Trail', 'Madison', '6085559435');
|
||||
INSERT INTO owners VALUES (10, 'Carlos', 'Estaban', '2335 Independence La.', 'Waunakee', '6085555487');
|
||||
|
||||
INSERT INTO pets VALUES (1, 'Leo', '2000-09-07', 1, 1);
|
||||
INSERT INTO pets VALUES (2, 'Basil', '2002-08-06', 6, 2);
|
||||
INSERT INTO pets VALUES (3, 'Rosy', '2001-04-17', 2, 3);
|
||||
INSERT INTO pets VALUES (4, 'Jewel', '2000-03-07', 2, 3);
|
||||
INSERT INTO pets VALUES (5, 'Iggy', '2000-11-30', 3, 4);
|
||||
INSERT INTO pets VALUES (6, 'George', '2000-01-20', 4, 5);
|
||||
INSERT INTO pets VALUES (7, 'Samantha', '1995-09-04', 1, 6);
|
||||
INSERT INTO pets VALUES (8, 'Max', '1995-09-04', 1, 6);
|
||||
INSERT INTO pets VALUES (9, 'Lucky', '1999-08-06', 5, 7);
|
||||
INSERT INTO pets VALUES (10, 'Mulligan', '1997-02-24', 2, 8);
|
||||
INSERT INTO pets VALUES (11, 'Freddy', '2000-03-09', 5, 9);
|
||||
INSERT INTO pets VALUES (12, 'Lucky', '2000-06-24', 2, 10);
|
||||
INSERT INTO pets VALUES (13, 'Sly', '2002-06-08', 1, 10);
|
||||
|
||||
INSERT INTO visits VALUES (1, 7, '1996-03-04', 'rabies shot');
|
||||
INSERT INTO visits VALUES (2, 8, '1996-03-04', 'rabies shot');
|
||||
INSERT INTO visits VALUES (3, 8, '1996-06-04', 'neutered');
|
||||
INSERT INTO visits VALUES (4, 7, '1996-09-04', 'spayed');
|
233
pom.xml
Normal file
233
pom.xml
Normal file
|
@ -0,0 +1,233 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.samples</groupId>
|
||||
<artifactId>org.springframework.samples.petclinic</artifactId>
|
||||
<name>petclinic-classic</name>
|
||||
<packaging>war</packaging>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<properties>
|
||||
<spring.version>3.0.0.RC2</spring.version>
|
||||
<slf4j.version>1.5.6</slf4j.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.oracle.toplink.essentials</groupId>
|
||||
<artifactId>com.springsource.oracle.toplink.essentials</artifactId>
|
||||
<version>2.0.0.b41-beta2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.syndication</groupId>
|
||||
<artifactId>com.springsource.com.sun.syndication</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.persistence</groupId>
|
||||
<artifactId>com.springsource.javax.persistence</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>com.springsource.javax.servlet</artifactId>
|
||||
<version>2.5.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>com.springsource.javax.servlet.jsp</artifactId>
|
||||
<version>2.1.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>com.springsource.javax.servlet.jsp.jstl</artifactId>
|
||||
<version>1.2.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
<artifactId>com.springsource.javax.xml.bind</artifactId>
|
||||
<version>2.1.7</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>com.springsource.org.apache.commons.dbcp</artifactId>
|
||||
<version>1.2.2.osgi</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.log4j</groupId>
|
||||
<artifactId>com.springsource.org.apache.log4j</artifactId>
|
||||
<version>1.2.15</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.openjpa</groupId>
|
||||
<artifactId>com.springsource.org.apache.openjpa</artifactId>
|
||||
<version>1.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.taglibs</groupId>
|
||||
<artifactId>com.springsource.org.apache.taglibs.standard</artifactId>
|
||||
<version>1.1.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>com.springsource.org.aspectj.weaver</artifactId>
|
||||
<version>1.6.3.RELEASE</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>com.springsource.org.hibernate</artifactId>
|
||||
<version>3.3.1.GA</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>com.springsource.org.hibernate.ejb</artifactId>
|
||||
<version>3.4.0.GA</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hsqldb</groupId>
|
||||
<artifactId>com.springsource.org.hsqldb</artifactId>
|
||||
<version>1.8.0.9</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jdom</groupId>
|
||||
<artifactId>com.springsource.org.jdom</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>org.springframework.asm</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>org.springframework.orm</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>org.springframework.oxm</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>org.springframework.web.servlet</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
</dependency>
|
||||
<!-- Test dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.junit</groupId>
|
||||
<artifactId>com.springsource.org.junit</artifactId>
|
||||
<version>4.5.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>org.springframework.test</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.transaction</groupId>
|
||||
<artifactId>com.springsource.javax.transaction</artifactId>
|
||||
<version>1.1.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>com.springsource.org.hibernate.annotations</artifactId>
|
||||
<version>3.4.0.GA</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>com.springsource.slf4j.org.apache.commons.logging</artifactId>
|
||||
<version>${slf4j.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>com.springsource.slf4j.api</artifactId>
|
||||
<version>${slf4j.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>com.springsource.slf4j.log4j</artifactId>
|
||||
<version>${slf4j.version}</version>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.log4j</groupId>
|
||||
<artifactId>com.springsource.org.apache.log4j</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>com.springsource.repository.bundles.release</id>
|
||||
<name>SpringSource Enterprise Bundle Repository - SpringSource Releases</name>
|
||||
<url>http://repository.springsource.com/maven/bundles/release</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>com.springsource.repository.bundles.milestone</id>
|
||||
<name>SpringSource Enterprise Bundle Repository - SpringSource Milestones</name>
|
||||
<url>http://repository.springsource.com/maven/bundles/milestone</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>com.springsource.repository.bundles.external</id>
|
||||
<name>SpringSource Enterprise Bundle Repository - External Releases</name>
|
||||
<url>http://repository.springsource.com/maven/bundles/external</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>com.springsource.repository.bundles.snapshot</id>
|
||||
<name>SpringSource Enterprise Bundle Repository - Snapshot Releases</name>
|
||||
<url>http://repository.springsource.com/maven/bundles/snapshot</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-release</id>
|
||||
<name>Spring Portfolio Release Repository</name>
|
||||
<url>http://maven.springframework.org/release</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-external</id>
|
||||
<name>Spring Portfolio External Repository</name>
|
||||
<url>http://maven.springframework.org/external</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-milestone</id>
|
||||
<name>Spring Portfolio Milestone Repository</name>
|
||||
<url>http://maven.springframework.org/milestone</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.5</source>
|
||||
<target>1.5</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>install</id>
|
||||
<phase>install</phase>
|
||||
<goals>
|
||||
<goal>sources</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
18
readme.txt
18
readme.txt
|
@ -44,22 +44,20 @@ pooling.
|
|||
=== Build and Deployment
|
||||
==========================================================================
|
||||
|
||||
The Spring PetClinic sample application is built using Spring Build, which
|
||||
is a custom build solution based on Ant and Ivy for dependency management.
|
||||
For deployment, the web application needs to be built with Apache Ant 1.6
|
||||
or higher. When the project is first built, Spring Build will use Ivy to
|
||||
automatically download all required dependencies. Thus the initial build
|
||||
The Spring PetClinic sample application is built using Maven.
|
||||
When the project is first built, Maven will automatically download all required
|
||||
dependencies (if these haven't been downloaded before). Thus the initial build
|
||||
may take a few minutes depending on the speed of your Internet connection,
|
||||
but subsequent builds will be much faster.
|
||||
|
||||
Available build commands:
|
||||
|
||||
- ant clean --> cleans the project
|
||||
- ant clean test --> cleans the project and runs all tests
|
||||
- ant clean jar --> cleans the project and builds the WAR
|
||||
- mvn clean --> cleans the project
|
||||
- mvn clean test --> cleans the project and runs all tests
|
||||
- mvn clean package --> cleans the project and builds the WAR
|
||||
|
||||
After building the project with "ant clean jar", you will find the
|
||||
resulting WAR file in the "target/artifacts" directory. By default, an
|
||||
After building the project with "mvn clean package", you will find the
|
||||
resulting WAR file in the "target/" directory. By default, an
|
||||
embedded HSQLDB instance in configured. No other steps are necessary to
|
||||
get the data source up and running: you can simply deploy the built WAR
|
||||
file directly to your Servlet container.
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
package org.springframework.samples.petclinic;
|
||||
|
||||
/**
|
||||
* Simple JavaBean domain object with an id property.
|
||||
* Used as a base class for objects needing this property.
|
||||
*
|
||||
* @author Ken Krebs
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class BaseEntity {
|
||||
|
||||
private Integer id;
|
||||
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public boolean isNew() {
|
||||
return (this.id == null);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package org.springframework.samples.petclinic;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
|
||||
/**
|
||||
* The high-level PetClinic business interface.
|
||||
*
|
||||
* <p>This is basically a data access object.
|
||||
* PetClinic doesn't have a dedicated business facade.
|
||||
*
|
||||
* @author Ken Krebs
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
public interface Clinic {
|
||||
|
||||
/**
|
||||
* Retrieve all <code>Vet</code>s from the data store.
|
||||
* @return a <code>Collection</code> of <code>Vet</code>s
|
||||
*/
|
||||
Collection<Vet> getVets() throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Retrieve all <code>PetType</code>s from the data store.
|
||||
* @return a <code>Collection</code> of <code>PetType</code>s
|
||||
*/
|
||||
Collection<PetType> getPetTypes() throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Retrieve <code>Owner</code>s from the data store by last name,
|
||||
* returning all owners whose last name <i>starts</i> with the given name.
|
||||
* @param lastName Value to search for
|
||||
* @return a <code>Collection</code> of matching <code>Owner</code>s
|
||||
* (or an empty <code>Collection</code> if none found)
|
||||
*/
|
||||
Collection<Owner> findOwners(String lastName) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Retrieve an <code>Owner</code> from the data store by id.
|
||||
* @param id the id to search for
|
||||
* @return the <code>Owner</code> if found
|
||||
* @throws org.springframework.dao.DataRetrievalFailureException if not found
|
||||
*/
|
||||
Owner loadOwner(int id) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Retrieve a <code>Pet</code> from the data store by id.
|
||||
* @param id the id to search for
|
||||
* @return the <code>Pet</code> if found
|
||||
* @throws org.springframework.dao.DataRetrievalFailureException if not found
|
||||
*/
|
||||
Pet loadPet(int id) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Save an <code>Owner</code> to the data store, either inserting or updating it.
|
||||
* @param owner the <code>Owner</code> to save
|
||||
* @see BaseEntity#isNew
|
||||
*/
|
||||
void storeOwner(Owner owner) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Save a <code>Pet</code> to the data store, either inserting or updating it.
|
||||
* @param pet the <code>Pet</code> to save
|
||||
* @see BaseEntity#isNew
|
||||
*/
|
||||
void storePet(Pet pet) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Save a <code>Visit</code> to the data store, either inserting or updating it.
|
||||
* @param visit the <code>Visit</code> to save
|
||||
* @see BaseEntity#isNew
|
||||
*/
|
||||
void storeVisit(Visit visit) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Deletes a <code>Pet</code> from the data store.
|
||||
*/
|
||||
void deletePet(int id) throws DataAccessException;
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package org.springframework.samples.petclinic;
|
||||
|
||||
/**
|
||||
* Simple JavaBean domain object adds a name property to <code>BaseEntity</code>.
|
||||
* Used as a base class for objects needing these properties.
|
||||
*
|
||||
* @author Ken Krebs
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class NamedEntity extends BaseEntity {
|
||||
|
||||
private String name;
|
||||
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.getName();
|
||||
}
|
||||
|
||||
}
|
127
src/main/java/org/springframework/samples/petclinic/Owner.java
Normal file
127
src/main/java/org/springframework/samples/petclinic/Owner.java
Normal file
|
@ -0,0 +1,127 @@
|
|||
package org.springframework.samples.petclinic;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.support.MutableSortDefinition;
|
||||
import org.springframework.beans.support.PropertyComparator;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
|
||||
/**
|
||||
* Simple JavaBean domain object representing an owner.
|
||||
*
|
||||
* @author Ken Krebs
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
public class Owner extends Person {
|
||||
|
||||
private String address;
|
||||
|
||||
private String city;
|
||||
|
||||
private String telephone;
|
||||
|
||||
private Set<Pet> pets;
|
||||
|
||||
|
||||
public String getAddress() {
|
||||
return this.address;
|
||||
}
|
||||
|
||||
public void setAddress(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public String getCity() {
|
||||
return this.city;
|
||||
}
|
||||
|
||||
public void setCity(String city) {
|
||||
this.city = city;
|
||||
}
|
||||
|
||||
public String getTelephone() {
|
||||
return this.telephone;
|
||||
}
|
||||
|
||||
public void setTelephone(String telephone) {
|
||||
this.telephone = telephone;
|
||||
}
|
||||
|
||||
protected void setPetsInternal(Set<Pet> pets) {
|
||||
this.pets = pets;
|
||||
}
|
||||
|
||||
protected Set<Pet> getPetsInternal() {
|
||||
if (this.pets == null) {
|
||||
this.pets = new HashSet<Pet>();
|
||||
}
|
||||
return this.pets;
|
||||
}
|
||||
|
||||
public List<Pet> getPets() {
|
||||
List<Pet> sortedPets = new ArrayList<Pet>(getPetsInternal());
|
||||
PropertyComparator.sort(sortedPets, new MutableSortDefinition("name", true, true));
|
||||
return Collections.unmodifiableList(sortedPets);
|
||||
}
|
||||
|
||||
public void addPet(Pet pet) {
|
||||
getPetsInternal().add(pet);
|
||||
pet.setOwner(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Pet with the given name, or null if none found for this Owner.
|
||||
*
|
||||
* @param name to test
|
||||
* @return true if pet name is already in use
|
||||
*/
|
||||
public Pet getPet(String name) {
|
||||
return getPet(name, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Pet with the given name, or null if none found for this Owner.
|
||||
*
|
||||
* @param name to test
|
||||
* @return true if pet name is already in use
|
||||
*/
|
||||
public Pet getPet(String name, boolean ignoreNew) {
|
||||
name = name.toLowerCase();
|
||||
for (Pet pet : getPetsInternal()) {
|
||||
if (!ignoreNew || !pet.isNew()) {
|
||||
String compName = pet.getName();
|
||||
compName = compName.toLowerCase();
|
||||
if (compName.equals(name)) {
|
||||
return pet;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringCreator(this)
|
||||
|
||||
.append("id", this.getId())
|
||||
|
||||
.append("new", this.isNew())
|
||||
|
||||
.append("lastName", this.getLastName())
|
||||
|
||||
.append("firstName", this.getFirstName())
|
||||
|
||||
.append("address", this.address)
|
||||
|
||||
.append("city", this.city)
|
||||
|
||||
.append("telephone", this.telephone)
|
||||
|
||||
.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package org.springframework.samples.petclinic;
|
||||
|
||||
/**
|
||||
* Simple JavaBean domain object representing an person.
|
||||
*
|
||||
* @author Ken Krebs
|
||||
*/
|
||||
public class Person extends BaseEntity {
|
||||
|
||||
private String firstName;
|
||||
|
||||
private String lastName;
|
||||
|
||||
public String getFirstName() {
|
||||
return this.firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return this.lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
77
src/main/java/org/springframework/samples/petclinic/Pet.java
Normal file
77
src/main/java/org/springframework/samples/petclinic/Pet.java
Normal file
|
@ -0,0 +1,77 @@
|
|||
package org.springframework.samples.petclinic;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.support.MutableSortDefinition;
|
||||
import org.springframework.beans.support.PropertyComparator;
|
||||
|
||||
/**
|
||||
* Simple JavaBean business object representing a pet.
|
||||
*
|
||||
* @author Ken Krebs
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
public class Pet extends NamedEntity {
|
||||
|
||||
private Date birthDate;
|
||||
|
||||
private PetType type;
|
||||
|
||||
private Owner owner;
|
||||
|
||||
private Set<Visit> visits;
|
||||
|
||||
|
||||
public void setBirthDate(Date birthDate) {
|
||||
this.birthDate = birthDate;
|
||||
}
|
||||
|
||||
public Date getBirthDate() {
|
||||
return this.birthDate;
|
||||
}
|
||||
|
||||
public void setType(PetType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public PetType getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
protected void setOwner(Owner owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
public Owner getOwner() {
|
||||
return this.owner;
|
||||
}
|
||||
|
||||
protected void setVisitsInternal(Set<Visit> visits) {
|
||||
this.visits = visits;
|
||||
}
|
||||
|
||||
protected Set<Visit> getVisitsInternal() {
|
||||
if (this.visits == null) {
|
||||
this.visits = new HashSet<Visit>();
|
||||
}
|
||||
return this.visits;
|
||||
}
|
||||
|
||||
public List<Visit> getVisits() {
|
||||
List<Visit> sortedVisits = new ArrayList<Visit>(getVisitsInternal());
|
||||
PropertyComparator.sort(sortedVisits, new MutableSortDefinition("date", false, false));
|
||||
return Collections.unmodifiableList(sortedVisits);
|
||||
}
|
||||
|
||||
public void addVisit(Visit visit) {
|
||||
getVisitsInternal().add(visit);
|
||||
visit.setPet(this);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package org.springframework.samples.petclinic;
|
||||
|
||||
/**
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class PetType extends NamedEntity {
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package org.springframework.samples.petclinic;
|
||||
|
||||
/**
|
||||
* Models a {@link Vet Vet's} specialty (for example, dentistry).
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class Specialty extends NamedEntity {
|
||||
|
||||
}
|
52
src/main/java/org/springframework/samples/petclinic/Vet.java
Normal file
52
src/main/java/org/springframework/samples/petclinic/Vet.java
Normal file
|
@ -0,0 +1,52 @@
|
|||
package org.springframework.samples.petclinic;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
|
||||
import org.springframework.beans.support.MutableSortDefinition;
|
||||
import org.springframework.beans.support.PropertyComparator;
|
||||
|
||||
/**
|
||||
* Simple JavaBean domain object representing a veterinarian.
|
||||
*
|
||||
* @author Ken Krebs
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
public class Vet extends Person {
|
||||
|
||||
private Set<Specialty> specialties;
|
||||
|
||||
|
||||
protected void setSpecialtiesInternal(Set<Specialty> specialties) {
|
||||
this.specialties = specialties;
|
||||
}
|
||||
|
||||
protected Set<Specialty> getSpecialtiesInternal() {
|
||||
if (this.specialties == null) {
|
||||
this.specialties = new HashSet<Specialty>();
|
||||
}
|
||||
return this.specialties;
|
||||
}
|
||||
|
||||
@XmlElement
|
||||
public List<Specialty> getSpecialties() {
|
||||
List<Specialty> sortedSpecs = new ArrayList<Specialty>(getSpecialtiesInternal());
|
||||
PropertyComparator.sort(sortedSpecs, new MutableSortDefinition("name", true, true));
|
||||
return Collections.unmodifiableList(sortedSpecs);
|
||||
}
|
||||
|
||||
public int getNrOfSpecialties() {
|
||||
return getSpecialtiesInternal().size();
|
||||
}
|
||||
|
||||
public void addSpecialty(Specialty specialty) {
|
||||
getSpecialtiesInternal().add(specialty);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright 2002-2009 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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
/**
|
||||
* Simple JavaBean domain object representing a list of veterinarians. Mostly here to be used for the 'vets'
|
||||
* {@link org.springframework.web.servlet.view.xml.MarshallingView}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
@XmlRootElement
|
||||
public class Vets {
|
||||
|
||||
private List<Vet> vets;
|
||||
|
||||
@XmlElement
|
||||
public List<Vet> getVetList() {
|
||||
if (vets == null) {
|
||||
vets = new ArrayList<Vet>();
|
||||
}
|
||||
return vets;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package org.springframework.samples.petclinic;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Simple JavaBean domain object representing a visit.
|
||||
*
|
||||
* @author Ken Krebs
|
||||
*/
|
||||
public class Visit extends BaseEntity {
|
||||
|
||||
/** Holds value of property date. */
|
||||
private Date date;
|
||||
|
||||
/** Holds value of property description. */
|
||||
private String description;
|
||||
|
||||
/** Holds value of property pet. */
|
||||
private Pet pet;
|
||||
|
||||
|
||||
/** Creates a new instance of Visit for the current date */
|
||||
public Visit() {
|
||||
this.date = new Date();
|
||||
}
|
||||
|
||||
|
||||
/** Getter for property date.
|
||||
* @return Value of property date.
|
||||
*/
|
||||
public Date getDate() {
|
||||
return this.date;
|
||||
}
|
||||
|
||||
/** Setter for property date.
|
||||
* @param date New value of property date.
|
||||
*/
|
||||
public void setDate(Date date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
/** Getter for property description.
|
||||
* @return Value of property description.
|
||||
*/
|
||||
public String getDescription() {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
/** Setter for property description.
|
||||
* @param description New value of property description.
|
||||
*/
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/** Getter for property pet.
|
||||
* @return Value of property pet.
|
||||
*/
|
||||
public Pet getPet() {
|
||||
return this.pet;
|
||||
}
|
||||
|
||||
/** Setter for property pet.
|
||||
* @param pet New value of property pet.
|
||||
*/
|
||||
public void setPet(Pet pet) {
|
||||
this.pet = pet;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package org.springframework.samples.petclinic.aspects;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Before;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
|
||||
/**
|
||||
* Aspect to illustrate Spring-driven load-time weaving.
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
* @since 2.5
|
||||
*/
|
||||
@Aspect
|
||||
public abstract class AbstractTraceAspect {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AbstractTraceAspect.class);
|
||||
|
||||
@Pointcut
|
||||
public abstract void traced();
|
||||
|
||||
@Before("traced()")
|
||||
public void trace(JoinPoint.StaticPart jpsp) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Entering " + jpsp.getSignature().toLongString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package org.springframework.samples.petclinic.aspects;
|
||||
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
|
||||
import org.springframework.jmx.export.annotation.ManagedAttribute;
|
||||
import org.springframework.jmx.export.annotation.ManagedOperation;
|
||||
import org.springframework.jmx.export.annotation.ManagedResource;
|
||||
import org.springframework.util.StopWatch;
|
||||
|
||||
/**
|
||||
* Simple AspectJ aspect that monitors call count and call invocation time.
|
||||
* Implements the CallMonitor management interface.
|
||||
*
|
||||
* @author Rob Harrop
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
*/
|
||||
@ManagedResource("petclinic:type=CallMonitor")
|
||||
@Aspect
|
||||
public class CallMonitoringAspect {
|
||||
|
||||
private boolean isEnabled = true;
|
||||
|
||||
private int callCount = 0;
|
||||
|
||||
private long accumulatedCallTime = 0;
|
||||
|
||||
|
||||
@ManagedAttribute
|
||||
public void setEnabled(boolean enabled) {
|
||||
isEnabled = enabled;
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
public boolean isEnabled() {
|
||||
return isEnabled;
|
||||
}
|
||||
|
||||
@ManagedOperation
|
||||
public void reset() {
|
||||
this.callCount = 0;
|
||||
this.accumulatedCallTime = 0;
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
public int getCallCount() {
|
||||
return callCount;
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
public long getCallTime() {
|
||||
return (this.callCount > 0 ? this.accumulatedCallTime / this.callCount : 0);
|
||||
}
|
||||
|
||||
|
||||
@Around("within(@org.springframework.stereotype.Service *)")
|
||||
public Object invoke(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||
if (this.isEnabled) {
|
||||
StopWatch sw = new StopWatch(joinPoint.toShortString());
|
||||
|
||||
sw.start("invoke");
|
||||
try {
|
||||
return joinPoint.proceed();
|
||||
}
|
||||
finally {
|
||||
sw.stop();
|
||||
synchronized (this) {
|
||||
this.callCount++;
|
||||
this.accumulatedCallTime += sw.getTotalTimeMillis();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
return joinPoint.proceed();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package org.springframework.samples.petclinic.aspects;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Before;
|
||||
|
||||
/**
|
||||
* Sample AspectJ annotation-style aspect that saves
|
||||
* every owner name requested to the clinic.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
*/
|
||||
@Aspect
|
||||
public class UsageLogAspect {
|
||||
|
||||
private int historySize = 100;
|
||||
|
||||
// Of course saving all names is not suitable for
|
||||
// production use, but this is a simple example.
|
||||
private List<String> namesRequested = new ArrayList<String>(this.historySize);
|
||||
|
||||
|
||||
public synchronized void setHistorySize(int historySize) {
|
||||
this.historySize = historySize;
|
||||
this.namesRequested = new ArrayList<String>(historySize);
|
||||
}
|
||||
|
||||
@Before("execution(* *.findOwners(String)) && args(name)")
|
||||
public synchronized void logNameRequest(String name) {
|
||||
// Not the most efficient implementation,
|
||||
// but we're aiming to illustrate the power of
|
||||
// @AspectJ AOP, not write perfect code here :-)
|
||||
if (this.namesRequested.size() > this.historySize) {
|
||||
this.namesRequested.remove(0);
|
||||
}
|
||||
this.namesRequested.add(name);
|
||||
}
|
||||
|
||||
public synchronized List<String> getNamesRequested() {
|
||||
return Collections.unmodifiableList(this.namesRequested);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,261 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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.config;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.StringWriter;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.dbcp.BasicDataSource;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
/**
|
||||
* A factory that creates a data source fit for use in a system environment. Creates a DBCP simple data source
|
||||
* from the provided connection properties.
|
||||
*
|
||||
* This factory returns a fully-initialized DataSource implementation. When the DataSource is returned, callers are
|
||||
* guaranteed that the database schema and data will have been loaded by that time.
|
||||
*
|
||||
* Is a FactoryBean, for exposing the fully-initialized DataSource as a Spring bean. See {@link #getObject()}.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Scott Andrews
|
||||
*/
|
||||
public class DbcpDataSourceFactory implements FactoryBean<DataSource>, DisposableBean {
|
||||
|
||||
// configurable properties
|
||||
|
||||
private String driverClassName;
|
||||
|
||||
private String url;
|
||||
|
||||
private String username;
|
||||
|
||||
private String password;
|
||||
|
||||
private boolean populate;
|
||||
|
||||
private Resource schemaLocation;
|
||||
|
||||
private Resource dataLocation;
|
||||
|
||||
private Resource dropLocation;
|
||||
|
||||
/**
|
||||
* The object created by this factory.
|
||||
*/
|
||||
private BasicDataSource dataSource;
|
||||
|
||||
public void setDriverClassName(String driverClassName) {
|
||||
this.driverClassName = driverClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* The data source connection URL
|
||||
*/
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
/**
|
||||
* The data source username
|
||||
*/
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
/**
|
||||
*The data source password
|
||||
*/
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that the data base should be populated from the schema and data locations
|
||||
*/
|
||||
public void setPopulate(boolean populate) {
|
||||
this.populate = populate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the location of the file containing the schema DDL to export to the database.
|
||||
* @param schemaLocation the location of the database schema DDL
|
||||
*/
|
||||
public void setSchemaLocation(Resource schemaLocation) {
|
||||
this.schemaLocation = schemaLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the location of the file containing the data to load into the database.
|
||||
* @param testDataLocation the location of the data file
|
||||
*/
|
||||
public void setDataLocation(Resource testDataLocation) {
|
||||
this.dataLocation = testDataLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the location of the file containing the drop scripts for the database.
|
||||
* @param testDataLocation the location of the data file
|
||||
*/
|
||||
public void setDropLocation(Resource testDropLocation) {
|
||||
this.dropLocation = testDropLocation;
|
||||
}
|
||||
|
||||
// implementing FactoryBean
|
||||
|
||||
// this method is called by Spring to expose the DataSource as a bean
|
||||
public DataSource getObject() throws Exception {
|
||||
if (dataSource == null) {
|
||||
initDataSource();
|
||||
}
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
public Class<DataSource> getObjectType() {
|
||||
return DataSource.class;
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// implementing DisposableBean
|
||||
|
||||
public void destroy() throws Exception {
|
||||
dataSource.close();
|
||||
}
|
||||
|
||||
// internal helper methods
|
||||
|
||||
// encapsulates the steps involved in initializing the data source: creating it, and populating it
|
||||
private void initDataSource() {
|
||||
// create the database source first
|
||||
this.dataSource = createDataSource();
|
||||
|
||||
if (this.populate) {
|
||||
// now populate the database by loading the schema and data
|
||||
populateDataSource();
|
||||
}
|
||||
}
|
||||
|
||||
private BasicDataSource createDataSource() {
|
||||
BasicDataSource dataSource = new BasicDataSource();
|
||||
dataSource.setDriverClassName(this.driverClassName);
|
||||
dataSource.setUrl(this.url);
|
||||
dataSource.setUsername(this.username);
|
||||
dataSource.setPassword(this.password);
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
private void populateDataSource() {
|
||||
DatabasePopulator populator = new DatabasePopulator(dataSource);
|
||||
if (dropLocation != null) {
|
||||
try {
|
||||
populator.populate(this.dropLocation);
|
||||
}
|
||||
catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
populator.populate(this.schemaLocation);
|
||||
populator.populate(this.dataLocation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates a in memory data source with data.
|
||||
*/
|
||||
private class DatabasePopulator {
|
||||
|
||||
private DataSource dataSource;
|
||||
|
||||
/**
|
||||
* Creates a new database populator.
|
||||
* @param dataSource the data source that will be populated.
|
||||
*/
|
||||
public DatabasePopulator(DataSource dataSource) {
|
||||
this.dataSource = dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the database executing the statements in the provided resource against the database
|
||||
* @param sqlFile spring resource containing SQL to run against the db
|
||||
*/
|
||||
public void populate(Resource sqlFile) {
|
||||
Connection connection = null;
|
||||
try {
|
||||
connection = dataSource.getConnection();
|
||||
try {
|
||||
String sql = parseSqlIn(sqlFile);
|
||||
executeSql(sql, connection);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("I/O exception occurred accessing the database schema file", e);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException("SQL exception occurred exporting database schema", e);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException("SQL exception occurred acquiring connection", e);
|
||||
} finally {
|
||||
if (connection != null) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (SQLException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// utility method to read a .sql txt input stream
|
||||
private String parseSqlIn(Resource resource) throws IOException {
|
||||
InputStream is = null;
|
||||
try {
|
||||
is = resource.getInputStream();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
|
||||
|
||||
StringWriter sw = new StringWriter();
|
||||
BufferedWriter writer = new BufferedWriter(sw);
|
||||
|
||||
for (int c=reader.read(); c != -1; c=reader.read()) {
|
||||
writer.write(c);
|
||||
}
|
||||
writer.flush();
|
||||
return sw.toString();
|
||||
|
||||
} finally {
|
||||
if (is != null) {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// utility method to run the parsed sql
|
||||
private void executeSql(String sql, Connection connection) throws SQLException {
|
||||
Statement statement = connection.createStatement();
|
||||
statement.execute(sql);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
package org.springframework.samples.petclinic.hibernate;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.samples.petclinic.Clinic;
|
||||
import org.springframework.samples.petclinic.Owner;
|
||||
import org.springframework.samples.petclinic.Pet;
|
||||
import org.springframework.samples.petclinic.PetType;
|
||||
import org.springframework.samples.petclinic.Vet;
|
||||
import org.springframework.samples.petclinic.Visit;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Hibernate implementation of the Clinic interface.
|
||||
*
|
||||
* <p>The mappings are defined in "petclinic.hbm.xml", located in the root of the
|
||||
* class path.
|
||||
*
|
||||
* <p>Note that transactions are declared with annotations and that some methods
|
||||
* contain "readOnly = true" which is an optimization that is particularly
|
||||
* valuable when using Hibernate (to suppress unnecessary flush attempts for
|
||||
* read-only operations).
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @author Mark Fisher
|
||||
* @since 19.10.2003
|
||||
*/
|
||||
@Repository
|
||||
@Transactional
|
||||
public class HibernateClinic implements Clinic {
|
||||
|
||||
private SessionFactory sessionFactory;
|
||||
|
||||
@Autowired
|
||||
public HibernateClinic(SessionFactory sessionFactory) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
@SuppressWarnings("unchecked")
|
||||
public Collection<Vet> getVets() {
|
||||
return sessionFactory.getCurrentSession().createQuery("from Vet vet order by vet.lastName, vet.firstName").list();
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
@SuppressWarnings("unchecked")
|
||||
public Collection<PetType> getPetTypes() {
|
||||
return sessionFactory.getCurrentSession().createQuery("from PetType type order by type.name").list();
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
@SuppressWarnings("unchecked")
|
||||
public Collection<Owner> findOwners(String lastName) {
|
||||
return sessionFactory.getCurrentSession().createQuery("from Owner owner where owner.lastName like :lastName")
|
||||
.setString("lastName", lastName + "%").list();
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public Owner loadOwner(int id) {
|
||||
return (Owner) sessionFactory.getCurrentSession().load(Owner.class, id);
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public Pet loadPet(int id) {
|
||||
return (Pet) sessionFactory.getCurrentSession().load(Pet.class, id);
|
||||
}
|
||||
|
||||
public void storeOwner(Owner owner) {
|
||||
// Note: Hibernate3's merge operation does not reassociate the object
|
||||
// with the current Hibernate Session. Instead, it will always copy the
|
||||
// state over to a registered representation of the entity. In case of a
|
||||
// new entity, it will register a copy as well, but will not update the
|
||||
// id of the passed-in object. To still update the ids of the original
|
||||
// objects too, we need to register Spring's
|
||||
// IdTransferringMergeEventListener on our SessionFactory.
|
||||
sessionFactory.getCurrentSession().merge(owner);
|
||||
}
|
||||
|
||||
public void storePet(Pet pet) {
|
||||
sessionFactory.getCurrentSession().merge(pet);
|
||||
}
|
||||
|
||||
public void storeVisit(Visit visit) {
|
||||
sessionFactory.getCurrentSession().merge(visit);
|
||||
}
|
||||
|
||||
public void deletePet(int id) throws DataAccessException {
|
||||
Pet pet = loadPet(id);
|
||||
sessionFactory.getCurrentSession().delete(pet);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* The classes in this package represent the Hibernate implementation
|
||||
* of PetClinic's persistence layer.
|
||||
*
|
||||
*/
|
||||
package org.springframework.samples.petclinic.hibernate;
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package org.springframework.samples.petclinic.jdbc;
|
||||
|
||||
import org.springframework.samples.petclinic.Pet;
|
||||
|
||||
/**
|
||||
* Subclass of Pet that carries temporary id properties which
|
||||
* are only relevant for a JDBC implmentation of the Clinic.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @see SimpleJdbcClinic
|
||||
*/
|
||||
class JdbcPet extends Pet {
|
||||
|
||||
private int typeId;
|
||||
|
||||
private int ownerId;
|
||||
|
||||
|
||||
public void setTypeId(int typeId) {
|
||||
this.typeId = typeId;
|
||||
}
|
||||
|
||||
public int getTypeId() {
|
||||
return this.typeId;
|
||||
}
|
||||
|
||||
public void setOwnerId(int ownerId) {
|
||||
this.ownerId = ownerId;
|
||||
}
|
||||
|
||||
public int getOwnerId() {
|
||||
return this.ownerId;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,342 @@
|
|||
package org.springframework.samples.petclinic.jdbc;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
|
||||
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
|
||||
import org.springframework.jdbc.core.simple.ParameterizedBeanPropertyRowMapper;
|
||||
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
|
||||
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
|
||||
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
|
||||
import org.springframework.jmx.export.annotation.ManagedOperation;
|
||||
import org.springframework.jmx.export.annotation.ManagedResource;
|
||||
import org.springframework.orm.ObjectRetrievalFailureException;
|
||||
import org.springframework.samples.petclinic.Clinic;
|
||||
import org.springframework.samples.petclinic.Owner;
|
||||
import org.springframework.samples.petclinic.Pet;
|
||||
import org.springframework.samples.petclinic.PetType;
|
||||
import org.springframework.samples.petclinic.Specialty;
|
||||
import org.springframework.samples.petclinic.Vet;
|
||||
import org.springframework.samples.petclinic.Visit;
|
||||
import org.springframework.samples.petclinic.util.EntityUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* A simple JDBC-based implementation of the {@link Clinic} interface.
|
||||
*
|
||||
* <p>This class uses Java 5 language features and the {@link SimpleJdbcTemplate}
|
||||
* plus {@link SimpleJdbcInsert}. It also takes advantage of classes like
|
||||
* {@link BeanPropertySqlParameterSource} and
|
||||
* {@link ParameterizedBeanPropertyRowMapper} which provide automatic mapping
|
||||
* between JavaBean properties and JDBC parameters or query results.
|
||||
*
|
||||
* <p>SimpleJdbcClinic is a rewrite of the AbstractJdbcClinic which was the base
|
||||
* class for JDBC implementations of the Clinic interface for Spring 2.0.
|
||||
*
|
||||
* @author Ken Krebs
|
||||
* @author Juergen Hoeller
|
||||
* @author Rob Harrop
|
||||
* @author Sam Brannen
|
||||
* @author Thomas Risberg
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
@Service
|
||||
@ManagedResource("petclinic:type=Clinic")
|
||||
public class SimpleJdbcClinic implements Clinic, SimpleJdbcClinicMBean {
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private SimpleJdbcTemplate simpleJdbcTemplate;
|
||||
|
||||
private SimpleJdbcInsert insertOwner;
|
||||
private SimpleJdbcInsert insertPet;
|
||||
private SimpleJdbcInsert insertVisit;
|
||||
|
||||
private final List<Vet> vets = new ArrayList<Vet>();
|
||||
|
||||
|
||||
@Autowired
|
||||
public void init(DataSource dataSource) {
|
||||
this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
|
||||
|
||||
this.insertOwner = new SimpleJdbcInsert(dataSource)
|
||||
.withTableName("owners")
|
||||
.usingGeneratedKeyColumns("id");
|
||||
this.insertPet = new SimpleJdbcInsert(dataSource)
|
||||
.withTableName("pets")
|
||||
.usingGeneratedKeyColumns("id");
|
||||
this.insertVisit = new SimpleJdbcInsert(dataSource)
|
||||
.withTableName("visits")
|
||||
.usingGeneratedKeyColumns("id");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Refresh the cache of Vets that the Clinic is holding.
|
||||
* @see org.springframework.samples.petclinic.Clinic#getVets()
|
||||
*/
|
||||
@ManagedOperation
|
||||
@Transactional(readOnly = true)
|
||||
public void refreshVetsCache() throws DataAccessException {
|
||||
synchronized (this.vets) {
|
||||
this.logger.info("Refreshing vets cache");
|
||||
|
||||
// Retrieve the list of all vets.
|
||||
this.vets.clear();
|
||||
this.vets.addAll(this.simpleJdbcTemplate.query(
|
||||
"SELECT id, first_name, last_name FROM vets ORDER BY last_name,first_name",
|
||||
ParameterizedBeanPropertyRowMapper.newInstance(Vet.class)));
|
||||
|
||||
// Retrieve the list of all possible specialties.
|
||||
final List<Specialty> specialties = this.simpleJdbcTemplate.query(
|
||||
"SELECT id, name FROM specialties",
|
||||
ParameterizedBeanPropertyRowMapper.newInstance(Specialty.class));
|
||||
|
||||
// Build each vet's list of specialties.
|
||||
for (Vet vet : this.vets) {
|
||||
final List<Integer> vetSpecialtiesIds = this.simpleJdbcTemplate.query(
|
||||
"SELECT specialty_id FROM vet_specialties WHERE vet_id=?",
|
||||
new ParameterizedRowMapper<Integer>() {
|
||||
public Integer mapRow(ResultSet rs, int row) throws SQLException {
|
||||
return Integer.valueOf(rs.getInt(1));
|
||||
}},
|
||||
vet.getId().intValue());
|
||||
for (int specialtyId : vetSpecialtiesIds) {
|
||||
Specialty specialty = EntityUtils.getById(specialties, Specialty.class, specialtyId);
|
||||
vet.addSpecialty(specialty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// START of Clinic implementation section *******************************
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public Collection<Vet> getVets() throws DataAccessException {
|
||||
synchronized (this.vets) {
|
||||
if (this.vets.isEmpty()) {
|
||||
refreshVetsCache();
|
||||
}
|
||||
return this.vets;
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public Collection<PetType> getPetTypes() throws DataAccessException {
|
||||
return this.simpleJdbcTemplate.query(
|
||||
"SELECT id, name FROM types ORDER BY name",
|
||||
ParameterizedBeanPropertyRowMapper.newInstance(PetType.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads {@link Owner Owners} from the data store by last name, returning
|
||||
* all owners whose last name <i>starts</i> with the given name; also loads
|
||||
* the {@link Pet Pets} and {@link Visit Visits} for the corresponding
|
||||
* owners, if not already loaded.
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public Collection<Owner> findOwners(String lastName) throws DataAccessException {
|
||||
List<Owner> owners = this.simpleJdbcTemplate.query(
|
||||
"SELECT id, first_name, last_name, address, city, telephone FROM owners WHERE last_name like ?",
|
||||
ParameterizedBeanPropertyRowMapper.newInstance(Owner.class),
|
||||
lastName + "%");
|
||||
loadOwnersPetsAndVisits(owners);
|
||||
return owners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the {@link Owner} with the supplied <code>id</code>; also loads
|
||||
* the {@link Pet Pets} and {@link Visit Visits} for the corresponding
|
||||
* owner, if not already loaded.
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public Owner loadOwner(int id) throws DataAccessException {
|
||||
Owner owner;
|
||||
try {
|
||||
owner = this.simpleJdbcTemplate.queryForObject(
|
||||
"SELECT id, first_name, last_name, address, city, telephone FROM owners WHERE id=?",
|
||||
ParameterizedBeanPropertyRowMapper.newInstance(Owner.class),
|
||||
id);
|
||||
}
|
||||
catch (EmptyResultDataAccessException ex) {
|
||||
throw new ObjectRetrievalFailureException(Owner.class, new Integer(id));
|
||||
}
|
||||
loadPetsAndVisits(owner);
|
||||
return owner;
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public Pet loadPet(int id) throws DataAccessException {
|
||||
JdbcPet pet;
|
||||
try {
|
||||
pet = this.simpleJdbcTemplate.queryForObject(
|
||||
"SELECT id, name, birth_date, type_id, owner_id FROM pets WHERE id=?",
|
||||
new JdbcPetRowMapper(),
|
||||
id);
|
||||
}
|
||||
catch (EmptyResultDataAccessException ex) {
|
||||
throw new ObjectRetrievalFailureException(Pet.class, new Integer(id));
|
||||
}
|
||||
Owner owner = loadOwner(pet.getOwnerId());
|
||||
owner.addPet(pet);
|
||||
pet.setType(EntityUtils.getById(getPetTypes(), PetType.class, pet.getTypeId()));
|
||||
loadVisits(pet);
|
||||
return pet;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void storeOwner(Owner owner) throws DataAccessException {
|
||||
if (owner.isNew()) {
|
||||
Number newKey = this.insertOwner.executeAndReturnKey(
|
||||
new BeanPropertySqlParameterSource(owner));
|
||||
owner.setId(newKey.intValue());
|
||||
}
|
||||
else {
|
||||
this.simpleJdbcTemplate.update(
|
||||
"UPDATE owners SET first_name=:firstName, last_name=:lastName, address=:address, " +
|
||||
"city=:city, telephone=:telephone WHERE id=:id",
|
||||
new BeanPropertySqlParameterSource(owner));
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void storePet(Pet pet) throws DataAccessException {
|
||||
if (pet.isNew()) {
|
||||
Number newKey = this.insertPet.executeAndReturnKey(
|
||||
createPetParameterSource(pet));
|
||||
pet.setId(newKey.intValue());
|
||||
}
|
||||
else {
|
||||
this.simpleJdbcTemplate.update(
|
||||
"UPDATE pets SET name=:name, birth_date=:birth_date, type_id=:type_id, " +
|
||||
"owner_id=:owner_id WHERE id=:id",
|
||||
createPetParameterSource(pet));
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void storeVisit(Visit visit) throws DataAccessException {
|
||||
if (visit.isNew()) {
|
||||
Number newKey = this.insertVisit.executeAndReturnKey(
|
||||
createVisitParameterSource(visit));
|
||||
visit.setId(newKey.intValue());
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("Visit update not supported");
|
||||
}
|
||||
}
|
||||
|
||||
public void deletePet(int id) throws DataAccessException {
|
||||
this.simpleJdbcTemplate.update("DELETE FROM pets WHERE id=?", id);
|
||||
}
|
||||
|
||||
// END of Clinic implementation section ************************************
|
||||
|
||||
|
||||
/**
|
||||
* Creates a {@link MapSqlParameterSource} based on data values from the
|
||||
* supplied {@link Pet} instance.
|
||||
*/
|
||||
private MapSqlParameterSource createPetParameterSource(Pet pet) {
|
||||
return new MapSqlParameterSource()
|
||||
.addValue("id", pet.getId())
|
||||
.addValue("name", pet.getName())
|
||||
.addValue("birth_date", pet.getBirthDate())
|
||||
.addValue("type_id", pet.getType().getId())
|
||||
.addValue("owner_id", pet.getOwner().getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link MapSqlParameterSource} based on data values from the
|
||||
* supplied {@link Visit} instance.
|
||||
*/
|
||||
private MapSqlParameterSource createVisitParameterSource(Visit visit) {
|
||||
return new MapSqlParameterSource()
|
||||
.addValue("id", visit.getId())
|
||||
.addValue("visit_date", visit.getDate())
|
||||
.addValue("description", visit.getDescription())
|
||||
.addValue("pet_id", visit.getPet().getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the {@link Visit} data for the supplied {@link Pet}.
|
||||
*/
|
||||
private void loadVisits(JdbcPet pet) {
|
||||
final List<Visit> visits = this.simpleJdbcTemplate.query(
|
||||
"SELECT id, visit_date, description FROM visits WHERE pet_id=?",
|
||||
new ParameterizedRowMapper<Visit>() {
|
||||
public Visit mapRow(ResultSet rs, int row) throws SQLException {
|
||||
Visit visit = new Visit();
|
||||
visit.setId(rs.getInt("id"));
|
||||
visit.setDate(rs.getTimestamp("visit_date"));
|
||||
visit.setDescription(rs.getString("description"));
|
||||
return visit;
|
||||
}
|
||||
},
|
||||
pet.getId().intValue());
|
||||
for (Visit visit : visits) {
|
||||
pet.addVisit(visit);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the {@link Pet} and {@link Visit} data for the supplied
|
||||
* {@link Owner}.
|
||||
*/
|
||||
private void loadPetsAndVisits(final Owner owner) {
|
||||
final List<JdbcPet> pets = this.simpleJdbcTemplate.query(
|
||||
"SELECT id, name, birth_date, type_id, owner_id FROM pets WHERE owner_id=?",
|
||||
new JdbcPetRowMapper(),
|
||||
owner.getId().intValue());
|
||||
for (JdbcPet pet : pets) {
|
||||
owner.addPet(pet);
|
||||
pet.setType(EntityUtils.getById(getPetTypes(), PetType.class, pet.getTypeId()));
|
||||
loadVisits(pet);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the {@link Pet} and {@link Visit} data for the supplied
|
||||
* {@link List} of {@link Owner Owners}.
|
||||
*
|
||||
* @param owners the list of owners for whom the pet and visit data should be loaded
|
||||
* @see #loadPetsAndVisits(Owner)
|
||||
*/
|
||||
private void loadOwnersPetsAndVisits(List<Owner> owners) {
|
||||
for (Owner owner : owners) {
|
||||
loadPetsAndVisits(owner);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ParameterizedRowMapper} implementation mapping data from a
|
||||
* {@link ResultSet} to the corresponding properties of the {@link JdbcPet} class.
|
||||
*/
|
||||
private class JdbcPetRowMapper implements ParameterizedRowMapper<JdbcPet> {
|
||||
|
||||
public JdbcPet mapRow(ResultSet rs, int rownum) throws SQLException {
|
||||
JdbcPet pet = new JdbcPet();
|
||||
pet.setId(rs.getInt("id"));
|
||||
pet.setName(rs.getString("name"));
|
||||
pet.setBirthDate(rs.getDate("birth_date"));
|
||||
pet.setTypeId(rs.getInt("type_id"));
|
||||
pet.setOwnerId(rs.getInt("owner_id"));
|
||||
return pet;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package org.springframework.samples.petclinic.jdbc;
|
||||
|
||||
/**
|
||||
* Interface that defines a cache refresh operation.
|
||||
* To be exposed for management via JMX.
|
||||
*
|
||||
* @author Rob Harrop
|
||||
* @author Juergen Hoeller
|
||||
* @see SimpleJdbcClinic
|
||||
*/
|
||||
public interface SimpleJdbcClinicMBean {
|
||||
|
||||
/**
|
||||
* Refresh the cache of Vets that the Clinic is holding.
|
||||
* @see org.springframework.samples.petclinic.Clinic#getVets()
|
||||
* @see SimpleJdbcClinic#refreshVetsCache()
|
||||
*/
|
||||
void refreshVetsCache();
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* The classes in this package represent the JDBC implementation
|
||||
* of PetClinic's persistence layer.
|
||||
*
|
||||
*/
|
||||
package org.springframework.samples.petclinic.jdbc;
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
package org.springframework.samples.petclinic.jpa;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceContext;
|
||||
import javax.persistence.Query;
|
||||
|
||||
import org.springframework.samples.petclinic.Clinic;
|
||||
import org.springframework.samples.petclinic.Owner;
|
||||
import org.springframework.samples.petclinic.Pet;
|
||||
import org.springframework.samples.petclinic.PetType;
|
||||
import org.springframework.samples.petclinic.Vet;
|
||||
import org.springframework.samples.petclinic.Visit;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
|
||||
/**
|
||||
* JPA implementation of the Clinic interface using EntityManager.
|
||||
*
|
||||
* <p>The mappings are defined in "orm.xml" located in the META-INF directory.
|
||||
*
|
||||
* @author Mike Keith
|
||||
* @author Rod Johnson
|
||||
* @author Sam Brannen
|
||||
* @since 22.4.2006
|
||||
*/
|
||||
@Repository
|
||||
@Transactional
|
||||
public class EntityManagerClinic implements Clinic {
|
||||
|
||||
@PersistenceContext
|
||||
private EntityManager em;
|
||||
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
@SuppressWarnings("unchecked")
|
||||
public Collection<Vet> getVets() {
|
||||
return this.em.createQuery("SELECT vet FROM Vet vet ORDER BY vet.lastName, vet.firstName").getResultList();
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
@SuppressWarnings("unchecked")
|
||||
public Collection<PetType> getPetTypes() {
|
||||
return this.em.createQuery("SELECT ptype FROM PetType ptype ORDER BY ptype.name").getResultList();
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
@SuppressWarnings("unchecked")
|
||||
public Collection<Owner> findOwners(String lastName) {
|
||||
Query query = this.em.createQuery("SELECT owner FROM Owner owner WHERE owner.lastName LIKE :lastName");
|
||||
query.setParameter("lastName", lastName + "%");
|
||||
return query.getResultList();
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public Owner loadOwner(int id) {
|
||||
return this.em.find(Owner.class, id);
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public Pet loadPet(int id) {
|
||||
return this.em.find(Pet.class, id);
|
||||
}
|
||||
|
||||
public void storeOwner(Owner owner) {
|
||||
// Consider returning the persistent object here, for exposing
|
||||
// a newly assigned id using any persistence provider...
|
||||
Owner merged = this.em.merge(owner);
|
||||
this.em.flush();
|
||||
owner.setId(merged.getId());
|
||||
}
|
||||
|
||||
public void storePet(Pet pet) {
|
||||
// Consider returning the persistent object here, for exposing
|
||||
// a newly assigned id using any persistence provider...
|
||||
Pet merged = this.em.merge(pet);
|
||||
this.em.flush();
|
||||
pet.setId(merged.getId());
|
||||
}
|
||||
|
||||
public void storeVisit(Visit visit) {
|
||||
// Consider returning the persistent object here, for exposing
|
||||
// a newly assigned id using any persistence provider...
|
||||
Visit merged = this.em.merge(visit);
|
||||
this.em.flush();
|
||||
visit.setId(merged.getId());
|
||||
}
|
||||
|
||||
public void deletePet(int id) throws DataAccessException {
|
||||
Pet pet = loadPet(id);
|
||||
this.em.remove(pet);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* The classes in this package represent the JPA implementation
|
||||
* of PetClinic's persistence layer.
|
||||
*
|
||||
*/
|
||||
package org.springframework.samples.petclinic.jpa;
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* The classes in this package represent PetClinic's business layer.
|
||||
*
|
||||
*/
|
||||
package org.springframework.samples.petclinic;
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
package org.springframework.samples.petclinic.toplink;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
|
||||
import oracle.toplink.essentials.exceptions.ValidationException;
|
||||
import oracle.toplink.essentials.platform.database.HSQLPlatform;
|
||||
import oracle.toplink.essentials.queryframework.ValueReadQuery;
|
||||
|
||||
/**
|
||||
* Subclass of the TopLink Essentials default HSQLPlatform class, using native
|
||||
* HSQLDB identity columns for id generation.
|
||||
*
|
||||
* <p>Necessary for PetClinic's default data model, which relies on identity
|
||||
* columns: this is uniformly used across all persistence layer implementations
|
||||
* (JDBC, Hibernate, and JPA).
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author <a href="mailto:james.x.clark@oracle.com">James Clark</a>
|
||||
* @since 1.2
|
||||
*/
|
||||
public class EssentialsHSQLPlatformWithNativeSequence extends HSQLPlatform {
|
||||
|
||||
private static final long serialVersionUID = -55658009691346735L;
|
||||
|
||||
|
||||
public EssentialsHSQLPlatformWithNativeSequence() {
|
||||
// setUsesNativeSequencing(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsNativeSequenceNumbers() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldNativeSequenceAcquireValueAfterInsert() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueReadQuery buildSelectQueryForNativeSequence() {
|
||||
return new ValueReadQuery("CALL IDENTITY()");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printFieldIdentityClause(Writer writer) throws ValidationException {
|
||||
try {
|
||||
writer.write(" IDENTITY");
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw ValidationException.fileError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* The classes in this package provide support for using the TopLink
|
||||
* implementation with PetClinic's EntityManagerClinic.
|
||||
*
|
||||
*
|
||||
*/
|
||||
package org.springframework.samples.petclinic.toplink;
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
|
||||
package org.springframework.samples.petclinic.util;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.orm.ObjectRetrievalFailureException;
|
||||
import org.springframework.samples.petclinic.BaseEntity;
|
||||
|
||||
/**
|
||||
* Utility methods for handling entities. Separate from the BaseEntity class
|
||||
* mainly because of dependency on the ORM-associated
|
||||
* ObjectRetrievalFailureException.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @since 29.10.2003
|
||||
* @see org.springframework.samples.petclinic.BaseEntity
|
||||
*/
|
||||
public abstract class EntityUtils {
|
||||
|
||||
/**
|
||||
* Look up the entity of the given class with the given id in the given
|
||||
* collection.
|
||||
*
|
||||
* @param entities the collection to search
|
||||
* @param entityClass the entity class to look up
|
||||
* @param entityId the entity id to look up
|
||||
* @return the found entity
|
||||
* @throws ObjectRetrievalFailureException if the entity was not found
|
||||
*/
|
||||
public static <T extends BaseEntity> T getById(Collection<T> entities, Class<T> entityClass, int entityId)
|
||||
throws ObjectRetrievalFailureException {
|
||||
for (T entity : entities) {
|
||||
if (entity.getId().intValue() == entityId && entityClass.isInstance(entity)) {
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
throw new ObjectRetrievalFailureException(entityClass, new Integer(entityId));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package org.springframework.samples.petclinic.validation;
|
||||
|
||||
import org.springframework.samples.petclinic.Owner;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.Errors;
|
||||
|
||||
/**
|
||||
* <code>Validator</code> for <code>Owner</code> forms.
|
||||
*
|
||||
* @author Ken Krebs
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class OwnerValidator {
|
||||
|
||||
public void validate(Owner owner, Errors errors) {
|
||||
if (!StringUtils.hasLength(owner.getFirstName())) {
|
||||
errors.rejectValue("firstName", "required", "required");
|
||||
}
|
||||
if (!StringUtils.hasLength(owner.getLastName())) {
|
||||
errors.rejectValue("lastName", "required", "required");
|
||||
}
|
||||
if (!StringUtils.hasLength(owner.getAddress())) {
|
||||
errors.rejectValue("address", "required", "required");
|
||||
}
|
||||
if (!StringUtils.hasLength(owner.getCity())) {
|
||||
errors.rejectValue("city", "required", "required");
|
||||
}
|
||||
|
||||
String telephone = owner.getTelephone();
|
||||
if (!StringUtils.hasLength(telephone)) {
|
||||
errors.rejectValue("telephone", "required", "required");
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < telephone.length(); ++i) {
|
||||
if ((Character.isDigit(telephone.charAt(i))) == false) {
|
||||
errors.rejectValue("telephone", "nonNumeric", "non-numeric");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package org.springframework.samples.petclinic.validation;
|
||||
|
||||
import org.springframework.samples.petclinic.Pet;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.Errors;
|
||||
|
||||
/**
|
||||
* <code>Validator</code> for <code>Pet</code> forms.
|
||||
*
|
||||
* @author Ken Krebs
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class PetValidator {
|
||||
|
||||
public void validate(Pet pet, Errors errors) {
|
||||
String name = pet.getName();
|
||||
if (!StringUtils.hasLength(name)) {
|
||||
errors.rejectValue("name", "required", "required");
|
||||
}
|
||||
else if (pet.isNew() && pet.getOwner().getPet(name, true) != null) {
|
||||
errors.rejectValue("name", "duplicate", "already exists");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package org.springframework.samples.petclinic.validation;
|
||||
|
||||
import org.springframework.samples.petclinic.Visit;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.Errors;
|
||||
|
||||
/**
|
||||
* <code>Validator</code> for <code>Visit</code> forms.
|
||||
*
|
||||
* @author Ken Krebs
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class VisitValidator {
|
||||
|
||||
public void validate(Visit visit, Errors errors) {
|
||||
if (!StringUtils.hasLength(visit.getDescription())) {
|
||||
errors.rejectValue("description", "required", "required");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* The classes in this package represent the set of Validator objects
|
||||
* the Business Layer makes available to the Presentation Layer.
|
||||
*
|
||||
*/
|
||||
package org.springframework.samples.petclinic.validation;
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
|
||||
package org.springframework.samples.petclinic.web;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.samples.petclinic.Clinic;
|
||||
import org.springframework.samples.petclinic.Owner;
|
||||
import org.springframework.samples.petclinic.validation.OwnerValidator;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.annotation.InitBinder;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.SessionAttributes;
|
||||
import org.springframework.web.bind.support.SessionStatus;
|
||||
|
||||
/**
|
||||
* JavaBean form controller that is used to add a new <code>Owner</code> to the
|
||||
* system.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Ken Krebs
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/owners/new")
|
||||
@SessionAttributes(types = Owner.class)
|
||||
public class AddOwnerForm {
|
||||
|
||||
private final Clinic clinic;
|
||||
|
||||
|
||||
@Autowired
|
||||
public AddOwnerForm(Clinic clinic) {
|
||||
this.clinic = clinic;
|
||||
}
|
||||
|
||||
@InitBinder
|
||||
public void setAllowedFields(WebDataBinder dataBinder) {
|
||||
dataBinder.setDisallowedFields("id");
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET)
|
||||
public String setupForm(Model model) {
|
||||
Owner owner = new Owner();
|
||||
model.addAttribute(owner);
|
||||
return "owners/form";
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.POST)
|
||||
public String processSubmit(@ModelAttribute Owner owner, BindingResult result, SessionStatus status) {
|
||||
new OwnerValidator().validate(owner, result);
|
||||
if (result.hasErrors()) {
|
||||
return "owners/form";
|
||||
}
|
||||
else {
|
||||
this.clinic.storeOwner(owner);
|
||||
status.setComplete();
|
||||
return "redirect:/owners/" + owner.getId();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
|
||||
package org.springframework.samples.petclinic.web;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.samples.petclinic.Clinic;
|
||||
import org.springframework.samples.petclinic.Owner;
|
||||
import org.springframework.samples.petclinic.Pet;
|
||||
import org.springframework.samples.petclinic.PetType;
|
||||
import org.springframework.samples.petclinic.validation.PetValidator;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.annotation.InitBinder;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.SessionAttributes;
|
||||
import org.springframework.web.bind.support.SessionStatus;
|
||||
|
||||
/**
|
||||
* JavaBean form controller that is used to add a new <code>Pet</code> to the
|
||||
* system.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Ken Krebs
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/owners/{ownerId}/pets/new")
|
||||
@SessionAttributes("pet")
|
||||
public class AddPetForm {
|
||||
|
||||
private final Clinic clinic;
|
||||
|
||||
|
||||
@Autowired
|
||||
public AddPetForm(Clinic clinic) {
|
||||
this.clinic = clinic;
|
||||
}
|
||||
|
||||
@ModelAttribute("types")
|
||||
public Collection<PetType> populatePetTypes() {
|
||||
return this.clinic.getPetTypes();
|
||||
}
|
||||
|
||||
@InitBinder
|
||||
public void setAllowedFields(WebDataBinder dataBinder) {
|
||||
dataBinder.setDisallowedFields("id");
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET)
|
||||
public String setupForm(@PathVariable("ownerId") int ownerId, Model model) {
|
||||
Owner owner = this.clinic.loadOwner(ownerId);
|
||||
Pet pet = new Pet();
|
||||
owner.addPet(pet);
|
||||
model.addAttribute("pet", pet);
|
||||
return "pets/form";
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.POST)
|
||||
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result, SessionStatus status) {
|
||||
new PetValidator().validate(pet, result);
|
||||
if (result.hasErrors()) {
|
||||
return "pets/form";
|
||||
}
|
||||
else {
|
||||
this.clinic.storePet(pet);
|
||||
status.setComplete();
|
||||
return "redirect:/owners/" + pet.getOwner().getId();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
|
||||
package org.springframework.samples.petclinic.web;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.samples.petclinic.Clinic;
|
||||
import org.springframework.samples.petclinic.Pet;
|
||||
import org.springframework.samples.petclinic.Visit;
|
||||
import org.springframework.samples.petclinic.validation.VisitValidator;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.annotation.InitBinder;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.SessionAttributes;
|
||||
import org.springframework.web.bind.support.SessionStatus;
|
||||
|
||||
/**
|
||||
* JavaBean form controller that is used to add a new <code>Visit</code> to the
|
||||
* system.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Ken Krebs
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/owners/*/pets/{petId}/visits/new")
|
||||
@SessionAttributes("visit")
|
||||
public class AddVisitForm {
|
||||
|
||||
private final Clinic clinic;
|
||||
|
||||
|
||||
@Autowired
|
||||
public AddVisitForm(Clinic clinic) {
|
||||
this.clinic = clinic;
|
||||
}
|
||||
|
||||
@InitBinder
|
||||
public void setAllowedFields(WebDataBinder dataBinder) {
|
||||
dataBinder.setDisallowedFields("id");
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET)
|
||||
public String setupForm(@PathVariable("petId") int petId, Model model) {
|
||||
Pet pet = this.clinic.loadPet(petId);
|
||||
Visit visit = new Visit();
|
||||
pet.addVisit(visit);
|
||||
model.addAttribute("visit", visit);
|
||||
return "pets/visitForm";
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.POST)
|
||||
public String processSubmit(@ModelAttribute("visit") Visit visit, BindingResult result, SessionStatus status) {
|
||||
new VisitValidator().validate(visit, result);
|
||||
if (result.hasErrors()) {
|
||||
return "pets/visitForm";
|
||||
}
|
||||
else {
|
||||
this.clinic.storeVisit(visit);
|
||||
status.setComplete();
|
||||
return "redirect:/owners/" + visit.getPet().getOwner().getId();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package org.springframework.samples.petclinic.web;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.propertyeditors.CustomDateEditor;
|
||||
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
|
||||
import org.springframework.samples.petclinic.Clinic;
|
||||
import org.springframework.samples.petclinic.PetType;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.support.WebBindingInitializer;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
|
||||
/**
|
||||
* Shared WebBindingInitializer for PetClinic's custom editors.
|
||||
*
|
||||
* <p>Alternatively, such init-binder code may be put into
|
||||
* {@link org.springframework.web.bind.annotation.InitBinder}
|
||||
* annotated methods on the controller classes themselves.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class ClinicBindingInitializer implements WebBindingInitializer {
|
||||
|
||||
@Autowired
|
||||
private Clinic clinic;
|
||||
|
||||
public void initBinder(WebDataBinder binder, WebRequest request) {
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
||||
dateFormat.setLenient(false);
|
||||
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
|
||||
binder.registerCustomEditor(String.class, new StringTrimmerEditor(false));
|
||||
binder.registerCustomEditor(PetType.class, new PetTypeEditor(this.clinic));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
|
||||
package org.springframework.samples.petclinic.web;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.samples.petclinic.Clinic;
|
||||
import org.springframework.samples.petclinic.Vets;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
/**
|
||||
* Annotation-driven <em>MultiActionController</em> that handles all non-form
|
||||
* URL's.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Mark Fisher
|
||||
* @author Ken Krebs
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
@Controller
|
||||
public class ClinicController {
|
||||
|
||||
private final Clinic clinic;
|
||||
|
||||
|
||||
@Autowired
|
||||
public ClinicController(Clinic clinic) {
|
||||
this.clinic = clinic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom handler for the welcome view.
|
||||
* <p>
|
||||
* Note that this handler relies on the RequestToViewNameTranslator to
|
||||
* determine the logical view name based on the request URL: "/welcome.do"
|
||||
* -> "welcome".
|
||||
*/
|
||||
@RequestMapping("/")
|
||||
public String welcomeHandler() {
|
||||
return "welcome";
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom handler for displaying vets.
|
||||
*
|
||||
* <p>Note that this handler returns a plain {@link ModelMap} object instead of
|
||||
* a ModelAndView, thus leveraging convention-based model attribute names.
|
||||
* It relies on the RequestToViewNameTranslator to determine the logical
|
||||
* view name based on the request URL: "/vets.do" -> "vets".
|
||||
*
|
||||
* @return a ModelMap with the model attributes for the view
|
||||
*/
|
||||
@RequestMapping("/vets")
|
||||
public ModelMap vetsHandler() {
|
||||
Vets vets = new Vets();
|
||||
vets.getVetList().addAll(this.clinic.getVets());
|
||||
return new ModelMap(vets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom handler for displaying an owner.
|
||||
*
|
||||
* @param ownerId the ID of the owner to display
|
||||
* @return a ModelMap with the model attributes for the view
|
||||
*/
|
||||
@RequestMapping("/owners/{ownerId}")
|
||||
public ModelAndView ownerHandler(@PathVariable("ownerId") int ownerId) {
|
||||
ModelAndView mav = new ModelAndView("owners/show");
|
||||
mav.addObject(this.clinic.loadOwner(ownerId));
|
||||
return mav;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom handler for displaying an list of visits.
|
||||
*
|
||||
* @param petId the ID of the pet whose visits to display
|
||||
* @return a ModelMap with the model attributes for the view
|
||||
*/
|
||||
@RequestMapping(value="/owners/*/pets/{petId}/visits", method=RequestMethod.GET)
|
||||
public ModelAndView visitsHandler(@PathVariable int petId) {
|
||||
ModelAndView mav = new ModelAndView("visits");
|
||||
mav.addObject("visits", this.clinic.loadPet(petId).getVisits());
|
||||
return mav;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
|
||||
package org.springframework.samples.petclinic.web;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.samples.petclinic.Clinic;
|
||||
import org.springframework.samples.petclinic.Owner;
|
||||
import org.springframework.samples.petclinic.validation.OwnerValidator;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.annotation.InitBinder;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.SessionAttributes;
|
||||
import org.springframework.web.bind.support.SessionStatus;
|
||||
|
||||
/**
|
||||
* JavaBean Form controller that is used to edit an existing <code>Owner</code>.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Ken Krebs
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/owners/{ownerId}/edit")
|
||||
@SessionAttributes(types = Owner.class)
|
||||
public class EditOwnerForm {
|
||||
|
||||
private final Clinic clinic;
|
||||
|
||||
|
||||
@Autowired
|
||||
public EditOwnerForm(Clinic clinic) {
|
||||
this.clinic = clinic;
|
||||
}
|
||||
|
||||
@InitBinder
|
||||
public void setAllowedFields(WebDataBinder dataBinder) {
|
||||
dataBinder.setDisallowedFields("id");
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET)
|
||||
public String setupForm(@PathVariable("ownerId") int ownerId, Model model) {
|
||||
Owner owner = this.clinic.loadOwner(ownerId);
|
||||
model.addAttribute(owner);
|
||||
return "owners/form";
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.PUT)
|
||||
public String processSubmit(@ModelAttribute Owner owner, BindingResult result, SessionStatus status) {
|
||||
new OwnerValidator().validate(owner, result);
|
||||
if (result.hasErrors()) {
|
||||
return "owners/form";
|
||||
}
|
||||
else {
|
||||
this.clinic.storeOwner(owner);
|
||||
status.setComplete();
|
||||
return "redirect:/owners/" + owner.getId();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
|
||||
package org.springframework.samples.petclinic.web;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.samples.petclinic.Clinic;
|
||||
import org.springframework.samples.petclinic.Pet;
|
||||
import org.springframework.samples.petclinic.PetType;
|
||||
import org.springframework.samples.petclinic.validation.PetValidator;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.annotation.InitBinder;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.SessionAttributes;
|
||||
import org.springframework.web.bind.support.SessionStatus;
|
||||
|
||||
/**
|
||||
* JavaBean Form controller that is used to edit an existing <code>Pet</code>.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Ken Krebs
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/owners/*/pets/{petId}/edit")
|
||||
@SessionAttributes("pet")
|
||||
public class EditPetForm {
|
||||
|
||||
private final Clinic clinic;
|
||||
|
||||
|
||||
@Autowired
|
||||
public EditPetForm(Clinic clinic) {
|
||||
this.clinic = clinic;
|
||||
}
|
||||
|
||||
@ModelAttribute("types")
|
||||
public Collection<PetType> populatePetTypes() {
|
||||
return this.clinic.getPetTypes();
|
||||
}
|
||||
|
||||
@InitBinder
|
||||
public void setAllowedFields(WebDataBinder dataBinder) {
|
||||
dataBinder.setDisallowedFields("id");
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET)
|
||||
public String setupForm(@PathVariable("petId") int petId, Model model) {
|
||||
Pet pet = this.clinic.loadPet(petId);
|
||||
model.addAttribute("pet", pet);
|
||||
return "pets/form";
|
||||
}
|
||||
|
||||
@RequestMapping(method = { RequestMethod.PUT, RequestMethod.POST })
|
||||
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result, SessionStatus status) {
|
||||
new PetValidator().validate(pet, result);
|
||||
if (result.hasErrors()) {
|
||||
return "pets/form";
|
||||
}
|
||||
else {
|
||||
this.clinic.storePet(pet);
|
||||
status.setComplete();
|
||||
return "redirect:/owners/" + pet.getOwner().getId();
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.DELETE)
|
||||
public String deletePet(@PathVariable int petId) {
|
||||
Pet pet = this.clinic.loadPet(petId);
|
||||
this.clinic.deletePet(petId);
|
||||
return "redirect:/owners/" + pet.getOwner().getId();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
|
||||
package org.springframework.samples.petclinic.web;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.samples.petclinic.Clinic;
|
||||
import org.springframework.samples.petclinic.Owner;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.annotation.InitBinder;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
/**
|
||||
* JavaBean Form controller that is used to search for <code>Owner</code>s by
|
||||
* last name.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Ken Krebs
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
@Controller
|
||||
public class FindOwnersForm {
|
||||
|
||||
private final Clinic clinic;
|
||||
|
||||
|
||||
@Autowired
|
||||
public FindOwnersForm(Clinic clinic) {
|
||||
this.clinic = clinic;
|
||||
}
|
||||
|
||||
@InitBinder
|
||||
public void setAllowedFields(WebDataBinder dataBinder) {
|
||||
dataBinder.setDisallowedFields("id");
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/owners/search", method = RequestMethod.GET)
|
||||
public String setupForm(Model model) {
|
||||
model.addAttribute("owner", new Owner());
|
||||
return "owners/search";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/owners", method = RequestMethod.GET)
|
||||
public String processSubmit(Owner owner, BindingResult result, Model model) {
|
||||
|
||||
// allow parameterless GET request for /owners to return all records
|
||||
if (owner.getLastName() == null) {
|
||||
owner.setLastName(""); // empty string signifies broadest possible search
|
||||
}
|
||||
|
||||
// find owners by last name
|
||||
Collection<Owner> results = this.clinic.findOwners(owner.getLastName());
|
||||
if (results.size() < 1) {
|
||||
// no owners found
|
||||
result.rejectValue("lastName", "notFound", "not found");
|
||||
return "owners/search";
|
||||
}
|
||||
if (results.size() > 1) {
|
||||
// multiple owners found
|
||||
model.addAttribute("selections", results);
|
||||
return "owners/list";
|
||||
}
|
||||
else {
|
||||
// 1 owner found
|
||||
owner = results.iterator().next();
|
||||
return "redirect:/owners/" + owner.getId();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package org.springframework.samples.petclinic.web;
|
||||
|
||||
import java.beans.PropertyEditorSupport;
|
||||
|
||||
import org.springframework.samples.petclinic.Clinic;
|
||||
import org.springframework.samples.petclinic.PetType;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class PetTypeEditor extends PropertyEditorSupport {
|
||||
|
||||
private final Clinic clinic;
|
||||
|
||||
|
||||
public PetTypeEditor(Clinic clinic) {
|
||||
this.clinic = clinic;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAsText(String text) throws IllegalArgumentException {
|
||||
for (PetType type : this.clinic.getPetTypes()) {
|
||||
if (type.getName().equals(text)) {
|
||||
setValue(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright 2002-2009 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.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.sun.syndication.feed.atom.Content;
|
||||
import com.sun.syndication.feed.atom.Entry;
|
||||
import com.sun.syndication.feed.atom.Feed;
|
||||
|
||||
import org.springframework.samples.petclinic.Visit;
|
||||
import org.springframework.web.servlet.view.feed.AbstractAtomFeedView;
|
||||
|
||||
/**
|
||||
* A view creating a Atom representation from a list of Visit objects.
|
||||
*
|
||||
* @author Alef Arendsen
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
public class VisitsAtomView extends AbstractAtomFeedView {
|
||||
|
||||
@Override
|
||||
protected void buildFeedMetadata(Map<String, Object> model, Feed feed, HttpServletRequest request) {
|
||||
feed.setId("tag:springsource.com");
|
||||
feed.setTitle("Pet Clinic Visits");
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Visit> visits = (List<Visit>) model.get("visits");
|
||||
for (Visit visit : visits) {
|
||||
Date date = visit.getDate();
|
||||
if (feed.getUpdated() == null || date.compareTo(feed.getUpdated()) > 0) {
|
||||
feed.setUpdated(date);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Entry> buildFeedEntries(Map<String, Object> model,
|
||||
HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Visit> visits = (List<Visit>) model.get("visits");
|
||||
List<Entry> entries = new ArrayList<Entry>(visits.size());
|
||||
|
||||
for (Visit visit : visits) {
|
||||
Entry entry = new Entry();
|
||||
String date = String.format("%1$tY-%1$tm-%1$td", visit.getDate());
|
||||
// see http://diveintomark.org/archives/2004/05/28/howto-atom-id#other
|
||||
entry.setId(String.format("tag:springsource.com,%s:%d", date, visit.getId()));
|
||||
entry.setTitle(String.format("%s visit on %s", visit.getPet().getName(), date));
|
||||
entry.setUpdated(visit.getDate());
|
||||
|
||||
Content summary = new Content();
|
||||
summary.setValue(visit.getDescription());
|
||||
entry.setSummary(summary);
|
||||
|
||||
entries.add(entry);
|
||||
}
|
||||
|
||||
return entries;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* The classes in this package represent PetClinic's web presentation layer.
|
||||
*
|
||||
*/
|
||||
package org.springframework.samples.petclinic.web;
|
||||
|
7
src/main/java/overview.html
Normal file
7
src/main/java/overview.html
Normal file
|
@ -0,0 +1,7 @@
|
|||
<html>
|
||||
<body>
|
||||
<p>
|
||||
The Spring Data Binding framework, an internal library used by Spring Web Flow.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
63
src/main/resources/jdbc.properties
Normal file
63
src/main/resources/jdbc.properties
Normal file
|
@ -0,0 +1,63 @@
|
|||
# Properties file with JDBC and JPA settings.
|
||||
#
|
||||
# Applied by <context:property-placeholder location="jdbc.properties"/> from
|
||||
# various application context XML files (e.g., "applicationContext-*.xml").
|
||||
# Targeted at system administrators, to avoid touching the context XML files.
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Common Settings
|
||||
|
||||
hibernate.generate_statistics=true
|
||||
hibernate.show_sql=true
|
||||
jpa.showSql=true
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# HSQL Settings
|
||||
|
||||
jdbc.driverClassName=org.hsqldb.jdbcDriver
|
||||
jdbc.url=jdbc:hsqldb:mem:petclinic
|
||||
jdbc.username=sa
|
||||
jdbc.password=
|
||||
|
||||
# Properties that control the population of schema and data for a new data source
|
||||
jdbc.populate=true
|
||||
jdbc.schemaLocation=classpath:/META-INF/hsqldb/initDB.txt
|
||||
jdbc.dataLocation=classpath:/META-INF/hsqldb/populateDB.txt
|
||||
jdbc.dropLocation=classpath:/META-INF/hsqldb/dropTables.txt
|
||||
|
||||
# Property that determines which Hibernate dialect to use
|
||||
# (only applied with "applicationContext-hibernate.xml")
|
||||
hibernate.dialect=org.hibernate.dialect.HSQLDialect
|
||||
|
||||
# Property that determines which JPA DatabasePlatform to use with TopLink Essentials
|
||||
jpa.databasePlatform=org.springframework.samples.petclinic.toplink.EssentialsHSQLPlatformWithNativeSequence
|
||||
|
||||
# Property that determines which database to use with an AbstractJpaVendorAdapter
|
||||
jpa.database=HSQL
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# MySQL Settings
|
||||
|
||||
#jdbc.driverClassName=com.mysql.jdbc.Driver
|
||||
#jdbc.url=jdbc:mysql://localhost:3306/petclinic
|
||||
#jdbc.username=pc
|
||||
#jdbc.password=pc
|
||||
|
||||
# Properties that control the population of schema and data for a new data source
|
||||
#jdbc.populate=false
|
||||
#jdbc.schemaLocation=
|
||||
#jdbc.dataLocation=
|
||||
#jdbc.dropLocation=
|
||||
|
||||
# Property that determines which Hibernate dialect to use
|
||||
# (only applied with "applicationContext-hibernate.xml")
|
||||
#hibernate.dialect=org.hibernate.dialect.MySQLDialect
|
||||
|
||||
# Property that determines which JPA DatabasePlatform to use with TopLink Essentials
|
||||
#jpa.databasePlatform=oracle.toplink.essentials.platform.database.MySQL4Platform
|
||||
|
||||
# Property that determines which database to use with an AbstractJpaVendorAdapter
|
||||
#jpa.database=MYSQL
|
18
src/main/resources/log4j.properties
Normal file
18
src/main/resources/log4j.properties
Normal file
|
@ -0,0 +1,18 @@
|
|||
# For JBoss: Avoid to setup Log4J outside $JBOSS_HOME/server/default/deploy/log4j.xml!
|
||||
# For all other servers: Comment out the Log4J listener in web.xml to activate Log4J.
|
||||
log4j.rootLogger=INFO, stdout, logfile
|
||||
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n
|
||||
|
||||
log4j.appender.logfile=org.apache.log4j.RollingFileAppender
|
||||
log4j.appender.logfile.File=${petclinic.root}/WEB-INF/petclinic.log
|
||||
log4j.appender.logfile.MaxFileSize=512KB
|
||||
# Keep three backup files.
|
||||
log4j.appender.logfile.MaxBackupIndex=3
|
||||
# Pattern to output: date priority [category] - message
|
||||
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
|
||||
|
||||
log4j.logger.org.springframework.samples.petclinic.aspects=DEBUG
|
8
src/main/resources/messages.properties
Normal file
8
src/main/resources/messages.properties
Normal file
|
@ -0,0 +1,8 @@
|
|||
welcome=Welcome
|
||||
required=is required
|
||||
notFound=has not been found
|
||||
duplicate=is already in use
|
||||
nonNumeric=must be all numeric
|
||||
duplicateFormSubmission=Duplicate form submission is not allowed
|
||||
typeMismatch.date=invalid date
|
||||
typeMismatch.birthDate=invalid date
|
8
src/main/resources/messages_de.properties
Normal file
8
src/main/resources/messages_de.properties
Normal file
|
@ -0,0 +1,8 @@
|
|||
welcome=Willkommen
|
||||
required=muss angegeben werden
|
||||
notFound=wurde nicht gefunden
|
||||
duplicate=ist bereits vergeben
|
||||
nonNumeric=darf nur numerisch sein
|
||||
duplicateFormSubmission=Wiederholtes Absenden des Formulars ist nicht erlaubt
|
||||
typeMismatch.date=ungültiges Datum
|
||||
typeMismatch.birthDate=ungültiges Datum
|
1
src/main/resources/messages_en.properties
Normal file
1
src/main/resources/messages_en.properties
Normal file
|
@ -0,0 +1 @@
|
|||
# This file is intentionally empty. Message look-ups will fall back to the default "messages.properties" file.
|
74
src/main/resources/petclinic.hbm.xml
Normal file
74
src/main/resources/petclinic.hbm.xml
Normal file
|
@ -0,0 +1,74 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
|
||||
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
|
||||
|
||||
<!--
|
||||
- Mapping file for the Hibernate implementation of the Clinic interface.
|
||||
-->
|
||||
<hibernate-mapping auto-import="true" default-lazy="false">
|
||||
|
||||
<class name="org.springframework.samples.petclinic.Vet" table="vets">
|
||||
<id name="id" column="id">
|
||||
<generator class="identity"/>
|
||||
</id>
|
||||
<property name="firstName" column="first_name"/>
|
||||
<property name="lastName" column="last_name"/>
|
||||
<set name="specialtiesInternal" table="vet_specialties">
|
||||
<key column="vet_id"/>
|
||||
<many-to-many column="specialty_id" class="org.springframework.samples.petclinic.Specialty"/>
|
||||
</set>
|
||||
</class>
|
||||
|
||||
<class name="org.springframework.samples.petclinic.Specialty" table="specialties">
|
||||
<id name="id" column="id">
|
||||
<generator class="identity"/>
|
||||
</id>
|
||||
<property name="name" column="name"/>
|
||||
</class>
|
||||
|
||||
<class name="org.springframework.samples.petclinic.Owner" table="owners">
|
||||
<id name="id" column="id">
|
||||
<generator class="identity"/>
|
||||
</id>
|
||||
<property name="firstName" column="first_name"/>
|
||||
<property name="lastName" column="last_name"/>
|
||||
<property name="address" column="address"/>
|
||||
<property name="city" column="city"/>
|
||||
<property name="telephone" column="telephone"/>
|
||||
<set name="petsInternal" inverse="true" cascade="all">
|
||||
<key column="owner_id"/>
|
||||
<one-to-many class="org.springframework.samples.petclinic.Pet"/>
|
||||
</set>
|
||||
</class>
|
||||
|
||||
<class name="org.springframework.samples.petclinic.Pet" table="pets">
|
||||
<id name="id" column="id">
|
||||
<generator class="identity"/>
|
||||
</id>
|
||||
<property name="name" column="name"/>
|
||||
<property name="birthDate" column="birth_date" type="date"/>
|
||||
<many-to-one name="owner" column="owner_id" class="org.springframework.samples.petclinic.Owner"/>
|
||||
<many-to-one name="type" column="type_id" class="org.springframework.samples.petclinic.PetType"/>
|
||||
<set name="visitsInternal" inverse="true" cascade="all">
|
||||
<key column="pet_id"/>
|
||||
<one-to-many class="org.springframework.samples.petclinic.Visit"/>
|
||||
</set>
|
||||
</class>
|
||||
|
||||
<class name="org.springframework.samples.petclinic.PetType" table="types">
|
||||
<id name="id" column="id">
|
||||
<generator class="identity"/>
|
||||
</id>
|
||||
<property name="name" column="name"/>
|
||||
</class>
|
||||
|
||||
<class name="org.springframework.samples.petclinic.Visit" table="visits">
|
||||
<id name="id" column="id">
|
||||
<generator class="identity"/>
|
||||
</id>
|
||||
<property name="date" column="visit_date" type="date"/>
|
||||
<property name="description" column="description"/>
|
||||
<many-to-one name="pet" column="pet_id" class="org.springframework.samples.petclinic.Pet"/>
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>
|
18
src/main/webapp/META-INF/aop.xml
Normal file
18
src/main/webapp/META-INF/aop.xml
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<!-- Custom aspects for the PetClinic sample application -->
|
||||
<aspectj>
|
||||
|
||||
<weaver>
|
||||
<include within="org.springframework.samples.petclinic..*"/>
|
||||
</weaver>
|
||||
|
||||
<aspects>
|
||||
<aspect name="org.springframework.samples.petclinic.aspects.UsageLogAspect"/>
|
||||
<concrete-aspect name="org.springframework.samples.petclinic.aspects.ApplicationTraceAspect"
|
||||
extends="org.springframework.samples.petclinic.aspects.AbstractTraceAspect">
|
||||
<pointcut name="traced" expression="execution(* org.springframework.samples..*.*(..))"/>
|
||||
</concrete-aspect>
|
||||
</aspects>
|
||||
|
||||
</aspectj>
|
7
src/main/webapp/META-INF/context.xml
Normal file
7
src/main/webapp/META-INF/context.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<!-- Tomcat context descriptor used for specifying a custom ClassLoader -->
|
||||
<Context path="/petclinic" reloadable="false">
|
||||
<!-- please note that useSystemClassLoaderAsParent is available since Tomcat 5.5.20 / remove if previous versions are being used -->
|
||||
<!--
|
||||
<Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader" useSystemClassLoaderAsParent="false"/>
|
||||
-->
|
||||
</Context>
|
7
src/main/webapp/META-INF/hsqldb/dropTables.txt
Normal file
7
src/main/webapp/META-INF/hsqldb/dropTables.txt
Normal file
|
@ -0,0 +1,7 @@
|
|||
DROP TABLE visits;
|
||||
DROP TABLE pets;
|
||||
DROP TABLE owners;
|
||||
DROP TABLE types;
|
||||
DROP TABLE vet_specialties;
|
||||
DROP TABLE specialties;
|
||||
DROP TABLE vets;
|
55
src/main/webapp/META-INF/hsqldb/initDB.txt
Normal file
55
src/main/webapp/META-INF/hsqldb/initDB.txt
Normal file
|
@ -0,0 +1,55 @@
|
|||
CREATE TABLE vets (
|
||||
id INTEGER NOT NULL IDENTITY PRIMARY KEY,
|
||||
first_name VARCHAR(30),
|
||||
last_name VARCHAR(30)
|
||||
);
|
||||
CREATE INDEX vets_last_name ON vets(last_name);
|
||||
|
||||
CREATE TABLE specialties (
|
||||
id INTEGER NOT NULL IDENTITY PRIMARY KEY,
|
||||
name VARCHAR(80)
|
||||
);
|
||||
CREATE INDEX specialties_name ON specialties(name);
|
||||
|
||||
CREATE TABLE vet_specialties (
|
||||
vet_id INTEGER NOT NULL,
|
||||
specialty_id INTEGER NOT NULL
|
||||
);
|
||||
alter table vet_specialties add constraint fk_vet_specialties_vets foreign key (vet_id) references vets(id);
|
||||
alter table vet_specialties add constraint fk_vet_specialties_specialties foreign key (specialty_id) references specialties(id);
|
||||
|
||||
CREATE TABLE types (
|
||||
id INTEGER NOT NULL IDENTITY PRIMARY KEY,
|
||||
name VARCHAR(80)
|
||||
);
|
||||
CREATE INDEX types_name ON types(name);
|
||||
|
||||
CREATE TABLE owners (
|
||||
id INTEGER NOT NULL IDENTITY PRIMARY KEY,
|
||||
first_name VARCHAR(30),
|
||||
last_name VARCHAR(30),
|
||||
address VARCHAR(255),
|
||||
city VARCHAR(80),
|
||||
telephone VARCHAR(20)
|
||||
);
|
||||
CREATE INDEX owners_last_name ON owners(last_name);
|
||||
|
||||
CREATE TABLE pets (
|
||||
id INTEGER NOT NULL IDENTITY PRIMARY KEY,
|
||||
name VARCHAR(30),
|
||||
birth_date DATE,
|
||||
type_id INTEGER NOT NULL,
|
||||
owner_id INTEGER NOT NULL
|
||||
);
|
||||
alter table pets add constraint fk_pets_owners foreign key (owner_id) references owners(id);
|
||||
alter table pets add constraint fk_pets_types foreign key (type_id) references types(id);
|
||||
CREATE INDEX pets_name ON pets(name);
|
||||
|
||||
CREATE TABLE visits (
|
||||
id INTEGER NOT NULL IDENTITY PRIMARY KEY,
|
||||
pet_id INTEGER NOT NULL,
|
||||
visit_date DATE,
|
||||
description VARCHAR(255)
|
||||
);
|
||||
alter table visits add constraint fk_visits_pets foreign key (pet_id) references pets(id);
|
||||
CREATE INDEX visits_pet_id ON visits(pet_id);
|
53
src/main/webapp/META-INF/hsqldb/populateDB.txt
Normal file
53
src/main/webapp/META-INF/hsqldb/populateDB.txt
Normal file
|
@ -0,0 +1,53 @@
|
|||
INSERT INTO vets VALUES (1, 'James', 'Carter');
|
||||
INSERT INTO vets VALUES (2, 'Helen', 'Leary');
|
||||
INSERT INTO vets VALUES (3, 'Linda', 'Douglas');
|
||||
INSERT INTO vets VALUES (4, 'Rafael', 'Ortega');
|
||||
INSERT INTO vets VALUES (5, 'Henry', 'Stevens');
|
||||
INSERT INTO vets VALUES (6, 'Sharon', 'Jenkins');
|
||||
|
||||
INSERT INTO specialties VALUES (1, 'radiology');
|
||||
INSERT INTO specialties VALUES (2, 'surgery');
|
||||
INSERT INTO specialties VALUES (3, 'dentistry');
|
||||
|
||||
INSERT INTO vet_specialties VALUES (2, 1);
|
||||
INSERT INTO vet_specialties VALUES (3, 2);
|
||||
INSERT INTO vet_specialties VALUES (3, 3);
|
||||
INSERT INTO vet_specialties VALUES (4, 2);
|
||||
INSERT INTO vet_specialties VALUES (5, 1);
|
||||
|
||||
INSERT INTO types VALUES (1, 'cat');
|
||||
INSERT INTO types VALUES (2, 'dog');
|
||||
INSERT INTO types VALUES (3, 'lizard');
|
||||
INSERT INTO types VALUES (4, 'snake');
|
||||
INSERT INTO types VALUES (5, 'bird');
|
||||
INSERT INTO types VALUES (6, 'hamster');
|
||||
|
||||
INSERT INTO owners VALUES (1, 'George', 'Franklin', '110 W. Liberty St.', 'Madison', '6085551023');
|
||||
INSERT INTO owners VALUES (2, 'Betty', 'Davis', '638 Cardinal Ave.', 'Sun Prairie', '6085551749');
|
||||
INSERT INTO owners VALUES (3, 'Eduardo', 'Rodriquez', '2693 Commerce St.', 'McFarland', '6085558763');
|
||||
INSERT INTO owners VALUES (4, 'Harold', 'Davis', '563 Friendly St.', 'Windsor', '6085553198');
|
||||
INSERT INTO owners VALUES (5, 'Peter', 'McTavish', '2387 S. Fair Way', 'Madison', '6085552765');
|
||||
INSERT INTO owners VALUES (6, 'Jean', 'Coleman', '105 N. Lake St.', 'Monona', '6085552654');
|
||||
INSERT INTO owners VALUES (7, 'Jeff', 'Black', '1450 Oak Blvd.', 'Monona', '6085555387');
|
||||
INSERT INTO owners VALUES (8, 'Maria', 'Escobito', '345 Maple St.', 'Madison', '6085557683');
|
||||
INSERT INTO owners VALUES (9, 'David', 'Schroeder', '2749 Blackhawk Trail', 'Madison', '6085559435');
|
||||
INSERT INTO owners VALUES (10, 'Carlos', 'Estaban', '2335 Independence La.', 'Waunakee', '6085555487');
|
||||
|
||||
INSERT INTO pets VALUES (1, 'Leo', '2000-09-07', 1, 1);
|
||||
INSERT INTO pets VALUES (2, 'Basil', '2002-08-06', 6, 2);
|
||||
INSERT INTO pets VALUES (3, 'Rosy', '2001-04-17', 2, 3);
|
||||
INSERT INTO pets VALUES (4, 'Jewel', '2000-03-07', 2, 3);
|
||||
INSERT INTO pets VALUES (5, 'Iggy', '2000-11-30', 3, 4);
|
||||
INSERT INTO pets VALUES (6, 'George', '2000-01-20', 4, 5);
|
||||
INSERT INTO pets VALUES (7, 'Samantha', '1995-09-04', 1, 6);
|
||||
INSERT INTO pets VALUES (8, 'Max', '1995-09-04', 1, 6);
|
||||
INSERT INTO pets VALUES (9, 'Lucky', '1999-08-06', 5, 7);
|
||||
INSERT INTO pets VALUES (10, 'Mulligan', '1997-02-24', 2, 8);
|
||||
INSERT INTO pets VALUES (11, 'Freddy', '2000-03-09', 5, 9);
|
||||
INSERT INTO pets VALUES (12, 'Lucky', '2000-06-24', 2, 10);
|
||||
INSERT INTO pets VALUES (13, 'Sly', '2002-06-08', 1, 10);
|
||||
|
||||
INSERT INTO visits VALUES (1, 7, '1996-03-04', 'rabies shot');
|
||||
INSERT INTO visits VALUES (2, 8, '1996-03-04', 'rabies shot');
|
||||
INSERT INTO visits VALUES (3, 8, '1996-06-04', 'neutered');
|
||||
INSERT INTO visits VALUES (4, 7, '1996-09-04', 'spayed');
|
122
src/main/webapp/META-INF/orm.xml
Normal file
122
src/main/webapp/META-INF/orm.xml
Normal file
|
@ -0,0 +1,122 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd"
|
||||
version="1.0">
|
||||
|
||||
<persistence-unit-metadata>
|
||||
<xml-mapping-metadata-complete/>
|
||||
<persistence-unit-defaults>
|
||||
<access>PROPERTY</access>
|
||||
</persistence-unit-defaults>
|
||||
</persistence-unit-metadata>
|
||||
|
||||
<package>org.springframework.samples.petclinic</package>
|
||||
|
||||
<mapped-superclass class="BaseEntity">
|
||||
<attributes>
|
||||
<id name="id">
|
||||
<generated-value strategy="IDENTITY"/>
|
||||
</id>
|
||||
<transient name="new"/>
|
||||
</attributes>
|
||||
</mapped-superclass>
|
||||
|
||||
<mapped-superclass class="NamedEntity">
|
||||
<attributes>
|
||||
<basic name="name">
|
||||
<column name="NAME"/>
|
||||
</basic>
|
||||
</attributes>
|
||||
</mapped-superclass>
|
||||
|
||||
<mapped-superclass class="Person">
|
||||
<attributes>
|
||||
<basic name="firstName">
|
||||
<column name="FIRST_NAME"/>
|
||||
</basic>
|
||||
<basic name="lastName">
|
||||
<column name="LAST_NAME"/>
|
||||
</basic>
|
||||
</attributes>
|
||||
</mapped-superclass>
|
||||
|
||||
<entity class="Vet">
|
||||
<table name="VETS"/>
|
||||
<attributes>
|
||||
<many-to-many name="specialtiesInternal" target-entity="Specialty" fetch="EAGER">
|
||||
<join-table name="VET_SPECIALTIES">
|
||||
<join-column name="VET_ID"/>
|
||||
<inverse-join-column name="SPECIALTY_ID"/>
|
||||
</join-table>
|
||||
</many-to-many>
|
||||
<transient name="specialties"/>
|
||||
<transient name="nrOfSpecialties"/>
|
||||
</attributes>
|
||||
</entity>
|
||||
|
||||
<entity class="Specialty">
|
||||
<table name="SPECIALTIES"/>
|
||||
</entity>
|
||||
|
||||
<entity class="Owner">
|
||||
<table name="OWNERS"/>
|
||||
<attributes>
|
||||
<basic name="address"/>
|
||||
<basic name="city"/>
|
||||
<basic name="telephone"/>
|
||||
<one-to-many name="petsInternal" target-entity="Pet" mapped-by="owner" fetch="EAGER">
|
||||
<cascade>
|
||||
<cascade-all/>
|
||||
</cascade>
|
||||
</one-to-many>
|
||||
<transient name="pets"/>
|
||||
</attributes>
|
||||
</entity>
|
||||
|
||||
<entity class="Pet">
|
||||
<table name="PETS"/>
|
||||
<attributes>
|
||||
<basic name="birthDate">
|
||||
<column name="BIRTH_DATE"/>
|
||||
<temporal>DATE</temporal>
|
||||
</basic>
|
||||
<many-to-one name="owner" fetch="EAGER">
|
||||
<cascade>
|
||||
<cascade-all/>
|
||||
</cascade>
|
||||
</many-to-one>
|
||||
<many-to-one name="type" fetch="EAGER">
|
||||
<cascade>
|
||||
<cascade-all/>
|
||||
</cascade>
|
||||
</many-to-one>
|
||||
<one-to-many name="visitsInternal" target-entity="Visit" mapped-by="pet" fetch="EAGER">
|
||||
<cascade>
|
||||
<cascade-all/>
|
||||
</cascade>
|
||||
</one-to-many>
|
||||
<transient name="visits"/>
|
||||
</attributes>
|
||||
</entity>
|
||||
|
||||
<entity class="PetType">
|
||||
<table name="TYPES"/>
|
||||
</entity>
|
||||
|
||||
<entity class="Visit">
|
||||
<table name="VISITS"/>
|
||||
<attributes>
|
||||
<basic name="date">
|
||||
<column name="VISIT_DATE"/>
|
||||
<temporal>DATE</temporal>
|
||||
</basic>
|
||||
<many-to-one name="pet" fetch="EAGER">
|
||||
<cascade>
|
||||
<cascade-all/>
|
||||
</cascade>
|
||||
</many-to-one>
|
||||
</attributes>
|
||||
</entity>
|
||||
|
||||
</entity-mappings>
|
16
src/main/webapp/META-INF/persistence.xml
Normal file
16
src/main/webapp/META-INF/persistence.xml
Normal file
|
@ -0,0 +1,16 @@
|
|||
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
|
||||
version="1.0">
|
||||
|
||||
<persistence-unit name="PetClinic" transaction-type="RESOURCE_LOCAL">
|
||||
|
||||
<!-- Explicitly define mapping file path, else Hibernate won't find the default -->
|
||||
<mapping-file>META-INF/orm.xml</mapping-file>
|
||||
|
||||
<!-- Prevent annotation scanning. In this app we are purely driven by orm.xml -->
|
||||
<exclude-unlisted-classes>true</exclude-unlisted-classes>
|
||||
|
||||
</persistence-unit>
|
||||
|
||||
</persistence>
|
89
src/main/webapp/WEB-INF/applicationContext-hibernate.xml
Normal file
89
src/main/webapp/WEB-INF/applicationContext-hibernate.xml
Normal file
|
@ -0,0 +1,89 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Application context definition for PetClinic on Hibernate.
|
||||
-->
|
||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
|
||||
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
|
||||
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
|
||||
|
||||
<!-- ========================= RESOURCE DEFINITIONS ========================= -->
|
||||
|
||||
<!-- Configurer that replaces ${...} placeholders with values from a properties file -->
|
||||
<!-- (in this case, JDBC-related settings for the dataSource definition below) -->
|
||||
<context:property-placeholder location="classpath:jdbc.properties"/>
|
||||
|
||||
<!--
|
||||
Uses Apache Commons DBCP for connection pooling. See Commons DBCP documentation
|
||||
for the required JAR files. Alternatively you can use another connection pool
|
||||
such as C3P0, similarly configured using Spring.
|
||||
-->
|
||||
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"
|
||||
p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}" p:username="${jdbc.username}"
|
||||
p:password="${jdbc.password}"/>
|
||||
|
||||
<!-- JNDI DataSource for JEE environments -->
|
||||
<!--
|
||||
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/petclinic"/>
|
||||
-->
|
||||
|
||||
<!-- Hibernate SessionFactory -->
|
||||
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"
|
||||
p:dataSource-ref="dataSource" p:mappingResources="petclinic.hbm.xml">
|
||||
<property name="hibernateProperties">
|
||||
<props>
|
||||
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
|
||||
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
|
||||
<prop key="hibernate.generate_statistics">${hibernate.generate_statistics}</prop>
|
||||
</props>
|
||||
</property>
|
||||
<property name="eventListeners">
|
||||
<map>
|
||||
<entry key="merge">
|
||||
<bean class="org.springframework.orm.hibernate3.support.IdTransferringMergeEventListener"/>
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) -->
|
||||
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"
|
||||
p:sessionFactory-ref="sessionFactory"/>
|
||||
|
||||
<!-- Transaction manager that delegates to JTA (for a transactional JNDI DataSource) -->
|
||||
<!--
|
||||
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
|
||||
-->
|
||||
|
||||
|
||||
<!-- ========================= BUSINESS OBJECT DEFINITIONS ========================= -->
|
||||
|
||||
<!--
|
||||
Activates various annotations to be detected in bean classes:
|
||||
Spring's @Required and @Autowired, as well as JSR 250's @Resource.
|
||||
-->
|
||||
<context:annotation-config/>
|
||||
|
||||
<!--
|
||||
Instruct Spring to perform declarative transaction management
|
||||
automatically on annotated classes.
|
||||
-->
|
||||
<tx:annotation-driven/>
|
||||
|
||||
<!--
|
||||
Exporter that exposes the Hibernate statistics service via JMX. Autodetects the
|
||||
service MBean, using its bean name as JMX object name.
|
||||
-->
|
||||
<context:mbean-export/>
|
||||
|
||||
<!-- PetClinic's central data access object: Hibernate implementation -->
|
||||
<bean id="clinic" class="org.springframework.samples.petclinic.hibernate.HibernateClinic"/>
|
||||
|
||||
<!-- Hibernate's JMX statistics service -->
|
||||
<bean name="petclinic:type=HibernateStatistics" class="org.hibernate.jmx.StatisticsService" autowire="byName"/>
|
||||
|
||||
</beans>
|
85
src/main/webapp/WEB-INF/applicationContext-jdbc.xml
Normal file
85
src/main/webapp/WEB-INF/applicationContext-jdbc.xml
Normal file
|
@ -0,0 +1,85 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Application context definition for PetClinic on JDBC.
|
||||
-->
|
||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee"
|
||||
xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
|
||||
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
|
||||
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
|
||||
|
||||
<!-- ========================= RESOURCE DEFINITIONS ========================= -->
|
||||
|
||||
<!-- Configurer that replaces ${...} placeholders with values from a properties file -->
|
||||
<!-- (in this case, JDBC-related settings for the dataSource definition below) -->
|
||||
<context:property-placeholder location="classpath:jdbc.properties"/>
|
||||
|
||||
<!--
|
||||
Spring FactoryBean that creates a DataSource using Apache Commons DBCP for connection
|
||||
pooling. See Commons DBCP documentation for the required JAR files. This factory bean
|
||||
can populate the data source with a schema and data scripts if configured to do so.
|
||||
|
||||
An alternate factory bean can be created for different connection pool implementations,
|
||||
C3P0 for example.
|
||||
-->
|
||||
<bean id="dataSource" class="org.springframework.samples.petclinic.config.DbcpDataSourceFactory"
|
||||
p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}"
|
||||
p:username="${jdbc.username}" p:password="${jdbc.password}" p:populate="${jdbc.populate}"
|
||||
p:schemaLocation="${jdbc.schemaLocation}" p:dataLocation="${jdbc.dataLocation}"/>
|
||||
|
||||
<!-- JNDI DataSource for JEE environments -->
|
||||
<!--
|
||||
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/petclinic"/>
|
||||
-->
|
||||
|
||||
<!-- Transaction manager for a single JDBC DataSource (alternative to JTA) -->
|
||||
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
|
||||
p:dataSource-ref="dataSource"/>
|
||||
|
||||
<!-- Transaction manager that delegates to JTA (for a transactional JNDI DataSource) -->
|
||||
<!--
|
||||
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
|
||||
-->
|
||||
|
||||
|
||||
<!-- ========================= BUSINESS OBJECT DEFINITIONS ========================= -->
|
||||
|
||||
<!--
|
||||
Activates various annotations to be detected in bean classes: Spring's
|
||||
@Required and @Autowired, as well as JSR 250's @PostConstruct,
|
||||
@PreDestroy and @Resource (if available) and JPA's @PersistenceContext
|
||||
and @PersistenceUnit (if available).
|
||||
-->
|
||||
<context:annotation-config/>
|
||||
|
||||
<!--
|
||||
Instruct Spring to retrieve and apply @AspectJ aspects which are defined
|
||||
as beans in this context (such as the CallMonitoringAspect below).
|
||||
-->
|
||||
<aop:aspectj-autoproxy/>
|
||||
|
||||
<!--
|
||||
Instruct Spring to perform automatic transaction management on annotated classes.
|
||||
The SimpleJdbcClinic implementation declares @Transactional annotations.
|
||||
"proxy-target-class" is set because of SimpleJdbcClinic's @ManagedOperation usage.
|
||||
-->
|
||||
<tx:annotation-driven/>
|
||||
|
||||
<!--
|
||||
Exporter that exposes the Clinic DAO and the CallMonitoringAspect via JMX,
|
||||
based on the @ManagedResource, @ManagedAttribute, and @ManagedOperation annotations.
|
||||
-->
|
||||
<context:mbean-export/>
|
||||
|
||||
<!-- PetClinic's central data access object using Spring's SimpleJdbcTemplate -->
|
||||
<bean id="clinic" class="org.springframework.samples.petclinic.jdbc.SimpleJdbcClinic"/>
|
||||
|
||||
<!-- Call monitoring aspect that monitors call count and call invocation time -->
|
||||
<bean id="callMonitor" class="org.springframework.samples.petclinic.aspects.CallMonitoringAspect"/>
|
||||
|
||||
</beans>
|
101
src/main/webapp/WEB-INF/applicationContext-jpa.xml
Normal file
101
src/main/webapp/WEB-INF/applicationContext-jpa.xml
Normal file
|
@ -0,0 +1,101 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Application context definition for PetClinic on JPA.
|
||||
-->
|
||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee"
|
||||
xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
|
||||
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
|
||||
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
|
||||
|
||||
<!-- ========================= RESOURCE DEFINITIONS ========================= -->
|
||||
|
||||
<!--
|
||||
Activates a load-time weaver for the context. Any bean within the context that
|
||||
implements LoadTimeWeaverAware (such as LocalContainerEntityManagerFactoryBean)
|
||||
will receive a reference to the autodetected load-time weaver.
|
||||
-->
|
||||
<context:load-time-weaver/>
|
||||
|
||||
<!-- Configurer that replaces ${...} placeholders with values from a properties file -->
|
||||
<!-- (in this case, JDBC-related settings for the dataSource definition below) -->
|
||||
<context:property-placeholder location="classpath:jdbc.properties"/>
|
||||
|
||||
<!--
|
||||
Uses Apache Commons DBCP for connection pooling. See Commons DBCP documentation
|
||||
for the required JAR files. Alternatively you can use another connection pool
|
||||
such as C3P0, similarly configured using Spring.
|
||||
-->
|
||||
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"
|
||||
p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}" p:username="${jdbc.username}"
|
||||
p:password="${jdbc.password}"/>
|
||||
|
||||
<!-- JNDI DataSource for JEE environments -->
|
||||
<!--
|
||||
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/petclinic"/>
|
||||
-->
|
||||
|
||||
<!-- JPA EntityManagerFactory -->
|
||||
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
|
||||
p:dataSource-ref="dataSource">
|
||||
<property name="jpaVendorAdapter">
|
||||
<bean class="org.springframework.orm.jpa.vendor.TopLinkJpaVendorAdapter"
|
||||
p:databasePlatform="${jpa.databasePlatform}" p:showSql="${jpa.showSql}"/>
|
||||
<!--
|
||||
<bean class="org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter"
|
||||
p:database="${jpa.database}" p:showSql="${jpa.showSql}"/>
|
||||
-->
|
||||
<!--
|
||||
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
|
||||
p:database="${jpa.database}" p:showSql="${jpa.showSql}"/>
|
||||
-->
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- Transaction manager for a single JPA EntityManagerFactory (alternative to JTA) -->
|
||||
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
|
||||
p:entityManagerFactory-ref="entityManagerFactory"/>
|
||||
|
||||
|
||||
<!-- ========================= BUSINESS OBJECT DEFINITIONS ========================= -->
|
||||
|
||||
<!--
|
||||
Activates various annotations to be detected in bean classes: Spring's
|
||||
@Required and @Autowired, as well as JSR 250's @PostConstruct,
|
||||
@PreDestroy and @Resource (if available) and JPA's @PersistenceContext
|
||||
and @PersistenceUnit (if available).
|
||||
-->
|
||||
<context:annotation-config/>
|
||||
|
||||
<!--
|
||||
Instruct Spring to perform declarative transaction management
|
||||
automatically on annotated classes.
|
||||
-->
|
||||
<tx:annotation-driven mode="aspectj"/>
|
||||
|
||||
<!--
|
||||
Simply defining this bean will cause requests to owner names to be saved.
|
||||
This aspect is defined in petclinic.jar's META-INF/aop.xml file.
|
||||
Note that we can dependency inject this bean like any other bean.
|
||||
-->
|
||||
<bean class="org.springframework.samples.petclinic.aspects.UsageLogAspect" p:historySize="300"/>
|
||||
|
||||
<!--
|
||||
Post-processor to perform exception translation on @Repository classes (from native
|
||||
exceptions such as JPA PersistenceExceptions to Spring's DataAccessException hierarchy).
|
||||
-->
|
||||
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
|
||||
|
||||
<!--
|
||||
Will automatically be transactional due to @Transactional.
|
||||
EntityManager will be auto-injected due to @PersistenceContext.
|
||||
PersistenceExceptions will be auto-translated due to @Repository.
|
||||
-->
|
||||
<bean id="clinic" class="org.springframework.samples.petclinic.jpa.EntityManagerClinic"/>
|
||||
|
||||
</beans>
|
18
src/main/webapp/WEB-INF/classes/log4j.properties
Normal file
18
src/main/webapp/WEB-INF/classes/log4j.properties
Normal file
|
@ -0,0 +1,18 @@
|
|||
# For JBoss: Avoid to setup Log4J outside $JBOSS_HOME/server/default/deploy/log4j.xml!
|
||||
# For all other servers: Comment out the Log4J listener in web.xml to activate Log4J.
|
||||
log4j.rootLogger=INFO, stdout, logfile
|
||||
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n
|
||||
|
||||
log4j.appender.logfile=org.apache.log4j.RollingFileAppender
|
||||
log4j.appender.logfile.File=${petclinic.root}/WEB-INF/petclinic.log
|
||||
log4j.appender.logfile.MaxFileSize=512KB
|
||||
# Keep three backup files.
|
||||
log4j.appender.logfile.MaxBackupIndex=3
|
||||
# Pattern to output: date priority [category] - message
|
||||
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
|
||||
|
||||
log4j.logger.org.springframework.samples.petclinic.aspects=DEBUG
|
8
src/main/webapp/WEB-INF/classes/messages.properties
Normal file
8
src/main/webapp/WEB-INF/classes/messages.properties
Normal file
|
@ -0,0 +1,8 @@
|
|||
welcome=Welcome
|
||||
required=is required
|
||||
notFound=has not been found
|
||||
duplicate=is already in use
|
||||
nonNumeric=must be all numeric
|
||||
duplicateFormSubmission=Duplicate form submission is not allowed
|
||||
typeMismatch.date=invalid date
|
||||
typeMismatch.birthDate=invalid date
|
8
src/main/webapp/WEB-INF/classes/messages_de.properties
Normal file
8
src/main/webapp/WEB-INF/classes/messages_de.properties
Normal file
|
@ -0,0 +1,8 @@
|
|||
welcome=Willkommen
|
||||
required=muss angegeben werden
|
||||
notFound=wurde nicht gefunden
|
||||
duplicate=ist bereits vergeben
|
||||
nonNumeric=darf nur numerisch sein
|
||||
duplicateFormSubmission=Wiederholtes Absenden des Formulars ist nicht erlaubt
|
||||
typeMismatch.date=ungültiges Datum
|
||||
typeMismatch.birthDate=ungültiges Datum
|
1
src/main/webapp/WEB-INF/classes/messages_en.properties
Normal file
1
src/main/webapp/WEB-INF/classes/messages_en.properties
Normal file
|
@ -0,0 +1 @@
|
|||
# This file is intentionally empty. Message look-ups will fall back to the default "messages.properties" file.
|
6
src/main/webapp/WEB-INF/geronimo-web.xml
Normal file
6
src/main/webapp/WEB-INF/geronimo-web.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app xmlns="http://geronimo.apache.org/xml/ns/j2ee/web-1.0"
|
||||
configId="org/springframework/samples/petclinic">
|
||||
<context-root>/petclinic</context-root>
|
||||
<context-priority-classloader>true</context-priority-classloader>
|
||||
</web-app>
|
19
src/main/webapp/WEB-INF/jsp/dataAccessFailure.jsp
Normal file
19
src/main/webapp/WEB-INF/jsp/dataAccessFailure.jsp
Normal file
|
@ -0,0 +1,19 @@
|
|||
<%@ include file="/WEB-INF/jsp/includes.jsp" %>
|
||||
<%@ include file="/WEB-INF/jsp/header.jsp" %>
|
||||
|
||||
<%
|
||||
Exception ex = (Exception) request.getAttribute("exception");
|
||||
%>
|
||||
|
||||
<h2>Data access failure: <%= ex.getMessage() %></h2>
|
||||
<p/>
|
||||
|
||||
<%
|
||||
ex.printStackTrace(new java.io.PrintWriter(out));
|
||||
%>
|
||||
|
||||
<p/>
|
||||
<br/>
|
||||
<a href="<spring:url value="/" htmlEscape="true" />">Home</a>
|
||||
|
||||
<%@ include file="/WEB-INF/jsp/footer.jsp" %>
|
12
src/main/webapp/WEB-INF/jsp/footer.jsp
Normal file
12
src/main/webapp/WEB-INF/jsp/footer.jsp
Normal file
|
@ -0,0 +1,12 @@
|
|||
|
||||
<table class="footer">
|
||||
<tr>
|
||||
<td><a href="<spring:url value="/" htmlEscape="true" />">Home</a></td>
|
||||
<td align="right"><img src="<spring:url value="/static/images/springsource-logo.png" htmlEscape="true" />" alt="Sponsored by SpringSource"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
14
src/main/webapp/WEB-INF/jsp/header.jsp
Normal file
14
src/main/webapp/WEB-INF/jsp/header.jsp
Normal file
|
@ -0,0 +1,14 @@
|
|||
<!--
|
||||
PetClinic :: a Spring Framework demonstration
|
||||
-->
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<link rel="stylesheet" href="<spring:url value="/static/styles/petclinic.css" htmlEscape="true" />" type="text/css"/>
|
||||
<title>PetClinic :: a Spring Framework demonstration</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
5
src/main/webapp/WEB-INF/jsp/includes.jsp
Normal file
5
src/main/webapp/WEB-INF/jsp/includes.jsp
Normal file
|
@ -0,0 +1,5 @@
|
|||
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
|
||||
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
|
||||
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
|
61
src/main/webapp/WEB-INF/jsp/owners/form.jsp
Normal file
61
src/main/webapp/WEB-INF/jsp/owners/form.jsp
Normal file
|
@ -0,0 +1,61 @@
|
|||
<%@ include file="/WEB-INF/jsp/includes.jsp" %>
|
||||
<%@ include file="/WEB-INF/jsp/header.jsp" %>
|
||||
<c:choose>
|
||||
<c:when test="${owner.new}"><c:set var="method" value="post"/></c:when>
|
||||
<c:otherwise><c:set var="method" value="put"/></c:otherwise>
|
||||
</c:choose>
|
||||
|
||||
<h2><c:if test="${owner.new}">New </c:if>Owner:</h2>
|
||||
<form:form modelAttribute="owner" method="${method}">
|
||||
<table>
|
||||
<tr>
|
||||
<th>
|
||||
First Name: <form:errors path="firstName" cssClass="errors"/>
|
||||
<br/>
|
||||
<form:input path="firstName" size="30" maxlength="80"/>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
Last Name: <form:errors path="lastName" cssClass="errors"/>
|
||||
<br/>
|
||||
<form:input path="lastName" size="30" maxlength="80"/>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
Address: <form:errors path="address" cssClass="errors"/>
|
||||
<br/>
|
||||
<form:input path="address" size="30" maxlength="80"/>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
City: <form:errors path="city" cssClass="errors"/>
|
||||
<br/>
|
||||
<form:input path="city" size="30" maxlength="80"/>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
Telephone: <form:errors path="telephone" cssClass="errors"/>
|
||||
<br/>
|
||||
<form:input path="telephone" size="20" maxlength="20"/>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<c:choose>
|
||||
<c:when test="${owner.new}">
|
||||
<p class="submit"><input type="submit" value="Add Owner"/></p>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<p class="submit"><input type="submit" value="Update Owner"/></p>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form:form>
|
||||
|
||||
<%@ include file="/WEB-INF/jsp/footer.jsp" %>
|
34
src/main/webapp/WEB-INF/jsp/owners/list.jsp
Normal file
34
src/main/webapp/WEB-INF/jsp/owners/list.jsp
Normal file
|
@ -0,0 +1,34 @@
|
|||
<%@ include file="/WEB-INF/jsp/includes.jsp" %>
|
||||
<%@ include file="/WEB-INF/jsp/header.jsp" %>
|
||||
|
||||
<h2>Owners:</h2>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<th>Name</th>
|
||||
<th>Address</th>
|
||||
<th>City</th>
|
||||
<th>Telephone</th>
|
||||
<th>Pets</th>
|
||||
</thead>
|
||||
<c:forEach var="owner" items="${selections}">
|
||||
<tr>
|
||||
<td>
|
||||
<spring:url value="owners/{ownerId}" var="ownerUrl">
|
||||
<spring:param name="ownerId" value="${owner.id}"/>
|
||||
</spring:url>
|
||||
<a href="${fn:escapeXml(ownerUrl)}">${owner.firstName} ${owner.lastName}</a>
|
||||
</td>
|
||||
<td>${owner.address}</td>
|
||||
<td>${owner.city}</td>
|
||||
<td>${owner.telephone}</td>
|
||||
<td>
|
||||
<c:forEach var="pet" items="${owner.pets}">
|
||||
${pet.name}
|
||||
</c:forEach>
|
||||
</td>
|
||||
</tr>
|
||||
</c:forEach>
|
||||
</table>
|
||||
|
||||
<%@ include file="/WEB-INF/jsp/footer.jsp" %>
|
26
src/main/webapp/WEB-INF/jsp/owners/search.jsp
Normal file
26
src/main/webapp/WEB-INF/jsp/owners/search.jsp
Normal file
|
@ -0,0 +1,26 @@
|
|||
<%@ include file="/WEB-INF/jsp/includes.jsp" %>
|
||||
<%@ include file="/WEB-INF/jsp/header.jsp" %>
|
||||
|
||||
|
||||
<h2>Find Owners:</h2>
|
||||
|
||||
<spring:url value="/owners" var="formUrl"/>
|
||||
<form:form modelAttribute="owner" action="${fn:escapeXml(formUrl)}" method="get">
|
||||
<table>
|
||||
<tr>
|
||||
<th>
|
||||
Last Name: <form:errors path="*" cssClass="errors"/>
|
||||
<br/>
|
||||
<form:input path="lastName" size="30" maxlength="80" />
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><p class="submit"><input type="submit" value="Find Owners"/></p></td>
|
||||
</tr>
|
||||
</table>
|
||||
</form:form>
|
||||
|
||||
<br/>
|
||||
<a href='<spring:url value="/owners/new" htmlEscape="true"/>'>Add Owner</a>
|
||||
|
||||
<%@ include file="/WEB-INF/jsp/footer.jsp" %>
|
108
src/main/webapp/WEB-INF/jsp/owners/show.jsp
Normal file
108
src/main/webapp/WEB-INF/jsp/owners/show.jsp
Normal file
|
@ -0,0 +1,108 @@
|
|||
<%@ include file="/WEB-INF/jsp/includes.jsp" %>
|
||||
<%@ include file="/WEB-INF/jsp/header.jsp" %>
|
||||
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
|
||||
|
||||
<h2>Owner Information</h2>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<td><b>${owner.firstName} ${owner.lastName}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Address</th>
|
||||
<td>${owner.address}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>City</th>
|
||||
<td>${owner.city}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Telephone </th>
|
||||
<td>${owner.telephone}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class="table-buttons">
|
||||
<tr>
|
||||
<td colspan="2" align="center">
|
||||
<spring:url value="{ownerId}/edit" var="editUrl">
|
||||
<spring:param name="ownerId" value="${owner.id}" />
|
||||
</spring:url>
|
||||
<a href="${fn:escapeXml(editUrl)}">Edit Owner</a>
|
||||
</td>
|
||||
<td>
|
||||
<spring:url value="{ownerId}/pets/new" var="addUrl">
|
||||
<spring:param name="ownerId" value="${owner.id}" />
|
||||
</spring:url>
|
||||
<a href="${fn:escapeXml(addUrl)}">Add New Pet</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h2>Pets and Visits</h2>
|
||||
|
||||
<c:forEach var="pet" items="${owner.pets}">
|
||||
<table width="94%">
|
||||
<tr>
|
||||
<td valign="top">
|
||||
<table>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<td><b>${pet.name}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Birth Date</th>
|
||||
<td><fmt:formatDate value="${pet.birthDate}" pattern="yyyy-MM-dd"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Type</th>
|
||||
<td>${pet.type.name}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td valign="top">
|
||||
<table>
|
||||
<thead>
|
||||
<th>Visit Date</th>
|
||||
<th>Description</th>
|
||||
</thead>
|
||||
<c:forEach var="visit" items="${pet.visits}">
|
||||
<tr>
|
||||
<td><fmt:formatDate value="${visit.date}" pattern="yyyy-MM-dd"/></td>
|
||||
<td>${visit.description}</td>
|
||||
</tr>
|
||||
</c:forEach>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class="table-buttons">
|
||||
<tr>
|
||||
<td>
|
||||
<spring:url value="{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>
|
||||
<td>
|
||||
<spring:url value="{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>
|
||||
<td></td>
|
||||
<td>
|
||||
<spring:url value="{ownerId}/pets/{petId}/visits.atom" var="feedUrl">
|
||||
<spring:param name="ownerId" value="${owner.id}"/>
|
||||
<spring:param name="petId" value="${pet.id}"/>
|
||||
</spring:url>
|
||||
<a href="${fn:escapeXml(feedUrl)}" rel="alternate" type="application/atom+xml">Atom Feed</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</c:forEach>
|
||||
|
||||
<%@ include file="/WEB-INF/jsp/footer.jsp" %>
|
56
src/main/webapp/WEB-INF/jsp/pets/form.jsp
Normal file
56
src/main/webapp/WEB-INF/jsp/pets/form.jsp
Normal file
|
@ -0,0 +1,56 @@
|
|||
<%@ include file="/WEB-INF/jsp/includes.jsp" %>
|
||||
<%@ include file="/WEB-INF/jsp/header.jsp" %>
|
||||
<c:choose>
|
||||
<c:when test="${pet.new}"><c:set var="method" value="post"/></c:when>
|
||||
<c:otherwise><c:set var="method" value="put"/></c:otherwise>
|
||||
</c:choose>
|
||||
|
||||
<h2><c:if test="${pet.new}">New </c:if>Pet</h2>
|
||||
|
||||
<b>Owner:</b> ${pet.owner.firstName} ${pet.owner.lastName}
|
||||
<br/>
|
||||
<form:form modelAttribute="pet" method="${method}">
|
||||
<table>
|
||||
<tr>
|
||||
<th>
|
||||
Name: <form:errors path="name" cssClass="errors"/>
|
||||
<br/>
|
||||
<form:input path="name" size="30" maxlength="30"/>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
Birth Date: <form:errors path="birthDate" cssClass="errors"/>
|
||||
<br/>
|
||||
<form:input path="birthDate" size="10" maxlength="10"/> (yyyy-mm-dd)
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
Type: <form:errors path="type" cssClass="errors"/>
|
||||
<br/>
|
||||
<form:select path="type" items="${types}"/>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<c:choose>
|
||||
<c:when test="${pet.new}">
|
||||
<p class="submit"><input type="submit" value="Add Pet"/></p>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<p class="submit"><input type="submit" value="Update Pet"/></p>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form:form>
|
||||
|
||||
<c:if test="${!pet.new}">
|
||||
<form:form method="delete">
|
||||
<p class="submit"><input type="submit" value="Delete Pet"/></p>
|
||||
</form:form>
|
||||
</c:if>
|
||||
|
||||
<%@ include file="/WEB-INF/jsp/footer.jsp" %>
|
68
src/main/webapp/WEB-INF/jsp/pets/visitForm.jsp
Normal file
68
src/main/webapp/WEB-INF/jsp/pets/visitForm.jsp
Normal file
|
@ -0,0 +1,68 @@
|
|||
<%@ include file="/WEB-INF/jsp/includes.jsp" %>
|
||||
<%@ include file="/WEB-INF/jsp/header.jsp" %>
|
||||
|
||||
<h2><c:if test="${visit.new}">New </c:if>Visit:</h2>
|
||||
|
||||
<form:form modelAttribute="visit">
|
||||
<b>Pet:</b>
|
||||
<table width="333">
|
||||
<thead>
|
||||
<th>Name</th>
|
||||
<th>Birth Date</th>
|
||||
<th>Type</th>
|
||||
<th>Owner</th>
|
||||
</thead>
|
||||
<tr>
|
||||
<td>${visit.pet.name}</td>
|
||||
<td><fmt:formatDate value="${visit.pet.birthDate}" pattern="yyyy-MM-dd"/></td>
|
||||
<td>${visit.pet.type.name}</td>
|
||||
<td>${visit.pet.owner.firstName} ${visit.pet.owner.lastName}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table width="333">
|
||||
<tr>
|
||||
<th>
|
||||
Date:
|
||||
<br/><form:errors path="date" cssClass="errors"/>
|
||||
</th>
|
||||
<td>
|
||||
<form:input path="date" size="10" maxlength="10"/> (yyyy-mm-dd)
|
||||
</td>
|
||||
<tr/>
|
||||
<tr>
|
||||
<th valign="top">
|
||||
Description:
|
||||
<br/><form:errors path="description" cssClass="errors"/>
|
||||
</th>
|
||||
<td>
|
||||
<form:textarea path="description" rows="10" cols="25"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<input type="hidden" name="petId" value="${visit.pet.id}"/>
|
||||
<p class="submit"><input type="submit" value="Add Visit"/></p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form:form>
|
||||
|
||||
<br/>
|
||||
<b>Previous Visits:</b>
|
||||
<table width="333">
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<c:forEach var="visit" items="${visit.pet.visits}">
|
||||
<c:if test="${!visit.new}">
|
||||
<tr>
|
||||
<td><fmt:formatDate value="${visit.date}" pattern="yyyy-MM-dd"/></td>
|
||||
<td>${visit.description}</td>
|
||||
</tr>
|
||||
</c:if>
|
||||
</c:forEach>
|
||||
</table>
|
||||
|
||||
<%@ include file="/WEB-INF/jsp/footer.jsp" %>
|
49
src/main/webapp/WEB-INF/jsp/uncaughtException.jsp
Normal file
49
src/main/webapp/WEB-INF/jsp/uncaughtException.jsp
Normal file
|
@ -0,0 +1,49 @@
|
|||
<%@ include file="/WEB-INF/jsp/includes.jsp" %>
|
||||
<%@ include file="/WEB-INF/jsp/header.jsp" %>
|
||||
|
||||
<h2/>Internal error</h2>
|
||||
<p/>
|
||||
|
||||
<%
|
||||
try {
|
||||
// The Servlet spec guarantees this attribute will be available
|
||||
Throwable exception = (Throwable) request.getAttribute("javax.servlet.error.exception");
|
||||
|
||||
if (exception != null) {
|
||||
if (exception instanceof ServletException) {
|
||||
// It's a ServletException: we should extract the root cause
|
||||
ServletException sex = (ServletException) exception;
|
||||
Throwable rootCause = sex.getRootCause();
|
||||
if (rootCause == null)
|
||||
rootCause = sex;
|
||||
out.println("** Root cause is: "+ rootCause.getMessage());
|
||||
rootCause.printStackTrace(new java.io.PrintWriter(out));
|
||||
}
|
||||
else {
|
||||
// It's not a ServletException, so we'll just show it
|
||||
exception.printStackTrace(new java.io.PrintWriter(out));
|
||||
}
|
||||
}
|
||||
else {
|
||||
out.println("No error information available");
|
||||
}
|
||||
|
||||
// Display cookies
|
||||
out.println("\nCookies:\n");
|
||||
Cookie[] cookies = request.getCookies();
|
||||
if (cookies != null) {
|
||||
for (int i = 0; i < cookies.length; i++) {
|
||||
out.println(cookies[i].getName() + "=[" + cookies[i].getValue() + "]");
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace(new java.io.PrintWriter(out));
|
||||
}
|
||||
%>
|
||||
|
||||
<p/>
|
||||
<br/>
|
||||
|
||||
|
||||
<%@ include file="/WEB-INF/jsp/footer.jsp" %>
|
31
src/main/webapp/WEB-INF/jsp/vets.jsp
Normal file
31
src/main/webapp/WEB-INF/jsp/vets.jsp
Normal file
|
@ -0,0 +1,31 @@
|
|||
<%@ include file="/WEB-INF/jsp/includes.jsp" %>
|
||||
<%@ include file="/WEB-INF/jsp/header.jsp" %>
|
||||
|
||||
<h2>Veterinarians:</h2>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<th>Name</th>
|
||||
<th>Specialties</th>
|
||||
</thead>
|
||||
<c:forEach var="vet" items="${vets.vetList}">
|
||||
<tr>
|
||||
<td>${vet.firstName} ${vet.lastName}</td>
|
||||
<td>
|
||||
<c:forEach var="specialty" items="${vet.specialties}">
|
||||
${specialty.name}
|
||||
</c:forEach>
|
||||
<c:if test="${vet.nrOfSpecialties == 0}">none</c:if>
|
||||
</td>
|
||||
</tr>
|
||||
</c:forEach>
|
||||
</table>
|
||||
<table class="table-buttons">
|
||||
<tr>
|
||||
<td>
|
||||
<a href="<spring:url value="/vets.xml" htmlEscape="true" />">View as XML</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<%@ include file="/WEB-INF/jsp/footer.jsp" %>
|
15
src/main/webapp/WEB-INF/jsp/welcome.jsp
Normal file
15
src/main/webapp/WEB-INF/jsp/welcome.jsp
Normal file
|
@ -0,0 +1,15 @@
|
|||
<%@ include file="/WEB-INF/jsp/includes.jsp" %>
|
||||
<%@ include file="/WEB-INF/jsp/header.jsp" %>
|
||||
|
||||
<img src="<spring:url value="/static/images/pets.png" htmlEscape="true" />" align="right" style="position:relative;right:30px;">
|
||||
<h2><fmt:message key="welcome"/></h2>
|
||||
|
||||
<ul>
|
||||
<li><a href="<spring:url value="/owners/search" htmlEscape="true" />">Find owner</a></li>
|
||||
<li><a href="<spring:url value="/vets" htmlEscape="true" />">Display all veterinarians</a></li>
|
||||
<li><a href="<spring:url value="/static/html/tutorial.html" htmlEscape="true" />">Tutorial</a></li>
|
||||
</ul>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<%@ include file="/WEB-INF/jsp/footer.jsp" %>
|
110
src/main/webapp/WEB-INF/petclinic-servlet.xml
Normal file
110
src/main/webapp/WEB-INF/petclinic-servlet.xml
Normal file
|
@ -0,0 +1,110 @@
|
|||
<?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"
|
||||
xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:oxm="http://www.springframework.org/schema/oxm"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
|
||||
http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd">
|
||||
|
||||
<!--
|
||||
- The controllers are autodetected POJOs labeled with the @Controller annotation.
|
||||
-->
|
||||
<context:component-scan base-package="org.springframework.samples.petclinic.web"/>
|
||||
|
||||
<!--
|
||||
- The form-based controllers within this application provide @RequestMapping
|
||||
- annotations at the type level for path mapping URLs and @RequestMapping
|
||||
- at the method level for request type mappings (e.g., GET and POST).
|
||||
- In contrast, ClinicController - which is not form-based - provides
|
||||
- @RequestMapping only at the method level for path mapping URLs.
|
||||
-
|
||||
- DefaultAnnotationHandlerMapping is driven by these annotations and is
|
||||
- enabled by default with Java 5+.
|
||||
-->
|
||||
|
||||
<!--
|
||||
- This bean processes annotated handler methods, applying PetClinic-specific PropertyEditors
|
||||
- for request parameter binding. It overrides the default AnnotationMethodHandlerAdapter.
|
||||
-->
|
||||
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
|
||||
<property name="webBindingInitializer">
|
||||
<bean class="org.springframework.samples.petclinic.web.ClinicBindingInitializer"/>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!--
|
||||
- This bean resolves specific types of exceptions to corresponding logical
|
||||
- view names for error views. The default behaviour of DispatcherServlet
|
||||
- is to propagate all exceptions to the servlet container: this will happen
|
||||
- here with all other types of exceptions.
|
||||
-->
|
||||
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
|
||||
<property name="exceptionMappings">
|
||||
<props>
|
||||
<prop key="org.springframework.web.servlet.PageNotFound">pageNotFound</prop>
|
||||
<prop key="org.springframework.dao.DataAccessException">dataAccessFailure</prop>
|
||||
<prop key="org.springframework.transaction.TransactionException">dataAccessFailure</prop>
|
||||
</props>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!--
|
||||
- This view resolver delegates to the InternalResourceViewResolver and BeanNameViewResolver,
|
||||
- and uses the requested media type to pick a matching view. When the media type is 'text/html',
|
||||
- it will delegate to the InternalResourceViewResolver's JstlView, otherwise to the
|
||||
- BeanNameViewResolver. Note the use of the expression language to refer to the contentType
|
||||
- property of the vets view bean, setting it to 'application/vnd.springsource.samples.petclinic+xml'.
|
||||
-->
|
||||
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
|
||||
<property name="mediaTypes">
|
||||
<map>
|
||||
<entry key="xml" value="#{vets.contentType}"/>
|
||||
<entry key="atom" value="#{visits.contentType}"/>
|
||||
</map>
|
||||
</property>
|
||||
<property name="order" value="0"/>
|
||||
</bean>
|
||||
|
||||
<!--
|
||||
- The BeanNameViewResolver is used to pick up the visits view name (below).
|
||||
- It has the order property set to 2, which means that this will
|
||||
- be the first view resolver to be used after the delegating content
|
||||
- negotiating view resolver.
|
||||
-->
|
||||
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver" p:order="1"/>
|
||||
<!--
|
||||
|
||||
- This bean configures the 'prefix' and 'suffix' properties of
|
||||
- InternalResourceViewResolver, which resolves logical view names
|
||||
- returned by Controllers. For example, a logical view name of "vets"
|
||||
- will be mapped to "/WEB-INF/jsp/vets.jsp".
|
||||
-->
|
||||
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="/WEB-INF/jsp/"
|
||||
p:suffix=".jsp" p:order="2"/>
|
||||
|
||||
<!--
|
||||
- The AtomView rendering a Atom feed of the visits
|
||||
-->
|
||||
<bean id="visits" class="org.springframework.samples.petclinic.web.VisitsAtomView"/>
|
||||
|
||||
<bean id="vets" class="org.springframework.web.servlet.view.xml.MarshallingView">
|
||||
<property name="contentType" value="application/vnd.springsource.samples.petclinic+xml"/>
|
||||
<property name="marshaller" ref="marshaller"/>
|
||||
</bean>
|
||||
|
||||
<oxm:jaxb2-marshaller id="marshaller">
|
||||
<oxm:class-to-be-bound name="org.springframework.samples.petclinic.Vets"/>
|
||||
</oxm:jaxb2-marshaller>
|
||||
|
||||
<!--
|
||||
- Message source for this context, loaded from localized "messages_xx" files.
|
||||
- Could also reside in the root application context, as it is generic,
|
||||
- but is currently just used within PetClinic's web tier.
|
||||
-->
|
||||
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"
|
||||
p:basename="messages"/>
|
||||
|
||||
</beans>
|
161
src/main/webapp/WEB-INF/web.xml
Normal file
161
src/main/webapp/WEB-INF/web.xml
Normal file
|
@ -0,0 +1,161 @@
|
|||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
|
||||
|
||||
<display-name>Spring PetClinic</display-name>
|
||||
|
||||
<description>Spring PetClinic sample application</description>
|
||||
|
||||
<!--
|
||||
Key of the system property that should specify the root directory of this
|
||||
web app. Applied by WebAppRootListener or Log4jConfigListener.
|
||||
-->
|
||||
<context-param>
|
||||
<param-name>webAppRootKey</param-name>
|
||||
<param-value>petclinic.root</param-value>
|
||||
</context-param>
|
||||
|
||||
|
||||
|
||||
<!--
|
||||
Location of the Log4J config file, for initialization and refresh checks.
|
||||
Applied by Log4jConfigListener.
|
||||
-->
|
||||
<context-param>
|
||||
<param-name>log4jConfigLocation</param-name>
|
||||
<param-value>/WEB-INF/classes/log4j.properties</param-value>
|
||||
</context-param>
|
||||
|
||||
<!--
|
||||
- Location of the XML file that defines the root application context.
|
||||
- Applied by ContextLoaderServlet.
|
||||
-
|
||||
- Can be set to:
|
||||
- "/WEB-INF/applicationContext-hibernate.xml" for the Hibernate implementation,
|
||||
- "/WEB-INF/applicationContext-jpa.xml" for the JPA one, or
|
||||
- "/WEB-INF/applicationContext-jdbc.xml" for the JDBC one.
|
||||
-->
|
||||
<context-param>
|
||||
<param-name>contextConfigLocation</param-name>
|
||||
|
||||
<param-value>/WEB-INF/applicationContext-jdbc.xml</param-value>
|
||||
<!--
|
||||
<param-value>/WEB-INF/applicationContext-hibernate.xml</param-value>
|
||||
<param-value>/WEB-INF/applicationContext-jpa.xml</param-value>
|
||||
-->
|
||||
|
||||
<!--
|
||||
To use the JPA variant above, you will need to enable Spring load-time
|
||||
weaving in your server environment. See PetClinic's readme and/or
|
||||
Spring's JPA documentation for information on how to do this.
|
||||
-->
|
||||
</context-param>
|
||||
|
||||
<!--
|
||||
- Configures Log4J for this web app.
|
||||
- As this context specifies a context-param "log4jConfigLocation", its file path
|
||||
- is used to load the Log4J configuration, including periodic refresh checks.
|
||||
-
|
||||
- Would fall back to default Log4J initialization (non-refreshing) if no special
|
||||
- context-params are given.
|
||||
-
|
||||
- Exports a "web app root key", i.e. a system property that specifies the root
|
||||
- directory of this web app, for usage in log file paths.
|
||||
- This web app specifies "petclinic.root" (see log4j.properties file).
|
||||
-->
|
||||
<!-- Leave the listener commented-out if using JBoss -->
|
||||
<!--
|
||||
<listener>
|
||||
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
|
||||
</listener>
|
||||
-->
|
||||
|
||||
<!--
|
||||
- Loads the root application context of this web app at startup,
|
||||
- by default from "/WEB-INF/applicationContext.xml".
|
||||
- Note that you need to fall back to Spring's ContextLoaderServlet for
|
||||
- J2EE servers that do not follow the Servlet 2.4 initialization order.
|
||||
-
|
||||
- Use WebApplicationContextUtils.getWebApplicationContext(servletContext)
|
||||
- to access it anywhere in the web application, outside of the framework.
|
||||
-
|
||||
- The root context is the parent of all servlet-specific contexts.
|
||||
- This means that its beans are automatically available in these child contexts,
|
||||
- both for getBean(name) calls and (external) bean references.
|
||||
-->
|
||||
<listener>
|
||||
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
|
||||
</listener>
|
||||
|
||||
<!--
|
||||
- Map static resources to the default servlet
|
||||
- examples:
|
||||
- http://localhost:8080/static/images/pets.png
|
||||
- http://localhost:8080/static/styles/petclinic.css
|
||||
-->
|
||||
<servlet-mapping>
|
||||
<servlet-name>default</servlet-name>
|
||||
<url-pattern>/static/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!--
|
||||
- Servlet that dispatches request to registered handlers (Controller implementations).
|
||||
- Has its own application context, by default defined in "{servlet-name}-servlet.xml",
|
||||
- i.e. "petclinic-servlet.xml".
|
||||
-
|
||||
- A web app can contain any number of such servlets.
|
||||
- Note that this web app has a shared root application context, serving as parent
|
||||
- of all DispatcherServlet contexts.
|
||||
-->
|
||||
<servlet>
|
||||
<servlet-name>petclinic</servlet-name>
|
||||
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
|
||||
<load-on-startup>2</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<!--
|
||||
- Maps the petclinic dispatcher to "*.do". All handler mappings in
|
||||
- petclinic-servlet.xml will by default be applied to this subpath.
|
||||
- If a mapping isn't a /* subpath, the handler mappings are considered
|
||||
- relative to the web app root.
|
||||
-
|
||||
- NOTE: A single dispatcher can be mapped to multiple paths, like any servlet.
|
||||
-->
|
||||
<servlet-mapping>
|
||||
<servlet-name>petclinic</servlet-name>
|
||||
<url-pattern>/</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<filter>
|
||||
<filter-name>httpMethodFilter</filter-name>
|
||||
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
|
||||
</filter>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>httpMethodFilter</filter-name>
|
||||
<servlet-name>petclinic</servlet-name>
|
||||
</filter-mapping>
|
||||
|
||||
<session-config>
|
||||
<session-timeout>10</session-timeout>
|
||||
</session-config>
|
||||
|
||||
<error-page>
|
||||
<exception-type>java.lang.Exception</exception-type>
|
||||
<!-- Displays a stack trace -->
|
||||
<location>/WEB-INF/jsp/uncaughtException.jsp</location>
|
||||
</error-page>
|
||||
|
||||
<!--
|
||||
- Reference to PetClinic database.
|
||||
- Only needed if not using a local DataSource but a JNDI one instead.
|
||||
-->
|
||||
<!--
|
||||
<resource-ref>
|
||||
<res-ref-name>jdbc/petclinic</res-ref-name>
|
||||
<res-type>javax.sql.DataSource</res-type>
|
||||
<res-auth>Container</res-auth>
|
||||
</resource-ref>
|
||||
-->
|
||||
|
||||
</web-app>
|
1153
src/main/webapp/html/tutorial.html
Normal file
1153
src/main/webapp/html/tutorial.html
Normal file
File diff suppressed because it is too large
Load diff
BIN
src/main/webapp/images/banner-graphic.png
Normal file
BIN
src/main/webapp/images/banner-graphic.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
BIN
src/main/webapp/images/bullet-arrow.png
Normal file
BIN
src/main/webapp/images/bullet-arrow.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.9 KiB |
BIN
src/main/webapp/images/pets.png
Normal file
BIN
src/main/webapp/images/pets.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 54 KiB |
BIN
src/main/webapp/images/springsource-logo.png
Normal file
BIN
src/main/webapp/images/springsource-logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.9 KiB |
BIN
src/main/webapp/images/submit-bg.png
Normal file
BIN
src/main/webapp/images/submit-bg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
234
src/main/webapp/styles/petclinic.css
Normal file
234
src/main/webapp/styles/petclinic.css
Normal file
|
@ -0,0 +1,234 @@
|
|||
/* main elements */
|
||||
|
||||
body,div,td {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #fff;
|
||||
background-image: url(../images/banner-graphic.png);
|
||||
background-position: top center;
|
||||
background-repeat: no-repeat;
|
||||
text-align: center;
|
||||
min-width: 600px;
|
||||
margin-top: 60px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
div {
|
||||
margin: 5px 25px 5px 25px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/* header and footer elements */
|
||||
|
||||
#main {
|
||||
margin:0 auto;
|
||||
position:relative;
|
||||
top: 35px;
|
||||
left:0px;
|
||||
width:560px;
|
||||
text-align:left;
|
||||
}
|
||||
|
||||
.footer {
|
||||
background:#fff;
|
||||
border:none;
|
||||
margin-top:20px;
|
||||
border-top:1px solid #999999;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
.footer td {color:#999999;}
|
||||
|
||||
.footer a:link {color: #7db223;}
|
||||
|
||||
|
||||
/* text styles */
|
||||
|
||||
h1,h2,h3 {
|
||||
font-family: Helvetica, sans-serif;
|
||||
color: #7db223;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 20px;
|
||||
line-height: 26px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 18px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 15px;
|
||||
line-height: 21px;
|
||||
color:#555;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.errors {
|
||||
color: red;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: underline;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
a:link {
|
||||
color: #7db223;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #456314;
|
||||
}
|
||||
|
||||
a:active {
|
||||
color: #7db223;
|
||||
}
|
||||
|
||||
a:visited {
|
||||
color: #7db223;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: disc url(../images/bullet-arrow.png);
|
||||
}
|
||||
|
||||
li {
|
||||
padding-top: 5px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
li ul {
|
||||
list-style: square url(../images/bullet-arrow.png);
|
||||
}
|
||||
|
||||
li ul li ul {
|
||||
list-style: circle none;
|
||||
}
|
||||
|
||||
/* table elements */
|
||||
|
||||
table {
|
||||
background: #d6e2c3;
|
||||
margin: 3px 0 0 0;
|
||||
border: 4px solid #d6e2c3;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
table table {
|
||||
margin: -5px 0;
|
||||
border: 0px solid #e0e7d3;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
table td,table th {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
table th {
|
||||
font-size: 12px;
|
||||
text-align: left;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
table thead {
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
background-color: #c2ceaf;
|
||||
}
|
||||
|
||||
table a:link {color: #303030;}
|
||||
|
||||
caption {
|
||||
caption-side: top;
|
||||
width: auto;
|
||||
text-align: left;
|
||||
font-size: 12px;
|
||||
color: #848f73;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
background: #e0e7d3;
|
||||
padding: 8px;
|
||||
padding-bottom: 22px;
|
||||
border: none;
|
||||
width: 560px;
|
||||
}
|
||||
|
||||
fieldset label {
|
||||
width: 70px;
|
||||
float: left;
|
||||
margin-top: 1.7em;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
fieldset textfield {
|
||||
margin: 3px;
|
||||
height: 20px;
|
||||
background: #e0e7d3;
|
||||
}
|
||||
|
||||
fieldset textarea {
|
||||
margin: 3px;
|
||||
height: 165px;
|
||||
background: #e0e7d3;
|
||||
}
|
||||
|
||||
fieldset input {
|
||||
margin: 3px;
|
||||
height: 20px;
|
||||
background: #e0e7d3;
|
||||
}
|
||||
|
||||
fieldset table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
fieldset th {
|
||||
padding-left: 25px;
|
||||
}
|
||||
|
||||
.table-buttons {
|
||||
background-color:#fff;
|
||||
border:none;
|
||||
}
|
||||
|
||||
.table-buttons td {
|
||||
border:none;
|
||||
}
|
||||
|
||||
.submit input {
|
||||
background:url(../images/submit-bg.png) repeat-x;
|
||||
border: 2px outset #d7b9c9;
|
||||
color:#383838;
|
||||
padding:2px 10px;
|
||||
font-size:11px;
|
||||
text-transform:uppercase;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
.updated {
|
||||
background:#ecf1e5;
|
||||
font-size:11px;
|
||||
margin-left:2px;
|
||||
border:4px solid #ecf1e5;
|
||||
}
|
||||
|
||||
.updated td {
|
||||
padding:2px 8px;
|
||||
font-size:11px;
|
||||
color:#888888;
|
||||
}
|
|
@ -0,0 +1,224 @@
|
|||
package org.springframework.samples.petclinic;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.samples.petclinic.util.EntityUtils;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Base class for {@link Clinic} integration tests.
|
||||
* </p>
|
||||
* <p>
|
||||
* "AbstractClinicTests-context.xml" declares a common
|
||||
* {@link javax.sql.DataSource DataSource}. Subclasses should specify
|
||||
* additional context locations which declare a
|
||||
* {@link org.springframework.transaction.PlatformTransactionManager PlatformTransactionManager}
|
||||
* and a concrete implementation of {@link Clinic}.
|
||||
* </p>
|
||||
* <p>
|
||||
* This class extends {@link AbstractTransactionalJUnit4SpringContextTests},
|
||||
* one of the valuable testing support classes provided by the
|
||||
* <em>Spring TestContext Framework</em> found in the
|
||||
* <code>org.springframework.test.context</code> package. The
|
||||
* annotation-driven configuration used here represents best practice for
|
||||
* integration tests with Spring. Note, however, that
|
||||
* AbstractTransactionalJUnit4SpringContextTests serves only as a convenience
|
||||
* for extension. For example, if you do not wish for your test classes to be
|
||||
* tied to a Spring-specific class hierarchy, you may configure your tests with
|
||||
* annotations such as {@link ContextConfiguration @ContextConfiguration},
|
||||
* {@link org.springframework.test.context.TestExecutionListeners @TestExecutionListeners},
|
||||
* {@link org.springframework.transaction.annotation.Transactional @Transactional},
|
||||
* etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* AbstractClinicTests and its subclasses benefit from the following services
|
||||
* provided by the Spring TestContext Framework:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li><strong>Spring IoC container caching</strong> which spares us
|
||||
* unnecessary set up time between test execution.</li>
|
||||
* <li><strong>Dependency Injection</strong> of test fixture instances,
|
||||
* meaning that we don't need to perform application context lookups. See the
|
||||
* use of {@link Autowired @Autowired} on the <code>clinic</code> instance
|
||||
* variable, which uses autowiring <em>by type</em>. As an alternative, we
|
||||
* could annotate <code>clinic</code> with
|
||||
* {@link javax.annotation.Resource @Resource} to achieve dependency injection
|
||||
* <em>by name</em>.
|
||||
* <em>(see: {@link ContextConfiguration @ContextConfiguration},
|
||||
* {@link org.springframework.test.context.support.DependencyInjectionTestExecutionListener DependencyInjectionTestExecutionListener})</em></li>
|
||||
* <li><strong>Transaction management</strong>, meaning each test method is
|
||||
* executed in its own transaction, which is automatically rolled back by
|
||||
* default. Thus, even if tests insert or otherwise change database state, there
|
||||
* is no need for a teardown or cleanup script.
|
||||
* <em>(see: {@link org.springframework.test.context.transaction.TransactionConfiguration @TransactionConfiguration},
|
||||
* {@link org.springframework.transaction.annotation.Transactional @Transactional},
|
||||
* {@link org.springframework.test.context.transaction.TransactionalTestExecutionListener TransactionalTestExecutionListener})</em></li>
|
||||
* <li><strong>Useful inherited protected fields</strong>, such as a
|
||||
* {@link org.springframework.jdbc.core.simple.SimpleJdbcTemplate SimpleJdbcTemplate}
|
||||
* that can be used to verify database state after test operations or to verify
|
||||
* the results of queries performed by application code. An
|
||||
* {@link org.springframework.context.ApplicationContext ApplicationContext} is
|
||||
* also inherited and can be used for explicit bean lookup if necessary.
|
||||
* <em>(see: {@link org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests AbstractJUnit4SpringContextTests},
|
||||
* {@link AbstractTransactionalJUnit4SpringContextTests})</em></li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* The Spring TestContext Framework and related unit and integration testing
|
||||
* support classes are shipped in <code>spring-test.jar</code>.
|
||||
* </p>
|
||||
*
|
||||
* @author Ken Krebs
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
@ContextConfiguration
|
||||
public abstract class AbstractClinicTests extends AbstractTransactionalJUnit4SpringContextTests {
|
||||
|
||||
@Autowired
|
||||
protected Clinic clinic;
|
||||
|
||||
|
||||
@Test
|
||||
public void getVets() {
|
||||
Collection<Vet> vets = this.clinic.getVets();
|
||||
// Use the inherited countRowsInTable() convenience method (from
|
||||
// AbstractTransactionalJUnit4SpringContextTests) to verify the results.
|
||||
assertEquals("JDBC query must show the same number of vets", super.countRowsInTable("VETS"), vets.size());
|
||||
Vet v1 = EntityUtils.getById(vets, Vet.class, 2);
|
||||
assertEquals("Leary", v1.getLastName());
|
||||
assertEquals(1, v1.getNrOfSpecialties());
|
||||
assertEquals("radiology", (v1.getSpecialties().get(0)).getName());
|
||||
Vet v2 = EntityUtils.getById(vets, Vet.class, 3);
|
||||
assertEquals("Douglas", v2.getLastName());
|
||||
assertEquals(2, v2.getNrOfSpecialties());
|
||||
assertEquals("dentistry", (v2.getSpecialties().get(0)).getName());
|
||||
assertEquals("surgery", (v2.getSpecialties().get(1)).getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPetTypes() {
|
||||
Collection<PetType> petTypes = this.clinic.getPetTypes();
|
||||
assertEquals("JDBC query must show the same number of pet types", super.countRowsInTable("TYPES"),
|
||||
petTypes.size());
|
||||
PetType t1 = EntityUtils.getById(petTypes, PetType.class, 1);
|
||||
assertEquals("cat", t1.getName());
|
||||
PetType t4 = EntityUtils.getById(petTypes, PetType.class, 4);
|
||||
assertEquals("snake", t4.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findOwners() {
|
||||
Collection<Owner> owners = this.clinic.findOwners("Davis");
|
||||
assertEquals(2, owners.size());
|
||||
owners = this.clinic.findOwners("Daviss");
|
||||
assertEquals(0, owners.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadOwner() {
|
||||
Owner o1 = this.clinic.loadOwner(1);
|
||||
assertTrue(o1.getLastName().startsWith("Franklin"));
|
||||
Owner o10 = this.clinic.loadOwner(10);
|
||||
assertEquals("Carlos", o10.getFirstName());
|
||||
|
||||
// XXX: Add programmatic support for ending transactions with the
|
||||
// TestContext Framework.
|
||||
|
||||
// Check lazy loading, by ending the transaction:
|
||||
// endTransaction();
|
||||
|
||||
// Now Owners are "disconnected" from the data store.
|
||||
// We might need to touch this collection if we switched to lazy loading
|
||||
// in mapping files, but this test would pick this up.
|
||||
o1.getPets();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void insertOwner() {
|
||||
Collection<Owner> owners = this.clinic.findOwners("Schultz");
|
||||
int found = owners.size();
|
||||
Owner owner = new Owner();
|
||||
owner.setLastName("Schultz");
|
||||
this.clinic.storeOwner(owner);
|
||||
// assertTrue(!owner.isNew()); -- NOT TRUE FOR TOPLINK (before commit)
|
||||
owners = this.clinic.findOwners("Schultz");
|
||||
assertEquals("Verifying number of owners after inserting a new one.", found + 1, owners.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateOwner() throws Exception {
|
||||
Owner o1 = this.clinic.loadOwner(1);
|
||||
String old = o1.getLastName();
|
||||
o1.setLastName(old + "X");
|
||||
this.clinic.storeOwner(o1);
|
||||
o1 = this.clinic.loadOwner(1);
|
||||
assertEquals(old + "X", o1.getLastName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadPet() {
|
||||
Collection<PetType> types = this.clinic.getPetTypes();
|
||||
Pet p7 = this.clinic.loadPet(7);
|
||||
assertTrue(p7.getName().startsWith("Samantha"));
|
||||
assertEquals(EntityUtils.getById(types, PetType.class, 1).getId(), p7.getType().getId());
|
||||
assertEquals("Jean", p7.getOwner().getFirstName());
|
||||
Pet p6 = this.clinic.loadPet(6);
|
||||
assertEquals("George", p6.getName());
|
||||
assertEquals(EntityUtils.getById(types, PetType.class, 4).getId(), p6.getType().getId());
|
||||
assertEquals("Peter", p6.getOwner().getFirstName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void insertPet() {
|
||||
Owner o6 = this.clinic.loadOwner(6);
|
||||
int found = o6.getPets().size();
|
||||
Pet pet = new Pet();
|
||||
pet.setName("bowser");
|
||||
Collection<PetType> types = this.clinic.getPetTypes();
|
||||
pet.setType(EntityUtils.getById(types, PetType.class, 2));
|
||||
pet.setBirthDate(new Date());
|
||||
o6.addPet(pet);
|
||||
assertEquals(found + 1, o6.getPets().size());
|
||||
// both storePet and storeOwner are necessary to cover all ORM tools
|
||||
this.clinic.storePet(pet);
|
||||
this.clinic.storeOwner(o6);
|
||||
// assertTrue(!pet.isNew()); -- NOT TRUE FOR TOPLINK (before commit)
|
||||
o6 = this.clinic.loadOwner(6);
|
||||
assertEquals(found + 1, o6.getPets().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updatePet() throws Exception {
|
||||
Pet p7 = this.clinic.loadPet(7);
|
||||
String old = p7.getName();
|
||||
p7.setName(old + "X");
|
||||
this.clinic.storePet(p7);
|
||||
p7 = this.clinic.loadPet(7);
|
||||
assertEquals(old + "X", p7.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void insertVisit() {
|
||||
Pet p7 = this.clinic.loadPet(7);
|
||||
int found = p7.getVisits().size();
|
||||
Visit visit = new Visit();
|
||||
p7.addVisit(visit);
|
||||
visit.setDescription("test");
|
||||
// both storeVisit and storePet are necessary to cover all ORM tools
|
||||
this.clinic.storeVisit(visit);
|
||||
this.clinic.storePet(p7);
|
||||
// assertTrue(!visit.isNew()); -- NOT TRUE FOR TOPLINK (before commit)
|
||||
p7 = this.clinic.loadPet(7);
|
||||
assertEquals(found + 1, p7.getVisits().size());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package org.springframework.samples.petclinic;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* JUnit test for the {@link Owner} class.
|
||||
*
|
||||
* @author Ken Krebs
|
||||
*/
|
||||
public class OwnerTests {
|
||||
|
||||
@Test
|
||||
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"));
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue