Spring Boot JdbcTemplate 示例:CRUD Rest API

Spring Boot JdbcTemplate example: CRUD Rest API - BezKodericon-default.png?t=M0H8https://www.bezkoder.com/spring-boot-jdbctemplate-crud-example/

在本教程中,我们将构建一个使用 Spring JdbcTemplate与 H2 数据库交互的 Spring Boot Rest CRUD API 示例。你会知道:

  • 如何配置 Spring Data JDBC 以使用数据库
  • 如何定义数据模型和存储库接口
  • 创建 Spring Rest Controller 处理 HTTP 请求的方法
  • 使用 Spring JdbcTemplate 与 H2 数据库交互的方式

Spring Boot JdbcTemplate CRUD 示例概述

我们将使用 Spring Data Jdbc 和 H2 数据库为教程应用程序构建一个 Spring Boot Rest API:

  • 每个教程都有 ID、标题、描述、发布状态。
  • API 帮助创建、检索、更新、删除教程。
  • APIs 还支持自定义查找器方法,例如按已发布状态或按标题查找。

这些是我们需要提供的 API:

方法网址行动
POST/api/tutorials创建新教程
GET/api/tutorials检索所有教程
GET/api/tutorials/:id检索教程 :id
PUT/api/tutorials/:id更新教程 :id
DELETE/api/tutorials/:id删除教程 :id
DELETE/api/tutorials删除所有教程
GET/api/tutorials/published查找所有已发布的教程
GET/api/tutorials?title=[关键字]查找标题包含的所有教程 keyword

– 我们使用 Spring Data Jdbc 进行 CRUD 操作和查找方法。
– 通过配置项目依赖和数据源,数据库将成为 H2 数据库(在内存中或磁盘上)。

技术

  • Java 8
  • Spring Boot 2.5.4(带有 Spring Web MVC、Spring Data JDBC)
  • H2 数据库
  • Maven 3.6.1

项目结构

让我简要解释一下。

Tutorial数据模型类对应实体和表教程
TutorialRepository是一个为 CRUD 操作和自定义查找器方法提供抽象方法的接口。它将自动装配到TutorialController.
JdbcTutorialRepository实施TutorialRepository。它使用JdbcTemplate执行 SQL 查询或更新以与数据库交互。
TutorialController是一个RestController,它具有 RESTful 请求的请求映射方法,例如:getAllTutorialscreateTutorialupdateTutorialdeleteTutorialfindByPublished ……
– 在application.properties中配置 Spring Datasource、H2 数据库。
– pom.xml包含 Spring Boot Web、JDBC 和 H2 数据库的依赖项。

创建和设置 Spring Boot 项目

使用Spring Web 工具或您的开发工具(Spring Tool Suite、Eclipse、Intellij)创建一个 Spring Boot 项目。

然后打开pom.xml并添加这些依赖项:

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

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

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

配置 Spring Data 和 H2 数据库

src / main / resources文件夹下,打开application.properties并写下这些行。

spring.h2.console.enabled=true
# default path: h2-console
spring.h2.console.path=/h2-ui
 
spring.datasource.url=jdbc:h2:file:H:/h2db/testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
  • spring.h2.console.enabled=true告诉 Spring 启动 H2 数据库管理工具,您可以在浏览器上访问此工具:http://localhost:8080/h2-console.
  • spring.h2.console.path=/h2-ui用于 H2 控制台的 url,因此默认 urlhttp://localhost:8080/h2-console将更改为http://localhost:8080/h2-ui.
  • spring.datasource.url:jdbc:h2:mem:[database-name]用于内存数据库和jdbc:h2:file:[path/database-name]基于磁盘的数据库。
  • spring.datasource.username&spring.datasource.password属性与您的数据库安装相同。

定义数据模型

我们的数据模型是具有四个字段的教程:id、title、description、published。
模型包中,我们定义了Tutorial类。

model/Tutorial.java

package com.bezkoder.spring.jdbc.model;

public class Tutorial {

  private long id;
  private String title;
  private String description;
  private boolean published;

  public Tutorial() {

  }
  
  public Tutorial(long id, String title, String description, boolean published) {
    this.id = id;
    this.title = title;
    this.description = description;
    this.published = published;
  }

  public Tutorial(String title, String description, boolean published) {
    this.title = title;
    this.description = description;
    this.published = published;
  }
  
  public void setId(long id) {
    this.id = id;
  }
  
  public long getId() {
    return id;
  }

  public String getTitle() {
    return title;
  }

  public void setTitle(String title) {
    this.title = title;
  }

  public String getDescription() {
    return description;
  }

  public void setDescription(String description) {
    this.description = description;
  }

  public boolean isPublished() {
    return published;
  }

  public void setPublished(boolean isPublished) {
    this.published = isPublished;
  }

  @Override
  public String toString() {
    return "Tutorial [id=" + id + ", title=" + title + ", desc=" + description + ", published=" + published + "]";
  }

}

创建 JDBC 存储库

让我们创建一个存储库以与数据库中的教程进行交互。

存储库包中,创建TutorialRepository提供抽象方法的接口:

  • 对于 CRUD 操作:savefindByIdfindAllupdatedeleteByIddeleteAll.
  • 自定义查找器方法:findByPublishedfindByTitleContaining.

repository/TutorialRepository.java

package com.bezkoder.spring.jdbc.repository;

import java.util.List;

import com.bezkoder.spring.jdbc.model.Tutorial;

public interface TutorialRepository {
  int save(Tutorial book);

  int update(Tutorial book);

  Tutorial findById(Long id);

  int deleteById(Long id);

  List<Tutorial> findAll();

  List<Tutorial> findByPublished(boolean published);

  List<Tutorial> findByTitleContaining(String title);

  int deleteAll();
}

我们继续定义JdbcTutorialRepository哪些实现TutorialRepository。它使用JdbcTemplate对象执行 SQL 查询或更新以与数据库交互。

repository/JdbcTutorialRepository.java

package com.bezkoder.spring.jdbc.repository;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import com.bezkoder.spring.jdbc.model.Tutorial;

@Repository
public class JdbcTutorialRepository implements TutorialRepository {

  @Autowired
  private JdbcTemplate jdbcTemplate;

  @Override
  public int save(Tutorial tutorial) {
    return jdbcTemplate.update("INSERT INTO tutorials (title, description, published) VALUES(?,?,?)",
        new Object[] { tutorial.getTitle(), tutorial.getDescription(), tutorial.isPublished() });
  }

  @Override
  public int update(Tutorial tutorial) {
    return jdbcTemplate.update("UPDATE tutorials SET title=?, description=?, published=? WHERE id=?",
        new Object[] { tutorial.getTitle(), tutorial.getDescription(), tutorial.isPublished(), tutorial.getId() });
  }

  @Override
  public Tutorial findById(Long id) {
    try {
      Tutorial tutorial = jdbcTemplate.queryForObject("SELECT * FROM tutorials WHERE id=?",
          BeanPropertyRowMapper.newInstance(Tutorial.class), id);

      return tutorial;
    } catch (IncorrectResultSizeDataAccessException e) {
      return null;
    }
  }

  @Override
  public int deleteById(Long id) {
    return jdbcTemplate.update("DELETE FROM tutorials WHERE id=?", id);
  }

  @Override
  public List<Tutorial> findAll() {
    return jdbcTemplate.query("SELECT * from tutorials", BeanPropertyRowMapper.newInstance(Tutorial.class));
  }

  @Override
  public List<Tutorial> findByPublished(boolean published) {
    return jdbcTemplate.query("SELECT * from tutorials WHERE published=?",
        BeanPropertyRowMapper.newInstance(Tutorial.class), published);
  }

  @Override
  public List<Tutorial> findByTitleContaining(String title) {
    String q = "SELECT * from tutorials WHERE title ILIKE '%" + title + "%'";

    return jdbcTemplate.query(q, BeanPropertyRowMapper.newInstance(Tutorial.class));
  }

  @Override
  public int deleteAll() {
    return jdbcTemplate.update("DELETE from tutorials");
  }
}

-JDBCTemplate器具JdbcOperations,其提供有用的方法:execute()query()update()queryForObject()...
-BeanPropertyRowMapper工具RowMapper,一个表行转换成指定的映射的目标类的一个新实例(Tutorial)。
Tutorial类必须是顶级类并具有默认构造函数(无参数)。

创建 Spring Rest API 控制器

最后,我们创建一个控制器,提供用于创建、检索、更新、删除和查找教程的 API。

controller/TutorialController.java

package com.bezkoder.spring.jdbc.controller;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.bezkoder.spring.jdbc.model.Tutorial;
import com.bezkoder.spring.jdbc.repository.TutorialRepository;

@CrossOrigin(origins = "http://localhost:8081")
@RestController
@RequestMapping("/api")
public class TutorialController {

  @Autowired
  TutorialRepository tutorialRepository;

  @GetMapping("/tutorials")
  public ResponseEntity<List<Tutorial>> getAllTutorials(@RequestParam(required = false) String title) {
    try {
      List<Tutorial> tutorials = new ArrayList<Tutorial>();

      if (title == null)
        tutorialRepository.findAll().forEach(tutorials::add);
      else
        tutorialRepository.findByTitleContaining(title).forEach(tutorials::add);

      if (tutorials.isEmpty()) {
        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
      }

      return new ResponseEntity<>(tutorials, HttpStatus.OK);
    } catch (Exception e) {
      return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  @GetMapping("/tutorials/{id}")
  public ResponseEntity<Tutorial> getTutorialById(@PathVariable("id") long id) {
    Tutorial tutorial = tutorialRepository.findById(id);

    if (tutorial != null) {
      return new ResponseEntity<>(tutorial, HttpStatus.OK);
    } else {
      return new ResponseEntity<>(HttpStatus.NOT_FOUND);
    }
  }

  @PostMapping("/tutorials")
  public ResponseEntity<String> createTutorial(@RequestBody Tutorial tutorial) {
    try {
      tutorialRepository.save(new Tutorial(tutorial.getTitle(), tutorial.getDescription(), false));
      return new ResponseEntity<>("Tutorial was created successfully.", HttpStatus.CREATED);
    } catch (Exception e) {
      return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  @PutMapping("/tutorials/{id}")
  public ResponseEntity<String> updateTutorial(@PathVariable("id") long id, @RequestBody Tutorial tutorial) {
    Tutorial _tutorial = tutorialRepository.findById(id);

    if (_tutorial != null) {
      _tutorial.setId(id);
      _tutorial.setTitle(tutorial.getTitle());
      _tutorial.setDescription(tutorial.getDescription());
      _tutorial.setPublished(tutorial.isPublished());

      tutorialRepository.update(_tutorial);
      return new ResponseEntity<>("Tutorial was updated successfully.", HttpStatus.OK);
    } else {
      return new ResponseEntity<>("Cannot find Tutorial with id=" + id, HttpStatus.NOT_FOUND);
    }
  }

  @DeleteMapping("/tutorials/{id}")
  public ResponseEntity<String> deleteTutorial(@PathVariable("id") long id) {
    try {
      int result = tutorialRepository.deleteById(id);
      if (result == 0) {
        return new ResponseEntity<>("Cannot find Tutorial with id=" + id, HttpStatus.OK);
      }
      return new ResponseEntity<>("Tutorial was deleted successfully.", HttpStatus.OK);
    } catch (Exception e) {
      return new ResponseEntity<>("Cannot delete tutorial.", HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  @DeleteMapping("/tutorials")
  public ResponseEntity<String> deleteAllTutorials() {
    try {
      int numRows = tutorialRepository.deleteAll();
      return new ResponseEntity<>("Deleted " + numRows + " Tutorial(s) successfully.", HttpStatus.OK);
    } catch (Exception e) {
      return new ResponseEntity<>("Cannot delete tutorials.", HttpStatus.INTERNAL_SERVER_ERROR);
    }

  }

  @GetMapping("/tutorials/published")
  public ResponseEntity<List<Tutorial>> findByPublished() {
    try {
      List<Tutorial> tutorials = tutorialRepository.findByPublished(true);

      if (tutorials.isEmpty()) {
        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
      }
      return new ResponseEntity<>(tutorials, HttpStatus.OK);
    } catch (Exception e) {
      return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

}

@CrossOrigin用于配置允许的来源。
@RestController注释用于定义控制器并指示方法的返回值应绑定到 Web 响应正文。
@RequestMapping("/api")声明控制器中所有 APIs 的 url 都以/api.
– 我们使用@Autowired注入TutorialRepositorybean 到局部变量。

运行和检查

使用命令运行 Spring Boot 应用程序:mvn spring-boot:run

让我们使用 url: 来打开 H2 控制台http://localhost:8080/h2-ui

– 对于内存数据库:

– 对于磁盘数据库:

单击连接按钮,然后检查 H2 数据库,您可以看到类似这样的内容。

SQL Statement中,编写 SQL 脚本来创建tutorials表:

CREATE TABLE tutorials
(
    id BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
    title VARCHAR(255),
    description VARCHAR(255),
    published NUMBER(1)
);

创建一些教程:

之后的H2数据库tutorials表:

更新一些教程:

表数据发生变化:

检索所有教程:

按 ID 检索教程:

查找所有已发布的教程:

查找标题包含字符串“jdbc”的所有教程:

删除教程:

删除所有教程:

数据库表现在很干净:

您还可以在以下帖子之一中使用 Client 测试此 Spring Boot 应用程序:

结论

今天我们使用 Spring Boot 构建了一个 CRUD Rest API,Spring Data JDBCTemplate 与 H2 数据库示例一起使用。

您可以处理此 Rest API 的异常是必要的:
– Spring Boot @ControllerAdvice & @ExceptionHandler 示例
– Spring Boot 中的 @RestControllerAdvice 示例

快乐学习!再见。

延伸阅读

全栈 CRUD 应用程序:
– Spring Boot + Vue.js 示例
– Angular 8 + Spring Boot 示例
– Angular 10 + Spring Boot 示例
– Angular 11 + Spring Boot 示例
– Angular 12 + Spring Boot 示例
– React + Spring Boot 示例

更多实践:
使用 Spring Security 和 JWT 身份验证保护 Spring Boot 应用程序
– Spring Boot Rest XML 示例 – 具有 XML 响应的 Web 服务
– Spring Boot 多部分文件上传示例
– Spring Boot 分页和排序示例

源代码

您可以在Github上找到本教程的完整源代码。

您还将看到它JpaRepository支持一种很好的方式来进行 CRUD 操作和自定义查找器方法,而无需样板代码。请访问:
Spring Boot JPA + H2 示例:构建 CRUD Rest API

其他数据库:
使用 MySQL 的
Spring Boot JdbcTemplate 示例–使用 PostgreSQL 的Spring Boot JdbcTemplate 示例 – 使用 SQL Server 的Spring Boot JdbcTemplate 示例 – 使用 Oracle 的 Spring Boot JdbcTemplate 示例

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值