mirror of
https://github.com/spring-projects/spring-petclinic.git
synced 2025-07-20 06:45:50 +00:00
Enable add Vet
This commit is contained in:
parent
317562a170
commit
ebd570af25
10 changed files with 262 additions and 34 deletions
|
@ -74,6 +74,7 @@ class OwnerController {
|
||||||
|
|
||||||
@PostMapping("/owners/new")
|
@PostMapping("/owners/new")
|
||||||
public String processCreationForm(@Valid Owner owner, BindingResult result, RedirectAttributes redirectAttributes) {
|
public String processCreationForm(@Valid Owner owner, BindingResult result, RedirectAttributes redirectAttributes) {
|
||||||
|
System.out.println("owner/new:"+owner);
|
||||||
if (result.hasErrors()) {
|
if (result.hasErrors()) {
|
||||||
redirectAttributes.addFlashAttribute("error", "There was an error in creating the owner.");
|
redirectAttributes.addFlashAttribute("error", "There was an error in creating the owner.");
|
||||||
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
|
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2019 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
|
||||||
|
*
|
||||||
|
* https://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.vet;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.format.Formatter;
|
||||||
|
import org.springframework.samples.petclinic.owner.OwnerRepository;
|
||||||
|
import org.springframework.samples.petclinic.owner.PetType;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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:
|
||||||
|
* https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#format
|
||||||
|
*
|
||||||
|
* @author Mark Fisher
|
||||||
|
* @author Juergen Hoeller
|
||||||
|
* @author Michael Isvy
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class SpecialtyFormatter implements Formatter<Specialty> {
|
||||||
|
|
||||||
|
|
||||||
|
VetRepository vetRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public SpecialtyFormatter(VetRepository vetRepository) {
|
||||||
|
this.vetRepository = vetRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String print(Specialty specialty) {
|
||||||
|
return specialty.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Specialty parse(String text, Locale locale) throws ParseException {
|
||||||
|
Collection<Specialty> specialties = this.vetRepository.findSpecialties();
|
||||||
|
for (Specialty specialty : specialties) {
|
||||||
|
if (specialty.getName().equals(text)) {
|
||||||
|
return specialty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new ParseException("specialty not found: " + text, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String print(Specialty object, Locale locale) {
|
||||||
|
return object.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package org.springframework.samples.petclinic.vet;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.samples.petclinic.vet.Specialty;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface SpecialtyRepository extends JpaRepository<Specialty, Long> {
|
||||||
|
|
||||||
|
@Query("SELECT s FROM Specialty s ORDER BY s.name")
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
List<Specialty> findSpecialties();
|
||||||
|
}
|
|
@ -15,11 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package org.springframework.samples.petclinic.vet;
|
package org.springframework.samples.petclinic.vet;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.springframework.beans.support.MutableSortDefinition;
|
import org.springframework.beans.support.MutableSortDefinition;
|
||||||
import org.springframework.beans.support.PropertyComparator;
|
import org.springframework.beans.support.PropertyComparator;
|
||||||
|
@ -45,12 +41,14 @@ import jakarta.xml.bind.annotation.XmlElement;
|
||||||
@Table(name = "vets")
|
@Table(name = "vets")
|
||||||
public class Vet extends Person {
|
public class Vet extends Person {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ManyToMany(fetch = FetchType.EAGER)
|
@ManyToMany(fetch = FetchType.EAGER)
|
||||||
@JoinTable(name = "vet_specialties", joinColumns = @JoinColumn(name = "vet_id"),
|
@JoinTable(name = "vet_specialties", joinColumns = @JoinColumn(name = "vet_id"),
|
||||||
inverseJoinColumns = @JoinColumn(name = "specialty_id"))
|
inverseJoinColumns = @JoinColumn(name = "specialty_id"))
|
||||||
private Set<Specialty> specialties;
|
private Collection<Specialty> specialties;
|
||||||
|
|
||||||
protected Set<Specialty> getSpecialtiesInternal() {
|
protected Collection<Specialty> getSpecialtiesInternal() {
|
||||||
if (this.specialties == null) {
|
if (this.specialties == null) {
|
||||||
this.specialties = new HashSet<>();
|
this.specialties = new HashSet<>();
|
||||||
}
|
}
|
||||||
|
@ -63,6 +61,9 @@ public class Vet extends Person {
|
||||||
PropertyComparator.sort(sortedSpecs, new MutableSortDefinition("name", true, true));
|
PropertyComparator.sort(sortedSpecs, new MutableSortDefinition("name", true, true));
|
||||||
return Collections.unmodifiableList(sortedSpecs);
|
return Collections.unmodifiableList(sortedSpecs);
|
||||||
}
|
}
|
||||||
|
public void setSpecialties(Collection<Specialty> specialties) {
|
||||||
|
this.specialties = specialties;
|
||||||
|
}
|
||||||
|
|
||||||
public int getNrOfSpecialties() {
|
public int getNrOfSpecialties() {
|
||||||
return getSpecialtiesInternal().size();
|
return getSpecialtiesInternal().size();
|
||||||
|
|
|
@ -15,16 +15,22 @@
|
||||||
*/
|
*/
|
||||||
package org.springframework.samples.petclinic.vet;
|
package org.springframework.samples.petclinic.vet;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.PageRequest;
|
import org.springframework.data.domain.PageRequest;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.samples.petclinic.model.NamedEntity;
|
||||||
|
import org.springframework.samples.petclinic.owner.Owner;
|
||||||
|
import org.springframework.samples.petclinic.owner.PetType;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.validation.BindingResult;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
|
@ -36,9 +42,16 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
class VetController {
|
class VetController {
|
||||||
|
|
||||||
private final VetRepository vetRepository;
|
private final VetRepository vetRepository;
|
||||||
|
private final SpecialtyRepository specialtyRepository;
|
||||||
|
|
||||||
public VetController(VetRepository clinicService) {
|
@Autowired
|
||||||
|
public VetController(VetRepository clinicService, SpecialtyRepository specialtyRepository) {
|
||||||
this.vetRepository = clinicService;
|
this.vetRepository = clinicService;
|
||||||
|
this.specialtyRepository = specialtyRepository;
|
||||||
|
}
|
||||||
|
@ModelAttribute("specialties")
|
||||||
|
public Collection<Specialty> populateSpecialties() {
|
||||||
|
return this.specialtyRepository.findSpecialties();
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/vets.html")
|
@GetMapping("/vets.html")
|
||||||
|
@ -50,7 +63,32 @@ class VetController {
|
||||||
vets.getVetList().addAll(paginated.toList());
|
vets.getVetList().addAll(paginated.toList());
|
||||||
return addPaginationModel(page, paginated, model);
|
return addPaginationModel(page, paginated, model);
|
||||||
}
|
}
|
||||||
|
@GetMapping("/vets/find")
|
||||||
|
public String initFindForm() {
|
||||||
|
return "vets/findVets";
|
||||||
|
}
|
||||||
|
@ModelAttribute("vet")
|
||||||
|
public Vet findVet(@PathVariable(name = "vetId", required = false) Integer vetId) {
|
||||||
|
return vetId == null ? new Vet()
|
||||||
|
: this.vetRepository.findById(vetId)
|
||||||
|
.orElseThrow(() -> new IllegalArgumentException("Vet not found with id: " + vetId
|
||||||
|
+ ". Please ensure the ID is correct " + "and the owner exists in the database."));
|
||||||
|
}
|
||||||
|
|
||||||
|
static final String VIEWS_VETS_CREATE_OR_UPDATE_FORM = "vets/createOrUpdateVetForm";
|
||||||
|
@GetMapping("/vets/new")
|
||||||
|
public String initCreationForm() {
|
||||||
|
System.out.println("Creating a new vet");
|
||||||
|
return VIEWS_VETS_CREATE_OR_UPDATE_FORM;
|
||||||
|
}
|
||||||
|
@PostMapping("/vets/new")
|
||||||
|
public String processCreationForm(@Valid Vet vet, BindingResult result, Model model) {
|
||||||
|
if (result.hasErrors()) {
|
||||||
|
return VIEWS_VETS_CREATE_OR_UPDATE_FORM;
|
||||||
|
}
|
||||||
|
this.vetRepository.save(vet);
|
||||||
|
return "redirect:/vets.html";
|
||||||
|
}
|
||||||
private String addPaginationModel(int page, Page<Vet> paginated, Model model) {
|
private String addPaginationModel(int page, Page<Vet> paginated, Model model) {
|
||||||
List<Vet> listVets = paginated.getContent();
|
List<Vet> listVets = paginated.getContent();
|
||||||
model.addAttribute("currentPage", page);
|
model.addAttribute("currentPage", page);
|
||||||
|
@ -59,6 +97,37 @@ class VetController {
|
||||||
model.addAttribute("listVets", listVets);
|
model.addAttribute("listVets", listVets);
|
||||||
return "vets/vetList";
|
return "vets/vetList";
|
||||||
}
|
}
|
||||||
|
@GetMapping("/vets")
|
||||||
|
public String processFindForm(@RequestParam(defaultValue = "1") int page, Vet vet, BindingResult result,
|
||||||
|
Model model) {
|
||||||
|
// allow parameterless GET request for /owners to return all records
|
||||||
|
System.out.println("Find vets:"+vet);
|
||||||
|
if (vet.getLastName() == null) {
|
||||||
|
vet.setLastName(""); // empty string signifies broadest possible search
|
||||||
|
}
|
||||||
|
|
||||||
|
// find owners by last name
|
||||||
|
Page<Vet> vetsResults = findPaginatedForVetsLastName(page, vet.getLastName());
|
||||||
|
if (vetsResults.isEmpty()) {
|
||||||
|
// no owners found
|
||||||
|
result.rejectValue("lastName", "notFound", "not found");
|
||||||
|
return "vets/findVets";
|
||||||
|
}
|
||||||
|
|
||||||
|
/*if (vetsResults.getTotalElements() == 1) {
|
||||||
|
// 1 owner found
|
||||||
|
vet = vetsResults.iterator().next();
|
||||||
|
return "redirect:/vets/" + vet.getId();
|
||||||
|
}*/
|
||||||
|
|
||||||
|
// multiple owners found
|
||||||
|
return addPaginationModel(page, vetsResults, model);
|
||||||
|
}
|
||||||
|
private Page<Vet> findPaginatedForVetsLastName(int page, String lastname) {
|
||||||
|
int pageSize = 5;
|
||||||
|
Pageable pageable = PageRequest.of(page - 1, pageSize);
|
||||||
|
return vetRepository.findByLastNameStartingWith(lastname, pageable);
|
||||||
|
}
|
||||||
|
|
||||||
private Page<Vet> findPaginated(int page) {
|
private Page<Vet> findPaginated(int page) {
|
||||||
int pageSize = 5;
|
int pageSize = 5;
|
||||||
|
@ -66,13 +135,13 @@ class VetController {
|
||||||
return vetRepository.findAll(pageable);
|
return vetRepository.findAll(pageable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping({ "/vets" })
|
// @GetMapping({ "/vets" })
|
||||||
public @ResponseBody Vets showResourcesVetList() {
|
// public @ResponseBody Vets showResourcesVetList() {
|
||||||
// Here we are returning an object of type 'Vets' rather than a collection of Vet
|
// // Here we are returning an object of type 'Vets' rather than a collection of Vet
|
||||||
// objects so it is simpler for JSon/Object mapping
|
// // objects so it is simpler for JSon/Object mapping
|
||||||
Vets vets = new Vets();
|
// Vets vets = new Vets();
|
||||||
vets.getVetList().addAll(this.vetRepository.findAll());
|
// vets.getVetList().addAll(this.vetRepository.findAll());
|
||||||
return vets;
|
// return vets;
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,14 +15,23 @@
|
||||||
*/
|
*/
|
||||||
package org.springframework.samples.petclinic.vet;
|
package org.springframework.samples.petclinic.vet;
|
||||||
|
|
||||||
|
import jakarta.annotation.Nonnull;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.JoinTable;
|
||||||
|
import jakarta.persistence.ManyToMany;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
import org.springframework.cache.annotation.Cacheable;
|
import org.springframework.cache.annotation.Cacheable;
|
||||||
import org.springframework.dao.DataAccessException;
|
import org.springframework.dao.DataAccessException;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
import org.springframework.data.repository.Repository;
|
import org.springframework.data.repository.Repository;
|
||||||
|
import org.springframework.samples.petclinic.owner.Owner;
|
||||||
|
import org.springframework.samples.petclinic.owner.PetType;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Repository class for <code>Vet</code> domain objects All method names are compliant
|
* Repository class for <code>Vet</code> domain objects All method names are compliant
|
||||||
|
@ -35,24 +44,21 @@ import java.util.Collection;
|
||||||
* @author Sam Brannen
|
* @author Sam Brannen
|
||||||
* @author Michael Isvy
|
* @author Michael Isvy
|
||||||
*/
|
*/
|
||||||
public interface VetRepository extends Repository<Vet, Integer> {
|
public interface VetRepository extends JpaRepository<Vet, Integer> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve all <code>Vet</code>s from the data store.
|
* Retrieve {@link Vet}s from the data store by last name, returning all owners
|
||||||
* @return a <code>Collection</code> of <code>Vet</code>s
|
* whose last name <i>starts</i> with the given name.
|
||||||
|
* @param lastName Value to search for
|
||||||
|
* @return a Collection of matching {@link Vet}s (or an empty Collection if none
|
||||||
|
* found)
|
||||||
*/
|
*/
|
||||||
@Transactional(readOnly = true)
|
Page<Vet> findByLastNameStartingWith(String lastName, Pageable pageable);
|
||||||
@Cacheable("vets")
|
|
||||||
Collection<Vet> findAll() throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve all <code>Vet</code>s from data store in Pages
|
|
||||||
* @param pageable
|
@Query("SELECT s FROM Specialty s ORDER BY s.name")
|
||||||
* @return
|
|
||||||
* @throws DataAccessException
|
|
||||||
*/
|
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
@Cacheable("vets")
|
List<Specialty> findSpecialties();
|
||||||
Page<Vet> findAll(Pageable pageable) throws DataAccessException;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@ INSERT INTO types VALUES (default, 'lizard');
|
||||||
INSERT INTO types VALUES (default, 'snake');
|
INSERT INTO types VALUES (default, 'snake');
|
||||||
INSERT INTO types VALUES (default, 'bird');
|
INSERT INTO types VALUES (default, 'bird');
|
||||||
INSERT INTO types VALUES (default, 'hamster');
|
INSERT INTO types VALUES (default, 'hamster');
|
||||||
|
INSERT INTO types VALUES (default, 'panda');
|
||||||
|
|
||||||
|
|
||||||
INSERT INTO owners VALUES (default, 'George', 'Franklin', '110 W. Liberty St.', 'Madison', '6085551023');
|
INSERT INTO owners VALUES (default, 'George', 'Franklin', '110 W. Liberty St.', 'Madison', '6085551023');
|
||||||
INSERT INTO owners VALUES (default, 'Betty', 'Davis', '638 Cardinal Ave.', 'Sun Prairie', '6085551749');
|
INSERT INTO owners VALUES (default, 'Betty', 'Davis', '638 Cardinal Ave.', 'Sun Prairie', '6085551749');
|
||||||
|
|
|
@ -59,6 +59,10 @@
|
||||||
<span class="fa fa-th-list" aria-hidden="true"></span>
|
<span class="fa fa-th-list" aria-hidden="true"></span>
|
||||||
<span>Veterinarians</span>
|
<span>Veterinarians</span>
|
||||||
</li>
|
</li>
|
||||||
|
<li th:replace="~{::menuItem ('/vets/find','vets','find veterinarians','search','Find Veterinarians')}">
|
||||||
|
<span class="fa fa-search" aria-hidden="true"></span>
|
||||||
|
<span>Find Veterinarians</span>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li
|
<li
|
||||||
th:replace="~{::menuItem ('/oups','error','trigger a RuntimeException to see how it is handled','exclamation-triangle','Error')}">
|
th:replace="~{::menuItem ('/oups','error','trigger a RuntimeException to see how it is handled','exclamation-triangle','Error')}">
|
||||||
|
|
25
src/main/resources/templates/vets/createOrUpdateVetForm.html
Normal file
25
src/main/resources/templates/vets/createOrUpdateVetForm.html
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<html xmlns:th="https://www.thymeleaf.org"
|
||||||
|
th:replace="~{fragments/layout :: layout (~{::body},'vets')}">
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h2>Vet</h2>
|
||||||
|
<form th:object="${vet}" class="form-horizontal" id="add-vet-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')}" />
|
||||||
|
<div th:replace="~{fragments/selectField :: select ('Specialties', 'specialties', ${specialties})}"></div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
|
<button
|
||||||
|
th:with="text=${vet['new']} ? 'Add Vet' : 'Update Vet'"
|
||||||
|
class="btn btn-primary" type="submit" th:text="${text}">Add
|
||||||
|
Vet</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
34
src/main/resources/templates/vets/findVets.html
Normal file
34
src/main/resources/templates/vets/findVets.html
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<html xmlns:th="https://www.thymeleaf.org"
|
||||||
|
th:replace="~{fragments/layout :: layout (~{::body},'vets')}">
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h2>Find Vets</h2>
|
||||||
|
|
||||||
|
<form th:object="${vet}" th:action="@{/vets}" method="get"
|
||||||
|
class="form-horizontal" id="search-vet-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-primary">Find
|
||||||
|
Vet</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a class="btn btn-primary" th:href="@{/vets/new}">Add Vet</a>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in a new issue