it72 - IT-Beratung

The smart way

it72 Blog

Themen zu Java- und Web-Technologie

Wicket, Spring 4 und Hibernate 5

Wie man Spring 4 und Hibernate 5 einfach in Wicket integriert. Minimaler Setup und Konfiguration.

Nachdem es im Netz mehrere Resourcen zum Thema Spring und Hibernate Integration in Apache Wicket gibt, und diese Anleitungen sich auf teils veraltete Spring und Hibernate Versionen beziehen, gebe ich für eine aktuelle Kombination mit Spring 4, Hibernate 6 und Wicket 6 eine Anleitung zum einfachen Setup. Nur mit Bibliotheken, die in jedem Fall gebraucht werden. Konfigurationen über Annotations und eine Properties Datei für die Datenbank-Verbindung.

Bibliotheken

Die folgenden Bibliotheken braucht man zwingend, um den Technologie-Stack Wicket, Spring, Hibernate mit aktuellen Bibliotheken zu realisieren.

Beispielhaft wird MySQL als Datenbank und Maven als Build-System verwendet.

Wicket 6

  • wicket-spring

Spring 4

  • spring-core
  • spring-context
  • spring-orm
  • spring-tx

Hibernate 5

  • hibernate-core
  • hibernate-entitymanager

3rd Party

  • commons-dbcp
  • javax.transaction / jta
  • mysql-connector

Maven POM

<properties>
    <!-- Wicket -->
    <wicket.version>6.21.0</wicket.version>

    <!-- Spring framework -->
    <springframework.version>4.2.3.RELEASE</springframework.version>

    <!-- Persistence -->
    <mysql.connector.version>5.1.37</mysql.connector.version>

    <!-- Hibernate -->
    <hibernate.version>5.0.4.Final</hibernate.version>
</properties>

<dependencies>
    <!-- Wicket -->
    <dependency>
        <groupId>org.apache.wicket</groupId>
        <artifactId>wicket-core</artifactId>
        <version>${wicket.version}</version>
    </dependency>

    <!-- Spring -->
    <dependency>
        <groupId>org.apache.wicket</groupId>
        <artifactId>wicket-spring</artifactId>
    <version>${wicket.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
    <version>${springframework.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${springframework.version}</version>
    </dependency>

    <!-- Spring ORM -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-orm</artifactId>
        <version>${springframework.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>${springframework.version}</version>
    </dependency>

    <!-- Hibernate -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>${hibernate.version}</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>${hibernate.version}</version>
    </dependency>

    <!-- DB connection pool -->
    <dependency>
        <groupId>commons-dbcp</groupId>
        <artifactId>commons-dbcp</artifactId>
        <version>1.4</version>
    </dependency>
    <!-- JTA -->
    <dependency>
        <groupId>javax.transaction</groupId>
        <artifactId>jta</artifactId>
        <version>1.1</version>
    </dependency>

    <!-- MySQL -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>${mysql.connector.version}</version>
    </dependency>
</dependencies>

Wicket Integration

Die Wicket Integration besteht aus Anpassung der WebApplication und dem Schreiben einer Spring Konfiguration.

WicketApplication

Jede Applikation überschreibt die Klasse WebApplication, dabei fügt man Folgendes ein:

public class WicketSpringHibernateApplication extends WebApplication {
    /** 
     * @see org.apache.wicket.Application#getHomePage() 
     */ 
    @Override    
    public Class<? extends WebPage> getHomePage() {
        return HomePage.class;
    }

    @Override
    public void init() {
        super.init();

        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        ctx.register(WicketSpringHibernateApplicationConfiguration.class);
        ctx.refresh();
        getComponentInstantiationListeners().add(new SpringComponentInjector(this, ctx));
    }
}

WicketApplicationConfiguration

Die oben referenzierte Instanz von WicketApplicationConfiguration ersetzt frühere XML-Konfigurationen von Spring und Hibernate sowie Eingriffe in die web.xml. Einzig und allein die Attribute der JDBC-Verbindung werden aus Properties ausgelesen.

@Configuration
@ComponentScan(basePackages = { "de.it72.repository", "de.it72.service" })
@EnableTransactionManagement
@PropertySource(value = { "classpath:application.properties" })
public class WicketSpringHibernateApplicationConfiguration {
    @Autowired
    private Environment environment;
    @Bean
    public LocalSessionFactoryBean sessionFactory() {
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        sessionFactory.setPackagesToScan(new String[] { "de.it72.domain" });
        sessionFactory.setHibernateProperties(hibernateProperties());

        return sessionFactory;
    }

    @Bean public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
        dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
        dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
        dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
		return dataSource;
	}
		
	private Properties hibernateProperties() {
		Properties properties = new Properties();
		properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
		properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
		properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
		
		return properties; 
	}
	
	@Bean
	@Autowired
	public HibernateTransactionManager transactionManager(SessionFactory s) {
		HibernateTransactionManager txManager = new HibernateTransactionManager(); 
		txManager.setSessionFactory(s); return txManager;
	}	
}

JDBC Properties-Datei

application.properties packt man in src/main/resources:

jdbc.driverClassName = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://${server_name}:${port}/${db_name}
jdbc.username = <user_name>
jdbc.password = <password>
jdbc.showSql=true
jdbc.generateDDL=fals

# Hibernate
hibernate.dialect = org.hibernate.dialect.MySQLDialect
hibernate.show_sql = true
hibernate.format_sql = false

jdbc.driverClassName = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://${server_name}:${port}/${db_name}
jdbc.username = <user_name>
jdbc.password = <password>
jdbc.showSql=true
jdbc.generateDDL=false

# Hibernate
hibernate.dialect = org.hibernate.dialect.MySQLDialect
hibernate.show_sql = true
hibernate.format_sql = false

Die Platzhalter ersetzt man durch die definierten Werte der Datenbankverbindung. Wenn der Datenbankserver gleich dem Applikationsserver ist. wird ${server_name}=localhost gelten.

Hibernate Repository – Spring Service Bean

An einem Beispiel soll nun gezeigt werden wie man Hibernate und Spring anwendet. Über die Annotationen @Repository und @Service findet Spring mit der obigen Konfiguration in @ComponentScan die bereitgestellten Klassen

Hibernate Repository

So könnte ein Hibernate Repository aussehen, im Beispiel Package de.it72.repository:

Schnittstelle

/**
 * Repository Interface zu {@link User}
 *
 */
public interface UserRepository extends HibernateRepository<User, Long> {
    User loadByUserName(String userName);
}

Repository Bean

Die Repository Bean mit der @Repository Annotation.

/**
 * Repository-Implementierung
 */ 
@Repository
public class UserRepositoryImpl extends HibernateDao<User, Long> implements UserRepository {

    /** * JPQL Query oder Criteria API */
    @Override
	public User loadByUserName(String userName) {
        List<User> list = getSession()... 

    return list; 
}

Spring Bean

Die Spring Bean wird in der Schnittstelle deklariert und in der Bean implementiert.

Service Schnittstelle

Im Beispiel Package de.it72.service definiert man folgende Schnittstelle:

/**
 * Service zu {@link User}
 */
public interface UserService extends UserRepository {
    User loadByUserName(String userName);
}

Service Bean

Schließlich die Service Bean, im Beispiel Package de.it72.service, mit der @Service Annotation.
@Transactional für Transaktionsunterstützung.


/**
 * Service Implementierung
 *
 */
@Service
@Transactional
public class UserServiceImpl implements UserService {
    @Autowired private UserRepository repository;
	
    @Override public User loadByUserName(String userName) {
	    return repository.loadByUserName(userName);
	}
}

Einbindung in Wicket WebPage

Der UserService kann nun über die Annotation @SpringBean in Wicket Komponenten injiziert werden, voilá!

/**
 * Webseite - Home Page
 */
public class HomePage extends WebPage {
    @SpringBean private UserService userService;

	public HomePage(final PageParameters parameters) {
        super(parameters);
		
		add(new Label("user", userService.loadByUserName("it72")));
	}
}