Configuration
Instead of using the traditional JPA persistence.xml configuration file, we use Java configuration. On top of the traditional WebConfig class, we have a JpaConfig class annotated with @EnableTransactionManagement to enable database transactions.The LocalContainerEntityManagerFactoryBean is the easiest mean to configure JPA. Notice that the persistence.xml database connection information is moved to the DataSource. The PlatformTransactionManager is required to process @Transactional annotated method (discussed further).
PersistenceExceptionTranslationPostProcessor converts any vendor specific exceptions into Spring DataAccessException for easier handling.
@Configuration @EnableTransactionManagement public class JpaConfig { @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(){ LocalContainerEntityManagerFactoryBean lcemfb = new LocalContainerEntityManagerFactoryBean(); lcemfb.setDataSource(this.dataSource()); lcemfb.setPackagesToScan(new String[] {"com.jverstry"} ); lcemfb.setPersistenceUnitName("MyPU"); HibernateJpaVendorAdapter va = new HibernateJpaVendorAdapter(); lcemfb.setJpaVendorAdapter(va); Properties ps = new Properties(); ps.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect"); ps.put("hibernate.hbm2ddl.auto", "create"); lcemfb.setJpaProperties(ps); lcemfb.afterPropertiesSet(); return lcemfb; } @Bean public DataSource dataSource(){ DriverManagerDataSource ds = new DriverManagerDataSource(); ds.setDriverClassName("org.hsqldb.jdbcDriver"); ds.setUrl("jdbc:hsqldb:mem:testdb"); ds.setUsername("sa"); ds.setPassword(""); return ds; } @Bean public PlatformTransactionManager transactionManager() { JpaTransactionManager tm = new JpaTransactionManager(); tm.setEntityManagerFactory( this.entityManagerFactoryBean().getObject() ); return tm; } @Bean public PersistenceExceptionTranslationPostProcessor exceptionTranslation() { return new PersistenceExceptionTranslationPostProcessor(); } }
Data Item, Controller & Repository
The persisted data relies on Pojomatic:@Entity @AutoProperty public class Item implements Serializable { @Id @GeneratedValue(strategy=GenerationType.AUTO) private long ID; private String name = ""; // Setter, Getters, Pojomatic methods... }
@Controller public class MyController { @Autowired private MyRepository rep; @RequestMapping(value = "/") public String home(Model model) { return "index"; } @RequestMapping(value = "/roundtrip") public String Roundtrip(Model model) { model.addAttribute("Messages", rep.performRoundtrip()); return "roundtrip"; } }
@Repository public class MyRepository { @PersistenceContext private EntityManager em; @Transactional public List<String> performRoundtrip() { List<String> l = new ArrayList<String>(); try { l.add("Before create"); create(l); l.add("Before read I"); read(l); l.add("Before update"); update(l); l.add("Before read II"); read(l); l.add("Before delete"); delete(l); l.add("Before read III"); read(l); } catch (Exception ex) { l.add(ex.toString()); } return l; } private Item i = null; @Transactional public void create(List<String> l) { i = new Item(); i.setName("Item A"); l.add("- Before saving : " + i); em.persist(i); l.add("- After saving : " + i); } @Transactional public void read(List<String> l) { Item retr = em.find(Item.class, this.i.getID()); l.add("- Retrieved : " + retr); } @Transactional public void update(List<String> l) { i.setName("Item B"); l.add("- Updated : " + i); em.persist(i); } @Transactional public void delete(List<String> l) { l.add("- Deleting : " + i); em.remove(i); } }
JSP Page
The following roundtrip.jsp displays the messages collected during the roundtrip:<%@page contentType="text/html" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Roundtrip !!!</title> </head> <body> <c:forEach items="${Messages}" var="element"> ${element}<br /> </c:forEach><br /> <a href="<c:url value='/'/>" />Home</a> </body> </html>
Running the example
Once compiled, the example can be run with mvn tomcat:run. Then, browse http://localhost:8585/spring-web-jpa-roundtrip/.The generated output is:
Before create - Before saving : Item{ID: {0}, name: {Item A}} - After saving : Item{ID: {1}, name: {Item A}} Before read I - Retrieved : Item{ID: {1}, name: {Item A}} Before update - Updated : Item{ID: {1}, name: {Item B}} Before read II - Retrieved : Item{ID: {1}, name: {Item B}} Before delete - Deleting : Item{ID: {1}, name: {Item B}} Before read III - Retrieved : null
More Spring related posts here.
No comments:
Post a Comment