restructure ui layout

This commit is contained in:
Dapeng 2016-09-19 16:48:58 +08:00
parent a2a9725618
commit db3fc815be
28 changed files with 182 additions and 1518 deletions

442
pom.xml
View file

@ -1,6 +1,13 @@
<?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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.0.RELEASE</version>
</parent>
<groupId>org.springframework.samples</groupId>
<artifactId>spring-petclinic</artifactId>
<version>1.0.0-SNAPSHOT</version>
@ -8,441 +15,72 @@
<name>petclinic</name>
<packaging>war</packaging>
<properties>
<!-- Generic properties -->
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- Spring -->
<spring-framework.version>4.1.6.RELEASE</spring-framework.version>
<spring-data-jpa.version>1.8.0.RELEASE</spring-data-jpa.version>
<!-- Java EE / Java SE dependencies -->
<jsp.version>2.2</jsp.version>
<jstl.version>1.2</jstl.version>
<tomcat.servlet.version>7.0.47</tomcat.servlet.version>
<jaxb-impl.version>2.2.7</jaxb-impl.version>
<!-- Hibernate / JPA -->
<hibernate.version>4.3.8.Final</hibernate.version>
<!-- Bean validation -->
<hibernate-validator.version>4.3.1.Final</hibernate-validator.version>
<!-- Database access -->
<tomcat-jdbc.version>7.0.42</tomcat-jdbc.version>
<ehcache.version>2.6.10</ehcache.version>
<hsqldb.version>2.3.2</hsqldb.version>
<!-- AOP -->
<aspectj.version>1.8.5</aspectj.version>
<!-- Logging -->
<logback.version>1.1.3</logback.version>
<slf4j.version>1.7.12</slf4j.version>
<!-- JSon-->
<json-path.version>2.0.0</json-path.version>
<!-- Test -->
<junit.version>4.12</junit.version>
<assertj.version>3.0.0</assertj.version>
<!-- Dates -->
<jodatime-hibernate.version>1.3</jodatime-hibernate.version>
<jodatime-jsptags.version>1.1.1</jodatime-jsptags.version>
<jodatime.version>2.7</jodatime.version>
<jadira-usertype-core.version>3.2.0.GA</jadira-usertype-core.version>
<jackson.datatype.joda.version>2.4.5</jackson.datatype.joda.version>
<!-- Web dependencies -->
<webjars-bootstrap.version>2.3.0</webjars-bootstrap.version>
<webjars-jquery-ui.version>1.10.3</webjars-jquery-ui.version>
<webjars-jquery.version>2.0.3-1</webjars-jquery.version>
<dandelion.version>0.10.1</dandelion.version>
<mysql.version>5.1.22</mysql.version>
<cobertura.version>2.7</cobertura.version>
</properties>
<dependencies>
<dependency>
<groupId>org.jadira.usertype</groupId>
<artifactId>usertype.core</artifactId>
<version>${jadira-usertype-core.version}</version>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-servlet-api</artifactId>
<version>${tomcat.servlet.version}</version>
<scope>provided</scope>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>jstl-impl</artifactId>
<version>1.2</version>
<exclusions>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>${jaxb-impl.version}</version>
<scope>provided</scope>
</dependency>
<!-- JSon -->
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>${json-path.version}</version>
<scope>test</scope>
</dependency>
<!-- SPRING, SPRING, SPRINGITY SPRING -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>${spring-data-jpa.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>*</artifactId>
</exclusion>
<!-- because Spring Data usually comes with a slightly older version of Spring -->
</exclusions>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<!-- used for EhCacheCacheManager -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${spring-framework.version}</version>
<exclusions>
<exclusion>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
<scope>runtime</scope>
</dependency>
<!-- Database connection pool
See here for more details on commons-dbcp versus tomcat-jdbc:
http://blog.ippon.fr/2013/03/13/improving-the-performance-of-the-spring-petclinic-sample-application-part-3-of-5/
-->
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
<version>${tomcat-jdbc.version}</version>
<scope>runtime</scope>
</dependency>
<!-- Logging with SLF4J & LogBack -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
<scope>runtime</scope>
</dependency>
<!-- Date and Time -->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>${jodatime.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-joda</artifactId>
<version>${jackson.datatype.joda.version}</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time-hibernate</artifactId>
<version>${jodatime-hibernate.version}</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time-jsptags</artifactId>
<version>${jodatime-jsptags.version}</version>
</dependency>
<!-- Databases - Uses HSQL by default -->
<!-- <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> -->
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>${hsqldb.version}</version>
<scope>runtime</scope>
</dependency>
<!-- For MySql only -->
<!-- <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> -->
<!-- HIBERNATE -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>${hibernate-validator.version}</version>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>${ehcache.version}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Webjars (static dependencies distributed as JAR files) -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>${webjars-bootstrap.version}</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery-ui</artifactId>
<version>${webjars-jquery-ui.version}</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>${webjars-jquery.version}</version>
</dependency>
<!-- Test Artifacts -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring-framework.version}</version>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${assertj.version}</version>
</dependency>
<!-- Dandelion -->
<dependency>
<groupId>com.github.dandelion</groupId>
<artifactId>datatables-jsp</artifactId>
<version>${dandelion.version}</version>
</dependency>
<dependency>
<groupId>com.github.dandelion</groupId>
<artifactId>datatables-export-itext</artifactId>
<version>${dandelion.version}</version>
</dependency>
</dependencies>
<!-- Maven plugin versions are mentioned in order to guarantee the build reproducibility in the long term -->
<build>
<defaultGoal>install</defaultGoal>
<testResources>
<testResource>
<!-- declared explicitly so Spring config files can be placed next to their corresponding JUnit test class -->
<directory>${project.basedir}/src/test/java</directory>
</testResource>
<testResource>
<directory>${project.basedir}/src/test/resources</directory>
</testResource>
</testResources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<compilerArguments>
<Xlint />
</compilerArguments>
<verbose>true</verbose>
<source>${java.version}</source>
<target>${java.version}</target>
<showWarnings>true</showWarnings>
<fork>true</fork>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.13</version>
<configuration>
<includes>
<include>**/*Tests.java</include>
</includes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<warName>petclinic</warName>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.9</version>
<configuration>
<downloadSources>true</downloadSources>
<downloadJavadocs>true</downloadJavadocs>
<wtpversion>2.0</wtpversion>
<sourceIncludes>
<sourceInclude>**/*.*</sourceInclude>
</sourceIncludes>
<additionalBuildcommands>
<buildCommand>
<name>org.springframework.ide.eclipse.core.springbuilder</name>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
</buildCommand>
</additionalBuildcommands>
<additionalProjectnatures>
<projectnature>org.eclipse.jdt.core.javanature</projectnature>
<projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
<projectnature>org.eclipse.m2e.core.maven2Nature</projectnature>
</additionalProjectnatures>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<server>tomcat-development-server</server>
<port>9966</port>
<path>/petclinic</path>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>${cobertura.version}</version>
<configuration>
</configuration>
<executions>
<execution>
<goals>
<goal>clean</goal>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<!-- integrate maven-cobertura-plugin to project site -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>${cobertura.version}</version>
<configuration>
<formats>
<format>html</format>
</formats>
</configuration>
</plugin>
</plugins>
</reporting>
<url>demopetclinic</url>
</project>

View file

@ -0,0 +1,12 @@
package org.springframework.samples.petclinic;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class PetClinicApplication {
public static void main(String[] args) {
SpringApplication.run(PetClinicApplication.class, args);
}
}

View file

@ -1,40 +0,0 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.samples.petclinic.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* Controller used to showcase what happens when an exception is thrown
*
* @author Michael Isvy
* <p/>
* Also see how the bean of type 'SimpleMappingExceptionResolver' has been declared inside
* /WEB-INF/mvc-core-config.xml
*/
@Controller
public class CrashController {
@RequestMapping(value = "/oups", method = RequestMethod.GET)
public String triggerException() {
throw new RuntimeException("Expected: controller used to showcase what " +
"happens when an exception is thrown");
}
}

View file

@ -31,6 +31,8 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
/**
* @author Juergen Hoeller
* @author Ken Krebs
@ -98,7 +100,7 @@ public class OwnerResource {
* Update Owner
*/
@RequestMapping(value = "/owner/{ownerId}", method = RequestMethod.PUT)
public Owner updateOwner(@PathVariable("ownerId") int ownerId, @RequestBody Owner ownerRequest) {
public Owner updateOwner(@PathVariable("ownerId") int ownerId, @Valid @RequestBody Owner ownerRequest) {
Owner ownerModel = retrieveOwner(ownerId);
// This is done by hand for simplicity purpose. In a real life use-case we should consider using MapStruct.
ownerModel.setFirstName(ownerRequest.getFirstName());

View file

@ -15,19 +15,23 @@
*/
package org.springframework.samples.petclinic.web;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.samples.petclinic.model.Owner;
import org.springframework.samples.petclinic.model.Pet;
import org.springframework.samples.petclinic.model.PetType;
import org.springframework.samples.petclinic.service.ClinicService;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.GetMapping;
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.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@ -43,23 +47,22 @@ public class PetResource {
private final ClinicService clinicService;
@Autowired
public PetResource(ClinicService clinicService) {
this.clinicService = clinicService;
}
@ModelAttribute("types")
public Collection<PetType> populatePetTypes() {
return this.clinicService.findPetTypes();
}
@InitBinder
public void setAllowedFields(WebDataBinder dataBinder) {
dataBinder.setDisallowedFields("id");
}
@RequestMapping(value = "/owners/{ownerId}/pets/new", method = RequestMethod.GET)
@GetMapping("/petTypes")
Object getPetTypes() {
return clinicService.findPetTypes();
}
@GetMapping("/owners/{ownerId}/pets/new")
public String initCreationForm(@PathVariable("ownerId") int ownerId, Map<String, Object> model) {
Owner owner = this.clinicService.findOwnerById(ownerId);
Pet pet = new Pet();
@ -68,7 +71,7 @@ public class PetResource {
return "pets/createOrUpdatePetForm";
}
@RequestMapping(value = "/owners/{ownerId}/pets/new", method = RequestMethod.POST)
@PostMapping("/owners/{ownerId}/pets/new")
public String processCreationForm(@ModelAttribute("pet") Pet pet, BindingResult result, SessionStatus status) {
new PetValidator().validate(pet, result);
if (result.hasErrors()) {
@ -80,10 +83,10 @@ public class PetResource {
}
}
@RequestMapping(value = "/owner/*/pet/{petId}", method = RequestMethod.GET)
public Pet findPet(@PathVariable("petId") int petId) {
@GetMapping("/owner/*/pet/{petId}")
public PetDetails findPet(@PathVariable("petId") int petId) {
Pet pet = this.clinicService.findPetById(petId);
return pet;
return new PetDetails(pet);
}
@RequestMapping(value = "/owners/{ownerId}/pets/{petId}/edit", method = {RequestMethod.PUT, RequestMethod.POST})
@ -99,4 +102,24 @@ public class PetResource {
}
}
@Getter
static class PetDetails {
long id;
String name;
String owner;
@DateTimeFormat(pattern = "yyyy-MM-dd")
Date birthDate;
PetType type;
PetDetails(Pet pet) {
this.id = pet.getId();
this.name = pet.getName();
this.owner = pet.getOwner().getFirstName() + " " + pet.getOwner().getLastName();
this.birthDate = pet.getBirthDate();
this.type = pet.getType();
}
}
}

View file

@ -1,66 +0,0 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.samples.petclinic.web;
import java.text.ParseException;
import java.util.Collection;
import java.util.Locale;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.Formatter;
import org.springframework.samples.petclinic.model.PetType;
import org.springframework.samples.petclinic.service.ClinicService;
/**
* Instructs Spring MVC on how to parse and print elements of type 'PetType'. Starting from Spring 3.0, Formatters have
* come as an improvement in comparison to legacy PropertyEditors. See the following links for more details: - The
* Spring ref doc: http://static.springsource.org/spring/docs/current/spring-framework-reference/html/validation.html#format-Formatter-SPI
* - A nice blog entry from Gordon Dickens: http://gordondickens.com/wordpress/2010/09/30/using-spring-3-0-custom-type-converter/
* <p/>
* Also see how the bean 'conversionService' has been declared inside /WEB-INF/mvc-core-config.xml
*
* @author Mark Fisher
* @author Juergen Hoeller
* @author Michael Isvy
*/
public class PetTypeFormatter implements Formatter<PetType> {
private final ClinicService clinicService;
@Autowired
public PetTypeFormatter(ClinicService clinicService) {
this.clinicService = clinicService;
}
@Override
public String print(PetType petType, Locale locale) {
return petType.getName();
}
@Override
public PetType parse(String text, Locale locale) throws ParseException {
Collection<PetType> findPetTypes = this.clinicService.findPetTypes();
for (PetType type : findPetTypes) {
if (type.getName().equals(text)) {
return type;
}
}
throw new ParseException("type not found: " + text, 0);
}
}

View file

@ -21,6 +21,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.samples.petclinic.model.Vet;
import org.springframework.samples.petclinic.service.ClinicService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@ -36,17 +37,13 @@ public class VetResource {
private final ClinicService clinicService;
@Autowired
public VetResource(ClinicService clinicService) {
this.clinicService = clinicService;
}
@RequestMapping(value="/vets", method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
@GetMapping("/vets")
public Collection<Vet> showResourcesVetList() {
return this.clinicService.findVets();
}
}

View file

@ -26,9 +26,11 @@ import org.springframework.samples.petclinic.service.ClinicService;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.GetMapping;
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.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@ -72,13 +74,13 @@ public class VisitController {
}
// Spring MVC calls method loadPetWithVisit(...) before initNewVisitForm is called
@RequestMapping(value = "/owners/*/pets/{petId}/visits/new", method = RequestMethod.GET)
@GetMapping("/owners/*/pets/{petId}/visits/new")
public String initNewVisitForm(@PathVariable("petId") int petId, Map<String, Object> model) {
return "pets/createOrUpdateVisitForm";
}
// Spring MVC calls method loadPetWithVisit(...) before processNewVisitForm is called
@RequestMapping(value = "/owners/{ownerId}/pets/{petId}/visits/new", method = RequestMethod.POST)
@PostMapping("/owners/{ownerId}/pets/{petId}/visits/new")
public String processNewVisitForm(@Valid Visit visit, BindingResult result) {
if (result.hasErrors()) {
return "pets/createOrUpdateVisitForm";
@ -88,7 +90,7 @@ public class VisitController {
}
}
@RequestMapping(value = "/owners/*/pets/{petId}/visits", method = RequestMethod.GET)
@GetMapping("/owners/*/pets/{petId}/visits")
public String showVisits(@PathVariable int petId, Map<String, Object> model) {
model.put("visits", this.clinicService.findPetById(petId).getVisits());
return "visitList";

View file

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

View file

@ -0,0 +1,22 @@
# database init, supports mysql too
database=hsqldb
spring.datasource.schema=classpath*:db/${database}/schema.sql
spring.datasource.data=classpath*:db/${database}/data.sql
# Web
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
# JPA
spring.jpa.hibernate.ddl-auto=none
# Internationalization
spring.messages.basename=messages/messages
# Actuator / Management
management.contextPath=/manage
# Logging
logging.level.org.springframework=INFO
server.context-path=/petclinic

View file

@ -1,17 +0,0 @@
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd"
updateCheck="false">
<diskStore path="java.io.tmpdir"/>
<!-- objects are evicted from the cache every 60 seconds -->
<cache name="vets"
timeToLiveSeconds="60"
maxElementsInMemory="100"
eternal="false"
overflowToDisk="false"
maxElementsOnDisk="10000000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="1"
memoryStoreEvictionPolicy="LRU"/>
</ehcache>

View file

@ -1,419 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" version="1.7">
<xs:element name="ehcache">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="1" minOccurs="0" ref="managementRESTService"/>
<xs:element maxOccurs="1" minOccurs="0" ref="diskStore"/>
<xs:element maxOccurs="1" minOccurs="0" ref="sizeOfPolicy"/>
<xs:element maxOccurs="1" minOccurs="0" ref="transactionManagerLookup"/>
<xs:element maxOccurs="1" minOccurs="0" ref="cacheManagerEventListenerFactory"/>
<xs:element maxOccurs="unbounded" minOccurs="0" ref="cacheManagerPeerProviderFactory"/>
<xs:element maxOccurs="unbounded" minOccurs="0" ref="cacheManagerPeerListenerFactory"/>
<xs:element maxOccurs="1" minOccurs="0" ref="terracottaConfig"/>
<xs:element maxOccurs="1" minOccurs="0" ref="defaultCache"/>
<xs:element maxOccurs="unbounded" minOccurs="0" ref="cache"/>
</xs:sequence>
<xs:attribute name="name" use="optional"/>
<xs:attribute default="true" name="updateCheck" type="xs:boolean" use="optional"/>
<xs:attribute default="autodetect" name="monitoring" type="monitoringType" use="optional"/>
<xs:attribute default="true" name="dynamicConfig" type="xs:boolean" use="optional"/>
<xs:attribute default="15" name="defaultTransactionTimeoutInSeconds" type="xs:integer" use="optional"/>
<xs:attribute default="0" name="maxBytesLocalHeap" type="memoryUnitOrPercentage" use="optional"/>
<xs:attribute default="0" name="maxBytesLocalOffHeap" type="memoryUnit" use="optional"/>
<xs:attribute default="0" name="maxBytesLocalDisk" type="memoryUnit" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="managementRESTService">
<xs:complexType>
<xs:attribute name="enabled" type="xs:boolean" use="optional"/>
<xs:attribute name="bind" use="optional"/>
<xs:attribute name="securityServiceLocation" use="optional"/>
<xs:attribute name="securityServiceTimeout" use="optional" type="xs:integer"/>
<xs:attribute name="sslEnabled" use="optional" type="xs:boolean"/>
<xs:attribute name="needClientAuth" use="optional" type="xs:boolean"/>
<xs:attribute name="sampleHistorySize" use="optional" type="xs:integer"/>
<xs:attribute name="sampleIntervalSeconds" use="optional" type="xs:integer"/>
<xs:attribute name="sampleSearchIntervalSeconds" use="optional" type="xs:integer"/>
</xs:complexType>
</xs:element>
<xs:element name="diskStore">
<xs:complexType>
<xs:attribute name="path" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="transactionManagerLookup">
<xs:complexType>
<xs:attribute name="class" use="required"/>
<xs:attribute name="properties" use="optional"/>
<xs:attribute name="propertySeparator" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="cacheManagerEventListenerFactory">
<xs:complexType>
<xs:attribute name="class" use="required"/>
<xs:attribute name="properties" use="optional"/>
<xs:attribute name="propertySeparator" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="cacheManagerPeerProviderFactory">
<xs:complexType>
<xs:attribute name="class" use="required"/>
<xs:attribute name="properties" use="optional"/>
<xs:attribute name="propertySeparator" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="cacheManagerPeerListenerFactory">
<xs:complexType>
<xs:attribute name="class" use="required"/>
<xs:attribute name="properties" use="optional"/>
<xs:attribute name="propertySeparator" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="terracottaConfig">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="1" minOccurs="0" name="tc-config">
<xs:complexType>
<xs:sequence>
<xs:any maxOccurs="unbounded" minOccurs="0" processContents="skip"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute default="localhost:9510" name="url" use="optional"/>
<xs:attribute name="rejoin" type="xs:boolean" use="optional" default="false"/>
</xs:complexType>
</xs:element>
<!-- add clone support for addition of cacheExceptionHandler. Important! -->
<xs:element name="defaultCache">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheEventListenerFactory"/>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheExtensionFactory"/>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheLoaderFactory"/>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheDecoratorFactory"/>
<xs:element minOccurs="0" maxOccurs="1" ref="bootstrapCacheLoaderFactory"/>
<xs:element minOccurs="0" maxOccurs="1" ref="cacheExceptionHandlerFactory"/>
<xs:element minOccurs="0" maxOccurs="1" ref="pinning"/>
<xs:element minOccurs="0" maxOccurs="1" ref="terracotta"/>
<xs:element minOccurs="0" maxOccurs="1" ref="cacheWriter"/>
<xs:element minOccurs="0" maxOccurs="1" ref="copyStrategy"/>
<xs:element minOccurs="0" maxOccurs="1" ref="elementValueComparator"/>
<xs:element minOccurs="0" maxOccurs="1" ref="sizeOfPolicy"/>
<xs:element minOccurs="0" maxOccurs="1" ref="persistence"/>
</xs:sequence>
<xs:attribute name="diskExpiryThreadIntervalSeconds" type="xs:integer" use="optional"/>
<xs:attribute name="diskSpoolBufferSizeMB" type="xs:integer" use="optional"/>
<xs:attribute name="diskPersistent" type="xs:boolean" use="optional"/>
<xs:attribute name="diskAccessStripes" type="xs:integer" use="optional" default="1"/>
<xs:attribute name="eternal" type="xs:boolean" use="optional" default="false"/>
<xs:attribute name="maxElementsInMemory" type="xs:integer" use="optional"/>
<xs:attribute name="maxEntriesLocalHeap" type="xs:integer" use="optional"/>
<xs:attribute name="clearOnFlush" type="xs:boolean" use="optional"/>
<xs:attribute name="memoryStoreEvictionPolicy" type="xs:string" use="optional"/>
<xs:attribute name="overflowToDisk" type="xs:boolean" use="optional"/>
<xs:attribute name="timeToIdleSeconds" type="xs:integer" use="optional"/>
<xs:attribute name="timeToLiveSeconds" type="xs:integer" use="optional"/>
<xs:attribute name="maxElementsOnDisk" type="xs:integer" use="optional"/>
<xs:attribute name="maxEntriesLocalDisk" type="xs:integer" use="optional"/>
<xs:attribute name="transactionalMode" type="transactionalMode" use="optional" default="off"/>
<xs:attribute name="statistics" type="xs:boolean" use="optional" default="false"/>
<xs:attribute name="copyOnRead" type="xs:boolean" use="optional" default="false"/>
<xs:attribute name="copyOnWrite" type="xs:boolean" use="optional" default="false"/>
<xs:attribute name="cacheLoaderTimeoutMillis" type="xs:integer" use="optional" default="0"/>
<xs:attribute name="overflowToOffHeap" type="xs:boolean" use="optional" default="false"/>
<xs:attribute name="maxMemoryOffHeap" type="xs:string" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="cache">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheEventListenerFactory"/>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheExtensionFactory"/>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheLoaderFactory"/>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheDecoratorFactory"/>
<xs:element minOccurs="0" maxOccurs="1" ref="bootstrapCacheLoaderFactory"/>
<xs:element minOccurs="0" maxOccurs="1" ref="cacheExceptionHandlerFactory"/>
<xs:element minOccurs="0" maxOccurs="1" ref="pinning"/>
<xs:element minOccurs="0" maxOccurs="1" ref="terracotta"/>
<xs:element minOccurs="0" maxOccurs="1" ref="cacheWriter"/>
<xs:element minOccurs="0" maxOccurs="1" ref="copyStrategy"/>
<xs:element minOccurs="0" maxOccurs="1" ref="searchable"/>
<xs:element minOccurs="0" maxOccurs="1" ref="elementValueComparator"/>
<xs:element minOccurs="0" maxOccurs="1" ref="sizeOfPolicy"/>
<xs:element minOccurs="0" maxOccurs="1" ref="persistence"/>
</xs:sequence>
<xs:attribute name="diskExpiryThreadIntervalSeconds" type="xs:integer" use="optional"/>
<xs:attribute name="diskSpoolBufferSizeMB" type="xs:integer" use="optional"/>
<xs:attribute name="diskPersistent" type="xs:boolean" use="optional"/>
<xs:attribute name="diskAccessStripes" type="xs:integer" use="optional" default="1"/>
<xs:attribute name="eternal" type="xs:boolean" use="optional" default="false"/>
<xs:attribute name="maxElementsInMemory" type="xs:integer" use="optional"/>
<xs:attribute name="maxEntriesLocalHeap" type="xs:integer" use="optional"/>
<xs:attribute name="memoryStoreEvictionPolicy" type="xs:string" use="optional"/>
<xs:attribute name="clearOnFlush" type="xs:boolean" use="optional"/>
<xs:attribute name="name" type="xs:string" use="required"/>
<xs:attribute name="overflowToDisk" type="xs:boolean" use="optional"/>
<xs:attribute name="timeToIdleSeconds" type="xs:integer" use="optional"/>
<xs:attribute name="timeToLiveSeconds" type="xs:integer" use="optional"/>
<xs:attribute name="maxElementsOnDisk" type="xs:integer" use="optional"/>
<xs:attribute name="maxEntriesLocalDisk" type="xs:integer" use="optional"/>
<xs:attribute name="transactionalMode" type="transactionalMode" use="optional" default="off"/>
<xs:attribute name="statistics" type="xs:boolean" use="optional" default="false"/>
<xs:attribute name="copyOnRead" type="xs:boolean" use="optional" default="false"/>
<xs:attribute name="copyOnWrite" type="xs:boolean" use="optional" default="false"/>
<xs:attribute name="logging" type="xs:boolean" use="optional" default="false"/>
<xs:attribute name="cacheLoaderTimeoutMillis" type="xs:integer" use="optional" default="0"/>
<xs:attribute name="overflowToOffHeap" type="xs:boolean" use="optional" default="false"/>
<xs:attribute name="maxMemoryOffHeap" type="xs:string" use="optional"/>
<xs:attribute default="0" name="maxBytesLocalHeap" type="memoryUnitOrPercentage" use="optional"/>
<xs:attribute default="0" name="maxBytesLocalOffHeap" type="memoryUnitOrPercentage" use="optional"/>
<xs:attribute default="0" name="maxBytesLocalDisk" type="memoryUnitOrPercentage" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="cacheEventListenerFactory">
<xs:complexType>
<xs:attribute name="class" use="required"/>
<xs:attribute name="properties" use="optional"/>
<xs:attribute name="propertySeparator" use="optional"/>
<xs:attribute name="listenFor" use="optional" type="notificationScope" default="all"/>
</xs:complexType>
</xs:element>
<xs:element name="bootstrapCacheLoaderFactory">
<xs:complexType>
<xs:attribute name="class" use="required"/>
<xs:attribute name="properties" use="optional"/>
<xs:attribute name="propertySeparator" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="cacheExtensionFactory">
<xs:complexType>
<xs:attribute name="class" use="required"/>
<xs:attribute name="properties" use="optional"/>
<xs:attribute name="propertySeparator" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="cacheExceptionHandlerFactory">
<xs:complexType>
<xs:attribute name="class" use="required"/>
<xs:attribute name="properties" use="optional"/>
<xs:attribute name="propertySeparator" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="cacheLoaderFactory">
<xs:complexType>
<xs:attribute name="class" use="required"/>
<xs:attribute name="properties" use="optional"/>
<xs:attribute name="propertySeparator" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="cacheDecoratorFactory">
<xs:complexType>
<xs:attribute name="class" use="required"/>
<xs:attribute name="properties" use="optional"/>
<xs:attribute name="propertySeparator" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="searchAttribute">
<xs:complexType>
<xs:attribute name="name" use="required" type="xs:string"/>
<xs:attribute name="expression" type="xs:string"/>
<xs:attribute name="class" type="xs:string"/>
<xs:attribute name="properties" use="optional"/>
<xs:attribute name="propertySeparator" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="searchable">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="searchAttribute"/>
</xs:sequence>
<xs:attribute name="keys" use="optional" type="xs:boolean" default="true"/>
<xs:attribute name="values" use="optional" type="xs:boolean" default="true"/>
</xs:complexType>
</xs:element>
<xs:element name="pinning">
<xs:complexType>
<xs:attribute name="store" use="required" type="pinningStoreType"/>
</xs:complexType>
</xs:element>
<xs:element name="terracotta">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" ref="nonstop"/>
</xs:sequence>
<xs:attribute name="clustered" use="optional" type="xs:boolean" default="true"/>
<xs:attribute name="valueMode" use="optional" type="terracottaCacheValueType" default="serialization"/>
<xs:attribute name="coherentReads" use="optional" type="xs:boolean" default="true"/>
<xs:attribute name="localKeyCache" use="optional" type="xs:boolean" default="false"/>
<xs:attribute name="localKeyCacheSize" use="optional" type="xs:positiveInteger" default="300000"/>
<xs:attribute name="orphanEviction" use="optional" type="xs:boolean" default="true"/>
<xs:attribute name="orphanEvictionPeriod" use="optional" type="xs:positiveInteger" default="4"/>
<xs:attribute name="copyOnRead" use="optional" type="xs:boolean" default="false"/>
<xs:attribute name="coherent" use="optional" type="xs:boolean" default="false"/>
<xs:attribute name="consistency" use="optional" type="consistencyType" default="eventual"/>
<xs:attribute name="synchronousWrites" use="optional" type="xs:boolean" default="false"/>
<xs:attribute name="concurrency" use="optional" type="xs:nonNegativeInteger" default="0"/>
<xs:attribute name="localCacheEnabled" use="optional" type="xs:boolean" default="true"/>
<xs:attribute name="compressionEnabled" use="optional" type="xs:boolean" default="false"/>
</xs:complexType>
</xs:element>
<xs:simpleType name="consistencyType">
<xs:restriction base="xs:string">
<xs:enumeration value="strong"/>
<xs:enumeration value="eventual"/>
</xs:restriction>
</xs:simpleType>
<xs:element name="nonstop">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" ref="timeoutBehavior"/>
</xs:sequence>
<xs:attribute name="enabled" use="optional" type="xs:boolean" default="true"/>
<xs:attribute name="immediateTimeout" use="optional" type="xs:boolean" default="false"/>
<xs:attribute name="timeoutMillis" use="optional" type="xs:positiveInteger" default="30000"/>
</xs:complexType>
</xs:element>
<xs:element name="timeoutBehavior">
<xs:complexType>
<xs:attribute name="type" use="optional" type="timeoutBehaviorType" default="exception"/>
<xs:attribute name="properties" use="optional" default=""/>
<xs:attribute name="propertySeparator" use="optional" default=","/>
</xs:complexType>
</xs:element>
<xs:simpleType name="timeoutBehaviorType">
<xs:restriction base="xs:string">
<xs:enumeration value="noop"/>
<xs:enumeration value="exception"/>
<xs:enumeration value="localReads"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="monitoringType">
<xs:restriction base="xs:string">
<xs:enumeration value="autodetect"/>
<xs:enumeration value="on"/>
<xs:enumeration value="off"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="pinningStoreType">
<xs:restriction base="xs:string">
<xs:enumeration value="localHeap"/>
<xs:enumeration value="localMemory"/>
<xs:enumeration value="inCache"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="terracottaCacheValueType">
<xs:restriction base="xs:string">
<xs:enumeration value="serialization"/>
<xs:enumeration value="identity"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="transactionalMode">
<xs:restriction base="xs:string">
<xs:enumeration value="off"/>
<xs:enumeration value="xa_strict"/>
<xs:enumeration value="xa"/>
<xs:enumeration value="local"/>
</xs:restriction>
</xs:simpleType>
<xs:element name="cacheWriter">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" ref="cacheWriterFactory"/>
</xs:sequence>
<xs:attribute name="writeMode" use="optional" type="writeModeType" default="write-through"/>
<xs:attribute name="notifyListenersOnException" use="optional" type="xs:boolean" default="false"/>
<xs:attribute name="minWriteDelay" use="optional" type="xs:nonNegativeInteger" default="1"/>
<xs:attribute name="maxWriteDelay" use="optional" type="xs:nonNegativeInteger" default="1"/>
<xs:attribute name="rateLimitPerSecond" use="optional" type="xs:nonNegativeInteger" default="0"/>
<xs:attribute name="writeCoalescing" use="optional" type="xs:boolean" default="false"/>
<xs:attribute name="writeBatching" use="optional" type="xs:boolean" default="false"/>
<xs:attribute name="writeBatchSize" use="optional" type="xs:positiveInteger" default="1"/>
<xs:attribute name="retryAttempts" use="optional" type="xs:nonNegativeInteger" default="0"/>
<xs:attribute name="retryAttemptDelaySeconds" use="optional" type="xs:nonNegativeInteger" default="1"/>
<xs:attribute name="writeBehindConcurrency" use="optional" type="xs:nonNegativeInteger" default="1"/>
<xs:attribute name="writeBehindMaxQueueSize" use="optional" type="xs:nonNegativeInteger" default="0"/>
</xs:complexType>
</xs:element>
<xs:simpleType name="writeModeType">
<xs:restriction base="xs:string">
<xs:enumeration value="write-through"/>
<xs:enumeration value="write-behind"/>
</xs:restriction>
</xs:simpleType>
<xs:element name="cacheWriterFactory">
<xs:complexType>
<xs:attribute name="class" use="required"/>
<xs:attribute name="properties" use="optional"/>
<xs:attribute name="propertySeparator" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="copyStrategy">
<xs:complexType>
<xs:attribute name="class" use="required" type="xs:string"/>
</xs:complexType>
</xs:element>
<xs:element name="elementValueComparator">
<xs:complexType>
<xs:attribute name="class" use="required" type="xs:string"/>
</xs:complexType>
</xs:element>
<xs:element name="sizeOfPolicy">
<xs:complexType>
<xs:attribute name="maxDepth" use="required" type="xs:integer"/>
<xs:attribute name="maxDepthExceededBehavior" use="optional" default="continue"
type="maxDepthExceededBehavior"/>
</xs:complexType>
</xs:element>
<xs:element name="persistence">
<xs:complexType>
<xs:attribute name="strategy" use="required" type="persistenceStrategy"/>
<xs:attribute name="synchronousWrites" use="optional" default="false" type="xs:boolean"/>
</xs:complexType>
</xs:element>
<xs:simpleType name="persistenceStrategy">
<xs:restriction base="xs:string">
<xs:enumeration value="localTempSwap"/>
<xs:enumeration value="localRestartable"/>
<xs:enumeration value="none"/>
<xs:enumeration value="distributed"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="maxDepthExceededBehavior">
<xs:restriction base="xs:string">
<xs:enumeration value="continue"/>
<xs:enumeration value="abort"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="notificationScope">
<xs:restriction base="xs:string">
<xs:enumeration value="local"/>
<xs:enumeration value="remote"/>
<xs:enumeration value="all"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="memoryUnit">
<xs:restriction base="xs:token">
<xs:pattern value="[0-9]+[bBkKmMgG]?"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="memoryUnitOrPercentage">
<xs:restriction base="xs:token">
<xs:pattern value="([0-9]+[bBkKmMgG]?|100%|[0-9]{1,2}%)"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>

View file

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

View file

@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xml>
<configuration scan="true" scanPeriod="30 seconds">
<contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
<resetJUL>true</resetJUL>
</contextListener>
<!-- To enable JMX Management -->
<jmxConfigurator/>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%-5level %logger{0} - %msg%n</pattern>
</encoder>
</appender>
<!--<logger name="org.hibernate" level="debug"/> -->
<logger name="org.springframework.samples.petclinic" level="debug"/>
<root level="info">
<appender-ref ref="console"/>
</root>
</configuration>

View file

@ -1,96 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Repository and Service layers
-->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- ========================= RESOURCE DEFINITIONS ========================= -->
<!-- import the dataSource definition -->
<import resource="datasource-config.xml"/>
<context:component-scan
base-package="org.springframework.samples.petclinic.service"/>
<!-- Configurer that replaces ${...} placeholders with values from a properties file -->
<!-- (in this case, JDBC-related settings for the JPA EntityManager definition below) -->
<context:property-placeholder location="classpath:spring/data-access.properties" system-properties-mode="OVERRIDE"/>
<!-- enables scanning for @Transactional annotations -->
<tx:annotation-driven />
<!-- ================== 3 Profiles to choose from ===================
- jdbc (uses Spring" JdbcTemplate)
- jpa
- spring-data-jpa
=============================================================================-->
<beans profile="jpa,spring-data-jpa">
<!-- 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.HibernateJpaVendorAdapter"
p:database="${jpa.database}" p:showSql="${jpa.showSql}"/>
<!-- the 'database' parameter refers to the database dialect being used.
By default, Hibernate will use a 'HSQL' dialect because 'jpa.database' has been set to 'HSQL'
inside file spring/data-access.properties
-->
</property>
<!-- gDickens: BOTH Persistence Unit and Packages to Scan are NOT compatible, persistenceUnit will win -->
<property name="persistenceUnitName" value="petclinic"/>
<property name="packagesToScan" value="org.springframework.samples.petclinic"/>
</bean>
<!-- Transaction manager for a single JPA EntityManagerFactory (alternative to JTA) -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManagerFactory"/>
<!--
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"/>
</beans>
<beans profile="jdbc">
<!-- Transaction manager for a single JDBC DataSource (alternative to JTA) -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource"/>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="dataSource"/>
</bean>
<bean id="namedParameterJdbcTemplate"
class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
<constructor-arg ref="dataSource"/>
</bean>
<context:component-scan base-package="org.springframework.samples.petclinic.repository.jdbc"/>
</beans>
<beans profile="jpa">
<!--
Loads JPA beans
Will automatically be transactional due to @Transactional.
EntityManager will be auto-injected due to @PersistenceContext.
PersistenceExceptions will be auto-translated due to @Repository.
-->
<context:component-scan base-package="org.springframework.samples.petclinic.repository.jpa"/>
</beans>
<beans profile="spring-data-jpa">
<jpa:repositories base-package="org.springframework.samples.petclinic.repository.springdatajpa"/>
</beans>
</beans>

View file

@ -1,41 +0,0 @@
# 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.
#-------------------------------------------------------------------------------
# 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.initLocation=classpath:db/hsqldb/initDB.sql
jdbc.dataLocation=classpath:db/hsqldb/populateDB.sql
# Property that determines which database to use with an AbstractJpaVendorAdapter
jpa.database=HSQL
jpa.showSql=true
#-------------------------------------------------------------------------------
# MySQL Settings
#jdbc.driverClassName=com.mysql.jdbc.Driver
#jdbc.url=jdbc:mysql://localhost:3306/petclinic
#jdbc.username=root
#jdbc.password=
# Properties that control the population of schema and data for a new data source
#jdbc.initLocation=classpath:db/mysql/initDB.sql
#jdbc.dataLocation=classpath:db/mysql/populateDB.sql
# Property that determines which Hibernate dialect to use
# (only applied with "applicationContext-hibernate.xml")
#hibernate.dialect=org.hibernate.dialect.MySQLDialect
# Property that determines which database to use with an AbstractJpaVendorAdapter
#jpa.database=MYSQL

View file

@ -1,43 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Application context definition for PetClinic Datasource.
-->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee.xsd">
<!-- ========================= DATASOURCE DEFINITION ========================= -->
<!-- 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:spring/data-access.properties" system-properties-mode="OVERRIDE"/>
<!-- DataSource configuration for the tomcat jdbc connection pool
See here for more details on commons-dbcp versus tomcat-jdbc:
http://blog.ippon.fr/2013/03/13/improving-the-performance-of-the-spring-petclinic-sample-application-part-3-of-5/-->
<bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSource"
p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}"
p:username="${jdbc.username}" p:password="${jdbc.password}"/>
<!-- Database initializer. If any of the script fails, the initialization stops. -->
<!-- As an alternative, for embedded databases see <jdbc:embedded-database/>. -->
<jdbc:initialize-database data-source="dataSource">
<jdbc:script location="${jdbc.initLocation}"/>
<jdbc:script location="${jdbc.dataLocation}"/>
</jdbc:initialize-database>
<beans profile="javaee" >
<!-- JNDI DataSource for JEE environments -->
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/petclinic"/>
</beans>
</beans>

View file

@ -1,75 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- DispatcherServlet application context for PetClinic's web tier.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<import resource="mvc-view-config.xml"/>
<!--
- POJOs labeled with the @Controller and @Service annotations are auto-detected.
-->
<context:component-scan
base-package="org.springframework.samples.petclinic.web"/>
<mvc:annotation-driven conversion-service="conversionService">
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean" />
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!-- all resources inside folder src/main/webapp/resources are mapped so they can be refered to inside JSP files
(see header.jsp for more details) -->
<mvc:resources mapping="/resources/**" location="/resources/"/>
<!-- uses WebJars so Javascript and CSS libs can be declared as Maven dependencies (Bootstrap, jQuery...) -->
<mvc:resources mapping="/webjars/**" location="classpath:/META-INF/resources/webjars/"/>
<mvc:view-controller path="/" view-name="welcome" />
<!-- serve static resources (*.html, ...) from src/main/webapp/
Required when both servlet-mapping is '/' and static resources need to be served -->
<mvc:default-servlet-handler />
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="formatters">
<set>
<bean class="org.springframework.samples.petclinic.web.PetTypeFormatter"/>
</set>
</property>
</bean>
<!--
- Message source for this context, loaded from localized "messages_xx" files.
- Files are stored inside src/main/resources
-->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"
p:basename="messages/messages"/>
<!--
- This bean resolves specific types of exceptions to corresponding logical
- view names for error views.
-->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- view name resolved using bean of type InternalResourceViewResolver (declared in mvc-view-config.xml) -->
<property name="defaultErrorView" value="exception"/>
<!-- results into 'WEB-INF/jsp/exception.jsp' -->
<property name="warnLogCategory" value="warn"/>
<!-- needed otherwise exceptions won't be logged anywhere -->
</bean>
</beans>

View file

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- DispatcherServlet application context for PetClinic's web tier.
-->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:oxm="http://www.springframework.org/schema/oxm" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<mvc:view-resolvers>
<mvc:bean-name />
</mvc:view-resolvers>
</beans>

View file

@ -1,49 +0,0 @@
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--
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.
-->
<aop:aspectj-autoproxy>
<aop:include name="callMonitor"/>
</aop:aspectj-autoproxy>
<!-- Call monitoring aspect that monitors call count and call invocation time -->
<bean id="callMonitor" class="org.springframework.samples.petclinic.util.CallMonitoringAspect"/>
<!--
Exporter that exposes the CallMonitoringAspect via JMX,
based on the @ManagedResource, @ManagedAttribute, and @ManagedOperation annotations.
-->
<context:mbean-export/>
<!-- enables scanning for @Cacheable annotation -->
<cache:annotation-driven/>
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="ehcache"/>
</bean>
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:cache/ehcache.xml"/>
</bean>
</beans>

View file

@ -1,95 +0,0 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>Spring PetClinic</display-name>
<description>Spring PetClinic sample application</description>
<context-param>
<param-name>spring.profiles.active</param-name>
<param-value>jpa</param-value>
</context-param>
<!-- When using Spring JDBC, use the following: -->
<!-- <context-param>
<param-name>spring.profiles.active</param-name>
<param-value>jdbc</param-value>
</context-param> -->
<!-- When using Spring Data JPA, uncomment the following: -->
<!--
<context-param>
<param-name>spring.profiles.active</param-name>
<param-value>spring-data-jpa</param-value>
</context-param>
-->
<!--
- Location of the XML file that defines the root application context.
- Applied by ContextLoaderListener.
-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/business-config.xml, classpath:spring/tools-config.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--
- Servlet that dispatches request to registered handlers (Controller implementations).
-->
<servlet>
<servlet-name>petclinic</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/mvc-core-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>petclinic</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- used so we can use forms of method type 'PUT' and 'DELETE' (such as in the Pet form)
see here: http://static.springsource.org/spring/docs/current/spring-framework-reference/html/view.html#rest-method-conversion
-->
<filter>
<filter-name>httpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>httpMethodFilter</filter-name>
<servlet-name>petclinic</servlet-name>
</filter-mapping>
<!-- used to provide the ability to enter Chinese characters inside the Owner Form -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>

View file

@ -5,9 +5,8 @@
<head>
<title>PetClinic :: a Spring Framework demonstration</title>
<link rel="stylesheet" href="bower_components/bootstrap/docs/assets/css/bootstrap.css" />
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
<link href="resources/css/petclinic.css" rel="stylesheet"/>
<script src="bower_components/angular/angular.js"></script>
<script src="bower_components/angular-ui-router/release/angular-ui-router.js"></script>
<script src="bower_components/angular-resource/angular-resource.js"></script>
@ -20,9 +19,7 @@
<body class="container">
<div ui-view="header"></div>
<div ui-view="content"></div>
<div ui-view="footer"></div>
</body>

View file

@ -1,20 +0,0 @@
.container {
padding-top: 10px;
width: 700px;
}
.form-horizontal {
width: 100%;
}
input[type="text"] {
height: 25px;
}
.navbar .nav > li > a {
color: #000000;
}
.form-horizontal .control-label {
text-align: left;
}

View file

@ -1,23 +1,24 @@
<nav class="navbar navbar-default">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" ui-sref="app">Pet Clinic</a>
<img src="resources/images/banner-graphic.png" var="banner"/>
</div>
<div class="navbar" style="width: 601px;">
<div class="navbar-inner">
<ul class="nav">
<li style="width: 120px;">
<a ui-sref="app"><i class="icon-home"></i> Home</a>
</li>
<li style="width: 150px;">
<a ui-sref="app.ownersearch"><i class="icon-search"></i> Find owners</a>
</li>
<li style="width: 160px;">
<a ui-sref="app.vets"><i class="icon-th-list"></i> Veterinarians</a>
</li>
<li style="width: 110px;">
<a href="oups.html" title="trigger a RuntimeException to see how it is handled">
<i class="icon-warning-sign"></i> Error</a>
</li>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li><a ui-sref="app">Home</a></li>
<li><a ui-sref="app.ownersearch">Owner</a></li>
<li><a ui-sref="app.vets">Vets</a></li>
</ul>
</div>
</div>
</nav>

View file

@ -1,11 +1,4 @@
<table class="footer">
<tr>
<td width="70%"></td>
<td align="right">
<div style="text-align: right">
<img src="resources/images/spring-pivotal-logo.png" alt="Sponsored by Pivotal"/>
</td>
</tr>
</table>
</div>

View file

@ -3,11 +3,9 @@
function loadPet($scope, $resource, $stateParams) {
var petResource = $resource('/petclinic/owner/' + $stateParams.ownerid +"/pet/" + $stateParams.petid);
$scope.pet = petResource.get();
$scope.types = $resource("/petclinic/petTypes").query();
}
/*
* Form used to create and edit pets
*/

View file

@ -1,44 +1,38 @@
<!DOCTYPE html>
<script>
$(function () {
$("#birthDate").datepicker({ dateFormat: 'yy/mm/dd'});
});
</script>
<div class="container">
<h2>Pet (work in progress) </h2>
<h2>Pet</h2>
<form class="form-horizontal" name="petForm" data-ng-controller="petFormController">
<fieldset>
<div class="control-group" id="owner">
<label class="control-label"> Owner </label>
{{pet.owner.firstName}} {{pet.owner.lastName}}
<div class="form-group">
<label class="col-sm-2 control-label">Owner</label>
<div class="col-sm-6">
<p class="form-control-static">{{pet.owner}}</p>
</div>
<div class="control-group" id="name">
<label class="control-label">Name </label>
<input ng-model="pet.name" name="name" required/>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Name </label>
<div class="col-sm-6">
<input class="form-control col-sm-4" ng-model="pet.name" name="name" required type="text"/>
<span ng-show="petForm.name.$error.required" class="help-inline"> Name is required.</span>
</div>
<div class="control-group" id="birthDate">
<label class="control-label">Birth date </label>
<input ng-model="pet.birthDate" value="{{pet.birthDate | date:'MM/dd/yyyy'}} name="birthDate" required/>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Birth date </label>
<div class="col-sm-6">
<input class="form-control" ng-model="pet.birthDate" value="{{pet.birthDate}}" required type="text"/>
<span ng-show="petForm.name.$error.required" class="help-inline"> birth date is required.</span>
</div>
<div class="control-group">
<petclinic:selectField name="type" label="Type " names="${types}" size="5"/>
</div>
<div class="form-actions">
<c:choose>
<c:when test="${pet['new']}">
<button type="submit">Add Pet</button>
</c:when>
<c:otherwise>
<button type="submit">Update Pet</button>
</c:otherwise>
</c:choose>
<div class="form-group">
<label class="col-sm-2 control-label">Type </label>
<div class="col-sm-6">
<select class="form-control" ng-model="pet.type.id">
<option ng-repeat="x in types" value="{{x.id}}">{{x.name}}</option>
</select>
</div>
</div>
</fieldset>
</form>
</div>