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