2013-02-10 27 views
5

Kalıcılık katmanı için JPA'dan yararlanan bir Spring MVC uygulaması oluşturmaya çalışıyorum. Ne yazık ki, EntityManager erişirken bir NullPointerException alıyordum bahar gibi enjekte görünmüyor. Yapılandırmamın tümü @EnableWebMvc ile ek açıklamadır. Bazı aramalardan sonra, @Configuration sınıfımdaki DAO ve @EnableTransactionManagement öğelerinde @ Transactional özelliğini ekledim. Sonra bir DataSource olmama konusunda bir hatam var. Muhtemelen, @EnableTransactionManagement ile bir sınıf TransactionManagementConfigurer uygulamak gerekiyor. Ancak, DataSource'u nasıl oluşturacağımı ve bunun neden benim persistence.xml dosyasından alamamış olduğunu bulmakta sorun yaşıyorum.Spring MVC'li JPA Açıklamalarla Yapılandırıldı

EntityManager'ın DAO'ma enjekte edilmesini sağlamaya çalışırken herhangi bir yardımı çok takdir ediyorum.

Benim @Configuration sınıf

@Configuration 
@EnableWebMvc 
@EnableTransactionManagement 
@ComponentScan("com.example.myapp") 
public class MvcConfig extends WebMvcConfigurerAdapter 
     implements TransactionManagementConfigurer { 

private static final boolean CACHE_ENABLED = true; 
private static final String TEMPLATE_PATH = "/WEB-INF/freemarker"; 
private static final String TEMPLATE_SUFFIX = ".ftl"; 

private static final Logger LOG = Logger.getLogger(MvcConfig.class); 

@Override 
public void addResourceHandlers(ResourceHandlerRegistry registry) { 
    registry.addResourceHandler("/stylesheets/**").addResourceLocations("/stylesheets/"); 
} 

@Bean 
public FreeMarkerConfigurer configureFreeMarker() { 
    final FreeMarkerConfigurer configurer = new FreeMarkerConfigurer(); 
    configurer.setTemplateLoaderPath(TEMPLATE_PATH); 
    return configurer; 
} 

@Bean 
public ViewResolver configureViewResolver() { 
    final FreeMarkerViewResolver resolver = new FreeMarkerViewResolver(); 
    resolver.setCache(CACHE_ENABLED); 
    resolver.setSuffix(TEMPLATE_SUFFIX); 
    return resolver; 
} 

@Bean 
@Override 
public PlatformTransactionManager annotationDrivenTransactionManager() { 
    return new DataSourceTransactionManager(); 
} 

} 

Benim DAO

@Component 
@Transactional 
public class MyDAO { 

    private static final Logger LOG = Logger.getLogger(MyDAO.class); 

    @PersistenceContext 
    private EntityManager entityManager; 

    public MyClass getMyClass() { 
     LOG.debug("getMyClass()"); 
     final CriteriaQuery<MyClass> query = criteriaBuilder.createQuery(MyClass.class); 
     // more code here, but it breaks by this point 
     return myData; 
    } 

} 

Güncellenen Kod

Ben noktaya ulaştı ki neredeyse tüm eserleri içinde. EntityManager düzgün şekilde enjekte ediliyor. Ancak işlemler çalışmıyor. Bir RESOURCE_LOCAL yaklaşımını kullanmaya çalışırsam hata alırım, böylece JTA yönetilen işlemlere bakıyorum. Herhangi bir DAO yöntemine @ Transactional eklediğimde, sorun giderme işlemine yardımcı olmak için herhangi bir günlük dosyasında daha fazla ayrıntı bulunmayan bir "Geri alma için işaretlenmiş İşlem" hatası alıyorum. Ek açıklamayı salt okunur bir seçenekten kaldırırsam, seçim gayet iyi çalışır (ek açıklamaları yalnızca seçime dayalı yöntemlere koymam gerekip gerekmediğinden emin değilim). Bununla birlikte, açıkçası bunun db yazmalarını gerçekleştiren yöntemler üzerinde çalışmasına ihtiyacım var. Koddan hata ayıklanırsam, verileri gayet iyi şekilde alır gibi görünüyor. Ancak, yöntemden döndürdüğü gibi javax.transaction.RollbackException atılır. Herşeyi anlamamdan, AOP yöntem-sonrası işleminde istisna oluşmuş gibi görünüyor.

Benim @Configuration sınıf başvurumun ben TransactionManagerConfigurer arabirimini uygulamak vermedi yılında

@Configuration 
@EnableWebMvc 
@EnableTransactionManagement 
@ComponentScan("com.example.myapp") 
public class MvcConfig extends WebMvcConfigurerAdapter { 

private static final boolean CACHE_ENABLED = true; 
private static final String TEMPLATE_PATH = "/WEB-INF/freemarker"; 
private static final String TEMPLATE_SUFFIX = ".ftl"; 

private static final Logger LOG = Logger.getLogger(MvcConfig.class); 

@Override 
public void addResourceHandlers(ResourceHandlerRegistry registry) { 
    registry.addResourceHandler("/stylesheets/**").addResourceLocations("/stylesheets/"); 
} 

@Bean 
public FreeMarkerConfigurer configureFreeMarker() { 
    final FreeMarkerConfigurer configurer = new FreeMarkerConfigurer(); 
    configurer.setTemplateLoaderPath(TEMPLATE_PATH); 
    return configurer; 
} 

@Bean 
public ViewResolver configureViewResolver() { 
    final FreeMarkerViewResolver resolver = new FreeMarkerViewResolver(); 
    resolver.setCache(CACHE_ENABLED); 
    resolver.setSuffix(TEMPLATE_SUFFIX); 
    return resolver; 
} 

@Bean 
public PlatformTransactionManager transactionManager() { 
    return new JtaTransactionManager(); 
} 

@Bean 
public AbstractEntityManagerFactoryBean entityManagerFactoryBean() { 
    LocalEntityManagerFactoryBean factory = new LocalEntityManagerFactoryBean(); 
    factory.setPersistenceUnitName("my_db"); 
    return factory; 
} 

} 

cevap

9

. JPA'yı (Hazırda Bekletme uygulamasıyla) yapılandırmak için bir sonraki kodu kullanıyorum. Aynı şeyi yapılandırma sınıfınızda da yapabilirsiniz. Bu)

DÜZENLEMEYİ size yardımcı olacaktır

@Bean 
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() { 
     LocalContainerEntityManagerFactoryBean factoryBean = 
       new LocalContainerEntityManagerFactoryBean(); 

     factoryBean.setDataSource(dataSource()); 
     factoryBean.setPackagesToScan(new String[] {"com.dimasco.springjpa.domain"}); 

     HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); 
     vendorAdapter.setShowSql(true); 
     //vendorAdapter.setGenerateDdl(generateDdl) 

     factoryBean.setJpaVendorAdapter(vendorAdapter); 

     Properties additionalProperties = new Properties(); 
     additionalProperties.put("hibernate.hbm2ddl.auto", "update"); 

     factoryBean.setJpaProperties(additionalProperties); 


     return factoryBean; 
    } 

    @Bean 
    public DataSource dataSource() { 
     final ComboPooledDataSource dataSource = new ComboPooledDataSource(); 

     try { 
      dataSource.setDriverClass(driverClass); 
     } catch (PropertyVetoException e) { 
      throw new RuntimeException(e); 
     } 

     dataSource.setJdbcUrl(jdbcUrl); 
     dataSource.setUser(user); 
     dataSource.setPassword(password); 
     dataSource.setMinPoolSize(3); 
     dataSource.setMaxPoolSize(15); 
     dataSource.setDebugUnreturnedConnectionStackTraces(true); 

     return dataSource; 
    } 

    @Bean 
    public PlatformTransactionManager transactionManager() { 
     JpaTransactionManager transactionManager = new JpaTransactionManager(); 
     transactionManager.setEntityManagerFactory(entityManagerFactoryBean().getObject()); 

     return transactionManager; 
    } 

    @Bean 
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){ 
     return new PersistenceExceptionTranslationPostProcessor(); 
    } 

Umut:

Sen Jndi aramasını kullanarak veri kaynağı alabilirsiniz:

@Bean 
public DataSource dataSource() throws Exception { 
    Context ctx = new InitialContext(); 
    return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource"); 
} 

Daha fazla detay sen in this article bulabilirsiniz. JndiDatasourceConfig sınıfı ile örnek var.

DÜZENLEME 2: Projemde persistence.xml olmayacaklarını, ancak boş:

<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"> 
    <persistence-unit name="JPA_And_Spring_Test"> 
    </persistence-unit> 
</persistence> 

Ve ben java yapılandırmasında herhangi kalıcı birimi adı belirtmedi.

https://github.com/springinpractice/sip13/blob/master/helpdesk/src/main/resources/spring/beans-repo.xml

Bu Bahar Veri JPA kullanır, ancak bunu yapmak zorunda değilsiniz:

+0

Bu durum, Hibernate'e özgü sınıfları, temeldeki uygulamaya bağladığı anlaşılan açık bir şekilde başvuruda bulunduğunuzla ilgilidir. Ayrıca, ideal olarak, veri kaynağı için JNDI araması kullanıyorum, ancak bunu nasıl yaptığımı bilmiyorum. Bunu yapmıyor mu varsayıyorum? – Marshmellow1328

+0

Temel uygulamaya uymayla ilgili - Spring olmadan JPA kullansanız bile, persistence.xml dosyasında kalıcılık sağlayıcı ayarlarını tanımlarsınız. Burada bunları bir kod entityManagerFactoryBean() yönteminde tanımlarsınız. Ama onları xml config dosyasına taşıyabilirsiniz.) – dimas

+0

Orijinal cevabımda JNDI araması yoluyla DataSource'un nasıl alınacağına örnek ekledim. – dimas

1

şu XML tabanlı konfigürasyon kullandığı halde, yardımcı olabilir.

@PersistenceContext private EntityManager entityManager; 

kullan (Ama kutunun dışında çok yetenekli DAOs sağladığından Bahar Veri JPA düşünün.)

Yan notu: DAOs için @Component üzerinde @Repository lehine. Bileşen taraması için her ikisi de işe yarar, ancak @Repository, kullanım amacını daha iyi tanımlar.

İlgili konular