SimpleJdbcClinic.java
上传用户:dezhong
上传日期:2022-08-10
资源大小:167k
文件大小:12k
源码类别:

Java编程

开发平台:

Java

  1. package org.springframework.samples.petclinic.jdbc;
  2. import java.sql.ResultSet;
  3. import java.sql.SQLException;
  4. import java.util.ArrayList;
  5. import java.util.Collection;
  6. import java.util.List;
  7. import javax.sql.DataSource;
  8. import org.apache.commons.logging.Log;
  9. import org.apache.commons.logging.LogFactory;
  10. import org.springframework.beans.factory.annotation.Autowired;
  11. import org.springframework.dao.DataAccessException;
  12. import org.springframework.dao.EmptyResultDataAccessException;
  13. import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
  14. import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
  15. import org.springframework.jdbc.core.simple.ParameterizedBeanPropertyRowMapper;
  16. import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
  17. import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
  18. import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
  19. import org.springframework.jmx.export.annotation.ManagedOperation;
  20. import org.springframework.jmx.export.annotation.ManagedResource;
  21. import org.springframework.orm.ObjectRetrievalFailureException;
  22. import org.springframework.samples.petclinic.Clinic;
  23. import org.springframework.samples.petclinic.Owner;
  24. import org.springframework.samples.petclinic.Pet;
  25. import org.springframework.samples.petclinic.PetType;
  26. import org.springframework.samples.petclinic.Specialty;
  27. import org.springframework.samples.petclinic.Vet;
  28. import org.springframework.samples.petclinic.Visit;
  29. import org.springframework.samples.petclinic.util.EntityUtils;
  30. import org.springframework.stereotype.Service;
  31. import org.springframework.transaction.annotation.Transactional;
  32. /**
  33.  * A simple JDBC-based implementation of the {@link Clinic} interface.
  34.  *
  35.  * <p>This class uses Java 5 language features and the {@link SimpleJdbcTemplate}
  36.  * plus {@link SimpleJdbcInsert}. It also takes advantage of classes like
  37.  * {@link BeanPropertySqlParameterSource} and
  38.  * {@link ParameterizedBeanPropertyRowMapper} which provide automatic mapping
  39.  * between JavaBean properties and JDBC parameters or query results.
  40.  *
  41.  * <p>SimpleJdbcClinic is a rewrite of the AbstractJdbcClinic which was the base
  42.  * class for JDBC implementations of the Clinic interface for Spring 2.0.
  43.  *
  44.  * @author Ken Krebs
  45.  * @author Juergen Hoeller
  46.  * @author Rob Harrop
  47.  * @author Sam Brannen
  48.  * @author Thomas Risberg
  49.  * @author Mark Fisher
  50.  */
  51. @Service
  52. @ManagedResource("petclinic:type=Clinic")
  53. public class SimpleJdbcClinic implements Clinic, SimpleJdbcClinicMBean {
  54. private final Log logger = LogFactory.getLog(getClass());
  55. private SimpleJdbcTemplate simpleJdbcTemplate;
  56. private SimpleJdbcInsert insertOwner;
  57. private SimpleJdbcInsert insertPet;
  58. private SimpleJdbcInsert insertVisit;
  59. private final List<Vet> vets = new ArrayList<Vet>();
  60. @Autowired
  61. public void init(DataSource dataSource) {
  62. this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
  63. this.insertOwner = new SimpleJdbcInsert(dataSource)
  64. .withTableName("owners")
  65. .usingGeneratedKeyColumns("id");
  66. this.insertPet = new SimpleJdbcInsert(dataSource)
  67. .withTableName("pets")
  68. .usingGeneratedKeyColumns("id");
  69. this.insertVisit = new SimpleJdbcInsert(dataSource)
  70. .withTableName("visits")
  71. .usingGeneratedKeyColumns("id");
  72. }
  73. /**
  74.  * Refresh the cache of Vets that the Clinic is holding.
  75.  * @see org.springframework.samples.petclinic.Clinic#getVets()
  76.  */
  77. @ManagedOperation
  78. @Transactional(readOnly = true)
  79. public void refreshVetsCache() throws DataAccessException {
  80. synchronized (this.vets) {
  81. this.logger.info("Refreshing vets cache");
  82. // Retrieve the list of all vets.
  83. this.vets.clear();
  84. this.vets.addAll(this.simpleJdbcTemplate.query(
  85. "SELECT id, first_name, last_name FROM vets ORDER BY last_name,first_name",
  86. ParameterizedBeanPropertyRowMapper.newInstance(Vet.class)));
  87. // Retrieve the list of all possible specialties.
  88. final List<Specialty> specialties = this.simpleJdbcTemplate.query(
  89. "SELECT id, name FROM specialties",
  90. ParameterizedBeanPropertyRowMapper.newInstance(Specialty.class));
  91. // Build each vet's list of specialties.
  92. for (Vet vet : this.vets) {
  93. final List<Integer> vetSpecialtiesIds = this.simpleJdbcTemplate.query(
  94. "SELECT specialty_id FROM vet_specialties WHERE vet_id=?",
  95. new ParameterizedRowMapper<Integer>() {
  96. public Integer mapRow(ResultSet rs, int row) throws SQLException {
  97. return Integer.valueOf(rs.getInt(1));
  98. }},
  99. vet.getId().intValue());
  100. for (int specialtyId : vetSpecialtiesIds) {
  101. Specialty specialty = EntityUtils.getById(specialties, Specialty.class, specialtyId);
  102. vet.addSpecialty(specialty);
  103. }
  104. }
  105. }
  106. }
  107. // START of Clinic implementation section *******************************
  108. @Transactional(readOnly = true)
  109. public Collection<Vet> getVets() throws DataAccessException {
  110. synchronized (this.vets) {
  111. if (this.vets.isEmpty()) {
  112. refreshVetsCache();
  113. }
  114. return this.vets;
  115. }
  116. }
  117. @Transactional(readOnly = true)
  118. public Collection<PetType> getPetTypes() throws DataAccessException {
  119. return this.simpleJdbcTemplate.query(
  120. "SELECT id, name FROM types ORDER BY name",
  121. ParameterizedBeanPropertyRowMapper.newInstance(PetType.class));
  122. }
  123. /**
  124.  * Loads {@link Owner Owners} from the data store by last name, returning
  125.  * all owners whose last name <i>starts</i> with the given name; also loads
  126.  * the {@link Pet Pets} and {@link Visit Visits} for the corresponding
  127.  * owners, if not already loaded.
  128.  */
  129. @Transactional(readOnly = true)
  130. public Collection<Owner> findOwners(String lastName) throws DataAccessException {
  131. List<Owner> owners = this.simpleJdbcTemplate.query(
  132. "SELECT id, first_name, last_name, address, city, telephone FROM owners WHERE last_name like ?",
  133. ParameterizedBeanPropertyRowMapper.newInstance(Owner.class),
  134. lastName + "%");
  135. loadOwnersPetsAndVisits(owners);
  136. return owners;
  137. }
  138. /**
  139.  * Loads the {@link Owner} with the supplied <code>id</code>; also loads
  140.  * the {@link Pet Pets} and {@link Visit Visits} for the corresponding
  141.  * owner, if not already loaded.
  142.  */
  143. @Transactional(readOnly = true)
  144. public Owner loadOwner(int id) throws DataAccessException {
  145. Owner owner;
  146. try {
  147. owner = this.simpleJdbcTemplate.queryForObject(
  148. "SELECT id, first_name, last_name, address, city, telephone FROM owners WHERE id=?",
  149. ParameterizedBeanPropertyRowMapper.newInstance(Owner.class),
  150. id);
  151. }
  152. catch (EmptyResultDataAccessException ex) {
  153. throw new ObjectRetrievalFailureException(Owner.class, new Integer(id));
  154. }
  155. loadPetsAndVisits(owner);
  156. return owner;
  157. }
  158. @Transactional(readOnly = true)
  159. public Pet loadPet(int id) throws DataAccessException {
  160. JdbcPet pet;
  161. try {
  162. pet = this.simpleJdbcTemplate.queryForObject(
  163. "SELECT id, name, birth_date, type_id, owner_id FROM pets WHERE id=?",
  164. new JdbcPetRowMapper(),
  165. id);
  166. }
  167. catch (EmptyResultDataAccessException ex) {
  168. throw new ObjectRetrievalFailureException(Pet.class, new Integer(id));
  169. }
  170. Owner owner = loadOwner(pet.getOwnerId());
  171. owner.addPet(pet);
  172. pet.setType(EntityUtils.getById(getPetTypes(), PetType.class, pet.getTypeId()));
  173. loadVisits(pet);
  174. return pet;
  175. }
  176. @Transactional
  177. public void storeOwner(Owner owner) throws DataAccessException {
  178. if (owner.isNew()) {
  179. Number newKey = this.insertOwner.executeAndReturnKey(
  180. new BeanPropertySqlParameterSource(owner));
  181. owner.setId(newKey.intValue());
  182. }
  183. else {
  184. this.simpleJdbcTemplate.update(
  185. "UPDATE owners SET first_name=:firstName, last_name=:lastName, address=:address, " +
  186. "city=:city, telephone=:telephone WHERE id=:id",
  187. new BeanPropertySqlParameterSource(owner));
  188. }
  189. }
  190. @Transactional
  191. public void storePet(Pet pet) throws DataAccessException {
  192. if (pet.isNew()) {
  193. Number newKey = this.insertPet.executeAndReturnKey(
  194. createPetParameterSource(pet));
  195. pet.setId(newKey.intValue());
  196. }
  197. else {
  198. this.simpleJdbcTemplate.update(
  199. "UPDATE pets SET name=:name, birth_date=:birth_date, type_id=:type_id, " +
  200. "owner_id=:owner_id WHERE id=:id",
  201. createPetParameterSource(pet));
  202. }
  203. }
  204. @Transactional
  205. public void storeVisit(Visit visit) throws DataAccessException {
  206. if (visit.isNew()) {
  207. Number newKey = this.insertVisit.executeAndReturnKey(
  208. createVisitParameterSource(visit));
  209. visit.setId(newKey.intValue());
  210. }
  211. else {
  212. throw new UnsupportedOperationException("Visit update not supported");
  213. }
  214. }
  215. // END of Clinic implementation section ************************************
  216. /**
  217.  * Creates a {@link MapSqlParameterSource} based on data values from the
  218.  * supplied {@link Pet} instance.
  219.  */
  220. private MapSqlParameterSource createPetParameterSource(Pet pet) {
  221. return new MapSqlParameterSource()
  222. .addValue("id", pet.getId())
  223. .addValue("name", pet.getName())
  224. .addValue("birth_date", pet.getBirthDate())
  225. .addValue("type_id", pet.getType().getId())
  226. .addValue("owner_id", pet.getOwner().getId());
  227. }
  228. /**
  229.  * Creates a {@link MapSqlParameterSource} based on data values from the
  230.  * supplied {@link Visit} instance.
  231.  */
  232. private MapSqlParameterSource createVisitParameterSource(Visit visit) {
  233. return new MapSqlParameterSource()
  234. .addValue("id", visit.getId())
  235. .addValue("visit_date", visit.getDate())
  236. .addValue("description", visit.getDescription())
  237. .addValue("pet_id", visit.getPet().getId());
  238. }
  239. /**
  240.  * Loads the {@link Visit} data for the supplied {@link Pet}.
  241.  */
  242. private void loadVisits(JdbcPet pet) {
  243. final List<Visit> visits = this.simpleJdbcTemplate.query(
  244. "SELECT id, visit_date, description FROM visits WHERE pet_id=?",
  245. new ParameterizedRowMapper<Visit>() {
  246. public Visit mapRow(ResultSet rs, int row) throws SQLException {
  247. Visit visit = new Visit();
  248. visit.setId(rs.getInt("id"));
  249. visit.setDate(rs.getTimestamp("visit_date"));
  250. visit.setDescription(rs.getString("description"));
  251. return visit;
  252. }
  253. },
  254. pet.getId().intValue());
  255. for (Visit visit : visits) {
  256. pet.addVisit(visit);
  257. }
  258. }
  259. /**
  260.  * Loads the {@link Pet} and {@link Visit} data for the supplied
  261.  * {@link Owner}.
  262.  */
  263. private void loadPetsAndVisits(final Owner owner) {
  264. final List<JdbcPet> pets = this.simpleJdbcTemplate.query(
  265. "SELECT id, name, birth_date, type_id, owner_id FROM pets WHERE owner_id=?",
  266. new JdbcPetRowMapper(),
  267. owner.getId().intValue());
  268. for (JdbcPet pet : pets) {
  269. owner.addPet(pet);
  270. pet.setType(EntityUtils.getById(getPetTypes(), PetType.class, pet.getTypeId()));
  271. loadVisits(pet);
  272. }
  273. }
  274. /**
  275.  * Loads the {@link Pet} and {@link Visit} data for the supplied
  276.  * {@link List} of {@link Owner Owners}.
  277.  *
  278.  * @param owners the list of owners for whom the pet and visit data should be loaded
  279.  * @see #loadPetsAndVisits(Owner)
  280.  */
  281. private void loadOwnersPetsAndVisits(List<Owner> owners) {
  282. for (Owner owner : owners) {
  283. loadPetsAndVisits(owner);
  284. }
  285. }
  286. /**
  287.  * {@link ParameterizedRowMapper} implementation mapping data from a
  288.  * {@link ResultSet} to the corresponding properties of the {@link JdbcPet} class.
  289.  */
  290. private class JdbcPetRowMapper implements ParameterizedRowMapper<JdbcPet> {
  291. public JdbcPet mapRow(ResultSet rs, int rownum) throws SQLException {
  292. JdbcPet pet = new JdbcPet();
  293. pet.setId(rs.getInt("id"));
  294. pet.setName(rs.getString("name"));
  295. pet.setBirthDate(rs.getDate("birth_date"));
  296. pet.setTypeId(rs.getInt("type_id"));
  297. pet.setOwnerId(rs.getInt("owner_id"));
  298. return pet;
  299. }
  300. }
  301. }