Introduction

Spring Framework is a popular, open-source, Java-based application framework - it’s well known for its flexibility and its rich ecosystem. Many other projects are in the Spring Platform, for big data, batch workloads, storing data, securing applications, and more! Spring based applications have a lot of configuration.

Spring Boot takes an opinionated view of the Spring platform and third-party libraries. With Spring Boot, it’s easy to create production-grade Spring based applications for all types of workloads Most Spring Boot applications need very little Spring configuration. Spring Boot is a "convention over configuration" type of framework, with no code generation.

When we use Spring MVC (the original web framework built on the Servlet API) for example, we need to configure for example the dispatcher servlet among other things. When we use the Spring support of Hibernate/JPA, we would need to configure a datasource, an entity manager factory, a transaction manager…​ Spring Boot simplifies all of these configuration elements, by auto-configuration. For example, when it sees spring-webmvc on the classpath, Spring Boot adds automatically @EnableWebMvc on your context.

During the whole lab, you’ll find the Spring Boot reference documentation / javadoc API and the Spring Framework reference documentation / javadoc API quite useful.

During this lab, we’ll first get to know the basic concepts behind Spring Framework and then create a Spring Boot application and experience the development lifecycle with it.

Getting started - Fast!

The best way to start a project with Spring is Spring Initializr. This website will help you to create a minimal skeleton for your project.

For this lab, we’ll select the following options:

  • We’ll generate a Gradle project with Spring Boot 1.5.7.RELEASE

  • Our group Id fr.emse.majeureinfo and artifact Id spring-boot-intro

  • In the dependencies search box, select Web, Devtools and JPA

Click on "Generate", then unzip the file somewhere.

In the spring-boot-intro folder, your build.gradle file should look like this:

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

apply plugin: 'java'
apply plugin: 'eclipse' (2)
apply plugin: 'org.springframework.boot'

group = 'fr.emse.majeureinfo'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

dependencies { (3)
    compile('org.springframework.boot:spring-boot-starter-data-jpa')
    compile('org.springframework.boot:spring-boot-starter-web')
    runtime('org.springframework.boot:spring-boot-devtools')
    testCompile('org.springframework.boot:spring-boot-starter-test')
}
1 Getting the latest stable version of Spring Boot
2 See below : you have to replace 'eclipse' by 'idea'
3 Getting the Web, Devtools Dependencies we selected on start.spring.io and the starter for testing No need to specify versions for all dependencies as Spring Boot manages many versions

Replace apply plugin: 'eclipse' by 'apply plugin: idea'

You can now open a new console and run the following command:

$ ./gradlew idea

Open your project into IDEA

If we have an IDEA notification "Unlinked Gradle project?", please choose to Import Gradle Project (choose your local Gradle distribution)

Then, run :

$ ./gradlew --continuous bootRun (1)

[...]
INFO 9740 --- [  restartedMain] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
INFO 9740 --- [  restartedMain] f.i.tc.s.SpringBootIntroApplication : Started SpringBootIntroApplication in 2.971 seconds
<==========---> 80% EXECUTING
> :bootRun (2)
1 the --continuous gradle option will restart the server when we recompile the project
2 the build gets "stuck" at 80%, but the server is actually started and ready to accept connections

A new Tomcat server instance has started and our application is running on port 8080. Open your browser, and tape http://localhost:8080.

You can see this message like this :

Whitelabel Error Page

This application has no explicit mapping for /error, so you are seeing this as a fallback.

Fri Oct 20 15:34:25 CEST 2017
There was an unexpected error (type=Not Found, status=404).
No message available

Don’t panic : since we’ve defined no web endpoint, Spring answers with a custom HTTP 404 error message…​ We’re going to uderstand what happened

You could have an error about the database configuration. Once again don’t panic : just comment this line in your build.gradle file : // compile('org.springframework.boot:spring-boot-starter-data-jpa'

Anatomy of a Spring Boot application

Now you can browse the source code of your application. Open it in IDEA!

spring-boot-intro
|- build.gradle (1)
|- src/
   |- main/
   |  |- java/
   |  |  |- fr/emse/majeureinfo/springbootintro/
   |  |     |- SpringBootIntroApplication.java (2)
   |  |- resources/
   |     |- static/ (3)
   |     |- templates/ (4)
   |     |- application.properties (5)
   |- test/
      |- java/
         |- fr/emse/majeureinfo/springbootintro/
            |- SpringBootIntroApplicationTests.java (6)
1 Our Gradle build
2 Main Application class
3 Static resources (e.g. CSS, JS)
4 Template files (for rendering HTML views)
5 Spring Boot application properties
6 An example test file

Our main Application class SpringBootIntroApplication looks like this:

src/main/java/fr/emse/majeureinfo/springbootintro/SpringBootIntroApplication.java
@SpringBootApplication (1)
public class SpringBootIntroApplication {

	public static void main(String[] args) { (2)
		SpringApplication.run(SpringBootIntroApplication.class, args); (3)
	}
}
1 This annotation triggers the scanning for Spring beans + auto-configuration of our application
2 You can start this application by just running the "main" method…​
3 …​ Spring Boot’s SpringApplication.run() method lets launch your application.

Did you notice that there wasn’t a single line of XML? No web.xml file either. This web application is 100% pure Java and you didn’t have to deal with configuring any plumbing or infrastructure.

As said above, @SpringBootApplication is a convenience annotation that adds auto-configuration, in fact that adds all of the following:

  • @Configuration tags the class as a source of bean definitions for the application context.

  • @EnableAutoConfiguration tells Spring Boot to start adding beans based on classpath settings, other beans, and various property settings.

  • Normally you would add @EnableWebMvc for a Spring MVC app, but Spring Boot adds it automatically when it sees spring-webmvc on the classpath. This flags the application as a web application and activates key behaviors such as setting up a DispatcherServlet.

  • @ComponentScan tells Spring to look for other components, configurations, and services in the springbootintro package, allowing it to find the controllers.

Dependency Injection

This section explains the concept of Dependency Injection - you’ll start writing code in the Using Dependency Injection section.

When writing an application, as developers, we break the problem we’re trying to solve into smaller ones and do our best keep in line with the architecture and design principles we’ve chosen for our application: flexible, decoupled, testable, easy to understand, etc.

To do that we can break our application into components that collaborate: components are depending on each other. But this adds some cost: we now have to manage the lifecycle and dependencies between those. We can imagine something like this:

Bootstrapping our application
// Setting up our components can be quite challenging
// and we have to maintain this code...
DataStoreConnectionPool connectionPool = new DataStoreConnectionPool();
DataStoreConnection connection = connectionPool.fetchConnection();
UserStore userStore = new UserStore();
CertificateManager certManager = new CertificateManager(certFile);
AuthenticationService authService = new AuthenticationService(userStore, certificateManager);
OrderService orderService = new OrderService(userStore, lineItemService);

Dependency injection solves that problem, and more.

With Spring, you don’t have to write that code, you just need to express those dependencies with Java annotations. Here’s how we could write that code:

using Spring Framework
// CertificateManager.java
@Component (1)
public class CertificateManager {

  //...
}


// DataStoreConnectionPool.java
@Component (1)
public class DataStoreConnectioniPool {

}

// MyAppConfiguration.java
@Configuration (2)
public class MyAppConfiguration {

  @Bean (3)
  public UserStore userStore(DataStoreConnectionPool connectionPool) {
    return new UserStore(connectionPool.fetchConnection());
  }

}

// AuthenticationService.java
@Service (4)
public class AuthenticationService {

  private final UserStore userStore;
  private final CertificateManager certManager;

  @Autowired (5)
  public AuthenticationService(UserStore userStore, CertificateManager certManager) {
    this.userStore = userStore;
    this.certManager = certManager;
  }

  public AcccountStatus getAccountStatus(UserAccount account) {
    // here we can use the UserStore with this.userStore
  }
}
1 We declare our application classes as components, by annotating them…​ @Component
2 We can also have Configuration classes, for components we can’t annotate (not in our codebase) or if we want to instantiate them ourselves. Annotating a class with the @Configuration indicates that the class can be used by the Spring IoC container as a source of bean definitions
3 "Beans" are components instances. A method annotated with @Bean will return an object that should be registered as a bean in the Spring application context @Bean is used to explicitly declare a single bean, rather than letting Spring do it automatically as @Component
4 There are other, specialized annotations to declare Spring components, like @Service
5 By using @Autowired on a constructor, we’re asking Spring to inject here dependencies

@Component (and @Service and @Repository) are used to auto-detect and auto-configure beans using classpath scanning

Once you’ve done that in your application, you need to configure Spring properly and start your application. Then Spring can:

  1. Look for components by scanning your application classpath (e.g. looking for annotated classes in the packages you’ve declared in your configuration)

  2. Register all those components in an application context

  3. Manage the lifecycle of those components (instantiate, set attributes, destroy, etc)

  4. Specialized components can accept work : Spring MVC Controllers will handle HTTP requests, Spring Batch Jobs will run your batch, Spring Data will make easier the usage of data access technologies, etc

In this picture, Spring Boot will configure Spring and provide automatically components for the libraries you’re using - so you can focus on your application code and not the boilerplate.

Using Dependency Injection

First, let’s create an interface for our application src/main/java/fr/emse/majeureinfo/springbootintro/hello/GreetingService.java

GreetingService.java
package fr.emse.majeureinfo.springbootintro.hello;

public interface GreetingService {

  void greet(String name);
}
Good habits fall to the wayside ;-( Don’t forget to commit periodically your work. For this, you have run the git init cmd to convert an existing, unversioned project to a Git repo.

Your first job is to output "Hello, Spring!" in the console as the application starts. For that, do the following:

Create a src/main/java/fr/emse/majeureinfo/springbootintro/hello/ConsoleGreetingService.java implementation of that interface, and mark is as a component. The implementation of the greet method should write to the console using System.out.println.

You can verify that your implementation is working properly by running the following test with the ./gradlew test command.

Add this test, src/test/java/fr/emse/majeureinfo/springbootintro/hello/ConsoleGreetingServiceTests.java, in the src/test folder of your application

ConsoleGreetingServiceTests.java
package fr.emse.majeureinfo.springbootintro.hello;

import org.hamcrest.Matchers;
import org.junit.Rule;
import org.junit.Test;

import org.springframework.boot.test.rule.OutputCapture;

public class ConsoleGreetingServiceTests {

  @Rule
  public OutputCapture outputCapture = new OutputCapture();

  @Test
  public void testGreeting() {
    ConsoleGreetingService greetingService = new ConsoleGreetingService(); (1)
    greetingService.greet("Spring");
    outputCapture.expect(Matchers.startsWith("Hello, Spring!"));
  }
}
1 We’re testing our service implementation without Spring being involved

Now, in the SpringBootIntroApplication class, add a new method that returns a CommandLineRunner. CommandLineRunner instances are found by Spring Boot in the Spring context and are executed during the application startup phase.

SpringBootIntroApplication.java
// inside the existing class, add this method
// import org.springframework.boot.CommandLineRunner;

(1)
public CommandLineRunner greetingCommandLine() { (2)
    return new CommandLineRunner() {
      @Override
      public void run(String... args) throws Exception {
        (3)
      }
    };
}
1 First, annotate this method to mark it as instantiating a bean
2 Then, tell Spring that here we need here a GreetingService component, by declaring it as a method argument
3 Finally, call here some service method to output the "Hello, Spring!" message at startup; since we’re getting GreetingService, no need to instantiate one manually.

Starting your application, you should see something like:

INFO 10522 --- [  restartedMain] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
Hello, Spring!
INFO 10522 --- [  restartedMain] f.i.tc.s.SpringBootIntroApplication      : Started SpringBootIntroApplication in 4.431 seconds (JVM running for 4.886)

DI Edge cases

Now, we’re going to test a few cases to understand how a Spring Application reacts to some situations. For each case, try the suggested modifications, restart your application and see what happens. Of course, after each case, revert those changes, to get "back to normal".

  1. What happens if you comment the @Component / @Service annotation on your ConsoleGreetingService?

  2. Now, try adding AnotherConsoleGreetingService (which says "Bonjour" instead of "Hello"), marked as a component as well. Try again this time after adding a @Primary annotation on ConsoleGreetingService.

  3. Finally, try the following - what happens and why?

ConsoleGreetingService.java
package fr.emse.majeureinfo.springbootintro.hello;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class ConsoleGreetingService implements GreetingService {

  private final CycleService cycleService;

  @Autowired
  public ConsoleGreetingService(CycleService cycleService) {
    this.cycleService = cycleService;
  }

  @Override
  public void greet(String name) {
    System.out.println("Hello, " + name + "!");
  }
}
src/main/java/fr/emse/majeureinfo/springbootintro/hello/CycleService.java
package fr.emse.majeureinfo.springbootintro.hello;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class CycleService {

  private final ConsoleGreetingService consoleGreetingService;

  @Autowired
  public CycleService(ConsoleGreetingService consoleGreetingService) {
    this.consoleGreetingService = consoleGreetingService;
  }
}
@Primary is not the only way to resolve multiple candidates, you can also use @Qualifier; check its javadoc to see how you could use it.

Does Spring Framework stop with Dependency Injection? No. It builds on the core concept of Dependeny Injection but comes with a number of other features (Web, Persistence, etc.) which bring simple abstractions. Aim of these abstractions is to reduce Boilerplate Code and Duplication Code, promoting Loose Coupling of your application architecture. Let’s the persistance support.

Persisting Entities to a database

What’s persistence in Java?

  • a low level standard : JDBC (Java Database Connectivity)

  • an API, JPA (Java Persistence API) and frameworks as Hibernate

With JDBC your code is linked to the database and could be harmful :

JDBC boilerplate
public void insertPerson(Person person) throws SQLException {
   Connection conn = null;
   PreparedStatement stmt = null;
   try {
      conn = dataSource.getConnection();
      stmt = conn.prepareStatement("insert into person (" +
	"id, firstName, lastName) values (?, ?, ?)");
      stmt.setInt(0, person.getId().intValue());
      stmt.setString(1, person.getFirstName());
      stmt.setString(2, person.getLastName());
      stmt.executeUpdate();
   }
   catch(SQLException e) {
      LOGGER.error(e);
   }
   finally {
      try { if (stmt != null) stmt.close(); }
      catch(SQLException e) { LOGGER.warn(e); }

      try { if (conn != null) conn.close(); }
      catch(SQLException e) { LOGGER.warn(e); }
   }
}

With Persistence API/Framework, the approach is to :

  • work with POJO <⇒ Plain Old Java Objects

  • add annotations to map entity properties to table columns

  • run database operations (Create, Update, Delete) in a simple way

  • run get database requests (Read) managing POJO

We’re going to use Spring Data JPA to store and retrieve data in a relational database, and "h2" as an in-memory database.

Do not confuse Spring Data with Spring Data JPA. We can read on in the offical doc that "Spring Data’s mission is to provide a familiar and consistent, Spring-based programming model for data access while still retaining the special traits of the underlying data store. It makes it easy to use data access technologies, relational and non-relational databases, map-reduce frameworks, and cloud-based data services. This is an umbrella project which contains many subprojects that are specific to a given database […​] Spring Data JPA is part of Spring Data, lets implement JPA based repositories. It makes it easier to build Spring-powered applications that use data access technologies."

The Java Persistence API (JPA) is a Java application programming interface specification that describes the management of relational data in applications using Java Platform, Standard Edition and Java Platform, Enterprise Edition.

Hibernate ORM is the JPA implementation that we’re going to use in this lab.

Now create a Light Entity class (src/main/java/fr/emse/majeureinfo/springbootintro/model/Light.java) that we will store a Light in our database.

Light.java
package fr.emse.majeureinfo.springbootintro.model;

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

@Entity (1)
@SuppressWarnings("serial")
public class Light {

  @Id
  @GeneratedValue (2)
  private Long id;

  @Column(nullable = false)
  private Integer level; (3)

  @Enumerated(EnumType.STRING)
  private Status status; (4)

  @SuppressWarnings("unused")
  public Light() {
  }

  public Light(Integer level, Status status) {
      this.level = level;
      this.status = status;
  }

  public Long getId() {
    return this.id;
  }

  public void setId(Long id) {
    this.id = id;
  }

  public Integer getLevel() {
     return level;
  }

  public void setLevel(Integer level) {
     this.level = level;
  }

  public Status getStatus() {
     return status;
  }

  public void setStatus(Status status) {
     this.status = status;
  }
}
1 @Entity define this class a an entity managed by Hibernate
2 use a generated value for the ID (ex : an SQL sequence)
3 the level of the light, mapped to column whcih will have the same name
4 the status (ON/OFF), you have to create an enum, Status, too
This class is annotated with @Column, @Entity and @Id, which helps Spring Data to map Java objects to an actual database table : this is what we call the object-relational mapping (ORM).

An Entity :

  • must have an empty constructor (public or protected). An empty constructor is needed to create a new instance via reflection (using Class<T>.newInstance()) by Hibernate which has to instantiate your Entity dynamically. If you don’t provide any additional constructors with arguments for the class, you don’t need to provide an empty constructor because you get one per default. Java always gives you a default invisible empty constructor. If an argument constructor is provided in your class, then jvm will not add the no-argument constructor.

  • must be annotated by @javax.persistence.Entity

  • must have an ID (@Id). This ID is immutable (as the primary key in the database)

Entity LifeCycle

The entities managed by Hibernate have a life-cycle associated with them. Either you can create a new object and save it into the database or your can fetch the data from the database. The Entities go through several stages in the life-cycle. The stages in the life cycle of an entity managed by Hibernate are as follows:

  • Transient Objects Transient objects are non transactional and in fact Hibernate has no knowledge of these objects

  • Persistent Objects Persistent entity has a valid database identity associated with.

  • Removed Object An object scheduled for deletion either by calling delete or because of orphan deletion of entities.

  • Detached Object The object in persistent state go into detached state after the persistent context is closed. Detached objects can be brought into other persistent context by reattachment or merging. Detached object still has a valid primary key attribute but it is no longer managed by Hibernate.

GitHub mascot
LifeCycle Entity

Association mappings

Association mappings are one of the key features of JPA and Hibernate. They define the relationship between the database tables and the attributes in your Entity.

You can use:

  • one-to-one associations,

  • many-to-one associations,

  • many-to-many associations.

You can map each of them as a uni- or bidirectional association. That means you can either model them as an attribute on only one of the associated entities or on both. That has no impact on your database mapping, but it defines in which direction you can use the relationship.

Write the Room Entity composed by 2 attributes : Light and Noise. Use the right Object-Relational Mapping :

extract of Room Entity
/**
 * The Light of a room
 */
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private Light light;

/**
 * The Noise of a room
 */
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private Noise noise;

Fetching Strategy

First of all, read this post

If you load entities, some of them are loaded as proxies due to lazy loading. If you need later to send some of this objects to your front client via an HTTP request, it could a problem to keep these proxies returned by Hibernate, for the HTTP serialization. There are still error scenarios:

  • 1: out of the persistence layer, in presentation layer (for example in a a controller), an access to a lazy loaded attribute room.getLight() will end up with the famous org.hibernate.LazyInitializationException because the Hibernate Session is closed and this lazy attribute don’t have the session attached and can’t load their lazy references;

  • 2: more, in some case, your could have an error like in your controller if it’s transactional:

Javassist Exception
09:21:26 ERROR fr.emse.majeureinfo.project.web.MyController handleException handleReadDetails error
java.lang.ClassCastException: fr.emse.majeureinfo.project.model.Room_$$_javassist_11 cannot be cast to fr.emse.majeureinfo.project.model.Room

For obvious performance reasons, it is not advisable to turn off the lazy loading: if an object with lazy loaded attributes is manipulated in persistence layer: no problem, the proxy will load the lazy loaded attribute once its necessary; during its ask. If you have to serialize your object, you have to use DTO

Data Access Object (DAO)

A DAO (Data Access Object) lets you persist your Entities. The DAO is basically an object or an interface that provides access to an underlying database or any other persistence storage.

That definition from Wikipedia

Create the following LightDao interface (in a dedicated dao package : src/main/java/fr/emse/majeureinfo/springbootintro/dao/LightDao.java)

LightDao.java
package fr.emse.majeureinfo.springbootintro.dao;

import fr.emse.majeureinfo.springbootintro.model.Light;
import org.springframework.data.jpa.repository.JpaRepository;

public interface LightDao extends JpaRepository<Light, Long> { (1)
}
1 This extends a Spring Data interface, which provides methods such as findOne, save and more. This repository will handle Light entities, and those are identified by an Id of type Long

Creating such an interface is enough! At runtime, Spring Data will create an implementation of that interface for you, and it will be available in the Spring context, so you can inject it in your application. This is a kind of magic!

Configure your database

You must have the following dependencies to your dependencies section of your build.gradle file:

compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('com.h2database:h2')

In the application.properties files, add the following properties to enable the H2 console and configure the Datasource and the Database

###
#   Database Settings (1)
###
spring.datasource.url=jdbc:h2:mem:rooms;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.platform=h2
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driverClassName=org.h2.Driver
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect

###
#   H2 Settings (2)
###
spring.h2.console.enabled=true
spring.h2.console.path=/console
spring.h2.console.settings.trace=false
spring.h2.console.settings.web-allow-others=false

###
#   Hibernate Settings (3)
###
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.use_sql_comments=false
spring.jpa.properties.hibernate.format_sql=false
1 the datasource configuration
2 the H2 console configuration
3 the Hibernate configuration

Now restart your server and with a browser, check out now http://localhost:8080/console .

Make sure to use the value jdbc:h2:mem:rooms as a connection URL in the "JDBC URL" form field (and keep the default username and password)

This is the admin console for our H2 database. You shouldn’t see any database table, since we haven’t persisted anything yet.

Now copy the following file, which should create at startup an entry in the database for you:

src/main/resources/import.sql
INSERT INTO LIGHT (LEVEL, STATUS) VALUES (2,'ON');

Verify, using the h2 console on http://localhost:8080/console/, that this entry is in your database.

Create and Test your first DAO

If your want to write your own DAO methods (for specific requests), you have to create custom interfaces and implementations with your custom methods.

Create your own interface LightDaoCustom

LightDaoCustom
public interface LightDaoCustom {

public List<Light> findOnLights();

}

Refactor your LightDAO interface : it has to extend LightDaoCustom

LightDao
public interface LightDao extends JpaRepository<Light, Long>, LightDaoCustom {
}

Following the TDD (Test Driven Development approach, write your test for your LightDaoCustom component. We’re going to use a dedicated library to test Dao : DBSetup (open source lib proudly powered by Ninja Squad ♥).

Add this to the dependencies section of your build.gradle file:

testCompile 'com.ninja-squad:DbSetup:2.1.0'

and write your test, what you’re expecting :

LightDaoCustomTest
@RunWith(SpringRunner.class)
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@TestPropertySource("/test.properties")
public class LightDaoCustomTest {

    @Autowired
    private LightDao lightDao;


    @Qualifier("dataSource")
    @Autowired
    private DataSource dataSource;

    protected static final DbSetupTracker TRACKER = new DbSetupTracker();

    private static final Operation DELETE_ALL = DeleteAll.from("light");

    protected void dbSetup(Operation operation) {
        DbSetup setup = new DbSetup(new DataSourceDestination(dataSource),
                Operations.sequenceOf(DELETE_ALL, operation));
        TRACKER.launchIfNecessary(setup);
    }

    @Before
    public void prepare() {
        Operation light =
                Insert.into("LIGHT")
                        .withDefaultValue("status", Status.ON)
                        .columns("id", "level")
                        .values(1L, 22)
                        .build();
        dbSetup(light);
    }

    @Test
    public void shouldFindOnLights() {
        TRACKER.skipNextLaunch();
        assertThat(lightDao.findOnLights()).hasSize(1);
    }


}

Create your own implementation of LightDao with your custom methods and inject the EntityManager (JPA)

LightDaoImpl
public class LightDaoImpl implements LightDaoCustom {
    @PersistenceContext
    private EntityManager em;

    @Override
    public List<Light> findOnLights() {
        String jpql = "select lt from Light lt where lt.status = :value";
        TypedQuery<Light> query = em.createQuery(jpql, Light.class);
        return query.setParameter("value", Status.ON)
                .getResultList();
    }
}

Develop other Entities and DAO

You have to test and develop :

  • Noise Entity (same attributes of Light)

  • NoiseDAO

  • RoomDAO

Add new values in your import.sql file, for example

src/main/resources/import.sql
INSERT INTO LIGHT (ID, LEVEL, STATUS) VALUES (1, 20,'ON');
INSERT INTO NOISE (ID, LEVEL, STATUS) VALUES (1, 30,'ON');
INSERT INTO ROOM (ID, LIGHT_ID, NOISE_ID) VALUES (1, 1, 1);

Web Development

Spring MVC is the Web Framework built in Spring; it helps you write web applications and takes care of a lot of boilerplate code, so you just have to focus on your application features.

Data Transfer Object (DTO)

A DTO is an object that carries data between processes. Creating a Data Transfer Object for our web process lets you manage all the data for the HTTP requests. Data need to be serializable to go across the HTTP connection. It’s often little more than a bunch of fields and the getters and setters for them.

For example, here is the LightDto (put in a web package : src/main/java/fr/emse/majeureinfo/springbootintro/web/LightDto.java) :

LightDto.java
public class LightDto {

    private final Long id;
    private final Integer level;
    private final Status status;

    public LightDto(Light light) {
        this.id = light.getId();
        this.level = light.getLevel();
        this.status = light.getStatus();
    }

    public Long getId() {
        return id;
    }

    public Integer getLevel() {
        return level;
    }

    public Status getStatus() {
        return status;
    }
}

With the same approach, write the NoiseDTo and the RoomDto.

Simple Controller

In Spring’s approach to building RESTful web services, HTTP requests are handled by a controller. Controllers are the link between the web http clients (browsers, mobiles) and your application; they should be lightweight and call other components in your application to perform actual work (DAO for example). These components are easily identified by the @Controller annotation.

Now, create the following RoomController (in a dedicated web package : src/main/java/fr/emse/majeureinfo/springbootintro/web/RoomController.java)

RoomController.java
@RestController
@RequestMapping(value = "/api/rooms")
@Transactional
public class RoomController {

    private final RoomDao roomDao;


    public RoomController(RoomDao roomDao) {
        this.roomDao = roomDao;
    }

    @GetMapping
    public List<RoomDto> list() {
        return roomDao.findAll().stream().map(RoomDto::new).collect(Collectors.toList());
    }

}

This RoomController handles GET requests for /api/rooms by returning a list of RoomDTO. Tu do hat, it uses a service of our RoomDAO.

CORS Filter

Add this filter in your project (under the web package). This CORS Filter is a generic solution for fitting Cross-Origin Resource Sharing (CORS) support to your application. CORS is a W3C standard for enabling cross-domain requests from web browsers to servers and web APIs that opt in to handle them.

When web have REST wevservices, we use generally the javascript method XMLHttpRequest (XHR) implemented bu your browser. In order to ensure the security, a lot of browsers forbid the “cross-domain” requests, in order to avoid XSRF attacks (Cross-site request forgery).

The Cross-origin resource sharing (CORS) allows to resolve the problem (under normalization by the W3C). CORS allows a server to relax the same-origin policy. Using CORS, a server can explicitly allow some cross-origin requests while rejecting others. CORS is safer and more flexible than earlier techniques such as JSONP.

The approach of CORS i to add informations is the HTTP Headers.

SimpleCORSFilter.java
package fr.emse.majeureinfo.springbootintro.web;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

@Component
@WebFilter(value = "/*")
public class SimpleCORSFilter implements Filter {

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest request = (HttpServletRequest) req;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Headers", "Origin,Accept,X-Requested-With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization");
        if(request.getMethod().equals(HttpMethod.OPTIONS.name())){
            response.setStatus(HttpStatus.NO_CONTENT.value());
        }else{
            chain.doFilter(req, res);
        }
    }

    public void init(FilterConfig filterConfig) {}

    public void destroy() {}
}

Deploy your app on a Cloud platform

Heroku is a good Cloud platform for making server configurations easy and painless. You don’t have to configure your own servers.

Let’s look at how we can deploy our application to Heroku. Read the documentation.

Your have to install the Heroku Command Line Interface (CLI), in order to use the heroku command from your command shell

Add this elements to the section dependencies of your build.gradle :

build.gradle`
compile "com.heroku.sdk:heroku-jdbc:0.1.1"

Run this cmd :

heroku login

Enter your Heroku credentials and Run this cmd :

heroku create

You should have this in the console :

Creating app... done, ⬢ limitless-hamlet-31632
https://limitless-hamlet-31632.herokuapp.com/ | https://git.heroku.com/limitless-hamlet-31632.git

This cmd creates an app on Heroku, which prepares Heroku to receive your source code. A Git remote (called heroku) is also created and associated with your local Git repository. Heroku generates a random name (in this case limitless-hamlet-31632) for your app, or you can pass a parameter to specify your own app name.

Now deploy your code:

git push heroku master

The application is now deployed. Now launch one instance of the app :

heroku ps:scale web=1

Now visit the app at the URL generated by its app name (in this case https://limitless-hamlet-31632.herokuapp.com/)

If you are lazy, you can open the website as follows:

heroku open

View information about your running app using one of the logging commands, heroku logs:

heroku logs --tail

(Press Control+C to stop streaming the logs)

To stop your application, run :

heroku ps:scale web=0

or :

heroku stop web=0

The Gradle buildpack will run different build tasks depending on the frameworks it detects in your app. For Spring Boot, it will run ./gradlew build -x test

If no known web frameworks are detected, it will run ./gradlew stage (if you need to customize your build, you can create a stage task in your `build.gradle file, we don’t need this in our case).

For Spring Boot, the Gradle buildpack will create too a web process type with the following command:

java -Dserver.port=$PORT $JAVA_OPTS -jar build/libs/*.jar

(If you need to customize or override the default web command, you must create a Procfile).

You can collaborate with your colleagues on your heroku deployment : read the doc

Do It Yourself

Now, develop the following services in your RoomController:

RoomController
    ...
    public RoomDto get(Long roomId) {
            ...
    }
    ...
    public RoomDto switchLight(Long roomId) {
            ...
    }
    ...
    public RoomDto switchRinger(Long roomId) {
            ...
    }
    ...
    public List<RoomDto> listWithOnLight() {
            ...
    }
Be careful, these methods above don’t have any annotation, but you’ll certainly need them! You have to find the right ones! For the last service, your have to write a custom RoomDao method findRoomsWithOnLight()