About

Speedment Enterprise offers a Spring Boot plugin that allows generation of Spring configurations, greatly simplifying integration between Speedment and Spring. The plugin can also generate complete REST endpoints for tables and views. These endpoints can be queried using filters, sorters and/or pagers.

Integration

To include the Enterprise Spring Boot Plugin in your Speedment project, add the SpringGeneratorBundle to the speedment-enterprise-maven-plugin:

<plugin>
    <groupId>com.speedment.enterprise</groupId>
    <artifactId>speedment-enterprise-maven-plugin</artifactId>
    <version>${speedment.version}</version>

    <configuration>
        <components>
            <component>com.speedment.enterprise.plugins.spring.SpringGeneratorBundle</component>
        </components>
        <appName>${project.artifactId}</appName>
        <packageName>${project.groupId}</packageName>
     </configuration>

     ...

</plugin>

In order to run a Spring Boot/Speedment application, you also need to include the Enterprise Spring Boot Plugin runtime dependency in your Speedment project:

<dependency>
    <groupId>com.speedment.enterprise.plugins</groupId>
    <artifactId>spring-runtime</artifactId>
    <version>${speedment.enterprise.version}</version>
</dependency>

Spring Configuration

The Spring Boot plugin will automatically generate Spring configuration files that can be picked up by Spring’s dependency injection features. For example, the following file will be generated if the plugin runs against the Sakila database (GeneratedSakilaConfiguration.java truncated for brievity):

@GeneratedCode("Speedment")
public class GeneratedSakilaConfiguration {

    @Bean
    public SakilaApplication getApplication() {
        return getApplicationBuilder().build();
    }

    public SakilaApplicationBuilder getApplicationBuilder() {
        ...
    }

    @Bean
    public JsonComponent getJsonComponent(SakilaApplication app) {
        return app.getOrThrow(JsonComponent.class);
    }

    @Bean
    public JoinComponent getJoinComponent(SakilaApplication app) {
        return app.getOrThrow(JoinComponent.class);
    }

    @Bean
    public FilmActorManager getFilmActorManager(SakilaApplication app) {
        return app.getOrThrow(FilmActorManager.class);
    }

    ...

}

These beans can then be picked up in Spring application by means of the @Autowired annotation as shown here:


    @Autowired FilmManager films:

    ...

    public long countAllFilms() {
        return films.stream().count();
     }

This greatly simplifies application development and creates a losened coupling between components compared to explicitly handling the components.

Application Settings

There are a number of custom application settings that can be set without modifying any code:

Name Meaning
spring.speedment.password The database password credential to be used when loging into the backing database
spring.speedment.username The database username credential to be used when loging into the backing database. If not set, uses the same username that was used for code generation
spring.speedment.host The database host name to be used when connecting to the backing database. If not set, uses the same address that was used for code generation
spring.speedment.port The port number of the Spring web server (1 - 65535). If not set, uses the same port that was used for code generation
spring.speedment.logging If set to true, enables logging of various evenst such as streaming and application build
spring.speedment.url The database connection URL to be used when connecting to the backing database. If not set, a default conneciton URL is used

These parameters can be set in resource files and/or on the command line.

The following command sets the database password to “sakila-password” for application when run:

java -jar target/rest-api-example-1.0.0-SNAPSHOT.jar --spring.speedment.password=sakila-password

The parameter resource file can be located either in the file ‘/src/main/resources/application.yml’ and/or in a file ‘application.yml’ located in the current directory of the application. Elements in the latter file will take precidence over eleeents in the former file and elements on the command line will take absoulte precidence. The following application.yml file sets the database password to “sakila-password”:

spring:
  speedment:
    password: sakila-password

REST Controllers

In order to open up a table for REST access, The REST controllers must be enabled in the Speedment Tool for the corresponding table as shown in the picture below:

Spring Plugin Table Properties
Tool: How to Enable REST Table Access.

REST Syntax

When REST is enabled for a table, it contents can be retrieved by invoking a rest call. For example, elements from the “film” table can be retrieved like this:

 curl localhost:8080/sakila/film

This will retrieve the first 25 films (where only the first two elements are shown for brievity):

[
   {
        "description": "A Epic Drama of a Feminist And a Mad Scientist who must Battle a Teacher in The Canadian Rockies",
        "filmId": 1,
        "languageId": 1,
        "lastUpdate": "2006-02-15 14:03:42.0",
        "length": "86",
        "originalLanguageId": null,
        "rating": "PG",
        "releaseYear": "2006-01-01",
        "rentalDuration": 6,
        "rentalRate": "0.99",
        "replacementCost": "20.99",
        "specialFeatures": "Deleted Scenes,Behind the Scenes",
        "title": "ACADEMY DINOSAUR"
    },
    {
        "description": "A Astounding Epistle of a Database Administrator And a Explorer who must Find a Car in Ancient China",
        "filmId": 2,
        "languageId": 1,
        "lastUpdate": "2006-02-15 14:03:42.0",
        "length": "48",
        "originalLanguageId": null,
        "rating": "G",
        "releaseYear": "2006-01-01",
        "rentalDuration": 3,
        "rentalRate": "4.99",
        "replacementCost": "12.99",
        "specialFeatures": "Trailers,Deleted Scenes",
        "title": "ACE GOLDFINGER"
    },
    ....
]

By default, only the first 25 elements are returned. See paging for information on retrieving any number of elements.

Using Filters

The spring plugin supports remote filtering. It means that the frontend can send predicates encoded as JSON-objects to the server, and the server will respond with a filtered JSON response. Speedment automatically parses the JSON filters into a SQL SELECT-statement or an in-memroy index search.

The syntax for the JSON filters is straight forward and is using a property/operator/value tuple to define the filters:

filter={"property":"xx","operator":"yy","value":zz}

The “property” xx is the name of the column you want to apply the filter to. For example “length” or “name”.

The “operator” yy can be any operator shown in the table below:

Operator Equivalence Meaning
eq = Equal to
ne != Not equal to
lt < Less than
le <= Less or equal to
gt > Greater than
ge >= Greater or equal to
like contains() Contains

The “value” zz is the fixed numeric or string value to use when applying the operator. For example, 60 or “The Golden Era”.

The following example shows how to retrieve films with a length less than 60 minutes:

curl -G localhost:8080/sakila/film --data-urlencode \
   'filter={"property":"length","operator":"lt","value":60}'

(The -G argument makes sure that the command is sent as a GET request and not a POST request)

This will produce the following output (only the first two elements are shown for brievity):

[
    {
        "description": "A Astounding Epistle of a Database Administrator And a Explorer who must Find a Car in Ancient China",
        "filmId": 2,
        "languageId": 1,
        "lastUpdate": "2006-02-15 14:03:42.0",
        "length": "48",
        "originalLanguageId": null,
        "rating": "G",
        "releaseYear": "2006-01-01",
        "rentalDuration": 3,
        "rentalRate": "4.99",
        "replacementCost": "12.99",
        "specialFeatures": "Trailers,Deleted Scenes",
        "title": "ACE GOLDFINGER"
    },
    {
        "description": "A Astounding Reflection of a Lumberjack And a Car who must Sink a Lumberjack in A Baloon Factory",
        "filmId": 3,
        "languageId": 1,
        "lastUpdate": "2006-02-15 14:03:42.0",
        "length": "50",
        "originalLanguageId": null,
        "rating": "NC-17",
        "releaseYear": "2006-01-01",
        "rentalDuration": 7,
        "rentalRate": "2.99",
        "replacementCost": "18.99",
        "specialFeatures": "Trailers,Deleted Scenes",
        "title": "ADAPTATION HOLES"
    },
    ...
]

Multiple filters can be used by wrapping the filters objects into an array like this:

curl -G localhost:8080/sakila/film --data-urlencode \
   'filter=[{"property":"length","operator":"lt","value":60},
   {"property":"length","operator":"ge","value":30}]'

This will return all films with a length between 30 and 60 minutes. By default, all the operators in the filter array are assumed to be separated with AND-operators. Thus, all the conditions must apply for a row to pass the filter. It is also possible to use an explicit OR-statement as shown hereunder:

curl -G localhost:8080/sakila/film --data-urlencode \
   'filter={"or":[{"property":"length","operator":"lt","value":30},
   {"property":"length","operator":"ge","value":60}]}'

This will return all films that are either shorter than 30 minutes or longer than one hour.

Using Sorters

The order in which elements appear in the output is undefined. To define a certain order, the sort command can be used.

The following example shows how to sort film elements by lenght in the default order (ascending):

curl -G localhost:8080/sakila/film --data-urlencode \
   'sort={"property":"length"}'

This will produce the following output (only the first two elements are shown for brievity):

[
    {
        "description": "A Brilliant Drama of a Cat And a Mad Scientist who must Battle a Feminist in A MySQL Convention",
        "filmId": 15,
        "languageId": 1,
        "lastUpdate": "2006-02-15 14:03:42.0",
        "length": "46",
        "originalLanguageId": null,
        "rating": "NC-17",
        "releaseYear": "2006-01-01",
        "rentalDuration": 5,
        "rentalRate": "2.99",
        "replacementCost": "10.99",
        "specialFeatures": "Trailers,Commentaries,Behind the Scenes",
        "title": "ALIEN CENTER"
    },
    {
        "description": "A Fast-Paced Documentary of a Mad Cow And a Boy who must Pursue a Dentist in A Baloon",
        "filmId": 469,
        "languageId": 1,
        "lastUpdate": "2006-02-15 14:03:42.0",
        "length": "46",
        "originalLanguageId": null,
        "rating": "PG",
        "releaseYear": "2006-01-01",
        "rentalDuration": 7,
        "rentalRate": "4.99",
        "replacementCost": "27.99",
        "specialFeatures": "Commentaries,Behind the Scenes",
        "title": "IRON MOON"
    },
    ...
]

The following example shows how to sort film elements by lenght in reversed (decending) order:

curl -G localhost:8080/sakila/film --data-urlencode \
   'sort={"property":"length","direction":"DESC"}'

This will produce the following output (only the first two elements are shown for brievity):

[
    {
        "description": "A Lacklusture Panorama of a A Shark And a Pioneer who must Confront a Student in The First Manned Space Station",
        "filmId": 817,
        "languageId": 1,
        "lastUpdate": "2006-02-15 14:03:42.0",
        "length": "185",
        "originalLanguageId": null,
        "rating": "R",
        "releaseYear": "2006-01-01",
        "rentalDuration": 7,
        "rentalRate": "4.99",
        "replacementCost": "27.99",
        "specialFeatures": "Trailers,Commentaries,Deleted Scenes,Behind the Scenes",
        "title": "SOLDIERS EVOLUTION"
    },
    {
        "description": "A Taut Character Study of a Woman And a A Shark who must Confront a Frisbee in Berlin",
        "filmId": 349,
        "languageId": 1,
        "lastUpdate": "2006-02-15 14:03:42.0",
        "length": "185",
        "originalLanguageId": null,
        "rating": "PG-13",
        "releaseYear": "2006-01-01",
        "rentalDuration": 4,
        "rentalRate": "2.99",
        "replacementCost": "27.99",
        "specialFeatures": "Behind the Scenes",
        "title": "GANGS PRIDE"
    },
    ...
]

By wrapping sort objects into an array, several sort orders can be use as shown hereunder:

curl -G localhost:8080/sakila/film --data-urlencode \
   'sort=[{"property":"length","direction":"DESC"},
   {"property":"title","direction":"ASC"}]'

This will prouduce an output sorded by lenght in decending order as primary sort criteria and by title in ascending order as secondary sort cirteria (only the first two elements are shown for brievity):

[
    {
        "description": "A Fateful Yarn of a Mad Cow And a Waitress who must Battle a Student in California",
        "filmId": 141,
        "languageId": 1,
        "lastUpdate": "2006-02-15 14:03:42.0",
        "length": "185",
        "originalLanguageId": null,
        "rating": "PG-13",
        "releaseYear": "2006-01-01",
        "rentalDuration": 6,
        "rentalRate": "4.99",
        "replacementCost": "11.99",
        "specialFeatures": "Deleted Scenes,Behind the Scenes",
        "title": "CHICAGO NORTH"
    },
    {
        "description": "A Fateful Documentary of a Robot And a Student who must Battle a Cat in A Monastery",
        "filmId": 182,
        "languageId": 1,
        "lastUpdate": "2006-02-15 14:03:42.0",
        "length": "185",
        "originalLanguageId": null,
        "rating": "G",
        "releaseYear": "2006-01-01",
        "rentalDuration": 7,
        "rentalRate": "4.99",
        "replacementCost": "9.99",
        "specialFeatures": "Commentaries",
        "title": "CONTROL ANTHEM"
    },
    ...
]

Using Paging

The last feature of the spring plugin plugin is the ability to page results to avoid sending unnecessary large objects to the consuming end. This is enabled by default, which is why at most 25 results are seen when querying the backend. To skip a number of results (not pages), the ?start= parameter can be used as shown here:

curl localhost:8080/sakila/film?start=25

This will skip the first 25 elements and begin at the 26th. The default page size can also be changed by adding the ?limit= parameter:

curl 'localhost:8080/sakila/film?start=25&limit=5'

This also begins at the 26th element, but only returns 5 elements instead of 25 as show hereunder (all five element are shown):

[
    {
        "description": "A Amazing Panorama of a Pastry Chef And a Boat who must Escape a Woman in An Abandoned Amusement Park",
        "filmId": 26,
        "languageId": 1,
        "lastUpdate": "2006-02-15 14:03:42.0",
        "length": "86",
        "originalLanguageId": null,
        "rating": "G",
        "releaseYear": "2006-01-01",
        "rentalDuration": 3,
        "rentalRate": "0.99",
        "replacementCost": "15.99",
        "specialFeatures": "Commentaries,Deleted Scenes",
        "title": "ANNIE IDENTITY"
    },
    {
        "description": "A Amazing Reflection of a Database Administrator And a Astronaut who must Outrace a Database Administrator in A Shark Tank",
        "filmId": 27,
        "languageId": 1,
        "lastUpdate": "2006-02-15 14:03:42.0",
        "length": "179",
        "originalLanguageId": null,
        "rating": "NC-17",
        "releaseYear": "2006-01-01",
        "rentalDuration": 7,
        "rentalRate": "0.99",
        "replacementCost": "12.99",
        "specialFeatures": "Deleted Scenes,Behind the Scenes",
        "title": "ANONYMOUS HUMAN"
    },
    {
        "description": "A Touching Panorama of a Waitress And a Woman who must Outrace a Dog in An Abandoned Amusement Park",
        "filmId": 28,
        "languageId": 1,
        "lastUpdate": "2006-02-15 14:03:42.0",
        "length": "91",
        "originalLanguageId": null,
        "rating": "PG-13",
        "releaseYear": "2006-01-01",
        "rentalDuration": 5,
        "rentalRate": "4.99",
        "replacementCost": "16.99",
        "specialFeatures": "Deleted Scenes,Behind the Scenes",
        "title": "ANTHEM LUKE"
    },
    {
        "description": "A Fateful Yarn of a Womanizer And a Feminist who must Succumb a Database Administrator in Ancient India",
        "filmId": 29,
        "languageId": 1,
        "lastUpdate": "2006-02-15 14:03:42.0",
        "length": "168",
        "originalLanguageId": null,
        "rating": "NC-17",
        "releaseYear": "2006-01-01",
        "rentalDuration": 5,
        "rentalRate": "2.99",
        "replacementCost": "11.99",
        "specialFeatures": "Trailers,Commentaries,Deleted Scenes",
        "title": "ANTITRUST TOMATOES"
    },
    {
        "description": "A Epic Story of a Pastry Chef And a Woman who must Chase a Feminist in An Abandoned Fun House",
        "filmId": 30,
        "languageId": 1,
        "lastUpdate": "2006-02-15 14:03:42.0",
        "length": "82",
        "originalLanguageId": null,
        "rating": "R",
        "releaseYear": "2006-01-01",
        "rentalDuration": 4,
        "rentalRate": "2.99",
        "replacementCost": "27.99",
        "specialFeatures": "Trailers,Deleted Scenes,Behind the Scenes",
        "title": "ANYTHING SAVANNAH"
    }
]

Combinations

Filters, sorters and paging can be combined to create a compound REST backend operation.

The following example will retrieve all films that are shorter than 60 minutes and that are sorted by title showing the third page (i.e. skipping 150 films and showing the following 50 films):

curl -G localhost:8080/sakila/film --data-urlencode \
   'filter={"property":"length","operator":"lt","value":60} \
   &sort={"property":"length"} \
   &start=150 \
   &limit50'

Discussion

Join the discussion in the comment field below or on Gitter