Spring Boot REST H2
last modified July 25, 2023
In this article we create a simple Spring Boot RESTful application with H2 database.
Spring is a popular Java application framework for creating enterprise applications. Spring Boot is a way to create stand-alone, production-grade Spring based applications with minimal effort.
Apache Tomcat is an open source Java Servlet Container developed by the Apache Software Foundation (ASF). Tomcat implements several Java EE specifications including Java Servlet, JavaServer Pages (JSP), Java EL, and WebSocket. Tomcat can be run in standalone and embedded mode.
H2 is an open source relational database management system created entirely in Java. It can be embedded in Java applications or run in the client-server mode. It is easy to deploy and install and has small footprint.
JdbcTemplate is a Spring library that helps programmers create
applications that work with relational databases and JDBC. It takes care of many
tedious and error-prone low-level details such as handling transactions,
cleaning up resources, and correctly handling exceptions.
JdbcTemplate is shipped in Spring's spring-jdbc
module.
JSON (JavaScript Object Notation) is a lightweight data-interchange
format. Humans can easily read and write and machines parse and generate JSON.
The official Internet media type for JSON is application/json
. The
JSON filename extension is .json
.
A RESTFul application follows the REST architectural style, which is used for designing networked applications. RESTful applications generate HTTP requests which perform CRUD (Create/Read/Update/Delete) operations on resources.
Application
Our application is a Spring Boot RESTful application that runs on embedded Tomcat server. It returns data from H2 database in JSON format. The application uses JdbcTemplate to simplify JDBC programming.
build.gradle ... src ├── main │ ├── java │ │ └── com │ │ └── zetcode │ │ ├── Application.java │ │ ├── bean │ │ │ └── City.java │ │ ├── controller │ │ │ └── MyController.java │ │ └── service │ │ ├── CityService.java │ │ └── ICityService.java │ └── resources │ ├── application.yml │ ├── data-h2.sql │ └── schema-h2.sql └── test └── java
This is the project structure.
plugins { id 'org.springframework.boot' version '3.1.1' id 'io.spring.dependency-management' version '1.1.0' id 'java' } group = 'com.zetcode' version = '0.0.1-SNAPSHOT' sourceCompatibility = '17' repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-jdbc' implementation 'com.h2database:h2' }
This is the Gradle build file. The h2
dependency is a driver for H2
database. The spring-boot-starter-web
is starter for building web,
including RESTful, applications using Spring MVC. The
spring-boot-starter-jdbc
is a starter for using JDBC in Spring
Boot.
server: port: 8086 servlet: context-path: /rest spring: main: banner-mode: "off" datasource: driverClassName: org.h2.Driver url: jdbc:h2:mem:testdb sql: init: platform: h2 logging: level: org: springframework: ERROR
The application.yml
file contains various configuration settings of
a Spring Boot application. We have mappings for server port and context path
(application name). With the banner-mode
property we turn off the
Spring banner. The platform value is used in SQL initialization scripts:
schema-${platform}.sql
and data-${platform}.sql
. The
H2 database is run in memory. Also, we set the logging level for spring
framework to ERROR. The file is located in the in the
src/main/resources
directory.
package com.zetcode.bean; public class City { private Long id; private String name; private int population; public City() { } public City(Long id, String name, int population) { this.id = id; this.name = name; this.population = population; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getPopulation() { return population; } public void setPopulation(int population) { this.population = population; } @Override public String toString() { return "City{" + "id=" + id + ", name=" + name + ", population=" + population + '}'; } }
This is the City
bean.
CREATE TABLE cities(id BIGINT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255), population BIGINT);
This SQL script creates the cities
table.
INSERT INTO cities(name, population) VALUES('Bratislava', 432000); INSERT INTO cities(name, population) VALUES('Budapest', 1759000); INSERT INTO cities(name, population) VALUES('Prague', 1280000); INSERT INTO cities(name, population) VALUES('Warsaw', 1748000); INSERT INTO cities(name, population) VALUES('Los Angeles', 3971000); INSERT INTO cities(name, population) VALUES('New York', 8550000); INSERT INTO cities(name, population) VALUES('Edinburgh', 464000); INSERT INTO cities(name, population) VALUES('Berlin', 3671000);
This script fills the table with data. Both scripts are located in the root of the classpath.
package com.zetcode.service; import com.zetcode.bean.City; import java.util.List; public interface ICityService { List<City> findAll(); City findById(Long id); }
ICityService
provides contract methods to get all cities and get a
city by its id from the data source.
package com.zetcode.service; import com.zetcode.bean.City; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import java.util.List; @Service public class CityService implements ICityService { private final JdbcTemplate jtm; @Autowired public CityService(JdbcTemplate jtm) { this.jtm = jtm; } @Override public List<City> findAll() { String sql = "SELECT * FROM cities"; return jtm.query(sql, new BeanPropertyRowMapper<>(City.class)); } @Override public City findById(Long id) { String sql = "SELECT * FROM cities WHERE id=?"; return jtm.queryForObject(sql, new BeanPropertyRowMapper<>(City.class), id); } }
CityService
contains the implementation of the findAll
and findById
methods. We use Spring JdbcTemplate to execute SQL
code.
private final JdbcTemplate jtm; @Autowired public CityService(JdbcTemplate jtm) { this.jtm = jtm; }
JdbcTemplate
is injected.
String sql = "SELECT * FROM cities";
This is SQL to select all cities from the cities
table.
return jtm.query(sql, new BeanPropertyRowMapper<>(City.class));
The statement is executed with query
.
BeanPropertyRowMapper
converts a row into a new instance of the
specified mapped target class.
String sql = "SELECT * FROM cities WHERE id=?";
This is SQL to select a specific city identified by id from the
cities
table.
return jtm.queryForObject(sql, new BeanPropertyRowMapper<>(City.class), id);
To get one row from the cities
table, we use the
queryForObject
method.
package com.zetcode.controller; import com.zetcode.bean.City; import com.zetcode.service.ICityService; 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; import java.util.List; @RestController public class MyController { private final ICityService cityService; @Autowired public MyController(ICityService cityService) { this.cityService = cityService; } @RequestMapping("/cities") public List<City> findCities() { return cityService.findAll(); } @RequestMapping("/cities/{userId}") public City findCity(@PathVariable Long userId) { return cityService.findById(userId); } }
This is the controller class for the Spring Boot RESTful application. The
@RestController
annotation creates a RESTful controller. While the
traditional MVC controller uses ModelAndView
, the RESTful
controller simply returns the object and the object data is written directly to
the HTTP response in JSON or XML format.
private final ICityService cityService; @Autowired public MyController(ICityService cityService) { this.cityService = cityService; }
We inject a ICityService
into the countryService
field.
@RequestMapping("/cities") public List<City> findCities() { return cityService.findAll(); }
The @RequestMapping
annotation is used to map web requests to Spring
controller methods. Here we map a request with the /cities
path
to the controller's findCities
method. The default request is
a GET request.
We do not need to convert the City
domain object to JSON manually.
Because Jackson 2 is on the classpath, included via
spring-boot-starter-web
, Spring chooses
MappingJackson2HttpMessageConverter
automatically to convert the City
instance to JSON.
package com.zetcode; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
The Application
sets up the Spring Boot application.
The @SpringBootApplication
enables auto-configuration and
component scanning.
$ ./gradlew bootRun
With ./gradlew bootRun
command, we run the application. The
application is deployed on embedded Tomcat server.
$ curl localhost:8086/rest/cities [{"id":1,"name":"Bratislava","population":432000},{"id":2,"name":"Budapest","population":1759000}, {"id":3,"name":"Prague","population":1280000},{"id":4,"name":"Warsaw","population":1748000}, {"id":5,"name":"Los Angeles","population":3971000},{"id":6,"name":"New York","population":8550000}, {"id":7,"name":"Edinburgh","population":464000},{"id":8,"name":"Berlin","population":3671000}]
With the curl
command, we get all cities.
$ curl localhost:8086/rest/cities/1 {"id":1,"name":"Bratislava","population":432000}
Here we get one city identified by its id.
In this article we have created a Spring Boot RESTful application, which returns data from H2 database in JSON format.