# Spring Boot H2 REST 教程

> 原文： [http://zetcode.com/articles/springbootresth2/](http://zetcode.com/articles/springbootresth2/)

在本教程中，我们将使用 H2 数据库创建一个简单的 Spring Boot RESTful 应用。

Spring 是用于创建企业应用的流行 Java 应用框架。 Spring Boot 是一种以最少的精力创建独立的，基于生产级别的基于 Spring 的应用的方法。

Apache Tomcat 是由 Apache 软件基金会（ASF）开发的开源 Java Servlet 容器。 Tomcat 实现了几种 Java EE 规范，包括 Java Servlet，JavaServer Pages（JSP），Java EL 和 WebSocket。 Tomcat 可以独立和嵌入式模式运行。

H2 是完全用 Java 创建的开源关系数据库管理系统。 它可以嵌入 Java 应用中或以客户端-服务器模式运行。 它易于部署和安装，占地面积小。

`JdbcTemplate`是一个 Spring 库，可以帮助程序员创建与关系数据库和 JDBC 一起使用的应用。 它会处理许多繁琐且容易出错的底层细节，例如处理事务，清理资源以及正确处理异常。 `JdbcTemplate`在 Spring 的`spring-jdbc`模块中提供。

JSON（JavaScript 对象表示法）是一种轻量级的数据交换格式。 人类可以轻松地进行读写，并通过机器解析并生成 JSON。 JSON 的官方互联网媒体类型为`application/json`。 JSON 文件扩展名是`.json`。

RESTFul 应用遵循 REST 架构样式，该样式用于设计网络应用。 RESTful 应用生成 HTTP 请求，这些请求对资源执行 CRUD（创建/读取/更新/删除）操作。

## 应用

我们的应用是一个运行在嵌入式 Tomcat 服务器上的 Spring Boot RESTful 应用。 它以 JSON 格式从 H2 数据库返回数据。 该应用使用`JdbcTemplate`简化 JDBC 编程。

```java
$ tree
.
├── pom.xml
└── 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         

```

这是项目结构。

`pom.xml`

```java
<?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.zetcode</groupId>
    <artifactId>SpringBootRestH2</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.3.RELEASE</version>
    </parent>    

    <dependencies>

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>     

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>                                              

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>         

    </dependencies>       

</project>

```

这是 Maven 构建文件。 `h2`依赖项是 H2 数据库的驱动程序。 `spring-boot-devtools`启用热插拔，禁用模板缓存并启用实时重载。 `spring-boot-starter-web`是使用 Spring MVC 构建 Web（包括 RESTful）应用的入门程序。 `spring-boot-starter-jdbc`是在 Spring Boot 中使用 JDBC 的入门工具。

`application.yml`

```java
server:
    port: 8086
    context-path: /rest

spring: 
    main:
        banner-mode: "off"       
    datasource:
        platform: h2
        driverClassName: org.h2.Driver
        url: jdbc:h2:mem:test;MODE=PostgreSQL

logging: 
    level: 
        org: 
            springframework: ERROR

```

`application.yml`文件包含 Spring Boot 应用的各种配置设置。 我们具有服务器端口和上下文路径（应用名称）的映射。 使用`banner-mode`属性，我们可以关闭 Spring 横幅。 该平台值用在 SQL 初始化脚本中：`schema-${platform}.sql`和`data-${platform}.sql`。 我们将 H2 设置为使用 PostgreSQL 兼容模式。 H2 数据库在内存中运行。 另外，我们将 spring 框架的日志记录级别设置为`ERROR`。 该文件位于`src/main/resources`目录中。

`City.java`

```java
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 + '}';
    }
}

```

这是`City` bean。

`schema-h2.sql`

```java
CREATE TABLE CITIES(ID BIGINT PRIMARY KEY AUTO_INCREMENT, 
                  NAME VARCHAR(30), POPULATION BIGINT);

```

该 SQL 脚本创建`CITIES`表。

`data-h2.sql`

```java
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);

```

该脚本用数据填充表。 这两个脚本都位于类路径的根目录中。

`ICityService.java`

```java
package com.zetcode.service;

import com.zetcode.bean.City;
import java.util.List;

public interface ICityService {

    public List<City> findAll();
    public City findById(Long id);
}

```

`ICityService`提供了获取所有城市并通过其 ID 从数据源获取城市的契约方法。

`CityService.java`

```java
package com.zetcode.service;

import com.zetcode.bean.City;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

@Service
public class CityService implements ICityService {

    @Autowired
    private JdbcTemplate jtm;

    @Override
    public List<City> findAll() {

        String sql = "SELECT * FROM CITIES";

        List<City> cities = jtm.query(sql, new BeanPropertyRowMapper(City.class));

        return cities;
    }

    @Override
    public City findById(Long id) {

        String sql = "SELECT * FROM CITIES WHERE ID=?";

        City city = (City) jtm.queryForObject(sql, new Object[]{id},
                new BeanPropertyRowMapper(City.class));

        return city;
    }
}

```

`CityService`包含`findAll()`和`findById()`方法的实现。 我们使用 Spring 的`JdbcTemplate`来执行 SQL 代码。

```java
@Autowired
private JdbcTemplate jtm;

```

注入`JdbcTemplate`。

```java
String sql = "SELECT * FROM CITIES";

```

这是从`CITIES`表中选择所有城市的 SQL。

```java
List<City> cities = jtm.query(sql, new BeanPropertyRowMapper(City.class));

```

`BeanPropertyRowMapper`将一行转换为指定映射目标类的新实例。

```java
String sql = "SELECT * FROM CITIES WHERE ID=?";

```

这是用于从`CITIES`表中选择由 ID 标识的特定城市的 SQL。

```java
City city = (City) jtm.queryForObject(sql, new Object[]{id},
        new BeanPropertyRowMapper(City.class));

```

要从`CITIES`表中获得一行，我们使用`queryForObject()`方法。

`MyController.java`

```java
package com.zetcode.controller;

import com.zetcode.bean.City;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import com.zetcode.service.ICityService;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

    @Autowired
    private ICityService cityService;

    @RequestMapping("/cities")
    public List<City> findCities() {

        return cityService.findAll();
    }

    @RequestMapping("/cities/{userId}")
    public City findCity(@PathVariable Long userId) {

        return cityService.findById(userId);
    }
}

```

这是 Spring Boot RESTful 应用的控制器类。 `@RestController`注解创建一个 RESTful 控制器。 传统的 MVC 控制器使用`ModelAndView`，而 RESTful 控制器仅返回对象，并且对象数据以 JSON 或 XML 格式直接写入 HTTP 响应。

```java
@Autowired
private ICityService cityService;

```

我们在`countryService`字段中插入`ICityService`。

```java
@RequestMapping("/cities")
public List<City> findCities() {

    return cityService.findAll();
}

```

`@RequestMapping`注解用于将 Web 请求映射到 Spring 控制器方法。 在这里，我们将具有`/cities`路径的请求映射到控制器的`findCities()`方法。 默认请求是 GET 请求。

我们不需要手动将`City`域对象转换为 JSON。 因为 Jackson 2 在类路径中（（通过`spring-boot-starter-web`包含在内），所以 Spring 会自动选择`MappingJackson2HttpMessageConverter`将`City`实例转换为 JSON。

`Application.java`

```java
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);
    }
}

```

`Application`设置 Spring Boot 应用。 `@SpringBootApplication`启用自动配置和组件扫描。

```java
$ mvn spring-boot:run

```

使用`mvn spring-boot:run`命令，运行应用。 该应用部署在嵌入式 Tomcat 服务器上。

```java
$ 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}]

```

使用`curl`命令，我们可以获得所有城市。

```java
$ curl localhost:8086/rest/cities/1
{"id":1,"name":"Bratislava","population":432000}

```

在这里，我们得到了一个由其 ID 标识的城市。

在本教程中，我们创建了一个 Spring Boot RESTful 应用，该应用以 JSON 格式从 H2 数据库返回数据。 您可能也对相关教程感兴趣： [Spring Boot Thymeleaf 教程](/articles/springbootthymeleaf/)， [Spring Boot Mustache 教程](/articles/springbootmustache/)， [Spring Boot Swing 集成教程](/articles/springbootswing/)， [Spring 传统的 Spring 应用简介](/articles/springwebfirst/)中的 Web 应用， [Spring Boot RESTFul 应用](/articles/springbootrestsimple/)，[`JdbcTemplate`](/articles/springjdbctemplate/)。