SpringBoot 进阶实战:异常处理、单元测试、多环境、日志配置全解析

在上一篇 SpringBoot 入门教程中,我们掌握了项目搭建、HelloWorld 开发和项目发布的基础操作,本次将聚焦 SpringBoot 实际开发中的四大核心工程能力:异常统一处理、整合 Junit 单元测试、多环境配置切换、Logback 日志配置,这些都是企业开发中必备的技能,也是 SpringBoot 项目规范化开发的关键,本文将通过实战代码 + 详细解析的方式,让你快速上手并落地使用!

一、SpringBoot 异常统一处理

在项目开发中,异常处理如果散落在各个业务代码中,会导致代码冗余、维护困难。SpringBoot 提供了多种优雅的异常处理方式,可适配传统页面跳转前后端分离 AJAX 请求两种场景。

1.1 基础方式:自定义统一错误页面

SpringBoot 内置了异常处理机制,程序抛出未捕获异常时,会自动向/error发送请求,由BasicErrorController处理并跳转到默认错误页。我们只需在指定目录创建固定名称的错误页,即可替换默认页面。

实现步骤
  1. src/main/resources/templates目录下创建error.html名称不可修改);
  2. 页面中可通过 Thymeleaf 表达式${error}获取异常信息;
核心代码

Controller(模拟抛出异常)

java 复制代码
@Controller
public class DemoController {
    // 抛出空指针异常
    @RequestMapping("/show")
    public String showInfo(){
        String str = null;
        str.length();
        return "index";
    }
    // 抛出算术异常
    @RequestMapping("/show2")
    public String showInfo2(){
        int a = 10/0;
        return "index";
    }
}

错误页面 error.html

html 复制代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>系统错误</title>
</head>
<body>
    系统出错啦,请联系管理员处理!<br>
    异常信息:<span th:text="${error}"></span>
</body>
</html>

1.2 传统项目:按异常类型自定义错误页(实现 HandlerExceptionResolver)

针对传统非 AJAX 项目,可实现HandlerExceptionResolver接口创建全局异常处理器,根据不同的异常类型,跳转到对应的专属错误页,实现异常的精细化处理。

实现步骤
  1. 创建异常处理器类,添加@Component注解交给 Spring 容器管理,实现HandlerExceptionResolver接口;
  2. 重写resolveException方法,判断异常类型,指定跳转的视图名,并传递异常信息;
  3. 为不同异常类型创建对应的错误页(如error1.htmlerror2.html)。
核心代码

全局异常处理器

java 复制代码
@Component
public class GlobalExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest request, 
                                         HttpServletResponse response, 
                                         Object handler, Exception ex) {
        ModelAndView mv = new ModelAndView();
        // 按异常类型跳转不同页面
        if(ex instanceof ArithmeticException){
            mv.setViewName("error1"); // 算术异常跳error1.html
        }else if(ex instanceof NullPointerException){
            mv.setViewName("error2"); // 空指针异常跳error2.html
        }
        mv.addObject("error", ex.toString()); // 传递异常信息
        return mv;
    }
}

1.3 前后端分离:AJAX 请求全局异常处理(@ControllerAdvice+@ExceptionHandler)

前后端分离项目中,前端通过 AJAX 请求接口,异常处理不能跳转页面,需返回JSON 格式的异常信息 。使用@ControllerAdvice+@ExceptionHandler组合是最优方案,可全局捕获异常并返回自定义 JSON 数据。

核心注解说明
  • @ControllerAdvice:全局控制器增强,作用于所有 Controller;
  • @ExceptionHandler:指定捕获的异常类型,可写多个方法捕获不同异常;
  • @ResponseBody:将返回的 Map 自动转为 JSON 格式。
核心代码
java 复制代码
@ControllerAdvice
public class AjaxGlobalExceptionHandler {
    // 捕获所有Exception类型异常
    @ResponseBody
    @ExceptionHandler(value = Exception.class)
    public Map<String, Object> errorHandler(Exception exception) {
        Map<String, Object> map = new HashMap<>();
        map.put("status", 500); // 自定义状态码
        map.put("msg", exception.getMessage()); // 异常详情
        map.put("success", false); // 前端判断标识
        return map;
    }
}

前端处理 :可根据返回的statussuccess字段,统一弹出错误提示,无需每个接口单独处理异常。

二、SpringBoot 整合 Junit4 单元测试

单元测试是验证业务代码正确性的关键,SpringBoot 提供了专门的 Junit 启动器,可快速整合 Spring 环境,无需手动加载容器,直接注入 Bean 进行测试,极大简化测试代码。

2.1 第一步:引入 Junit 启动器依赖

SpringBoot 的spring-boot-starter-test已整合 Junit4、SpringTest 等相关依赖,直接引入即可:

XML 复制代码
<!-- SpringBoot整合Junit启动器 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope> <!-- 仅测试环境生效 -->
</dependency>

2.2 第二步:编写待测试的业务代码

以用户新增业务为例,编写简单的 DAO 和 Service 层代码(模拟数据库操作):

DAO 层

java 复制代码
@Repository
public class UserDaoImpl {
    // 模拟用户入库
    public void saveUser(){
        System.out.println("=====用户数据插入成功=====");
    }
}

Service 层

java 复制代码
@Service
public class UserServiceImpl {
    @Autowired
    private UserDaoImpl userDaoImpl;
    // 业务方法:调用DAO层
    public void addUser(){
        this.userDaoImpl.saveUser();
    }
}

SpringBoot 启动类

java 复制代码
@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

2.3 第三步:编写单元测试代码

测试类需放在src/test/java目录下,通过两个核心注解整合 Spring 环境,直接注入 Service/DAO 层 Bean 进行测试。

核心注解说明
  • @RunWith(SpringJUnit4ClassRunner.class):让 Junit 运行在 Spring 环境中,加载 Spring 容器;
  • @SpringBootTest(classes={App.class}):指定 SpringBoot 的启动类,确定容器加载的配置范围。
测试代码
java 复制代码
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes={App.class})
public class UserServiceTest {
    // 自动注入待测试的Service Bean
    @Autowired
    private UserServiceImpl userServiceImpl;
    // 测试方法,添加@Test注解
    @Test
    public void testAddUser(){
        userServiceImpl.addUser(); // 调用业务方法
    }
}

运行结果 :控制台打印=====用户数据插入成功=====,说明测试通过,业务代码正常执行。

三、SpringBoot 多环境配置(开发 / 测试 / 生产)

实际开发中,开发、测试、生产环境 的配置(如端口、数据库地址、redis 地址)往往不同,如果手动修改配置文件,容易出错且效率低。SpringBoot 提供了优雅的多环境配置方案,支持多文件配置单文件多文档块配置,一键切换环境。

3.1 核心规则

配置文件命名遵循固定语法:application-{profile}.yml/properties,其中profile环境标识(如 dev:开发、test:测试、prod:生产)。

3.2 方式 1:多文件配置(推荐,结构清晰)

为每个环境创建独立的配置文件,主配置文件中指定激活的环境。

步骤 1:创建多环境配置文件
  • application-dev.yml:开发环境,端口 8090
java 复制代码
server:
  port: 8090

application-test.yml:测试环境,端口 8091

java 复制代码
server:
  port: 8091

application-prod.yml:生产环境,端口 8092

java 复制代码
server:
  port: 8092
步骤 2:主配置文件激活指定环境

application.yml(主配置文件,全局生效)中通过spring.profiles.active指定要激活的环境,只需修改该值即可一键切换

java 复制代码
# 激活开发环境,可改为test/prod切换
spring:
  profiles:
    active: dev

3.3 方式 2:单文件多文档块配置(适合简单配置)

如果配置内容较少,可将所有环境的配置写在同一个 application.yml 中,通过---分割不同环境的配置块,spring.profiles指定环境名称。

java 复制代码
# 全局配置:激活生产环境
spring:
  profiles:
    active: prod
---
# 开发环境:profiles指定环境名dev
spring:
  profiles: dev
server:
  port: 8090
---
# 测试环境:profiles指定环境名test
spring:
  profiles: test
server:
  port: 8091
---
# 生产环境:profiles指定环境名prod
spring:
  profiles: prod
server:
  port: 8092

注意---是 YAML 格式的文档分隔符,必须单独一行,不可省略。

四、SpringBoot 日志配置(Logback)

日志是项目排错、运行监控的重要工具,SpringBoot默认集成 Logback (Log4j 的改良版本,性能更高、配置更灵活),无需额外引入依赖,只需编写logback.xml配置文件,即可实现控制台输出文件滚动存储日志级别控制等功能。

4.1 Logback 核心优势

相比传统的 Log4j,Logback 有以下显著优势:

  1. 性能提升:内核重写,运行速度更快,内存占用更小;
  2. 动态配置:配置文件修改后,自动重新加载,无需重启项目;
  3. 多环境适配:通过<if>/<else>标签,一个配置文件适配所有环境;
  4. 异步压缩:日志文件自动按时间 / 大小分割,压缩过程异步执行,不影响主程序;
  5. 原生支持:SpringBoot 默认内置,无需额外引入依赖。

4.2 经典 Logback.xml 配置(可直接复用)

配置文件需放在src/main/resources目录下,SpringBoot 会自动加载。以下是企业开发中最常用的配置,包含控制台输出按天滚动的文件输出,并限制日志文件大小和保存天数。

XML 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
    <!-- 定义日志存储根路径,不存在则自动创建 -->
    <property name="LOG_HOME" value="./logs" />
    <!-- 1. 控制台输出配置:Stdout -->
    <appender name="Stdout" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <!-- 日志输出格式:时间 线程 级别 类名 日志信息 换行 -->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 控制台编码 -->
        </layout>
    </appender>

    <!-- 2. 文件滚动输出配置:RollingFile -->
    <appender name="RollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 日志滚动策略:按天分割,保留30天 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>${LOG_HOME}/server.%d{yyyy-MM-dd}.log</FileNamePattern>
            <MaxHistory>30</MaxHistory> <!-- 日志保存30天 -->
        </rollingPolicy>
        <!-- 单文件大小限制:超过10MB自动分割 -->
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <MaxFileSize>10MB</MaxFileSize>
        </triggeringPolicy>
        <!-- 日志输出格式 -->
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset>
        </layout>
    </appender>

    <!-- 全局日志级别:DEBUG(开发)/INFO(测试/生产),级别从低到高:TRACE<DEBUG<INFO<WARN<ERROR -->
    <root level="INFO">
        <!-- 关联控制台和文件输出appender -->
        <appender-ref ref="Stdout" />
        <appender-ref ref="RollingFile" />
    </root>
</configuration>

4.3 日志级别说明

日志级别用于控制日志的输出粒度,开发环境一般用DEBUG(打印详细调试信息),测试 / 生产环境用INFO(仅打印关键运行信息),级别越高,输出的日志越少:

  • TRACE:最细粒度,几乎不用;
  • DEBUG:调试信息,开发排错用;
  • INFO:常规运行信息,如项目启动、接口调用;
  • WARN:警告信息,如配置缺失、资源不足;
  • ERROR:错误信息,如程序异常、接口调用失败。

4.4 代码中使用日志

在类中注入Logger对象,即可打印不同级别的日志,替代传统的System.out.println

java 复制代码
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl {
    // 创建Logger对象,指定当前类
    private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);
    
    public void addUser(){
        logger.debug("=====开始执行用户新增业务=====");
        logger.info("=====用户新增业务执行成功=====");
        // logger.error("=====用户新增业务执行失败=====");
    }
}

五、总结

本次教程全面讲解了 SpringBoot 开发中的四大核心工程能力,核心要点总结如下:

  1. 异常处理 :页面项目用HandlerExceptionResolver,前后端分离用@ControllerAdvice+@ExceptionHandler,拒绝零散 try-catch;
  2. 单元测试 :引入spring-boot-starter-test,通过@RunWith+@SpringBootTest整合 Spring 环境,直接注入 Bean 测试;
  3. 多环境配置 :遵循application-{profile}.yml命名规则,主配置文件通过spring.profiles.active一键切换环境;
  4. Logback 日志 :SpringBoot 默认集成,编写logback.xml实现控制台 + 文件输出,按时间 / 大小分割,合理设置日志级别。

这些技能是 SpringBoot 项目从「入门」到「实战」的关键,也是企业开发中规范化、工程化的基础。掌握后可大幅提升开发效率,让项目更易维护、更稳定。

相关推荐
polaris06302 小时前
Spring Boot 集成 MyBatis 全面讲解
spring boot·后端·mybatis
tumeng07112 小时前
Spring Boot与MyBatis
spring boot·后端·mybatis
码视野3 小时前
#Cursor加Specs编程,3小时上线一个有管理后台和移动端的检举举报全流程平台(完全开源)
spring boot·小程序·ai编程
yiyaozjk3 小时前
springcloud springboot nacos版本对应
spring boot·spring·spring cloud
鬼蛟3 小时前
Spring Boot整合全局异常处理器、junit、多环境、logback
java·spring boot·后端
小江的记录本3 小时前
【Logback】Logback 日志框架 与 SLF4J绑定、三层模块、MDC链路追踪、异步日志、滚动策略
java·spring boot·后端·spring·log4j·maven·logback
随风,奔跑3 小时前
Spring Boot笔记
java·spring boot·笔记·后端
难忘经典3 小时前
springboot中配置logback-spring.xml
spring boot·spring·logback
huabiangaozhi3 小时前
SpringBoot + vue 管理系统
vue.js·spring boot·后端