在java后端开发领域,springboot无疑是最受欢迎的技术框架之一。其通过"约定优于配置"的理念,极大地简化了spring应用的初始搭建和开发过程。这种简化不仅体现在代码层面,更深刻地改变了java web应用的部署范式——springboot与tomcat形成的嵌入式集成关系,将传统需要独立安装配置的应用服务器直接内置于应用之中,使得复杂的web应用部署转变为简单的可执行jar包运行。
回顾传统的java web开发,开发者需要经历繁琐的环境配置:独立安装tomcat服务器、配置server.xml、部署war包、管理应用服务器生命周期。而springboot的革命性设计彻底改变了这一局面,其默认将tomcat作为内置服务器打包在应用中,让每个springboot应用都成为一个自包含、可独立运行的执行单元。这种设计带来了真正的开箱即用体验——开发者无需单独安装配置tomcat,只需一行java -jar命令即可启动完整的web服务。
本文我们将基于springboot+gradle技术栈,从零开始构建一个简单的http服务,逐步实现从项目初始化、api开发、业务逻辑构建到最终部署上线的全流程。
一、环境准备
首先选择一个适合自己的集成开发环境,例如intellij idea或vscode,并使用对应的开发环境创建一个springboot应用程序。
我创建的demo程序应用结构如下所示:
springbootdemo/ ├── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/xiaxl/demo/ │ │ │ ├── demoapplication.java │ │ │ └── controller/ │ │ └── resources/ │ │ └── application.properties │ └── test/ ├── build.gradle └── settings.gradle
settings.gradle 是gradle的项目设置文件,用于定义项目的基本信息和模块配置,这里定义了项目的根模块名称。
# 项目名称,影响构建产物的命名 rootproject.name = 'springbootdemo'
build.gradle 是gradle构建脚本的核心文件,定义了项目的构建配置、依赖管理和插件应用。
plugins {
# 应用java插件,提供编译、测试、打包等任务
id 'java'
# springboot插件,提供bootjar、bootrun等任务
id 'org.springframework.boot' version '3.3.3'
# 依赖管理插件,简化spring依赖版本管理
id 'io.spring.dependency-management' version '1.1.6'
}
group = 'com.xiaxl' # 组织标识,通常使用公司域名
version = '0.0.1-snapshot' # 项目版本,snapshot表示开发中版本
java {
toolchain {
languageversion = javalanguageversion.of(23) # 指定jdk版本为23
}
}
repositories {
// 配置国内镜像加速依赖下载(按需使用)
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服务器)
// - jackson (json处理)
// - 验证、数据绑定等
// spring boot web starter
implementation 'org.springframework.boot:spring-boot-starter-web'
// 数据校验
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应用的核心配置文件,用于定义应用的各种配置参数,如服务器端口、应用名称、数据库连接等。
spring.application.name=springbootdemo # 应用名称 spring.servlet.multipart.max-file-size=-1 # 单个文件大小限制,-1表示不限制 spring.servlet.multipart.max-request-size=-1 # 请求总大小限制,-1表示不限制 server.port=8081 # 服务端口
demoapplication.java springboot 是spring boot应用的主启动类,是应用程序的入口点。通过@springbootapplication注解标记,包含了自动配置、组件扫描等spring boot核心功能。
package com.xiaxl.demo;
import org.springframework.boot.springapplication;
import org.springframework.boot.autoconfigure.springbootapplication;
// 使用@springbootapplication注解标记该类为spring boot应用的主配置类
@springbootapplication
public class demoapplication {
// main方法是java应用程序的入口点
// 当jvm启动时,首先执行这个方法
// args参数用于接收命令行参数
public static void main(string[] args) {
// springapplication.run()是启动spring boot应用的核心方法
// 第一个参数:主配置类(通常是带有@springbootapplication注解的类)
// 第二个参数:命令行参数,会传递给spring应用上下文
// 这个方法执行以下操作:
// 1. 创建spring应用上下文(applicationcontext)
// 2. 启用自动配置
// 3. 启动嵌入式web服务器(如tomcat)
// 4. 扫描并注册所有spring组件
// 5. 返回应用上下文对象(此处未接收返回值)
springapplication.run(demoapplication.class, args);
}
}hellocontroller
创建一个hellocontroller,用于验证环境是否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:标记这个类为一个 rest 控制器,意味着类中的方法会处理 http 请求并返回数据。
@restcontroller
public class hellocontroller {
@getmapping("/api/hello")
public helloresponse gethellomessages() {
helloresponse response = new helloresponse();
response.setstartupmessage("欢迎来到精彩世界!");
response.setnewmessages(arrays.aslist("望长城内外惟余莽莽,大河上下顿失滔滔。"));
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

二、基础接口实现
掌握 springboot 基础环境构建后,将学习如何实现常用的 http 接口。涵盖 get 和 post 两种最常用的 http 方法。
apiresponse.java - 统一响应格式封装类
在构建 restful api 时,保持统一的响应格式非常重要。这有助于提高代码的可维护性。这里我们创建一个通用的 apiresponse类来封装所有接口的响应。
这个类用于标准化所有 api 接口的响应格式,包含成功状态、消息、数据、时间戳和状态码,确保前后端交互的一致性。
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
// 生成无参构造函数
@noargsconstructor
// 生成全参构造函数
@allargsconstructor
// jackson序列化注解:当字段值为null时,不包含在json输出中。这样可以减少响应体大小,避免前端处理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;
// 成功响应快捷方法
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);
}
// 失败响应快捷方法
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 - 用户数据传输对象
为了在不同层之间传递数据,我们使用 dto(data transfer object)模式。userdto类用于封装用户相关的数据传输。
这个类定义了用户数据的结构,包含用户的基本信息和业务字段,支持链式调用提高代码可读性。
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
// 生成无参构造函数
@noargsconstructor
// 生成全参构造函数
@allargsconstructor
// 使用lombok的@accessors注解,开启链式调用(chain = true)。
// 使得setter方法返回当前对象,可以连续调用。如:user.setid(1l).setname("张三")
@accessors(chain = true) // 支持链式调用
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;
// 静态工厂方法
public static userdto createdefault() {
return new userdto()
.setid(1l)
.setname("张三")
.setemail("zhangsan@example.com")
.setage(25)
.setphone("13800138000")
.setaddress("北京市海淀区")
.setactive(true)
.setcreatetime(localdatetime.now())
.setupdatetime(localdatetime.now())
.setroles(list.of("user", "editor"));
}
}usercontroller.java - 用户控制器基类
下面创建控制器基类,并初始化一些模拟数据用于演示。在实际项目中,这些数据通常来自数据库。
这是处理用户相关请求的控制器,使用内存 map 模拟数据库存储,包含数据初始化方法。
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 {
// 内存存储模拟数据(替代数据库)
private final map<long, userdto> musermap = new hashmap<>();
private long idcounter = 1l;
// 初始化一些测试数据
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 方法中最常用的一种,主要用于从服务器请求数据。在实际的 web 开发中,根据不同的数据检索需求,get 接口的实现也分为多种形式。本文将详细介绍三种最常见的 get 接口实现方式。
1.1 基础 get 接口
这种接口用于获取某一类资源的完整集合或列表,通常不需要任何输入参数。它是最简单、最直接的 get 接口形式,适用于像“获取所有用户”、“查询所有文章”这样的场景。
关键注解:@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 路径参数 get 接口
实际开发中,我们经常需要获取某个特定id(或唯一标识)的资源详情。这时,将标识符作为url路径的一部分(路径参数)是最佳实践。这种方式语义清晰,符合restful架构风格。
关键注解:@pathvariable用于将url中的模板变量绑定到方法的参数上。
/**
* get请求 - 根据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("根据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 查询参数 get 接口
实际开发中,对于复杂的检索需求,例如根据多个条件过滤结果或进行分页查询,使用查询参数是最灵活的方式。查询参数以 ?开始,以 key=value的形式拼接在url后面,多个参数用 &连接。这种接口非常适合实现搜索功能。
关键注解:@requestparam用于将请求参数绑定到控制器的方法参数。required=false表示参数非必填,defaultvalue提供默认值。
/**
* get请求 - 带查询参数的用户搜索
* 访问地址: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 请求用于向服务器提交数据,通常用于创建新资源。在restful架构中,post方法对应crud中的create操作,用于向服务器添加新的资源。
在正式开始介绍前,先介绍一个userrequest类,这是一个数据验证dto(data transfer object)类,用于接收和验证前端传递的用户创建请求数据。
userrequest.java
userrequest通过jakarta validation api提供了字段级别的数据验证规则,确保输入数据的合法性。
import jakarta.validation.constraints.*;
import lombok.data;
@data
// 用户创建请求dto(data transfer object)类
// 用于接收前端传递的用户创建请求数据
// 包含各种验证注解,确保数据合法性
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 = "手机号格式不正确")
private string phone;
@notblank(message = "地址不能为空")
private string address;
private string remark;
@asserttrue(message = "必须同意用户协议")
private boolean agreeterms;
}2.1 post 接口处理 json 数据
以下举例展示如何处理 json 格式的 post 请求。json是目前restful api最常用的数据交换格式,具有结构清晰、跨平台、易于解析的优点。本接口演示了完整的用户创建流程,包括参数验证、业务逻辑处理和响应返回。
/**
* post请求 - 创建用户(json格式请求体)
* 访问地址:post http://localhost:8081/api/post/users
* 请求头:content-type: application/json
* 请求体示例:
* {
* "name": "李四",
* "email": "lisi@example.com",
* "age": 30, * "phone": "13900139000",
* "address": "上海市浦东新区",
* "agreeterms": true
* }
* @param request 接收并验证请求体中的json数据,自动反序列化为userrequest对象,
* valid注解触发对userrequest对象中字段的验证规则
* @param bindingresult 接收参数验证结果,包含所有验证错误信息
* @return apiresponse<userdto>
*/
@postmapping("/api/post/users")
public responseentity<apiresponse<userdto>> createuser(
@valid @requestbody userrequest request,
bindingresult bindingresult) {
log.info("创建用户 - 请求数据: {}", request);
// 参数校验
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));
}
// 创建用户
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("用户创建成功,id: {}", newuser.getid());
return responseentity
.status(httpstatus.created)
.body(apiresponse.success("用户创建成功", 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":"上海市浦东新区",
"agreeterms":true
}
2.2 post 接口处理表单请求
除了 json 格式,表单提交是另一种常见的 post 请求方式,常用于文本表单提交。表单提交通常用于传统的web应用,通过application/x-www-form-urlencoded格式传递键值对数据。这种方式适合简单的数据传输,如登录、搜索等场景。
/**
* 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应用中常见的功能,通过multipart/form-data格式支持二进制文件传输。这种方式允许在单个请求中同时传输文本字段和二进制文件,非常适合需要上传图片、文档等文件的场景。
/**
* 处理多个文件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字节流数据
* ----4235013262151947840
* content-disposition: form-data; name="files"; filename="222.png" * content-type: image/png * <p>
* 222.png字节流数据
* ----4235013262151947840
* * @param files 文件列表
* @return
*/
@postmapping("/api/uploadfiles")
public responseentity<apiresponse<list<string>>> uploadfiles(@requestparam("files") multipartfile[] files) {
// 创建一个列表
list<string> fileuris = new arraylist<>();
// 循环输入的文件
for (multipartfile file : files) {
try {
// 获取并清理文件名
string filename = stringutils.cleanpath(file.getoriginalfilename());
// 构建文件上传路径
path uploadpath = paths.get(upload_dir + filename);
// 创建上传目录
file uploaddir = new file(upload_dir);
if (!uploaddir.exists()) {
uploaddir.mkdirs();
}
// 创建输出流,写入文件
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字节流数据 ----4235013262151947840 content-disposition: form-data; name="files"; filename="222.png" content-type: image/png 222.png字节流数据 ----4235013262151947840

三、数据库集成
在现代web应用开发中,数据库集成是至关重要的一环。spring boot通过spring data jpa提供了简洁高效的数据访问解决方案,可以大大减少样板代码的编写。本章将详细介绍如何在spring boot项目中集成sqlite数据库,并实现完整的用户管理功能。
本示例使用sqlite,因为它无需单独安装数据库服务器,且数据存储在单一文件中,便于开发和测试。同时,我们将采用分层架构设计,确保代码的可维护性和扩展性。
1. 环境准备
在开始编码之前,需要配置项目依赖和数据库连接。以下是具体的配置步骤:
build.gradle 添加sqlite数据库相关依赖库,这些依赖将为我们提供数据库连接、jpa支持以及必要的工具类。
dependencies {
// sqlite数据库(关键依赖)
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 添加数据库相关配置,这些配置项定义了数据库连接参数、jpa行为以及sql日志输出等设置。
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 创建一个userentity类,该类对应数据库中的users表,使用jpa注解定义实体与表的映射关系。
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
// 生成无参构造函数
@noargsconstructor
// 生成全参构造函数
@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;
// 自动设置时间
@prepersist
protected void oncreate() {
createtime = localdatetime.now();
updatetime = localdatetime.now();
}
@preupdate
protected void onupdate() {
updatetime = localdatetime.now();
}
}userdbcontroller
创建一个userdbcontroller,作为用户管理的restful api控制器,处理http请求并调用服务层方法。
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字段的构造函数
// 这通常用于依赖注入,spring会自动调用此构造函数注入所需的依赖
public class userdbcontroller {
// 声明一个userservice类型的final常量,使用依赖注入方式初始化
// userservice是spring data jpa接口,用于操作用户数据表
// final关键字确保该引用在构造函数初始化后不能被修改
private final userservice muserservice;
// 使用构造器注入(推荐)
@autowired
public userdbcontroller(userservice userservice) {
this.muserservice = userservice;
}
}userservice
创建一个userservice,作为业务逻辑层,处理用户相关的业务操作,包括数据转换和业务规则验证。
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接口,用于操作用户数据表
// final关键字确保该引用在构造函数初始化后不能被修改
private final userrepository muserrepository;
// 使用构造器注入(推荐)
@autowired
public userservice(userrepository userrepository) {
this.muserrepository = userrepository;
}
/**
* 实体转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
创建一个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> {
// 根据用户名查找用户
optional<userentity> findbyname(string name);
// 根据邮箱查找用户
optional<userentity> findbyemail(string email);
// 查找所有用户按创建时间倒序
@query("select u from userentity u order by u.createtime desc")
list<userentity> findallorderbycreatedatdesc();
}2. post创建用户接口
现在来实现创建用户的api接口。这个接口将接收post请求,验证输入数据,并将用户信息保存到数据库中。
userdbcontroller中添加如下方法,创建用于客户端post请求创建用户。
/**
* post请求 - 创建用户(json格式请求体)
* 访问地址:post http://localhost:8081/api/post/users
* 请求头:content-type: application/json
* 请求体示例:
* {
* "name": "李四",
* "email": "lisi@example.com", * "age": 30, * "phone": "13900139000", * "address": "上海市浦东新区",
* "agreeterms": true * } * * @param request 接收并验证请求体中的json数据,自动反序列化为usercreaterequest对象,
* valid注解触发对usercreaterequest对象中字段的验证规则
* @param bindingresult 接收参数验证结果,包含所有验证错误信息
* @return apiresponse<userdto>
*/
@postmapping("/api/post/create/user")
public responseentity<apiresponse<userdto>> createuser(
@valid @requestbody userrequest request,
bindingresult bindingresult) {
log.info("创建用户 - 请求数据: {}", request);
// 参数校验
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中添加如下方法,创建用于客户端post请求创建用户。
/**
* 创建用户
*
* @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("邮箱已存在"));
}
// 调用内部事务方法
userentity saveduserentity = saveuserentity(request);
return responseentity.status(httpstatus.created)
.body(apiresponse.success("用户创建成功", converttodto(saveduserentity)));
}
@transactional
public userentity saveuserentity(userrequest request) {
log.info("saveuserentity: ", request);
try {
// 实际的创建逻辑,带有事务
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发送post请求到创建用户接口,可以验证接口功能是否正常。

3. 返回所有用户
接下来实现获取所有用户信息的接口。当用户数量较多时,直接返回所有用户可能导致性能问题,但在开发阶段,这个功能对于测试和数据验证非常有用。
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中添加如下方法,实现获取所有用户的业务逻辑。
/**
* 返回全部用户
*
* @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测试获取所有用户接口,可以查看当前数据库中的所有用户信息。

至此,已经完成了spring boot与sqlite数据库的基本集成,实现了用户的创建和查询功能。这种分层架构的设计使得代码结构清晰,各层职责分明,便于后续的功能扩展和维护。
三、案例代码
以上完整的案例代码,请见以下地址:
https://download.csdn.net/download/aiwusheng/92620719
该案例代码是一个完整的spring boot项目示例,展示了如何实现文件上传功能并集成sqlite数据库。项目采用标准的mvc分层架构,包含controller层、service层、repository层和entity层,代码结构清晰,便于学习和扩展。
项目结构说明:
- controller层:处理http请求,接收参数并返回响应
- service层:实现业务逻辑,包括用户创建、查询等操作
- repository层:继承jparepository,提供数据访问接口
- entity层:定义数据表映射实体类
- 配置文件:包含gradle依赖配置和数据库连接配置
主要功能:
- 多文件上传接口(post /api/uploadfiles)
- 用户创建接口(post /api/post/create/user)
- 用户查询接口(get /api/get/users)
- 参数校验和异常处理
- 事务管理
- 日志记录
技术栈:
- spring boot 3.x
- spring data jpa
- sqlite数据库
- lombok简化代码
- 参数校验注解
- spring web(文件上传支持)
项目可直接运行,适合作为spring boot文件上传和数据库集成的入门学习参考。
到此这篇关于一文掌握springboot:http服务开发从入门到部署 的文章就介绍到这了,更多相关springboot http服务开发内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论