创建一个SpringBoot项目,实现简单的CRUD功能和分页查询

news/2024/9/16 3:46:13/文章来源:https://www.cnblogs.com/xyuanzi/p/18396899

背景

本博文主要是创建了一个新的SpringBoot项目,实现基本的增删改查,分页查询,带条件的分页查询功能。是方便初学者学习后端项目的一个比较清晰明了的实践代码,读者可根据博文,从自己动手创建一个新的SpringBoot项目,到使用PostMan测试基本请求,完完全全实践一遍,写出自己的代码,或者实现自己想要的功能。因为在这个过程中会遇到许多的问题,从JDK的版本选择到跑通SpringBoot项目,最后到成功发起一个请求。所以,最好是自己练习一下,最终做到游刃有余。

环境的安装

本次SpringBoot项目主要用到,一是IDEA,二是MYSQL(服务端),三是DBeaver(一个数据库的客户端),四是PostMan(用于发送HTTP请求)。
建议读者先按照MYSQL包,再按照DBeaver, 调通数据库以后,再开始编写项目。

MYSQL和DBeaver的安装和使用

mysql服务的安装按照以下这个教程装就好了。链接如下:https://blog.csdn.net/Sublime_16/article/details/124227417
需要注意的是,生成临时密码以后,千万要先复制到一个文本文件中,避免在启动服务的时候,终端已经关闭,没有临时密码,无法启动服务;我就是因为临时密码没有保存下来,结果后面又重新去生成这个临时密码。浪费了一些时间。
另外就是,打开终端的时候,使用管理员的身份运行
DBeaver是一个免费的、通用的数据库管理工具,支持多种数据库系统,包括 MySQL、PostgreSQL、SQLite、Oracle、SQL Server 等。它提供了图形界面和强大的功能,使用户能够连接、管理和操作不同类型的数据库。安装和使用的链接如下:https://www.cnblogs.com/nigx128/p/Jf4QN.html
需要注意的是,如果出现了这样的报错,

可重新编辑连接,设置驱动属性为true。

另外就是在一开始建立一个数据库的时候,这里不要写具体的名称。数据库连接以后,再定义具体的数据库名,mydatabase


我们本次的建表语句如下:

-- mydatabase.student_info definitionCREATE TABLE `student_info` (`id` int NOT NULL AUTO_INCREMENT,`name` varchar(100) CHARACTER SET utf8mb3 NOT NULL DEFAULT '""',`address` varchar(100) CHARACTER SET utf8mb3 NOT NULL,`other` varchar(100) CHARACTER SET utf8mb3 NOT NULL,`age` int NOT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=macce;

建好表以后,往表中添加如下示例数据。添加好的表数据如下

创建一个新的SpringBoot项目

1、新建一个project;
这边我们使用maven管理依赖,maven的依赖管理目录可以单独设置一个空目录,自己比较好找到的目录,有时候依赖下载失败,需要从这个目录中删除一些依赖文件;目录的设置可在项目生成以后在IDEA中进行设置。然后jdk的版本有8 就选择8, 没有的话,这里随便选一下,后面编译的时候,可以在IDEA中重新设置。

点击下一步,可以设置SpringBoot的版本。以及要在pom中引入哪些依赖包,方便我们后续写代码的时候调用。我这边简单选了几个,如果还有要使用的依赖,直接勾选就行,或者项目建好后手动在pom添加也可以。
,
点击create, 并使用new windows打开,就得到一个新的SpringBoot项目。接下来就等待依赖下载成功,下载成功以后,maven的目录是这样的。本次项目的pom.xml文件如下:

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.6</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.example</groupId><artifactId>demo3</artifactId><version>0.0.1-SNAPSHOT</version><name>demo3</name><description>demo3</description><url/><licenses><license/></licenses><developers><developer/></developers><scm><connection/><developerConnection/><tag/><url/></scm><properties><java.version>8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>
</project>

配置文件 application.yml

配置文件中的数据库的用户名和密码都要和你实际进行数据库连接时配置的一样,url也是如此。

server.port: 8088
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: 123456url: jdbc:mysql://localhost:3306/mydatabasejpa:hibernate:ddl-auto: noneshow-sql: trueproperties:hibernate:temp:use_jdbc_metadata_defaults: falsedialect: org.hibernate.dialect.MySQL5InnoDBDialect

业务代码

在Web后端应用程序中,Controller主要接收来自用户的请求并根据请求调用适当的业务逻辑(Service层),然后将处理结果返回给用户。
总结的说,Controller的作用是:1、接收请求;2、调用Service层的方法;3、参数解析,对请求头中的参数进行解析;4、返回响应结果。将处理结果封装成适当的响应(如HTML页面、JSON数据等)返回给客户端。我这边为了方便起见,直接调repository中的方法了,后续补充一个Service层。
1、先写一个Controller

package com.example.demo3.controller;import com.example.demo3.repository.StudentEntity;
import com.example.demo3.repository.StudentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.web.bind.annotation.*;import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.List;@RestController // 注意,该注解表明是是rest风格的API, 返回值通常是数据对象,Spring 将数据转换为JSON或者XML格式,返回给客户端。
// controller返回的是视图名称或者ModelAndView对象。需要配置@ReponseBody使用,即在方法的前面加上这个注解。
@RequestMapping("/student")
public class StudentController {@AutowiredStudentRepository repository;//查, 通过姓名查询@RequestMapping(value = "/byname", method = {RequestMethod.GET})//@ResponseBodypublic List<StudentEntity> findByName(@RequestParam("name") String name) {return repository.findByName(name);}// 全部返回,线上我们一般都用分页查询,因为数据量比较大嘛。直接返回全部数据的接口用的很少或者几乎不用。@GetMapping(value = "/all")public List<StudentEntity> findAlls() {List<StudentEntity> all = repository.findAll();return all;}// 增@PostMapping(value = "/add")private String addOne(@RequestBody StudentEntity student){repository.save(student);return "学生" + student.getName() + "添加成功";}// 改@PutMapping(value = "/update")private String updateOne(@RequestBody StudentEntity student){repository.save(student);return "学生" + student.getName() + "修改成功";}// 删@DeleteMapping(value = "/delete")private String deleteOne(@RequestParam("id") Integer id) {repository.deleteById(id);return "用户" + id + "删除成功";}// 简单分页查询@GetMapping("/page")public Page<StudentEntity> findByPage(@RequestParam(value = "page", defaultValue = "0") int page, @RequestParam(value = "size", defaultValue = "2") Integer size) {Pageable pageable = PageRequest.of(page, size);return repository.findAll(pageable);}// 带条件复杂分页查询@GetMapping("/page2")public Page<StudentEntity> findByPage2(@RequestParam(value = "name") String name, @RequestParam(value = "age") Integer age, @RequestParam(value = "page", defaultValue = "0") int page, @RequestParam(value = "size", defaultValue = "2") Integer size) {Pageable pageable = PageRequest.of(page, size);Specification<StudentEntity> specification = prediacte(name, age);return repository.findAll(specification, pageable);}public static Specification<StudentEntity> prediacte(String name, Integer age) {return (Root<StudentEntity> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) -> {Predicate namePredicate = criteriaBuilder.equal(root.get("name"), name);Predicate agePredicate = criteriaBuilder.equal(root.get("age"), age);return criteriaBuilder.and(namePredicate, agePredicate);};}
}

2、Repository
这个是dao层,主要是执行一些和数据库交互的功能。在和数据库交互的时候,我们要创建一个实体类Entity, 这边我们叫做StudentEntity实体对象,相应的,数据库里面也应该有和这个实体类一一映射的表。数据库中的表名就可以写在Table注解里。
entity类中注解的作用如下。首先, @Entity的含义是用于标识一个java类作为JPA(java persistence api)实体类, 表示该类将映射到数据库中的表。也就是说,实体类和数据库表的映射关系由该注解的实现,其中的映射关系具体体现在:实体类的属性和数据库表的字段一一对应。
id注解用于表示某个字段作为表的主键,每个表必须要显式定义一个主键。
@Column 注解是 JPA(Java Persistence API)中用于描述实体属性与数据库表列之间映射关系的注解。通过 @Column 注解,可以指定实体类属性与数据库表中列的映射细节,如列名、数据类型、长度、是否可为空等。即可以更精细地控制实体属性与数据库表列的映射关系。如代码所示,name中指定的列名和表中的对应起来,然后private 属性就可以任意取一个名字了,不过建议还是都对应起来。
StudentEntity

package com.example.demo3.repository;import lombok.Data;import javax.persistence.*;@Entity
@Table(name = "student_info")
@Data
public class StudentEntity {@Id@Column(name = "id")@GeneratedValue(strategy = GenerationType.IDENTITY)private int id;@Column(name = "name")private String name;@Column(name = "age")private int age;@Column(name = "address")private String address;@Column(name = "other")private String other;
}

以下是StudentRepository类,这边定义的几个方法都是直接调用Spring JPA 封装好的方法,可直接调用。如果遇到比较复杂的场景,我们也可以在这里写一个接口,再写接口方法的具体实现。

package com.example.demo3.repository;import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;import java.util.List;public interface StudentRepository extends JpaRepository<StudentEntity, Integer>, JpaSpecificationExecutor<StudentEntity> {List<StudentEntity> findByName(String name);List<StudentEntity> findAll();void deleteById(Integer id);Page<StudentEntity> findAll(Pageable pageable);
}

测试结果

有两种测试方法,可以在网页端直接输入url 发起HTTP请求,由于我们的HTTP请求中要使用对象,所以选择POstman会比较方便。
1、根据name查询

2、增加一个student

3、修改id=XX的学生的信息

4、删除id=XX的学生信息

5、分页查询

{"content": [{"id": 1,"name": "小红","age": 18,"address": "深圳市","other": "女;本科毕业,程序员"},{"id": 2,"name": "小黑","age": 29,"address": "广州市","other": "男;本科毕业,程序员"}],"pageable": {"sort": {"empty": true,"sorted": false,"unsorted": true},"offset": 0,"pageSize": 2,"pageNumber": 0,"paged": true,"unpaged": false},"totalElements": 5,"last": false,"totalPages": 3,"number": 0,"size": 2,"sort": {"empty": true,"sorted": false,"unsorted": true},"numberOfElements": 2,"first": true,"empty": false
}

6、带条件的分页查询

{
"content": [
{
"id": 2,
"name": "小黑",
"age": 29,
"address": "广州市",
"other": "男;本科毕业,程序员"
}
],
"pageable": {
"sort": {
"empty": true,
"sorted": false,
"unsorted": true
},
"offset": 0,
"pageNumber": 0,
"pageSize": 2,
"unpaged": false,
"paged": true
},
"last": true,
"totalPages": 1,
"totalElements": 1,
"number": 0,
"size": 2,
"sort": {
"empty": true,
"sorted": false,
"unsorted": true
},
"numberOfElements": 1,
"first": true,
"empty": false
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/792304.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

每天5分钟复习OpenStack(十五)Ceph与Bcache结合

上一章我们成功部署了bcache,这一章我们将Ceph与Bcache结合来使用,使用Bcache来为ceph的数据盘提速。1 ceph 架构 一个标准的ceph集群可能是如下的架构,SSD/NVME 存储元数据,而SATA盘存储数据。这样的架构下,物理介质的SATA盘读写速率上限决定了存储集群Ceph的上限(木桶效…

青岛-烟台-威海攻略

烟台 朝阳街-烟台山-所城里朝阳街 漫心酒店外小熊烟台山 烟台开埠陈列馆 烟台京剧艺术馆 冰心纪念馆 烟台地标 烟台山灯塔 旗袍博物馆所城里 宣化城墙金沙滩-滨海中路-渔人码头金沙滩城市展示中心 新城北街养马岛 可以在岛上租电驴 需要一整天酒店推荐烟台站附近 Day1 芝罘湾广…

探索Matplotlib-Gallery:Python数据可视化的游乐园

探索matplotlib-gallery:Python数据可视化的游乐园在数据科学的世界里,数据可视化是一个不可或缺的工具,它帮助我们理解数据、发现模式、并传达信息。Matplotlib是Python中最强大的数据可视化库之一,而其Gallery则是一个展示各种可视化技巧和图表类型的宝库。今天,我们将一…

freeRTOS源码解析4--task.c 2

4、task.c解析 时隔两年,还是决定继续把这个系统解析完成,有始有终。不过这次源码又从官网上下载了最新的,可能和我以前看的略有区别,但应该基本不影响理解。 接下来正式开始。4.1.3 新增或是遗漏的两个宏1 /* Returns pdTRUE if the task is actively running and not…

Charles - 夜神模拟器证书安装App抓包-charles监控手机出现unknown 已解决

1.Openssl安装 http://slproweb.com/products/Win32OpenSSL.html exe下载安装后进行配置 新建系统变量OPENSSL_HOME,变量值设为(绝对路径)软件安装目录下的bin 直接浏览 编辑用户变量path,新建%OPENSSL_HOME%,最后点击确定 查看openssl版本,输入命令:openssl version2.夜…

基于迭代扩展卡尔曼滤波算法的倒立摆控制系统matlab仿真

1.课题概述基于迭代扩展卡尔曼滤波算法的倒立摆控制系统,对比UKF,EKF迭代UKF,迭代EKF四种卡尔曼滤波的控制效果。2.系统仿真结果 3.核心程序与模型 版本:MATLAB2022a%迭代扩展卡尔曼滤波 X_iukf = zeros(2, Times1); X_iukf(:,1) = state0; P_iukf = zeros(2…

支持大模型的小模型

https://www.arxiv.org/pdf/2408.12748 (SLM Meets LLM: Balancing Latency, Interpretability and Consistency in Hallucination Detection )平衡会话 AI 幻觉检测中的延迟、可解释性和一致性 介绍 大型语言模型(llm)在实时任务(如同步的会 话 ui)中与延迟作斗争。 当额外的…

基于颜色模型和边缘检测的火焰识别FPGA实现,包含testbench和matlab验证程序

1.算法运行效果图预览 (完整程序运行后无水印)将FPGA仿真结果导入到matlab显示结果:测试样本1测试样本2测试样本32.算法运行软件版本 vivado2019.2matlab2022a3.部分核心程序 (完整版代码包含注释和操作步骤视频)`timescale 1ns / 1ps // // Company: // Engineer: // //…

exkmp/Z函数

扩展 KMP/exKMP(Z 函数) 首先我们求出 \(ne\) 数组。代表 \(b\) 与 \(b\) 的每一个后缀的最长公共前缀长度。 我们设当前要求 \(ne_x\),且 \(k\) 为使得 \(p=k+ne_k-1\) 最大的位置且 \(0\le k<x\)。于是我们得到了两个蓝块相同。再通过这个图,得出两个绿块相等。

群晖搭建个人图书馆

概述 本文依赖于 github 项目 talebook (https://github.com/talebook ) 本文依赖于 github 项目(GitHub - cxfksword/douban-api-rs: 简单的豆瓣api,主要用于在jellyfin中刮削电影信息) 其实就是面向于新手的个人图书馆项目搭建,但是作者本人也是新手[/笑哭]。 搭建 tale…

业务类中处理点赞、收藏和浏览量

在对点赞、收藏和浏览量进行操作时,获取分布式锁,以确保并发情况下数据的准确性。 先更新缓存,然后将更新数据库的操作放入消息队列中异步处理,以提高响应速度。 缓存预热 在系统启动或定期将热门文章的相关数据加载到缓存中,减少首次访问时的数据库查询。描述 点赞、收藏…

极速全景图下载出错显示Permission denied怎么回事

在极速全景图下载大师下载拼接全景图的过程中, 出现了错误, 提示错误信息: creating file kvmem_xxxxx_xxxxx.swap failed: Permission denied (errno=13)经过排查, 上述错误是由以下原因导致的: - 系统运行内存不足, 导致在拼接过程无法创建缓存文件, 导致出错 解决方案: 检查…