Show Navigation

Build a Spring Boot application with GORM

Learn how to build a Spring Boot application using GORM

Authors: Ben Rhine, Sergio del Amo

Grails Version: N/A - Spring Boot Version: 1.5.6.RELEASE

1 Grails Training

Grails Training - Developed and delivered by the folks who created and actively maintain the Grails framework!.

2 Getting Started

In this guide you are going to build a Spring Boot application using GORM.

2.1 What you will need

To complete this guide, you will need the following:

  • Some time on your hands

  • A decent text editor or IDE

  • JDK 1.7 or greater installed with JAVA_HOME configured appropriately

2.2 How to complete the guide

To get started do the following:

or

The Grails guides repositories contain two folders:

  • initial Initial project. Often a simple Grails app with some additional code to give you a head-start.

  • complete A completed example. It is the result of working through the steps presented by the guide and applying those changes to the initial folder.

To complete the guide, go to the initial folder

  • cd into grails-guides/gorm-without-grails/initial

and follow the instructions in the next sections.

You can go right to the completed example if you cd into grails-guides/gorm-without-grails/complete

If you want to start from scratch, create a new Spring Boot application using Spring Initializr.

Select a Gradle Project using Groovy with Spring Boot 1.5.6. Once you have selected your build and project type, set the Group to your organization ie. com.example in our case we will use demo.

Once that is done add the Web and h2 dependencies to the project.

buildAndMetadata
dependency1
dependency2

Click Generate Project.

3 Configuring your Build

Edit build.gradle files to include GORM dependencies.

/build.gradle
buildscript {
    ext {
        springBootVersion = '1.5.6.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

apply plugin: 'groovy'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'

version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
    mavenCentral()
}


dependencies {
    compile('org.springframework.boot:spring-boot-starter-web')
    compile('org.codehaus.groovy:groovy')
    runtime('com.h2database:h2')
    testCompile('org.springframework.boot:spring-boot-starter-test')

    (1)
    compile("org.grails:gorm-hibernate5-spring-boot:6.1.6.RELEASE")
    compile "org.hibernate:hibernate-core:5.1.0.Final"
    compile "org.hibernate:hibernate-ehcache:5.1.0.Final"

    (2)
    runtime "org.apache.tomcat:tomcat-jdbc:8.5.0"
    runtime "org.apache.tomcat.embed:tomcat-embed-logging-log4j:8.5.0"
    runtime "org.slf4j:slf4j-api:1.7.10"

    runtime "org.glassfish.web:el-impl:2.1.2-b03"
}
1 Add the required dependencies for GORM to our project.
2 For connection pooling

3.1 Configuration

GORM for Hibernate can be configured with src/main/resources/application.yml file when using Spring Boot.

src/main/resources/application.yml
dataSource:
    pooled: true
    dbCreate: create-drop
    url: jdbc:h2:mem:devDb
    driverClassName: org.h2.Driver
    username: sa
    password:
hibernate:
    cache:
        queries: false
        use_second_level_cache: true
        use_query_cache: false
        region.factory_class: org.hibernate.cache.ehcache.EhCacheRegionFactory

4 Writing the Application

We are going to create a package structure similar to the one you find in Grails application:

  • demo.controller

  • demo.domain

  • demo.service

  • demo.init

4.1 Creating the domain

Now with our packages in place lets go ahead and create our domain objects.

  • Manufacturer.groovy

  • Vehicle.groovy

Feel free to use your favorite IDE to create these or execute the following

$ cd complete/src/main/groovy/demo/domain/
$ touch Manufacturer.groovy
$ touch Vehicle.groovy

Now that all our class stubs are in place lets go ahead and edit them.

/src/main/groovy/demo/domain/Manufacturer.groovy
package demo.domain

import grails.gorm.annotation.Entity
import groovy.transform.ToString
import org.grails.datastore.gorm.GormEntity

@ToString
@Entity
class Manufacturer implements GormEntity<Manufacturer> {

    String name

    static hasMany = [vehicles: Vehicle]

    static constraints = {
        name blank: false
    }
}
/src/main/groovy/demo/domain/Vehicle.groovy
package demo.domain

import grails.gorm.annotation.Entity
import org.grails.datastore.gorm.GormEntity
import groovy.transform.ToString

@ToString
@Entity
class Vehicle implements GormEntity<Vehicle> {
    String name
    Integer year
    static belongsTo = [manufacturer: Manufacturer]

    static constraints = {
        name nullable: false, blank: false
    }
}

Manufacturer and Vehicle have a one-to-many relationship.

We are using GORM outside of Grails. Because of that, we need to annotate our domain classes with the grails.gorm.annotation.Entity. Additionally we implement the GormEntity trait. It is merely to aid IDE support of GORM outside of Grails.

4.2 Seed Data

When the application starts we save some data.

/src/main/groovy/demo/Application.groovy
package demo

import org.springframework.boot.ApplicationArguments
import demo.init.BootStrap
import groovy.transform.CompileStatic
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.ApplicationRunner
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.context.annotation.ComponentScan

@EnableAutoConfiguration
@ComponentScan
@CompileStatic
@SpringBootApplication
class Application implements ApplicationRunner {

    @Autowired
    BootStrap bootStrap

    static void main(String[] args) {
        SpringApplication.run Application, args
    }

    void run(ApplicationArguments args) throws Exception {
        bootStrap.init()
    }
}
/src/main/groovy/demo/init/BootStrap.groovy
package demo.init

import demo.domain.Manufacturer
import demo.domain.Vehicle
import grails.gorm.transactions.Transactional
import groovy.transform.CompileStatic
import org.springframework.stereotype.Component

@Component
@CompileStatic
class BootStrap {

    @Transactional
    void init() {
        Manufacturer audi = new Manufacturer(name: 'audi')
        audi.addToVehicles(new Vehicle(name: 'A3', year: 1996))
        audi.addToVehicles(new Vehicle(name: 'A4', year: 1994))
        audi.save()

        Manufacturer ford = new Manufacturer(name: 'ford')
        ford.addToVehicles(new Vehicle(name: 'Ford KA', year: 1996))
        ford.save()
    }
}

4.3 Creating the Service layer

Next lets create our service layer for our application.

  $ cd src/main/groovy/demo/service
  $ touch ManufacturerService
  $ touch VehicleService

We are going to use GORM 6.1 Data Services.

Data Services take the work out of implemented service layer logic by adding the ability to automatically implement abstract classes or interfaces using GORM logic.

/src/main/groovy/demo/service/ManufacturerService.groovy
package demo.service

import demo.domain.Manufacturer
import groovy.transform.CompileStatic
import org.springframework.stereotype.Service

@CompileStatic
@grails.gorm.services.Service(Manufacturer)
@Service
interface ManufacturerService {
    List<Manufacturer> findAll()
}
/src/main/groovy/demo/service/VehicleService.groovy
package demo.service

import demo.domain.Manufacturer
import demo.domain.Vehicle
import grails.gorm.services.Where
import groovy.transform.CompileStatic
import org.springframework.stereotype.Service

@CompileStatic
@grails.gorm.services.Service(Vehicle)
@Service
interface VehicleService {

    @Where({ manufacturer.name == manufacturerName })
    List<Vehicle> findAllByManufacturer(String manufacturerName)

}

Additionally all our service classes make use of the @Service('someName') annotation. This annotation tells Spring what our services are called so it can properly map our dependency injection.

4.4 Creating a controller

Finally lets create some controllers so we can have basic UI access to our data.

  $ cd src/main/groovy/demo/controller
  $ touch ManufacturerController
  $ touch VehicleController

Now let’s edit our controllers under src/main/groovy/demo/controller.

The controllers will have the following annotations

  • @RestController - Denotes the controller as restful and that it can return data via url

  • @Autowired - Allows use to use dependency injection to access our services

  • @RequestMapping("/") - Sets the url mapping for the method

/src/main/groovy/demo/controller/VehicleController.groovy
package demo.controller

import demo.domain.Vehicle
import demo.service.VehicleService
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController

@RestController
class VehicleController {

    @Autowired VehicleService vehicleService

    @RequestMapping("/{manufacturerName}/vehicles")
    List<String> vehiclesByManufacturer(@PathVariable String manufacturerName) {
        vehicleService.findAllByManufacturer(manufacturerName)*.name
    }
}
/src/main/groovy/demo/controller/ManufacturerController.groovy
package demo.controller

import demo.service.ManufacturerService
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController

@RestController
class ManufacturerController {

    @Autowired
    ManufacturerService manufacturerService

    @RequestMapping("/")
    List<String> index(){
        manufacturerService.findAll()*.name
    }
}

Run the app:

./gradlew bootRun

You should be able to call the endpoints:

curl "http://localhost:8080"

and get the response:

["audi","ford"]

Or retrieve the vehicles of a manufacturer:

curl "http://localhost:8080/audi/vehicles"

and get the response:

["A3","A4"]

5 Do you need help with GORM or Grails?

OCI sponsored the creation of this Guide. OCI offers several Grails services:

Free consultation

The OCI Grails Team includes Grails co-founders, Jeff Scott Brown and Graeme Rocher. Check our Grails courses and learn from the engineers who developed, matured and maintain Grails.

Grails OCI Team