mirror of
https://github.com/spring-projects/spring-petclinic.git
synced 2025-07-17 21:15:50 +00:00
full refactoring
This commit is contained in:
parent
39f75b0d7e
commit
03b0759065
35 changed files with 579 additions and 567 deletions
|
@ -20,16 +20,16 @@ import org.springframework.boot.SpringApplication;
|
|||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* PetClinic Spring Boot Application.
|
||||
* KidClinic Spring Boot Application.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class PetClinicApplication {
|
||||
public class KidClinicApplication {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
SpringApplication.run(PetClinicApplication.class, args);
|
||||
SpringApplication.run(KidClinicApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.samples.kidclinic.vet;
|
||||
package org.springframework.samples.kidclinic.doctor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
@ -42,11 +42,11 @@ import org.springframework.samples.kidclinic.model.Person;
|
|||
* @author Arjen Poutsma
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "vets")
|
||||
public class Vet extends Person {
|
||||
@Table(name = "doctors")
|
||||
public class Doctor extends Person {
|
||||
|
||||
@ManyToMany(fetch = FetchType.EAGER)
|
||||
@JoinTable(name = "vet_specialties", joinColumns = @JoinColumn(name = "vet_id"), inverseJoinColumns = @JoinColumn(name = "specialty_id"))
|
||||
@JoinTable(name = "doctor_specialties", joinColumns = @JoinColumn(name = "doctor_id"), inverseJoinColumns = @JoinColumn(name = "specialty_id"))
|
||||
private Set<Specialty> specialties;
|
||||
|
||||
protected Set<Specialty> getSpecialtiesInternal() {
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.samples.kidclinic.vet;
|
||||
package org.springframework.samples.kidclinic.doctor;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -29,32 +29,32 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
|||
* @author Arjen Poutsma
|
||||
*/
|
||||
@Controller
|
||||
class VetController {
|
||||
class DoctorController {
|
||||
|
||||
private final VetRepository vets;
|
||||
private final DoctorRepository doctors;
|
||||
|
||||
@Autowired
|
||||
public VetController(VetRepository clinicService) {
|
||||
this.vets = clinicService;
|
||||
public DoctorController(DoctorRepository clinicService) {
|
||||
this.doctors = clinicService;
|
||||
}
|
||||
|
||||
@RequestMapping(value = { "/vets.html" })
|
||||
public String showVetList(Map<String, Object> model) {
|
||||
// Here we are returning an object of type 'Vets' rather than a collection of Vet
|
||||
@RequestMapping(value = { "/doctors.html" })
|
||||
public String showDoctorList(Map<String, Object> model) {
|
||||
// Here we are returning an object of type 'Doctors' rather than a collection of Doctor
|
||||
// objects so it is simpler for Object-Xml mapping
|
||||
Vets vets = new Vets();
|
||||
vets.getVetList().addAll(this.vets.findAll());
|
||||
model.put("vets", vets);
|
||||
return "vets/vetList";
|
||||
Doctors doctors = new Doctors();
|
||||
doctors.getDoctorList().addAll(this.doctors.findAll());
|
||||
model.put("doctors", doctors);
|
||||
return "doctors/doctorList";
|
||||
}
|
||||
|
||||
@RequestMapping(value = { "/vets.json", "/vets.xml" })
|
||||
public @ResponseBody Vets showResourcesVetList() {
|
||||
// Here we are returning an object of type 'Vets' rather than a collection of Vet
|
||||
@RequestMapping(value = { "/doctors.json", "/doctors.xml" })
|
||||
public @ResponseBody Doctors showResourcesVetList() {
|
||||
// Here we are returning an object of type 'Doctors' rather than a collection of Doctor
|
||||
// objects so it is simpler for JSon/Object mapping
|
||||
Vets vets = new Vets();
|
||||
vets.getVetList().addAll(this.vets.findAll());
|
||||
return vets;
|
||||
Doctors doctors = new Doctors();
|
||||
doctors.getDoctorList().addAll(this.doctors.findAll());
|
||||
return doctors;
|
||||
}
|
||||
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.samples.kidclinic.vet;
|
||||
package org.springframework.samples.kidclinic.doctor;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
|
@ -23,7 +23,7 @@ import org.springframework.data.repository.Repository;
|
|||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Repository class for <code>Vet</code> domain objects All method names are compliant with Spring Data naming
|
||||
* Repository class for <code>Doctor</code> domain objects All method names are compliant with Spring Data naming
|
||||
* conventions so this interface can easily be extended for Spring Data See here: http://static.springsource.org/spring-data/jpa/docs/current/reference/html/jpa.repositories.html#jpa.query-methods.query-creation
|
||||
*
|
||||
* @author Ken Krebs
|
||||
|
@ -31,16 +31,16 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
* @author Sam Brannen
|
||||
* @author Michael Isvy
|
||||
*/
|
||||
public interface VetRepository extends Repository<Vet, Integer> {
|
||||
public interface DoctorRepository extends Repository<Doctor, Integer> {
|
||||
|
||||
/**
|
||||
* Retrieve all <code>Vet</code>s from the data store.
|
||||
* Retrieve all <code>Doctor</code>s from the data store.
|
||||
*
|
||||
* @return a <code>Collection</code> of <code>Vet</code>s
|
||||
* @return a <code>Collection</code> of <code>Doctor</code>s
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
@Cacheable("vets")
|
||||
Collection<Vet> findAll() throws DataAccessException;
|
||||
@Cacheable("doctors")
|
||||
Collection<Doctor> findAll() throws DataAccessException;
|
||||
|
||||
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.samples.kidclinic.vet;
|
||||
package org.springframework.samples.kidclinic.doctor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -22,22 +22,22 @@ import javax.xml.bind.annotation.XmlElement;
|
|||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
/**
|
||||
* Simple domain object representing a list of veterinarians. Mostly here to be used for the 'vets' {@link
|
||||
* Simple domain object representing a list of doctors. Mostly here to be used for the 'doctors' {@link
|
||||
* org.springframework.web.servlet.view.xml.MarshallingView}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
@XmlRootElement
|
||||
public class Vets {
|
||||
public class Doctors {
|
||||
|
||||
private List<Vet> vets;
|
||||
private List<Doctor> doctors;
|
||||
|
||||
@XmlElement
|
||||
public List<Vet> getVetList() {
|
||||
if (vets == null) {
|
||||
vets = new ArrayList<>();
|
||||
public List<Doctor> getDoctorList() {
|
||||
if (doctors == null) {
|
||||
doctors = new ArrayList<>();
|
||||
}
|
||||
return vets;
|
||||
return doctors;
|
||||
}
|
||||
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.samples.kidclinic.vet;
|
||||
package org.springframework.samples.kidclinic.doctor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
@ -23,7 +23,7 @@ import javax.persistence.Table;
|
|||
import org.springframework.samples.kidclinic.model.NamedEntity;
|
||||
|
||||
/**
|
||||
* Models a {@link Vet Vet's} specialty (for example, dentistry).
|
||||
* Models a {@link Doctor Doctor's} specialty (for example, dentistry).
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
*/
|
|
@ -1,136 +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.kidclinic.owner;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.annotation.InitBinder;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
/**
|
||||
* @author Juergen Hoeller
|
||||
* @author Ken Krebs
|
||||
* @author Arjen Poutsma
|
||||
* @author Michael Isvy
|
||||
*/
|
||||
@Controller
|
||||
class OwnerController {
|
||||
|
||||
private static final String VIEWS_OWNER_CREATE_OR_UPDATE_FORM = "owners/createOrUpdateOwnerForm";
|
||||
private final OwnerRepository owners;
|
||||
|
||||
|
||||
@Autowired
|
||||
public OwnerController(OwnerRepository clinicService) {
|
||||
this.owners = clinicService;
|
||||
}
|
||||
|
||||
@InitBinder
|
||||
public void setAllowedFields(WebDataBinder dataBinder) {
|
||||
dataBinder.setDisallowedFields("id");
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/owners/new", method = RequestMethod.GET)
|
||||
public String initCreationForm(Map<String, Object> model) {
|
||||
Owner owner = new Owner();
|
||||
model.put("owner", owner);
|
||||
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/owners/new", method = RequestMethod.POST)
|
||||
public String processCreationForm(@Valid Owner owner, BindingResult result) {
|
||||
if (result.hasErrors()) {
|
||||
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
|
||||
} else {
|
||||
this.owners.save(owner);
|
||||
return "redirect:/owners/" + owner.getId();
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/owners/find", method = RequestMethod.GET)
|
||||
public String initFindForm(Map<String, Object> model) {
|
||||
model.put("owner", new Owner());
|
||||
return "owners/findOwners";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/owners", method = RequestMethod.GET)
|
||||
public String processFindForm(Owner owner, BindingResult result, Map<String, Object> model) {
|
||||
|
||||
// allow parameterless GET request for /owners to return all records
|
||||
if (owner.getLastName() == null) {
|
||||
owner.setLastName(""); // empty string signifies broadest possible search
|
||||
}
|
||||
|
||||
// find owners by last name
|
||||
Collection<Owner> results = this.owners.findByLastName(owner.getLastName());
|
||||
if (results.isEmpty()) {
|
||||
// no owners found
|
||||
result.rejectValue("lastName", "notFound", "not found");
|
||||
return "owners/findOwners";
|
||||
} else if (results.size() == 1) {
|
||||
// 1 owner found
|
||||
owner = results.iterator().next();
|
||||
return "redirect:/owners/" + owner.getId();
|
||||
} else {
|
||||
// multiple owners found
|
||||
model.put("selections", results);
|
||||
return "owners/ownersList";
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/owners/{ownerId}/edit", method = RequestMethod.GET)
|
||||
public String initUpdateOwnerForm(@PathVariable("ownerId") int ownerId, Model model) {
|
||||
Owner owner = this.owners.findById(ownerId);
|
||||
model.addAttribute(owner);
|
||||
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/owners/{ownerId}/edit", method = RequestMethod.POST)
|
||||
public String processUpdateOwnerForm(@Valid Owner owner, BindingResult result, @PathVariable("ownerId") int ownerId) {
|
||||
if (result.hasErrors()) {
|
||||
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
|
||||
} else {
|
||||
owner.setId(ownerId);
|
||||
this.owners.save(owner);
|
||||
return "redirect:/owners/{ownerId}";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom handler for displaying an owner.
|
||||
*
|
||||
* @param ownerId the ID of the owner to display
|
||||
* @return a ModelMap with the model attributes for the view
|
||||
*/
|
||||
@RequestMapping("/owners/{ownerId}")
|
||||
public ModelAndView showOwner(@PathVariable("ownerId") int ownerId) {
|
||||
ModelAndView mav = new ModelAndView("owners/ownerDetails");
|
||||
mav.addObject(this.owners.findById(ownerId));
|
||||
return mav;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,116 +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.kidclinic.owner;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.annotation.InitBinder;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
/**
|
||||
* @author Juergen Hoeller
|
||||
* @author Ken Krebs
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/owners/{ownerId}")
|
||||
class PetController {
|
||||
|
||||
private static final String VIEWS_PETS_CREATE_OR_UPDATE_FORM = "pets/createOrUpdatePetForm";
|
||||
private final PetRepository pets;
|
||||
private final OwnerRepository owners;
|
||||
|
||||
@Autowired
|
||||
public PetController(PetRepository pets, OwnerRepository owners) {
|
||||
this.pets = pets;
|
||||
this.owners = owners;
|
||||
}
|
||||
|
||||
@ModelAttribute("types")
|
||||
public Collection<PetType> populatePetTypes() {
|
||||
return this.pets.findPetTypes();
|
||||
}
|
||||
|
||||
@ModelAttribute("owner")
|
||||
public Owner findOwner(@PathVariable("ownerId") int ownerId) {
|
||||
return this.owners.findById(ownerId);
|
||||
}
|
||||
|
||||
@InitBinder("owner")
|
||||
public void initOwnerBinder(WebDataBinder dataBinder) {
|
||||
dataBinder.setDisallowedFields("id");
|
||||
}
|
||||
|
||||
@InitBinder("pet")
|
||||
public void initPetBinder(WebDataBinder dataBinder) {
|
||||
dataBinder.setValidator(new PetValidator());
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/pets/new", method = RequestMethod.GET)
|
||||
public String initCreationForm(Owner owner, ModelMap model) {
|
||||
Pet pet = new Pet();
|
||||
owner.addPet(pet);
|
||||
model.put("pet", pet);
|
||||
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/pets/new", method = RequestMethod.POST)
|
||||
public String processCreationForm(Owner owner, @Valid Pet pet, BindingResult result, ModelMap model) {
|
||||
if (StringUtils.hasLength(pet.getName()) && pet.isNew() && owner.getPet(pet.getName(), true) != null){
|
||||
result.rejectValue("name", "duplicate", "already exists");
|
||||
}
|
||||
if (result.hasErrors()) {
|
||||
model.put("pet", pet);
|
||||
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
|
||||
} else {
|
||||
owner.addPet(pet);
|
||||
this.pets.save(pet);
|
||||
return "redirect:/owners/{ownerId}";
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/pets/{petId}/edit", method = RequestMethod.GET)
|
||||
public String initUpdateForm(@PathVariable("petId") int petId, ModelMap model) {
|
||||
Pet pet = this.pets.findById(petId);
|
||||
model.put("pet", pet);
|
||||
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/pets/{petId}/edit", method = RequestMethod.POST)
|
||||
public String processUpdateForm(@Valid Pet pet, BindingResult result, Owner owner, ModelMap model) {
|
||||
if (result.hasErrors()) {
|
||||
pet.setOwner(owner);
|
||||
model.put("pet", pet);
|
||||
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
|
||||
} else {
|
||||
owner.addPet(pet);
|
||||
this.pets.save(pet);
|
||||
return "redirect:/owners/{ownerId}";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.samples.kidclinic.owner;
|
||||
package org.springframework.samples.kidclinic.parent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
@ -48,8 +48,8 @@ import org.springframework.samples.kidclinic.visit.Visit;
|
|||
* @author Sam Brannen
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "pets")
|
||||
public class Pet extends NamedEntity {
|
||||
@Table(name = "kids")
|
||||
public class Kid extends NamedEntity {
|
||||
|
||||
@Column(name = "birth_date")
|
||||
@Temporal(TemporalType.DATE)
|
||||
|
@ -57,14 +57,14 @@ public class Pet extends NamedEntity {
|
|||
private Date birthDate;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "type_id")
|
||||
private PetType type;
|
||||
@JoinColumn(name = "gender_id")
|
||||
private KidGender gender;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "owner_id")
|
||||
private Owner owner;
|
||||
@JoinColumn(name = "parent_id")
|
||||
private Parent parent;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "petId", fetch = FetchType.EAGER)
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "kidId", fetch = FetchType.EAGER)
|
||||
private Set<Visit> visits = new LinkedHashSet<>();
|
||||
|
||||
public void setBirthDate(Date birthDate) {
|
||||
|
@ -75,20 +75,20 @@ public class Pet extends NamedEntity {
|
|||
return this.birthDate;
|
||||
}
|
||||
|
||||
public PetType getType() {
|
||||
return this.type;
|
||||
public KidGender getGender() {
|
||||
return this.gender;
|
||||
}
|
||||
|
||||
public void setType(PetType type) {
|
||||
this.type = type;
|
||||
public void setGender(KidGender gender) {
|
||||
this.gender = gender;
|
||||
}
|
||||
|
||||
public Owner getOwner() {
|
||||
return this.owner;
|
||||
public Parent getParent() {
|
||||
return this.parent;
|
||||
}
|
||||
|
||||
protected void setOwner(Owner owner) {
|
||||
this.owner = owner;
|
||||
protected void setParent(Parent parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
protected Set<Visit> getVisitsInternal() {
|
||||
|
@ -111,7 +111,7 @@ public class Pet extends NamedEntity {
|
|||
|
||||
public void addVisit(Visit visit) {
|
||||
getVisitsInternal().add(visit);
|
||||
visit.setPetId(this.getId());
|
||||
visit.setKidId(this.getId());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* 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.kidclinic.parent;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.annotation.InitBinder;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
/**
|
||||
* @author Juergen Hoeller
|
||||
* @author Ken Krebs
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/parents/{parentId}")
|
||||
class KidController {
|
||||
|
||||
private static final String VIEWS_KIDS_CREATE_OR_UPDATE_FORM = "kids/createOrUpdateKidForm";
|
||||
private final KidRepository kids;
|
||||
private final ParentRepository parents;
|
||||
|
||||
@Autowired
|
||||
public KidController(KidRepository kids, ParentRepository parents) {
|
||||
this.kids = kids;
|
||||
this.parents = parents;
|
||||
}
|
||||
|
||||
@ModelAttribute("gender")
|
||||
public Collection<KidGender> populateKidGenders() {
|
||||
return this.kids.findKidGenders();
|
||||
}
|
||||
|
||||
@ModelAttribute("parent")
|
||||
public Parent findParent(@PathVariable("parentId") int parentId) {
|
||||
return this.parents.findById(parentId);
|
||||
}
|
||||
|
||||
@InitBinder("parent")
|
||||
public void initParentBinder(WebDataBinder dataBinder) {
|
||||
dataBinder.setDisallowedFields("id");
|
||||
}
|
||||
|
||||
@InitBinder("kid")
|
||||
public void initKidBinder(WebDataBinder dataBinder) {
|
||||
dataBinder.setValidator(new KidValidator());
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/kids/new", method = RequestMethod.GET)
|
||||
public String initCreationForm(Parent parent, ModelMap model) {
|
||||
Kid kid = new Kid();
|
||||
parent.addKid(kid);
|
||||
model.put("kid", kid);
|
||||
return VIEWS_KIDS_CREATE_OR_UPDATE_FORM;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/kids/new", method = RequestMethod.POST)
|
||||
public String processCreationForm(Parent parent, @Valid Kid kid, BindingResult result, ModelMap model) {
|
||||
if (StringUtils.hasLength(kid.getName()) && kid.isNew() && parent.getKid(kid.getName(), true) != null){
|
||||
result.rejectValue("name", "duplicate", "already exists");
|
||||
}
|
||||
if (result.hasErrors()) {
|
||||
model.put("kid", kid);
|
||||
return VIEWS_KIDS_CREATE_OR_UPDATE_FORM;
|
||||
} else {
|
||||
parent.addKid(kid);
|
||||
this.kids.save(kid);
|
||||
return "redirect:/parents/{parentId}";
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/kids/{kidId}/edit", method = RequestMethod.GET)
|
||||
public String initUpdateForm(@PathVariable("kidId") int kidId, ModelMap model) {
|
||||
Kid kid = this.kids.findById(kidId);
|
||||
model.put("kid", kid);
|
||||
return VIEWS_KIDS_CREATE_OR_UPDATE_FORM;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/kids/{kidsId}/edit", method = RequestMethod.POST)
|
||||
public String processUpdateForm(@Valid Kid kid, BindingResult result, Parent parent, ModelMap model) {
|
||||
if (result.hasErrors()) {
|
||||
kid.setParent(parent);
|
||||
model.put("kid", kid);
|
||||
return VIEWS_KIDS_CREATE_OR_UPDATE_FORM;
|
||||
} else {
|
||||
parent.addKid(kid);
|
||||
this.kids.save(kid);
|
||||
return "redirect:/parents/{parentId}";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.samples.kidclinic.owner;
|
||||
package org.springframework.samples.kidclinic.parent;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
|
@ -25,7 +25,7 @@ import org.springframework.samples.kidclinic.model.NamedEntity;
|
|||
* Can be Cat, Dog, Hamster...
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "types")
|
||||
public class PetType extends NamedEntity {
|
||||
@Table(name = "gender")
|
||||
public class KidGender extends NamedEntity {
|
||||
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.samples.kidclinic.owner;
|
||||
package org.springframework.samples.kidclinic.parent;
|
||||
|
||||
|
||||
import java.text.ParseException;
|
||||
|
@ -25,7 +25,7 @@ import org.springframework.format.Formatter;
|
|||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Instructs Spring MVC on how to parse and print elements of type 'PetType'. Starting from Spring 3.0, Formatters have
|
||||
* Instructs Spring MVC on how to parse and print elements of type 'KidGender'. 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/
|
||||
|
@ -36,30 +36,30 @@ import org.springframework.stereotype.Component;
|
|||
* @author Michael Isvy
|
||||
*/
|
||||
@Component
|
||||
public class PetTypeFormatter implements Formatter<PetType> {
|
||||
public class KidGenderFormatter implements Formatter<KidGender> {
|
||||
|
||||
private final PetRepository pets;
|
||||
private final KidRepository kids;
|
||||
|
||||
|
||||
@Autowired
|
||||
public PetTypeFormatter(PetRepository pets) {
|
||||
this.pets = pets;
|
||||
public KidGenderFormatter(KidRepository kids) {
|
||||
this.kids = kids;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String print(PetType petType, Locale locale) {
|
||||
return petType.getName();
|
||||
public String print(KidGender kidGender, Locale locale) {
|
||||
return kidGender.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PetType parse(String text, Locale locale) throws ParseException {
|
||||
Collection<PetType> findPetTypes = this.pets.findPetTypes();
|
||||
for (PetType type : findPetTypes) {
|
||||
if (type.getName().equals(text)) {
|
||||
return type;
|
||||
public KidGender parse(String text, Locale locale) throws ParseException {
|
||||
Collection<KidGender> findKidGenders = this.kids.findKidGenders();
|
||||
for (KidGender gender : findKidGenders) {
|
||||
if (gender.getName().equals(text)) {
|
||||
return gender;
|
||||
}
|
||||
}
|
||||
throw new ParseException("type not found: " + text, 0);
|
||||
throw new ParseException("gender not found: " + text, 0);
|
||||
}
|
||||
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.samples.kidclinic.owner;
|
||||
package org.springframework.samples.kidclinic.parent;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -22,7 +22,7 @@ import org.springframework.data.repository.Repository;
|
|||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Repository class for <code>Pet</code> domain objects All method names are compliant with Spring Data naming
|
||||
* Repository class for <code>Kid</code> domain objects All method names are compliant with Spring Data naming
|
||||
* conventions so this interface can easily be extended for Spring Data See here: http://static.springsource.org/spring-data/jpa/docs/current/reference/html/jpa.repositories.html#jpa.query-methods.query-creation
|
||||
*
|
||||
* @author Ken Krebs
|
||||
|
@ -30,29 +30,29 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
* @author Sam Brannen
|
||||
* @author Michael Isvy
|
||||
*/
|
||||
public interface PetRepository extends Repository<Pet, Integer> {
|
||||
public interface KidRepository extends Repository<Kid, Integer> {
|
||||
|
||||
/**
|
||||
* Retrieve all {@link PetType}s from the data store.
|
||||
* @return a Collection of {@link PetType}s.
|
||||
* Retrieve all {@link KidGender}s from the data store.
|
||||
* @return a Collection of {@link KidGender}s.
|
||||
*/
|
||||
@Query("SELECT ptype FROM PetType ptype ORDER BY ptype.name")
|
||||
@Query("SELECT ptype FROM KidGender ptype ORDER BY ptype.name")
|
||||
@Transactional(readOnly = true)
|
||||
List<PetType> findPetTypes();
|
||||
List<KidGender> findKidGenders();
|
||||
|
||||
/**
|
||||
* Retrieve a {@link Pet} from the data store by id.
|
||||
* Retrieve a {@link Kid} from the data store by id.
|
||||
* @param id the id to search for
|
||||
* @return the {@link Pet} if found
|
||||
* @return the {@link Kid} if found
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
Pet findById(Integer id);
|
||||
Kid findById(Integer id);
|
||||
|
||||
/**
|
||||
* Save a {@link Pet} to the data store, either inserting or updating it.
|
||||
* @param pet the {@link Pet} to save
|
||||
* Save a {@link Kid} to the data store, either inserting or updating it.
|
||||
* @param kid the {@link Kid} to save
|
||||
*/
|
||||
void save(Pet pet);
|
||||
void save(Kid kid);
|
||||
|
||||
}
|
||||
|
|
@ -13,14 +13,14 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.samples.kidclinic.owner;
|
||||
package org.springframework.samples.kidclinic.parent;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.Validator;
|
||||
|
||||
/**
|
||||
* <code>Validator</code> for <code>Pet</code> forms.
|
||||
* <code>Validator</code> for <code>Kid</code> forms.
|
||||
* <p>
|
||||
* We're not using Bean Validation annotations here because it is easier to define such validation rule in Java.
|
||||
* </p>
|
||||
|
@ -28,36 +28,36 @@ import org.springframework.validation.Validator;
|
|||
* @author Ken Krebs
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class PetValidator implements Validator {
|
||||
public class KidValidator implements Validator {
|
||||
|
||||
private static final String REQUIRED = "required";
|
||||
|
||||
@Override
|
||||
public void validate(Object obj, Errors errors) {
|
||||
Pet pet = (Pet) obj;
|
||||
String name = pet.getName();
|
||||
Kid kid = (Kid) obj;
|
||||
String name = kid.getName();
|
||||
// name validation
|
||||
if (!StringUtils.hasLength(name)) {
|
||||
errors.rejectValue("name", REQUIRED, REQUIRED);
|
||||
}
|
||||
|
||||
// type validation
|
||||
if (pet.isNew() && pet.getType() == null) {
|
||||
errors.rejectValue("type", REQUIRED, REQUIRED);
|
||||
// gender validation
|
||||
if (kid.isNew() && kid.getGender() == null) {
|
||||
errors.rejectValue("gender", REQUIRED, REQUIRED);
|
||||
}
|
||||
|
||||
// birth date validation
|
||||
if (pet.getBirthDate() == null) {
|
||||
if (kid.getBirthDate() == null) {
|
||||
errors.rejectValue("birthDate", REQUIRED, REQUIRED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This Validator validates *just* Pet instances
|
||||
* This Validator validates *just* Kid instances
|
||||
*/
|
||||
@Override
|
||||
public boolean supports(Class<?> clazz) {
|
||||
return Pet.class.isAssignableFrom(clazz);
|
||||
return Kid.class.isAssignableFrom(clazz);
|
||||
}
|
||||
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.samples.kidclinic.owner;
|
||||
package org.springframework.samples.kidclinic.parent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
@ -35,7 +35,7 @@ import org.springframework.core.style.ToStringCreator;
|
|||
import org.springframework.samples.kidclinic.model.Person;
|
||||
|
||||
/**
|
||||
* Simple JavaBean domain object representing an owner.
|
||||
* Simple JavaBean domain object representing an parent.
|
||||
*
|
||||
* @author Ken Krebs
|
||||
* @author Juergen Hoeller
|
||||
|
@ -43,8 +43,8 @@ import org.springframework.samples.kidclinic.model.Person;
|
|||
* @author Michael Isvy
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "owners")
|
||||
public class Owner extends Person {
|
||||
@Table(name = "parents")
|
||||
public class Parent extends Person {
|
||||
@Column(name = "address")
|
||||
@NotEmpty
|
||||
private String address;
|
||||
|
@ -58,8 +58,8 @@ public class Owner extends Person {
|
|||
@Digits(fraction = 0, integer = 10)
|
||||
private String telephone;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "owner")
|
||||
private Set<Pet> pets;
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "parent")
|
||||
private Set<Kid> kids;
|
||||
|
||||
|
||||
public String getAddress() {
|
||||
|
@ -86,54 +86,54 @@ public class Owner extends Person {
|
|||
this.telephone = telephone;
|
||||
}
|
||||
|
||||
protected Set<Pet> getPetsInternal() {
|
||||
if (this.pets == null) {
|
||||
this.pets = new HashSet<>();
|
||||
protected Set<Kid> getKidsInternal() {
|
||||
if (this.kids == null) {
|
||||
this.kids = new HashSet<>();
|
||||
}
|
||||
return this.pets;
|
||||
return this.kids;
|
||||
}
|
||||
|
||||
protected void setPetsInternal(Set<Pet> pets) {
|
||||
this.pets = pets;
|
||||
protected void setKidsInternal(Set<Kid> kids) {
|
||||
this.kids = kids;
|
||||
}
|
||||
|
||||
public List<Pet> getPets() {
|
||||
List<Pet> sortedPets = new ArrayList<>(getPetsInternal());
|
||||
PropertyComparator.sort(sortedPets, new MutableSortDefinition("name", true, true));
|
||||
return Collections.unmodifiableList(sortedPets);
|
||||
public List<Kid> getKids() {
|
||||
List<Kid> sortedKids = new ArrayList<>(getKidsInternal());
|
||||
PropertyComparator.sort(sortedKids, new MutableSortDefinition("name", true, true));
|
||||
return Collections.unmodifiableList(sortedKids);
|
||||
}
|
||||
|
||||
public void addPet(Pet pet) {
|
||||
if (pet.isNew()) {
|
||||
getPetsInternal().add(pet);
|
||||
public void addKid(Kid kid) {
|
||||
if (kid.isNew()) {
|
||||
getKidsInternal().add(kid);
|
||||
}
|
||||
pet.setOwner(this);
|
||||
kid.setParent(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Pet with the given name, or null if none found for this Owner.
|
||||
* Return the Kid with the given name, or null if none found for this Parent.
|
||||
*
|
||||
* @param name to test
|
||||
* @return true if pet name is already in use
|
||||
* @return true if kid name is already in use
|
||||
*/
|
||||
public Pet getPet(String name) {
|
||||
return getPet(name, false);
|
||||
public Kid getKid(String name) {
|
||||
return getKid(name, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Pet with the given name, or null if none found for this Owner.
|
||||
* Return the Kid with the given name, or null if none found for this Kid.
|
||||
*
|
||||
* @param name to test
|
||||
* @return true if pet name is already in use
|
||||
* @return true if kid name is already in use
|
||||
*/
|
||||
public Pet getPet(String name, boolean ignoreNew) {
|
||||
public Kid getKid(String name, boolean ignoreNew) {
|
||||
name = name.toLowerCase();
|
||||
for (Pet pet : getPetsInternal()) {
|
||||
if (!ignoreNew || !pet.isNew()) {
|
||||
String compName = pet.getName();
|
||||
for (Kid kid : getKidsInternal()) {
|
||||
if (!ignoreNew || !kid.isNew()) {
|
||||
String compName = kid.getName();
|
||||
compName = compName.toLowerCase();
|
||||
if (compName.equals(name)) {
|
||||
return pet;
|
||||
return kid;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* 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.kidclinic.parent;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.annotation.InitBinder;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
/**
|
||||
* @author Juergen Hoeller
|
||||
* @author Ken Krebs
|
||||
* @author Arjen Poutsma
|
||||
* @author Michael Isvy
|
||||
*/
|
||||
@Controller
|
||||
class ParentController {
|
||||
|
||||
private static final String VIEWS_PARENT_CREATE_OR_UPDATE_FORM = "parents/createOrUpdateParentForm";
|
||||
private final ParentRepository parents;
|
||||
|
||||
|
||||
@Autowired
|
||||
public ParentController(ParentRepository clinicService) {
|
||||
this.parents = clinicService;
|
||||
}
|
||||
|
||||
@InitBinder
|
||||
public void setAllowedFields(WebDataBinder dataBinder) {
|
||||
dataBinder.setDisallowedFields("id");
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/parents/new", method = RequestMethod.GET)
|
||||
public String initCreationForm(Map<String, Object> model) {
|
||||
Parent parent = new Parent();
|
||||
model.put("parent", parent);
|
||||
return VIEWS_PARENT_CREATE_OR_UPDATE_FORM;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/parents/new", method = RequestMethod.POST)
|
||||
public String processCreationForm(@Valid Parent parent, BindingResult result) {
|
||||
if (result.hasErrors()) {
|
||||
return VIEWS_PARENT_CREATE_OR_UPDATE_FORM;
|
||||
} else {
|
||||
this.parents.save(parent);
|
||||
return "redirect:/parent/" + parent.getId();
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/parents/find", method = RequestMethod.GET)
|
||||
public String initFindForm(Map<String, Object> model) {
|
||||
model.put("parent", new Parent());
|
||||
return "parents/findParents";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/parents", method = RequestMethod.GET)
|
||||
public String processFindForm(Parent parent, BindingResult result, Map<String, Object> model) {
|
||||
|
||||
// allow parameterless GET request for /parents to return all records
|
||||
if (parent.getLastName() == null) {
|
||||
parent.setLastName(""); // empty string signifies broadest possible search
|
||||
}
|
||||
|
||||
// find parents by last name
|
||||
Collection<Parent> results = this.parents.findByLastName(parent.getLastName());
|
||||
if (results.isEmpty()) {
|
||||
// no parents found
|
||||
result.rejectValue("lastName", "notFound", "not found");
|
||||
return "parents/findParents";
|
||||
} else if (results.size() == 1) {
|
||||
// 1 parent found
|
||||
parent = results.iterator().next();
|
||||
return "redirect:/parents/" + parent.getId();
|
||||
} else {
|
||||
// multiple parents found
|
||||
model.put("selections", results);
|
||||
return "parents/parentsList";
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/parents/{parentId}/edit", method = RequestMethod.GET)
|
||||
public String initUpdateParentForm(@PathVariable("parentId") int parentId, Model model) {
|
||||
Parent parent = this.parents.findById(parentId);
|
||||
model.addAttribute(parent);
|
||||
return VIEWS_PARENT_CREATE_OR_UPDATE_FORM;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/parents/{parentId}/edit", method = RequestMethod.POST)
|
||||
public String processUpdateParentForm(@Valid Parent parent, BindingResult result, @PathVariable("parentId") int parentId) {
|
||||
if (result.hasErrors()) {
|
||||
return VIEWS_PARENT_CREATE_OR_UPDATE_FORM;
|
||||
} else {
|
||||
parent.setId(parentId);
|
||||
this.parents.save(parent);
|
||||
return "redirect:/parents/{parentId}";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom handler for displaying an parent.
|
||||
*
|
||||
* @param parentId the ID of the parent to display
|
||||
* @return a ModelMap with the model attributes for the view
|
||||
*/
|
||||
@RequestMapping("/parents/{parentId}")
|
||||
public ModelAndView showParent(@PathVariable("parentId") int parentId) {
|
||||
ModelAndView mav = new ModelAndView("parents/parentDetails");
|
||||
mav.addObject(this.parents.findById(parentId));
|
||||
return mav;
|
||||
}
|
||||
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.samples.kidclinic.owner;
|
||||
package org.springframework.samples.kidclinic.parent;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
|
@ -23,7 +23,7 @@ import org.springframework.data.repository.query.Param;
|
|||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Repository class for <code>Owner</code> domain objects All method names are compliant with Spring Data naming
|
||||
* Repository class for <code>Parent</code> domain objects All method names are compliant with Spring Data naming
|
||||
* conventions so this interface can easily be extended for Spring Data See here: http://static.springsource.org/spring-data/jpa/docs/current/reference/html/jpa.repositories.html#jpa.query-methods.query-creation
|
||||
*
|
||||
* @author Ken Krebs
|
||||
|
@ -31,33 +31,33 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
* @author Sam Brannen
|
||||
* @author Michael Isvy
|
||||
*/
|
||||
public interface OwnerRepository extends Repository<Owner, Integer> {
|
||||
public interface ParentRepository extends Repository<Parent, Integer> {
|
||||
|
||||
/**
|
||||
* Retrieve {@link Owner}s from the data store by last name, returning all owners
|
||||
* Retrieve {@link Parent}s from the data store by last name, returning all parents
|
||||
* whose last name <i>starts</i> with the given name.
|
||||
* @param lastName Value to search for
|
||||
* @return a Collection of matching {@link Owner}s (or an empty Collection if none
|
||||
* @return a Collection of matching {@link Parent}s (or an empty Collection if none
|
||||
* found)
|
||||
*/
|
||||
@Query("SELECT DISTINCT owner FROM Owner owner left join fetch owner.pets WHERE owner.lastName LIKE :lastName%")
|
||||
@Query("SELECT DISTINCT parent FROM Parent parent left join fetch parent.kids WHERE parent.lastName LIKE :lastName%")
|
||||
@Transactional(readOnly = true)
|
||||
Collection<Owner> findByLastName(@Param("lastName") String lastName);
|
||||
Collection<Parent> findByLastName(@Param("lastName") String lastName);
|
||||
|
||||
/**
|
||||
* Retrieve an {@link Owner} from the data store by id.
|
||||
* Retrieve an {@link Parent} from the data store by id.
|
||||
* @param id the id to search for
|
||||
* @return the {@link Owner} if found
|
||||
* @return the {@link Parent} if found
|
||||
*/
|
||||
@Query("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:id")
|
||||
@Query("SELECT parent FROM Parent parent left join fetch parent.kids WHERE parent.id =:id")
|
||||
@Transactional(readOnly = true)
|
||||
Owner findById(@Param("id") Integer id);
|
||||
Parent findById(@Param("id") Integer id);
|
||||
|
||||
/**
|
||||
* Save an {@link Owner} to the data store, either inserting or updating it.
|
||||
* @param owner the {@link Owner} to save
|
||||
* Save an {@link Parent} to the data store, either inserting or updating it.
|
||||
* @param owner the {@link Parent} to save
|
||||
*/
|
||||
void save(Owner owner);
|
||||
void save(Parent parent);
|
||||
|
||||
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.samples.kidclinic.owner;
|
||||
package org.springframework.samples.kidclinic.parent;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -42,13 +42,13 @@ import org.springframework.web.bind.annotation.RequestMethod;
|
|||
class VisitController {
|
||||
|
||||
private final VisitRepository visits;
|
||||
private final PetRepository pets;
|
||||
private final KidRepository kids;
|
||||
|
||||
|
||||
@Autowired
|
||||
public VisitController(VisitRepository visits, PetRepository pets) {
|
||||
public VisitController(VisitRepository visits, KidRepository kids) {
|
||||
this.visits = visits;
|
||||
this.pets = pets;
|
||||
this.kids = kids;
|
||||
}
|
||||
|
||||
@InitBinder
|
||||
|
@ -60,35 +60,35 @@ class VisitController {
|
|||
* Called before each and every @RequestMapping annotated method.
|
||||
* 2 goals:
|
||||
* - Make sure we always have fresh data
|
||||
* - Since we do not use the session scope, make sure that Pet object always has an id
|
||||
* - Since we do not use the session scope, make sure that Kid object always has an id
|
||||
* (Even though id is not part of the form fields)
|
||||
*
|
||||
* @param petId
|
||||
* @return Pet
|
||||
* @param kidId
|
||||
* @return Kid
|
||||
*/
|
||||
@ModelAttribute("visit")
|
||||
public Visit loadPetWithVisit(@PathVariable("petId") int petId, Map<String, Object> model) {
|
||||
Pet pet = this.pets.findById(petId);
|
||||
model.put("pet", pet);
|
||||
public Visit loadKidWithVisit(@PathVariable("kidId") int kidId, Map<String, Object> model) {
|
||||
Kid kid = this.kids.findById(kidId);
|
||||
model.put("kid", kid);
|
||||
Visit visit = new Visit();
|
||||
pet.addVisit(visit);
|
||||
kid.addVisit(visit);
|
||||
return visit;
|
||||
}
|
||||
|
||||
// Spring MVC calls method loadPetWithVisit(...) before initNewVisitForm is called
|
||||
@RequestMapping(value = "/owners/*/pets/{petId}/visits/new", method = RequestMethod.GET)
|
||||
public String initNewVisitForm(@PathVariable("petId") int petId, Map<String, Object> model) {
|
||||
return "pets/createOrUpdateVisitForm";
|
||||
// Spring MVC calls method loadKidWithVisit(...) before initNewVisitForm is called
|
||||
@RequestMapping(value = "/parents/*/kids/{kidId}/visits/new", method = RequestMethod.GET)
|
||||
public String initNewVisitForm(@PathVariable("kidId") int kidId, Map<String, Object> model) {
|
||||
return "kids/createOrUpdateVisitForm";
|
||||
}
|
||||
|
||||
// Spring MVC calls method loadPetWithVisit(...) before processNewVisitForm is called
|
||||
@RequestMapping(value = "/owners/{ownerId}/pets/{petId}/visits/new", method = RequestMethod.POST)
|
||||
// Spring MVC calls method loadKidWithVisit(...) before processNewVisitForm is called
|
||||
@RequestMapping(value = "/parents/{parentId}/kids/{kidId}/visits/new", method = RequestMethod.POST)
|
||||
public String processNewVisitForm(@Valid Visit visit, BindingResult result) {
|
||||
if (result.hasErrors()) {
|
||||
return "pets/createOrUpdateVisitForm";
|
||||
return "kids/createOrUpdateVisitForm";
|
||||
} else {
|
||||
this.visits.save(visit);
|
||||
return "redirect:/owners/{ownerId}";
|
||||
return "redirect:/parents/{parentId}";
|
||||
}
|
||||
}
|
||||
|
|
@ -20,7 +20,7 @@ class CacheConfig {
|
|||
public JCacheManagerCustomizer cacheManagerCustomizer() {
|
||||
return cm -> {
|
||||
Configuration<Object, Object> cacheConfiguration = createCacheConfiguration();
|
||||
cm.createCache("vets", cacheConfiguration);
|
||||
cm.createCache("doctors", cacheConfiguration);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ import org.springframework.web.bind.annotation.RequestMethod;
|
|||
@Controller
|
||||
class CrashController {
|
||||
|
||||
@RequestMapping(value = "/oups", method = RequestMethod.GET)
|
||||
@RequestMapping(value = "/oops", method = RequestMethod.GET)
|
||||
public String triggerException() {
|
||||
throw new RuntimeException(
|
||||
"Expected: controller used to showcase what " + "happens when an exception is thrown");
|
||||
|
|
|
@ -55,8 +55,8 @@ public class Visit extends BaseEntity {
|
|||
/**
|
||||
* Holds value of property pet.
|
||||
*/
|
||||
@Column(name = "pet_id")
|
||||
private Integer petId;
|
||||
@Column(name = "kid_id")
|
||||
private Integer kidId;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -104,21 +104,21 @@ public class Visit extends BaseEntity {
|
|||
}
|
||||
|
||||
/**
|
||||
* Getter for property pet id.
|
||||
* Getter for property kid id.
|
||||
*
|
||||
* @return Value of property pet id.
|
||||
* @return Value of property kid id.
|
||||
*/
|
||||
public Integer getPetId() {
|
||||
return this.petId;
|
||||
public Integer getKidId() {
|
||||
return this.kidId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for property pet id.
|
||||
* Setter for property kid id.
|
||||
*
|
||||
* @param petId New value of property pet id.
|
||||
* @param petId New value of property kid id.
|
||||
*/
|
||||
public void setPetId(Integer petId) {
|
||||
this.petId = petId;
|
||||
public void setKidId(Integer kidId) {
|
||||
this.kidId = kidId;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -40,6 +40,6 @@ public interface VisitRepository extends Repository<Visit, Integer> {
|
|||
*/
|
||||
void save(Visit visit) throws DataAccessException;
|
||||
|
||||
List<Visit> findByPetId(Integer petId);
|
||||
List<Visit> findByKidId(Integer kidId);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,50 +1,50 @@
|
|||
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 doctors VALUES (1, 'James', 'Carter');
|
||||
INSERT INTO doctors VALUES (2, 'Helen', 'Leary');
|
||||
INSERT INTO doctors VALUES (3, 'Linda', 'Douglas');
|
||||
INSERT INTO doctors VALUES (4, 'Rafael', 'Ortega');
|
||||
INSERT INTO doctors VALUES (5, 'Henry', 'Stevens');
|
||||
INSERT INTO doctors 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 doctor_specialties VALUES (2, 1);
|
||||
INSERT INTO doctor_specialties VALUES (3, 2);
|
||||
INSERT INTO doctor_specialties VALUES (3, 3);
|
||||
INSERT INTO doctor_specialties VALUES (4, 2);
|
||||
INSERT INTO doctor_specialties VALUES (5, 1);
|
||||
|
||||
INSERT INTO types VALUES (1, 'male');
|
||||
INSERT INTO types VALUES (2, 'female');
|
||||
INSERT INTO gender VALUES (1, 'male');
|
||||
INSERT INTO gender VALUES (2, 'female');
|
||||
|
||||
|
||||
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 parents VALUES (1, 'George', 'Franklin', '110 W. Liberty St.', 'Madison', '6085551023');
|
||||
INSERT INTO parents VALUES (2, 'Betty', 'Davis', '638 Cardinal Ave.', 'Sun Prairie', '6085551749');
|
||||
INSERT INTO parents VALUES (3, 'Eduardo', 'Rodriquez', '2693 Commerce St.', 'McFarland', '6085558763');
|
||||
INSERT INTO parents VALUES (4, 'Harold', 'Davis', '563 Friendly St.', 'Windsor', '6085553198');
|
||||
INSERT INTO parents VALUES (5, 'Peter', 'McTavish', '2387 S. Fair Way', 'Madison', '6085552765');
|
||||
INSERT INTO parents VALUES (6, 'Jean', 'Coleman', '105 N. Lake St.', 'Monona', '6085552654');
|
||||
INSERT INTO parents VALUES (7, 'Jeff', 'Black', '1450 Oak Blvd.', 'Monona', '6085555387');
|
||||
INSERT INTO parents VALUES (8, 'Maria', 'Escobito', '345 Maple St.', 'Madison', '6085557683');
|
||||
INSERT INTO parents VALUES (9, 'David', 'Schroeder', '2749 Blackhawk Trail', 'Madison', '6085559435');
|
||||
INSERT INTO parents VALUES (10, 'Carlos', 'Estaban', '2335 Independence La.', 'Waunakee', '6085555487');
|
||||
|
||||
INSERT INTO pets VALUES (1, 'Alyssa', '2000-09-07', 2, 1);
|
||||
INSERT INTO pets VALUES (2, 'Joe', '2002-08-06', 1, 2);
|
||||
INSERT INTO pets VALUES (3, 'Lauren', '2001-04-17', 2, 3);
|
||||
INSERT INTO pets VALUES (4, 'Nicole', '2000-03-07', 2, 3);
|
||||
INSERT INTO pets VALUES (5, 'Thomas', '2000-11-30', 1, 4);
|
||||
INSERT INTO pets VALUES (6, 'Samantha', '2000-01-20', 2, 5);
|
||||
INSERT INTO pets VALUES (7, 'George', '1995-09-04', 1, 6);
|
||||
INSERT INTO pets VALUES (8, 'Max', '1995-09-04', 1, 6);
|
||||
INSERT INTO pets VALUES (9, 'Brendan', '1999-08-06', 1, 7);
|
||||
INSERT INTO pets VALUES (10, 'Elizabeth', '1997-02-24', 2, 8);
|
||||
INSERT INTO pets VALUES (11, 'Lucy', '2000-03-09', 2, 9);
|
||||
INSERT INTO pets VALUES (12, 'Sunny', '2000-06-24', 2, 10);
|
||||
INSERT INTO pets VALUES (13, 'Conner', '2002-06-08', 1, 10);
|
||||
INSERT INTO kids VALUES (1, 'Alyssa', '2000-09-07', 2, 1);
|
||||
INSERT INTO kids VALUES (2, 'Joe', '2002-08-06', 1, 2);
|
||||
INSERT INTO kids VALUES (3, 'Lauren', '2001-04-17', 2, 3);
|
||||
INSERT INTO kids VALUES (4, 'Nicole', '2000-03-07', 2, 3);
|
||||
INSERT INTO kids VALUES (5, 'Thomas', '2000-11-30', 1, 4);
|
||||
INSERT INTO kids VALUES (6, 'Samantha', '2000-01-20', 2, 5);
|
||||
INSERT INTO kids VALUES (7, 'George', '1995-09-04', 1, 6);
|
||||
INSERT INTO kids VALUES (8, 'Max', '1995-09-04', 1, 6);
|
||||
INSERT INTO kids VALUES (9, 'Brendan', '1999-08-06', 1, 7);
|
||||
INSERT INTO kids VALUES (10, 'Elizabeth', '1997-02-24', 2, 8);
|
||||
INSERT INTO kids VALUES (11, 'Lucy', '2000-03-09', 2, 9);
|
||||
INSERT INTO kids VALUES (12, 'Sunny', '2000-06-24', 2, 10);
|
||||
INSERT INTO kids VALUES (13, 'Conner', '2002-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');
|
||||
INSERT INTO visits VALUES (3, 8, '2013-01-03', 'cold');
|
||||
INSERT INTO visits VALUES (4, 7, '2013-01-04', 'flu');
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
DROP TABLE vet_specialties IF EXISTS;
|
||||
DROP TABLE vets IF EXISTS;
|
||||
DROP TABLE doctor_specialties IF EXISTS;
|
||||
DROP TABLE doctors 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;
|
||||
DROP TABLE kids IF EXISTS;
|
||||
DROP TABLE gender IF EXISTS;
|
||||
DROP TABLE parents IF EXISTS;
|
||||
|
||||
|
||||
CREATE TABLE vets (
|
||||
CREATE TABLE doctors (
|
||||
id INTEGER IDENTITY PRIMARY KEY,
|
||||
first_name VARCHAR(30),
|
||||
last_name VARCHAR(30)
|
||||
);
|
||||
CREATE INDEX vets_last_name ON vets (last_name);
|
||||
CREATE INDEX doctors_last_name ON doctors (last_name);
|
||||
|
||||
CREATE TABLE specialties (
|
||||
id INTEGER IDENTITY PRIMARY KEY,
|
||||
|
@ -20,20 +20,20 @@ CREATE TABLE specialties (
|
|||
);
|
||||
CREATE INDEX specialties_name ON specialties (name);
|
||||
|
||||
CREATE TABLE vet_specialties (
|
||||
vet_id INTEGER NOT NULL,
|
||||
CREATE TABLE doctor_specialties (
|
||||
doctor_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);
|
||||
ALTER TABLE doctor_specialties ADD CONSTRAINT fk_doctor_specialties_doctors FOREIGN KEY (doctor_id) REFERENCES doctors (id);
|
||||
ALTER TABLE doctor_specialties ADD CONSTRAINT fk_doctor_specialties_specialties FOREIGN KEY (specialty_id) REFERENCES specialties (id);
|
||||
|
||||
CREATE TABLE types (
|
||||
CREATE TABLE gender (
|
||||
id INTEGER IDENTITY PRIMARY KEY,
|
||||
name VARCHAR(80)
|
||||
);
|
||||
CREATE INDEX types_name ON types (name);
|
||||
CREATE INDEX gender_name ON gender (name);
|
||||
|
||||
CREATE TABLE owners (
|
||||
CREATE TABLE parents (
|
||||
id INTEGER IDENTITY PRIMARY KEY,
|
||||
first_name VARCHAR(30),
|
||||
last_name VARCHAR_IGNORECASE(30),
|
||||
|
@ -41,24 +41,24 @@ CREATE TABLE owners (
|
|||
city VARCHAR(80),
|
||||
telephone VARCHAR(20)
|
||||
);
|
||||
CREATE INDEX owners_last_name ON owners (last_name);
|
||||
CREATE INDEX parents_last_name ON parents (last_name);
|
||||
|
||||
CREATE TABLE pets (
|
||||
CREATE TABLE kids (
|
||||
id INTEGER IDENTITY PRIMARY KEY,
|
||||
name VARCHAR(30),
|
||||
birth_date DATE,
|
||||
type_id INTEGER NOT NULL,
|
||||
owner_id INTEGER NOT NULL
|
||||
parent_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);
|
||||
ALTER TABLE kids ADD CONSTRAINT fk_kids_parents FOREIGN KEY (parent_id) REFERENCES parents (id);
|
||||
ALTER TABLE kids ADD CONSTRAINT fk_kids_gender FOREIGN KEY (type_id) REFERENCES gender (id);
|
||||
CREATE INDEX kids_name ON kids (name);
|
||||
|
||||
CREATE TABLE visits (
|
||||
id INTEGER IDENTITY PRIMARY KEY,
|
||||
pet_id INTEGER NOT NULL,
|
||||
kid_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);
|
||||
ALTER TABLE visits ADD CONSTRAINT fk_visits_kids FOREIGN KEY (kid_id) REFERENCES kids (id);
|
||||
CREATE INDEX visits_kid_id ON visits (kid_id);
|
||||
|
|
28
src/main/resources/templates/doctors/doctorList.html
Normal file
28
src/main/resources/templates/doctors/doctorList.html
Normal file
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html xmlns:th="http://www.thymeleaf.org"
|
||||
th:replace="~{fragments/layout :: layout (~{::body},'doctors')}">
|
||||
|
||||
<body>
|
||||
|
||||
<h2>Pediatricians</h2>
|
||||
|
||||
<table id="doctors" class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Specialties</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr th:each="doctor : ${doctors.doctorList}">
|
||||
<td th:text="${doctor.firstName + ' ' + doctor.lastName}"></td>
|
||||
<td><span th:each="specialty : ${doctor.specialties}"
|
||||
th:text="${specialty.name + ' '}" /> <span
|
||||
th:if="${doctor.nrOfSpecialties == 0}">none</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -3,8 +3,8 @@
|
|||
<html xmlns:th="http://www.thymeleaf.org" th:replace="~{fragments/layout :: layout (~{::body},'error')}">
|
||||
|
||||
<body>
|
||||
<h2>Reviews</h2>
|
||||
<p>We are currently curating our review.</p>
|
||||
<h2>Errors</h2>
|
||||
<p th:text="${message}">Exception message</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
<link rel="shortcut icon" type="image/x-icon" th:href="@{/resources/images/favicon.png}">
|
||||
|
||||
<title>PetClinic :: a Spring Framework demonstration</title>
|
||||
<title>KidClinic :: a Spring Framework demonstration</title>
|
||||
|
||||
<!--[if lt IE 9]>
|
||||
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
|
||||
|
@ -40,11 +40,13 @@
|
|||
<a class="navbar-brand" href="#" size="5">KidClinic</a>
|
||||
<li th:class="${module == 'home' ? 'active' : ''}"><a href="#" th:href="@{/}" ><span class="glyphicon glyphicon-home"> Home</a></li>
|
||||
|
||||
<li th:classappend="${module == 'owners' ? 'active' : ''}"><a href="/owners/find" th:href="@{/owners/find}" ><span class="glyphicon glyphicon-search"> Owners</a></li>
|
||||
<li th:classappend="${module == 'parents' ? 'active' : ''}"><a href="/parents/find" th:href="@{/parents/find}" ><span class="glyphicon glyphicon-search"> Parents</a></li>
|
||||
|
||||
<li th:classappend="${module == 'vets' ? 'active' : ''}"><a href="/vets.html" th:href="@{/vets.html}"><span class="glyphicon glyphicon-th-list"> Doctors</a></li>
|
||||
<li th:classappend="${module == 'doctors' ? 'active' : ''}"><a href="/doctors.html" th:href="@{/doctors.html}"><span class="glyphicon glyphicon-th-list"> Doctors</a></li>
|
||||
|
||||
<li th:classappend="${module == 'reviews' ? 'active' : ''}"><a href="/reviews.html" th:href="@{/reviews.html}"><span class="glyphicon glyphicon-star"> Reviews</a></li>
|
||||
|
||||
<li th:classappend="${module == 'error' ? 'active' : ''}"><a href="/oups" th:href="@{/oups}" ><span class="glyphicon glyphicon-star"> Reviews</a></li>
|
||||
<li th:classappend="${module == 'error' ? 'active' : ''}"><a href="/oops" th:href="@{/oops}" ><span class="glyphicon glyphicon-warning-sign"> Errors</a></li>
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
<html xmlns:th="http://www.thymeleaf.org"
|
||||
th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
|
||||
th:replace="~{fragments/layout :: layout (~{::body},'parents')}">
|
||||
|
||||
<body>
|
||||
|
||||
<h2>
|
||||
<th:block th:if="${pet['new']}">New </th:block>
|
||||
Pet
|
||||
<th:block th:if="${kid['new']}">New </th:block>
|
||||
Kid
|
||||
</h2>
|
||||
<form th:object="${pet}" class="form-horizontal" method="post">
|
||||
<form th:object="${kid}" class="form-horizontal" method="post">
|
||||
<input type="hidden" name="id" th:value="*{id}" />
|
||||
<div class="form-group has-feedback">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label">Owner</label>
|
||||
<label class="col-sm-2 control-label">Parent</label>
|
||||
<div class="col-sm-10">
|
||||
<span th:text="${pet.owner?.firstName + ' ' + pet.owner?.lastName}" />
|
||||
<span th:text="${kid.parent?.firstName + ' ' + kid.parent?.lastName}" />
|
||||
</div>
|
||||
</div>
|
||||
<input
|
||||
|
@ -26,9 +26,9 @@
|
|||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button
|
||||
th:with="text=${owner['new']} ? 'Add Pet' : 'Update Pet'"
|
||||
th:with="text=${parent['new']} ? 'Add Kid' : 'Update Kid'"
|
||||
class="btn btn-default" type="submit" th:text="${text}">Add
|
||||
Pet</button>
|
||||
Kid</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
|
@ -1,5 +1,5 @@
|
|||
<html xmlns:th="http://www.thymeleaf.org"
|
||||
th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
|
||||
th:replace="~{fragments/layout :: layout (~{::body},'parents')}">
|
||||
|
||||
<body>
|
||||
|
||||
|
@ -8,23 +8,23 @@
|
|||
Visit
|
||||
</h2>
|
||||
|
||||
<b>Pet</b>
|
||||
<b>Kid</b>
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Birth Date</th>
|
||||
<th>Type</th>
|
||||
<th>Owner</th>
|
||||
<th>Parent</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr>
|
||||
<td th:text="${pet.name}" /></td>
|
||||
<td th:text="${kid.name}" /></td>
|
||||
<td
|
||||
th:text="${#calendars.format(pet.birthDate, 'yyyy-MM-dd')}" /></td>
|
||||
<td th:text="${pet.type}" /></td>
|
||||
th:text="${#calendars.format(kid.birthDate, 'yyyy-MM-dd')}" /></td>
|
||||
<td th:text="${kid.gender}" /></td>
|
||||
<td
|
||||
th:text="${pet.owner?.firstName + ' ' + pet.owner?.lastName}" /></td>
|
||||
th:text="${kid.parent?.firstName + ' ' + kid.parent?.lastName}" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
@ -38,7 +38,7 @@
|
|||
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<input type="hidden" name="petId" th:value="${pet.id}" />
|
||||
<input type="hidden" name="kidId" th:value="${kid.id}" />
|
||||
<button class="btn btn-default" type="submit">Add Visit</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -51,7 +51,7 @@
|
|||
<th>Date</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr th:if="${!visit['new']}" th:each="visit : ${pet.visits}">
|
||||
<tr th:if="${!visit['new']}" th:each="visit : ${kid.visits}">
|
||||
<td th:text="${#calendars.format(visit.date, 'yyyy-MM-dd')}" /></td>
|
||||
<td th:text=" ${visit.description}" /></td>
|
||||
</tr>
|
|
@ -1,10 +1,10 @@
|
|||
<html xmlns:th="http://www.thymeleaf.org"
|
||||
th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
|
||||
th:replace="~{fragments/layout :: layout (~{::body},'parents')}">
|
||||
|
||||
<body>
|
||||
|
||||
<h2>Parent</h2>
|
||||
<form th:object="${owner}" class="form-horizontal" id="add-owner-form" method="post">
|
||||
<form th:object="${parent}" class="form-horizontal" id="add-parent-form" method="post">
|
||||
<div class="form-group has-feedback">
|
||||
<input
|
||||
th:replace="~{fragments/inputField :: input ('First Name', 'firstName')}" />
|
||||
|
@ -20,7 +20,7 @@
|
|||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<button
|
||||
th:with="text=${owner['new']} ? 'Add Owner' : 'Update Owner'"
|
||||
th:with="text=${parent['new']} ? 'Add Parent' : 'Update Parent'"
|
||||
class="btn btn-default" type="submit" th:text="${text}">Add
|
||||
Parent</button>
|
||||
</div>
|
|
@ -1,12 +1,12 @@
|
|||
<html xmlns:th="http://www.thymeleaf.org"
|
||||
th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
|
||||
th:replace="~{fragments/layout :: layout (~{::body},'parents')}">
|
||||
|
||||
<body>
|
||||
|
||||
<h2>Find Parents</h2>
|
||||
|
||||
<form th:object="${owner}" th:action="@{/owners}" method="get"
|
||||
class="form-horizontal" id="search-owner-form">
|
||||
<form th:object="${parent}" th:action="@{/parents}" method="get"
|
||||
class="form-horizontal" id="search-parent-form">
|
||||
<div class="form-group">
|
||||
<div class="control-group" id="lastName">
|
||||
<label class="col-sm-2 control-label">Last name </label>
|
||||
|
@ -29,7 +29,7 @@
|
|||
</form>
|
||||
|
||||
<br />
|
||||
<a class="btn btn-default" th:href="@{/owners/new}">Add Parent</a>
|
||||
<a class="btn btn-default" th:href="@{/parents/new}">Add Parent</a>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -1,7 +1,7 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html xmlns:th="http://www.thymeleaf.org"
|
||||
th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
|
||||
th:replace="~{fragments/layout :: layout (~{::body},'parents')}">
|
||||
|
||||
<body>
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
|||
<h2>Parent Information</h2>
|
||||
|
||||
|
||||
<table class="table table-striped" th:object="${owner}">
|
||||
<table class="table table-striped" th:object="${parents}">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<td><b th:text="*{firstName + ' ' + lastName}"></b></td>
|
||||
|
@ -28,9 +28,9 @@
|
|||
</tr>
|
||||
</table>
|
||||
|
||||
<a th:href="@{{id}/edit(id=${owner.id})}" class="btn btn-default">Edit
|
||||
<a th:href="@{{id}/edit(id=${parent.id})}" class="btn btn-default">Edit
|
||||
Parent</a>
|
||||
<a th:href="@{{id}/pets/new(id=${owner.id})}" class="btn btn-default">Add
|
||||
<a th:href="@{{id}/kids/new(id=${parent.id})}" class="btn btn-default">Add
|
||||
New Child</a>
|
||||
|
||||
<br />
|
||||
|
@ -40,16 +40,16 @@
|
|||
|
||||
<table class="table table-striped">
|
||||
|
||||
<tr th:each="pet : ${owner.pets}">
|
||||
<tr th:each="kid : ${parent.kids}">
|
||||
<td valign="top">
|
||||
<dl class="dl-horizontal">
|
||||
<dt>Name</dt>
|
||||
<dd th:text="${pet.name}" /></dd>
|
||||
<dd th:text="${kid.name}" /></dd>
|
||||
<dt>Birth Date</dt>
|
||||
<dd
|
||||
th:text="${#calendars.format(pet.birthDate, 'yyyy-MM-dd')}" /></dd>
|
||||
th:text="${#calendars.format(kid.birthDate, 'yyyy-MM-dd')}" /></dd>
|
||||
<dt>Type</dt>
|
||||
<dd th:text="${pet.type}" /></dd>
|
||||
<dd th:text="${kid.gender}" /></dd>
|
||||
</dl>
|
||||
</td>
|
||||
<td valign="top">
|
||||
|
@ -60,16 +60,16 @@
|
|||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr th:each="visit : ${pet.visits}">
|
||||
<tr th:each="visit : ${kid.visits}">
|
||||
<td th:text="${#calendars.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
|
||||
th:href="@{{parentId}/kids/{kidId}/edit(parentId=${parent.id},kidId=${kid.id})}">Edit
|
||||
Child</a></td>
|
||||
<td><a
|
||||
th:href="@{{ownerId}/pets/{petId}/visits/new(ownerId=${owner.id},petId=${pet.id})}">Add
|
||||
th:href="@{{parentId}/kids/{kidId}/visits/new(parentId=${parent.id},kidId=${kid.id})}">Add
|
||||
Visit</a></td>
|
||||
</tr>
|
||||
</table>
|
|
@ -1,12 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html xmlns:th="http://www.thymeleaf.org" th:replace="~{fragments/layout :: layout (~{::body},'owners')}">
|
||||
<html xmlns:th="http://www.thymeleaf.org" th:replace="~{fragments/layout :: layout (~{::body},'parents')}">
|
||||
|
||||
<body>
|
||||
|
||||
<h2>Parents</h2>
|
||||
|
||||
<table id="vets" class="table table-striped">
|
||||
<table id="doctors" class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 150px;">Name</th>
|
||||
|
@ -17,14 +17,14 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr th:each="owner : ${selections}">
|
||||
<tr th:each="parent : ${selections}">
|
||||
<td>
|
||||
<a th:href="@{owners/__${owner.id}__}" th:text="${owner.firstName + ' ' + owner.lastName}"/></a>
|
||||
<a th:href="@{parents/__${parent.id}__}" th:text="${parent.firstName + ' ' + parent.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>
|
||||
<td th:text="${parent.address}"/>
|
||||
<td th:text="${parent.city}"/>
|
||||
<td th:text="${parent.telephone}"/>
|
||||
<td><span th:each="kid : ${parent.kids}" th:text="${kid.name} + ' '"/></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
10
src/main/resources/templates/reviews.html
Normal file
10
src/main/resources/templates/reviews.html
Normal file
|
@ -0,0 +1,10 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html xmlns:th="http://www.thymeleaf.org" th:replace="~{fragments/layout :: layout (~{::body},'reviews')}">
|
||||
|
||||
<body>
|
||||
<h2>Reviews</h2>
|
||||
<p>We are currently curating our review.</p>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,28 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html xmlns:th="http://www.thymeleaf.org"
|
||||
th:replace="~{fragments/layout :: layout (~{::body},'vets')}">
|
||||
|
||||
<body>
|
||||
|
||||
<h2>Pediatricians</h2>
|
||||
|
||||
<table id="vets" class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Specialties</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr th:each="vet : ${vets.vetList}">
|
||||
<td th:text="${vet.firstName + ' ' + vet.lastName}"></td>
|
||||
<td><span th:each="specialty : ${vet.specialties}"
|
||||
th:text="${specialty.name + ' '}" /> <span
|
||||
th:if="${vet.nrOfSpecialties == 0}">none</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in a new issue