SpringBoot应用开发课程相关技术——8 大主题一次性搞定

1.如何配置开发环境(JDK、Maven、IDEA等);

2.如何快速搭建SpringBoot项目;

3.如何在SpringBoot中整合持久层框架(Mabatis、Mabatis-Plus、JPA等);

4.如何进行数据缓存管理。

5.如何使用Thymeleaf进行视图开发。

6.如何进行权限控制和安全控制。

7.消息服务和任务管理。

8.完整的项目开发流程等。

① 如何配置开发环境(JDK、Maven、IDEA等)

  1. 一、JDK 17(LTS)安装与配置

    JDK 是 Java 开发的核心,推荐安装长期支持版(LTS)的 JDK 17。

    1. 下载 JDK
  2. 官方推荐渠道:
  3. 选择对应系统版本:
    • Windows:x64 架构的 .msi(傻瓜式安装)或 .zip(手动解压)
    • macOS:x64 或 aarch64(M1/M2 芯片)的 .pkg 或 .tar.gz
  4. 配置开发环境的核心步骤:

  5. 安装 JDK 并配置 JAVA_HOME,确保 java -version 正常。
  6. 安装 Maven 并配置镜像和本地仓库,确保 mvn -v 正常。
  7. 在 IDEA 中关联 JDK 和 Maven,安装必要插件,配置编码。

    四、验证开发环境

  1. 打开 IDEA → 点击 “New Project” → 选择 “Spring Initializr” → 选择 JDK 17 → 填写项目信息(Group、Artifact) → 勾选 “Spring Web” 依赖 → 点击 “Create”。
  2. 新建一个 Controller 类:

    java

    运行

    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class TestController {
        @GetMapping("/test")
        public String test() {
            return "Hello, Dev Environment!";
        }
    }
    
  3. 运行项目的主启动类 → 访问 http://localhost:8080/test,若返回字符串则环境配置成功。
  4. 5. 配置编码格式(避免中文乱码)
  5. 进入 “File → Settings → Editor → File Encodings”。
  6. 全部设置为 “UTF-8”:
    • Global Encoding: UTF-8
    • Project Encoding: UTF-8
    • Default encoding for properties files: UTF-8
    • 勾选 “Transparent native-to-ascii conversion”。
  7. 4. 安装必要插件
  8. 进入 “File → Settings → Plugins”。
  9. 搜索并安装以下插件:
    • Spring Boot DevTools:支持热部署,修改代码后无需重启应用。
    • Spring Initializr and Assistant:快速创建 Spring Boot 项目。
    • Thymeleaf:Thymeleaf 模板语法高亮和提示。
    • Lombok:简化实体类代码(需配合 Lombok 依赖使用)。
    • MyBatisX:MyBatis 框架的 XML 映射文件和接口跳转支持。
  10. 3. 配置 Maven
  11. 进入 “File → Settings”(Windows/Linux)或 “IntelliJ IDEA → Settings”(macOS)。
  12. 搜索 “Maven” → 配置以下参数:
    • “Maven home path”:选择 Maven 安装目录(如 D:\dev\apache-maven-3.9.6)。
    • “User settings file”:选择 Maven 的 conf/settings.xml(启用 “Override” 后选择)。
    • “Local repository”:自动读取 settings.xml 中的本地仓库路径,无需手动修改。
  13. 点击 “Apply → OK” 生效。
  14. 2. 配置 JDK
  15. 打开 IDEA → 进入 “File → Project Structure”(或新建项目时)。
  16. 在 “SDKs” 选项卡 → 点击 “+” → “Add JDK” → 选择已安装的 JDK 17 路径(如 C:\Program Files\Eclipse Adoptium\jdk-17.0.10+7) → 点击 “OK”。
  17. 设为默认 JDK:在 “Project” 选项卡中,将 “Project SDK” 选为 JDK 17。
  18. 1. 下载与安装 IDEA
  19. 访问JetBrains 官网,选择 “Community Edition”(社区版)下载。
  20. 安装时勾选:
    • “Create Desktop Shortcut”(创建桌面快捷方式)
    • “Add launchers dir to PATH”(可选,便于命令行启动)
    • 关联 .java 等文件(根据需求勾选)。
  21. 三、IntelliJ IDEA 配置

    IDEA 是主流的 Java IDE,社区版(Community)免费,功能足够开发 Spring Boot 项目。

    5. 验证 Maven 安装
  22. 终端输入:

    bash

    mvn -v
    
  23. 输出类似以下内容即为成功:

    plaintext

    Apache Maven 3.9.6 (bc0240f3c744dd6b6ec2920b3cd08ccf28cc53)
    Maven home: D:\dev\apache-maven-3.9.6
    Java version: 17.0.10, vendor: Eclipse Adoptium, runtime: C:\Program Files\Eclipse Adoptium\jdk-17.0.10+7
    
  24. 4. 配置 Maven 仓库(加速依赖下载)

    默认 Maven 仓库在国外,建议配置阿里云镜像,并修改本地仓库路径(避免 C 盘占用)。

  25. 打开 Maven 安装目录下的 conf/settings.xml
  26. 配置本地仓库路径:在 <settings> 标签内添加(路径自定义):

    xml

    <localRepository>D:/dev/maven-repo</localRepository>  <!-- Windows -->
    <!-- 或 -->
    <localRepository>~/dev/maven-repo</localRepository>   <!-- macOS/Linux -->
    
  27. 配置阿里云镜像:在 <mirrors> 标签内添加:

    xml

    <mirror>
        <id>aliyunmaven</id>
        <mirrorOf>*</mirrorOf>
        <name>阿里云公共仓库</name>
        <url>https://maven.aliyun.com/repository/public</url>
    </mirror>
    
  28. macOS/Linux
  29. 编辑 ~/.zshrc 或 ~/.bash_profile,添加:

    bash

    export MAVEN_HOME=~/dev/apache-maven-3.9.6  # 替换为实际路径
    export PATH=$MAVEN_HOME/bin:$PATH
    
  30. 生效配置:source ~/.zshrc
  31. 3. 配置环境变量
    Windows
  32. 新建系统变量 MAVEN_HOME,值为 Maven 解压路径(如 D:\dev\apache-maven-3.9.6)。
  33. 编辑 Path,新增 %MAVEN_HOME%\bin
  34. 2. 安装 Maven
  35. Windows:解压到自定义目录(如 D:\dev\apache-maven-3.9.6)。
  36. macOS/Linux:解压到 /usr/local/ 或 ~/dev/ 目录(如 ~/dev/apache-maven-3.9.6)。
  37. 二、Maven 安装与配置

    Maven 是 Java 项目的构建工具,用于依赖管理和项目打包。

    1. 下载 Maven
  38. 访问Maven 官网,下载最新版二进制压缩包(如 apache-maven-3.9.6-bin.zip)。
  39. 4. 验证 JDK 安装
  40. 打开终端 / 命令提示符,输入:

    bash

    java -version
    javac -version
    
  41. 输出类似以下内容即为成功:

    plaintext

    openjdk version "17.0.10" 2024-01-16 LTS
    OpenJDK Runtime Environment Temurin-17.0.10+7 (build 17.0.10+7)
    OpenJDK 64-Bit Server VM Temurin-17.0.10+7 (build 17.0.10+7, mixed mode, sharing)
    
  42. macOS/Linux
  43. 打开终端,编辑配置文件(~/.bash_profile 或 ~/.zshrc,根据 shell 类型选择):

    bash

    vi ~/.zshrc  # 或 .bash_profile
    
  44. 添加以下内容(路径替换为实际 JDK 路径):

    bash

    export JAVA_HOME=/Library/Java/JavaVirtualMachines/temurin-17.jdk/Contents/Home
    export PATH=$JAVA_HOME/bin:$PATH
    
  45. 生效配置:

    bash

    source ~/.zshrc  # 或 .bash_profile
    
  46. 3. 配置环境变量(Windows 手动配置或 macOS)
    Windows
  47. 右键 “此电脑” → “属性” → “高级系统设置” → “环境变量”。
  48. 新建系统变量
    • 变量名:JAVA_HOME
    • 变量值:JDK 安装路径(如 C:\Program Files\Eclipse Adoptium\jdk-17.0.10+7)。
  49. 编辑系统变量 Path
    • 新增 %JAVA_HOME%\bin 和 %JAVA_HOME%\jre\bin(若存在 jre 目录)。
  50. macOS 系统
  51. .pkg 安装包:双击文件 → 按照向导安装,默认路径为 /Library/Java/JavaVirtualMachines/temurin-17.jdk/Contents/Home
  52. .tar.gz 压缩包:解压到 /Library/Java/JavaVirtualMachines/ 或自定义目录(如 ~/dev/jdk-17)。
  53. 2. 安装 JDK
    Windows 系统
  54. .msi 安装包:双击文件 → 勾选 “Add to PATH”(自动配置环境变量,推荐) → 选择安装路径(如 C:\Program Files\Eclipse Adoptium\jdk-17.0.10+7) → 点击 “Install” 完成。
  55. .zip 压缩包:解压到指定目录(如 D:\dev\jdk-17) → 手动配置环境变量(见步骤 3)。

② 快速搭建 SpringBoot 项目

方法二:使用 IDEA 内置工具(推荐,更便捷)

如果使用 IntelliJ IDEA(旗舰版,社区版需手动配置),可直接在 IDE 内生成项目,无需访问网页。

方法三:手动创建(了解底层,适合学习)

适合想深入理解项目结构的场景,手动配置 Maven/Gradle 文件。

项目启动与测试

总结

  1. 方法一:使用 Spring Initializr(官方推荐,最常用)

    Spring 官方提供的初始化工具,可视化配置,适合快速生成基础项目结构。

  2. 访问官网打开 Spring Initializr(国内可访问 start.springboot.io 镜像)。

  3. 配置项目信息

    • Project:选择构建工具(Maven/Gradle,推荐 Maven)。
    • Language:选择开发语言(Java/Kotlin/Groovy,通常选 Java)。
    • Spring Boot:选择版本(建议选 稳定版,如 3.2.x,避免最新快照版)。
    • Project Metadata:填写 Group(组织 ID,如com.example)、Artifact(项目名,如demo)、Package Name 等。
    • Packaging:选择打包方式(Jar/War,Spring Boot 默认推荐 Jar,内置 Tomcat)。
    • Java:选择 JDK 版本(需与本地安装的 JDK 匹配,如 JDK17)。
  4. 添加依赖(Dependencies)在搜索框中输入需要的依赖(如 Web、MySQL、MyBatis 等),勾选后自动添加到配置中。

    • 基础 Web 项目必选:Spring Web(提供 RESTful 接口、内置服务器等)。
    • 其他常用:Spring Data JPA、MyBatis、Lombok(简化代码)、Spring Security 等。
  5. 生成项目点击 Generate 按钮,下载压缩包,解压后导入 IDE(如 IDEA、Eclipse)即可。

  6. 新建项目打开 IDEA → File → New → Project → 左侧选择 Spring Initializr,默认使用官方地址(或替换为国内镜像)。

  7. 配置项目信息同方法一的步骤 2(Project Metadata、Java 版本等)。

  8. 选择依赖在依赖列表中勾选所需组件(如 Web、Lombok 等),IDEA 会实时显示选中的依赖。

  9. 完成创建选择项目保存路径,点击 Finish,IDEA 会自动下载依赖并构建项目。

  10. 创建目录结构按 Maven 标准结构创建文件夹:

    plaintext

    demo/
    ├─ src/
    │  ├─ main/
    │  │  ├─ java/
    │  │  │  └─ com/example/demo/  # 包路径
    │  │  └─ resources/            # 配置文件
    │  └─ test/                    # 测试代码
    └─ pom.xml                     # Maven配置文件
    
  11. 编写 pom.xml添加 Spring Boot 父工程和核心依赖(以 Maven 为例):

    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 http://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>3.2.0</version> <!-- 版本号 -->
            <relativePath/>
        </parent>
    
        <groupId>com.example</groupId>
        <artifactId>demo</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    
        <properties>
            <java.version>17</java.version> <!-- JDK版本 -->
        </properties>
    
        <!-- 核心依赖:Web场景 -->
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <!-- 测试依赖 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
        <!-- 打包插件:支持Spring Boot的Jar包构建和运行 -->
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    </project>
    
  12. 创建启动类在 src/main/java/com/example/demo/ 下新建启动类 DemoApplication.java

    java

    运行

    package com.example.demo;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication // 核心注解:开启自动配置、组件扫描等
    public class DemoApplication {
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args); // 启动Spring Boot
        }
    }
    
  13. 验证项目运行 main 方法,控制台输出 Started DemoApplication in xxx seconds 即表示成功。

  14. 启动项目

    • IDE 中直接运行启动类的 main 方法。
    • 命令行:进入项目根目录,执行 mvn spring-boot:run(Maven)或 ./gradlew bootRun(Gradle)。
  15. 测试接口(以 Web 项目为例)新建一个 Controller 类(如 HelloController.java):

    java

    运行

    package com.example.demo.controller;
    
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class HelloController {
        @GetMapping("/hello")
        public String hello() {
            return "Hello, Spring Boot!";
        }
    }
    

    重启项目后,访问 http://localhost:8080/hello,若返回字符串则说明搭建成功。

  16. 推荐使用 Spring Initializr 或 IDEA 内置工具,1-2 分钟即可完成基础项目搭建,重点是选对依赖和版本。
  17. 手动创建适合学习底层原理,理解 Spring Boot 的自动配置和依赖管理机制。
  18. 国内用户建议使用国内镜像(如 start.springboot.io)加速依赖下载。

③ 如何在SpringBoot中整合持久层框架(Mabatis、Mabatis-Plus、JPA等)

一、整合 MyBatis

MyBatis 是一款轻量级持久层框架,需要手动编写 SQL 和映射文件(或注解)。

1. 引入依赖

pom.xml中添加 MyBatis 和数据库驱动依赖(以 MySQL 为例):

<!-- Spring Boot整合MyBatis -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>3.0.3</version> <!-- 版本需与Spring Boot兼容 -->
</dependency>

<!-- MySQL驱动 -->
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>

<!-- 可选:数据库连接池(Spring Boot默认用HikariCP) -->
<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
</dependency>
2. 配置数据源

application.yml(或application.properties)中配置数据库连接信息:

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test_db?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
    username: root
    password: 123456
    hikari:
      maximum-pool-size: 10 # 连接池最大连接数

# MyBatis配置(可选)
mybatis:
  mapper-locations: classpath:mapper/*.xml # 映射文件路径(若用XML方式)
  type-aliases-package: com.example.demo.entity # 实体类包路径(简化别名)
  configuration:
    map-underscore-to-camel-case: true # 开启下划线转驼峰(如user_name → userName)
3. 定义实体类(Entity)
public class User {
    private Long id;
    private String username;
    private Integer age;
    // 省略getter、setter、构造方法
}
4. 定义 Mapper 接口

两种方式:注解方式(简单 SQL)或XML 方式(复杂 SQL)。

  • 注解方式(无需 XML):

    @Mapper // 标记为MyBatis映射接口(或在启动类加@MapperScan("com.example.demo.mapper")批量扫描)
    public interface UserMapper {
        @Select("SELECT * FROM user WHERE id = #{id}")
        User getById(Long id);
    
        @Insert("INSERT INTO user(username, age) VALUES(#{username}, #{age})")
        @Options(useGeneratedKeys = true, keyProperty = "id") // 自增主键回显
        int insert(User user);
    }
    
  • XML 方式(推荐复杂 SQL):

    1. 创建src/main/resources/mapper/UserMapper.xml
      <?xml version="1.0" encoding="UTF-8"?>
      <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
      "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
      
      <mapper namespace="com.example.demo.mapper.UserMapper">
          <select id="getById" resultType="User">
              SELECT * FROM user WHERE id = #{id}
          </select>
          
          <insert id="insert" useGeneratedKeys="true" keyProperty="id">
              INSERT INTO user(username, age) VALUES(#{username}, #{age})
          </insert>
      </mapper>
      
    2. 对应的 Mapper 接口(无需注解):
      public interface UserMapper {
          User getById(Long id);
          int insert(User user);
      }
      
5. 测试使用

通过 Service 层调用 Mapper:

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    public User getUser(Long id) {
        return userMapper.getById(id);
    }
}

二、整合 MyBatis-Plus

MyBatis-Plus 是 MyBatis 的增强工具,提供 CRUD 通用接口、条件构造器等,简化开发。

1. 引入依赖

替换 MyBatis 依赖为 MyBatis-Plus:

<!-- MyBatis-Plus Starter -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.5</version>
</dependency>

<!-- MySQL驱动(同上) -->
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>
2. 配置数据源

与 MyBatis 相同(application.yml),可额外添加 MyBatis-Plus 配置:

mybatis-plus:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.example.demo.entity
  global-config:
    db-config:
      table-prefix: t_ # 表名前缀(如实体User对应表t_user)
      id-type: auto # 主键自增策略
3. 定义实体类

使用@TableName(指定表名)、@TableId(主键)等注解:

@TableName("t_user") // 对应数据库表t_user
public class User {
    @TableId(type = IdType.AUTO) // 主键自增
    private Long id;
    
    @TableField("username") // 对应表字段(若名称一致可省略)
    private String username;
    
    private Integer age;
    // 省略getter、setter
}
4. 定义 Mapper 接口

继承BaseMapper<T>,无需手动编写基础 CRUD 方法:

@Mapper
public interface UserMapper extends BaseMapper<User> {
    // 继承后直接拥有selectById、insert、updateById、deleteById等方法
    // 复杂SQL仍可通过注解或XML扩展
}
5. 测试使用

利用 MyBatis-Plus 的通用方法和条件构造器:

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    // 查询:根据ID
    public User getById(Long id) {
        return userMapper.selectById(id);
    }

    // 新增
    public boolean add(User user) {
        return userMapper.insert(user) > 0;
    }

    // 条件查询:年龄大于18的用户
    public List<User> getByAge() {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.gt("age", 18); // gt = greater than
        return userMapper.selectList(queryWrapper);
    }
}

三、整合 Spring Data JPA

JPA(Java Persistence API)是 ORM 规范,Spring Data JPA 基于 Hibernate 实现,提供全自动 CRUD 操作,适合快速开发。

1. 引入依赖
<!-- Spring Data JPA -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<!-- MySQL驱动(同上) -->
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>
2. 配置数据源与 JPA
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test_db?useSSL=false&serverTimezone=UTC
    username: root
    password: 123456
  jpa:
    hibernate:
      ddl-auto: update # 自动创建/更新表结构(create:每次启动重建,update:更新,none:不操作)
    show-sql: true # 控制台打印SQL
    properties:
      hibernate:
        format_sql: true # SQL格式化
    database-platform: org.hibernate.dialect.MySQL8Dialect # 指定数据库方言
3. 定义实体类

使用 JPA 注解映射表关系:

@Entity // 标记为JPA实体
@Table(name = "t_user") // 对应表名
public class User {
    @Id // 主键
    @GeneratedValue(strategy = GenerationType.IDENTITY) // 自增策略
    private Long id;

    @Column(name = "username", length = 50) // 对应表字段
    private String username;

    private Integer age;
    // 省略getter、setter
}
4. 定义 Repository 接口

继承JpaRepository<T, ID>,自动拥有 CRUD 方法:

// 泛型:实体类User,主键类型Long
public interface UserRepository extends JpaRepository<User, Long> {
    // 支持方法名自动生成SQL(无需手动编写)
    List<User> findByAgeGreaterThan(Integer age); // 等价于WHERE age > ?
    User findByUsername(String username); // 等价于WHERE username = ?
}
5. 测试使用

通过 Service 调用 Repository:

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;

    // 查询所有
    public List<User> getAll() {
        return userRepository.findAll();
    }

    // 根据年龄查询(自定义方法)
    public List<User> getByAge(Integer age) {
        return userRepository.findByAgeGreaterThan(age);
    }

    // 保存/更新(id存在则更新,否则新增)
    public User save(User user) {
        return userRepository.save(user);
    }
}

总结

框架特点适用场景
MyBatis轻量、SQL 可控性高,需手动编写映射复杂 SQL 场景、性能要求高的系统
MyBatis-Plus增强 MyBatis,提供通用 CRUD、条件构造器简化开发,兼顾 SQL 灵活性
JPA全自动 ORM,无需写 SQL,依赖方法名生成快速开发、SQL 简单的业务(如后台管理系统)

整合核心步骤:

  1. 引入对应框架的 Starter 依赖;
  2. 配置数据源(数据库连接信息);
  3. 定义实体类(映射数据库表);
  4. 定义数据访问接口(Mapper/Repository);
  5. 通过 Service 层调用接口实现数据库操作。

④ 如何进行数据缓存管理。

一、基础:使用 Spring Cache(注解驱动,简化缓存操作)

Spring Cache 提供了统一的缓存抽象,支持多种缓存实现(如内存缓存、Redis 等),通过注解即可完成缓存的增删改查。

1. 引入依赖

根据缓存类型选择依赖:

  • 本地缓存(适合单节点应用,如 Caffeine):

    xml

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>
    <!-- Caffeine缓存(高性能本地缓存) -->
    <dependency>
        <groupId>com.github.ben-manes.caffeine</groupId>
        <artifactId>caffeine</artifactId>
    </dependency>
    
  • 分布式缓存(适合集群应用,如 Redis):

    xml

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    
2. 开启缓存支持

在启动类添加@EnableCaching注解:

java

运行

@SpringBootApplication
@EnableCaching // 开启缓存功能
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
3. 配置缓存(以 Redis 为例)

application.yml中配置缓存参数:

yaml

spring:
  # Redis配置
  redis:
    host: localhost
    port: 6379
    password: 123456 # 无密码可省略
    timeout: 5000ms
  # 缓存配置
  cache:
    type: redis # 指定缓存类型为Redis(本地缓存可设为caffeine)
    redis:
      time-to-live: 3600000ms # 缓存过期时间(1小时)
      key-prefix: "cache:" # 缓存key前缀
      use-key-prefix: true # 启用前缀
      cache-null-values: false # 是否缓存null值(防止缓存穿透)

本地缓存(Caffeine)配置

yaml

spring:
  cache:
    type: caffeine
    caffeine:
      spec: maximumSize=1000,expireAfterWrite=60s # 最大1000条,写入后60秒过期
4. 核心缓存注解使用

通过注解在 Service 层控制缓存逻辑:

注解作用常用属性
@Cacheable方法执行前先查缓存,无则执行方法并缓存结果value/cacheNames(缓存名称)、key(缓存 key)
@CachePut执行方法后更新缓存(不影响方法执行)key(指定更新的缓存 key)
@CacheEvict删除缓存allEntries=true(清空整个缓存)
@Caching组合多个缓存操作(如同时更新 + 删除)包含cacheableputevict

示例代码

java

运行

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    // 查询:优先查缓存,无则查DB并缓存结果
    @Cacheable(value = "userCache", key = "#id") // 缓存名称userCache,key为参数id
    public User getById(Long id) {
        System.out.println("查询DB:id=" + id); // 仅首次执行
        return userMapper.selectById(id);
    }

    // 更新:执行后更新缓存(确保缓存与DB一致)
    @CachePut(value = "userCache", key = "#user.id") // key为用户id
    public User update(User user) {
        userMapper.updateById(user);
        return user; // 缓存此返回值
    }

    // 删除:删除对应缓存
    @CacheEvict(value = "userCache", key = "#id")
    public void delete(Long id) {
        userMapper.deleteById(id);
    }

    // 清空整个缓存(如批量删除场景)
    @CacheEvict(value = "userCache", allEntries = true)
    public void deleteAll() {
        // 批量删除逻辑
    }
}
5. 自定义缓存 Key

默认 key 生成策略为方法名+参数,可通过keyGenerator自定义:

java

运行

@Configuration
public class CacheConfig {
    @Bean
    public KeyGenerator myKeyGenerator() {
        return (target, method, params) -> {
            // 生成格式:类名.方法名:参数1,参数2...
            StringBuilder key = new StringBuilder();
            key.append(target.getClass().getName()).append(".");
            key.append(method.getName()).append(":");
            for (Object param : params) {
                key.append(param).append(",");
            }
            return key.toString();
        };
    }
}

使用自定义生成器:

java

运行

@Cacheable(value = "userCache", keyGenerator = "myKeyGenerator")
public User getByUsername(String username) { ... }

二、高级:分布式缓存(Redis)进阶配置

当应用部署在多节点(集群)时,本地缓存会导致数据不一致,需使用 Redis 等分布式缓存。

1. 序列化配置(解决 Redis 存储对象乱码)

默认 JDK 序列化会导致 Redis 中数据可读性差,建议改用 JSON 序列化:

java

运行

@Configuration
public class RedisCacheConfig {
    @Bean
    public RedisCacheConfiguration cacheConfiguration() {
        // JSON序列化器
        RedisSerializer<Object> serializer = new GenericJackson2JsonRedisSerializer();
        
        return RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofHours(1)) // 全局过期时间
                .serializeKeysWith(RedisSerializationContext.SerializationPair
                        .fromSerializer(new StringRedisSerializer())) // key用String序列化
                .serializeValuesWith(RedisSerializationContext.SerializationPair
                        .fromSerializer(serializer)) // value用JSON序列化
                .disableCachingNullValues(); // 不缓存null
    }
}
2. 缓存穿透、击穿、雪崩解决方案
  • 缓存穿透:查询不存在的数据,导致每次都访问 DB。解决:缓存 null 值(cache-null-values: true),或使用布隆过滤器提前拦截。

  • 缓存击穿:热点 key 过期瞬间,大量请求穿透到 DB。解决:加互斥锁(如 Redisson 的RLock),或设置热点 key 永不过期。

  • 缓存雪崩:大量 key 同时过期,导致 DB 压力骤增。解决:过期时间加随机值(避免同时过期),或使用多级缓存(本地缓存 + Redis)。

示例:用互斥锁解决缓存击穿

java

运行

@Service
public class UserService {
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private UserMapper userMapper;

    public User getByIdWithLock(Long id) {
        String key = "cache:user:" + id;
        // 1. 查缓存
        String json = redisTemplate.opsForValue().get(key);
        if (json != null) {
            return JSON.parseObject(json, User.class);
        }

        // 2. 缓存未命中,加锁
        String lockKey = "lock:user:" + id;
        boolean locked = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS);
        if (!locked) {
            // 未抢到锁,重试
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) { ... }
            return getByIdWithLock(id); // 递归重试
        }

        try {
            // 3. 查DB
            User user = userMapper.selectById(id);
            if (user != null) {
                // 4. 写入缓存
                redisTemplate.opsForValue().set(key, JSON.toJSONString(user), 1, TimeUnit.HOURS);
            }
            return user;
        } finally {
            // 5. 释放锁
            redisTemplate.delete(lockKey);
        }
    }
}

三、缓存管理最佳实践

  1. 缓存粒度:缓存高频访问、变化少的数据(如字典、用户信息),避免缓存大对象或频繁变化的数据。
  2. 过期策略:根据业务设置合理的 TTL(生存时间),避免缓存数据长期无效。
  3. 一致性:更新 DB 后需同步更新或删除缓存(@CachePut/@CacheEvict),避免缓存与 DB 不一致。
  4. 监控:通过 Redis 监控工具(如 Redis Insight)监控缓存命中率、内存占用等指标。

总结

  • 简单场景:用@EnableCaching+@Cacheable等注解,配合 Redis 实现分布式缓存。
  • 复杂场景:自定义序列化、解决缓存三大问题(穿透、击穿、雪崩),必要时引入 Redisson 等工具增强分布式锁能力。
  • 核心目标:减少 DB 访问,同时保证缓存与数据一致性。

⑤ 如何使用Thymeleaf进行视图开发。

一、环境准备

1. 引入依赖

在 pom.xml 中添加 Thymeleaf 依赖(Spring Boot 会自动配置):

xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
2. 配置 Thymeleaf(可选)

默认配置已满足基本需求,如需自定义,在 application.yml 中配置:

yaml

spring:
  thymeleaf:
    prefix: classpath:/templates/  # 模板文件存放路径(默认)
    suffix: .html                  # 模板文件后缀(默认)
    mode: HTML5                    # 模板模式
    encoding: UTF-8                # 编码
    cache: false                   # 开发环境关闭缓存(避免修改后需重启)

二、基础使用流程

1. 创建控制器(Controller)

通过控制器向前端传递数据:

java

运行

@Controller // 注意:用@Controller而非@RestController(@RestController返回JSON)
public class UserController {

    // 向视图传递数据
    @GetMapping("/user")
    public String user(Model model) {
        // 存储单个对象
        User user = new User(1L, "张三", 20);
        model.addAttribute("user", user);

        // 存储集合
        List<User> users = Arrays.asList(
            new User(2L, "李四", 22),
            new User(3L, "王五", 25)
        );
        model.addAttribute("users", users);

        // 存储基本类型
        model.addAttribute("message", "欢迎使用Thymeleaf!");
        model.addAttribute("isVip", true);

        // 返回模板文件名(对应 templates/user.html)
        return "user";
    }
}
2. 创建实体类(User)

java

运行

public class User {
    private Long id;
    private String name;
    private Integer age;

    // 构造方法、getter、setter
    public User(Long id, String name, Integer age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
    // getter和setter省略
}
3. 创建 Thymeleaf 模板

在 src/main/resources/templates/ 目录下创建 user.html

html

预览

<!DOCTYPE html>
<!-- 声明 Thymeleaf 命名空间,支持IDE自动提示 -->
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>用户信息</title>
</head>
<body>
    <!-- 1. 输出文本(th:text 替换标签内容) -->
    <h1 th:text="${message}">默认文本(浏览器直接打开时显示)</h1>

    <!-- 2. 访问对象属性(${对象.属性名}) -->
    <div>
        <p>ID:<span th:text="${user.id}">0</span></p>
        <p>姓名:<span th:text="${user.name}">未知</span></p>
        <p>年龄:<span th:text="${user.age}">0</span></p>
    </div>

    <!-- 3. 条件判断(th:if / th:unless) -->
    <p th:if="${isVip}">您是VIP用户</p>
    <p th:unless="${isVip}">您是普通用户</p>

    <!-- 4. 循环遍历(th:each) -->
    <h3>用户列表</h3>
    <ul>
        <!-- 遍历users集合,每次迭代的元素为u -->
        <li th:each="u : ${users}">
            <span th:text="${u.id}"></span> - 
            <span th:text="${u.name}"></span> - 
            <span th:text="${u.age}"></span>
        </li>
    </ul>

    <!-- 5. 链接(th:href) -->
    <a th:href="@{/home}">首页</a> <!-- 生成 /home 路径 -->
    <a th:href="@{/user/detail(id=${user.id})}">用户详情</a> <!-- 生成 /user/detail?id=1 -->

    <!-- 6. 内联文本([[ ]] 等价于 th:text,需在标签内使用) -->
    <p>内联文本示例:[[${user.name}]]的年龄是[[${user.age}]]</p>
</body>
</html>

三、核心语法详解

1. 变量表达式(${...}

用于获取模型中的数据,支持对象、集合、基本类型:

  • 访问对象属性:${user.name}(调用 user.getName()
  • 访问集合元素:${users[0].name}
  • 调用方法:${user.getName()}(与 user.name 等价)
2. 选择表达式(*{...}

结合 th:object 使用,简化对象属性访问:

html

预览

<div th:object="${user}"> <!-- 声明当前对象为user -->
    <p>姓名:<span th:text="*{name}"></span></p> <!-- 等价于 ${user.name} -->
    <p>年龄:<span th:text="*{age}"></span></p>
</div>
3. 链接表达式(@{...}

生成 URL,自动处理上下文路径(Context Path):

  • 绝对路径:@{http://www.example.com}
  • 相对路径:
    • 相对于当前页面:@{user/detail} → /当前上下文/user/detail
    • 相对于根路径:@{/user/detail} → /当前上下文/user/detail(推荐)
  • 带参数:@{/user/detail(id=${user.id}, name=${user.name})} → /user/detail?id=1&name=张三
4. 条件判断
  • th:if:条件为 true 时显示标签
  • th:unless:条件为 false 时显示标签(与 th:if 相反)
  • th:switch + th:case:多条件判断

html

预览

<div th:switch="${user.age}">
    <p th:case="20">年龄是20</p>
    <p th:case="22">年龄是22</p>
    <p th:case="*">其他年龄</p> <!-- * 表示默认 -->
</div>
5. 循环遍历(th:each

遍历集合、数组、Map 等,支持获取迭代状态:

html

预览

<ul>
    <!-- status 为迭代状态对象,包含 index(索引)、count(计数)、size(总长度)等 -->
    <li th:each="u, status : ${users}">
        索引:<span th:text="${status.index}"></span>,
        计数:<span th:text="${status.count}"></span>,
        姓名:<span th:text="${u.name}"></span>
    </li>
</ul>
6. 模板复用(片段包含)
  • 定义片段:用 th:fragment 标记可复用的代码块(如 header.html):

    html

    预览

    <!-- templates/header.html -->
    <header th:fragment="siteHeader(title)">
        <h1 th:text="${title}">网站标题</h1>
        <nav>菜单导航</nav>
    </header>
    
  • 引入片段:用 th:include 或 th:replace 引入(推荐 th:replace):

    html

    预览

    <!-- 在 user.html 中引入 header 片段 -->
    <div th:replace="header :: siteHeader('用户页面')"></div>
    <!-- 语法:模板名 :: 片段名(参数) -->
    
  • 片段排除:用 th:remove 移除不需要的标签(如开发时的占位符):

    html

    预览

    <p th:remove="all">此内容在渲染时会被移除</p>
    
7. 表单处理

结合 th:field 绑定表单数据到模型对象:

html

预览

<!-- 表单提交到 /user/save,方法为POST -->
<form th:action="@{/user/save}" th:method="post" th:object="${user}">
    <!-- 绑定 user.id -->
    <input type="hidden" th:field="*{id}">
    
    <!-- 绑定 user.name,自动设置 name 和 value 属性 -->
    <input type="text" th:field="*{name}" placeholder="姓名">
    
    <!-- 绑定 user.age -->
    <input type="number" th:field="*{age}" placeholder="年龄">
    
    <button type="submit">提交</button>
</form>

控制器接收表单数据:

java

运行

@PostMapping("/user/save")
public String save(User user) { // 自动绑定表单数据到User对象
    // 保存逻辑...
    return "redirect:/user"; // 重定向到用户列表页
}

四、开发技巧

  1. 关闭缓存:开发时设置 spring.thymeleaf.cache=false,修改模板后无需重启应用。
  2. 自然模板:Thymeleaf 模板可直接在浏览器中打开(显示默认文本),便于前端调试。
  3. IDE 支持:IntelliJ IDEA 或 Eclipse 安装 Thymeleaf 插件,获得语法高亮和自动提示。
  4. 内置对象:Thymeleaf 提供常用内置对象,如:
    • #request:HttpServletRequest 对象
    • #session:HttpSession 对象
    • #dates:日期格式化工具(#dates.format(user.birthday, 'yyyy-MM-dd')
    • #strings:字符串工具(#strings.isEmpty(user.name)

总结

Thymeleaf 通过简洁的标签和表达式,实现了后端数据与前端视图的无缝整合,核心步骤为:

  1. 引入依赖并配置(简化版可省略配置);
  2. 控制器通过 Model 传递数据;
  3. 模板中使用 th:* 标签渲染数据,支持条件、循环、表单等功能;
  4. 利用片段复用减少重复代码。

⑥ 如何进行权限控制和安全控制。

一、核心概念

  • 认证(Authentication):验证用户身份(如用户名密码登录、OAuth2 登录)。
  • 授权(Authorization):控制用户能访问哪些资源(如接口、页面)。
  • 角色(Role):一组权限的集合(如ROLE_ADMINROLE_USER)。
  • 权限(Permission):具体操作权限(如user:readuser:write)。

二、整合 Spring Security 实现权限控制

1. 引入依赖

pom.xml中添加 Spring Security 依赖:

xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

<!-- 如需操作数据库存储用户/权限,添加JDBC依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId> <!-- 或mybatis -->
</dependency>
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>
2. 配置 Spring Security(核心)

创建配置类,继承WebSecurityConfigurerAdapter(Spring Security 5.7 + 推荐用组件式配置,这里以兼容方式示例):

java

运行

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) // 开启方法级权限控制
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    // 注入自定义用户服务(从数据库查询用户)
    @Autowired
    private UserDetailsService userDetailsService;

    // 密码加密器(Spring Security 5+强制要求密码加密)
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(); // 推荐BCrypt加密
    }

    // 配置认证管理器(用户身份验证逻辑)
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 使用自定义用户服务+密码加密器
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    // 配置HTTP请求授权规则
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable() // 开发环境可关闭CSRF保护(生产环境需开启)
            .authorizeRequests()
                // 放行静态资源和登录页
                .antMatchers("/login", "/css/**", "/js/**").permitAll()
                // 管理员角色才能访问/admin/**
                .antMatchers("/admin/**").hasRole("ADMIN")
                // 需要user:read权限才能访问/user/**
                .antMatchers("/user/**").hasAuthority("user:read")
                // 其他所有请求需要认证(登录后才能访问)
                .anyRequest().authenticated()
            .and()
            // 配置表单登录
            .formLogin()
                .loginPage("/login") // 自定义登录页路径
                .defaultSuccessUrl("/index") // 登录成功后跳转页
                .failureUrl("/login?error") // 登录失败后跳转页
                .permitAll() // 允许所有用户访问登录页
            .and()
            // 配置退出登录
            .logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("/login?logout") // 退出成功后跳转页
                .permitAll();
    }
}
3. 实现自定义用户服务(UserDetailsService)

从数据库查询用户信息(用户名、密码、角色、权限),并封装成UserDetails对象:

java

运行

@Service
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
    private UserRepository userRepository; // 假设用JPA操作数据库

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 1. 从数据库查询用户
        User user = userRepository.findByUsername(username)
                .orElseThrow(() -> new UsernameNotFoundException("用户不存在"));

        // 2. 转换用户角色和权限为Spring Security需要的格式
        // 角色需以"ROLE_"为前缀,权限直接使用字符串
        Collection<? extends GrantedAuthority> authorities = user.getRoles().stream()
                .map(role -> new SimpleGrantedAuthority("ROLE_" + role.getName())) // 角色
                .collect(Collectors.toList());
        // 额外添加权限(如从user.getPermissions()获取)
        user.getPermissions().forEach(perm -> 
            authorities.add(new SimpleGrantedAuthority(perm.getName()))
        );

        // 3. 返回UserDetails对象(包含用户名、加密后的密码、权限集合等)
        return new org.springframework.security.core.userdetails.User(
            user.getUsername(),
            user.getPassword(), // 数据库中存储的是加密后的密码
            user.isEnabled(), // 账号是否启用
            true, // 账号是否未过期
            true, // 凭证是否未过期
            true, // 账号是否未锁定
            authorities
        );
    }
}
4. 数据库设计(用户 - 角色 - 权限关联)

典型的多对多关系设计:

  • users:用户表(id, username, password, enabled)
  • roles:角色表(id, name, description)
  • permissions:权限表(id, name, description)
  • user_roles:用户 - 角色关联表(user_id, role_id)
  • role_permissions:角色 - 权限关联表(role_id, permission_id)

示例实体类(JPA):

java

运行

// User实体
@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String password; // 存储BCrypt加密后的密码
    private boolean enabled = true;

    // 多对多关联角色
    @ManyToMany(fetch = FetchType.EAGER) // 立即加载角色
    @JoinTable(
        name = "user_roles",
        joinColumns = @JoinColumn(name = "user_id"),
        inverseJoinColumns = @JoinColumn(name = "role_id")
    )
    private Set<Role> roles = new HashSet<>();

    // 多对多关联权限(或通过角色关联,二选一)
    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(
        name = "user_permissions",
        joinColumns = @JoinColumn(name = "user_id"),
        inverseJoinColumns = @JoinColumn(name = "permission_id")
    )
    private Set<Permission> permissions = new HashSet<>();
    // getter/setter
}

三、权限控制方式

1. URL 级别的权限控制(配置类中)

通过HttpSecurityantMatchers()指定 URL 的访问权限,如:

java

运行

.antMatchers("/admin/**").hasRole("ADMIN") // 角色控制
.antMatchers("/user/**").hasAuthority("user:read") // 权限控制
.antMatchers("/public/**").permitAll() // 无需认证
.anyRequest().authenticated() // 其他需认证
2. 方法级别的权限控制(注解)

在 Service 或 Controller 方法上使用注解,需开启@EnableGlobalMethodSecurity(prePostEnabled = true)

注解作用示例
@PreAuthorize方法执行前检查权限@PreAuthorize("hasRole('ADMIN')")
@PostAuthorize方法执行后检查权限(较少用)@PostAuthorize("returnObject.username == authentication.name")
@PreFilter过滤集合参数@PreFilter("filterObject.owner == authentication.name")
@PostFilter过滤返回的集合@PostFilter("filterObject.owner == authentication.name")

示例:

java

运行

@RestController
public class UserController {

    // 只有ADMIN角色能访问
    @PreAuthorize("hasRole('ADMIN')")
    @GetMapping("/admin/users")
    public List<User> getAllUsers() { ... }

    // 需要user:write权限,且只能操作自己的资源
    @PreAuthorize("hasAuthority('user:write') and #id == authentication.principal.id")
    @PutMapping("/user/{id}")
    public User updateUser(@PathVariable Long id, @RequestBody User user) { ... }
}
3. 页面元素级别的权限控制(Thymeleaf)

结合 Thymeleaf 的 Spring Security 方言,控制页面元素是否显示:

  1. 引入依赖(Thymeleaf 与 Security 整合):

xml

<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
  1. 在页面中使用:

html

预览

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<body>
    <!-- 显示当前登录用户信息 -->
    <div sec:authorize="isAuthenticated()">
        用户名:<span sec:authentication="name"></span>
        角色:<span sec:authentication="principal.authorities"></span>
    </div>

    <!-- 只有ADMIN角色可见 -->
    <a href="/admin/users" sec:authorize="hasRole('ADMIN')">用户管理</a>

    <!-- 有user:write权限可见 -->
    <button sec:authorize="hasAuthority('user:write')">编辑用户</button>

    <!-- 未登录时显示登录按钮 -->
    <a href="/login" sec:authorize="isAnonymous()">登录</a>

    <!-- 登录后显示退出按钮 -->
    <a href="/logout" sec:authorize="isAuthenticated()">退出</a>
</body>
</html>

四、安全增强功能

1. 密码加密

使用BCryptPasswordEncoder加密密码(不可逆),存储加密后的字符串:

java

运行

// 加密示例(通常在用户注册时调用)
@Service
public class UserService {
    @Autowired
    private PasswordEncoder passwordEncoder;

    public void createUser(String username, String rawPassword) {
        String encodedPassword = passwordEncoder.encode(rawPassword); // 加密
        // 保存到数据库(存储encodedPassword)
    }
}
2. 防止暴力破解(限制登录失败次数)

使用UserDetailsChecker或第三方库(如spring-security-login-lock)实现:

java

运行

@Bean
public AuthenticationFailureHandler failureHandler() {
    return new SimpleUrlAuthenticationFailureHandler("/login?error") {
        @Override
        public void onAuthenticationFailure(...) {
            // 记录失败次数,超过阈值锁定账号
            String username = exception.getAuthentication().getName();
            userService.incrementLoginFailureCount(username);
            super.onAuthenticationFailure(request, response, exception);
        }
    };
}
3. 集成 OAuth2/OpenID(第三方登录)

如需支持微信、GitHub 等第三方登录,引入 OAuth2 依赖:

xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>

配置第三方登录信息(application.yml):

yaml

spring:
  security:
    oauth2:
      client:
        registration:
          github:
            client-id: 你的GitHub客户端ID
            client-secret: 你的GitHub客户端密钥
            scope: read:user
4. CSRF 保护

生产环境需开启 CSRF 保护(默认开启),表单需携带 CSRF 令牌:

html

预览

<form th:action="@{/user/save}" method="post">
    <!-- 自动生成CSRF令牌 -->
    <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
    <!-- 其他表单字段 -->
</form>

五、总结

Spring Security 实现权限控制的核心步骤:

  1. 引入依赖并配置SecurityConfig,定义 URL 访问规则、登录 / 退出行为。
  2. 实现UserDetailsService,从数据库加载用户信息(用户名、密码、权限)。
  3. 通过URL 级别(配置类)或方法级别(注解)控制权限。
  4. 结合 Thymeleaf 实现页面元素的权限控制。
  5. 增强安全特性:密码加密、防暴力破解、CSRF 保护、第三方登录等。

⑦ 消息服务和任务管理。

一、消息服务(异步通信)

消息服务通过消息队列(如 RabbitMQ、Kafka、ActiveMQ)实现组件间的异步通信,解耦系统、削峰填谷。Spring Boot 通过Spring AMQP(RabbitMQ)、Spring Kafka等组件简化集成。

1. 整合 RabbitMQ(最常用)

RabbitMQ 是基于 AMQP 协议的消息队列,支持多种消息模式(简单队列、工作队列、扇形交换机、主题交换机等)。

步骤 1:安装 RabbitMQ
  • 本地安装:RabbitMQ 官网 下载,启动后访问 http://localhost:15672(默认账号密码 guest/guest)。
  • 云服务:使用阿里云、AWS 等提供的 RabbitMQ 服务。
步骤 2:引入依赖

xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
步骤 3:配置 RabbitMQ

application.yml中配置连接信息:

yaml

spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
    virtual-host: / # 虚拟主机(默认/)
步骤 4:定义交换机、队列和绑定关系

通过配置类声明消息路由规则:

java

运行

@Configuration
public class RabbitConfig {
    // 队列名
    public static final String DEMO_QUEUE = "demo.queue";
    // 交换机名
    public static final String DEMO_EXCHANGE = "demo.exchange";
    // 路由键
    public static final String DEMO_ROUTING_KEY = "demo.routing.key";

    // 声明队列
    @Bean
    public Queue demoQueue() {
        // durable:是否持久化;exclusive:是否独占;autoDelete:无消费者时是否自动删除
        return QueueBuilder.durable(DEMO_QUEUE).build();
    }

    // 声明交换机(主题交换机,支持通配符路由)
    @Bean
    public TopicExchange demoExchange() {
        return ExchangeBuilder.topicExchange(DEMO_EXCHANGE).durable(true).build();
    }

    // 绑定队列到交换机(指定路由键)
    @Bean
    public Binding binding(Queue demoQueue, TopicExchange demoExchange) {
        return BindingBuilder.bind(demoQueue).to(demoExchange).with(DEMO_ROUTING_KEY);
    }
}
步骤 5:发送消息(生产者)

使用RabbitTemplate发送消息:

java

运行

@Service
public class MessageProducer {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void sendMessage(String content) {
        // 发送字符串消息
        rabbitTemplate.convertAndSend(
            RabbitConfig.DEMO_EXCHANGE,
            RabbitConfig.DEMO_ROUTING_KEY,
            content
        );
        // 发送对象消息(需序列化,推荐用JSON)
        User user = new User(1L, "张三");
        rabbitTemplate.convertAndSend(
            RabbitConfig.DEMO_EXCHANGE,
            RabbitConfig.DEMO_ROUTING_KEY,
            user
        );
    }
}
步骤 6:接收消息(消费者)

使用@RabbitListener注解监听队列:

java

运行

@Service
public class MessageConsumer {
    // 监听指定队列
    @RabbitListener(queues = RabbitConfig.DEMO_QUEUE)
    public void receiveMessage(String content) {
        System.out.println("收到字符串消息:" + content);
    }

    // 监听对象消息(需配置JSON反序列化)
    @RabbitListener(queues = RabbitConfig.DEMO_QUEUE)
    public void receiveUser(User user) {
        System.out.println("收到用户消息:" + user.getName());
    }
}
JSON 序列化配置(可选)

默认使用 JDK 序列化,建议改为 JSON:

java

运行

@Configuration
public class RabbitJsonConfig {
    @Bean
    public MessageConverter messageConverter() {
        return new Jackson2JsonMessageConverter();
    }
}
2. 整合 Kafka(高吞吐场景)

Kafka 适合大数据量、高吞吐的消息场景,整合方式类似 RabbitMQ:

  • 引入依赖:spring-boot-starter-kafka
  • 配置:spring.kafka.bootstrap-servers=localhost:9092
  • 发送:KafkaTemplate.send(topic, message)
  • 接收:@KafkaListener(topics = "topic-name")

二、任务管理

Spring Boot 支持两种任务:异步任务(非阻塞执行)和定时任务(按时间规则执行)。

1. 异步任务(@Async)

通过@Async注解标记方法为异步执行,避免阻塞主线程。

步骤 1:开启异步支持

在启动类或配置类添加@EnableAsync

java

运行

@SpringBootApplication
@EnableAsync // 开启异步任务
public class DemoApplication { ... }
步骤 2:定义异步方法

在 Service 中用@Async标记方法:

java

运行

@Service
public class AsyncService {
    // 异步执行此方法
    @Async
    public CompletableFuture<String> doAsyncTask() {
        try {
            Thread.sleep(3000); // 模拟耗时操作
        } catch (InterruptedException e) { ... }
        return CompletableFuture.completedFuture("异步任务完成");
    }
}
步骤 3:调用异步方法

java

运行

@Controller
public class TaskController {
    @Autowired
    private AsyncService asyncService;

    @GetMapping("/async")
    public String testAsync() throws ExecutionException, InterruptedException {
        // 调用异步方法(立即返回,不阻塞)
        CompletableFuture<String> future = asyncService.doAsyncTask();
        // 等待结果(可选)
        String result = future.get();
        System.out.println(result);
        return "index";
    }
}
自定义线程池(可选)

默认使用 SimpleAsyncTaskExecutor,建议自定义线程池优化性能:

java

运行

@Configuration
public class AsyncConfig {
    @Bean(name = "asyncExecutor")
    public Executor asyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5); // 核心线程数
        executor.setMaxPoolSize(10); // 最大线程数
        executor.setQueueCapacity(25); // 队列容量
        executor.setThreadNamePrefix("Async-"); // 线程名前缀
        executor.initialize();
        return executor;
    }
}

指定线程池:@Async("asyncExecutor")

2. 定时任务(@Scheduled)

按时间规则自动执行任务,如定时备份数据、发送提醒。

步骤 1:开启定时任务支持

在启动类添加@EnableScheduling

java

运行

@SpringBootApplication
@EnableScheduling // 开启定时任务
public class DemoApplication { ... }
步骤 2:定义定时任务

@Scheduled标记方法,指定执行规则:

java

运行

@Service
public class ScheduledService {
    //  fixedRate:固定间隔(毫秒),从上一次开始执行时间计算
    @Scheduled(fixedRate = 5000)
    public void task1() {
        System.out.println("每5秒执行一次(fixedRate):" + new Date());
    }

    //  fixedDelay:固定延迟(毫秒),从上一次执行完成时间计算
    @Scheduled(fixedDelay = 3000)
    public void task2() {
        System.out.println("每3秒执行一次(fixedDelay):" + new Date());
    }

    //  cron表达式:更灵活的时间规则(秒 分 时 日 月 周)
    @Scheduled(cron = "0 0 12 * * ?") // 每天12点执行
    public void task3() {
        System.out.println("每天12点执行:" + new Date());
    }
}
Cron 表达式详解

格式:秒 分 时 日 月 周 [年](年可选)常用示例:

  • 0 0 8 * * ?:每天 8 点执行
  • 0 0/30 9-17 * * ?:9 点到 17 点,每 30 分钟执行
  • 0 0 12 ? * SAT:每周六 12 点执行
  • 0 0 1 1 * ?:每月 1 日 1 点执行
定时任务线程池配置(可选)

默认单线程执行所有定时任务,任务间可能阻塞,建议配置线程池:

yaml

spring:
  task:
    scheduling:
      pool:
        size: 5 # 定时任务线程池大小
      thread-name-prefix: Scheduled- # 线程名前缀

三、总结

组件用途核心技术
消息服务系统解耦、异步通信、削峰填谷RabbitMQ(@RabbitListener)、Kafka
异步任务非阻塞执行耗时操作@Async + 线程池
定时任务按时间规则自动执行任务@Scheduled + Cron 表达式

⑧ 完整的项目开发流程等。

一、项目启动阶段

1. 需求分析与规划
  • 目标:明确项目核心功能、业务场景、用户群体及非功能需求(性能、安全性、可扩展性等)。
  • 输出物
    • 需求文档(PRD,Product Requirement Document):详细描述功能点、交互逻辑、业务规则(如用户注册流程、订单状态流转)。
    • 原型设计:用 Axure、墨刀等工具绘制页面原型,明确 UI/UX 交互。
    • 技术可行性分析:评估现有技术栈能否满足需求(如高并发场景需考虑缓存、分布式架构)。
2. 技术选型与架构设计
  • 技术栈确定
    • 后端:Spring Boot 版本(如 3.2.x)、JDK 版本(如 JDK17)、数据库(MySQL/PostgreSQL)、持久层框架(MyBatis-Plus/JPA)、缓存(Redis)、消息队列(RabbitMQ)等。
    • 前端:Vue/React/Angular、UI 组件库(Element UI/Ant Design)、构建工具(Webpack/Vite)。
    • 部署:Docker、Kubernetes、CI/CD 工具(Jenkins/GitHub Actions)。
  • 架构设计
    • 整体架构:单体架构(中小项目)或微服务架构(大型项目,需考虑服务注册发现、网关等)。
    • 模块划分:按业务领域拆分(如用户模块、订单模块、支付模块),明确模块间依赖关系。
    • 数据库设计:ER 图设计、表结构定义(字段类型、索引、外键),遵循三范式(避免冗余)。
  • 输出物:架构设计文档、数据库设计文档(DDL)、技术栈清单。

二、开发阶段

1. 项目初始化与环境搭建
  • 版本控制:创建 Git 仓库(GitHub/GitLab),分支策略约定(如main主分支、develop开发分支、feature/*功能分支)。
  • 项目骨架搭建
    • 用 Spring Initializr 生成基础项目,引入核心依赖(Web、数据库、安全框架等)。
    • 统一项目结构(按模块划分包路径):

      plaintext

      com.example.project
      ├─ config/        # 配置类(数据库、安全、缓存等)
      ├─ controller/    # 接口层(接收请求、返回响应)
      ├─ service/       # 业务逻辑层(接口+实现)
      │  ├─ impl/
      ├─ mapper/        # 数据访问层(MyBatis接口或JPA Repository)
      ├─ entity/        # 实体类(数据库映射、DTO/VO)
      ├─ common/        # 公共组件(工具类、常量、异常处理)
      ├─ exception/     # 自定义异常
      └─ ProjectApplication.java  # 启动类
      
  • 开发规范制定
    • 代码规范:遵循阿里巴巴 Java 开发手册(命名规则、注释要求、异常处理)。
    • 接口规范:RESTful API 设计(URL 命名、HTTP 方法、状态码、响应格式统一)。

      json

      // 统一响应格式示例
      {
        "code": 200,       // 状态码(200成功、400参数错误、500服务器异常)
        "message": "成功", // 提示信息
        "data": { ... }    // 业务数据
      }
      
    • 数据库规范:表名 / 字段名小写 + 下划线,主键自增策略,通用字段(create_timeupdate_time)。
2. 功能开发(迭代式)
  • 分工开发:按模块分配任务,开发者基于feature分支开发具体功能。
  • 核心开发流程
    1. 接口设计:先定义 Controller 接口(如/api/v1/users/{id}),明确入参(DTO)和出参(VO)。
    2. 业务实现:Service 层编写业务逻辑,调用 Mapper 层操作数据库,处理事务(@Transactional)。
    3. 数据访问:通过 MyBatis-Plus/JPA 实现 CRUD,复杂 SQL 用 XML 或注解编写。
    4. 公共组件开发
      • 全局异常处理(@ControllerAdvice):统一捕获并处理异常,返回标准响应。
      • 拦截器 / 过滤器:处理登录验证、日志记录、接口限流等。
      • 工具类:日期、加密、JSON 转换等通用功能。
  • 代码提交:遵循 Conventional Commits 规范(如feat: 新增用户注册功能fix: 修复订单查询bug),提交前自查代码规范。
3. 单元测试与集成测试
  • 单元测试:用 JUnit 5 + Mockito 测试 Service 层方法,覆盖核心业务逻辑(如订单创建、权限校验)。

    java

    运行

    @SpringBootTest
    public class UserServiceTest {
        @MockBean
        private UserMapper userMapper;
        @Autowired
        private UserService userService;
    
        @Test
        public void testGetUserById() {
            // 模拟Mapper返回
            User mockUser = new User(1L, "test");
            when(userMapper.selectById(1L)).thenReturn(mockUser);
            // 测试Service方法
            User user = userService.getById(1L);
            assertEquals("test", user.getName());
        }
    }
    
  • 集成测试:用@SpringBootTest + TestRestTemplate测试 Controller 接口,验证 HTTP 请求响应是否符合预期。
  • 测试覆盖率:通过 JaCoCo 等工具监控测试覆盖率,核心模块建议≥80%。

三、测试阶段

1. 功能测试
  • 测试人员根据 PRD 执行黑盒测试,验证功能是否符合需求(如用户登录、下单流程)。
  • 输出测试用例和 Bug 清单,开发者修复后回归测试。
2. 非功能测试
  • 性能测试:用 JMeter 测试接口响应时间、并发量(如 1000 用户同时下单),优化瓶颈(如慢查询、未命中缓存)。
  • 安全测试:检查 SQL 注入、XSS 攻击、权限漏洞(如越权访问他人订单),通过 Spring Security 加固。
  • 兼容性测试:前端页面在不同浏览器、设备上的展示效果。
3. 回归测试与验收
  • 修复 Bug 后,全面回归测试确保功能正常,无新问题引入。
  • 邀请产品或客户进行验收测试(UAT),确认满足业务需求。

四、部署与上线阶段

1. 环境准备
  • 区分环境:开发环境(dev)、测试环境(test)、预生产环境(staging)、生产环境(prod)。
  • 配置管理:用application-{profile}.yml区分不同环境的配置(数据库地址、Redis 端口等),敏感信息(密码)通过配置中心(Nacos/Apollo)或环境变量注入。
2. 构建与打包
  • 用 Maven/Gradle 打包:mvn clean package -DskipTests,生成 Jar/War 包。
  • 容器化:编写 Dockerfile,构建镜像并推送到镜像仓库(Harbor/Docker Hub)。

    dockerfile

    FROM openjdk:17-jdk-slim
    COPY target/project-0.0.1-SNAPSHOT.jar /app.jar
    ENTRYPOINT ["java", "-jar", "/app.jar", "--spring.profiles.active=prod"]
    
3. 部署上线
  • 单机部署:直接运行 Jar 包(java -jar app.jar)或通过 Docker 启动容器。
  • 集群部署:用 Kubernetes 编排容器,实现自动扩缩容、滚动更新。
  • CI/CD 自动化:通过 Jenkins 配置流水线,实现代码提交→自动构建→测试→部署全流程自动化。
4. 监控与运维
  • 监控:集成 Spring Boot Actuator 暴露监控端点,结合 Prometheus + Grafana 监控系统指标(CPU、内存、接口 QPS)。
  • 日志:用 Logback/Log4j2 记录日志,通过 ELK(Elasticsearch+Logstash+Kibana)收集分析日志,快速定位问题。
  • 告警:配置关键指标告警(如接口错误率过高、服务器负载超标),通过邮件 / 钉钉通知运维人员。

五、项目维护阶段

  • Bug 修复:线上出现问题时,紧急修复并发布补丁版本(hotfix)。
  • 功能迭代:根据用户反馈和业务需求,规划新功能迭代,重复开发→测试→部署流程。
  • 系统优化:定期 review 代码,优化性能(如 SQL 索引优化、缓存策略调整),重构冗余模块。
  • 文档更新:同步更新 API 文档(用 Swagger)、部署文档、运维手册,确保团队信息一致。

总结

完整的项目开发流程是需求驱动、迭代推进、测试保障、运维兜底的闭环:

  1. 前期通过需求分析和架构设计明确方向;
  2. 开发阶段遵循规范,注重代码质量和测试覆盖;
  3. 上线前通过多轮测试验证功能和性能;
  4. 上线后通过监控和运维确保系统稳定运行,并持续迭代优化。

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值