個人Spring Data Jpa教程的第一部分描述了,如何配置Spring Data JPA,本博文進一步描述怎樣使用Spring Data JPA建立一個簡單的CRUD應用。該應用要求以下:html
如今我已經描述了建立的應用的要求,如今開始工做並實現它。java
CRUD應用的實現能夠分割成以下步驟:git
下面詳細解釋每一步驟.github
Person 類的實現是至關簡單的,不過有幾個問題我須要指出:web
個人 Person 類的源碼以下:spring
import org.apache.commons.lang.builder.ToStringBuilder; import javax.persistence.*; /** * An entity class which contains the information of a single person. * @author Petri Kainulainen */ @Entity @Table(name = "persons") public class Person { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @Column(name = "creation_time", nullable = false) private Date creationTime; @Column(name = "first_name", nullable = false) private String firstName; @Column(name = "last_name", nullable = false) private String lastName; @Column(name = "modification_time", nullable = false) private Date modificationTime; @Version private long version = 0; public Long getId() { return id; } /** * Gets a builder which is used to create Person objects. * @param firstName The first name of the created user. * @param lastName The last name of the created user. * @return A new Builder instance. */ public static Builder getBuilder(String firstName, String lastName) { return new Builder(firstName, lastName); } public Date getCreationTime() { return creationTime; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } /** * Gets the full name of the person. * @return The full name of the person. */ @Transient public String getName() { StringBuilder name = new StringBuilder(); name.append(firstName); name.append(" "); name.append(lastName); return name.toString(); } public Date getModificationTime() { return modificationTime; } public long getVersion() { return version; } public void update(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } @PreUpdate public void preUpdate() { modificationTime = new Date(); } @PrePersist public void prePersist() { Date now = new Date(); creationTime = now; modificationTime = now; } @Override public String toString() { return ToStringBuilder.reflectionToString(this); } /** * A Builder class used to create new Person objects. */ public static class Builder { Person built; /** * Creates a new Builder instance. * @param firstName The first name of the created Person object. * @param lastName The last name of the created Person object. */ Builder(String firstName, String lastName) { built = new Person(); built.firstName = firstName; built.lastName = lastName; } /** * Builds the new Person object. * @return The created Person object. */ public Person build() { return built; } } /** * This setter method should only be used by unit tests. * @param id */ protected void setId(Long id) { this.id = id; } }
實現一個爲Person模型對象提供CRUD操做的repository是至關簡略的,你所要作的就是常見一個繼承自JpaRepository接口的接口。 JpaRepository接口是向Repository接口的JPA規範擴展,給你訪問以下方法,它們用於實現CRUD應用.數據庫
個人PersonRepository 接口源碼以下:apache
import org.springframework.data.jpa.repository.JpaRepository; /** * Specifies methods used to obtain and modify person related information * which is stored in the database. * @author Petri Kainulainen */ public interface PersonRepository extends JpaRepository<Person, Long> { }
你如今已經建立model對象和與數據庫交互須要的repository,下一步是實現服務類,它是控制器和實現repository之間的中介,服務層的結構下一步描述api
PersonDTO是一個簡單的DTO對象,在個人示例應用中用於form對象,它的源碼以下app
import org.apache.commons.lang.builder.ToStringBuilder; import org.hibernate.validator.constraints.NotEmpty; /** * A DTO object which is used as a form object * in create person and edit person forms. * @author Petri Kainulainen */ public class PersonDTO { private Long id; @NotEmpty private String firstName; @NotEmpty private String lastName; public PersonDTO() { } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } @Override public String toString() { return ToStringBuilder.reflectionToString(this); } }
PersonService接口聲明實際實現提供的方法,它的源碼以下:
/** * Declares methods used to obtain and modify person information. * @author Petri Kainulainen */ public interface PersonService { /** * Creates a new person. * @param created The information of the created person. * @return The created person. */ public Person create(PersonDTO created); /** * Deletes a person. * @param personId The id of the deleted person. * @return The deleted person. * @throws PersonNotFoundException if no person is found with the given id. */ public Person delete(Long personId) throws PersonNotFoundException; /** * Finds all persons. * @return A list of persons. */ public List<Person> findAll(); /** * Finds person by id. * @param id The id of the wanted person. * @return The found person. If no person is found, this method returns null. */ public Person findById(Long id); /** * Updates the information of a person. * @param updated The information of the updated person. * @return The updated person. * @throws PersonNotFoundException if no person is found with given id. */ public Person update(PersonDTO updated) throws PersonNotFoundException; }
RepositoryPersonService類實現PersonService接口,其源碼以下:
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; /** * This implementation of the PersonService interface communicates with * the database by using a Spring Data JPA repository. * @author Petri Kainulainen */ @Service public class RepositoryPersonService implements PersonService { private static final Logger LOGGER = LoggerFactory.getLogger(RepositoryPersonService.class); @Resource private PersonRepository personRepository; @Transactional @Override public Person create(PersonDTO created) { LOGGER.debug("Creating a new person with information: " + created); Person person = Person.getBuilder(created.getFirstName(), created.getLastName()).build(); return personRepository.save(person); } @Transactional(rollbackFor = PersonNotFoundException.class) @Override public Person delete(Long personId) throws PersonNotFoundException { LOGGER.debug("Deleting person with id: " + personId); Person deleted = personRepository.findOne(personId); if (deleted == null) { LOGGER.debug("No person found with id: " + personId); throw new PersonNotFoundException(); } personRepository.delete(deleted); return deleted; } @Transactional(readOnly = true) @Override public List<Person> findAll() { LOGGER.debug("Finding all persons"); return personRepository.findAll(); } @Transactional(readOnly = true) @Override public Person findById(Long id) { LOGGER.debug("Finding person by id: " + id); return personRepository.findOne(id); } @Transactional(rollbackFor = PersonNotFoundException.class) @Override public Person update(PersonDTO updated) throws PersonNotFoundException { LOGGER.debug("Updating person with information: " + updated); Person person = personRepository.findOne(updated.getId()); if (person == null) { LOGGER.debug("No person found with id: " + updated.getId()); throw new PersonNotFoundException(); } person.update(updated.getFirstName(), updated.getLastName()); return person; } /** * This setter method should be used only by unit tests. * @param personRepository */ protected void setPersonRepository(PersonRepository personRepository) { this.personRepository = personRepository; } }
本步驟的最後部分是爲RepositoryPersonService類編寫單元測試,這些單元測試的源碼以下:
import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import static junit.framework.Assert.assertEquals; import static org.mockito.Mockito.*; public class RepositoryPersonServiceTest { private static final Long PERSON_ID = Long.valueOf(5); private static final String FIRST_NAME = "Foo"; private static final String FIRST_NAME_UPDATED = "FooUpdated"; private static final String LAST_NAME = "Bar"; private static final String LAST_NAME_UPDATED = "BarUpdated"; private RepositoryPersonService personService; private PersonRepository personRepositoryMock; @Before public void setUp() { personService = new RepositoryPersonService(); personRepositoryMock = mock(PersonRepository.class); personService.setPersonRepository(personRepositoryMock); } @Test public void create() { PersonDTO created = PersonTestUtil.createDTO(null, FIRST_NAME, LAST_NAME); Person persisted = PersonTestUtil.createModelObject(PERSON_ID, FIRST_NAME, LAST_NAME); when(personRepositoryMock.save(any(Person.class))).thenReturn(persisted); Person returned = personService.create(created); ArgumentCaptor<Person> personArgument = ArgumentCaptor.forClass(Person.class); verify(personRepositoryMock, times(1)).save(personArgument.capture()); verifyNoMoreInteractions(personRepositoryMock); assertPerson(created, personArgument.getValue()); assertEquals(persisted, returned); } @Test public void delete() throws PersonNotFoundException { Person deleted = PersonTestUtil.createModelObject(PERSON_ID, FIRST_NAME, LAST_NAME); when(personRepositoryMock.findOne(PERSON_ID)).thenReturn(deleted); Person returned = personService.delete(PERSON_ID); verify(personRepositoryMock, times(1)).findOne(PERSON_ID); verify(personRepositoryMock, times(1)).delete(deleted); verifyNoMoreInteractions(personRepositoryMock); assertEquals(deleted, returned); } @Test(expected = PersonNotFoundException.class) public void deleteWhenPersonIsNotFound() throws PersonNotFoundException { when(personRepositoryMock.findOne(PERSON_ID)).thenReturn(null); personService.delete(PERSON_ID); verify(personRepositoryMock, times(1)).findOne(PERSON_ID); verifyNoMoreInteractions(personRepositoryMock); } @Test public void findAll() { List<Person> persons = new ArrayList<Person>(); when(personRepositoryMock.findAll()).thenReturn(persons); List<Person> returned = personService.findAll(); verify(personRepositoryMock, times(1)).findAll(); verifyNoMoreInteractions(personRepositoryMock); assertEquals(persons, returned); } @Test public void findById() { Person person = PersonTestUtil.createModelObject(PERSON_ID, FIRST_NAME, LAST_NAME); when(personRepositoryMock.findOne(PERSON_ID)).thenReturn(person); Person returned = personService.findById(PERSON_ID); verify(personRepositoryMock, times(1)).findOne(PERSON_ID); verifyNoMoreInteractions(personRepositoryMock); assertEquals(person, returned); } @Test public void update() throws PersonNotFoundException { PersonDTO updated = PersonTestUtil.createDTO(PERSON_ID, FIRST_NAME_UPDATED, LAST_NAME_UPDATED); Person person = PersonTestUtil.createModelObject(PERSON_ID, FIRST_NAME, LAST_NAME); when(personRepositoryMock.findOne(updated.getId())).thenReturn(person); Person returned = personService.update(updated); verify(personRepositoryMock, times(1)).findOne(updated.getId()); verifyNoMoreInteractions(personRepositoryMock); assertPerson(updated, returned); } @Test(expected = PersonNotFoundException.class) public void updateWhenPersonIsNotFound() throws PersonNotFoundException { PersonDTO updated = PersonTestUtil.createDTO(PERSON_ID, FIRST_NAME_UPDATED, LAST_NAME_UPDATED); when(personRepositoryMock.findOne(updated.getId())).thenReturn(null); personService.update(updated); verify(personRepositoryMock, times(1)).findOne(updated.getId()); verifyNoMoreInteractions(personRepositoryMock); } private void assertPerson(PersonDTO expected, Person actual) { assertEquals(expected.getId(), actual.getId()); assertEquals(expected.getFirstName(), actual.getFirstName()); assertEquals(expected.getLastName(), expected.getLastName()); } }
本人已經向你演示瞭如何用Spring Data JPA實現一個簡單的CRUD應用,若是你對查看個人所有實踐的功能示例感興趣,你能夠從Github獲取,個人Spring Data JPA教程的第三部分描述如何用query方法建立自定義查詢
---------------------------------------------------------------------------
本系列Spring Data JPA 教程翻譯系本人原創
做者 博客園 刺蝟的溫馴
本文連接http://www.cnblogs.com/chenying99/archive/2013/06/19/3143527.html
本文版權歸做者全部,未經做者贊成,嚴禁轉載及用做商業傳播,不然將追究法律責任。