Thomas Darimont
Erfahrenes Mitglied
Hallo,
als Fortsetzung zu meinem anderen Spring Beispiel
(http://www.tutorials.de/java/356059...bernate-3-x-lombok-junit-4-und-maven-2-x.html)
hier eine aktualisierte Fassung.
Der gesamte Code findet man im Anhang. //Edit: oder auf github:
https://github.com/thomasdarimont/de.tutorials.training.spring311
Hier mal ein kleines Beispiel zur Verwendung von JPA mit Spring, Lombok ,JUnit und Maven 3.x realisiert mit
der Spring Toolsuite (STS) IDE, mysql, H2 und Tomcat 7.0.26.
Dabei verwende ich diesmal die Spring Java Config Konfigurationsvariante
(Spring Konfiguration "fast ohne" XML), und Spring-Data-JPA zur Implementierung der DAOs.
Verwendete Technologien:
Demonstrierte Features:
In diesem Beispiel gibt es 3 Maven Projekte.
Hier die Maven Konfigurationsdatei pom.xml des Maven-Parent Projektes:
Hier die Maven Konfigurationsdatei pom.xml unseres Anwendungsprojektes (de.tutorials.training.spring.application):
Unser Domain Model:
Unser Service-Interface:
Unsere Service-Implementierung:
Unsere Repositories (aka DAOs).
Da wir Spring-Data-JPA verwendend brauchen wir für unsere JPA Daos keine direkten
Implementierungen mehr. Diese wird von Spring Data JPA zur Laufzeit zur Verfügung gestellt.
Mehr infos dazu gibt es hier:
http://static.springsource.org/spri...nt/reference/html/#jpa.query-methods.at-query
UserRepository-Interface
Unser RoleRepository-Interface
Nun komment wir zur Konfiguration unseres Moduls mit Spring Java Config:
Nun noch die eigentliche Spring Konfiguration mit der gesamten Infrastruktur:
Der JUnit-Test für UserAdminService:
Unter src/main/resources/config haben wir folgende Konfigurationseinträge in system.properties:
Unter src/main/resources/spring haben wir die einzige Spring Konfiguration im XML-Format.
Spring-Data-JPA lässt sich derzeit (04.03.2012) nicht voll über Spring Java Config Konfigurieren.
:
Unser Schema für die embedded h2 Datenbank schemasrc/test/resources/schema.sql
Hier noch die Konfigurationsdatei für das Logback Logging-Framework:
Hier nun die Maven Konfigurationsdatei pom.xml unserer Webapplication:
Auch im Web Projekt verwenden wir keine XML Konfiguration. Das setzt allerdings voraus, dass ein
Servlet 3.0 fähiger Servlet Container verwendet wird!
Unser Spring / Spring WebMVC Bootstrap welcher die Spring Umgebung im Servlet Container startet.
Hier unsere Konfiguration des MVC Dispatchers:
Hier unserer Controller zu unserem UserAdminService:
Die index.html implementiert das Frontend zum UserAdminController
Unsere Fronted Logik app.js:
Nachdem man die Projekte aus dem Zip-Archiv in Eclipse importiert hat muss man gegebenenfalls für die Projekte die Maven Konfiguration aktualisieren (Projekt -> Kontextmenü -> Maven -> Update Project Configuration).
Wenn man das Projekt anschließend auf einem Servlet Container über Eclipse ausführen möchte muss einfach das WebProjekt per Drag & Drop auf den zuvor definierten Tomcat Server ziehen.
Nun startet man die Webanwendung über das Kontextmenü -> Run As -> Run on Server und wählt dort die Tomcat-Serverkonfiguration aus, auf die man zuvor das Projekt deployed hat.
Anschließend kann man die Web-Anwendung über die URL:
http://localhost:TOMCAT_PORT/de.tutorials.training.spring.webapp/
aufrufen.
Gruß Tom
als Fortsetzung zu meinem anderen Spring Beispiel
(http://www.tutorials.de/java/356059...bernate-3-x-lombok-junit-4-und-maven-2-x.html)
hier eine aktualisierte Fassung.
Der gesamte Code findet man im Anhang. //Edit: oder auf github:
https://github.com/thomasdarimont/de.tutorials.training.spring311
Hier mal ein kleines Beispiel zur Verwendung von JPA mit Spring, Lombok ,JUnit und Maven 3.x realisiert mit
der Spring Toolsuite (STS) IDE, mysql, H2 und Tomcat 7.0.26.
Dabei verwende ich diesmal die Spring Java Config Konfigurationsvariante
(Spring Konfiguration "fast ohne" XML), und Spring-Data-JPA zur Implementierung der DAOs.
Verwendete Technologien:
- Spring: 3.1.1.Release, Spring-Data-Jpa 1.0.3.Release
- Hibernate: 4.0.1.Final (Hibernate -EntityManager), 4.2.0.Final (JSR-303 BeanValidation via Hibernate-Validation)
- H2 Emebdded Database für Tests:
- Lombok: 0.10.8
- JUnit 4.10
- Logback: 1.0.0
- CDI: 1.0
- Tomcat: 7.0.26
- STS: 2.8.1
- Maven: 3.0.3
- JQuery: 1.7.1
Demonstrierte Features:
- Spring Java Config
- Spring Profiles
- Spring Environment Konfiguration
- Unit / Integration Testing mit Embedded Database (H2)
- JPA / JSR 303 Bean Validation
- Spring-Data-JPA
- Spring Web MVC
- Mehrere Maven Module
- JQuery
- JQuery Templating
In diesem Beispiel gibt es 3 Maven Projekte.
- Das Maven-Parent Projekt (de.tutorials.training.spring.parent)
- Die eigentliche Anwendungslogik: (de.tutorials.training.spring.application)
- Eine kleine Java EE 6 Webapp welche die Anwendungslogik verwendet (de.tutorials.training.spring.web)
Hier die Maven Konfigurationsdatei pom.xml des Maven-Parent Projektes:
XML:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>de.tutorials</groupId>
<artifactId>de.tutorials.training.spring.parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<org.springframework.version>3.1.1.RELEASE</org.springframework.version>
<org.springframework.data.version>1.0.3.RELEASE</org.springframework.data.version>
<org.hibernate.hibernate-entitymanager.version>4.0.1.Final</org.hibernate.hibernate-entitymanager.version>
<org.hibernate.hibernate-validator.version>4.2.0.Final</org.hibernate.hibernate-validator.version>
<org.junit.version>[4.,)</org.junit.version>
<org.cglib.version>[2.,)</org.cglib.version>
<org.slf4j.version> [1.4,)</org.slf4j.version>
<ch.qos.logback.version>1.0.0</ch.qos.logback.version>
<javax.enterprise.cdi-api.version>1.0</javax.enterprise.cdi-api.version>
<org.projectlombok.lombok.version>0.10.8</org.projectlombok.lombok.version>
<mysql.mysql-connector-java.version>[5.1.,)</mysql.mysql-connector-java.version>
<com.h2database.version>1.3.164</com.h2database.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.mysql-connector-java.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>
${org.hibernate.hibernate-entitymanager.version}
</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${org.springframework.version}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${org.slf4j.version}</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>${org.cglib.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${org.projectlombok.lombok.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${org.junit.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>${org.springframework.data.version}</version>
</dependency>
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>${javax.enterprise.cdi-api.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${ch.qos.logback.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${ch.qos.logback.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>${org.hibernate.hibernate-validator.version}</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${com.h2database.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<modules>
<module>../de.tutorials.training.spring.application</module>
<module>../de.tutorials.training.spring.webapp</module>
</modules>
</project>
Hier die Maven Konfigurationsdatei pom.xml unseres Anwendungsprojektes (de.tutorials.training.spring.application):
XML:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>de.tutorials.training.spring.application</artifactId>
<parent>
<artifactId>de.tutorials.training.spring.parent</artifactId>
<groupId>de.tutorials</groupId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../de.tutorials.training.spring.parent/pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>compile</scope>
</dependency>
<!-- start testing dependencies -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<type>jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<type>jar</type>
<scope>test</scope>
</dependency>
<!-- end testing dependencies -->
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
</dependencies>
</project>
Unser Domain Model:
Java:
package de.tutorials.app.useradmin.model;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.validator.constraints.Email;
@Entity
@Getter
@Setter
@Table(name="UA_USER")
public class User implements Serializable{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue
protected Long id;
@Column(unique = true)
protected String name;
@Email
@Column(unique = true)
protected String email;
@ManyToMany(fetch=FetchType.EAGER)
@JoinTable(name="UA_USER_ROLE")
protected Collection<Role> roles = new HashSet<Role>();
public User() {
}
public User(String name, String email, Role... roles) {
this.name = name;
this.email = email;
for (Role role : roles) {
this.roles.add(role);
}
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("User [id=");
builder.append(id);
builder.append(", name=");
builder.append(name);
builder.append(", roles=");
builder.append(roles);
builder.append("]");
return builder.toString();
}
}
Java:
package de.tutorials.app.useradmin.model;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Getter;
import lombok.Setter;
@Entity
@Getter
@Setter
@Table(name="UA_ROLE")
public class Role implements Serializable{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue
protected Long id;
@Column(unique = true)
protected String name;
public Role() {
}
public Role(String name) {
this.name = name;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Role [id=");
builder.append(id);
builder.append(", name=");
builder.append(name);
builder.append("]");
return builder.toString();
}
}
Unser Service-Interface:
Java:
package de.tutorials.app.useradmin.service;
import java.util.List;
import de.tutorials.app.useradmin.model.Role;
import de.tutorials.app.useradmin.model.User;
public interface UserAdminService {
Role register(Role role);
User register(User user);
List<User> findAllUsers();
List<Role> findAllRoles();
List<User> findUserInRole(Role role);
}
Unsere Service-Implementierung:
Java:
package de.tutorials.app.useradmin.service;
import java.util.List;
import javax.inject.Inject;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import de.tutorials.app.useradmin.model.Role;
import de.tutorials.app.useradmin.model.User;
import de.tutorials.app.useradmin.persistence.RoleRepository;
import de.tutorials.app.useradmin.persistence.UserAdminRepository;
@Service
@Transactional
public class DefaultUserAdminService implements UserAdminService {
@Inject
protected UserAdminRepository userRepository;
@Inject
protected RoleRepository roleRepository;
@Override
public Role register(Role role) {
return roleRepository.save(role);
}
@Override
public User register(User user) {
return userRepository.save(user);
}
@Override
public List<Role> findAllRoles() {
return roleRepository.findAll();
}
@Override
public List<User> findAllUsers() {
return userRepository.findAll();
}
@Override
public List<User> findUserInRole(Role role) {
return userRepository.findUserByRolesName(role.getName());
}
}
Unsere Repositories (aka DAOs).
Da wir Spring-Data-JPA verwendend brauchen wir für unsere JPA Daos keine direkten
Implementierungen mehr. Diese wird von Spring Data JPA zur Laufzeit zur Verfügung gestellt.
Mehr infos dazu gibt es hier:
http://static.springsource.org/spri...nt/reference/html/#jpa.query-methods.at-query
UserRepository-Interface
Java:
package de.tutorials.app.useradmin.persistence;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import de.tutorials.app.useradmin.model.User;
public interface UserAdminRepository extends JpaRepository<User, Long> {
List<User> findUserByRolesName(String roleName);
}
Unser RoleRepository-Interface
Java:
package de.tutorials.app.useradmin.persistence;
import org.springframework.data.jpa.repository.JpaRepository;
import de.tutorials.app.useradmin.model.Role;
public interface RoleRepository extends JpaRepository<Role, Long>{
}
Nun komment wir zur Konfiguration unseres Moduls mit Spring Java Config:
Java:
package de.tutorials.app.useradmin;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import de.tutorials.app.useradmin.service.DefaultUserAdminService;
import de.tutorials.app.useradmin.service.UserAdminService;
@Configuration
public class UseradminModuleConfiguration {
@Bean
public UserAdminService userAdminService() {
//we don't need a bean definition for this service since it is automatically picked up
//via component scanning... we leave this bean definition just for demo purposes
DefaultUserAdminService userAdminService = new DefaultUserAdminService();
return userAdminService;
}
}
Nun noch die eigentliche Spring Konfiguration mit der gesamten Infrastruktur:
Java:
package de.tutorials.app.system;
import java.sql.Driver;
import java.util.Arrays;
import javax.inject.Inject;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.orm.hibernate4.HibernateExceptionTranslator;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@EnableTransactionManagement(proxyTargetClass = true)
@PropertySource("classpath:/config/system.properties")
@ImportResource("classpath:/spring/spring-data-config.xml") //At the time of this writing 04.03.2012 Spring-Data-JPA is not able to be fully configured via javaconfig
//therefore we have to include one small xml file...
@ComponentScan(basePackages = { "de.tutorials.app" })
public class SystemModuleConfiguration {
@Inject
protected Environment env;
@Bean
public DataSource dataSource() {
if (Arrays.asList(env.getActiveProfiles()).contains("testing")) {
//Wir testen mit einer embedded h2 db
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).addScript("classpath:/db/schema.sql").build();
} else {
SimpleDriverDataSource ds = new SimpleDriverDataSource();
ds.setDriverClass(env.getPropertyAsClass("persistence.db.driverClass", Driver.class));
ds.setUrl(env.getProperty("persistence.db.url"));
ds.setUsername(env.getProperty("persistence.db.username"));
ds.setPassword(env.getProperty("persistence.db.password"));
return ds;
}
}
@Bean
public JpaTransactionManager transactionManager() {
return new JpaTransactionManager(entityManagerFactory());
}
@Bean
public EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setJpaVendorAdapter(jpaVendorAdapter());
em.setPackagesToScan("de.tutorials.app"); //this implicitly generates an appropriate persistence.xml for us at runtime .
em.afterPropertiesSet();
return em.getObject();
}
@Bean
public PersistenceExceptionTranslator hibernateExceptionTranslator() {
return new HibernateExceptionTranslator();
}
@Bean
public HibernateJpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
adapter.setShowSql(env.getProperty("persistence.hibernate.showSql",
Boolean.class));
adapter.setGenerateDdl(env.getProperty(
"persistence.hibernate.generateDdl", Boolean.class));
adapter.setDatabasePlatform(env
.getProperty("persistence.hibernate.databasePlatform"));
return adapter;
}
}
Der JUnit-Test für UserAdminService:
Java:
package de.tutorials.app.useradmin.service;
import java.util.List;
import javax.inject.Inject;
import javax.persistence.PersistenceException;
import javax.validation.ConstraintViolationException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
import de.tutorials.app.system.SystemModuleConfiguration;
import de.tutorials.app.useradmin.UseradminModuleConfiguration;
import de.tutorials.app.useradmin.model.Role;
import de.tutorials.app.useradmin.model.User;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
@Transactional
@ActiveProfiles("testing")
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { SystemModuleConfiguration.class,
UseradminModuleConfiguration.class })
public class UserAdminServiceTest {
@Inject
UserAdminService userAdminService;
@Test
@Rollback(true)
public void registerUser() {
User user = new User();
user.setName("User1");
user = userAdminService.register(user);
List<User> allUsers = userAdminService.findAllUsers();
User savedUser = allUsers.get(0);
assertEquals("There should be one saved user", 1, allUsers.size());
assertEquals("The user should be equal to saved user", user, savedUser);
}
@Test(expected = ConstraintViolationException.class)
@Rollback(true)
public void registerUserWithInvalidEmailShouldFail() {
User user = new User();
user.setName("User1");
user.setEmail("xxx.yyy");
user = userAdminService.register(user);
fail("A user with invalid email adress is not allowed!");
}
// @Test(expected=ConstraintViolationException.class) -> Spring Exception
// Translation does not catch Unique Constraints on column level?!
@Test(expected = PersistenceException.class)
@Rollback(true)
public void registerUserWithAlreadyExistingUsernameShouldFail() {
User user = new User();
user.setName("User1");
user = userAdminService.register(user);
user = new User();
user.setName("User1");
user = userAdminService.register(user);
fail("Duplicate usernames are not allowed!");
}
@Test
@Rollback(true)
public void registerUserWithRoles() {
User user = new User();
user.setName("Admin");
user.setEmail("admin@company.com");
Role roleAdmin = new Role("admin");
Role roleUser = new Role("user");
roleAdmin = userAdminService.register(roleAdmin);
roleUser = userAdminService.register(roleUser);
user.getRoles().add(roleAdmin);
user.getRoles().add(roleUser);
user = userAdminService.register(user);
List<User> allUsers = userAdminService.findAllUsers();
User savedUser = allUsers.get(0);
assertEquals("The user should be equal to saved user", user, savedUser);
assertEquals("The user should have 2 roles", 2, savedUser.getRoles()
.size());
assertTrue("The user should have role user", savedUser.getRoles()
.contains(roleUser));
assertTrue("The user should have role admin", savedUser.getRoles()
.contains(roleAdmin));
}
@Test
@Rollback
public void findAllRolesShouldReturnAllRoles() {
userAdminService.register(new Role("foo"));
userAdminService.register(new Role("bar"));
userAdminService.register(new Role("user"));
userAdminService.register(new Role("admin"));
List<Role> roles = userAdminService.findAllRoles();
assertEquals(4, roles.size());
}
@Test
@Rollback(true)
public void findUserByRoleName() {
Role fooRole = userAdminService.register(new Role("foo"));
Role barRole = userAdminService.register(new Role("bar"));
userAdminService.register(new User("foo1", null, fooRole));
userAdminService.register(new User("foo2", null, fooRole));
userAdminService.register(new User("bar", null, barRole));
userAdminService.register(new User("foo3", null, fooRole));
userAdminService.register(new User("foobar", null, fooRole, barRole));
List<User> foos = userAdminService.findUserInRole(fooRole);
assertEquals(4, foos.size());
List<User> bars = userAdminService.findUserInRole(barRole);
assertEquals(2, bars.size());
}
}
Unter src/main/resources/config haben wir folgende Konfigurationseinträge in system.properties:
Code:
persistence.db.driverClass=com.mysql.jdbc.Driver
persistence.db.url=jdbc\:mysql\://localhost\:3306/springapp
persistence.db.username=root
persistence.db.password=tutorials
persistence.hibernate.showSql=true
persistence.hibernate.generateDdl=true
persistence.hibernate.databasePlatform=org.hibernate.dialect.MySQL5InnoDBDialect
Unter src/main/resources/spring haben wir die einzige Spring Konfiguration im XML-Format.
Spring-Data-JPA lässt sich derzeit (04.03.2012) nicht voll über Spring Java Config Konfigurieren.
:
XML:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:lang="http://www.springframework.org/schema/lang"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"
default-autowire="byName">
<jpa:repositories base-package="de.tutorials.app"/>
</beans>
Unser Schema für die embedded h2 Datenbank schemasrc/test/resources/schema.sql
SQL:
CREATE TABLE ua_role (
id identity NOT NULL,
name varchar(255) not NULL,
PRIMARY KEY (id),
UNIQUE KEY ua_role_name (name)
);
CREATE TABLE ua_user (
id identity NOT NULL,
email varchar(255) default NULL,
name varchar(255) not NULL,
PRIMARY KEY (id),
UNIQUE KEY ua_user_email (email),
UNIQUE KEY ua_user_name (name)
);
CREATE TABLE ua_user_role (
UA_USER_id bigint(20) NOT NULL,
roles_id bigint(20) NOT NULL,
UNIQUE KEY unique_user_role (UA_USER_id, roles_id)
);
ALTER TABLE ua_user_role ADD FOREIGN KEY (roles_id) REFERENCES ua_role (id);
ALTER TABLE ua_user_role ADD FOREIGN KEY (UA_USER_id) REFERENCES ua_user (id);
Hier noch die Konfigurationsdatei für das Logback Logging-Framework:
XML:
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
Hier nun die Maven Konfigurationsdatei pom.xml unserer Webapplication:
XML:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>de.tutorials.training.spring.webapp</artifactId>
<parent>
<artifactId>de.tutorials.training.spring.parent</artifactId>
<groupId>de.tutorials</groupId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../de.tutorials.training.spring.parent/pom.xml</relativePath>
</parent>
<packaging>war</packaging>
<name>de.tutorials.training.spring.webapp</name>
<properties>
<endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>6.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>de.tutorials</groupId>
<artifactId>
de.tutorials.training.spring.application
</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.1.1.RELEASE</version>
</dependency>
<!-- Jackson JSON Mapper -->
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>[1.9.,)</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<compilerArguments>
<endorseddirs>${endorsed.dir}</endorseddirs>
</compilerArguments>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.1.1</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<outputDirectory>${endorsed.dir}</outputDirectory>
<silent>true</silent>
<artifactItems>
<artifactItem>
<groupId>javax</groupId>
<artifactId>javaee-endorsed-api</artifactId>
<version>6.0</version>
<type>jar</type>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<!--This plugin's configuration is used to store Eclipse m2e settings
only. It has no influence on the Maven build itself. -->
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>
org.apache.maven.plugins
</groupId>
<artifactId>
maven-dependency-plugin
</artifactId>
<versionRange>
[2.1,)
</versionRange>
<goals>
<goal>copy</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore></ignore>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
Auch im Web Projekt verwenden wir keine XML Konfiguration. Das setzt allerdings voraus, dass ein
Servlet 3.0 fähiger Servlet Container verwendet wird!
Unser Spring / Spring WebMVC Bootstrap welcher die Spring Umgebung im Servlet Container startet.
Java:
package de.tutorials.app.web;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.HiddenHttpMethodFilter;
import org.springframework.web.servlet.DispatcherServlet;
public class Bootstrap implements WebApplicationInitializer {
AnnotationConfigWebApplicationContext rootContext;
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
setupApplicationContext();
registerServlets(servletContext);
registerListeners(servletContext);
registerFilters(servletContext);
}
private void registerServlets(ServletContext servletContext) {
// Create the dispatcher servlet's Spring application context
AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
dispatcherContext.register(DispatcherConfig.class);
// Register and map the dispatcher servlet
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/dispatch/*");
}
private void setupApplicationContext() {
this.rootContext = new AnnotationConfigWebApplicationContext();
this.rootContext.scan("de.tutorials.app");
//this.rootContext.register(annotatedClasses)
}
private void registerListeners(ServletContext servletContext) {
servletContext.addListener(new ContextLoaderListener(this.rootContext ));
}
private void registerFilters(ServletContext servletContext) {
servletContext.addFilter("hiddenHttpMethodFilter", HiddenHttpMethodFilter.class).addMappingForUrlPatterns(null, false, "/*");
}
}
Hier unsere Konfiguration des MVC Dispatchers:
Java:
package de.tutorials.app.web;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@EnableWebMvc
@Configuration
@ComponentScan(basePackageClasses = { DispatcherConfig.class })
public class DispatcherConfig {
}
Hier unserer Controller zu unserem UserAdminService:
Java:
package de.tutorials.app.web.rest;
import java.util.Date;
import java.util.List;
import javax.inject.Inject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import de.tutorials.app.useradmin.model.User;
import de.tutorials.app.useradmin.service.UserAdminService;
@Controller
@RequestMapping("/useradmin")
public class UserAdminController {
@Inject
protected UserAdminService userAdminService;
@RequestMapping(method = { RequestMethod.POST }, value = "/registeruser", consumes = { "application/json" }, produces = { "application/json" })
@ResponseBody
public User registerUser(@RequestBody User user) {
user.setId(null);
return userAdminService.register(user);
}
@RequestMapping(method = { RequestMethod.GET }, value = "/listusers", produces = { "application/json" })
public @ResponseBody
List<User> listUsers() {
return userAdminService.findAllUsers();
}
@RequestMapping(value = "ping")
public void ping() {
System.out.println("ping " + new Date());
}
}
Die index.html implementiert das Frontend zum UserAdminController
HTML:
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Tutorials Spring App</title>
<script type="text/javascript" src="res/3rdparty/jq/jquery-1.7.1.min.js"></script>
<script type="text/javascript" src="res/3rdparty/jq/jquery.tmpl.min.js"></script>
<script type="text/javascript" src="res/3rdparty/json2/json2.js"></script>
<script id="userentryTemplate" type="text/x-jquery-tmpl">
<tr>
<td>${name}</td>
<td>${email}</td>
</tr>
</script>
<script type="text/javascript" src="res/js/app.js"></script>
</head>
<body>
<h1>Welcome Tutorials Spring App</h1>
<form id="addUserForm">
<label for="txtUsername">Username: </label><input type="text"id="txtUsername" /><br />
<label for="txtEmail">Email: </label><input type="email" id="txtEmail" /><br />
<input type="submit" value="Register" />
</form>
<div id="userlist">
<table border="1">
<thead>
<tr>
<th>Username</th>
<th>Email</th>
</tr>
</thead>
<tbody id="userlistBody">
</tbody>
</table>
</div>
</body>
</html>
Unsere Fronted Logik app.js:
Javascript:
var refreshUsersList = function(users) {
var $userEntryTemplate = $("#userentryTemplate").template();
$("#userlistBody").empty();
$.tmpl($userEntryTemplate, users).appendTo("#userlistBody");
};
var useradminAPI = {
createRequest : function(type, urlSuffix, data) {
var request = {
url : "dispatch/" + urlSuffix,
type : type,
data : data ? JSON.stringify(data) : null,
contentType : "application/json",
dataType : "json"
};
return request;
}
,
registerUser : function(user) {
var request = useradminAPI.createRequest("POST",
"useradmin/registeruser", user);
$.ajax(request).done(function(reponse) {
useradminAPI.findAllUsers();
});
},
findAllUsers : function() {
var request = useradminAPI.createRequest("GET",
"useradmin/listusers");
$.ajax(request).done(function(users) {
refreshUsersList(users);
});
}
};
var init = function() {
$("#addUserForm").submit(function() {
var user = {
name : $("#txtUsername").val(),
email : $("#txtEmail").val()
};
useradminAPI.registerUser(user);
return false;
});
useradminAPI.findAllUsers();
};
$(init);
Nachdem man die Projekte aus dem Zip-Archiv in Eclipse importiert hat muss man gegebenenfalls für die Projekte die Maven Konfiguration aktualisieren (Projekt -> Kontextmenü -> Maven -> Update Project Configuration).
Wenn man das Projekt anschließend auf einem Servlet Container über Eclipse ausführen möchte muss einfach das WebProjekt per Drag & Drop auf den zuvor definierten Tomcat Server ziehen.
Nun startet man die Webanwendung über das Kontextmenü -> Run As -> Run on Server und wählt dort die Tomcat-Serverkonfiguration aus, auf die man zuvor das Projekt deployed hat.
Anschließend kann man die Web-Anwendung über die URL:
http://localhost:TOMCAT_PORT/de.tutorials.training.spring.webapp/
aufrufen.
Gruß Tom
Anhänge
Zuletzt bearbeitet von einem Moderator: