Spring Boot Web 示例
项目核心配置(application.yml)
server:
# 配置端口号
port: 80
spring:
# 配置数据源(依赖mybatis-spring-boot-starter)
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/cuit_scss?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&allowMultiQueries=true
username: root
password: root
mybatis:
type-aliases-package: com.springboot.entity # 实体类别名包(简化 XML 中 resultType 配置)
configuration:
# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 可选:开启MyBatis控制台SQL打印
map-underscore-to-camel-case: true # 启用下划线转驼峰映射
pagehelper:
row-bounds-with-count: true # 开启分页总条数统计
reasonable: true # 允许分页合理化
logging:
level:
root: info # 默认日志级别
com.springboot.mapper: debug # Mapper层日志级别(便于调试SQL)
# file:
# name: logs/hippo.log # 可选:日志输出到文件(需手动创建logs目录)
参数说明
服务器配置
数据源配置(MySQL)
- 驱动类:
com.mysql.cj.jdbc.Driver
- 数据库连接地址:
jdbc:mysql://localhost:3306/cuit_scss
- 连接参数说明:
useUnicode=true&characterEncoding=utf-8:启用Unicode编码,UTF-8字符集
useSSL=false:关闭SSL连接(开发环境常用)
allowPublicKeyRetrieval=true:允许获取公钥(解决MySQL 8.0+ 连接报错问题)
zeroDateTimeBehavior=convertToNull:将零日期转换为NULL
transformedBitIsBoolean=true:将BIT类型映射为Boolean
allowMultiQueries=true:允许执行多语句查询
- 数据库账号:root,密码:root(开发环境默认配置,生产环境需修改为安全账号密码)
MyBatis 配置
- 实体类别名包:
com.springboot.entity(XML中可直接使用实体类名,无需写全类路径)
- 核心配置:
map-underscore-to-camel-case: true:启用下划线命名转驼峰命名映射(如数据库字段user_name对应实体类属性userName)
- 日志配置(注释状态):
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl,开启后可在控制台打印SQL语句,便于调试
分页插件配置(PageHelper)
row-bounds-with-count: true:开启分页查询时的总条数统计
reasonable: true:分页合理化(如页码小于1时自动查询第1页,大于最大页码时查询最后一页)
日志配置
- 全局日志级别:info(默认记录info及以上级别日志)
- 特定包日志级别:
com.springboot.mapper: debug(Mapper层日志为debug级别,便于查看SQL执行细节)
- 日志文件(注释状态):
name: logs/hippo.log,开启后日志会输出到指定文件路径
实体类(Entity)
User 实体类(用户表映射)
- 功能:映射数据库
user表,包含用户核心字段
- 依赖注解:
@Data:Lombok注解,自动生成getter、setter、toString等方法
@Accessors(chain = true):支持链式调用(如user.setId(1).setUsername("admin"))
- 字段说明:
id:用户唯一标识(Integer类型,自增主键)
username:用户名(登录账号)
password:密码(实际项目需加密存储,如MD5、BCrypt)
package com.springboot.entity;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class User {
private Integer id; // 用户ID(主键)
private String username; // 用户名
private String password; // 密码(建议加密存储)
}
统一返回结果(DTO)
ResponseResult 统一响应模型
- 功能:标准化接口返回格式,便于前端统一处理
- 核心字段:
code:响应状态码(200=成功,500=默认失败,支持自定义错误码)
data:响应数据(泛型T,支持任意数据类型)
message:响应信息(成功/失败描述)
- 静态工具方法:
- 成功响应:
ok()、ok(T data)、ok(T data, String message)
- 失败响应:
fail(String message)、fail(int code, String message)、fail(T data, String message)等
package com.springboot.entity.dto;
/**
* 统一接口返回结果模型
* @param <T> 响应数据类型
*/
public record ResponseResult<T>(int code, T data, String message) {
/**
* 成功响应(无数据,默认消息)
*/
public static <T> ResponseResult<T> ok() {
return new ResponseResult<>(200, null, "success");
}
/**
* 成功响应(带数据,默认消息)
*/
public static <T> ResponseResult<T> ok(T data) {
return new ResponseResult<>(200, data, "success");
}
/**
* 成功响应(带数据和自定义消息)
*/
public static <T> ResponseResult<T> ok(T data, String message) {
return new ResponseResult<>(200, data, message);
}
/**
* 失败响应(自定义错误码和消息)
*/
public static <T> ResponseResult<T> fail(int code, String message) {
return new ResponseResult<>(code, null, message);
}
/**
* 失败响应(自定义错误码、数据和消息)
*/
public static <T> ResponseResult<T> fail(int code, T data, String message) {
return new ResponseResult<>(code, data, message);
}
/**
* 失败响应(带数据和消息,默认错误码500)
*/
public static <T> ResponseResult<T> fail(T data, String message) {
return new ResponseResult<>(500, data, message);
}
/**
* 失败响应(仅消息,默认错误码500)
*/
public static <T> ResponseResult<T> fail(String message) {
return new ResponseResult<>(500, null, message);
}
}
数据访问层(Mapper)
UserMapper 接口
- 功能:定义用户数据操作方法(CRUD)
- 方法说明:
- 单条查询:
getById(int id)(按ID查询)、getByUsername(String username)(按用户名查询)
- 增删改:
insert(User user)、update(User user)、deleteById(int id)
- 批量查询:
findAll()(查询所有用户,配合分页插件使用)
package com.springboot.mapper;
import com.springboot.entity.User;
import java.util.List;
/**
* 用户数据访问接口(MyBatis Mapper)
*/
public interface UserMapper {
// 按ID查询用户
User getById(int id);
// 按用户名查询用户
User getByUsername(String username);
// 新增用户
int insert(User user);
// 更新用户信息
int update(User user);
// 按ID删除用户
int deleteById(int id);
// 查询所有用户(分页通过PageHelper实现)
List<User> findAll();
}
UserMapper.xml 映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.springboot.mapper.UserMapper">
<!-- 新增用户:插入用户名和密码 -->
<insert id="insert">
insert into user(username,password) values(#{username},#{password})
</insert>
<!-- 更新用户:按ID更新用户名和密码 -->
<update id="update">
update user set username = #{username},password = #{password} where id = #{id}
</update>
<!-- 删除用户:按ID删除 -->
<delete id="deleteById">
delete from user where id = #{id}
</delete>
<!-- 按ID查询用户 -->
<select id="getById" resultType="user">
select * from user where id = #{id}
</select>
<!-- 按用户名查询用户 -->
<select id="getByUsername" resultType="user">
select * from user where username = #{username}
</select>
<!-- 查询所有用户 -->
<select id="findAll" resultType="user">
select * from user
</select>
</mapper>
业务逻辑层(Service)
UserService 接口
- 功能:定义用户业务操作规范,与Mapper接口方法对应(业务层可扩展复杂逻辑)
package com.springboot.service;
import com.github.pagehelper.PageInfo;
import com.springboot.entity.User;
import java.util.List;
/**
* 用户业务逻辑接口
*/
public interface UserService {
User getById(int id);
User getByUsername(String username);
int insert(User user);
int update(User user);
int deleteById(int id);
PageInfo<User> findAll(int pageNum, int pageSize);
}
UserServiceBean 实现类
- 注解说明:
@Service:标识为Spring业务层组件,自动扫描注入
@Transactional:类级事务注解(默认对所有public方法生效)
@Resource:依赖注入UserMapper(JDK原生注解,按名称匹配)
@Transactional(propagation = Propagation.REQUIRED):方法级事务传播机制(默认,支持事务嵌套)
- 分页实现:通过
PageHelper.startPage(pageNum, pageSize)开启分页,查询后封装为PageInfo返回(包含总条数、总页数等分页信息)
package com.springboot.service.bean;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.springboot.entity.User;
import com.springboot.mapper.UserMapper;
import com.springboot.service.UserService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
/**
* 用户业务逻辑实现类
*/
@Service
@Transactional // 开启事务管理
public class UserServiceBean implements UserService {
@Resource
private UserMapper userMapper;
@Override
public User getById(int id) {
return userMapper.getById(id);
}
@Override
public User getByUsername(String username) {
return userMapper.getByUsername(username);
}
@Override
@Transactional(propagation = Propagation.REQUIRED) // 事务传播机制:必要时创建新事务
public int insert(User user) {
return userMapper.insert(user);
}
@Override
@Transactional(propagation = Propagation.REQUIRED)
public int update(User user) {
return userMapper.update(user);
}
@Override
@Transactional(propagation = Propagation.REQUIRED)
public int deleteById(int id) {
return userMapper.deleteById(id);
}
@Override
public PageInfo<User> findAll(int pageNum, int pageSize) {
PageHelper.startPage(pageNum, pageSize); // 开启分页
List<User> userList = userMapper.findAll(); // 执行查询(自动分页)
return new PageInfo<>(userList); // 封装分页结果
}
}
全局配置类
跨域配置(WebConfig)
- 功能:解决前后端分离架构中的跨域请求问题
- 核心配置:
addMapping("/**"):对所有接口生效
allowedOrigins("*"):允许所有来源(生产环境建议指定具体域名,如http://localhost:8080)
allowedMethods:允许的请求方法(GET、POST、PUT、DELETE、OPTIONS)
allowedHeaders("*"):允许所有请求头
maxAge(3600):预检请求缓存时间(1小时,减少重复预检)
- 注意:若需支持跨域携带Cookie,需将
allowedOrigins("*")改为具体域名,并开启allowCredentials(true)
package com.springboot.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* Web全局配置(跨域、拦截器等)
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
/**
* 配置跨域请求
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 所有接口都支持跨域
.allowedOrigins("*") // 允许所有来源(生产环境需指定具体域名)
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") // 允许的请求方法
.allowedHeaders("*") // 允许所有请求头
//.allowCredentials(true) // 允许携带Cookie(需配合具体allowedOrigins)
.maxAge(3600); // 预检请求缓存时间(秒)
}
}
日志切面(ApplicationLogAspect)
- 功能:通过AOP切面记录Service层方法调用日志(入参、执行耗时等)
- 依赖注解:
@Aspect:标识为AOP切面类
@Component:Spring组件,自动扫描
@Slf4j:Lombok注解,简化日志输出(无需手动创建Logger对象)
- 切面逻辑:
@Pointcut:定义切点(execution(* com.springboot.service.*.*(..)):匹配Service包下所有类的所有方法)
@Before:方法执行前记录类名和方法名
@AfterReturning:方法执行后记录耗时
@After:最终清理ThreadLocal(避免内存泄漏)
package com.springboot.aspect;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* 应用日志切面(AOP):记录Service层方法调用日志
*/
@Slf4j
@Aspect
@Component
public class ApplicationLogAspect {
// ThreadLocal存储方法开始时间(线程安全)
private static ThreadLocal<Long> startTime = new ThreadLocal<>();
/**
* 定义切点:匹配com.springboot.service包下所有类的所有方法
*/
@Pointcut("execution(* com.springboot.service.*.*(..))")
private void pointcut() {
}
/**
* 方法执行前通知:记录调用的类和方法
*/
@Before("pointcut()")
public void before(JoinPoint joinPoint) {
long begin = System.currentTimeMillis();
startTime.set(begin);
log.info("Class Method:{}.{}",
joinPoint.getSignature().getDeclaringTypeName(), // 类全名
joinPoint.getSignature().getName() // 方法名
);
}
/**
* 方法正常返回后通知:记录执行耗时
*/
@AfterReturning("pointcut()")
public void afterReturning() {
long end = System.currentTimeMillis();
long cost = end - startTime.get();
log.info("Method Execution Cost: {}ms", cost);
}
/**
* 方法最终通知:清理ThreadLocal(避免内存泄漏)
*/
@After("pointcut()")
public void afterFinally() {
startTime.remove();
}
}
控制层(Controller)
UserController 接口控制器
- 注解说明:
@RestController:标识为REST接口控制器(自动返回JSON格式)
@RequestMapping("/user"):统一接口前缀(所有接口路径以/user开头)
@Resource:注入UserService业务层对象
@GetMapping:GET请求映射(查询操作)
@PathVariable:获取URL路径参数
@RequestParam:获取请求参数(支持默认值)
- 接口说明:
GET /user/{id}:按ID查询用户(返回单个用户信息)
GET /user:分页查询所有用户(默认页码1,每页10条,支持自定义pageNum和pageSize)
- 响应处理:通过
ResponseResult统一返回,查询不到数据时返回失败信息
package com.springboot.controller;
import com.github.pagehelper.PageInfo;
import com.springboot.entity.User;
import com.springboot.entity.dto.ResponseResult;
import com.springboot.service.UserService;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;
/**
* 用户模块接口控制器(RESTful API)
*/
@RestController
@RequestMapping("/user")
public class UserController {
@Resource
private UserService userService;
/**
* 按ID查询用户
* @param id 用户ID(路径参数)
* @return 成功返回用户信息,失败返回提示
*/
@GetMapping("/{id}")
public ResponseResult<User> getById(@PathVariable int id) {
User user = userService.getById(id);
return user == null ? ResponseResult.fail("用户不存在") : ResponseResult.ok(user);
}
/**
* 分页查询所有用户
* @param pageNum 页码(默认1)
* @param pageSize 每页条数(默认10)
* @return 分页用户列表
*/
@GetMapping
public ResponseResult<PageInfo<User>> findAll(
@RequestParam(name = "pageNum", defaultValue = "1") int pageNum,
@RequestParam(name = "pageSize", defaultValue = "10") int pageSize
) {
PageInfo<User> pageInfo = userService.findAll(pageNum, pageSize);
return ResponseResult.ok(pageInfo);
}
}
项目依赖说明(需在build.gradle中添加)
plugins {
id 'java'
id 'org.springframework.boot' version '4.0.1'
id 'io.spring.dependency-management' version '1.1.7'
}
group = 'com'
version = '0.0.1-SNAPSHOT'
description = 'springboot'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-web'
// MyBatis 依赖
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:4.0.1'
// MySQL 8.0.33
implementation 'mysql:mysql-connector-java:8.0.33'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
// 分页插件
implementation 'com.github.pagehelper:pagehelper-spring-boot-starter:2.1.1'
}
tasks.named('test') {
useJUnitPlatform()
}