This commit is contained in:
fakukpg 2020-10-17 21:04:48 -03:00
parent 27109010a5
commit 2b047a0f7d
116 changed files with 11096 additions and 0 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,2 @@
#Sat Oct 17 20:51:58 ART 2020
gradle.version=6.7

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

62
build.gradle Normal file
View file

@ -0,0 +1,62 @@
/*
* This file was generated by the Gradle 'init' task.
*/
plugins {
id 'java'
id 'maven-publish'
id 'org.springframework.boot' version '2.1.9.RELEASE'
}
repositories {
mavenLocal()
maven {
url = uri('https://repo.spring.io/snapshot')
}
maven {
url = uri('https://repo.spring.io/milestone')
}
maven {
url = uri('https://repo.maven.apache.org/maven2/')
}
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator:2.3.3.RELEASE'
implementation 'org.springframework.boot:spring-boot-starter-cache:2.3.3.RELEASE'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa:2.3.3.RELEASE'
implementation 'org.springframework.boot:spring-boot-starter-web:2.3.3.RELEASE'
implementation 'org.springframework.boot:spring-boot-starter-validation:2.3.3.RELEASE'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf:2.3.3.RELEASE'
implementation 'javax.cache:cache-api:1.1.1'
implementation 'org.ehcache:ehcache:3.8.1'
implementation 'org.webjars:webjars-locator-core:0.45'
implementation 'org.webjars:jquery:2.2.4'
implementation 'org.webjars:jquery-ui:1.11.4'
implementation 'org.webjars:bootstrap:3.3.6'
implementation 'org.springframework.boot:spring-boot-devtools:2.3.3.RELEASE'
runtimeOnly 'com.h2database:h2:1.4.200'
runtimeOnly 'mysql:mysql-connector-java:8.0.21'
testImplementation 'org.springframework.boot:spring-boot-starter-test:2.3.3.RELEASE'
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.6.2'
testImplementation 'org.mockito:mockito-junit-jupiter:3.3.3'
}
group = 'org.springframework.samples'
version = '2.3.0.BUILD-SNAPSHOT'
description = 'petclinic'
java.sourceCompatibility = JavaVersion.VERSION_1_8
publishing {
publications {
maven(MavenPublication) {
from(components.java)
}
}
}
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}

Binary file not shown.

View file

@ -0,0 +1,179 @@
body {
margin: 0;
padding: 0;
font-family: sans-serif;
font-size: 12pt;
}
body, a, a:visited {
color: #303030;
}
#content {
padding-left: 50px;
padding-right: 50px;
padding-top: 30px;
padding-bottom: 30px;
}
#content h1 {
font-size: 160%;
margin-bottom: 10px;
}
#footer {
margin-top: 100px;
font-size: 80%;
white-space: nowrap;
}
#footer, #footer a {
color: #a0a0a0;
}
#line-wrapping-toggle {
vertical-align: middle;
}
#label-for-line-wrapping-toggle {
vertical-align: middle;
}
ul {
margin-left: 0;
}
h1, h2, h3 {
white-space: nowrap;
}
h2 {
font-size: 120%;
}
ul.tabLinks {
padding-left: 0;
padding-top: 10px;
padding-bottom: 10px;
overflow: auto;
min-width: 800px;
width: auto !important;
width: 800px;
}
ul.tabLinks li {
float: left;
height: 100%;
list-style: none;
padding-left: 10px;
padding-right: 10px;
padding-top: 5px;
padding-bottom: 5px;
margin-bottom: 0;
-moz-border-radius: 7px;
border-radius: 7px;
margin-right: 25px;
border: solid 1px #d4d4d4;
background-color: #f0f0f0;
}
ul.tabLinks li:hover {
background-color: #fafafa;
}
ul.tabLinks li.selected {
background-color: #c5f0f5;
border-color: #c5f0f5;
}
ul.tabLinks a {
font-size: 120%;
display: block;
outline: none;
text-decoration: none;
margin: 0;
padding: 0;
}
ul.tabLinks li h2 {
margin: 0;
padding: 0;
}
div.tab {
}
div.selected {
display: block;
}
div.deselected {
display: none;
}
div.tab table {
min-width: 350px;
width: auto !important;
width: 350px;
border-collapse: collapse;
}
div.tab th, div.tab table {
border-bottom: solid #d0d0d0 1px;
}
div.tab th {
text-align: left;
white-space: nowrap;
padding-left: 6em;
}
div.tab th:first-child {
padding-left: 0;
}
div.tab td {
white-space: nowrap;
padding-left: 6em;
padding-top: 5px;
padding-bottom: 5px;
}
div.tab td:first-child {
padding-left: 0;
}
div.tab td.numeric, div.tab th.numeric {
text-align: right;
}
span.code {
display: inline-block;
margin-top: 0em;
margin-bottom: 1em;
}
span.code pre {
font-size: 11pt;
padding-top: 10px;
padding-bottom: 10px;
padding-left: 10px;
padding-right: 10px;
margin: 0;
background-color: #f7f7f7;
border: solid 1px #d0d0d0;
min-width: 700px;
width: auto !important;
width: 700px;
}
span.wrapped pre {
word-wrap: break-word;
white-space: pre-wrap;
word-break: break-all;
}
label.hidden {
display: none;
}

View file

@ -0,0 +1,84 @@
#summary {
margin-top: 30px;
margin-bottom: 40px;
}
#summary table {
border-collapse: collapse;
}
#summary td {
vertical-align: top;
}
.breadcrumbs, .breadcrumbs a {
color: #606060;
}
.infoBox {
width: 110px;
padding-top: 15px;
padding-bottom: 15px;
text-align: center;
}
.infoBox p {
margin: 0;
}
.counter, .percent {
font-size: 120%;
font-weight: bold;
margin-bottom: 8px;
}
#duration {
width: 125px;
}
#successRate, .summaryGroup {
border: solid 2px #d0d0d0;
-moz-border-radius: 10px;
border-radius: 10px;
}
#successRate {
width: 140px;
margin-left: 35px;
}
#successRate .percent {
font-size: 180%;
}
.success, .success a {
color: #008000;
}
div.success, #successRate.success {
background-color: #bbd9bb;
border-color: #008000;
}
.failures, .failures a {
color: #b60808;
}
.skipped, .skipped a {
color: #c09853;
}
div.failures, #successRate.failures {
background-color: #ecdada;
border-color: #b60808;
}
ul.linkList {
padding-left: 0;
}
ul.linkList li {
list-style: none;
margin-bottom: 5px;
}

View file

@ -0,0 +1,92 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="x-ua-compatible" content="IE=edge"/>
<title>Test results - Test Summary</title>
<link href="css/base-style.css" rel="stylesheet" type="text/css"/>
<link href="css/style.css" rel="stylesheet" type="text/css"/>
<script src="js/report.js" type="text/javascript"></script>
</head>
<body>
<div id="content">
<h1>Test Summary</h1>
<div id="summary">
<table>
<tr>
<td>
<div class="summaryGroup">
<table>
<tr>
<td>
<div class="infoBox" id="tests">
<div class="counter">0</div>
<p>tests</p>
</div>
</td>
<td>
<div class="infoBox" id="failures">
<div class="counter">0</div>
<p>failures</p>
</div>
</td>
<td>
<div class="infoBox" id="ignored">
<div class="counter">0</div>
<p>ignored</p>
</div>
</td>
<td>
<div class="infoBox" id="duration">
<div class="counter">-</div>
<p>duration</p>
</div>
</td>
</tr>
</table>
</div>
</td>
<td>
<div class="infoBox success" id="successRate">
<div class="percent">-</div>
<p>successful</p>
</div>
</td>
</tr>
</table>
</div>
<div id="tabs">
<ul class="tabLinks">
<li>
<a href="#tab0">Classes</a>
</li>
</ul>
<div id="tab0" class="tab">
<h2>Classes</h2>
<table>
<thead>
<tr>
<th>Class</th>
<th>Tests</th>
<th>Failures</th>
<th>Ignored</th>
<th>Duration</th>
<th>Success rate</th>
</tr>
</thead>
<tbody/>
</table>
</div>
</div>
<div id="footer">
<p>
<div>
<label class="hidden" id="label-for-line-wrapping-toggle" for="line-wrapping-toggle">Wrap lines
<input id="line-wrapping-toggle" type="checkbox" autocomplete="off"/>
</label>
</div>Generated by
<a href="http://www.gradle.org">Gradle 6.7</a> at Oct 17, 2020, 8:57:49 PM</p>
</div>
</div>
</body>
</html>

View file

@ -0,0 +1,194 @@
(function (window, document) {
"use strict";
var tabs = {};
function changeElementClass(element, classValue) {
if (element.getAttribute("className")) {
element.setAttribute("className", classValue);
} else {
element.setAttribute("class", classValue);
}
}
function getClassAttribute(element) {
if (element.getAttribute("className")) {
return element.getAttribute("className");
} else {
return element.getAttribute("class");
}
}
function addClass(element, classValue) {
changeElementClass(element, getClassAttribute(element) + " " + classValue);
}
function removeClass(element, classValue) {
changeElementClass(element, getClassAttribute(element).replace(classValue, ""));
}
function initTabs() {
var container = document.getElementById("tabs");
tabs.tabs = findTabs(container);
tabs.titles = findTitles(tabs.tabs);
tabs.headers = findHeaders(container);
tabs.select = select;
tabs.deselectAll = deselectAll;
tabs.select(0);
return true;
}
function getCheckBox() {
return document.getElementById("line-wrapping-toggle");
}
function getLabelForCheckBox() {
return document.getElementById("label-for-line-wrapping-toggle");
}
function findCodeBlocks() {
var spans = document.getElementById("tabs").getElementsByTagName("span");
var codeBlocks = [];
for (var i = 0; i < spans.length; ++i) {
if (spans[i].className.indexOf("code") >= 0) {
codeBlocks.push(spans[i]);
}
}
return codeBlocks;
}
function forAllCodeBlocks(operation) {
var codeBlocks = findCodeBlocks();
for (var i = 0; i < codeBlocks.length; ++i) {
operation(codeBlocks[i], "wrapped");
}
}
function toggleLineWrapping() {
var checkBox = getCheckBox();
if (checkBox.checked) {
forAllCodeBlocks(addClass);
} else {
forAllCodeBlocks(removeClass);
}
}
function initControls() {
if (findCodeBlocks().length > 0) {
var checkBox = getCheckBox();
var label = getLabelForCheckBox();
checkBox.onclick = toggleLineWrapping;
checkBox.checked = false;
removeClass(label, "hidden");
}
}
function switchTab() {
var id = this.id.substr(1);
for (var i = 0; i < tabs.tabs.length; i++) {
if (tabs.tabs[i].id === id) {
tabs.select(i);
break;
}
}
return false;
}
function select(i) {
this.deselectAll();
changeElementClass(this.tabs[i], "tab selected");
changeElementClass(this.headers[i], "selected");
while (this.headers[i].firstChild) {
this.headers[i].removeChild(this.headers[i].firstChild);
}
var h2 = document.createElement("H2");
h2.appendChild(document.createTextNode(this.titles[i]));
this.headers[i].appendChild(h2);
}
function deselectAll() {
for (var i = 0; i < this.tabs.length; i++) {
changeElementClass(this.tabs[i], "tab deselected");
changeElementClass(this.headers[i], "deselected");
while (this.headers[i].firstChild) {
this.headers[i].removeChild(this.headers[i].firstChild);
}
var a = document.createElement("A");
a.setAttribute("id", "ltab" + i);
a.setAttribute("href", "#tab" + i);
a.onclick = switchTab;
a.appendChild(document.createTextNode(this.titles[i]));
this.headers[i].appendChild(a);
}
}
function findTabs(container) {
return findChildElements(container, "DIV", "tab");
}
function findHeaders(container) {
var owner = findChildElements(container, "UL", "tabLinks");
return findChildElements(owner[0], "LI", null);
}
function findTitles(tabs) {
var titles = [];
for (var i = 0; i < tabs.length; i++) {
var tab = tabs[i];
var header = findChildElements(tab, "H2", null)[0];
header.parentNode.removeChild(header);
if (header.innerText) {
titles.push(header.innerText);
} else {
titles.push(header.textContent);
}
}
return titles;
}
function findChildElements(container, name, targetClass) {
var elements = [];
var children = container.childNodes;
for (var i = 0; i < children.length; i++) {
var child = children.item(i);
if (child.nodeType === 1 && child.nodeName === name) {
if (targetClass && child.className.indexOf(targetClass) < 0) {
continue;
}
elements.push(child);
}
}
return elements;
}
// Entry point.
window.onload = function() {
initTabs();
initControls();
};
} (window, window.document));

View file

@ -0,0 +1,7 @@
# database init, supports mysql too
database=mysql
spring.datasource.url=${MYSQL_URL:jdbc:mysql://localhost/petclinic}
spring.datasource.username=${MYSQL_USER:petclinic}
spring.datasource.password=${MYSQL_PASS:petclinic}
# SQL is written to be idempotent so this is safe
spring.datasource.initialization-mode=always

View file

@ -0,0 +1,25 @@
# database init, supports mysql too
database=h2
spring.datasource.schema=classpath*:db/${database}/schema.sql
spring.datasource.data=classpath*:db/${database}/data.sql
# Web
spring.thymeleaf.mode=HTML
# JPA
spring.jpa.hibernate.ddl-auto=none
spring.jpa.open-in-view=false
# Internationalization
spring.messages.basename=messages/messages
# Actuator
management.endpoints.web.exposure.include=*
# Logging
logging.level.org.springframework=INFO
# logging.level.org.springframework.web=DEBUG
# logging.level.org.springframework.context.annotation=TRACE
# Maximum time static resources should be cached
spring.resources.cache.cachecontrol.max-age=12h

View file

@ -0,0 +1,15 @@
|\ _,,,--,,_
/,`.-'`' ._ \-;;,_
_______ __|,4- ) )_ .;.(__`'-'__ ___ __ _ ___ _______
| | '---''(_/._)-'(_\_) | | | | | | | | |
| _ | ___|_ _| | | | | |_| | | | __ _ _
| |_| | |___ | | | | | | | | | | \ \ \ \
| ___| ___| | | | _| |___| | _ | | _| \ \ \ \
| | | |___ | | | |_| | | | | | | |_ ) ) ) )
|___| |_______| |___| |_______|_______|___|_| |__|___|_______| / / / /
==================================================================/_/_/_/
:: Built with Spring Boot :: ${spring-boot.version}

View 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', '2010-09-07', 1, 1);
INSERT INTO pets VALUES (2, 'Basil', '2012-08-06', 6, 2);
INSERT INTO pets VALUES (3, 'Rosy', '2011-04-17', 2, 3);
INSERT INTO pets VALUES (4, 'Jewel', '2010-03-07', 2, 3);
INSERT INTO pets VALUES (5, 'Iggy', '2010-11-30', 3, 4);
INSERT INTO pets VALUES (6, 'George', '2010-01-20', 4, 5);
INSERT INTO pets VALUES (7, 'Samantha', '2012-09-04', 1, 6);
INSERT INTO pets VALUES (8, 'Max', '2012-09-04', 1, 6);
INSERT INTO pets VALUES (9, 'Lucky', '2011-08-06', 5, 7);
INSERT INTO pets VALUES (10, 'Mulligan', '2007-02-24', 2, 8);
INSERT INTO pets VALUES (11, 'Freddy', '2010-03-09', 5, 9);
INSERT INTO pets VALUES (12, 'Lucky', '2010-06-24', 2, 10);
INSERT INTO pets VALUES (13, 'Sly', '2012-06-08', 1, 10);
INSERT INTO visits VALUES (1, 7, '2013-01-01', 'rabies shot');
INSERT INTO visits VALUES (2, 8, '2013-01-02', 'rabies shot');
INSERT INTO visits VALUES (3, 8, '2013-01-03', 'neutered');
INSERT INTO visits VALUES (4, 7, '2013-01-04', 'spayed');

View file

@ -0,0 +1,64 @@
DROP TABLE vet_specialties IF EXISTS;
DROP TABLE vets IF EXISTS;
DROP TABLE specialties IF EXISTS;
DROP TABLE visits IF EXISTS;
DROP TABLE pets IF EXISTS;
DROP TABLE types IF EXISTS;
DROP TABLE owners IF EXISTS;
CREATE TABLE vets (
id INTEGER 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 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 IDENTITY PRIMARY KEY,
name VARCHAR(80)
);
CREATE INDEX types_name ON types (name);
CREATE TABLE owners (
id INTEGER IDENTITY PRIMARY KEY,
first_name VARCHAR(30),
last_name VARCHAR_IGNORECASE(30),
address VARCHAR(255),
city VARCHAR(80),
telephone VARCHAR(20)
);
CREATE INDEX owners_last_name ON owners (last_name);
CREATE TABLE pets (
id INTEGER 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 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);

View 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', '2010-09-07', 1, 1);
INSERT INTO pets VALUES (2, 'Basil', '2012-08-06', 6, 2);
INSERT INTO pets VALUES (3, 'Rosy', '2011-04-17', 2, 3);
INSERT INTO pets VALUES (4, 'Jewel', '2010-03-07', 2, 3);
INSERT INTO pets VALUES (5, 'Iggy', '2010-11-30', 3, 4);
INSERT INTO pets VALUES (6, 'George', '2010-01-20', 4, 5);
INSERT INTO pets VALUES (7, 'Samantha', '2012-09-04', 1, 6);
INSERT INTO pets VALUES (8, 'Max', '2012-09-04', 1, 6);
INSERT INTO pets VALUES (9, 'Lucky', '2011-08-06', 5, 7);
INSERT INTO pets VALUES (10, 'Mulligan', '2007-02-24', 2, 8);
INSERT INTO pets VALUES (11, 'Freddy', '2010-03-09', 5, 9);
INSERT INTO pets VALUES (12, 'Lucky', '2010-06-24', 2, 10);
INSERT INTO pets VALUES (13, 'Sly', '2012-06-08', 1, 10);
INSERT INTO visits VALUES (1, 7, '2013-01-01', 'rabies shot');
INSERT INTO visits VALUES (2, 8, '2013-01-02', 'rabies shot');
INSERT INTO visits VALUES (3, 8, '2013-01-03', 'neutered');
INSERT INTO visits VALUES (4, 7, '2013-01-04', 'spayed');

View file

@ -0,0 +1,64 @@
DROP TABLE vet_specialties IF EXISTS;
DROP TABLE vets IF EXISTS;
DROP TABLE specialties IF EXISTS;
DROP TABLE visits IF EXISTS;
DROP TABLE pets IF EXISTS;
DROP TABLE types IF EXISTS;
DROP TABLE owners IF EXISTS;
CREATE TABLE vets (
id INTEGER 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 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 IDENTITY PRIMARY KEY,
name VARCHAR(80)
);
CREATE INDEX types_name ON types (name);
CREATE TABLE owners (
id INTEGER IDENTITY PRIMARY KEY,
first_name VARCHAR(30),
last_name VARCHAR_IGNORECASE(30),
address VARCHAR(255),
city VARCHAR(80),
telephone VARCHAR(20)
);
CREATE INDEX owners_last_name ON owners (last_name);
CREATE TABLE pets (
id INTEGER 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 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);

View file

@ -0,0 +1,53 @@
INSERT IGNORE INTO vets VALUES (1, 'James', 'Carter');
INSERT IGNORE INTO vets VALUES (2, 'Helen', 'Leary');
INSERT IGNORE INTO vets VALUES (3, 'Linda', 'Douglas');
INSERT IGNORE INTO vets VALUES (4, 'Rafael', 'Ortega');
INSERT IGNORE INTO vets VALUES (5, 'Henry', 'Stevens');
INSERT IGNORE INTO vets VALUES (6, 'Sharon', 'Jenkins');
INSERT IGNORE INTO specialties VALUES (1, 'radiology');
INSERT IGNORE INTO specialties VALUES (2, 'surgery');
INSERT IGNORE INTO specialties VALUES (3, 'dentistry');
INSERT IGNORE INTO vet_specialties VALUES (2, 1);
INSERT IGNORE INTO vet_specialties VALUES (3, 2);
INSERT IGNORE INTO vet_specialties VALUES (3, 3);
INSERT IGNORE INTO vet_specialties VALUES (4, 2);
INSERT IGNORE INTO vet_specialties VALUES (5, 1);
INSERT IGNORE INTO types VALUES (1, 'cat');
INSERT IGNORE INTO types VALUES (2, 'dog');
INSERT IGNORE INTO types VALUES (3, 'lizard');
INSERT IGNORE INTO types VALUES (4, 'snake');
INSERT IGNORE INTO types VALUES (5, 'bird');
INSERT IGNORE INTO types VALUES (6, 'hamster');
INSERT IGNORE INTO owners VALUES (1, 'George', 'Franklin', '110 W. Liberty St.', 'Madison', '6085551023');
INSERT IGNORE INTO owners VALUES (2, 'Betty', 'Davis', '638 Cardinal Ave.', 'Sun Prairie', '6085551749');
INSERT IGNORE INTO owners VALUES (3, 'Eduardo', 'Rodriquez', '2693 Commerce St.', 'McFarland', '6085558763');
INSERT IGNORE INTO owners VALUES (4, 'Harold', 'Davis', '563 Friendly St.', 'Windsor', '6085553198');
INSERT IGNORE INTO owners VALUES (5, 'Peter', 'McTavish', '2387 S. Fair Way', 'Madison', '6085552765');
INSERT IGNORE INTO owners VALUES (6, 'Jean', 'Coleman', '105 N. Lake St.', 'Monona', '6085552654');
INSERT IGNORE INTO owners VALUES (7, 'Jeff', 'Black', '1450 Oak Blvd.', 'Monona', '6085555387');
INSERT IGNORE INTO owners VALUES (8, 'Maria', 'Escobito', '345 Maple St.', 'Madison', '6085557683');
INSERT IGNORE INTO owners VALUES (9, 'David', 'Schroeder', '2749 Blackhawk Trail', 'Madison', '6085559435');
INSERT IGNORE INTO owners VALUES (10, 'Carlos', 'Estaban', '2335 Independence La.', 'Waunakee', '6085555487');
INSERT IGNORE INTO pets VALUES (1, 'Leo', '2000-09-07', 1, 1);
INSERT IGNORE INTO pets VALUES (2, 'Basil', '2002-08-06', 6, 2);
INSERT IGNORE INTO pets VALUES (3, 'Rosy', '2001-04-17', 2, 3);
INSERT IGNORE INTO pets VALUES (4, 'Jewel', '2000-03-07', 2, 3);
INSERT IGNORE INTO pets VALUES (5, 'Iggy', '2000-11-30', 3, 4);
INSERT IGNORE INTO pets VALUES (6, 'George', '2000-01-20', 4, 5);
INSERT IGNORE INTO pets VALUES (7, 'Samantha', '1995-09-04', 1, 6);
INSERT IGNORE INTO pets VALUES (8, 'Max', '1995-09-04', 1, 6);
INSERT IGNORE INTO pets VALUES (9, 'Lucky', '1999-08-06', 5, 7);
INSERT IGNORE INTO pets VALUES (10, 'Mulligan', '1997-02-24', 2, 8);
INSERT IGNORE INTO pets VALUES (11, 'Freddy', '2000-03-09', 5, 9);
INSERT IGNORE INTO pets VALUES (12, 'Lucky', '2000-06-24', 2, 10);
INSERT IGNORE INTO pets VALUES (13, 'Sly', '2002-06-08', 1, 10);
INSERT IGNORE INTO visits VALUES (1, 7, '2010-03-04', 'rabies shot');
INSERT IGNORE INTO visits VALUES (2, 8, '2011-03-04', 'rabies shot');
INSERT IGNORE INTO visits VALUES (3, 8, '2009-06-04', 'neutered');
INSERT IGNORE INTO visits VALUES (4, 7, '2008-09-04', 'spayed');

View file

@ -0,0 +1,32 @@
================================================================================
=== Spring PetClinic sample application - MySQL Configuration ===
================================================================================
@author Sam Brannen
@author Costin Leau
@author Dave Syer
--------------------------------------------------------------------------------
1) Download and install the MySQL database (e.g., MySQL Community Server 5.1.x),
which can be found here: https://dev.mysql.com/downloads/. Or run the
"docker-compose.yml" from the root of the project (if you have docker installed
locally):
$ docker-compose up
...
mysql_1_eedb4818d817 | MySQL init process done. Ready for start up.
...
2) (Once only) create the PetClinic database and user by executing the "db/mysql/user.sql"
scripts. You can connect to the database running in the docker container using
`mysql -u root -h localhost --protocol tcp`, but you don't need to run the script there
because the petclinic user is already set up if you use the provided `docker-compose.yaml`.
3) Run the app with `spring.profiles.active=mysql` (e.g. as a System property via the command
line, but any way that sets that property in a Spring Boot app should work).
N.B. the "petclinic" database has to exist for the app to work with the JDBC URL value
as it is configured by default. This condition is taken care of automatically by the
docker-compose configuration provided, or by the `user.sql` script if you run that as
root.

View file

@ -0,0 +1,55 @@
CREATE TABLE IF NOT EXISTS 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 IF NOT EXISTS specialties (
id INT(4) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(80),
INDEX(name)
) engine=InnoDB;
CREATE TABLE IF NOT EXISTS vet_specialties (
vet_id INT(4) UNSIGNED NOT NULL,
specialty_id INT(4) UNSIGNED NOT NULL,
FOREIGN KEY (vet_id) REFERENCES vets(id),
FOREIGN KEY (specialty_id) REFERENCES specialties(id),
UNIQUE (vet_id,specialty_id)
) engine=InnoDB;
CREATE TABLE IF NOT EXISTS types (
id INT(4) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(80),
INDEX(name)
) engine=InnoDB;
CREATE TABLE IF NOT EXISTS 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 IF NOT EXISTS 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),
FOREIGN KEY (owner_id) REFERENCES owners(id),
FOREIGN KEY (type_id) REFERENCES types(id)
) engine=InnoDB;
CREATE TABLE IF NOT EXISTS visits (
id INT(4) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
pet_id INT(4) UNSIGNED NOT NULL,
visit_date DATE,
description VARCHAR(255),
FOREIGN KEY (pet_id) REFERENCES pets(id)
) engine=InnoDB;

View file

@ -0,0 +1,7 @@
CREATE DATABASE IF NOT EXISTS petclinic;
ALTER DATABASE petclinic
DEFAULT CHARACTER SET utf8
DEFAULT COLLATE utf8_general_ci;
GRANT ALL PRIVILEGES ON petclinic.* TO 'petclinic@%' IDENTIFIED BY 'petclinic';

View 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

View 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

View file

@ -0,0 +1 @@
# This file is intentionally empty. Message look-ups will fall back to the default "messages.properties" file.

View file

@ -0,0 +1,8 @@
welcome=Bienvenido
required=Es requerido
notFound=No ha sido encontrado
duplicate=Ya se encuentra en uso
nonNumeric=Sólo debe contener numeros
duplicateFormSubmission=No se permite el envío de formularios duplicados
typeMismatch.date=Fecha invalida
typeMismatch.birthDate=Fecha invalida

File diff suppressed because it is too large Load diff

After

Width:  |  Height:  |  Size: 83 KiB

File diff suppressed because it is too large Load diff

After

Width:  |  Height:  |  Size: 362 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 528 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html xmlns:th="https://www.thymeleaf.org" th:replace="~{fragments/layout :: layout (~{::body},'error')}">
<body>
<img src="../static/resources/images/pets.png" th:src="@{/resources/images/pets.png}"/>
<h2>Something happened...</h2>
<p th:text="${message}">Exception message</p>
</body>
</html>

View file

@ -0,0 +1,30 @@
<html>
<body>
<form>
<th:block th:fragment="input (label, name, type)">
<div th:with="valid=${!#fields.hasErrors(name)}"
th:class="${'form-group' + (valid ? '' : ' has-error')}"
class="form-group">
<label class="col-sm-2 control-label" th:text="${label}">Label</label>
<div class="col-sm-10">
<div th:switch="${type}">
<input th:case="'text'" class="form-control" type="text" th:field="*{__${name}__}" />
<input th:case="'date'" class="form-control" type="text" th:field="*{__${name}__}"
placeholder="YYYY-MM-DD" title="Enter a date in this format: YYYY-MM-DD"
pattern="(?:19|20)[0-9]{2}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-9])|(?:(?!02)(?:0[1-9]|1[0-2])-(?:30))|(?:(?:0[13578]|1[02])-31))"/>
</div>
<span th:if="${valid}"
class="glyphicon glyphicon-ok form-control-feedback"
aria-hidden="true"></span>
<th:block th:if="${!valid}">
<span
class="glyphicon glyphicon-remove form-control-feedback"
aria-hidden="true"></span>
<span class="help-inline" th:errors="*{__${name}__}">Error</span>
</th:block>
</div>
</div>
</th:block>
</form>
</body>
</html>

View file

@ -0,0 +1,104 @@
<!doctype html>
<html th:fragment="layout (template, menu)">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" type="image/x-icon" th:href="@{/resources/images/favicon.png}">
<title>PetClinic :: a Spring Framework demonstration</title>
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<link rel="stylesheet" th:href="@{/resources/css/petclinic.css}" />
</head>
<body>
<nav class="navbar navbar-default" role="navigation">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" th:href="@{/}"><span></span></a>
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#main-navbar">
<span class="sr-only">
<os-p>Toggle navigation</os-p>
</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<div class="navbar-collapse collapse" id="main-navbar">
<ul class="nav navbar-nav navbar-right" th:remove="all">
<li th:fragment="menuItem (link,active,title,glyph,text)" class="active"
th:class="${active==menu ? 'active' : ''}">
<a th:href="@{__${link}__}" th:title="${title}">
<span th:class="'glyphicon glyphicon-'+${glyph}" class="glyphicon glyphicon-home"
aria-hidden="true"></span>
<span th:text="${text}">Template</span>
</a>
</li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li th:replace="::menuItem ('/','home','home page','home','Home')">
<span class="glyphicon glyphicon-home" aria-hidden="true"></span>
<span>Home</span>
</li>
<li th:replace="::menuItem ('/owners/find','owners','find owners','search','Find owners')">
<span class="glyphicon glyphicon-search" aria-hidden="true"></span>
<span>Find owners</span>
</li>
<li th:replace="::menuItem ('/vets.html','vets','veterinarians','th-list','Veterinarians')">
<span class="glyphicon glyphicon-th-list" aria-hidden="true"></span>
<span>Veterinarians</span>
</li>
<li
th:replace="::menuItem ('/oups','error','trigger a RuntimeException to see how it is handled','warning-sign','Error')">
<span class="glyphicon glyphicon-warning-sign" aria-hidden="true"></span>
<span>Error</span>
</li>
</ul>
</div>
</div>
</nav>
<div class="container-fluid">
<div class="container xd-container">
<th:block th:include="${template}" />
<br />
<br />
<div class="container">
<div class="row">
<div class="col-12 text-center">
<img src="../static/resources/images/spring-pivotal-logo.png"
th:src="@{/resources/images/spring-pivotal-logo.png}" alt="Sponsored by Pivotal" /></div>
</div>
</div>
</div>
</div>
<script th:src="@{/webjars/jquery/jquery.min.js}"></script>
<script th:src="@{/webjars/jquery-ui/jquery-ui.min.js}"></script>
<script th:src="@{/webjars/bootstrap/js/bootstrap.min.js}"></script>
</body>
</html>

View file

@ -0,0 +1,29 @@
<html>
<body>
<form>
<th:block th:fragment="select (label, name, items)">
<div th:with="valid=${!#fields.hasErrors(name)}"
th:class="${'form-group' + (valid ? '' : ' has-error')}"
class="form-group">
<label class="col-sm-2 control-label" th:text="${label}">Label</label>
<div class="col-sm-10">
<select th:field="*{__${name}__}">
<option th:each="item : ${items}" th:value="${item}"
th:text="${item}">dog</option>
</select>
<span th:if="${valid}"
class="glyphicon glyphicon-ok form-control-feedback"
aria-hidden="true"></span>
<th:block th:if="${!valid}">
<span
class="glyphicon glyphicon-remove form-control-feedback"
aria-hidden="true"></span>
<span class="help-inline" th:errors="*{__${name}__}">Error</span>
</th:block>
</div>
</div>
</th:block>
</form>
</body>
</html>

View file

@ -0,0 +1,30 @@
<html xmlns:th="https://www.thymeleaf.org"
th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
<body>
<h2>Owner</h2>
<form th:object="${owner}" class="form-horizontal" id="add-owner-form" method="post">
<div class="form-group has-feedback">
<input
th:replace="~{fragments/inputField :: input ('First Name', 'firstName', 'text')}" />
<input
th:replace="~{fragments/inputField :: input ('Last Name', 'lastName', 'text')}" />
<input
th:replace="~{fragments/inputField :: input ('Address', 'address', 'text')}" />
<input
th:replace="~{fragments/inputField :: input ('City', 'city', 'text')}" />
<input
th:replace="~{fragments/inputField :: input ('Telephone', 'telephone', 'text')}" />
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button
th:with="text=${owner['new']} ? 'Add Owner' : 'Update Owner'"
class="btn btn-default" type="submit" th:text="${text}">Add
Owner</button>
</div>
</div>
</form>
</body>
</html>

View file

@ -0,0 +1,35 @@
<html xmlns:th="https://www.thymeleaf.org"
th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
<body>
<h2>Find Owners</h2>
<form th:object="${owner}" th:action="@{/owners}" method="get"
class="form-horizontal" id="search-owner-form">
<div class="form-group">
<div class="control-group" id="lastNameGroup">
<label class="col-sm-2 control-label">Last name </label>
<div class="col-sm-10">
<input class="form-control" th:field="*{lastName}" size="30"
maxlength="80" /> <span class="help-inline"><div
th:if="${#fields.hasAnyErrors()}">
<p th:each="err : ${#fields.allErrors()}" th:text="${err}">Error</p>
</div></span>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default">Find
Owner</button>
</div>
</div>
</form>
<br />
<a class="btn btn-default" th:href="@{/owners/new}">Add Owner</a>
</body>
</html>

View file

@ -0,0 +1,83 @@
<!DOCTYPE html>
<html xmlns:th="https://www.thymeleaf.org"
th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
<body>
<h2>Owner Information</h2>
<table class="table table-striped" th:object="${owner}">
<tr>
<th>Name</th>
<td><b th:text="*{firstName + ' ' + lastName}"></b></td>
</tr>
<tr>
<th>Address</th>
<td th:text="*{address}"></td>
</tr>
<tr>
<th>City</th>
<td th:text="*{city}"></td>
</tr>
<tr>
<th>Telephone</th>
<td th:text="*{telephone}"></td>
</tr>
</table>
<a th:href="@{{id}/edit(id=${owner.id})}" class="btn btn-default">Edit
Owner</a>
<a th:href="@{{id}/pets/new(id=${owner.id})}" class="btn btn-default">Add
New Pet</a>
<br />
<br />
<br />
<h2>Pets and Visits</h2>
<table class="table table-striped">
<tr th:each="pet : ${owner.pets}">
<td valign="top">
<dl class="dl-horizontal">
<dt>Name</dt>
<dd th:text="${pet.name}"></dd>
<dt>Birth Date</dt>
<dd
th:text="${#temporals.format(pet.birthDate, 'yyyy-MM-dd')}"></dd>
<dt>Type</dt>
<dd th:text="${pet.type}"></dd>
</dl>
</td>
<td valign="top">
<table class="table-condensed">
<thead>
<tr>
<th>Visit Date</th>
<th>Description</th>
</tr>
</thead>
<tr th:each="visit : ${pet.visits}">
<td th:text="${#temporals.format(visit.date, 'yyyy-MM-dd')}"></td>
<td th:text="${visit?.description}"></td>
</tr>
<tr>
<td><a
th:href="@{{ownerId}/pets/{petId}/edit(ownerId=${owner.id},petId=${pet.id})}">Edit
Pet</a></td>
<td><a
th:href="@{{ownerId}/pets/{petId}/visits/new(ownerId=${owner.id},petId=${pet.id})}">Add
Visit</a></td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>

View file

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html xmlns:th="https://www.thymeleaf.org" th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
<body>
<h2>Owners</h2>
<table id="owners" class="table table-striped">
<thead>
<tr>
<th style="width: 150px;">Name</th>
<th style="width: 200px;">Address</th>
<th>City</th>
<th style="width: 120px">Telephone</th>
<th>Pets</th>
</tr>
</thead>
<tbody>
<tr th:each="owner : ${selections}">
<td>
<a th:href="@{/owners/__${owner.id}__}" th:text="${owner.firstName + ' ' + owner.lastName}"/></a>
</td>
<td th:text="${owner.address}"/>
<td th:text="${owner.city}"/>
<td th:text="${owner.telephone}"/>
<td><span th:each="pet : ${owner.pets}" th:text="${pet.name} "/></td>
</tr>
</tbody>
</table>
</body>
</html>

Some files were not shown because too many files have changed in this diff Show more