Spring Boot JPA + H2 示例:构建 CRUD Rest API

Spring Boot JPA + H2 example: Build a CRUD Rest APIs - BezKodericon-default.png?t=M0H8https://www.bezkoder.com/spring-boot-jpa-h2-example/

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

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

Spring Boot JPA + H2 示例概述

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

  • 每个教程都有 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 JPA 的 CRUD 操作和查找方法JpaRepository
– 通过配置项目依赖和数据源,数据库将成为 H2 数据库(在内存中或磁盘上)。

技术

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

项目结构

让我简要解释一下。

Tutorial数据模型类对应实体和表教程
–是为 CRUD 方法和自定义查找器方法TutorialRepository扩展JpaRepository的接口。它将自动装配到TutorialController.
TutorialController是一个RestController,它具有 RESTful 请求的请求映射方法,例如:getAllTutorialscreateTutorialupdateTutorialdeleteTutorialfindByPublished …… – 在application.properties
中配置 Spring Datasource、JPA 和 Hibernate 。– pom.xml
包含 Spring Boot 和 H2 数据库的依赖项。

我们可以通过为每个教程添加注释来改进示例。这是一对多关系,我为此写了一个教程:
Spring Boot One To Many example with JPA, Hibernate

创建和设置 Spring Boot 项目

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

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

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-jpa</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 Boot、JPA、h2、Hibernate

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

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
 
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto= update

spring.h2.console.enabled=true
# default path: h2-console
spring.h2.console.path=/h2-ui
  • spring.datasource.url:jdbc:h2:mem:[database-name]用于内存数据库和jdbc:h2:file:[path/database-name]基于磁盘的数据库。
  • spring.datasource.username&spring.datasource.password属性与您的数据库安装相同。
  • Spring Boot 使用 Hibernate 进行 JPA 实现,我们H2Dialect为 H2 数据库配置
  • spring.jpa.hibernate.ddl-auto用于数据库初始化。我们将 value 设置为 value,update以便在数据库中创建一个表,自动对应于定义的数据模型。对模型的任何更改也将触发对表的更新。对于生产,这个属性应该是validate
  • 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.

定义数据模型

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

model/Tutorial.java

package com.bezkoder.spring.jpa.h2.model;

import javax.persistence.*;

@Entity
@Table(name = "tutorials")
public class Tutorial {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private long id;

	@Column(name = "title")
	private String title;

	@Column(name = "description")
	private String description;

	@Column(name = "published")
	private boolean published;

	public Tutorial() {

	}

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

	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 + "]";
	}

}

@Entity注解表明该类是一个持久的 Java 类。
@Table注释提供映射该实体的表。
@Id注释用于主键。
@GeneratedValue注解用于定义主键的生成策略。GenerationType.AUTO表示自动增量字段。
@Column注释用于定义数据库中映射注释字段的列。

创建存储库接口

让我们创建一个存储库以与数据库中的教程进行交互。
存储库包中,创建TutorialRepository扩展接口JpaRepository

repository/TutorialRepository.java

package com.bezkoder.spring.jpa.h2.repository;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;

import com.bezkoder.spring.jpa.h2.model.Tutorial;

public interface TutorialRepository extends JpaRepository<Tutorial, Long> {
  List<Tutorial> findByPublished(boolean published);

  List<Tutorial> findByTitleContaining(String title);
}

现在我们可以使用 JpaRepository 的方法:save()findOne()findById()findAll()count()delete()deleteById()... 而不实现这些方法。

我们还定义了自定义查找器方法:
– findByPublished():返回所有published具有输入值的教程published
findByTitleContaining():返回所有标题包含输入的教程title

该实现由Spring Data JPA自动插入。

您可以修改此存储库:
– 使用分页,可以在以下位置找到说明:
Spring Boot 分页和过滤器示例 | Spring JPA,Pageable
– 或使用教程按多个字段排序/排序:
Spring Data JPA 按多列排序/排序 | 弹簧靴

您还可以在以下位置找到为此 JPA 存储库编写单元测试的方法:
Spring Boot Unit Test for JPA Repositiory with @DataJpaTest

创建 Spring Rest API 控制器

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

controller/TutorialController.java

package com.bezkoder.spring.jpa.h2.controller;

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

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.jpa.h2.model.Tutorial;
import com.bezkoder.spring.jpa.h2.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) {
		Optional<Tutorial> tutorialData = tutorialRepository.findById(id);

		if (tutorialData.isPresent()) {
			return new ResponseEntity<>(tutorialData.get(), HttpStatus.OK);
		} else {
			return new ResponseEntity<>(HttpStatus.NOT_FOUND);
		}
	}

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

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

		if (tutorialData.isPresent()) {
			Tutorial _tutorial = tutorialData.get();
			_tutorial.setTitle(tutorial.getTitle());
			_tutorial.setDescription(tutorial.getDescription());
			_tutorial.setPublished(tutorial.isPublished());
			return new ResponseEntity<>(tutorialRepository.save(_tutorial), HttpStatus.OK);
		} else {
			return new ResponseEntity<>(HttpStatus.NOT_FOUND);
		}
	}

	@DeleteMapping("/tutorials/{id}")
	public ResponseEntity<HttpStatus> deleteTutorial(@PathVariable("id") long id) {
		try {
			tutorialRepository.deleteById(id);
			return new ResponseEntity<>(HttpStatus.NO_CONTENT);
		} catch (Exception e) {
			return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
		}
	}

	@DeleteMapping("/tutorials")
	public ResponseEntity<HttpStatus> deleteAllTutorials() {
		try {
			tutorialRepository.deleteAll();
			return new ResponseEntity<>(HttpStatus.NO_CONTENT);
		} catch (Exception e) {
			return new ResponseEntity<>(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 数据库,您可以看到如下内容:

创建一些教程:

之后的H2数据库tutorials表:

 

更新一些教程:

表数据发生变化:

 

检索所有教程:

按 ID 检索教程:

 

查找所有已发布的教程:

查找所有标题包含字符串 'ot' 的教程:

删除教程:

删除所有教程:

H2 数据库表现在是干净的:

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

结论

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

我们还看到它JpaRepository支持一种很好的方式来进行 CRUD 操作和自定义查找器方法,而无需样板代码。

如果你想在这个 Spring 项目中添加 Pagination,你可以在以下位置找到说明:
Spring Boot Pagination & Filter example | Spring JPA,可分页

按多个字段排序/排序:
Spring Data JPA 按多列排序/排序 | 弹簧靴

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

或为 JPA 存储库编写单元测试的方法:
Spring Boot Unit Test for JPA Repositiory with @DataJpaTest

快乐学习!再见。

延伸阅读

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

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

我们可以通过为每个教程添加注释来改进示例。这是一对多关系,我为此写了一个教程:
Spring Boot One To Many example with JPA, Hibernate

源代码

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

使用其他数据库:
– Spring JPA + SQL Server
– Spring JPA + PostgreSQL
– Spring JPA + MySQL
– Spring Data + MongoDB

或者 JdbcTemplate 代替:
Spring Boot JdbcTemplate 示例:CRUD Rest API

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
抱歉,我是一个语言模型,无法提供完整的代码案例。但我可以提供一些指导,希望对你有所帮助。 首先,你需要了解以下技术: - layui:一个基于 jQuery 的前端 UI 框架,用于构建 Web 界面。 - Spring Boot:一个快速构建基于 Spring 框架的应用程序的框架。 - JPAJava Persistence API,用于将 Java 对象映射到数据库表。 - FullCalendar:一个开源的日历插件,用于展示日程。 接下来,你需要创建一个 Spring Boot 项目,并添加相关依赖。在 pom.xml 文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>3.6.0</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>layui</artifactId> <version>2.5.6</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>fullcalendar</artifactId> <version>3.10.0</version> </dependency> ``` 接下来,你需要创建一个实体类来映射数据库表。在这个例子中,我们创建一个 Event 实体类,用于存储日程信息。 ```java @Entity @Table(name = "event") public class Event { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String title; @Temporal(TemporalType.TIMESTAMP) private Date start; @Temporal(TemporalType.TIMESTAMP) private Date end; private String color; // getter 和 setter 方法省略 } ``` 接下来,你需要创建一个 JPA Repository 接口来操作数据库。在这个例子中,我们创建一个 EventRepository 接口,用于增删改查日程信息。 ```java public interface EventRepository extends JpaRepository<Event, Long> { } ``` 接下来,你需要创建一个控制器来处理前端请求。在这个例子中,我们创建一个 EventController 控制器,用于处理日程的增删改查请求。 ```java @Controller public class EventController { @Autowired private EventRepository eventRepository; @GetMapping("/") public String index() { return "index"; } @GetMapping("/events") @ResponseBody public List<Event> events() { return eventRepository.findAll(); } @PostMapping("/events") @ResponseBody public Event addEvent(@RequestBody Event event) { return eventRepository.save(event); } @PutMapping("/events") @ResponseBody public Event updateEvent(@RequestBody Event event) { return eventRepository.save(event); } @DeleteMapping("/events/{id}") @ResponseBody public void deleteEvent(@PathVariable Long id) { eventRepository.deleteById(id); } } ``` 最后,你需要创建一个前端页面来展示日程信息。在这个例子中,我们使用了 layui 和 FullCalendar 插件来构建前端页面。 ```html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Layui + Spring Boot + JPA + FullCalendar Demo</title> <link rel="stylesheet" href="/webjars/layui/2.5.6/css/layui.css"> <link rel="stylesheet" href="/webjars/fullcalendar/3.10.0/fullcalendar.min.css"> <script src="/webjars/jquery/3.6.0/jquery.min.js"></script> <script src="/webjars/layui/2.5.6/layui.all.js"></script> <script src="/webjars/fullcalendar/3.10.0/fullcalendar.min.js"></script> </head> <body> <div class="layui-container"> <div class="layui-row"> <div class="layui-col-md12"> <div id="calendar"></div> </div> </div> </div> <script> layui.use(['layer'], function () { var layer = layui.layer; $('#calendar').fullCalendar({ header: { left: 'prev,next today', center: 'title', right: 'month,agendaWeek,agendaDay' }, editable: true, eventLimit: true, events: '/events', eventColor: '#378006', eventDrop: function (event) { $.ajax({ url: '/events', type: 'PUT', data: JSON.stringify(event), contentType: 'application/json; charset=utf-8', dataType: 'json', success: function (response) { layer.msg('修改成功'); }, error: function (response) { layer.msg('修改失败'); } }); }, eventResize: function (event) { $.ajax({ url: '/events', type: 'PUT', data: JSON.stringify(event), contentType: 'application/json; charset=utf-8', dataType: 'json', success: function (response) { layer.msg('修改成功'); }, error: function (response) { layer.msg('修改失败'); } }); }, dayClick: function (date, jsEvent, view) { layer.prompt({ formType: 0, title: '请输入日程标题' }, function (value, index) { $.ajax({ url: '/events', type: 'POST', data: JSON.stringify({ title: value, start: date.format(), end: date.format(), color: '#378006' }), contentType: 'application/json; charset=utf-8', dataType: 'json', success: function (response) { $('#calendar').fullCalendar('renderEvent', response, true); layer.msg('添加成功'); }, error: function (response) { layer.msg('添加失败'); } }); layer.close(index); }); }, eventClick: function (event, jsEvent, view) { layer.confirm('确定要删除该日程吗?', function (index) { $.ajax({ url: '/events/' + event.id, type: 'DELETE', success: function (response) { $('#calendar').fullCalendar('removeEvents', event.id); layer.msg('删除成功'); }, error: function (response) { layer.msg('删除失败'); } }); layer.close(index); }); } }); }); </script> </body> </html> ``` 这样,一个简单的 layui + Spring Boot + JPA + FullCalendar 的增删改查完整案例就完成了。你可以根据实际需求进行修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值