Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • s51119/broken-petclinic
  • s72462/broken-petclinic
  • s61200/broken-petclinic
  • s76620/broken-petclinic
  • s76545/broken-petclinic
  • s76915/broken-petclinic
  • s70130/broken-petclinic
  • s72523/broken-petclinic
  • s77047/broken-petclinic
  • s70178/broken-petclinic
  • s76522/broken-petclinic
  • s76426/broken-petclinic
  • s76863/broken-petclinic
  • s76856/broken-petclinic
  • s76728/broken-petclinic
  • williamreetz/broken-petclinic
  • s77034/broken-petclinic
  • s76400/broken-petclinic
  • s72288/broken-petclinic
  • s76608/broken-petclinic
20 results
Show changes
Showing
with 267 additions and 766 deletions
/* /*
* Copyright 2002-2013 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
......
/* /*
* Copyright 2002-2013 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
...@@ -17,8 +17,7 @@ package org.springframework.samples.petclinic.model; ...@@ -17,8 +17,7 @@ package org.springframework.samples.petclinic.model;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.MappedSuperclass; import javax.persistence.MappedSuperclass;
import javax.validation.constraints.NotEmpty;
import org.hibernate.validator.constraints.NotEmpty;
/** /**
* Simple JavaBean domain object representing an person. * Simple JavaBean domain object representing an person.
...@@ -30,11 +29,11 @@ public class Person extends BaseEntity { ...@@ -30,11 +29,11 @@ public class Person extends BaseEntity {
@Column(name = "first_name") @Column(name = "first_name")
@NotEmpty @NotEmpty
protected String firstName; private String firstName;
@Column(name = "last_name") @Column(name = "last_name")
@NotEmpty @NotEmpty
protected String lastName; private String lastName;
public String getFirstName() { public String getFirstName() {
return this.firstName; return this.firstName;
...@@ -52,5 +51,4 @@ public class Person extends BaseEntity { ...@@ -52,5 +51,4 @@ public class Person extends BaseEntity {
this.lastName = lastName; this.lastName = lastName;
} }
} }
/** /*
* The classes in this package represent PetClinic's business layer. * Copyright 2012-2019 the original author or authors.
*/ *
package org.springframework.samples.petclinic.model; * 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.
*/
/**
* The classes in this package represent utilities used by the domain.
*/
package org.springframework.samples.petclinic.model;
/* /*
* Copyright 2002-2013 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.model; package org.springframework.samples.petclinic.owner;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
...@@ -27,11 +27,12 @@ import javax.persistence.Entity; ...@@ -27,11 +27,12 @@ import javax.persistence.Entity;
import javax.persistence.OneToMany; import javax.persistence.OneToMany;
import javax.persistence.Table; import javax.persistence.Table;
import javax.validation.constraints.Digits; import javax.validation.constraints.Digits;
import javax.validation.constraints.NotEmpty;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.beans.support.MutableSortDefinition; import org.springframework.beans.support.MutableSortDefinition;
import org.springframework.beans.support.PropertyComparator; import org.springframework.beans.support.PropertyComparator;
import org.springframework.core.style.ToStringCreator; import org.springframework.core.style.ToStringCreator;
import org.springframework.samples.petclinic.model.Person;
/** /**
* Simple JavaBean domain object representing an owner. * Simple JavaBean domain object representing an owner.
...@@ -60,7 +61,6 @@ public class Owner extends Person { ...@@ -60,7 +61,6 @@ public class Owner extends Person {
@OneToMany(cascade = CascadeType.ALL, mappedBy = "owner") @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner")
private Set<Pet> pets; private Set<Pet> pets;
public String getAddress() { public String getAddress() {
return this.address; return this.address;
} }
...@@ -98,12 +98,15 @@ public class Owner extends Person { ...@@ -98,12 +98,15 @@ public class Owner extends Person {
public List<Pet> getPets() { public List<Pet> getPets() {
List<Pet> sortedPets = new ArrayList<>(getPetsInternal()); List<Pet> sortedPets = new ArrayList<>(getPetsInternal());
PropertyComparator.sort(sortedPets, new MutableSortDefinition("name", true, true)); PropertyComparator.sort(sortedPets,
new MutableSortDefinition("name", true, true));
return Collections.unmodifiableList(sortedPets); return Collections.unmodifiableList(sortedPets);
} }
public void addPet(Pet pet) { public void addPet(Pet pet) {
getPetsInternal().add(pet); if (pet.isNew()) {
getPetsInternal().add(pet);
}
pet.setOwner(this); pet.setOwner(this);
} }
...@@ -141,13 +144,9 @@ public class Owner extends Person { ...@@ -141,13 +144,9 @@ public class Owner extends Person {
public String toString() { public String toString() {
return new ToStringCreator(this) return new ToStringCreator(this)
.append("id", this.getId()) .append("id", this.getId()).append("new", this.isNew())
.append("new", this.isNew()) .append("lastName", this.getLastName())
.append("lastName", this.getLastName()) .append("firstName", this.getFirstName()).append("address", this.address)
.append("firstName", this.getFirstName()) .append("city", this.city).append("telephone", this.telephone).toString();
.append("address", this.address)
.append("city", this.city)
.append("telephone", this.telephone)
.toString();
} }
} }
/* /*
* Copyright 2002-2013 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
...@@ -13,26 +13,22 @@ ...@@ -13,26 +13,22 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.web; package org.springframework.samples.petclinic.owner;
import java.util.Collection;
import java.util.Map;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.samples.petclinic.model.Owner;
import org.springframework.samples.petclinic.service.ClinicService;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.validation.BindingResult; import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.ModelAndView;
import javax.validation.Valid;
import java.util.Collection;
import java.util.Map;
/** /**
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Ken Krebs * @author Ken Krebs
...@@ -40,15 +36,14 @@ import org.springframework.web.servlet.ModelAndView; ...@@ -40,15 +36,14 @@ import org.springframework.web.servlet.ModelAndView;
* @author Michael Isvy * @author Michael Isvy
*/ */
@Controller @Controller
public class OwnerController { class OwnerController {
private static final String VIEWS_OWNER_CREATE_OR_UPDATE_FORM = "owners/createOrUpdateOwnerForm"; private static final String VIEWS_OWNER_CREATE_OR_UPDATE_FORM = "owners/createOrUpdateOwnerForm";
private final ClinicService clinicService; private final OwnerRepository owners;
@Autowired public OwnerController(OwnerRepository clinicService) {
public OwnerController(ClinicService clinicService) { this.owners = clinicService;
this.clinicService = clinicService;
} }
@InitBinder @InitBinder
...@@ -56,30 +51,30 @@ public class OwnerController { ...@@ -56,30 +51,30 @@ public class OwnerController {
dataBinder.setDisallowedFields("id"); dataBinder.setDisallowedFields("id");
} }
@RequestMapping(value = "/owners/new", method = RequestMethod.GET) @GetMapping("/owners/new")
public String initCreationForm(Map<String, Object> model) { public String initCreationForm(Map<String, Object> model) {
Owner owner = new Owner(); Owner owner = new Owner();
model.put("owner", owner); model.put("owner", owner);
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM; return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
} }
@RequestMapping(value = "/owners/new", method = RequestMethod.POST) @PostMapping("/owners/new")
public String processCreationForm(@Valid Owner owner, BindingResult result) { public String processCreationForm(@Valid Owner owner, BindingResult result) {
if (result.hasErrors()) { if (result.hasErrors()) {
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM; return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
} else { } else {
this.clinicService.saveOwner(owner); this.owners.save(owner);
return "redirect:/owners/" + owner.getId(); return "redirect:/owners/" + owner.getId();
} }
} }
@RequestMapping(value = "/owners/find", method = RequestMethod.GET) @GetMapping("/owners/find")
public String initFindForm(Map<String, Object> model) { public String initFindForm(Map<String, Object> model) {
model.put("owner", new Owner()); model.put("owner", new Owner());
return "owners/findOwners"; return "owners/findOwners";
} }
@RequestMapping(value = "/owners", method = RequestMethod.GET) @GetMapping("/owners")
public String processFindForm(Owner owner, BindingResult result, Map<String, Object> model) { public String processFindForm(Owner owner, BindingResult result, Map<String, Object> model) {
// allow parameterless GET request for /owners to return all records // allow parameterless GET request for /owners to return all records
...@@ -88,7 +83,7 @@ public class OwnerController { ...@@ -88,7 +83,7 @@ public class OwnerController {
} }
// find owners by last name // find owners by last name
Collection<Owner> results = this.clinicService.findOwnerByLastName(owner.getLastName()); Collection<Owner> results = this.owners.findByLastName(owner.getLastName());
if (results.isEmpty()) { if (results.isEmpty()) {
// no owners found // no owners found
result.rejectValue("lastName", "notFound", "not found"); result.rejectValue("lastName", "notFound", "not found");
...@@ -104,20 +99,20 @@ public class OwnerController { ...@@ -104,20 +99,20 @@ public class OwnerController {
} }
} }
@RequestMapping(value = "/owners/{ownerId}/edit", method = RequestMethod.GET) @GetMapping("/owners/{ownerId}/edit")
public String initUpdateOwnerForm(@PathVariable("ownerId") int ownerId, Model model) { public String initUpdateOwnerForm(@PathVariable("ownerId") int ownerId, Model model) {
Owner owner = this.clinicService.findOwnerById(ownerId); Owner owner = this.owners.findById(ownerId);
model.addAttribute(owner); model.addAttribute(owner);
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM; return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
} }
@RequestMapping(value = "/owners/{ownerId}/edit", method = RequestMethod.POST) @PostMapping("/owners/{ownerId}/edit")
public String processUpdateOwnerForm(@Valid Owner owner, BindingResult result, @PathVariable("ownerId") int ownerId) { public String processUpdateOwnerForm(@Valid Owner owner, BindingResult result, @PathVariable("ownerId") int ownerId) {
if (result.hasErrors()) { if (result.hasErrors()) {
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM; return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
} else { } else {
owner.setId(ownerId); owner.setId(ownerId);
this.clinicService.saveOwner(owner); this.owners.save(owner);
return "redirect:/owners/{ownerId}"; return "redirect:/owners/{ownerId}";
} }
} }
...@@ -128,10 +123,10 @@ public class OwnerController { ...@@ -128,10 +123,10 @@ public class OwnerController {
* @param ownerId the ID of the owner to display * @param ownerId the ID of the owner to display
* @return a ModelMap with the model attributes for the view * @return a ModelMap with the model attributes for the view
*/ */
@RequestMapping("/owners/{ownerId}") @GetMapping("/owners/{ownerId}")
public ModelAndView showOwner(@PathVariable("ownerId") int ownerId) { public ModelAndView showOwner(@PathVariable("ownerId") int ownerId) {
ModelAndView mav = new ModelAndView("owners/ownerDetails"); ModelAndView mav = new ModelAndView("owners/ownerDetails");
mav.addObject(this.clinicService.findOwnerById(ownerId)); mav.addObject(this.owners.findById(ownerId));
return mav; return mav;
} }
......
/* /*
* Copyright 2002-2013 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
...@@ -13,52 +13,52 @@ ...@@ -13,52 +13,52 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.repository; package org.springframework.samples.petclinic.owner;
import java.util.Collection; import java.util.Collection;
import org.springframework.dao.DataAccessException; import org.springframework.data.jpa.repository.Query;
import org.springframework.samples.petclinic.model.BaseEntity; import org.springframework.data.repository.Repository;
import org.springframework.samples.petclinic.model.Owner; 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>Owner</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 * conventions so this interface can easily be extended for Spring Data.
* See: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation
* *
* @author Ken Krebs * @author Ken Krebs
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Sam Brannen * @author Sam Brannen
* @author Michael Isvy * @author Michael Isvy
*/ */
public interface OwnerRepository { public interface OwnerRepository extends Repository<Owner, Integer> {
/** /**
* Retrieve <code>Owner</code>s from the data store by last name, returning all owners whose last name <i>starts</i> * Retrieve {@link Owner}s from the data store by last name, returning all owners
* with the given name. * whose last name <i>starts</i> with the given name.
*
* @param lastName Value to search for * @param lastName Value to search for
* @return a <code>Collection</code> of matching <code>Owner</code>s (or an empty <code>Collection</code> if none * @return a Collection of matching {@link Owner}s (or an empty Collection if none
* found) * found)
*/ */
Collection<Owner> findByLastName(String lastName) throws DataAccessException; @Query("SELECT DISTINCT owner FROM Owner owner left join fetch owner.pets WHERE owner.lastName LIKE :lastName%")
@Transactional(readOnly = true)
Collection<Owner> findByLastName(@Param("lastName") String lastName);
/** /**
* Retrieve an <code>Owner</code> from the data store by id. * Retrieve an {@link Owner} from the data store by id.
*
* @param id the id to search for * @param id the id to search for
* @return the <code>Owner</code> if found * @return the {@link Owner} if found
* @throws org.springframework.dao.DataRetrievalFailureException if not found
*/ */
Owner findById(int id) throws DataAccessException; @Query("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:id")
@Transactional(readOnly = true)
Owner findById(@Param("id") Integer id);
/** /**
* Save an <code>Owner</code> to the data store, either inserting or updating it. * Save an {@link Owner} to the data store, either inserting or updating it.
* * @param owner the {@link Owner} to save
* @param owner the <code>Owner</code> to save
* @see BaseEntity#isNew
*/ */
void save(Owner owner) throws DataAccessException; void save(Owner owner);
} }
/* /*
* Copyright 2002-2013 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
...@@ -13,11 +13,13 @@ ...@@ -13,11 +13,13 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.model; package org.springframework.samples.petclinic.owner;
import java.time.LocalDate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
...@@ -30,12 +32,11 @@ import javax.persistence.ManyToOne; ...@@ -30,12 +32,11 @@ import javax.persistence.ManyToOne;
import javax.persistence.OneToMany; import javax.persistence.OneToMany;
import javax.persistence.Table; import javax.persistence.Table;
import org.hibernate.annotations.Type;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.springframework.beans.support.MutableSortDefinition; import org.springframework.beans.support.MutableSortDefinition;
import org.springframework.beans.support.PropertyComparator; import org.springframework.beans.support.PropertyComparator;
import org.springframework.format.annotation.DateTimeFormat; import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.samples.petclinic.model.NamedEntity;
import org.springframework.samples.petclinic.visit.Visit;
/** /**
* Simple business object representing a pet. * Simple business object representing a pet.
...@@ -49,8 +50,7 @@ import org.springframework.format.annotation.DateTimeFormat; ...@@ -49,8 +50,7 @@ import org.springframework.format.annotation.DateTimeFormat;
public class Pet extends NamedEntity { public class Pet extends NamedEntity {
@Column(name = "birth_date") @Column(name = "birth_date")
@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDate") @DateTimeFormat(pattern = "yyyy-MM-dd")
@DateTimeFormat(pattern = "yyyy/MM/dd")
private LocalDate birthDate; private LocalDate birthDate;
@ManyToOne @ManyToOne
...@@ -61,17 +61,17 @@ public class Pet extends NamedEntity { ...@@ -61,17 +61,17 @@ public class Pet extends NamedEntity {
@JoinColumn(name = "owner_id") @JoinColumn(name = "owner_id")
private Owner owner; private Owner owner;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "pet", fetch = FetchType.EAGER) @OneToMany(cascade = CascadeType.ALL, mappedBy = "petId", fetch = FetchType.EAGER)
private Set<Visit> visits; private Set<Visit> visits = new LinkedHashSet<>();
public LocalDate getBirthDate() {
return this.birthDate;
}
public void setBirthDate(LocalDate birthDate) { public void setBirthDate(LocalDate birthDate) {
this.birthDate = birthDate; this.birthDate = birthDate;
} }
public LocalDate getBirthDate() {
return this.birthDate;
}
public PetType getType() { public PetType getType() {
return this.type; return this.type;
} }
...@@ -101,13 +101,14 @@ public class Pet extends NamedEntity { ...@@ -101,13 +101,14 @@ public class Pet extends NamedEntity {
public List<Visit> getVisits() { public List<Visit> getVisits() {
List<Visit> sortedVisits = new ArrayList<>(getVisitsInternal()); List<Visit> sortedVisits = new ArrayList<>(getVisitsInternal());
PropertyComparator.sort(sortedVisits, new MutableSortDefinition("date", false, false)); PropertyComparator.sort(sortedVisits,
new MutableSortDefinition("date", false, false));
return Collections.unmodifiableList(sortedVisits); return Collections.unmodifiableList(sortedVisits);
} }
public void addVisit(Visit visit) { public void addVisit(Visit visit) {
getVisitsInternal().add(visit); getVisitsInternal().add(visit);
visit.setPet(this); visit.setPetId(this.getId());
} }
} }
/* /*
* Copyright 2002-2013 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
...@@ -13,13 +13,8 @@ ...@@ -13,13 +13,8 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.web; package org.springframework.samples.petclinic.owner;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.samples.petclinic.model.Owner;
import org.springframework.samples.petclinic.model.Pet;
import org.springframework.samples.petclinic.model.PetType;
import org.springframework.samples.petclinic.service.ClinicService;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap; import org.springframework.ui.ModelMap;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
...@@ -28,7 +23,6 @@ import org.springframework.web.bind.WebDataBinder; ...@@ -28,7 +23,6 @@ import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.Collection; import java.util.Collection;
/** /**
...@@ -38,24 +32,25 @@ import java.util.Collection; ...@@ -38,24 +32,25 @@ import java.util.Collection;
*/ */
@Controller @Controller
@RequestMapping("/owners/{ownerId}") @RequestMapping("/owners/{ownerId}")
public class PetController { class PetController {
private static final String VIEWS_PETS_CREATE_OR_UPDATE_FORM = "pets/createOrUpdatePetForm"; private static final String VIEWS_PETS_CREATE_OR_UPDATE_FORM = "pets/createOrUpdatePetForm";
private final ClinicService clinicService; private final PetRepository pets;
private final OwnerRepository owners;
@Autowired public PetController(PetRepository pets, OwnerRepository owners) {
public PetController(ClinicService clinicService) { this.pets = pets;
this.clinicService = clinicService; this.owners = owners;
} }
@ModelAttribute("types") @ModelAttribute("types")
public Collection<PetType> populatePetTypes() { public Collection<PetType> populatePetTypes() {
return this.clinicService.findPetTypes(); return this.pets.findPetTypes();
} }
@ModelAttribute("owner") @ModelAttribute("owner")
public Owner findOwner(@PathVariable("ownerId") int ownerId) { public Owner findOwner(@PathVariable("ownerId") int ownerId) {
return this.clinicService.findOwnerById(ownerId); return this.owners.findById(ownerId);
} }
@InitBinder("owner") @InitBinder("owner")
...@@ -68,7 +63,7 @@ public class PetController { ...@@ -68,7 +63,7 @@ public class PetController {
dataBinder.setValidator(new PetValidator()); dataBinder.setValidator(new PetValidator());
} }
@RequestMapping(value = "/pets/new", method = RequestMethod.GET) @GetMapping("/pets/new")
public String initCreationForm(Owner owner, ModelMap model) { public String initCreationForm(Owner owner, ModelMap model) {
Pet pet = new Pet(); Pet pet = new Pet();
owner.addPet(pet); owner.addPet(pet);
...@@ -76,36 +71,37 @@ public class PetController { ...@@ -76,36 +71,37 @@ public class PetController {
return VIEWS_PETS_CREATE_OR_UPDATE_FORM; return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
} }
@RequestMapping(value = "/pets/new", method = RequestMethod.POST) @PostMapping("/pets/new")
public String processCreationForm(Owner owner, @Valid Pet pet, BindingResult result, ModelMap model) { 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){ if (StringUtils.hasLength(pet.getName()) && pet.isNew() && owner.getPet(pet.getName(), true) != null){
result.rejectValue("name", "duplicate", "already exists"); result.rejectValue("name", "duplicate", "already exists");
} }
owner.addPet(pet);
if (result.hasErrors()) { if (result.hasErrors()) {
model.put("pet", pet); model.put("pet", pet);
return VIEWS_PETS_CREATE_OR_UPDATE_FORM; return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
} else { } else {
owner.addPet(pet); this.pets.save(pet);
this.clinicService.savePet(pet);
return "redirect:/owners/{ownerId}"; return "redirect:/owners/{ownerId}";
} }
} }
@RequestMapping(value = "/pets/{petId}/edit", method = RequestMethod.GET) @GetMapping("/pets/{petId}/edit")
public String initUpdateForm(@PathVariable("petId") int petId, ModelMap model) { public String initUpdateForm(@PathVariable("petId") int petId, ModelMap model) {
Pet pet = this.clinicService.findPetById(petId); Pet pet = this.pets.findById(petId);
model.put("pet", pet); model.put("pet", pet);
return VIEWS_PETS_CREATE_OR_UPDATE_FORM; return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
} }
@RequestMapping(value = "/pets/{petId}/edit", method = RequestMethod.POST) @PostMapping("/pets/{petId}/edit")
public String processUpdateForm(@Valid Pet pet, BindingResult result, Owner owner, ModelMap model) { public String processUpdateForm(@Valid Pet pet, BindingResult result, Owner owner, ModelMap model) {
if (result.hasErrors()) { if (result.hasErrors()) {
pet.setOwner(owner);
model.put("pet", pet); model.put("pet", pet);
return VIEWS_PETS_CREATE_OR_UPDATE_FORM; return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
} else { } else {
owner.addPet(pet); owner.addPet(pet);
this.clinicService.savePet(pet); this.pets.save(pet);
return "redirect:/owners/{ownerId}"; return "redirect:/owners/{ownerId}";
} }
} }
......
/* /*
* Copyright 2002-2013 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
...@@ -13,48 +13,47 @@ ...@@ -13,48 +13,47 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.repository; package org.springframework.samples.petclinic.owner;
import java.util.List; import java.util.List;
import org.springframework.dao.DataAccessException; import org.springframework.data.jpa.repository.Query;
import org.springframework.samples.petclinic.model.BaseEntity; import org.springframework.data.repository.Repository;
import org.springframework.samples.petclinic.model.Pet; import org.springframework.transaction.annotation.Transactional;
import org.springframework.samples.petclinic.model.PetType;
/** /**
* Repository class for <code>Pet</code> domain objects All method names are compliant with Spring Data naming * Repository class for <code>Pet</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 * conventions so this interface can easily be extended for Spring Data.
* See: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation
* *
* @author Ken Krebs * @author Ken Krebs
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Sam Brannen * @author Sam Brannen
* @author Michael Isvy * @author Michael Isvy
*/ */
public interface PetRepository { public interface PetRepository extends Repository<Pet, Integer> {
/** /**
* Retrieve all <code>PetType</code>s from the data store. * Retrieve all {@link PetType}s from the data store.
* * @return a Collection of {@link PetType}s.
* @return a <code>Collection</code> of <code>PetType</code>s
*/ */
List<PetType> findPetTypes() throws DataAccessException; @Query("SELECT ptype FROM PetType ptype ORDER BY ptype.name")
@Transactional(readOnly = true)
List<PetType> findPetTypes();
/** /**
* Retrieve a <code>Pet</code> from the data store by id. * Retrieve a {@link Pet} from the data store by id.
*
* @param id the id to search for * @param id the id to search for
* @return the <code>Pet</code> if found * @return the {@link Pet} if found
* @throws org.springframework.dao.DataRetrievalFailureException if not found
*/ */
Pet findById(int id) throws DataAccessException; @Transactional(readOnly = true)
Pet findById(Integer id);
/** /**
* Save a <code>Pet</code> to the data store, either inserting or updating it. * Save a {@link Pet} to the data store, either inserting or updating it.
* * @param pet the {@link Pet} to save
* @param pet the <code>Pet</code> to save
* @see BaseEntity#isNew
*/ */
void save(Pet pet) throws DataAccessException; void save(Pet pet);
} }
/* /*
* Copyright 2002-2013 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
...@@ -13,11 +13,13 @@ ...@@ -13,11 +13,13 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.model; package org.springframework.samples.petclinic.owner;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.Table; import javax.persistence.Table;
import org.springframework.samples.petclinic.model.NamedEntity;
/** /**
* @author Juergen Hoeller * @author Juergen Hoeller
* Can be Cat, Dog, Hamster... * Can be Cat, Dog, Hamster...
......
/* /*
* Copyright 2002-2013 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
...@@ -13,8 +13,7 @@ ...@@ -13,8 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.web; package org.springframework.samples.petclinic.owner;
import java.text.ParseException; import java.text.ParseException;
import java.util.Collection; import java.util.Collection;
...@@ -22,29 +21,26 @@ import java.util.Locale; ...@@ -22,29 +21,26 @@ import java.util.Locale;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.Formatter; import org.springframework.format.Formatter;
import org.springframework.samples.petclinic.model.PetType; import org.springframework.stereotype.Component;
import org.springframework.samples.petclinic.service.ClinicService;
/** /**
* Instructs Spring MVC on how to parse and print elements of type 'PetType'. Starting from Spring 3.0, Formatters have * 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 * 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 * Spring ref doc: https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#format
* - A nice blog entry from Gordon Dickens: http://gordondickens.com/wordpress/2010/09/30/using-spring-3-0-custom-type-converter/
* <p/>
* Also see how the bean 'conversionService' has been declared inside /WEB-INF/mvc-core-config.xml
* *
* @author Mark Fisher * @author Mark Fisher
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Michael Isvy * @author Michael Isvy
*/ */
@Component
public class PetTypeFormatter implements Formatter<PetType> { public class PetTypeFormatter implements Formatter<PetType> {
private final ClinicService clinicService; private final PetRepository pets;
@Autowired @Autowired
public PetTypeFormatter(ClinicService clinicService) { public PetTypeFormatter(PetRepository pets) {
this.clinicService = clinicService; this.pets = pets;
} }
@Override @Override
...@@ -54,7 +50,7 @@ public class PetTypeFormatter implements Formatter<PetType> { ...@@ -54,7 +50,7 @@ public class PetTypeFormatter implements Formatter<PetType> {
@Override @Override
public PetType parse(String text, Locale locale) throws ParseException { public PetType parse(String text, Locale locale) throws ParseException {
Collection<PetType> findPetTypes = this.clinicService.findPetTypes(); Collection<PetType> findPetTypes = this.pets.findPetTypes();
for (PetType type : findPetTypes) { for (PetType type : findPetTypes) {
if (type.getName().equals(text)) { if (type.getName().equals(text)) {
return type; return type;
......
/* /*
* Copyright 2002-2013 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
...@@ -13,9 +13,8 @@ ...@@ -13,9 +13,8 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.web; package org.springframework.samples.petclinic.owner;
import org.springframework.samples.petclinic.model.Pet;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.validation.Errors; import org.springframework.validation.Errors;
import org.springframework.validation.Validator; import org.springframework.validation.Validator;
......
/* /*
* Copyright 2002-2013 the original author or authors. * Copyright 2012-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * https://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
...@@ -13,40 +13,35 @@ ...@@ -13,40 +13,35 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.samples.petclinic.web; package org.springframework.samples.petclinic.owner;
import java.util.Map; import org.springframework.samples.petclinic.visit.Visit;
import org.springframework.samples.petclinic.visit.VisitRepository;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.samples.petclinic.model.Pet;
import org.springframework.samples.petclinic.model.Visit;
import org.springframework.samples.petclinic.service.ClinicService;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult; import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable; import javax.validation.Valid;
import org.springframework.web.bind.annotation.RequestMapping; import java.util.Map;
import org.springframework.web.bind.annotation.RequestMethod;
/** /**
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Ken Krebs * @author Ken Krebs
* @author Arjen Poutsma * @author Arjen Poutsma
* @author Michael Isvy * @author Michael Isvy
* @author Dave Syer
*/ */
@Controller @Controller
public class VisitController { class VisitController {
private final ClinicService clinicService; private final VisitRepository visits;
private final PetRepository pets;
@Autowired public VisitController(VisitRepository visits, PetRepository pets) {
public VisitController(ClinicService clinicService) { this.visits = visits;
this.clinicService = clinicService; this.pets = pets;
} }
@InitBinder @InitBinder
...@@ -65,34 +60,29 @@ public class VisitController { ...@@ -65,34 +60,29 @@ public class VisitController {
* @return Pet * @return Pet
*/ */
@ModelAttribute("visit") @ModelAttribute("visit")
public Visit loadPetWithVisit(@PathVariable("petId") int petId) { public Visit loadPetWithVisit(@PathVariable("petId") int petId, Map<String, Object> model) {
Pet pet = this.clinicService.findPetById(petId); Pet pet = this.pets.findById(petId);
model.put("pet", pet);
Visit visit = new Visit(); Visit visit = new Visit();
pet.addVisit(visit); pet.addVisit(visit);
return visit; return visit;
} }
// Spring MVC calls method loadPetWithVisit(...) before initNewVisitForm is called // Spring MVC calls method loadPetWithVisit(...) before initNewVisitForm is called
@RequestMapping(value = "/owners/*/pets/{petId}/visits/new", method = RequestMethod.GET) @GetMapping("/owners/*/pets/{petId}/visits/new")
public String initNewVisitForm(@PathVariable("petId") int petId, Map<String, Object> model) { public String initNewVisitForm(@PathVariable("petId") int petId, Map<String, Object> model) {
return "pets/createOrUpdateVisitForm"; return "pets/createOrUpdateVisitForm";
} }
// Spring MVC calls method loadPetWithVisit(...) before processNewVisitForm is called // Spring MVC calls method loadPetWithVisit(...) before processNewVisitForm is called
@RequestMapping(value = "/owners/{ownerId}/pets/{petId}/visits/new", method = RequestMethod.POST) @PostMapping("/owners/{ownerId}/pets/{petId}/visits/new")
public String processNewVisitForm(@Valid Visit visit, BindingResult result) { public String processNewVisitForm(@Valid Visit visit, BindingResult result) {
if (result.hasErrors()) { if (result.hasErrors()) {
return "pets/createOrUpdateVisitForm"; return "pets/createOrUpdateVisitForm";
} else { } else {
this.clinicService.saveVisit(visit); this.visits.save(visit);
return "redirect:/owners/{ownerId}"; return "redirect:/owners/{ownerId}";
} }
} }
@RequestMapping(value = "/owners/*/pets/{petId}/visits", method = RequestMethod.GET)
public String showVisits(@PathVariable int petId, Map<String, Object> model) {
model.put("visits", this.clinicService.findPetById(petId).getVisits());
return "visitList";
}
} }
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.samples.petclinic.repository.jdbc;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.orm.ObjectRetrievalFailureException;
import org.springframework.samples.petclinic.model.Owner;
import org.springframework.samples.petclinic.model.Pet;
import org.springframework.samples.petclinic.model.PetType;
import org.springframework.samples.petclinic.model.Visit;
import org.springframework.samples.petclinic.repository.OwnerRepository;
import org.springframework.samples.petclinic.util.EntityUtils;
import org.springframework.stereotype.Repository;
/**
* A simple JDBC-based implementation of the {@link OwnerRepository} interface.
*
* @author Ken Krebs
* @author Juergen Hoeller
* @author Rob Harrop
* @author Sam Brannen
* @author Thomas Risberg
* @author Mark Fisher
*/
@Repository
public class JdbcOwnerRepositoryImpl implements OwnerRepository {
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
private SimpleJdbcInsert insertOwner;
@Autowired
public JdbcOwnerRepositoryImpl(DataSource dataSource, NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
this.insertOwner = new SimpleJdbcInsert(dataSource)
.withTableName("owners")
.usingGeneratedKeyColumns("id");
this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
}
/**
* Loads {@link Owner Owners} from the data store by last name, returning all owners whose last name <i>starts</i> with
* the given name; also loads the {@link Pet Pets} and {@link Visit Visits} for the corresponding owners, if not
* already loaded.
*/
@Override
public Collection<Owner> findByLastName(String lastName) throws DataAccessException {
Map<String, Object> params = new HashMap<>();
params.put("lastName", lastName + "%");
List<Owner> owners = this.namedParameterJdbcTemplate.query(
"SELECT id, first_name, last_name, address, city, telephone FROM owners WHERE last_name like :lastName",
params,
BeanPropertyRowMapper.newInstance(Owner.class)
);
loadOwnersPetsAndVisits(owners);
return owners;
}
/**
* Loads the {@link Owner} with the supplied <code>id</code>; also loads the {@link Pet Pets} and {@link Visit Visits}
* for the corresponding owner, if not already loaded.
*/
@Override
public Owner findById(int id) throws DataAccessException {
Owner owner;
try {
Map<String, Object> params = new HashMap<>();
params.put("id", id);
owner = this.namedParameterJdbcTemplate.queryForObject(
"SELECT id, first_name, last_name, address, city, telephone FROM owners WHERE id= :id",
params,
BeanPropertyRowMapper.newInstance(Owner.class)
);
} catch (EmptyResultDataAccessException ex) {
throw new ObjectRetrievalFailureException(Owner.class, id);
}
loadPetsAndVisits(owner);
return owner;
}
public void loadPetsAndVisits(final Owner owner) {
Map<String, Object> params = new HashMap<>();
params.put("id", owner.getId());
final List<JdbcPet> pets = this.namedParameterJdbcTemplate.query(
"SELECT pets.id, name, birth_date, type_id, owner_id, visits.id as visit_id, visit_date, description, pet_id FROM pets LEFT OUTER JOIN visits ON pets.id = pet_id WHERE owner_id=:id",
params,
new JdbcPetVisitExtractor()
);
Collection<PetType> petTypes = getPetTypes();
for (JdbcPet pet : pets) {
pet.setType(EntityUtils.getById(petTypes, PetType.class, pet.getTypeId()));
owner.addPet(pet);
}
}
@Override
public void save(Owner owner) throws DataAccessException {
BeanPropertySqlParameterSource parameterSource = new BeanPropertySqlParameterSource(owner);
if (owner.isNew()) {
Number newKey = this.insertOwner.executeAndReturnKey(parameterSource);
owner.setId(newKey.intValue());
} else {
this.namedParameterJdbcTemplate.update(
"UPDATE owners SET first_name=:firstName, last_name=:lastName, address=:address, " +
"city=:city, telephone=:telephone WHERE id=:id",
parameterSource);
}
}
public Collection<PetType> getPetTypes() throws DataAccessException {
return this.namedParameterJdbcTemplate.query(
"SELECT id, name FROM types ORDER BY name", new HashMap<String, Object>(),
BeanPropertyRowMapper.newInstance(PetType.class));
}
/**
* Loads the {@link Pet} and {@link Visit} data for the supplied {@link List} of {@link Owner Owners}.
*
* @param owners the list of owners for whom the pet and visit data should be loaded
* @see #loadPetsAndVisits(Owner)
*/
private void loadOwnersPetsAndVisits(List<Owner> owners) {
for (Owner owner : owners) {
loadPetsAndVisits(owner);
}
}
}
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.samples.petclinic.repository.jdbc;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.orm.ObjectRetrievalFailureException;
import org.springframework.samples.petclinic.model.Owner;
import org.springframework.samples.petclinic.model.Pet;
import org.springframework.samples.petclinic.model.PetType;
import org.springframework.samples.petclinic.model.Visit;
import org.springframework.samples.petclinic.repository.OwnerRepository;
import org.springframework.samples.petclinic.repository.PetRepository;
import org.springframework.samples.petclinic.repository.VisitRepository;
import org.springframework.samples.petclinic.util.EntityUtils;
import org.springframework.stereotype.Repository;
/**
* @author Ken Krebs
* @author Juergen Hoeller
* @author Rob Harrop
* @author Sam Brannen
* @author Thomas Risberg
* @author Mark Fisher
*/
@Repository
public class JdbcPetRepositoryImpl implements PetRepository {
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
private SimpleJdbcInsert insertPet;
private OwnerRepository ownerRepository;
private VisitRepository visitRepository;
@Autowired
public JdbcPetRepositoryImpl(DataSource dataSource, OwnerRepository ownerRepository, VisitRepository visitRepository) {
this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
this.insertPet = new SimpleJdbcInsert(dataSource)
.withTableName("pets")
.usingGeneratedKeyColumns("id");
this.ownerRepository = ownerRepository;
this.visitRepository = visitRepository;
}
@Override
public List<PetType> findPetTypes() throws DataAccessException {
Map<String, Object> params = new HashMap<>();
return this.namedParameterJdbcTemplate.query(
"SELECT id, name FROM types ORDER BY name",
params,
BeanPropertyRowMapper.newInstance(PetType.class));
}
@Override
public Pet findById(int id) throws DataAccessException {
Integer ownerId;
try {
Map<String, Object> params = new HashMap<>();
params.put("id", id);
ownerId = this.namedParameterJdbcTemplate.queryForObject("SELECT owner_id FROM pets WHERE id=:id", params, Integer.class);
} catch (EmptyResultDataAccessException ex) {
throw new ObjectRetrievalFailureException(Pet.class, id);
}
Owner owner = this.ownerRepository.findById(ownerId);
return EntityUtils.getById(owner.getPets(), Pet.class, id);
}
@Override
public void save(Pet pet) throws DataAccessException {
if (pet.isNew()) {
Number newKey = this.insertPet.executeAndReturnKey(
createPetParameterSource(pet));
pet.setId(newKey.intValue());
} else {
this.namedParameterJdbcTemplate.update(
"UPDATE pets SET name=:name, birth_date=:birth_date, type_id=:type_id, " +
"owner_id=:owner_id WHERE id=:id",
createPetParameterSource(pet));
}
}
/**
* Creates a {@link MapSqlParameterSource} based on data values from the supplied {@link Pet} instance.
*/
private MapSqlParameterSource createPetParameterSource(Pet pet) {
return new MapSqlParameterSource()
.addValue("id", pet.getId())
.addValue("name", pet.getName())
.addValue("birth_date", pet.getBirthDate().toDate())
.addValue("type_id", pet.getType().getId())
.addValue("owner_id", pet.getOwner().getId());
}
}
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.samples.petclinic.repository.jdbc;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.springframework.jdbc.core.RowMapper;
/**
* {@link RowMapper} implementation mapping data from a {@link ResultSet} to the corresponding properties
* of the {@link JdbcPet} class.
*/
class JdbcPetRowMapper implements RowMapper<JdbcPet> {
@Override
public JdbcPet mapRow(ResultSet rs, int rownum) throws SQLException {
JdbcPet pet = new JdbcPet();
pet.setId(rs.getInt("pets.id"));
pet.setName(rs.getString("name"));
Date birthDate = rs.getDate("birth_date");
pet.setBirthDate(new LocalDate(birthDate));
pet.setTypeId(rs.getInt("type_id"));
pet.setOwnerId(rs.getInt("owner_id"));
return pet;
}
}
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.samples.petclinic.repository.jdbc;
import org.springframework.data.jdbc.core.OneToManyResultSetExtractor;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.samples.petclinic.model.Visit;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* {@link ResultSetExtractor} implementation by using the
* {@link OneToManyResultSetExtractor} of Spring Data Core JDBC Extensions.
*/
public class JdbcPetVisitExtractor extends
OneToManyResultSetExtractor<JdbcPet, Visit, Integer> {
public JdbcPetVisitExtractor() {
super(new JdbcPetRowMapper(), new JdbcVisitRowMapper());
}
@Override
protected Integer mapPrimaryKey(ResultSet rs) throws SQLException {
return rs.getInt("pets.id");
}
@Override
protected Integer mapForeignKey(ResultSet rs) throws SQLException {
if (rs.getObject("visits.pet_id") == null) {
return null;
} else {
return rs.getInt("visits.pet_id");
}
}
@Override
protected void addChild(JdbcPet root, Visit child) {
root.addVisit(child);
}
}
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.samples.petclinic.repository.jdbc;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.samples.petclinic.model.Specialty;
import org.springframework.samples.petclinic.model.Vet;
import org.springframework.samples.petclinic.repository.VetRepository;
import org.springframework.samples.petclinic.util.EntityUtils;
import org.springframework.stereotype.Repository;
/**
* A simple JDBC-based implementation of the {@link VetRepository} interface.
*
* @author Ken Krebs
* @author Juergen Hoeller
* @author Rob Harrop
* @author Sam Brannen
* @author Thomas Risberg
* @author Mark Fisher
* @author Michael Isvy
*/
@Repository
public class JdbcVetRepositoryImpl implements VetRepository {
private JdbcTemplate jdbcTemplate;
@Autowired
public JdbcVetRepositoryImpl(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
/**
* Refresh the cache of Vets that the ClinicService is holding.
*/
@Override
public Collection<Vet> findAll() throws DataAccessException {
List<Vet> vets = new ArrayList<>();
// Retrieve the list of all vets.
vets.addAll(this.jdbcTemplate.query(
"SELECT id, first_name, last_name FROM vets ORDER BY last_name,first_name",
BeanPropertyRowMapper.newInstance(Vet.class)));
// Retrieve the list of all possible specialties.
final List<Specialty> specialties = this.jdbcTemplate.query(
"SELECT id, name FROM specialties",
BeanPropertyRowMapper.newInstance(Specialty.class));
// Build each vet's list of specialties.
for (Vet vet : vets) {
final List<Integer> vetSpecialtiesIds = this.jdbcTemplate.query(
"SELECT specialty_id FROM vet_specialties WHERE vet_id=?",
new BeanPropertyRowMapper<Integer>() {
@Override
public Integer mapRow(ResultSet rs, int row) throws SQLException {
return rs.getInt(1);
}
},
vet.getId());
for (int specialtyId : vetSpecialtiesIds) {
Specialty specialty = EntityUtils.getById(specialties, Specialty.class, specialtyId);
vet.addSpecialty(specialty);
}
}
return vets;
}
}
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.samples.petclinic.repository.jdbc;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.samples.petclinic.model.Visit;
import org.springframework.samples.petclinic.repository.VisitRepository;
import org.springframework.stereotype.Repository;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* A simple JDBC-based implementation of the {@link VisitRepository} interface.
*
* @author Ken Krebs
* @author Juergen Hoeller
* @author Rob Harrop
* @author Sam Brannen
* @author Thomas Risberg
* @author Mark Fisher
* @author Michael Isvy
*/
@Repository
public class JdbcVisitRepositoryImpl implements VisitRepository {
private NamedParameterJdbcTemplate jdbcTemplate;
private SimpleJdbcInsert insertVisit;
@Autowired
public JdbcVisitRepositoryImpl(DataSource dataSource) {
this.jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
this.insertVisit = new SimpleJdbcInsert(dataSource)
.withTableName("visits")
.usingGeneratedKeyColumns("id");
}
@Override
public void save(Visit visit) throws DataAccessException {
if (visit.isNew()) {
Number newKey = this.insertVisit.executeAndReturnKey(
createVisitParameterSource(visit));
visit.setId(newKey.intValue());
} else {
throw new UnsupportedOperationException("Visit update not supported");
}
}
/**
* Creates a {@link MapSqlParameterSource} based on data values from the supplied {@link Visit} instance.
*/
private MapSqlParameterSource createVisitParameterSource(Visit visit) {
return new MapSqlParameterSource()
.addValue("id", visit.getId())
.addValue("visit_date", visit.getDate().toDate())
.addValue("description", visit.getDescription())
.addValue("pet_id", visit.getPet().getId());
}
@Override
public List<Visit> findByPetId(Integer petId) {
Map<String, Object> params = new HashMap<>();
params.put("id", petId);
JdbcPet pet = this.jdbcTemplate.queryForObject(
"SELECT id, name, birth_date, type_id, owner_id FROM pets WHERE id=:id",
params,
new JdbcPetRowMapper());
List<Visit> visits = this.jdbcTemplate.query(
"SELECT id as visit_id, visit_date, description FROM visits WHERE pet_id=:id",
params, new JdbcVisitRowMapper());
for (Visit visit: visits) {
visit.setPet(pet);
}
return visits;
}
}
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.samples.petclinic.repository.jdbc;
import org.joda.time.LocalDate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.samples.petclinic.model.Visit;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
/**
* {@link RowMapper} implementation mapping data from a {@link ResultSet} to the corresponding properties
* of the {@link Visit} class.
*/
class JdbcVisitRowMapper implements RowMapper<Visit> {
@Override
public Visit mapRow(ResultSet rs, int row) throws SQLException {
Visit visit = new Visit();
visit.setId(rs.getInt("visit_id"));
Date visitDate = rs.getDate("visit_date");
visit.setDate(new LocalDate(visitDate));
visit.setDescription(rs.getString("description"));
return visit;
}
}