Spring Boot REST H2
最后修改于 2023 年 7 月 25 日
本文将创建一个简单的 Spring Boot RESTful 应用程序,并使用 H2 数据库。
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 Object Notation) 是一种轻量级的数据交换格式。它易于人类阅读和编写,也易于机器解析和生成。JSON 的官方 Internet 媒体类型是 application/json。JSON 文件扩展名为 .json。
RESTful 应用程序遵循 REST 架构风格,用于设计网络应用程序。RESTful 应用程序生成 HTTP 请求,这些请求对资源执行 CRUD(创建/读取/更新/删除)操作。
应用程序
我们的应用程序是一个 Spring Boot RESTful 应用程序,它运行在嵌入式 Tomcat 服务器上。它以 JSON 格式返回 H2 数据库中的数据。该应用程序使用 JdbcTemplate 来简化 JDBC 编程。
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
这是项目结构。
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'
}
这是 Gradle 构建文件。h2 依赖项是 H2 数据库的驱动程序。spring-boot-starter-web 是用于使用 Spring MVC 构建 Web(包括 RESTful)应用程序的启动器。spring-boot-starter-jdbc 是在 Spring Boot 中使用 JDBC 的启动器。
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
application.yml 文件包含 Spring Boot 应用程序的各种配置设置。我们有服务器端口和上下文路径(应用程序名称)的映射。使用 banner-mode 属性可以关闭 Spring 启动横幅。平台值用于 SQL 初始化脚本:schema-${platform}.sql 和 data-${platform}.sql。H2 数据库在内存中运行。此外,我们将 spring 框架的日志级别设置为 ERROR。该文件位于 src/main/resources 目录中。
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。
CREATE TABLE cities(id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255), population BIGINT);
此 SQL 脚本创建 cities 表。
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);
此脚本用数据填充表。这两个脚本都位于类路径的根目录。
package com.zetcode.service;
import com.zetcode.bean.City;
import java.util.List;
public interface ICityService {
List<City> findAll();
City findById(Long id);
}
ICityService 提供了从数据源获取所有城市和按 ID 获取城市的方法契约。
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 包含 findAll 和 findById 方法的实现。我们使用 Spring JdbcTemplate 执行 SQL 代码。
private final JdbcTemplate jtm;
@Autowired
public CityService(JdbcTemplate jtm) {
this.jtm = jtm;
}
JdbcTemplate 已注入。
String sql = "SELECT * FROM cities";
这是从 cities 表中选择所有城市的 SQL。
return jtm.query(sql, new BeanPropertyRowMapper<>(City.class));
该语句使用 query 执行。BeanPropertyRowMapper 将一行转换为指定映射目标类的新实例。
String sql = "SELECT * FROM cities WHERE id=?";
这是从 cities 表中选择由 id 标识的特定城市的 SQL。
return jtm.queryForObject(sql, new BeanPropertyRowMapper<>(City.class), id);
要从 cities 表中获取一行,我们使用 queryForObject 方法。
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);
}
}
这是 Spring Boot RESTful 应用程序的控制器类。@RestController 注解创建了一个 RESTful 控制器。传统的 MVC 控制器使用 ModelAndView,而 RESTful 控制器直接返回对象,对象数据以 JSON 或 XML 格式直接写入 HTTP 响应。
private final ICityService cityService;
@Autowired
public MyController(ICityService cityService) {
this.cityService = cityService;
}
我们将 ICityService 注入到 countryService 字段中。
@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。
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 启用了自动配置和组件扫描。
$ ./gradlew bootRun
使用 ./gradlew bootRun 命令运行应用程序。应用程序部署在嵌入式 Tomcat 服务器上。
$ 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 命令,我们可以获取所有城市。
$ curl localhost:8086/rest/cities/1
{"id":1,"name":"Bratislava","population":432000}
在这里,我们获取一个由其 id 标识的城市。
在本文中,我们创建了一个 Spring Boot RESTful 应用程序,该应用程序以 JSON 格式返回 H2 数据库中的数据。