SPRING IN ACTION 第4版笔记-第十一章Persisting data with object-relational mapping-004JPA例子的代码
一、结构
二、Repository层
1.
1 package spittr.db; 2 3 import java.util.List; 4 5 import spittr.domain.Spitter; 6 7 /** 8 * Repository interface with operations for {@link Spitter} persistence. 9 * @author habuma 10 */ 11 public interface SpitterRepository { 12 13 long count(); 14 15 Spitter save(Spitter spitter); 16 17 Spitter findOne(long id); 18 19 Spitter findByUsername(String username); 20 21 List<Spitter> findAll(); 22 23 }
2.
1 package spittr.db; 2 3 import java.util.List; 4 5 import spittr.domain.Spittle; 6 7 /** 8 * Repository interface with operations for {@link Spittle} persistence. 9 * @author habuma 10 */ 11 public interface SpittleRepository { 12 13 long count(); 14 15 List<Spittle> findRecent(); 16 17 List<Spittle> findRecent(int count); 18 19 Spittle findOne(long id); 20 21 Spittle save(Spittle spittle); 22 23 List<Spittle> findBySpitterId(long spitterId); 24 25 void delete(long id); 26 27 }
3.
1 package spittr.db.jpa; 2 3 import java.util.List; 4 5 import javax.persistence.EntityManager; 6 import javax.persistence.PersistenceContext; 7 8 import org.springframework.stereotype.Repository; 9 10 import spittr.db.SpitterRepository; 11 import spittr.domain.Spitter; 12 13 @Repository 14 public class JpaSpitterRepository implements SpitterRepository { 15 16 @PersistenceContext 17 private EntityManager entityManager; 18 19 public long count() { 20 return findAll().size(); 21 } 22 23 public Spitter save(Spitter spitter) { 24 entityManager.persist(spitter); 25 return spitter; 26 } 27 28 public Spitter findOne(long id) { 29 return entityManager.find(Spitter.class, id); 30 } 31 32 public Spitter findByUsername(String username) { 33 return (Spitter) entityManager.createQuery("select s from Spitter s where s.username=?").setParameter(1, username).getSingleResult(); 34 } 35 36 public List<Spitter> findAll() { 37 return (List<Spitter>) entityManager.createQuery("select s from Spitter s").getResultList(); 38 } 39 40 }
4.
1 package spittr.db.jpa; 2 3 import java.util.List; 4 5 import javax.persistence.EntityManager; 6 import javax.persistence.PersistenceContext; 7 8 import org.springframework.stereotype.Repository; 9 10 import spittr.db.SpittleRepository; 11 import spittr.domain.Spittle; 12 13 @Repository 14 public class JpaSpittleRepository implements SpittleRepository { 15 16 @PersistenceContext 17 private EntityManager entityManager; 18 19 public long count() { 20 return findAll().size(); 21 } 22 23 public List<Spittle> findRecent() { 24 return findRecent(10); 25 } 26 27 public List<Spittle> findRecent(int count) { 28 return (List<Spittle>) entityManager.createQuery("select s from Spittle s order by s.postedTime desc") 29 .setMaxResults(count) 30 .getResultList(); 31 } 32 33 public Spittle findOne(long id) { 34 return entityManager.find(Spittle.class, id); 35 } 36 37 public Spittle save(Spittle spittle) { 38 entityManager.persist(spittle); 39 return spittle; 40 } 41 42 public List<Spittle> findBySpitterId(long spitterId) { 43 return (List<Spittle>) entityManager.createQuery("select s from Spittle s, Spitter sp where s.spitter = sp and sp.id=? order by s.postedTime desc") 44 .setParameter(1, spitterId) 45 .getResultList(); 46 } 47 48 public void delete(long id) { 49 entityManager.remove(findOne(id)); 50 } 51 52 public List<Spittle> findAll() { 53 return (List<Spittle>) entityManager.createQuery("select s from Spittle s").getResultList(); 54 } 55 56 }
三、domain层
1.
1 package spittr.domain; 2 3 import javax.persistence.Column; 4 import javax.persistence.Entity; 5 import javax.persistence.GeneratedValue; 6 import javax.persistence.GenerationType; 7 import javax.persistence.Id; 8 9 10 @Entity 11 public class Spitter { 12 13 private Spitter() {} 14 15 @Id 16 @GeneratedValue(strategy=GenerationType.IDENTITY) 17 private Long id; 18 19 @Column(name="username") 20 private String username; 21 22 @Column(name="password") 23 private String password; 24 25 @Column(name="fullname") 26 private String fullName; 27 28 @Column(name="email") 29 private String email; 30 31 @Column(name="updateByEmail") 32 private boolean updateByEmail; 33 34 public Spitter(Long id, String username, String password, String fullName, String email, boolean updateByEmail) { 35 this.id = id; 36 this.username = username; 37 this.password = password; 38 this.fullName = fullName; 39 this.email = email; 40 this.updateByEmail = updateByEmail; 41 } 42 43 public Long getId() { 44 return id; 45 } 46 47 public String getUsername() { 48 return username; 49 } 50 51 public String getPassword() { 52 return password; 53 } 54 55 public String getFullName() { 56 return fullName; 57 } 58 59 public String getEmail() { 60 return email; 61 } 62 63 public boolean isUpdateByEmail() { 64 return updateByEmail; 65 } 66 67 }
2.
1 package spittr.domain; 2 3 import java.util.Date; 4 5 import javax.persistence.Column; 6 import javax.persistence.Entity; 7 import javax.persistence.GeneratedValue; 8 import javax.persistence.GenerationType; 9 import javax.persistence.Id; 10 import javax.persistence.JoinColumn; 11 import javax.persistence.ManyToOne; 12 13 @Entity 14 public class Spittle { 15 16 private Spittle() {} 17 18 @Id 19 @GeneratedValue(strategy=GenerationType.IDENTITY) 20 private Long id; 21 22 @ManyToOne 23 @JoinColumn(name="spitter") 24 private Spitter spitter; 25 26 @Column 27 private String message; 28 29 @Column 30 private Date postedTime; 31 32 public Spittle(Long id, Spitter spitter, String message, Date postedTime) { 33 this.id = id; 34 this.spitter = spitter; 35 this.message = message; 36 this.postedTime = postedTime; 37 } 38 39 public Long getId() { 40 return this.id; 41 } 42 43 public String getMessage() { 44 return this.message; 45 } 46 47 public Date getPostedTime() { 48 return this.postedTime; 49 } 50 51 public Spitter getSpitter() { 52 return this.spitter; 53 } 54 55 }
四、配置文件及数据库文件
1.
1 package spittr.db.jpa; 2 3 import javax.inject.Inject; 4 import javax.persistence.EntityManagerFactory; 5 import javax.sql.DataSource; 6 7 import org.springframework.context.annotation.Bean; 8 import org.springframework.context.annotation.ComponentScan; 9 import org.springframework.context.annotation.Configuration; 10 import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase; 11 import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; 12 import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; 13 import org.springframework.orm.jpa.JpaTransactionManager; 14 import org.springframework.orm.jpa.JpaVendorAdapter; 15 import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; 16 import org.springframework.orm.jpa.vendor.Database; 17 import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; 18 import org.springframework.transaction.PlatformTransactionManager; 19 import org.springframework.transaction.annotation.EnableTransactionManagement; 20 import org.springframework.transaction.annotation.TransactionManagementConfigurer; 21 22 @Configuration 23 @ComponentScan 24 public class JpaConfig { 25 26 @Bean 27 public DataSource dataSource() { 28 EmbeddedDatabaseBuilder edb = new EmbeddedDatabaseBuilder(); 29 edb.setType(EmbeddedDatabaseType.H2); 30 edb.addScript("spittr/db/jpa/schema.sql"); 31 edb.addScript("spittr/db/jpa/test-data.sql"); 32 EmbeddedDatabase embeddedDatabase = edb.build(); 33 return embeddedDatabase; 34 } 35 36 @Bean 37 public LocalContainerEntityManagerFactoryBean emf(DataSource dataSource, JpaVendorAdapter jpaVendorAdapter) { 38 LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean(); 39 emf.setDataSource(dataSource); 40 emf.setPersistenceUnitName("spittr"); 41 emf.setJpaVendorAdapter(jpaVendorAdapter); 42 emf.setPackagesToScan("spittr.domain"); 43 return emf; 44 } 45 46 @Bean 47 public JpaVendorAdapter jpaVendorAdapter() { 48 HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter(); 49 adapter.setDatabase(Database.H2); 50 adapter.setShowSql(true); 51 adapter.setGenerateDdl(false); 52 adapter.setDatabasePlatform("org.hibernate.dialect.H2Dialect"); 53 return adapter; 54 } 55 56 57 @Configuration 58 @EnableTransactionManagement 59 public static class TransactionConfig implements TransactionManagementConfigurer { 60 @Inject 61 private EntityManagerFactory emf; 62 63 public PlatformTransactionManager annotationDrivenTransactionManager() { 64 JpaTransactionManager transactionManager = new JpaTransactionManager(); 65 transactionManager.setEntityManagerFactory(emf); 66 return transactionManager; 67 } 68 } 69 }
2.RepositoryTest-context.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jdbc="http://www.springframework.org/schema/jdbc" 4 xmlns:c="http://www.springframework.org/schema/c" xmlns:context="http://www.springframework.org/schema/context" 5 xmlns:p="http://www.springframework.org/schema/p" 6 xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd 7 http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 8 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd"> 9 10 11 <context:component-scan base-package="spittr.db.jpa" /> 12 13 <bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" 14 p:dataSource-ref="dataSource" 15 p:persistenceUnitName="spittr" 16 p:jpaVendorAdapter-ref="jpaVendorAdapter" 17 p:packagesToScan="spittr.domain" /> 18 19 <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> 20 <property name="database" value="H2" /> 21 <property name="showSql" value="true" /> 22 <property name="generateDdl" value="false" /> 23 <property name="databasePlatform" value="org.hibernate.dialect.H2Dialect" /> 24 </bean> 25 26 <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" 27 p:entityManagerFactory-ref="emf" /> 28 29 <jdbc:embedded-database id="dataSource" type="H2"> 30 <jdbc:script location="spittr/db/jpa/schema.sql" /> 31 <jdbc:script location="spittr/db/jpa/test-data.sql" /> 32 </jdbc:embedded-database> 33 34 </beans>
3.schema.sql
1 drop table if exists spittle; 2 drop table if exists spitter; 3 4 create table spitter ( 5 id identity, 6 username varchar(25) not null, 7 password varchar(25) not null, 8 fullName varchar(100) not null, 9 email varchar(50) not null, 10 updateByEmail boolean not null 11 ); 12 13 create table spittle ( 14 id integer identity primary key, 15 spitter integer not null, 16 message varchar(2000) not null, 17 postedTime datetime not null, 18 foreign key (spitter) references spitter(id) 19 );
4.test-data.sql
1 insert into Spitter (username, password, fullname, email, updateByEmail) values ('habuma', 'password', 'Craig Walls', 'craig@habuma.com', false); 2 insert into Spitter (username, password, fullname, email, updateByEmail) values ('mwalls', 'password', 'Michael Walls', 'mwalls@habuma.com', true); 3 insert into Spitter (username, password, fullname, email, updateByEmail) values ('chuck', 'password', 'Chuck Wagon', 'chuck@habuma.com', false); 4 insert into Spitter (username, password, fullname, email, updateByEmail) values ('artnames', 'password', 'Art Names', 'art@habuma.com', true); 5 6 insert into Spittle (spitter, message, postedTime) values (1, 'This is a test spittle message', '2012-06-09 22:00:00Z'); 7 insert into Spittle (spitter, message, postedTime) values (1, 'This is another test spittle message', '2012-06-09 22:10:00Z'); 8 insert into Spittle (spitter, message, postedTime) values (1, 'This is a third test spittle message', '2012-07-04 23:30:00Z'); 9 insert into Spittle (spitter, message, postedTime) values (2, 'Hello from Chuck!', '2012-03-25 12:15:00Z'); 10 insert into Spittle (spitter, message, postedTime) values (4, 'Hello from Art!', '2012-03-25 12:15:00Z'); 11 insert into Spittle (spitter, message, postedTime) values (4, 'Hello again from Art!', '2012-03-25 12:25:00Z'); 12 insert into Spittle (spitter, message, postedTime) values (4, 'Hola from Arthur!', '2012-03-25 12:35:00Z'); 13 insert into Spittle (spitter, message, postedTime) values (4, 'Buenos Dias from Art!', '2012-03-25 12:45:00Z'); 14 insert into Spittle (spitter, message, postedTime) values (4, 'Ni Hao from Art!', '2012-03-25 12:55:00Z'); 15 insert into Spittle (spitter, message, postedTime) values (4, 'Guten Tag from Art!', '2012-03-25 13:05:00Z'); 16 insert into Spittle (spitter, message, postedTime) values (4, 'Konnichi wa from Art!', '2012-03-25 13:15:00Z'); 17 insert into Spittle (spitter, message, postedTime) values (4, 'Buon giorno from Art!', '2012-03-25 13:25:00Z'); 18 insert into Spittle (spitter, message, postedTime) values (4, 'Bonjour from Art!', '2012-03-25 13:35:00Z'); 19 insert into Spittle (spitter, message, postedTime) values (4, 'Aloha from Art!', '2012-03-25 13:45:00Z'); 20 insert into Spittle (spitter, message, postedTime) values (4, 'God dag from Art!', '2012-03-25 13:55:00Z');
5.log4j.properties
1 log4j.rootCategory=INFO, stdout 2 3 log4j.appender.stdout=org.apache.log4j.ConsoleAppender 4 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 5 log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %40.40c:%4L - %m%n
五、测试文件
1.
1 package spittr.db.jpa; 2 3 import static org.junit.Assert.*; 4 5 import java.util.List; 6 7 import org.junit.BeforeClass; 8 import org.junit.Ignore; 9 import org.junit.Test; 10 import org.junit.runner.RunWith; 11 import org.springframework.beans.factory.annotation.Autowired; 12 import org.springframework.test.context.ContextConfiguration; 13 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 14 import org.springframework.transaction.annotation.Transactional; 15 16 import spittr.db.SpitterRepository; 17 import spittr.domain.Spitter; 18 19 @RunWith(SpringJUnit4ClassRunner.class) 20 @ContextConfiguration(classes=JpaConfig.class) 21 public class SpitterRepositoryTest { 22 23 @Autowired 24 SpitterRepository spitterRepository; 25 26 @Test 27 @Transactional 28 public void count() { 29 assertEquals(4, spitterRepository.count()); 30 } 31 32 @Test 33 @Transactional 34 public void findAll() { 35 List<Spitter> spitters = spitterRepository.findAll(); 36 assertEquals(4, spitters.size()); 37 assertSpitter(0, spitters.get(0)); 38 assertSpitter(1, spitters.get(1)); 39 assertSpitter(2, spitters.get(2)); 40 assertSpitter(3, spitters.get(3)); 41 } 42 43 @Test 44 @Transactional 45 public void findByUsername() { 46 assertSpitter(0, spitterRepository.findByUsername("habuma")); 47 assertSpitter(1, spitterRepository.findByUsername("mwalls")); 48 assertSpitter(2, spitterRepository.findByUsername("chuck")); 49 assertSpitter(3, spitterRepository.findByUsername("artnames")); 50 } 51 52 @Test 53 @Transactional 54 public void findOne() { 55 assertSpitter(0, spitterRepository.findOne(1L)); 56 assertSpitter(1, spitterRepository.findOne(2L)); 57 assertSpitter(2, spitterRepository.findOne(3L)); 58 assertSpitter(3, spitterRepository.findOne(4L)); 59 } 60 61 @Test 62 @Transactional 63 public void save_newSpitter() { 64 assertEquals(4, spitterRepository.count()); 65 Spitter spitter = new Spitter(null, "newbee", "letmein", "New Bee", "newbee@habuma.com", true); 66 Spitter saved = spitterRepository.save(spitter); 67 assertEquals(5, spitterRepository.count()); 68 assertSpitter(4, saved); 69 assertSpitter(4, spitterRepository.findOne(5L)); 70 } 71 72 @Test 73 @Transactional 74 @Ignore 75 public void save_existingSpitter() { 76 assertEquals(4, spitterRepository.count()); 77 Spitter spitter = new Spitter(4L, "arthur", "letmein", "Arthur Names", "arthur@habuma.com", false); 78 Spitter saved = spitterRepository.save(spitter); 79 assertSpitter(5, saved); 80 assertEquals(4, spitterRepository.count()); 81 Spitter updated = spitterRepository.findOne(4L); 82 assertSpitter(5, updated); 83 } 84 85 private static void assertSpitter(int expectedSpitterIndex, Spitter actual) { 86 assertSpitter(expectedSpitterIndex, actual, "Newbie"); 87 } 88 89 private static void assertSpitter(int expectedSpitterIndex, Spitter actual, String expectedStatus) { 90 Spitter expected = SPITTERS[expectedSpitterIndex]; 91 assertEquals(expected.getId(), actual.getId()); 92 assertEquals(expected.getUsername(), actual.getUsername()); 93 assertEquals(expected.getPassword(), actual.getPassword()); 94 assertEquals(expected.getFullName(), actual.getFullName()); 95 assertEquals(expected.getEmail(), actual.getEmail()); 96 assertEquals(expected.isUpdateByEmail(), actual.isUpdateByEmail()); 97 } 98 99 private static Spitter[] SPITTERS = new Spitter[6]; 100 101 @BeforeClass 102 public static void before() { 103 SPITTERS[0] = new Spitter(1L, "habuma", "password", "Craig Walls", "craig@habuma.com", false); 104 SPITTERS[1] = new Spitter(2L, "mwalls", "password", "Michael Walls", "mwalls@habuma.com", true); 105 SPITTERS[2] = new Spitter(3L, "chuck", "password", "Chuck Wagon", "chuck@habuma.com", false); 106 SPITTERS[3] = new Spitter(4L, "artnames", "password", "Art Names", "art@habuma.com", true); 107 SPITTERS[4] = new Spitter(5L, "newbee", "letmein", "New Bee", "newbee@habuma.com", true); 108 SPITTERS[5] = new Spitter(4L, "arthur", "letmein", "Arthur Names", "arthur@habuma.com", false); 109 } 110 111 }
2.
1 package spittr.db.jpa; 2 3 import static org.junit.Assert.*; 4 5 import java.util.Date; 6 import java.util.List; 7 8 import org.junit.Test; 9 import org.junit.runner.RunWith; 10 import org.springframework.beans.factory.annotation.Autowired; 11 import org.springframework.test.context.ContextConfiguration; 12 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 13 import org.springframework.transaction.annotation.Transactional; 14 15 import spittr.db.SpittleRepository; 16 import spittr.domain.Spitter; 17 import spittr.domain.Spittle; 18 19 @RunWith(SpringJUnit4ClassRunner.class) 20 //@ContextConfiguration("classpath:spittr/db/jpa/RepositoryTest-context.xml") 21 @ContextConfiguration(classes=JpaConfig.class) 22 public class SpittleRepositoryTest { 23 24 @Autowired 25 SpittleRepository spittleRepository; 26 27 @Test 28 @Transactional 29 public void count() { 30 assertEquals(15, spittleRepository.count()); 31 } 32 33 @Test 34 @Transactional 35 public void findRecent() { 36 // default case 37 { 38 List<Spittle> recent = spittleRepository.findRecent(); 39 assertRecent(recent, 10); 40 } 41 42 // specific count case 43 { 44 List<Spittle> recent = spittleRepository.findRecent(5); 45 assertRecent(recent, 5); 46 } 47 } 48 49 @Test 50 @Transactional 51 public void findOne() { 52 Spittle thirteen = spittleRepository.findOne(13); 53 assertEquals(13, thirteen.getId().longValue()); 54 assertEquals("Bonjour from Art!", thirteen.getMessage()); 55 assertEquals(1332682500000L, thirteen.getPostedTime().getTime()); 56 assertEquals(4, thirteen.getSpitter().getId().longValue()); 57 assertEquals("artnames", thirteen.getSpitter().getUsername()); 58 assertEquals("password", thirteen.getSpitter().getPassword()); 59 assertEquals("Art Names", thirteen.getSpitter().getFullName()); 60 assertEquals("art@habuma.com", thirteen.getSpitter().getEmail()); 61 assertTrue(thirteen.getSpitter().isUpdateByEmail()); 62 } 63 64 @Test 65 @Transactional 66 public void findBySpitter() { 67 List<Spittle> spittles = spittleRepository.findBySpitterId(4L); 68 assertEquals(11, spittles.size()); 69 for (int i = 0; i < 11; i++) { 70 assertEquals(15-i, spittles.get(i).getId().longValue()); 71 } 72 } 73 74 @Test 75 @Transactional 76 public void save() { 77 assertEquals(15, spittleRepository.count()); 78 Spitter spitter = spittleRepository.findOne(13).getSpitter(); 79 Spittle spittle = new Spittle(null, spitter, "Un Nuevo Spittle from Art", new Date()); 80 Spittle saved = spittleRepository.save(spittle); 81 assertEquals(16, spittleRepository.count()); 82 assertNewSpittle(saved); 83 assertNewSpittle(spittleRepository.findOne(16L)); 84 } 85 86 @Test 87 @Transactional 88 public void delete() { 89 assertEquals(15, spittleRepository.count()); 90 assertNotNull(spittleRepository.findOne(13)); 91 spittleRepository.delete(13L); 92 assertEquals(14, spittleRepository.count()); 93 assertNull(spittleRepository.findOne(13)); 94 } 95 96 private void assertRecent(List<Spittle> recent, int count) { 97 long[] recentIds = new long[] {3,2,1,15,14,13,12,11,10,9}; 98 assertEquals(count, recent.size()); 99 for (int i = 0; i < count; i++) { 100 assertEquals(recentIds[i], recent.get(i).getId().longValue()); 101 } 102 } 103 104 private void assertNewSpittle(Spittle spittle) { 105 assertEquals(16, spittle.getId().longValue()); 106 } 107 108 }
You can do anything you set your mind to, man!