SpringBoot HTTP服務(wù)開發(fā)從入門到部署完整流程
在Java后端開發(fā)領(lǐng)域,SpringBoot無疑是最受歡迎的技術(shù)框架之一。其通過"約定優(yōu)于配置"的理念,極大地簡化了Spring應(yīng)用的初始搭建和開發(fā)過程。這種簡化不僅體現(xiàn)在代碼層面,更深刻地改變了Java Web應(yīng)用的部署范式——SpringBoot與Tomcat形成的嵌入式集成關(guān)系,將傳統(tǒng)需要獨立安裝配置的應(yīng)用服務(wù)器直接內(nèi)置于應(yīng)用之中,使得復(fù)雜的Web應(yīng)用部署轉(zhuǎn)變?yōu)楹唵蔚目蓤?zhí)行JAR包運行。
回顧傳統(tǒng)的Java Web開發(fā),開發(fā)者需要經(jīng)歷繁瑣的環(huán)境配置:獨立安裝Tomcat服務(wù)器、配置server.xml、部署WAR包、管理應(yīng)用服務(wù)器生命周期。而SpringBoot的革命性設(shè)計徹底改變了這一局面,其默認(rèn)將Tomcat作為內(nèi)置服務(wù)器打包在應(yīng)用中,讓每個SpringBoot應(yīng)用都成為一個自包含、可獨立運行的執(zhí)行單元。這種設(shè)計帶來了真正的開箱即用體驗——開發(fā)者無需單獨安裝配置Tomcat,只需一行java -jar命令即可啟動完整的Web服務(wù)。
本文我們將基于SpringBoot+Gradle技術(shù)棧,從零開始構(gòu)建一個簡單的HTTP服務(wù),逐步實現(xiàn)從項目初始化、API開發(fā)、業(yè)務(wù)邏輯構(gòu)建到最終部署上線的全流程。
一、環(huán)境準(zhǔn)備
首先選擇一個適合自己的集成開發(fā)環(huán)境,例如IntelliJ IDEA或VSCode,并使用對應(yīng)的開發(fā)環(huán)境創(chuàng)建一個SpringBoot應(yīng)用程序。
我創(chuàng)建的Demo程序應(yīng)用結(jié)構(gòu)如下所示:
SpringBootDemo/ ├── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/xiaxl/demo/ │ │ │ ├── DemoApplication.java │ │ │ └── controller/ │ │ └── resources/ │ │ └── application.properties │ └── test/ ├── build.gradle └── settings.gradle
settings.gradle 是Gradle的項目設(shè)置文件,用于定義項目的基本信息和模塊配置,這里定義了項目的根模塊名稱。
# 項目名稱,影響構(gòu)建產(chǎn)物的命名 rootProject.name = 'SpringBootDemo'
build.gradle 是Gradle構(gòu)建腳本的核心文件,定義了項目的構(gòu)建配置、依賴管理和插件應(yīng)用。
plugins {
# 應(yīng)用Java插件,提供編譯、測試、打包等任務(wù)
id 'java'
# SpringBoot插件,提供bootJar、bootRun等任務(wù)
id 'org.springframework.boot' version '3.3.3'
# 依賴管理插件,簡化Spring依賴版本管理
id 'io.spring.dependency-management' version '1.1.6'
}
group = 'com.xiaxl' # 組織標(biāo)識,通常使用公司域名
version = '0.0.1-SNAPSHOT' # 項目版本,SNAPSHOT表示開發(fā)中版本
java {
toolchain {
languageVersion = JavaLanguageVersion.of(23) # 指定JDK版本為23
}
}
repositories {
// 配置國內(nèi)鏡像加速依賴下載(按需使用)
maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' }
maven { url 'https://mirrors.cloud.tencent.com/nexus/repository/maven-public/' }
maven { url 'https://developer.huawei.com/repo/' }
// maven倉庫
mavenCentral()
}
dependencies {
// 核心依賴:SpringBoot Web Starter,包含:
// - Spring MVC (Web框架)
// - Tomcat (嵌入式Web服務(wù)器)
// - Jackson (JSON處理)
// - 驗證、數(shù)據(jù)綁定等
// Spring Boot Web Starter
implementation 'org.springframework.boot:spring-boot-starter-web'
// 數(shù)據(jù)校驗
implementation 'org.springframework.boot:spring-boot-starter-validation'
// Lombok簡化代碼
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
//
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
tasks.named('test') {
useJUnitPlatform()
}
// 可選:配置JAR包輸出名稱
bootJar {
archiveFileName = 'springboot-demo.jar'
}application.properties 是Spring Boot應(yīng)用的核心配置文件,用于定義應(yīng)用的各種配置參數(shù),如服務(wù)器端口、應(yīng)用名稱、數(shù)據(jù)庫連接等。
spring.application.name=SpringBootDemo # 應(yīng)用名稱 spring.servlet.multipart.max-file-size=-1 # 單個文件大小限制,-1表示不限制 spring.servlet.multipart.max-request-size=-1 # 請求總大小限制,-1表示不限制 server.port=8081 # 服務(wù)端口
DemoApplication.java SpringBoot 是Spring Boot應(yīng)用的主啟動類,是應(yīng)用程序的入口點。通過@SpringBootApplication注解標(biāo)記,包含了自動配置、組件掃描等Spring Boot核心功能。
package com.xiaxl.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
// 使用@SpringBootApplication注解標(biāo)記該類為Spring Boot應(yīng)用的主配置類
@SpringBootApplication
public class DemoApplication {
// main方法是Java應(yīng)用程序的入口點
// 當(dāng)JVM啟動時,首先執(zhí)行這個方法
// args參數(shù)用于接收命令行參數(shù)
public static void main(String[] args) {
// SpringApplication.run()是啟動Spring Boot應(yīng)用的核心方法
// 第一個參數(shù):主配置類(通常是帶有@SpringBootApplication注解的類)
// 第二個參數(shù):命令行參數(shù),會傳遞給Spring應(yīng)用上下文
// 這個方法執(zhí)行以下操作:
// 1. 創(chuàng)建Spring應(yīng)用上下文(ApplicationContext)
// 2. 啟用自動配置
// 3. 啟動嵌入式Web服務(wù)器(如Tomcat)
// 4. 掃描并注冊所有Spring組件
// 5. 返回應(yīng)用上下文對象(此處未接收返回值)
SpringApplication.run(DemoApplication.class, args);
}
}HelloController
創(chuàng)建一個HelloController,用于驗證環(huán)境是否OK。
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
// 訪問地址:GET http://localhost:8081/api/hello
// @RestController:標(biāo)記這個類為一個 REST 控制器,意味著類中的方法會處理 HTTP 請求并返回數(shù)據(jù)。
@RestController
public class HelloController {
@GetMapping("/api/hello")
public HelloResponse getHelloMessages() {
HelloResponse response = new HelloResponse();
response.setStartupMessage("歡迎來到精彩世界!");
response.setNewMessages(Arrays.asList("望長城內(nèi)外惟余莽莽,大河上下頓失滔滔。"));
response.setStatusCode(200);
return response;
}
public static class HelloResponse {
private String startupMessage;
private List<String> newMessages;
private int statusCode;
public String getStartupMessage() {
return startupMessage;
}
public void setStartupMessage(String startupMessage) {
this.startupMessage = startupMessage;
}
public List<String> getNewMessages() {
return newMessages;
}
public void setNewMessages(List<String> newMessages) {
this.newMessages = newMessages;
}
public int getStatusCode() {
return statusCode;
}
public void setStatusCode(int statusCode) {
this.statusCode = statusCode;
}
public void addNewMessage(String message) {
if (this.newMessages == null) {
this.newMessages = new ArrayList<>();
}
this.newMessages.add(message);
}
}
}使用示例: 訪問 http://localhost:8081/api/hello

二、基礎(chǔ)接口實現(xiàn)
掌握 SpringBoot 基礎(chǔ)環(huán)境構(gòu)建后,將學(xué)習(xí)如何實現(xiàn)常用的 HTTP 接口。涵蓋 GET 和 POST 兩種最常用的 HTTP 方法。
ApiResponse.java - 統(tǒng)一響應(yīng)格式封裝類
在構(gòu)建 RESTful API 時,保持統(tǒng)一的響應(yīng)格式非常重要。這有助于提高代碼的可維護(hù)性。這里我們創(chuàng)建一個通用的 ApiResponse類來封裝所有接口的響應(yīng)。
這個類用于標(biāo)準(zhǔn)化所有 API 接口的響應(yīng)格式,包含成功狀態(tài)、消息、數(shù)據(jù)、時間戳和狀態(tài)碼,確保前后端交互的一致性。
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
// 使用Lombok注解自動生成getter、setter、toString、equals和hashCode方法
@Data
// 生成無參構(gòu)造函數(shù)
@NoArgsConstructor
// 生成全參構(gòu)造函數(shù)
@AllArgsConstructor
// Jackson序列化注解:當(dāng)字段值為null時,不包含在JSON輸出中。這樣可以減少響應(yīng)體大小,避免前端處理null值。
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ApiResponse<T> {
private boolean success;
private String message;
private T data;
private LocalDateTime timestamp;
private Integer code;
// 成功響應(yīng)快捷方法
public static <T> ApiResponse<T> success(T data) {
return new ApiResponse<>(true, "操作成功", data, LocalDateTime.now(), 200);
}
public static <T> ApiResponse<T> success(String message, T data) {
return new ApiResponse<>(true, message, data, LocalDateTime.now(), 200);
}
// 失敗響應(yīng)快捷方法
public static <T> ApiResponse<T> error(String message) {
return new ApiResponse<>(false, message, null, LocalDateTime.now(), 500);
}
public static <T> ApiResponse<T> error(String message, Integer code) {
return new ApiResponse<>(false, message, null, LocalDateTime.now(), code);
}
}UserDTO.java - 用戶數(shù)據(jù)傳輸對象
為了在不同層之間傳遞數(shù)據(jù),我們使用 DTO(Data Transfer Object)模式。UserDTO類用于封裝用戶相關(guān)的數(shù)據(jù)傳輸。
這個類定義了用戶數(shù)據(jù)的結(jié)構(gòu),包含用戶的基本信息和業(yè)務(wù)字段,支持鏈?zhǔn)秸{(diào)用提高代碼可讀性。
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;
import java.util.List;
// 使用Lombok注解自動生成getter、setter、toString、equals和hashCode方法
@Data
// 生成無參構(gòu)造函數(shù)
@NoArgsConstructor
// 生成全參構(gòu)造函數(shù)
@AllArgsConstructor
// 使用Lombok的@Accessors注解,開啟鏈?zhǔn)秸{(diào)用(chain = true)。
// 使得setter方法返回當(dāng)前對象,可以連續(xù)調(diào)用。如:user.setId(1L).setName("張三")
@Accessors(chain = true) // 支持鏈?zhǔn)秸{(diào)用
public class UserDTO {
private Long id;
private String name;
private String email;
private Integer age;
private String phone;
private String address;
private Boolean active;
private LocalDateTime createTime;
private LocalDateTime updateTime;
private List<String> roles;
// 靜態(tài)工廠方法
public static UserDTO createDefault() {
return new UserDTO()
.setId(1L)
.setName("張三")
.setEmail("zhangsan@example.com")
.setAge(25)
.setPhone("13800138000")
.setAddress("北京市海淀區(qū)")
.setActive(true)
.setCreateTime(LocalDateTime.now())
.setUpdateTime(LocalDateTime.now())
.setRoles(List.of("USER", "EDITOR"));
}
}UserController.java - 用戶控制器基類
下面創(chuàng)建控制器基類,并初始化一些模擬數(shù)據(jù)用于演示。在實際項目中,這些數(shù)據(jù)通常來自數(shù)據(jù)庫。
這是處理用戶相關(guān)請求的控制器,使用內(nèi)存 Map 模擬數(shù)據(jù)庫存儲,包含數(shù)據(jù)初始化方法。
import com.xiaxl.demo.model.response.ApiResponse;
import com.xiaxl.demo.model.response.UserDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
@RestController
public class UserController {
// 內(nèi)存存儲模擬數(shù)據(jù)(替代數(shù)據(jù)庫)
private final Map<Long, UserDTO> mUserMap = new HashMap<>();
private Long idCounter = 1L;
// 初始化一些測試數(shù)據(jù)
public UserController() {
initMockData();
}
private void initMockData() {
for (int i = 1; i <= 3; i++) {
UserDTO user = new UserDTO()
.setId((long) i)
.setName("用戶" + i)
.setEmail("user" + i + "@example.com")
.setAge(20 + i)
.setPhone("1380013800" + i)
.setAddress("地址" + i)
.setActive(true)
.setCreateTime(LocalDateTime.now())
.setUpdateTime(LocalDateTime.now())
.setRoles(List.of("USER"));
mUserMap.put(user.getId(), user);
idCounter++;
}
}
}1. GET 接口
GET 請求是 HTTP 方法中最常用的一種,主要用于從服務(wù)器請求數(shù)據(jù)。在實際的 Web 開發(fā)中,根據(jù)不同的數(shù)據(jù)檢索需求,GET 接口的實現(xiàn)也分為多種形式。本文將詳細(xì)介紹三種最常見的 GET 接口實現(xiàn)方式。
1.1 基礎(chǔ) GET 接口
這種接口用于獲取某一類資源的完整集合或列表,通常不需要任何輸入?yún)?shù)。它是最簡單、最直接的 GET 接口形式,適用于像“獲取所有用戶”、“查詢所有文章”這樣的場景。
關(guān)鍵注解:@GetMapping用于將 HTTP GET 請求映射到特定的控制器方法。
/**
* 簡單的GET請求 - 獲取所有用戶列表
* 訪問地址:GET http://localhost:8081/api/users
*/
@GetMapping("/api/users")
public ResponseEntity<ApiResponse<List<UserDTO>>> getAllUsers() {
log.info("獲取所有用戶列表");
List<UserDTO> userList = new ArrayList<>(mUserMap.values());
return ResponseEntity.ok(ApiResponse.success("獲取用戶列表成功", userList));
} 使用示例:
- 訪問
http://localhost:8081/api/users

1.2 路徑參數(shù) GET 接口
實際開發(fā)中,我們經(jīng)常需要獲取某個特定ID(或唯一標(biāo)識)的資源詳情。這時,將標(biāo)識符作為URL路徑的一部分(路徑參數(shù))是最佳實踐。這種方式語義清晰,符合RESTful架構(gòu)風(fēng)格。
關(guān)鍵注解:@PathVariable用于將URL中的模板變量綁定到方法的參數(shù)上。
/**
* GET請求 - 根據(jù)ID獲取單個用戶
* 訪問地址:GET http://localhost:8081/api/users/{id}
* 例如:GET http://localhost:8081/api/users/1
*/
@GetMapping("/api/users/{id}")
public ResponseEntity<ApiResponse<UserDTO>> getUserById(@PathVariable Long id) {
log.info("根據(jù)ID查詢用戶,ID: {}", id);
UserDTO user = mUserMap.get(id);
if (user == null) {
return ResponseEntity
.status(HttpStatus.NOT_FOUND)
.body(ApiResponse.error("用戶不存在", 404));
}
return ResponseEntity.ok(ApiResponse.success("獲取用戶成功", user));
}- 訪問
http://localhost:8081/api/users/1

1.3 查詢參數(shù) GET 接口
實際開發(fā)中,對于復(fù)雜的檢索需求,例如根據(jù)多個條件過濾結(jié)果或進(jìn)行分頁查詢,使用查詢參數(shù)是最靈活的方式。查詢參數(shù)以 ?開始,以 key=value的形式拼接在URL后面,多個參數(shù)用 &連接。這種接口非常適合實現(xiàn)搜索功能。
關(guān)鍵注解:@RequestParam用于將請求參數(shù)綁定到控制器的方法參數(shù)。required=false表示參數(shù)非必填,defaultValue提供默認(rèn)值。
/**
* GET請求 - 帶查詢參數(shù)的用戶搜索
* 訪問地址:GET http://localhost:8081/api/users/search?name=用戶1&active=true
*/@GetMapping("/api/users//search")
public ResponseEntity<ApiResponse<List<UserDTO>>> searchUsers(
@RequestParam(required = false) String name,
@RequestParam(required = false) Boolean active,
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer size) {
log.info("搜索用戶 - name: {}, active: {}, page: {}, size: {}",
name, active, page, size);
List<UserDTO> result = mUserMap.values().stream()
.filter(user -> name == null || user.getName().contains(name))
.filter(user -> active == null || user.getActive().equals(active))
.skip((page - 1) * (long) size)
.limit(size)
.toList();
return ResponseEntity.ok(ApiResponse.success("搜索成功", result));
}- 訪問
http://localhost:8081/api/users/search?name=用戶1&active=true

2. POST接口
POST 請求用于向服務(wù)器提交數(shù)據(jù),通常用于創(chuàng)建新資源。在RESTful架構(gòu)中,POST方法對應(yīng)CRUD中的Create操作,用于向服務(wù)器添加新的資源。
在正式開始介紹前,先介紹一個UserRequest類,這是一個數(shù)據(jù)驗證DTO(Data Transfer Object)類,用于接收和驗證前端傳遞的用戶創(chuàng)建請求數(shù)據(jù)。
UserRequest.java
UserRequest通過Jakarta Validation API提供了字段級別的數(shù)據(jù)驗證規(guī)則,確保輸入數(shù)據(jù)的合法性。
import jakarta.validation.constraints.*;
import lombok.Data;
@Data
// 用戶創(chuàng)建請求DTO(Data Transfer Object)類
// 用于接收前端傳遞的用戶創(chuàng)建請求數(shù)據(jù)
// 包含各種驗證注解,確保數(shù)據(jù)合法性
public class UserRequest {
@NotBlank(message = "用戶名不能為空")
@Size(min = 2, max = 20, message = "用戶名長度必須在2-20個字符之間")
private String name;
@NotBlank(message = "郵箱不能為空")
@Email(message = "郵箱格式不正確")
private String email;
@NotNull(message = "年齡不能為空")
@Min(value = 1, message = "年齡必須大于0")
@Max(value = 150, message = "年齡不能超過150")
private Integer age;
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手機(jī)號格式不正確")
private String phone;
@NotBlank(message = "地址不能為空")
private String address;
private String remark;
@AssertTrue(message = "必須同意用戶協(xié)議")
private Boolean agreeTerms;
}2.1 POST 接口處理 JSON 數(shù)據(jù)
以下舉例展示如何處理 JSON 格式的 POST 請求。JSON是目前RESTful API最常用的數(shù)據(jù)交換格式,具有結(jié)構(gòu)清晰、跨平臺、易于解析的優(yōu)點。本接口演示了完整的用戶創(chuàng)建流程,包括參數(shù)驗證、業(yè)務(wù)邏輯處理和響應(yīng)返回。
/**
* POST請求 - 創(chuàng)建用戶(JSON格式請求體)
* 訪問地址:POST http://localhost:8081/api/post/users
* 請求頭:Content-Type: application/json
* 請求體示例:
* {
* "name": "李四",
* "email": "lisi@example.com",
* "age": 30, * "phone": "13900139000",
* "address": "上海市浦東新區(qū)",
* "agreeTerms": true
* }
* @param request 接收并驗證請求體中的JSON數(shù)據(jù),自動反序列化為UserRequest對象,
* Valid注解觸發(fā)對UserRequest對象中字段的驗證規(guī)則
* @param bindingResult 接收參數(shù)驗證結(jié)果,包含所有驗證錯誤信息
* @return ApiResponse<UserDTO>
*/
@PostMapping("/api/post/users")
public ResponseEntity<ApiResponse<UserDTO>> createUser(
@Valid @RequestBody UserRequest request,
BindingResult bindingResult) {
log.info("創(chuàng)建用戶 - 請求數(shù)據(jù): {}", request);
// 參數(shù)校驗
if (bindingResult.hasErrors()) {
Map<String, String> errors = new HashMap<>();
for (FieldError error : bindingResult.getFieldErrors()) {
errors.put(error.getField(), error.getDefaultMessage());
}
return ResponseEntity
.badRequest()
.body(ApiResponse.error(errors.toString(), 400));
}
// 檢查用戶名是否已存在
boolean exists = mUserMap.values().stream()
.anyMatch(user -> user.getName().equals(request.getName()));
if (exists) {
return ResponseEntity
.badRequest()
.body(ApiResponse.error("用戶名已存在", 400));
}
// 創(chuàng)建用戶
UserDTO newUser = new UserDTO()
.setId(idCounter++)
.setName(request.getName())
.setEmail(request.getEmail())
.setAge(request.getAge())
.setPhone(request.getPhone())
.setAddress(request.getAddress())
.setActive(true)
.setCreateTime(LocalDateTime.now())
.setUpdateTime(LocalDateTime.now())
.setRoles(List.of("USER"));
mUserMap.put(newUser.getId(), newUser);
log.info("用戶創(chuàng)建成功,ID: {}", newUser.getId());
return ResponseEntity
.status(HttpStatus.CREATED)
.body(ApiResponse.success("用戶創(chuàng)建成功", newUser));
}使用 Postman 測試:
POST http://localhost:8081/api/post/users
Headers:Content-Type: application/json
Body:
{
"name":"李四",
"email":"lisi@example.com",
"age":30,
"phone":"13900139000",
"address":"上海市浦東新區(qū)",
"agreeTerms":true
}
2.2 POST 接口處理表單請求
除了 JSON 格式,表單提交是另一種常見的 POST 請求方式,常用于文本表單提交。表單提交通常用于傳統(tǒng)的Web應(yīng)用,通過application/x-www-form-urlencoded格式傳遞鍵值對數(shù)據(jù)。這種方式適合簡單的數(shù)據(jù)傳輸,如登錄、搜索等場景。
/**
* POST表單請求 - 用戶登錄(application/x-www-form-urlencoded)
* 訪問地址:POST http://localhost:8081/api/users/login
* 請求頭:Content-Type: application/x-www-form-urlencoded
* 請求體:name=張三&password=123456
*/
@PostMapping(value = "/api/users/login", consumes = "application/x-www-form-urlencoded")
public ResponseEntity<ApiResponse<Map<String, Object>>> login(
@RequestParam String name,
@RequestParam String password) {
log.info("用戶登錄 - name: {}", name);
// 模擬用戶驗證
Optional<UserDTO> userOptional = mUserMap.values().stream()
.filter(user -> user.getName().equals(name))
.findFirst();
if (userOptional.isEmpty()) {
return ResponseEntity
.badRequest()
.body(ApiResponse.error("用戶名或密碼錯誤", 401));
}
// 模擬密碼驗證(實際項目中使用加密驗證)
UserDTO user = userOptional.get();
if (!"123456".equals(password)) { // 模擬固定密碼
return ResponseEntity
.badRequest()
.body(ApiResponse.error("用戶名或密碼錯誤", 401));
}
// 生成模擬token
String token = "Bearer " + UUID.randomUUID();
Map<String, Object> loginResult = new HashMap<>();
loginResult.put("user", user);
loginResult.put("token", token);
loginResult.put("expiresIn", 3600);
log.info("用戶登錄成功,生成token: {}", token);
return ResponseEntity.ok(ApiResponse.success("登錄成功", loginResult));
}使用 Postman 測試:
POST http://localhost:8081/api/users/login Headers:Content-Type: application/x-www-form-urlencoded Body:name=張三&password=123456

2.3 POST 接口文件請求
文件上傳是Web應(yīng)用中常見的功能,通過multipart/form-data格式支持二進(jìn)制文件傳輸。這種方式允許在單個請求中同時傳輸文本字段和二進(jìn)制文件,非常適合需要上傳圖片、文檔等文件的場景。
/**
* 處理多個文件POST上傳
* POST http://localhost:8081/api/uploadFiles
* Content-Type: multipart/form-data; boundary=4235013262151947840 * <p>
* ----4235013262151947840
* Content-Disposition: form-data; name="files"; filename="111.png" * Content-Type: image/png * <p>
* 111.png字節(jié)流數(shù)據(jù)
* ----4235013262151947840
* Content-Disposition: form-data; name="files"; filename="222.png" * Content-Type: image/png * <p>
* 222.png字節(jié)流數(shù)據(jù)
* ----4235013262151947840
* * @param files 文件列表
* @return
*/
@PostMapping("/api/uploadFiles")
public ResponseEntity<ApiResponse<List<String>>> uploadFiles(@RequestParam("files") MultipartFile[] files) {
// 創(chuàng)建一個列表
List<String> fileUris = new ArrayList<>();
// 循環(huán)輸入的文件
for (MultipartFile file : files) {
try {
// 獲取并清理文件名
String fileName = StringUtils.cleanPath(file.getOriginalFilename());
// 構(gòu)建文件上傳路徑
Path uploadPath = Paths.get(UPLOAD_DIR + fileName);
// 創(chuàng)建上傳目錄
File uploadDir = new File(UPLOAD_DIR);
if (!uploadDir.exists()) {
uploadDir.mkdirs();
}
// 創(chuàng)建輸出流,寫入文件
try (FileOutputStream fos = new FileOutputStream(uploadPath.toFile())) {
fos.write(file.getBytes());
}
// 上傳后的文件路徑
String fileUri = UPLOAD_DIR + fileName;
// 緩存到文件列表中
fileUris.add(fileUri);
} catch (IOException e) {
e.printStackTrace();
return ResponseEntity
.badRequest()
.body(ApiResponse.error(e.getMessage(), 500));
}
}
return ResponseEntity.ok(ApiResponse.success("上傳成功", fileUris));
}使用 Postman 測試:
POST http://localhost:8081/api/uploadFiles Content-Type: multipart/form-data; boundary=4235013262151947840 ----4235013262151947840 Content-Disposition: form-data; name="files"; filename="111.png" Content-Type: image/png 111.png字節(jié)流數(shù)據(jù) ----4235013262151947840 Content-Disposition: form-data; name="files"; filename="222.png" Content-Type: image/png 222.png字節(jié)流數(shù)據(jù) ----4235013262151947840

三、數(shù)據(jù)庫集成
在現(xiàn)代Web應(yīng)用開發(fā)中,數(shù)據(jù)庫集成是至關(guān)重要的一環(huán)。Spring Boot通過Spring Data JPA提供了簡潔高效的數(shù)據(jù)訪問解決方案,可以大大減少樣板代碼的編寫。本章將詳細(xì)介紹如何在Spring Boot項目中集成SQLite數(shù)據(jù)庫,并實現(xiàn)完整的用戶管理功能。
本示例使用SQLite,因為它無需單獨安裝數(shù)據(jù)庫服務(wù)器,且數(shù)據(jù)存儲在單一文件中,便于開發(fā)和測試。同時,我們將采用分層架構(gòu)設(shè)計,確保代碼的可維護(hù)性和擴(kuò)展性。
1. 環(huán)境準(zhǔn)備
在開始編碼之前,需要配置項目依賴和數(shù)據(jù)庫連接。以下是具體的配置步驟:
build.gradle? 添加SQLite數(shù)據(jù)庫相關(guān)依賴庫,這些依賴將為我們提供數(shù)據(jù)庫連接、JPA支持以及必要的工具類。
dependencies {
// SQLite數(shù)據(jù)庫(關(guān)鍵依賴)
implementation 'org.xerial:sqlite-jdbc:3.45.1.0'
// 添加以下依賴以支持SQLite方言
implementation 'org.hibernate.orm:hibernate-community-dialects:6.3.1.Final'
// Spring Data JPA
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
// JSON序列化
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310'
}application.properties 添加數(shù)據(jù)庫相關(guān)配置,這些配置項定義了數(shù)據(jù)庫連接參數(shù)、JPA行為以及SQL日志輸出等設(shè)置。
spring.datasource.url=jdbc:sqlite:demo.db spring.datasource.driver-class-name=org.sqlite.JDBC spring.datasource.username=admin spring.datasource.password=123456 spring.jpa.database-platform=org.hibernate.community.dialect.SQLiteDialect spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true spring.jpa.properties.hibernate.dialect=org.hibernate.community.dialect.SQLiteDialect spring.sql.init.mode=never
DemoApplication.java 增加注解EnableJpaRepositories,啟用JPA倉庫功能,這是Spring Data JPA的核心配置。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@SpringBootApplication
@EnableJpaRepositories
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}UserEntity.java 創(chuàng)建一個UserEntity類,該類對應(yīng)數(shù)據(jù)庫中的users表,使用JPA注解定義實體與表的映射關(guān)系。
import jakarta.persistence.*;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import java.time.LocalDateTime;
import java.util.List;
@Entity
@Table(name = "users")
@Data
// 生成無參構(gòu)造函數(shù)
@NoArgsConstructor
// 生成全參構(gòu)造函數(shù)
@AllArgsConstructor
public class UserEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String name;
@Column(nullable = false)
private String email;
private String password;
@Column(name = "nick_name")
private String nickname;
private Integer age;
private String phone;
private String address;
private Boolean active;
private List<String> roles;
@Column(name = "create_time")
private LocalDateTime createTime;
@Column(name = "update_time")
private LocalDateTime updateTime;
// 自動設(shè)置時間
@PrePersist
protected void onCreate() {
createTime = LocalDateTime.now();
updateTime = LocalDateTime.now();
}
@PreUpdate
protected void onUpdate() {
updateTime = LocalDateTime.now();
}
}UserDbController
創(chuàng)建一個UserDbController,作為用戶管理的RESTful API控制器,處理HTTP請求并調(diào)用服務(wù)層方法。
import com.xiaxl.demo.model.response.ApiResponse;
import com.xiaxl.demo.model.response.UserDTO;
import com.xiaxl.demo.model.request.UserRequest;
import com.xiaxl.demo.service.UserService;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.*;
import java.util.*;
@Slf4j
@RestController
// Lombok注解,自動生成一個包含所有final字段的構(gòu)造函數(shù)
// 這通常用于依賴注入,Spring會自動調(diào)用此構(gòu)造函數(shù)注入所需的依賴
public class UserDbController {
// 聲明一個UserService類型的final常量,使用依賴注入方式初始化
// UserService是Spring Data JPA接口,用于操作用戶數(shù)據(jù)表
// final關(guān)鍵字確保該引用在構(gòu)造函數(shù)初始化后不能被修改
private final UserService mUserService;
// 使用構(gòu)造器注入(推薦)
@Autowired
public UserDbController(UserService userService) {
this.mUserService = userService;
}
}UserService
創(chuàng)建一個UserService,作為業(yè)務(wù)邏輯層,處理用戶相關(guān)的業(yè)務(wù)操作,包括數(shù)據(jù)轉(zhuǎn)換和業(yè)務(wù)規(guī)則驗證。
import com.xiaxl.demo.model.db.UserEntity;
import com.xiaxl.demo.model.response.ApiResponse;
import com.xiaxl.demo.model.response.UserDTO;
import com.xiaxl.demo.model.request.UserRequest;
import com.xiaxl.demo.repository.UserRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
@Slf4j
@Service
public class UserService {
// 聲明一個UserRepository類型的final常量,使用依賴注入方式初始化
// UserRepository是Spring Data JPA接口,用于操作用戶數(shù)據(jù)表
// final關(guān)鍵字確保該引用在構(gòu)造函數(shù)初始化后不能被修改
private final UserRepository mUserRepository;
// 使用構(gòu)造器注入(推薦)
@Autowired
public UserService(UserRepository userRepository) {
this.mUserRepository = userRepository;
}
/**
* 實體轉(zhuǎn)DTO
*
* @param userEntity
* @return
*/
public UserDTO convertToDTO(UserEntity userEntity) {
UserDTO dto = new UserDTO();
BeanUtils.copyProperties(userEntity, dto);
return dto;
}
/**
* @param userDTO
* @return
*/
public UserEntity convertToEntity(UserDTO userDTO) {
UserEntity userEntity = new UserEntity();
BeanUtils.copyProperties(userDTO, userEntity);
return userEntity;
}
}UserRepository.java
創(chuàng)建一個UserRepository接口,繼承JpaRepository,獲得基本的CRUD操作能力,并定義自定義查詢方法。
import com.xiaxl.demo.model.db.UserEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
@Repository // 添加 @Repository 注解
public interface UserRepository extends JpaRepository<UserEntity, Long> {
// 根據(jù)用戶名查找用戶
Optional<UserEntity> findByName(String name);
// 根據(jù)郵箱查找用戶
Optional<UserEntity> findByEmail(String email);
// 查找所有用戶按創(chuàng)建時間倒序
@Query("SELECT u FROM UserEntity u ORDER BY u.createTime DESC")
List<UserEntity> findAllOrderByCreatedAtDesc();
}2. Post創(chuàng)建用戶接口
現(xiàn)在來實現(xiàn)創(chuàng)建用戶的API接口。這個接口將接收POST請求,驗證輸入數(shù)據(jù),并將用戶信息保存到數(shù)據(jù)庫中。
UserDbController中添加如下方法,創(chuàng)建用于客戶端post請求創(chuàng)建用戶。
/**
* POST請求 - 創(chuàng)建用戶(JSON格式請求體)
* 訪問地址:POST http://localhost:8081/api/post/users
* 請求頭:Content-Type: application/json
* 請求體示例:
* {
* "name": "李四",
* "email": "lisi@example.com", * "age": 30, * "phone": "13900139000", * "address": "上海市浦東新區(qū)",
* "agreeTerms": true * } * * @param request 接收并驗證請求體中的JSON數(shù)據(jù),自動反序列化為UserCreateRequest對象,
* Valid注解觸發(fā)對UserCreateRequest對象中字段的驗證規(guī)則
* @param bindingResult 接收參數(shù)驗證結(jié)果,包含所有驗證錯誤信息
* @return ApiResponse<UserDTO>
*/
@PostMapping("/api/post/create/user")
public ResponseEntity<ApiResponse<UserDTO>> createUser(
@Valid @RequestBody UserRequest request,
BindingResult bindingResult) {
log.info("創(chuàng)建用戶 - 請求數(shù)據(jù): {}", request);
// 參數(shù)校驗
if (bindingResult.hasErrors()) {
Map<String, String> errors = new HashMap<>();
for (FieldError error : bindingResult.getFieldErrors()) {
errors.put(error.getField(), error.getDefaultMessage());
}
return ResponseEntity
.badRequest()
.body(ApiResponse.error(errors.toString(), 400));
}
return mUserService.createUser(request);
}UserService中添加如下方法,創(chuàng)建用于客戶端post請求創(chuàng)建用戶。
/**
* 創(chuàng)建用戶
*
* @param request
* @return
*/
public ResponseEntity<ApiResponse<UserDTO>> createUser(UserRequest request) {
// 檢查用戶名是否已存在
if (mUserRepository.findByName(request.getName()).isPresent()) {
return ResponseEntity.badRequest()
.body(ApiResponse.error("用戶名已存在"));
}
// 檢查郵箱是否已存在
if (mUserRepository.findByEmail(request.getEmail()).isPresent()) {
return ResponseEntity.badRequest()
.body(ApiResponse.error("郵箱已存在"));
}
// 調(diào)用內(nèi)部事務(wù)方法
UserEntity savedUserEntity = saveUserEntity(request);
return ResponseEntity.status(HttpStatus.CREATED)
.body(ApiResponse.success("用戶創(chuàng)建成功", convertToDTO(savedUserEntity)));
}
@Transactional
public UserEntity saveUserEntity(UserRequest request) {
log.info("saveUserEntity: ", request);
try {
// 實際的創(chuàng)建邏輯,帶有事務(wù)
UserEntity newUserEntity = new UserEntity();
newUserEntity.setName(request.getName());
newUserEntity.setEmail(request.getEmail());
newUserEntity.setAge(request.getAge());
newUserEntity.setPhone(request.getPhone());
newUserEntity.setAddress(request.getAddress());
newUserEntity.setActive(true);
newUserEntity.setCreateTime(LocalDateTime.now());
newUserEntity.setUpdateTime(LocalDateTime.now());
newUserEntity.setRoles(List.of("USER"));
log.info("saveUserEntity: ", request);
return mUserRepository.save(newUserEntity);
}catch (Exception e){
e.printStackTrace();
log.info("Exception: ", e.getMessage());
}
return null;
}使用 Postman 測試: 通過Postman發(fā)送POST請求到創(chuàng)建用戶接口,可以驗證接口功能是否正常。

3. 返回所有用戶
接下來實現(xiàn)獲取所有用戶信息的接口。當(dāng)用戶數(shù)量較多時,直接返回所有用戶可能導(dǎo)致性能問題,但在開發(fā)階段,這個功能對于測試和數(shù)據(jù)驗證非常有用。
UserDbController中添加如下方法,處理獲取所有用戶的GET請求。
/**
* 獲取所有用戶
* GET http://localhost:8081/api/get/users
*/@GetMapping("/api/get/users")
public ResponseEntity<ApiResponse<List<UserDTO>>> getAllUsers() {
log.info("getAllUsers");
return mUserService.getAllUsers();
}
UserService中添加如下方法,實現(xiàn)獲取所有用戶的業(yè)務(wù)邏輯。
/**
* 返回全部用戶
*
* @return
*/
public ResponseEntity<ApiResponse<List<UserDTO>>> getAllUsers() {
List<UserDTO> users = mUserRepository.findAllOrderByCreatedAtDesc().stream()
.map(this::convertToDTO)
.collect(Collectors.toList());
return ResponseEntity.ok(ApiResponse.success("獲取成功", users));
}
使用 Postman 測試: 通過Postman測試獲取所有用戶接口,可以查看當(dāng)前數(shù)據(jù)庫中的所有用戶信息。

至此,已經(jīng)完成了Spring Boot與SQLite數(shù)據(jù)庫的基本集成,實現(xiàn)了用戶的創(chuàng)建和查詢功能。這種分層架構(gòu)的設(shè)計使得代碼結(jié)構(gòu)清晰,各層職責(zé)分明,便于后續(xù)的功能擴(kuò)展和維護(hù)。
三、案例代碼
以上完整的案例代碼,請見以下地址:
https://download.csdn.net/download/aiwusheng/92620719
該案例代碼是一個完整的Spring Boot項目示例,展示了如何實現(xiàn)文件上傳功能并集成SQLite數(shù)據(jù)庫。項目采用標(biāo)準(zhǔn)的MVC分層架構(gòu),包含Controller層、Service層、Repository層和Entity層,代碼結(jié)構(gòu)清晰,便于學(xué)習(xí)和擴(kuò)展。
項目結(jié)構(gòu)說明:
- Controller層:處理HTTP請求,接收參數(shù)并返回響應(yīng)
- Service層:實現(xiàn)業(yè)務(wù)邏輯,包括用戶創(chuàng)建、查詢等操作
- Repository層:繼承JpaRepository,提供數(shù)據(jù)訪問接口
- Entity層:定義數(shù)據(jù)表映射實體類
- 配置文件:包含Gradle依賴配置和數(shù)據(jù)庫連接配置
主要功能:
- 多文件上傳接口(POST /api/uploadFiles)
- 用戶創(chuàng)建接口(POST /api/post/create/user)
- 用戶查詢接口(GET /api/get/users)
- 參數(shù)校驗和異常處理
- 事務(wù)管理
- 日志記錄
技術(shù)棧:
- Spring Boot 3.x
- Spring Data JPA
- SQLite數(shù)據(jù)庫
- Lombok簡化代碼
- 參數(shù)校驗注解
- Spring Web(文件上傳支持)
項目可直接運行,適合作為Spring Boot文件上傳和數(shù)據(jù)庫集成的入門學(xué)習(xí)參考。
到此這篇關(guān)于一文掌握SpringBoot:HTTP服務(wù)開發(fā)從入門到部署 的文章就介紹到這了,更多相關(guān)SpringBoot HTTP服務(wù)開發(fā)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- springBoot發(fā)布https服務(wù)及調(diào)用的過程詳解
- SpringBoot改造MCP服務(wù)器的詳細(xì)說明(StreamableHTTP 類型)
- springboot項目如何開啟https服務(wù)
- SpringBoot添加SSL證書,開啟HTTPS方式(單向認(rèn)證服務(wù)端)
- Springboot?HTTP如何調(diào)用其他服務(wù)
- 關(guān)于springboot 中使用httpclient或RestTemplate做MultipartFile文件跨服務(wù)傳輸?shù)膯栴}
- 為SpringBoot服務(wù)添加HTTPS證書的方法
- SpringBoot實現(xiàn)本地存儲文件上傳及提供HTTP訪問服務(wù)的方法
- springboot添加https服務(wù)器的方法
相關(guān)文章
Java 數(shù)據(jù)結(jié)構(gòu)進(jìn)階二叉樹題集上
二叉樹可以簡單理解為對于一個節(jié)點來說,最多擁有一個上級節(jié)點,同時最多具備左右兩個下級節(jié)點的數(shù)據(jù)結(jié)構(gòu)。本文將帶你通過實際題目來熟練掌握2022-04-04
Hibernate傳入Java對象創(chuàng)建動態(tài)表并錄入數(shù)據(jù)
這篇文章主要介紹了Hibernate傳入Java對象創(chuàng)建動態(tài)表并錄入數(shù)據(jù),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-10-10
Java網(wǎng)絡(luò)編程之UDP協(xié)議詳細(xì)解讀
這篇文章主要介紹了Java網(wǎng)絡(luò)編程之UDP協(xié)議詳細(xì)解讀,UDP協(xié)議全稱是用戶數(shù)據(jù)報協(xié)議,在網(wǎng)絡(luò)中它與TCP協(xié)議一樣用于處理數(shù)據(jù)包,是一種無連接的協(xié)議,在OSI模型中,在第四層——傳輸層,處于IP協(xié)議的上一層,需要的朋友可以參考下2023-12-12
java面向?qū)ο笾畬W(xué)生信息管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了java面向?qū)ο笾畬W(xué)生信息管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-03-03
使用Swagger時Controller中api接口顯示不全的問題分析及解決
swagger是一個十分好用的api接口管理、測試框架,現(xiàn)在越來越多的人使用這個做接口的測試和管理,但經(jīng)常遇到Controller中的api接口顯示不全的問題,所以本文給大家詳細(xì)分析了問題以及解決方法,需要的朋友可以參考下2024-02-02
java利用Future實現(xiàn)多線程執(zhí)行與結(jié)果聚合實例代碼
這篇文章主要給大家介紹了關(guān)于java利用Future實現(xiàn)多線程執(zhí)行與結(jié)果聚合的相關(guān)資料,Future模式的核心,去除了主函數(shù)的等待時間,并使得原本需要等待的時間段可以用于處理其他業(yè)務(wù)邏輯,需要的朋友可以參考下2021-12-12
使用springboot aop來實現(xiàn)讀寫分離和事物配置
這篇文章主要介紹了使用springboot aop來實現(xiàn)讀寫分離和事物配置,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-04-04

