diff --git a/src/main/java/org/springframework/samples/petclinic/Clinic.java b/src/main/java/org/springframework/samples/petclinic/Clinic.java deleted file mode 100644 index 9eca087e8..000000000 --- a/src/main/java/org/springframework/samples/petclinic/Clinic.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.springframework.samples.petclinic; - -import java.util.Collection; - -import org.springframework.dao.DataAccessException; - -/** - * The high-level PetClinic business interface. - * - *

This is basically a data access object. - * PetClinic doesn't have a dedicated business facade. - * - * @author Ken Krebs - * @author Juergen Hoeller - * @author Sam Brannen - */ -public interface Clinic { - - /** - * Retrieve all Vets from the data store. - * @return a Collection of Vets - */ - Collection getVets() throws DataAccessException; - - /** - * Retrieve all PetTypes from the data store. - * @return a Collection of PetTypes - */ - Collection getPetTypes() throws DataAccessException; - - /** - * Retrieve Owners from the data store by last name, - * returning all owners whose last name starts with the given name. - * @param lastName Value to search for - * @return a Collection of matching Owners - * (or an empty Collection if none found) - */ - Collection findOwners(String lastName) throws DataAccessException; - - /** - * Retrieve an Owner from the data store by id. - * @param id the id to search for - * @return the Owner if found - * @throws org.springframework.dao.DataRetrievalFailureException if not found - */ - Owner findOwner(int id) throws DataAccessException; - - /** - * Retrieve a Pet from the data store by id. - * @param id the id to search for - * @return the Pet if found - * @throws org.springframework.dao.DataRetrievalFailureException if not found - */ - Pet findPet(int id) throws DataAccessException; - - /** - * Save an Owner to the data store, either inserting or updating it. - * @param owner the Owner to save - * @see BaseEntity#isNew - */ - void storeOwner(Owner owner) throws DataAccessException; - - /** - * Save a Pet to the data store, either inserting or updating it. - * @param pet the Pet to save - * @see BaseEntity#isNew - */ - void storePet(Pet pet) throws DataAccessException; - - /** - * Save a Visit to the data store, either inserting or updating it. - * @param visit the Visit to save - * @see BaseEntity#isNew - */ - void storeVisit(Visit visit) throws DataAccessException; - - /** - * Deletes a Pet from the data store. - */ - void deletePet(int id) throws DataAccessException; - -} diff --git a/src/main/java/org/springframework/samples/petclinic/Owner.java b/src/main/java/org/springframework/samples/petclinic/Owner.java index 65e3df8fe..cb24f263e 100644 --- a/src/main/java/org/springframework/samples/petclinic/Owner.java +++ b/src/main/java/org/springframework/samples/petclinic/Owner.java @@ -126,19 +126,12 @@ public class Owner extends Person { return new ToStringCreator(this) .append("id", this.getId()) - .append("new", this.isNew()) - .append("lastName", this.getLastName()) - .append("firstName", this.getFirstName()) - .append("address", this.address) - .append("city", this.city) - .append("telephone", this.telephone) - .toString(); } } diff --git a/src/main/java/org/springframework/samples/petclinic/aspects/UsageLogAspect.java b/src/main/java/org/springframework/samples/petclinic/aspects/UsageLogAspect.java index e326abfb7..b7fde3779 100644 --- a/src/main/java/org/springframework/samples/petclinic/aspects/UsageLogAspect.java +++ b/src/main/java/org/springframework/samples/petclinic/aspects/UsageLogAspect.java @@ -9,7 +9,7 @@ import org.aspectj.lang.annotation.Before; /** * Sample AspectJ annotation-style aspect that saves - * every owner name requested to the clinic. + * every owner name requested to the petRepository. * * @author Rod Johnson * @author Juergen Hoeller diff --git a/src/main/java/org/springframework/samples/petclinic/jdbc/JdbcClinicImpl.java b/src/main/java/org/springframework/samples/petclinic/jdbc/JdbcClinicImpl.java deleted file mode 100644 index ecd8cb13b..000000000 --- a/src/main/java/org/springframework/samples/petclinic/jdbc/JdbcClinicImpl.java +++ /dev/null @@ -1,344 +0,0 @@ -package org.springframework.samples.petclinic.jdbc; - -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import javax.sql.DataSource; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.dao.DataAccessException; -import org.springframework.dao.EmptyResultDataAccessException; -import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource; -import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; -import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; -import org.springframework.jdbc.core.simple.ParameterizedBeanPropertyRowMapper; -import org.springframework.jdbc.core.simple.ParameterizedRowMapper; -import org.springframework.jdbc.core.simple.SimpleJdbcInsert; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jmx.export.annotation.ManagedOperation; -import org.springframework.jmx.export.annotation.ManagedResource; -import org.springframework.orm.ObjectRetrievalFailureException; -import org.springframework.samples.petclinic.Clinic; -import org.springframework.samples.petclinic.Owner; -import org.springframework.samples.petclinic.Pet; -import org.springframework.samples.petclinic.PetType; -import org.springframework.samples.petclinic.Specialty; -import org.springframework.samples.petclinic.Vet; -import org.springframework.samples.petclinic.Visit; -import org.springframework.samples.petclinic.util.EntityUtils; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -/** - * A simple JDBC-based implementation of the {@link Clinic} interface. - * - *

This class uses Java 5 language features and the {@link SimpleJdbcTemplate} - * plus {@link SimpleJdbcInsert}. It also takes advantage of classes like - * {@link BeanPropertySqlParameterSource} and - * {@link ParameterizedBeanPropertyRowMapper} which provide automatic mapping - * between JavaBean properties and JDBC parameters or query results. - * - *

JdbcClinicImpl is a rewrite of the AbstractJdbcClinic which was the base - * class for JDBC implementations of the Clinic interface for Spring 2.0. - * - * @author Ken Krebs - * @author Juergen Hoeller - * @author Rob Harrop - * @author Sam Brannen - * @author Thomas Risberg - * @author Mark Fisher - */ -@Service -@ManagedResource("petclinic:type=Clinic") -public class JdbcClinicImpl implements Clinic, JdbcClinicImplMBean { - - private final Logger logger = LoggerFactory.getLogger(getClass()); - - private JdbcTemplate jdbcTemplate; - private NamedParameterJdbcTemplate namedParameterJdbcTemplate; - - private SimpleJdbcInsert insertOwner; - private SimpleJdbcInsert insertPet; - private SimpleJdbcInsert insertVisit; - - private final List vets = new ArrayList(); - - - @Autowired - public void init(DataSource dataSource) { - this.jdbcTemplate = new JdbcTemplate(dataSource); - this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource); - - this.insertOwner = new SimpleJdbcInsert(dataSource) - .withTableName("owners") - .usingGeneratedKeyColumns("id"); - this.insertPet = new SimpleJdbcInsert(dataSource) - .withTableName("pets") - .usingGeneratedKeyColumns("id"); - this.insertVisit = new SimpleJdbcInsert(dataSource) - .withTableName("visits") - .usingGeneratedKeyColumns("id"); - } - - - /** - * Refresh the cache of Vets that the Clinic is holding. - * @see org.springframework.samples.petclinic.Clinic#getVets() - */ - @ManagedOperation - @Transactional(readOnly = true) - public void refreshVetsCache() throws DataAccessException { - synchronized (this.vets) { - this.logger.info("Refreshing vets cache"); - - // Retrieve the list of all vets. - this.vets.clear(); - this.vets.addAll(this.jdbcTemplate.query( - "SELECT id, first_name, last_name FROM vets ORDER BY last_name,first_name", - ParameterizedBeanPropertyRowMapper.newInstance(Vet.class))); - - // Retrieve the list of all possible specialties. - final List specialties = this.jdbcTemplate.query( - "SELECT id, name FROM specialties", - ParameterizedBeanPropertyRowMapper.newInstance(Specialty.class)); - - // Build each vet's list of specialties. - for (Vet vet : this.vets) { - final List vetSpecialtiesIds = this.jdbcTemplate.query( - "SELECT specialty_id FROM vet_specialties WHERE vet_id=?", - new ParameterizedRowMapper() { - public Integer mapRow(ResultSet rs, int row) throws SQLException { - return Integer.valueOf(rs.getInt(1)); - }}, - vet.getId().intValue()); - for (int specialtyId : vetSpecialtiesIds) { - Specialty specialty = EntityUtils.getById(specialties, Specialty.class, specialtyId); - vet.addSpecialty(specialty); - } - } - } - } - - - // START of Clinic implementation section ******************************* - - @Transactional(readOnly = true) - public Collection getVets() throws DataAccessException { - synchronized (this.vets) { - if (this.vets.isEmpty()) { - refreshVetsCache(); - } - return this.vets; - } - } - - @Transactional(readOnly = true) - public Collection getPetTypes() throws DataAccessException { - return this.jdbcTemplate.query( - "SELECT id, name FROM types ORDER BY name", - ParameterizedBeanPropertyRowMapper.newInstance(PetType.class)); - } - - /** - * Loads {@link Owner Owners} from the data store by last name, returning - * all owners whose last name starts with the given name; also loads - * the {@link Pet Pets} and {@link Visit Visits} for the corresponding - * owners, if not already loaded. - */ - @Transactional(readOnly = true) - public Collection findOwners(String lastName) throws DataAccessException { - List owners = this.jdbcTemplate.query( - "SELECT id, first_name, last_name, address, city, telephone FROM owners WHERE last_name like ?", - ParameterizedBeanPropertyRowMapper.newInstance(Owner.class), - lastName + "%"); - loadOwnersPetsAndVisits(owners); - return owners; - } - - /** - * Loads the {@link Owner} with the supplied id; also loads - * the {@link Pet Pets} and {@link Visit Visits} for the corresponding - * owner, if not already loaded. - */ - @Transactional(readOnly = true) - public Owner findOwner(int id) throws DataAccessException { - Owner owner; - try { - owner = this.jdbcTemplate.queryForObject( - "SELECT id, first_name, last_name, address, city, telephone FROM owners WHERE id=?", - ParameterizedBeanPropertyRowMapper.newInstance(Owner.class), - id); - } - catch (EmptyResultDataAccessException ex) { - throw new ObjectRetrievalFailureException(Owner.class, new Integer(id)); - } - loadPetsAndVisits(owner); - return owner; - } - - @Transactional(readOnly = true) - public Pet findPet(int id) throws DataAccessException { - JdbcPet pet; - try { - pet = this.jdbcTemplate.queryForObject( - "SELECT id, name, birth_date, type_id, owner_id FROM pets WHERE id=?", - new JdbcPetRowMapper(), - id); - } - catch (EmptyResultDataAccessException ex) { - throw new ObjectRetrievalFailureException(Pet.class, new Integer(id)); - } - Owner owner = findOwner(pet.getOwnerId()); - owner.addPet(pet); - pet.setType(EntityUtils.getById(getPetTypes(), PetType.class, pet.getTypeId())); - loadVisits(pet); - return pet; - } - - @Transactional - public void storeOwner(Owner owner) throws DataAccessException { - if (owner.isNew()) { - Number newKey = this.insertOwner.executeAndReturnKey( - new BeanPropertySqlParameterSource(owner)); - 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", - new BeanPropertySqlParameterSource(owner)); - } - } - - @Transactional - public void storePet(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)); - } - } - - @Transactional - public void storeVisit(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"); - } - } - - public void deletePet(int id) throws DataAccessException { - this.jdbcTemplate.update("DELETE FROM pets WHERE id=?", id); - } - - // END of Clinic implementation section ************************************ - - - /** - * 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()) - .addValue("type_id", pet.getType().getId()) - .addValue("owner_id", pet.getOwner().getId()); - } - - /** - * 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()) - .addValue("description", visit.getDescription()) - .addValue("pet_id", visit.getPet().getId()); - } - - /** - * Loads the {@link Visit} data for the supplied {@link Pet}. - */ - private void loadVisits(JdbcPet pet) { - final List visits = this.jdbcTemplate.query( - "SELECT id, visit_date, description FROM visits WHERE pet_id=?", - new ParameterizedRowMapper() { - public Visit mapRow(ResultSet rs, int row) throws SQLException { - Visit visit = new Visit(); - visit.setId(rs.getInt("id")); - visit.setDate(rs.getTimestamp("visit_date")); - visit.setDescription(rs.getString("description")); - return visit; - } - }, - pet.getId().intValue()); - for (Visit visit : visits) { - pet.addVisit(visit); - } - } - - /** - * Loads the {@link Pet} and {@link Visit} data for the supplied - * {@link Owner}. - */ - private void loadPetsAndVisits(final Owner owner) { - final List pets = this.jdbcTemplate.query( - "SELECT id, name, birth_date, type_id, owner_id FROM pets WHERE owner_id=?", - new JdbcPetRowMapper(), - owner.getId().intValue()); - for (JdbcPet pet : pets) { - owner.addPet(pet); - pet.setType(EntityUtils.getById(getPetTypes(), PetType.class, pet.getTypeId())); - loadVisits(pet); - } - } - - /** - * 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 owners) { - for (Owner owner : owners) { - loadPetsAndVisits(owner); - } - } - - /** - * {@link ParameterizedRowMapper} implementation mapping data from a - * {@link ResultSet} to the corresponding properties of the {@link JdbcPet} class. - */ - private class JdbcPetRowMapper implements ParameterizedRowMapper { - - public JdbcPet mapRow(ResultSet rs, int rownum) throws SQLException { - JdbcPet pet = new JdbcPet(); - pet.setId(rs.getInt("id")); - pet.setName(rs.getString("name")); - pet.setBirthDate(rs.getDate("birth_date")); - pet.setTypeId(rs.getInt("type_id")); - pet.setOwnerId(rs.getInt("owner_id")); - return pet; - } - } - -} diff --git a/src/main/java/org/springframework/samples/petclinic/repository/OwnerRepository.java b/src/main/java/org/springframework/samples/petclinic/repository/OwnerRepository.java new file mode 100644 index 000000000..4a24d5413 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/repository/OwnerRepository.java @@ -0,0 +1,47 @@ +package org.springframework.samples.petclinic.repository; + +import java.util.Collection; + +import org.springframework.dao.DataAccessException; +import org.springframework.samples.petclinic.BaseEntity; +import org.springframework.samples.petclinic.Owner; + +/** + * The high-level PetClinic business interface. + * + *

This is basically a data access object. + * PetClinic doesn't have a dedicated business facade. + * + * @author Ken Krebs + * @author Juergen Hoeller + * @author Sam Brannen + */ +public interface OwnerRepository { + + /** + * Retrieve Owners from the data store by last name, + * returning all owners whose last name starts with the given name. + * @param lastName Value to search for + * @return a Collection of matching Owners + * (or an empty Collection if none found) + */ + Collection findByLastName(String lastName) throws DataAccessException; + + /** + * Retrieve an Owner from the data store by id. + * @param id the id to search for + * @return the Owner if found + * @throws org.springframework.dao.DataRetrievalFailureException if not found + */ + Owner findById(int id) throws DataAccessException; + + + /** + * Save an Owner to the data store, either inserting or updating it. + * @param owner the Owner to save + * @see BaseEntity#isNew + */ + void save(Owner owner) throws DataAccessException; + + +} diff --git a/src/main/java/org/springframework/samples/petclinic/repository/PetRepository.java b/src/main/java/org/springframework/samples/petclinic/repository/PetRepository.java new file mode 100644 index 000000000..119e0e31b --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/repository/PetRepository.java @@ -0,0 +1,51 @@ +package org.springframework.samples.petclinic.repository; + +import java.util.Collection; + +import org.springframework.dao.DataAccessException; +import org.springframework.samples.petclinic.BaseEntity; +import org.springframework.samples.petclinic.Owner; +import org.springframework.samples.petclinic.Pet; +import org.springframework.samples.petclinic.PetType; +import org.springframework.samples.petclinic.Vet; +import org.springframework.samples.petclinic.Visit; + +/** + * The high-level PetClinic business interface. + * + *

This is basically a data access object. + * PetClinic doesn't have a dedicated business facade. + * + * @author Ken Krebs + * @author Juergen Hoeller + * @author Sam Brannen + */ +public interface PetRepository { + + /** + * Retrieve all PetTypes from the data store. + * @return a Collection of PetTypes + */ + Collection getPetTypes() throws DataAccessException; + + /** + * Retrieve a Pet from the data store by id. + * @param id the id to search for + * @return the Pet if found + * @throws org.springframework.dao.DataRetrievalFailureException if not found + */ + Pet findById(int id) throws DataAccessException; + + /** + * Save a Pet to the data store, either inserting or updating it. + * @param pet the Pet to save + * @see BaseEntity#isNew + */ + void storePet(Pet pet) throws DataAccessException; + + /** + * Deletes a Pet from the data store. + */ + void deletePet(int id) throws DataAccessException; + +} diff --git a/src/main/java/org/springframework/samples/petclinic/repository/VetRepository.java b/src/main/java/org/springframework/samples/petclinic/repository/VetRepository.java new file mode 100644 index 000000000..a3068601e --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/repository/VetRepository.java @@ -0,0 +1,27 @@ +package org.springframework.samples.petclinic.repository; + +import java.util.Collection; + +import org.springframework.dao.DataAccessException; +import org.springframework.samples.petclinic.Vet; + +/** + * The high-level PetClinic business interface. + * + *

This is basically a data access object. + * PetClinic doesn't have a dedicated business facade. + * + * @author Ken Krebs + * @author Juergen Hoeller + * @author Sam Brannen + */ +public interface VetRepository { + + /** + * Retrieve all Vets from the data store. + * @return a Collection of Vets + */ + Collection getVets() throws DataAccessException; + + +} diff --git a/src/main/java/org/springframework/samples/petclinic/repository/VisitRepository.java b/src/main/java/org/springframework/samples/petclinic/repository/VisitRepository.java new file mode 100644 index 000000000..2af5ac743 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/repository/VisitRepository.java @@ -0,0 +1,30 @@ +package org.springframework.samples.petclinic.repository; + +import java.util.List; + +import org.springframework.dao.DataAccessException; +import org.springframework.samples.petclinic.BaseEntity; +import org.springframework.samples.petclinic.Visit; + +/** + * The high-level PetClinic business interface. + * + *

This is basically a data access object. + * PetClinic doesn't have a dedicated business facade. + * + * @author Ken Krebs + * @author Juergen Hoeller + * @author Sam Brannen + */ +public interface VisitRepository { + + /** + * Save a Visit to the data store, either inserting or updating it. + * @param visit the Visit to save + * @see BaseEntity#isNew + */ + void storeVisit(Visit visit) throws DataAccessException; + + List findByPetId(Integer petId); + +} diff --git a/src/main/java/org/springframework/samples/petclinic/jdbc/JdbcClinicImplMBean.java b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcClinicImplMBean.java similarity index 59% rename from src/main/java/org/springframework/samples/petclinic/jdbc/JdbcClinicImplMBean.java rename to src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcClinicImplMBean.java index 6eaa97cf5..b3240360a 100644 --- a/src/main/java/org/springframework/samples/petclinic/jdbc/JdbcClinicImplMBean.java +++ b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcClinicImplMBean.java @@ -1,4 +1,4 @@ -package org.springframework.samples.petclinic.jdbc; +package org.springframework.samples.petclinic.repository.jdbc; /** * Interface that defines a cache refresh operation. @@ -11,8 +11,8 @@ package org.springframework.samples.petclinic.jdbc; public interface JdbcClinicImplMBean { /** - * Refresh the cache of Vets that the Clinic is holding. - * @see org.springframework.samples.petclinic.Clinic#getVets() + * Refresh the cache of Vets that the ClinicService is holding. + * @see org.springframework.samples.petclinic.service.ClinicService#getVets() * @see JdbcClinicImpl#refreshVetsCache() */ void refreshVetsCache(); diff --git a/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcOwnerRepositoryImpl.java b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcOwnerRepositoryImpl.java new file mode 100644 index 000000000..eef9dfdef --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcOwnerRepositoryImpl.java @@ -0,0 +1,173 @@ +package org.springframework.samples.petclinic.repository.jdbc; + +import java.util.Collection; +import java.util.List; + +import javax.sql.DataSource; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.jdbc.core.simple.ParameterizedBeanPropertyRowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcInsert; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; +import org.springframework.orm.ObjectRetrievalFailureException; +import org.springframework.samples.petclinic.Owner; +import org.springframework.samples.petclinic.Pet; +import org.springframework.samples.petclinic.PetType; +import org.springframework.samples.petclinic.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.service.ClinicService; +import org.springframework.samples.petclinic.util.EntityUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * A simple JDBC-based implementation of the {@link ClinicService} interface. + * + *

This class uses Java 5 language features and the {@link SimpleJdbcTemplate} + * plus {@link SimpleJdbcInsert}. It also takes advantage of classes like + * {@link BeanPropertySqlParameterSource} and + * {@link ParameterizedBeanPropertyRowMapper} which provide automatic mapping + * between JavaBean properties and JDBC parameters or query results. + * + *

JdbcClinicImpl is a rewrite of the AbstractJdbcClinic which was the base + * class for JDBC implementations of the ClinicService interface for Spring 2.0. + * + * @author Ken Krebs + * @author Juergen Hoeller + * @author Rob Harrop + * @author Sam Brannen + * @author Thomas Risberg + * @author Mark Fisher + */ +@Service +public class JdbcOwnerRepositoryImpl implements OwnerRepository { + + @Autowired + private PetRepository petRepository; + + @Autowired + private VisitRepository visitRepository; + + @Autowired + private JdbcTemplate jdbcTemplate; + + @Autowired + private NamedParameterJdbcTemplate namedParameterJdbcTemplate; + + private SimpleJdbcInsert insertOwner; + + @Autowired + public void init(DataSource dataSource) { + + this.insertOwner = new SimpleJdbcInsert(dataSource) + .withTableName("owners") + .usingGeneratedKeyColumns("id"); + } + + + + + /** + * Loads {@link Owner Owners} from the data store by last name, returning + * all owners whose last name starts with the given name; also loads + * the {@link Pet Pets} and {@link Visit Visits} for the corresponding + * owners, if not already loaded. + */ + @Transactional(readOnly = true) + public Collection findByLastName(String lastName) throws DataAccessException { + List owners = this.jdbcTemplate.query( + "SELECT id, first_name, last_name, address, city, telephone FROM owners WHERE last_name like ?", + ParameterizedBeanPropertyRowMapper.newInstance(Owner.class), + lastName + "%"); + loadOwnersPetsAndVisits(owners); + return owners; + } + + /** + * Loads the {@link Owner} with the supplied id; also loads + * the {@link Pet Pets} and {@link Visit Visits} for the corresponding + * owner, if not already loaded. + */ + @Transactional(readOnly = true) + public Owner findById(int id) throws DataAccessException { + Owner owner; + try { + owner = this.jdbcTemplate.queryForObject( + "SELECT id, first_name, last_name, address, city, telephone FROM owners WHERE id=?", + ParameterizedBeanPropertyRowMapper.newInstance(Owner.class), + id); + } + catch (EmptyResultDataAccessException ex) { + throw new ObjectRetrievalFailureException(Owner.class, new Integer(id)); + } + loadPetsAndVisits(owner); + return owner; + } + + public void loadPetsAndVisits(final Owner owner) { + final List pets = this.jdbcTemplate.query( + "SELECT id, name, birth_date, type_id, owner_id FROM pets WHERE owner_id=?", + new JdbcPetRowMapper(), + owner.getId().intValue()); + for (JdbcPet pet : pets) { + owner.addPet(pet); + pet.setType(EntityUtils.getById(getPetTypes(), PetType.class, pet.getTypeId())); + List visits = this.visitRepository.findByPetId(pet.getId()); + for (Visit visit : visits) { + pet.addVisit(visit); + } + } + } + + + + @Transactional + public void save(Owner owner) throws DataAccessException { + if (owner.isNew()) { + Number newKey = this.insertOwner.executeAndReturnKey( + new BeanPropertySqlParameterSource(owner)); + 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", + new BeanPropertySqlParameterSource(owner)); + } + } + + + + + + @Transactional(readOnly = true) + public Collection getPetTypes() throws DataAccessException { + return this.jdbcTemplate.query( + "SELECT id, name FROM types ORDER BY name", + ParameterizedBeanPropertyRowMapper.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 owners) { + for (Owner owner : owners) { + loadPetsAndVisits(owner); + } + } + + +} diff --git a/src/main/java/org/springframework/samples/petclinic/jdbc/JdbcPet.java b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcPet.java similarity index 78% rename from src/main/java/org/springframework/samples/petclinic/jdbc/JdbcPet.java rename to src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcPet.java index aa0bf183d..4a9ccf3bc 100644 --- a/src/main/java/org/springframework/samples/petclinic/jdbc/JdbcPet.java +++ b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcPet.java @@ -1,10 +1,10 @@ -package org.springframework.samples.petclinic.jdbc; +package org.springframework.samples.petclinic.repository.jdbc; import org.springframework.samples.petclinic.Pet; /** * Subclass of Pet that carries temporary id properties which - * are only relevant for a JDBC implmentation of the Clinic. + * are only relevant for a JDBC implmentation of the ClinicService. * * @author Juergen Hoeller * @see JdbcClinicImpl diff --git a/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcPetRepositoryImpl.java b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcPetRepositoryImpl.java new file mode 100644 index 000000000..6efff5f5b --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcPetRepositoryImpl.java @@ -0,0 +1,160 @@ +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 javax.sql.DataSource; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource; +import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.jdbc.core.simple.ParameterizedBeanPropertyRowMapper; +import org.springframework.jdbc.core.simple.ParameterizedRowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcInsert; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jmx.export.annotation.ManagedOperation; +import org.springframework.jmx.export.annotation.ManagedResource; +import org.springframework.orm.ObjectRetrievalFailureException; +import org.springframework.samples.petclinic.Owner; +import org.springframework.samples.petclinic.Pet; +import org.springframework.samples.petclinic.PetType; +import org.springframework.samples.petclinic.Specialty; +import org.springframework.samples.petclinic.Vet; +import org.springframework.samples.petclinic.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.service.ClinicService; +import org.springframework.samples.petclinic.util.EntityUtils; +import org.springframework.stereotype.Repository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * A simple JDBC-based implementation of the {@link ClinicService} interface. + * + *

This class uses Java 5 language features and the {@link SimpleJdbcTemplate} + * plus {@link SimpleJdbcInsert}. It also takes advantage of classes like + * {@link BeanPropertySqlParameterSource} and + * {@link ParameterizedBeanPropertyRowMapper} which provide automatic mapping + * between JavaBean properties and JDBC parameters or query results. + * + *

JdbcClinicImpl is a rewrite of the AbstractJdbcClinic which was the base + * class for JDBC implementations of the ClinicService interface for Spring 2.0. + * + * @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 JdbcTemplate jdbcTemplate; + private NamedParameterJdbcTemplate namedParameterJdbcTemplate; + + private SimpleJdbcInsert insertPet; + + @Autowired + private OwnerRepository ownerRepository; + + @Autowired + private VisitRepository visitRepository; + + private final List vets = new ArrayList(); + + + @Autowired + public void init(DataSource dataSource) { + this.jdbcTemplate = new JdbcTemplate(dataSource); + this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource); + + this.insertPet = new SimpleJdbcInsert(dataSource) + .withTableName("pets") + .usingGeneratedKeyColumns("id"); + } + + @Transactional(readOnly = true) + public Collection getPetTypes() throws DataAccessException { + return this.jdbcTemplate.query( + "SELECT id, name FROM types ORDER BY name", + ParameterizedBeanPropertyRowMapper.newInstance(PetType.class)); + } + + @Transactional(readOnly = true) + public Pet findById(int id) throws DataAccessException { + JdbcPet pet; + try { + pet = this.jdbcTemplate.queryForObject( + "SELECT id, name, birth_date, type_id, owner_id FROM pets WHERE id=?", + new JdbcPetRowMapper(), + id); + } + catch (EmptyResultDataAccessException ex) { + throw new ObjectRetrievalFailureException(Pet.class, new Integer(id)); + } + Owner owner = this.ownerRepository.findById(pet.getOwnerId()); + owner.addPet(pet); + pet.setType(EntityUtils.getById(getPetTypes(), PetType.class, pet.getTypeId())); + + List visits = this.visitRepository.findByPetId(pet.getId()); + for (Visit visit : visits) { + pet.addVisit(visit); + } + return pet; + } + + @Transactional + public void storePet(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()) + .addValue("type_id", pet.getType().getId()) + .addValue("owner_id", pet.getOwner().getId()); + } + + @Override + public void deletePet(int id) throws DataAccessException { + // TODO Auto-generated method stub + + } + + + /** + * Loads the {@link Pet} and {@link Visit} data for the supplied + * {@link Owner}. + */ + + + + +} diff --git a/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcPetRowMapper.java b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcPetRowMapper.java new file mode 100644 index 000000000..575f4608a --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcPetRowMapper.java @@ -0,0 +1,23 @@ +package org.springframework.samples.petclinic.repository.jdbc; + +import java.sql.ResultSet; +import java.sql.SQLException; + +import org.springframework.jdbc.core.simple.ParameterizedRowMapper; + +/** + * {@link ParameterizedRowMapper} implementation mapping data from a + * {@link ResultSet} to the corresponding properties of the {@link JdbcPet} class. + */ +class JdbcPetRowMapper implements ParameterizedRowMapper { + + public JdbcPet mapRow(ResultSet rs, int rownum) throws SQLException { + JdbcPet pet = new JdbcPet(); + pet.setId(rs.getInt("id")); + pet.setName(rs.getString("name")); + pet.setBirthDate(rs.getDate("birth_date")); + pet.setTypeId(rs.getInt("type_id")); + pet.setOwnerId(rs.getInt("owner_id")); + return pet; + } +} diff --git a/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcVetRepositoryImpl.java b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcVetRepositoryImpl.java new file mode 100644 index 000000000..88b8c0301 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcVetRepositoryImpl.java @@ -0,0 +1,118 @@ +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 javax.sql.DataSource; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource; +import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.jdbc.core.simple.ParameterizedBeanPropertyRowMapper; +import org.springframework.jdbc.core.simple.ParameterizedRowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcInsert; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jmx.export.annotation.ManagedOperation; +import org.springframework.jmx.export.annotation.ManagedResource; +import org.springframework.orm.ObjectRetrievalFailureException; +import org.springframework.samples.petclinic.Owner; +import org.springframework.samples.petclinic.Pet; +import org.springframework.samples.petclinic.PetType; +import org.springframework.samples.petclinic.Specialty; +import org.springframework.samples.petclinic.Vet; +import org.springframework.samples.petclinic.Visit; +import org.springframework.samples.petclinic.repository.VetRepository; +import org.springframework.samples.petclinic.service.ClinicService; +import org.springframework.samples.petclinic.util.EntityUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * A simple JDBC-based implementation of the {@link ClinicService} interface. + * + *

This class uses Java 5 language features and the {@link SimpleJdbcTemplate} + * plus {@link SimpleJdbcInsert}. It also takes advantage of classes like + * {@link BeanPropertySqlParameterSource} and + * {@link ParameterizedBeanPropertyRowMapper} which provide automatic mapping + * between JavaBean properties and JDBC parameters or query results. + * + *

JdbcClinicImpl is a rewrite of the AbstractJdbcClinic which was the base + * class for JDBC implementations of the ClinicService interface for Spring 2.0. + * + * @author Ken Krebs + * @author Juergen Hoeller + * @author Rob Harrop + * @author Sam Brannen + * @author Thomas Risberg + * @author Mark Fisher + */ +@Service +public class JdbcVetRepositoryImpl implements VetRepository { + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private JdbcTemplate jdbcTemplate; + + private final List vets = new ArrayList(); + + + + /** + * Refresh the cache of Vets that the ClinicService is holding. + * @see org.springframework.samples.petclinic.service.ClinicService#getVets() + */ + @ManagedOperation + @Transactional(readOnly = true) + public void refreshVetsCache() throws DataAccessException { + synchronized (this.vets) { + this.logger.info("Refreshing vets cache"); + + // Retrieve the list of all vets. + this.vets.clear(); + this.vets.addAll(this.jdbcTemplate.query( + "SELECT id, first_name, last_name FROM vets ORDER BY last_name,first_name", + ParameterizedBeanPropertyRowMapper.newInstance(Vet.class))); + + // Retrieve the list of all possible specialties. + final List specialties = this.jdbcTemplate.query( + "SELECT id, name FROM specialties", + ParameterizedBeanPropertyRowMapper.newInstance(Specialty.class)); + + // Build each vet's list of specialties. + for (Vet vet : this.vets) { + final List vetSpecialtiesIds = this.jdbcTemplate.query( + "SELECT specialty_id FROM vet_specialties WHERE vet_id=?", + new ParameterizedRowMapper() { + public Integer mapRow(ResultSet rs, int row) throws SQLException { + return Integer.valueOf(rs.getInt(1)); + }}, + vet.getId().intValue()); + for (int specialtyId : vetSpecialtiesIds) { + Specialty specialty = EntityUtils.getById(specialties, Specialty.class, specialtyId); + vet.addSpecialty(specialty); + } + } + } + } + + @Transactional(readOnly = true) + public Collection getVets() throws DataAccessException { + synchronized (this.vets) { + if (this.vets.isEmpty()) { + refreshVetsCache(); + } + return this.vets; + } + } + + +} diff --git a/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcVisitRepositoryImpl.java b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcVisitRepositoryImpl.java new file mode 100644 index 000000000..f1cc60bcc --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcVisitRepositoryImpl.java @@ -0,0 +1,131 @@ +package org.springframework.samples.petclinic.repository.jdbc; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; + +import javax.sql.DataSource; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource; +import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; +import org.springframework.jdbc.core.simple.ParameterizedBeanPropertyRowMapper; +import org.springframework.jdbc.core.simple.ParameterizedRowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcInsert; +import org.springframework.samples.petclinic.Pet; +import org.springframework.samples.petclinic.Visit; +import org.springframework.samples.petclinic.repository.VisitRepository; +import org.springframework.samples.petclinic.service.ClinicService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * A simple JDBC-based implementation of the {@link ClinicService} interface. + * + *

This class uses Java 5 language features and the {@link SimpleJdbcTemplate} + * plus {@link SimpleJdbcInsert}. It also takes advantage of classes like + * {@link BeanPropertySqlParameterSource} and + * {@link ParameterizedBeanPropertyRowMapper} which provide automatic mapping + * between JavaBean properties and JDBC parameters or query results. + * + *

JdbcClinicImpl is a rewrite of the AbstractJdbcClinic which was the base + * class for JDBC implementations of the ClinicService interface for Spring 2.0. + * + * @author Ken Krebs + * @author Juergen Hoeller + * @author Rob Harrop + * @author Sam Brannen + * @author Thomas Risberg + * @author Mark Fisher + */ +@Service +public class JdbcVisitRepositoryImpl implements VisitRepository { + + private JdbcTemplate jdbcTemplate; + + private SimpleJdbcInsert insertVisit; + + @Autowired + public void init(DataSource dataSource) { + this.jdbcTemplate = new JdbcTemplate(dataSource); + + this.insertVisit = new SimpleJdbcInsert(dataSource) + .withTableName("visits") + .usingGeneratedKeyColumns("id"); + } + + + @Transactional + public void storeVisit(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"); + } + } + + public void deletePet(int id) throws DataAccessException { + this.jdbcTemplate.update("DELETE FROM pets WHERE id=?", id); + } + + // END of ClinicService implementation section ************************************ + + + /** + * 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()) + .addValue("description", visit.getDescription()) + .addValue("pet_id", visit.getPet().getId()); + } + + + + @Override + public List findByPetId(Integer petId) { + final List visits = this.jdbcTemplate.query( + "SELECT id, visit_date, description FROM visits WHERE pet_id=?", + new ParameterizedRowMapper() { + public Visit mapRow(ResultSet rs, int row) throws SQLException { + Visit visit = new Visit(); + visit.setId(rs.getInt("id")); + visit.setDate(rs.getTimestamp("visit_date")); + visit.setDescription(rs.getString("description")); + return visit; + } + }, + petId); + return visits; + } + + + + /** + * {@link ParameterizedRowMapper} implementation mapping data from a + * {@link ResultSet} to the corresponding properties of the {@link JdbcPet} class. + */ + private class JdbcPetRowMapper implements ParameterizedRowMapper { + + public JdbcPet mapRow(ResultSet rs, int rownum) throws SQLException { + JdbcPet pet = new JdbcPet(); + pet.setId(rs.getInt("id")); + pet.setName(rs.getString("name")); + pet.setBirthDate(rs.getDate("birth_date")); + pet.setTypeId(rs.getInt("type_id")); + pet.setOwnerId(rs.getInt("owner_id")); + return pet; + } + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/jdbc/package-info.java b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/package-info.java similarity index 62% rename from src/main/java/org/springframework/samples/petclinic/jdbc/package-info.java rename to src/main/java/org/springframework/samples/petclinic/repository/jdbc/package-info.java index 6ec278b44..edd0bf855 100644 --- a/src/main/java/org/springframework/samples/petclinic/jdbc/package-info.java +++ b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/package-info.java @@ -5,5 +5,5 @@ * of PetClinic's persistence layer. * */ -package org.springframework.samples.petclinic.jdbc; +package org.springframework.samples.petclinic.repository.jdbc; diff --git a/src/main/java/org/springframework/samples/petclinic/jpa/JpaClinicImpl.java b/src/main/java/org/springframework/samples/petclinic/repository/jpa/JpaClinicImpl.java similarity index 89% rename from src/main/java/org/springframework/samples/petclinic/jpa/JpaClinicImpl.java rename to src/main/java/org/springframework/samples/petclinic/repository/jpa/JpaClinicImpl.java index 4d198970f..361fd4b36 100644 --- a/src/main/java/org/springframework/samples/petclinic/jpa/JpaClinicImpl.java +++ b/src/main/java/org/springframework/samples/petclinic/repository/jpa/JpaClinicImpl.java @@ -1,4 +1,4 @@ -package org.springframework.samples.petclinic.jpa; +package org.springframework.samples.petclinic.repository.jpa; import java.util.Collection; @@ -6,18 +6,18 @@ import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.Query; -import org.springframework.samples.petclinic.Clinic; import org.springframework.samples.petclinic.Owner; import org.springframework.samples.petclinic.Pet; import org.springframework.samples.petclinic.PetType; import org.springframework.samples.petclinic.Vet; import org.springframework.samples.petclinic.Visit; +import org.springframework.samples.petclinic.service.ClinicService; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; import org.springframework.dao.DataAccessException; /** - * JPA implementation of the Clinic interface using EntityManager. + * JPA implementation of the ClinicService interface using EntityManager. * *

The mappings are defined in "orm.xml" located in the META-INF directory. * @@ -29,7 +29,7 @@ import org.springframework.dao.DataAccessException; */ @Repository @Transactional -public class JpaClinicImpl implements Clinic { +public class JpaClinicImpl implements ClinicService { @PersistenceContext private EntityManager em; diff --git a/src/main/java/org/springframework/samples/petclinic/repository/jpa/JpaOwnerRepositoryImpl.java b/src/main/java/org/springframework/samples/petclinic/repository/jpa/JpaOwnerRepositoryImpl.java new file mode 100644 index 000000000..73ee82ac1 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/repository/jpa/JpaOwnerRepositoryImpl.java @@ -0,0 +1,57 @@ +package org.springframework.samples.petclinic.repository.jpa; + +import java.util.Collection; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.persistence.Query; + +import org.springframework.dao.DataAccessException; +import org.springframework.samples.petclinic.Owner; +import org.springframework.samples.petclinic.Pet; +import org.springframework.samples.petclinic.PetType; +import org.springframework.samples.petclinic.Vet; +import org.springframework.samples.petclinic.Visit; +import org.springframework.samples.petclinic.repository.OwnerRepository; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; + +/** + * JPA implementation of the ClinicService interface using EntityManager. + * + *

The mappings are defined in "orm.xml" located in the META-INF directory. + * + * @author Mike Keith + * @author Rod Johnson + * @author Sam Brannen + * @author Michael Isvy + * @since 22.4.2006 + */ +@Repository +@Transactional +public class JpaOwnerRepositoryImpl implements OwnerRepository { + + @PersistenceContext + private EntityManager em; + + + @Transactional(readOnly = true) + @SuppressWarnings("unchecked") + public Collection findByLastName(String lastName) { + Query query = this.em.createQuery("SELECT owner FROM Owner owner WHERE owner.lastName LIKE :lastName"); + query.setParameter("lastName", lastName + "%"); + return query.getResultList(); + } + + @Transactional(readOnly = true) + public Owner findById(int id) { + return this.em.find(Owner.class, id); + } + + + public void save(Owner owner) { + this.em.merge(owner); + + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/jpa/SpringDataClinic.java b/src/main/java/org/springframework/samples/petclinic/repository/jpa/SpringDataClinic.java similarity index 83% rename from src/main/java/org/springframework/samples/petclinic/jpa/SpringDataClinic.java rename to src/main/java/org/springframework/samples/petclinic/repository/jpa/SpringDataClinic.java index f21a576bb..cf1af4b53 100644 --- a/src/main/java/org/springframework/samples/petclinic/jpa/SpringDataClinic.java +++ b/src/main/java/org/springframework/samples/petclinic/repository/jpa/SpringDataClinic.java @@ -1,22 +1,22 @@ -package org.springframework.samples.petclinic.jpa; +package org.springframework.samples.petclinic.repository.jpa; import java.util.Collection; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.Repository; -import org.springframework.samples.petclinic.Clinic; import org.springframework.samples.petclinic.Owner; import org.springframework.samples.petclinic.Pet; import org.springframework.samples.petclinic.PetType; import org.springframework.samples.petclinic.Vet; import org.springframework.samples.petclinic.Visit; +import org.springframework.samples.petclinic.service.ClinicService; /** * * @author Michael Isvy * @since 15.1.2013 */ -public interface SpringDataClinic extends Clinic, Repository { +public interface SpringDataClinic extends ClinicService, Repository { diff --git a/src/main/java/org/springframework/samples/petclinic/repository/jpa/SpringDataOwnerRepository.java b/src/main/java/org/springframework/samples/petclinic/repository/jpa/SpringDataOwnerRepository.java new file mode 100644 index 000000000..f32b34ced --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/repository/jpa/SpringDataOwnerRepository.java @@ -0,0 +1,13 @@ +package org.springframework.samples.petclinic.repository.jpa; + +import org.springframework.data.repository.Repository; +import org.springframework.samples.petclinic.Owner; +import org.springframework.samples.petclinic.repository.OwnerRepository; + +/** + * + * @author Michael Isvy + * @since 15.1.2013 + */ +public interface SpringDataOwnerRepository extends OwnerRepository, Repository { +} diff --git a/src/main/java/org/springframework/samples/petclinic/jpa/package-info.java b/src/main/java/org/springframework/samples/petclinic/repository/jpa/package-info.java similarity index 62% rename from src/main/java/org/springframework/samples/petclinic/jpa/package-info.java rename to src/main/java/org/springframework/samples/petclinic/repository/jpa/package-info.java index 8093784ec..13c8552ed 100644 --- a/src/main/java/org/springframework/samples/petclinic/jpa/package-info.java +++ b/src/main/java/org/springframework/samples/petclinic/repository/jpa/package-info.java @@ -5,5 +5,5 @@ * of PetClinic's persistence layer. * */ -package org.springframework.samples.petclinic.jpa; +package org.springframework.samples.petclinic.repository.jpa; diff --git a/src/main/java/org/springframework/samples/petclinic/service/ClinicService.java b/src/main/java/org/springframework/samples/petclinic/service/ClinicService.java new file mode 100644 index 000000000..24a932946 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/service/ClinicService.java @@ -0,0 +1,39 @@ +package org.springframework.samples.petclinic.service; + +import java.util.Collection; + +import org.springframework.dao.DataAccessException; +import org.springframework.samples.petclinic.Owner; +import org.springframework.samples.petclinic.Pet; +import org.springframework.samples.petclinic.PetType; +import org.springframework.samples.petclinic.Vet; +import org.springframework.samples.petclinic.Visit; + + +/** + * The high-level PetClinic business interface. + * + *

This is basically a data access object. + * PetClinic doesn't have a dedicated business facade. + * + * @author Ken Krebs + * @author Juergen Hoeller + * @author Sam Brannen + */ +public interface ClinicService { + + public Collection getPetTypes() throws DataAccessException; + + public Owner findOwnerById(int id) throws DataAccessException; + + public Pet findPetById(int id) throws DataAccessException; + + public void storePet(Pet pet) throws DataAccessException; + + public void deletePet(int id) throws DataAccessException; + + public void storeVisit(Visit visit) throws DataAccessException; + + public Collection getVets() throws DataAccessException; + +} diff --git a/src/main/java/org/springframework/samples/petclinic/service/ClinicServiceImpl.java b/src/main/java/org/springframework/samples/petclinic/service/ClinicServiceImpl.java new file mode 100644 index 000000000..b4e51e771 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/service/ClinicServiceImpl.java @@ -0,0 +1,71 @@ +package org.springframework.samples.petclinic.service; + +import java.util.Collection; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.samples.petclinic.Owner; +import org.springframework.samples.petclinic.Pet; +import org.springframework.samples.petclinic.PetType; +import org.springframework.samples.petclinic.Vet; +import org.springframework.samples.petclinic.Visit; +import org.springframework.samples.petclinic.repository.OwnerRepository; +import org.springframework.samples.petclinic.repository.PetRepository; +import org.springframework.samples.petclinic.repository.VetRepository; +import org.springframework.samples.petclinic.repository.VisitRepository; +import org.springframework.stereotype.Service; + +@Service +public class ClinicServiceImpl implements ClinicService { + + @Autowired + private PetRepository petRepository; + + @Autowired + private VetRepository vetRepository; + + @Autowired + private OwnerRepository ownerRepository; + + @Autowired + private VisitRepository visitRepository; + + public Collection getPetTypes() throws DataAccessException { + return petRepository.getPetTypes(); + } + + public Owner findOwnerById(int id) throws DataAccessException { + return ownerRepository.findById(id); + } + + public void storeVisit(Visit visit) throws DataAccessException { + visitRepository.storeVisit(visit); + } + + public Pet findPetById(int id) throws DataAccessException { + return petRepository.findById(id); + } + + public void storePet(Pet pet) throws DataAccessException { + petRepository.storePet(pet); + } + + public void deletePet(int id) throws DataAccessException { + petRepository.deletePet(id); + } + + public Collection getVets() throws DataAccessException { + return vetRepository.getVets(); + } + + + + + + + + + + + +} diff --git a/src/main/java/org/springframework/samples/petclinic/web/ClinicBindingInitializer.java b/src/main/java/org/springframework/samples/petclinic/web/ClinicBindingInitializer.java index 2d2a8bdc1..4421ce008 100644 --- a/src/main/java/org/springframework/samples/petclinic/web/ClinicBindingInitializer.java +++ b/src/main/java/org/springframework/samples/petclinic/web/ClinicBindingInitializer.java @@ -6,8 +6,8 @@ import java.util.Date; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.propertyeditors.CustomDateEditor; import org.springframework.beans.propertyeditors.StringTrimmerEditor; -import org.springframework.samples.petclinic.Clinic; import org.springframework.samples.petclinic.PetType; +import org.springframework.samples.petclinic.service.ClinicService; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.support.WebBindingInitializer; import org.springframework.web.context.request.WebRequest; @@ -24,14 +24,14 @@ import org.springframework.web.context.request.WebRequest; public class ClinicBindingInitializer implements WebBindingInitializer { @Autowired - private Clinic clinic; + private ClinicService clinicService; public void initBinder(WebDataBinder binder, WebRequest request) { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); dateFormat.setLenient(false); binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false)); binder.registerCustomEditor(String.class, new StringTrimmerEditor(false)); - binder.registerCustomEditor(PetType.class, new PetTypeEditor(this.clinic)); + binder.registerCustomEditor(PetType.class, new PetTypeEditor(this.clinicService)); } } diff --git a/src/main/java/org/springframework/samples/petclinic/web/ClinicController.java b/src/main/java/org/springframework/samples/petclinic/web/ClinicController.java deleted file mode 100644 index 8d5ea2dd0..000000000 --- a/src/main/java/org/springframework/samples/petclinic/web/ClinicController.java +++ /dev/null @@ -1,99 +0,0 @@ - -package org.springframework.samples.petclinic.web; - -import java.text.SimpleDateFormat; -import java.util.Date; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.propertyeditors.CustomDateEditor; -import org.springframework.beans.propertyeditors.StringTrimmerEditor; -import org.springframework.samples.petclinic.Clinic; -import org.springframework.samples.petclinic.PetType; -import org.springframework.samples.petclinic.Vets; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.ui.ModelMap; -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; - -/** - * Annotation-driven MultiActionController that handles all non-form - * URL's. - * - * @author Juergen Hoeller - * @author Mark Fisher - * @author Ken Krebs - * @author Arjen Poutsma - */ -@Controller -public class ClinicController { - - private final Clinic clinic; - - - @Autowired - public ClinicController(Clinic clinic) { - this.clinic = clinic; - } - - /** - * Custom handler for the welcome view. - *

- * Note that this handler relies on the RequestToViewNameTranslator to - * determine the logical view name based on the request URL: "/welcome.do" - * -> "welcome". - */ - @RequestMapping("/") - public String welcomeHandler() { - return "welcome"; - } - - /** - * Custom handler for displaying vets. - * - *

Note that this handler returns a plain {@link ModelMap} object instead of - * a ModelAndView, thus leveraging convention-based model attribute names. - * It relies on the RequestToViewNameTranslator to determine the logical - * view name based on the request URL: "/vets.do" -> "vets". - * - * @return a ModelMap with the model attributes for the view - */ - @RequestMapping("/vets") - public String showVetList(Model model) { - Vets vets = new Vets(); - vets.getVetList().addAll(this.clinic.getVets()); - model.addAttribute("vets", vets); - return "vetsList"; - } - - /** - * 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.clinic.findOwner(ownerId)); - return mav; - } - - /** - * Custom handler for displaying an list of visits. - * - * @param petId the ID of the pet whose visits to display - * @return a ModelMap with the model attributes for the view - */ - @RequestMapping(value="/owners/*/pets/{petId}/visits", method=RequestMethod.GET) - public ModelAndView visitsHandler(@PathVariable int petId) { - ModelAndView mav = new ModelAndView("visits"); - mav.addObject("visits", this.clinic.findPet(petId).getVisits()); - return mav; - } - -} diff --git a/src/main/java/org/springframework/samples/petclinic/web/OwnerController.java b/src/main/java/org/springframework/samples/petclinic/web/OwnerController.java index 7b9fb494b..a7f760a97 100644 --- a/src/main/java/org/springframework/samples/petclinic/web/OwnerController.java +++ b/src/main/java/org/springframework/samples/petclinic/web/OwnerController.java @@ -6,8 +6,8 @@ import java.util.Collection; import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.samples.petclinic.Clinic; import org.springframework.samples.petclinic.Owner; +import org.springframework.samples.petclinic.repository.OwnerRepository; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; @@ -18,6 +18,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.SessionAttributes; import org.springframework.web.bind.support.SessionStatus; +import org.springframework.web.servlet.ModelAndView; /** * JavaBean form controller that is used to handle Owners . @@ -31,12 +32,12 @@ import org.springframework.web.bind.support.SessionStatus; @SessionAttributes(types = Owner.class) public class OwnerController { - private final Clinic clinic; + private final OwnerRepository ownerRepository; @Autowired - public OwnerController(Clinic clinic) { - this.clinic = clinic; + public OwnerController(OwnerRepository ownerRepository) { + this.ownerRepository = ownerRepository; } @InitBinder @@ -57,7 +58,7 @@ public class OwnerController { return "owners/createOrUpdateOwnerForm"; } else { - this.clinic.storeOwner(owner); + this.ownerRepository.save(owner); status.setComplete(); return "redirect:/owners/" + owner.getId(); } @@ -78,7 +79,7 @@ public class OwnerController { } // find owners by last name - Collection results = this.clinic.findOwners(owner.getLastName()); + Collection results = this.ownerRepository.findByLastName(owner.getLastName()); if (results.size() < 1) { // no owners found result.rejectValue("lastName", "notFound", "not found"); @@ -98,7 +99,7 @@ public class OwnerController { @RequestMapping(value="/owners/{ownerId}/edit", method = RequestMethod.GET) public String initUpdateOwnerForm(@PathVariable("ownerId") int ownerId, Model model) { - Owner owner = this.clinic.findOwner(ownerId); + Owner owner = this.ownerRepository.findById(ownerId); model.addAttribute(owner); return "owners/createOrUpdateOwnerForm"; } @@ -109,10 +110,23 @@ public class OwnerController { return "owners/createOrUpdateOwnerForm"; } else { - this.clinic.storeOwner(owner); + this.ownerRepository.save(owner); status.setComplete(); return "redirect:/owners/" + owner.getId(); } } + + /** + * 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.ownerRepository.findById(ownerId)); + return mav; + } } diff --git a/src/main/java/org/springframework/samples/petclinic/web/PetController.java b/src/main/java/org/springframework/samples/petclinic/web/PetController.java index 55e4e9391..b440a79bf 100644 --- a/src/main/java/org/springframework/samples/petclinic/web/PetController.java +++ b/src/main/java/org/springframework/samples/petclinic/web/PetController.java @@ -4,10 +4,10 @@ package org.springframework.samples.petclinic.web; import java.util.Collection; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.samples.petclinic.Clinic; import org.springframework.samples.petclinic.Owner; import org.springframework.samples.petclinic.Pet; import org.springframework.samples.petclinic.PetType; +import org.springframework.samples.petclinic.service.ClinicService; import org.springframework.samples.petclinic.validation.PetValidator; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; @@ -33,17 +33,17 @@ import org.springframework.web.bind.support.SessionStatus; @SessionAttributes("pet") public class PetController { - private final Clinic clinic; - + private final ClinicService clinicService; + @Autowired - public PetController(Clinic clinic) { - this.clinic = clinic; + public PetController(ClinicService clinicService) { + this.clinicService = clinicService; } @ModelAttribute("types") public Collection populatePetTypes() { - return this.clinic.getPetTypes(); + return this.clinicService.getPetTypes(); } @InitBinder @@ -53,7 +53,7 @@ public class PetController { @RequestMapping(value="/owners/{ownerId}/pets/new", method = RequestMethod.GET) public String initCreationForm(@PathVariable("ownerId") int ownerId, Model model) { - Owner owner = this.clinic.findOwner(ownerId); + Owner owner = this.clinicService.findOwnerById(ownerId); Pet pet = new Pet(); owner.addPet(pet); model.addAttribute("pet", pet); @@ -67,7 +67,7 @@ public class PetController { return "pets/createOrUpdatePetForm"; } else { - this.clinic.storePet(pet); + this.clinicService.storePet(pet); status.setComplete(); return "redirect:/owners/" + pet.getOwner().getId(); } @@ -75,7 +75,7 @@ public class PetController { @RequestMapping(value="/owners/*/pets/{petId}/edit", method = RequestMethod.GET) public String initUpdateForm(@PathVariable("petId") int petId, Model model) { - Pet pet = this.clinic.findPet(petId); + Pet pet = this.clinicService.findPetById(petId); model.addAttribute("pet", pet); return "pets/createOrUpdatePetForm"; } @@ -88,7 +88,7 @@ public class PetController { return "pets/createOrUpdatePetForm"; } else { - this.clinic.storePet(pet); + this.clinicService.storePet(pet); status.setComplete(); return "redirect:/owners/" + pet.getOwner().getId(); } @@ -96,8 +96,8 @@ public class PetController { @RequestMapping(value="/owners/*/pets/{petId}/edit", method = RequestMethod.DELETE) public String deletePet(@PathVariable("petId") int petId) { - Pet pet = this.clinic.findPet(petId); - this.clinic.deletePet(petId); + Pet pet = this.clinicService.findPetById(petId); + this.clinicService.deletePet(petId); return "redirect:/owners/" + pet.getOwner().getId(); } diff --git a/src/main/java/org/springframework/samples/petclinic/web/PetTypeEditor.java b/src/main/java/org/springframework/samples/petclinic/web/PetTypeEditor.java index 812b648d7..1be37c98c 100644 --- a/src/main/java/org/springframework/samples/petclinic/web/PetTypeEditor.java +++ b/src/main/java/org/springframework/samples/petclinic/web/PetTypeEditor.java @@ -2,8 +2,8 @@ package org.springframework.samples.petclinic.web; import java.beans.PropertyEditorSupport; -import org.springframework.samples.petclinic.Clinic; import org.springframework.samples.petclinic.PetType; +import org.springframework.samples.petclinic.service.ClinicService; /** * @author Mark Fisher @@ -11,16 +11,16 @@ import org.springframework.samples.petclinic.PetType; */ public class PetTypeEditor extends PropertyEditorSupport { - private final Clinic clinic; + private final ClinicService clinicService; - public PetTypeEditor(Clinic clinic) { - this.clinic = clinic; + public PetTypeEditor(ClinicService clinicService) { + this.clinicService = clinicService; } @Override public void setAsText(String text) throws IllegalArgumentException { - for (PetType type : this.clinic.getPetTypes()) { + for (PetType type : this.clinicService.getPetTypes()) { if (type.getName().equals(text)) { setValue(type); } diff --git a/src/main/java/org/springframework/samples/petclinic/web/VetController.java b/src/main/java/org/springframework/samples/petclinic/web/VetController.java new file mode 100644 index 000000000..5bcdfa299 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/web/VetController.java @@ -0,0 +1,54 @@ + +package org.springframework.samples.petclinic.web; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.samples.petclinic.Vets; +import org.springframework.samples.petclinic.service.ClinicService; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +/** + * Annotation-driven MultiActionController that handles all non-form + * URL's. + * + * @author Juergen Hoeller + * @author Mark Fisher + * @author Ken Krebs + * @author Arjen Poutsma + */ +@Controller +public class VetController { + + private final ClinicService clinicService; + + + @Autowired + public VetController(ClinicService clinicService) { + this.clinicService = clinicService; + } + + /** + * Custom handler for displaying vets. + * + *

Note that this handler returns a plain {@link ModelMap} object instead of + * a ModelAndView, thus leveraging convention-based model attribute names. + * It relies on the RequestToViewNameTranslator to determine the logical + * view name based on the request URL: "/vets.do" -> "vets". + * + * @return a ModelMap with the model attributes for the view + */ + @RequestMapping("/vets") + public String showVetList(Model model) { + Vets vets = new Vets(); + vets.getVetList().addAll(this.clinicService.getVets()); + model.addAttribute("vets", vets); + return "vetsList"; + } + + + + + +} diff --git a/src/main/java/org/springframework/samples/petclinic/web/VisitController.java b/src/main/java/org/springframework/samples/petclinic/web/VisitController.java index 0f3874338..f093c04d6 100644 --- a/src/main/java/org/springframework/samples/petclinic/web/VisitController.java +++ b/src/main/java/org/springframework/samples/petclinic/web/VisitController.java @@ -4,9 +4,9 @@ package org.springframework.samples.petclinic.web; import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.samples.petclinic.Clinic; import org.springframework.samples.petclinic.Pet; import org.springframework.samples.petclinic.Visit; +import org.springframework.samples.petclinic.service.ClinicService; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; @@ -17,6 +17,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.SessionAttributes; import org.springframework.web.bind.support.SessionStatus; +import org.springframework.web.servlet.ModelAndView; /** * JavaBean form controller that is used to add a new Visit to the @@ -30,12 +31,12 @@ import org.springframework.web.bind.support.SessionStatus; @SessionAttributes("visit") public class VisitController { - private final Clinic clinic; + private final ClinicService clinicService; @Autowired - public VisitController(Clinic clinic) { - this.clinic = clinic; + public VisitController(ClinicService clinicService) { + this.clinicService = clinicService; } @InitBinder @@ -44,8 +45,8 @@ public class VisitController { } @RequestMapping(value="/owners/*/pets/{petId}/visits/new", method = RequestMethod.GET) - public String setupForm(@PathVariable("petId") int petId, Model model) { - Pet pet = this.clinic.findPet(petId); + public String initNewVisitForm(@PathVariable("petId") int petId, Model model) { + Pet pet = this.clinicService.findPetById(petId); Visit visit = new Visit(); pet.addVisit(visit); model.addAttribute("visit", visit); @@ -53,15 +54,28 @@ public class VisitController { } @RequestMapping(value="/owners/*/pets/{petId}/visits/new", method = RequestMethod.POST) - public String processSubmit(@Valid Visit visit, BindingResult result, SessionStatus status) { + public String processNewVisitForm(@Valid Visit visit, BindingResult result, SessionStatus status) { if (result.hasErrors()) { return "pets/createOrUpdateVisitForm"; } else { - this.clinic.storeVisit(visit); + this.clinicService.storeVisit(visit); status.setComplete(); return "redirect:/owners/" + visit.getPet().getOwner().getId(); } } + + /** + * Custom handler for displaying an list of visits. + * + * @param petId the ID of the pet whose visits to display + * @return a ModelMap with the model attributes for the view + */ + @RequestMapping(value="/owners/*/pets/{petId}/visits", method=RequestMethod.GET) + public ModelAndView showVisits(@PathVariable int petId) { + ModelAndView mav = new ModelAndView("visits"); + mav.addObject("visits", this.clinicService.findPetById(petId).getVisits()); + return mav; + } } diff --git a/src/main/java/org/springframework/samples/petclinic/web/VisitsAtomView.java b/src/main/java/org/springframework/samples/petclinic/web/VisitsAtomView.java index e9da832e4..f5f69e0fd 100644 --- a/src/main/java/org/springframework/samples/petclinic/web/VisitsAtomView.java +++ b/src/main/java/org/springframework/samples/petclinic/web/VisitsAtomView.java @@ -41,7 +41,7 @@ public class VisitsAtomView extends AbstractAtomFeedView { @Override protected void buildFeedMetadata(Map model, Feed feed, HttpServletRequest request) { feed.setId("tag:springsource.com"); - feed.setTitle("Pet Clinic Visits"); + feed.setTitle("Pet ClinicService Visits"); @SuppressWarnings("unchecked") List visits = (List) model.get("visits"); for (Visit visit : visits) { diff --git a/src/main/resources/spring/applicationContext-dao.xml b/src/main/resources/spring/applicationContext-dao.xml index 1ce97187d..69f23d977 100644 --- a/src/main/resources/spring/applicationContext-dao.xml +++ b/src/main/resources/spring/applicationContext-dao.xml @@ -96,10 +96,16 @@ - - - - + + + + + + + + + + @@ -109,12 +115,12 @@ EntityManager will be auto-injected due to @PersistenceContext. PersistenceExceptions will be auto-translated due to @Repository. --> - + - + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/petclinic-servlet.xml b/src/main/webapp/WEB-INF/petclinic-servlet.xml index d203e4a1b..c619a4f5c 100644 --- a/src/main/webapp/WEB-INF/petclinic-servlet.xml +++ b/src/main/webapp/WEB-INF/petclinic-servlet.xml @@ -13,7 +13,7 @@ - + @@ -25,6 +25,8 @@ + +