創建一個SpringBoot項目,實現簡單的CRUD功能和分頁查詢
背景
本博文主要是創建了一個新的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 等。它提供了圖形界面和強大的功能,使用戶能夠連接、管理和操作不同類型的數據庫。安裝和使用的鏈接如下:http://www.rzrgm.cn/nigx128/p/Jf4QN.html
需要注意的是,如果出現了這樣的報錯,

可重新編輯連接,設置驅動屬性為true。

另外就是在一開始建立一個數據庫的時候,這里不要寫具體的名稱。數據庫連接以后,再定義具體的數據庫名,mydatabase


我們本次的建表語句如下:
-- mydatabase.student_info definition
CREATE 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 是tomcat的端口號。
com.mysql.cj.jdbc.Driver是一個驅動類,是MySQL Connector 驅動程序中的 JDBC 驅動類,用于在 Java 應用程序中建立與 MySQL 數據庫的連接。 一旦建立了連接,JDBC 驅動類允許 Java 應用程序執行 SQL 查詢、更新和其他數據庫操作。應用程序可以使用 JDBC API 與數據庫進行通信,發送和接收數據。JDBC 驅動類還支持事務管理。Java 應用程序可以使用 JDBC API 開啟、提交或回滾事務,確保數據庫操作的原子性、一致性、隔離性和持久性(ACID 屬性)。在發生錯誤或異常時,驅動類也會生成適當的異常,應用程序可以捕獲并處理這些異常。
加載驅動類是建立連接和執行數據庫操作的第一步!
url 指的是數據庫連接的 URL,它用于指定要連接的數據庫的位置和其他連接參數,localhost指的是本地的主機名,3306是mysql的默認端口號。mydatabase是要連接的數據庫的名稱。應用程序和數據庫通信,首先會通過該url建立連接,不過root和password需要和數據庫連接配置中嚴格一致,否則會連不到數據庫。
有關hibernate 的這段配置意味著通過 JPA 和 Hibernate 配置了禁用自動 DDL(Data Definition Language)生成、打印執行的SQL語句到控制臺,以及指定了 Hibernate 使用的 MySQL 數據庫方言是 MySQL 5 的 InnoDB 存儲引擎方言。use_jdbc_metadata_defaults參數當設置為 false 時,Hibernate 將不使用 JDBC 元數據的默認設置。
重點說明一下ddl-auto, 等于none是指Hibernate 不會嘗試自動創建、更新或刪除數據庫表結構。
server.port: 8088
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 123456
url: jdbc:mysql://localhost:3306/mydatabase
jpa:
hibernate:
ddl-auto: none
show-sql: true
properties:
hibernate:
temp:
use_jdbc_metadata_defaults: false
dialect: 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 {
@Autowired
StudentRepository repository;
//查, 通過姓名查詢
@RequestMapping(value = "/byname", method = {RequestMethod.GET})
//@ResponseBody
public 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) -> {
// 這邊簡單用name和age查詢一下
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、分頁查詢

我們默認的是取第0頁的數據,每頁取size個數據。 故"pageSize": 2,"pageNumber": 0。 totalPages指的是總共有多少條數據, "totalPages": 3指的是一共要分多少頁。5條數據,每頁2個數據,那么就是分3頁。"sort"是分頁時排序的屬性。
{
"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
}
總結
后面我會加一個Service層。今天就先寫這么多吧。

浙公網安備 33010602011771號