SpringBoot with JPA on WildFly

User Rating: 5 / 5

Star ActiveStar ActiveStar ActiveStar ActiveStar Active
 

In this second tutorial about Spring Boot we will learn how to deploy a JPA based application on a Java EE container such as WildFly 10.

We recommend going through our first tutorial to learn how to setup quickly a Maven project with Spring Boot: Spring Boot Hello World on WildFly

So we assumed you have created a basic Maven project: start adding the main class App.java which contains also the RestController to interact with our CityService:

package com.mastertheboss.springboot;

import java.util.List;

import com.mastertheboss.springboot.model.City;
import com.mastertheboss.springboot.service.CityService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.boot.web.support.SpringBootServletInitializer;

@SpringBootApplication
public class App extends SpringBootServletInitializer {

	public static void main(String[] args) {
		SpringApplication.run(applicationClass, args);
	}

	@Override
	protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
		return application.sources(applicationClass);
	}

	private static Class<App> applicationClass = App.class;
}

@RestController
@RequestMapping("/rest")
class HelloController {

	@Autowired
	private CityService cityService;

	@RequestMapping("/find/{city}/{country}")
	String find(@PathVariable String city, @PathVariable String country) {

		return cityService.getCity(city, country).toString();

	}

	@RequestMapping(value = "/findAll", headers = "Accept=application/json")
	List<City> findAll() {

		List<City> list = cityService.findAll();
		return list;

	}

}

So the HelloController maps two REST GET methods: find and findAll. The first one will return the result of a query using city and country as parameter. The second will return all the City objects available.

In Spring Service classes are the equivalent, in JEE terms, of EJBs as they can be used to hold business logic and calculations. Following here is the simple implementation of the CityService interface which adds some trivial logic to it, such as validating parameters.

package com.mastertheboss.springboot.service;


import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import com.mastertheboss.springboot.model.City;

@Component("cityService")
@Transactional
class CityServiceImpl implements CityService {

	@Autowired
	private CityRepository cityRepository;


	public CityServiceImpl( ) {	}
	 
	@Override
	public City getCity(String name, String country) {
		Assert.notNull(name, "Name must not be null");
		Assert.notNull(country, "Country must not be null");
		return this.cityRepository.findByNameAndCountryAllIgnoringCase(name, country);
	}

	@Override
	public List<City> findAll() {
		 
		return this.cityRepository.findAll();
	}

 }

This class is annotated with @Component which is generic stereotype for any Spring-managed component. By using @Transactional, many important aspects such as transaction propagation are handled automatically by Spring. And here's its interface definition:

package com.mastertheboss.springboot.service;

import java.util.List;

import com.mastertheboss.springboot.model.City;

public interface CityService {

    City getCity(String name, String country);
    List<City> findAll();	 

}

Last part of the project are the Repository classes which are the beans eligible for handling persistence. This interface acts primarily as a marker interface to capture the types to work with and providing sophisticated CRUD functionality for the entity class that is being managed. In our case, the findAll method will return all domain objects of type City and findByNameAndCountryAllIgnoringCase is equivalent to a case-insensitive "SELECT * from City where name = ? and country = ?"

package com.mastertheboss.springboot.service;

import java.util.List;
import org.springframework.data.repository.Repository;

import com.mastertheboss.springboot.model.City;

interface CityRepository extends Repository<City, Long> {

	City findByNameAndCountryAllIgnoringCase(String name, String country);
	List<City> findAll();

}

Finally, the Domain class which is annotated with JPA javax.persistence classes:

package com.mastertheboss.springboot.model;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class City implements Serializable {

	private static final long serialVersionUID = 1L;

	@Id
	@GeneratedValue
	private Long id;

	@Column(nullable = false)
	private String name;

	@Column(nullable = false)
	private String state;

	@Column(nullable = false)
	private String country;

	@Column(nullable = false)
	private String map;

	protected City() {
	}

	public City(String name, String country) {
		super();
		this.name = name;
		this.country = country;
	}

	public String getName() {
		return this.name;
	}

	public String getState() {
		return this.state;
	}

	public String getCountry() {
		return this.country;
	}

	public String getMap() {
		return this.map;
	}

	@Override
	public String toString() {
		return getName() + "," + getState() + "," + getCountry();
	}
}

That's all. In order to produce a war file, we need to specify the correct packaging in the pom.xml and also exclude the default Tomcat Starter classes. In this simple example we have used the default H2 database to persist our objects:

<?xml version="1.0" encoding="UTF-8"?>
<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>com.mastertheboss.springboot</groupId>
	<artifactId>SpringBootJPA</artifactId>
	<version>1.0-SNAPSHOT</version>
	<packaging>war</packaging>

	<name>Spring Boot Demo Project with JPA</name>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.4.0.RELEASE</version>
	</parent>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>

			<exclusions>
				<exclusion>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-starter-tomcat</artifactId>
				</exclusion>
			</exclusions>

		</dependency>

		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
			<scope>provided</scope>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<scope>runtime</scope>
		</dependency>

	</dependencies>
	<properties>
		<java.version>1.8</java.version>
	</properties>


	<build>
		<finalName>SpringBootJPA</finalName>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

In order to add some default data at application deployment, you could include a file import.sql under the resources folder of your project:

insert into city(country, name, state, map) values ('Italy', 'Roma', 'Lazio', '-27.470933, 153.023502')
insert into city(country, name, state, map) values ('France', 'Paris', 'IleDeFrance', '-37.813187, 144.96298')

Now compile as usual the project with:

$ mvn clean package

You will generate a SpringBootJPA.war file which can be deployed with:

$ cp target/SpringBootJPA.war %JBOSS_HOME/standalone/deployments

We can test that our application is working as follows:

$ wget http://localhost:8080/SpringBootJPA/rest/findAll
$ wget http://localhost:8080/SpringBootJPA/rest/findByNameAndCountryAllIgnoringCase/Roma/Italy

You can download the full project on Github at: https://github.com/fmarchioni/mastertheboss/tree/master/spring/SpringBootJPA

In the following tutorial (Configuring the DataBase in Spring Boot applications) we will learn how to change the default H2 database to use PostgreSQL.

Follow us on Twitter