Spring Boot Web

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目录)

参数说明

服务器配置

  • 端口号:80

数据源配置(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条,支持自定义pageNumpageSize
  • 响应处理:通过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()
}
posted @ 2026-01-09 17:01  Jing61  阅读(4)  评论(0)    收藏  举报