SpringBoot 技能实战:异常处理、单元测试、多环境配置、日志

一、前言

在 SpringBoot 开发过程中,异常处理、单元测试、多环境配置和日志管理是保障项目稳定性、可维护性的核心技能。本文将从实战角度出发,详细讲解这四大核心模块的实现方式,帮助开发者快速掌握并应用到实际项目中。

二、SpringBoot 异常处理

SpringBoot 默认提供了异常处理机制,当程序出现异常时,会向/error路径发送请求,由BasicErrorController处理并跳转至默认异常页面。我们可以通过自定义错误页面、全局异常处理器等方式实现更灵活的异常处理。

2.1 整合 AJAX 全局异常处理(重点)

对于 AJAX 请求,通常需要返回 JSON 格式的异常信息,可通过@ControllerAdvice@ExceptionHandler实现。前后端分离

java

java 复制代码
package com.hg.exception;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashMap;
import java.util.Map;

@ControllerAdvice
public class GlobalExceptionResolver {
    //ajax全局异常处理  前后端分离【重点】   适合次数少的
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Map ExceptionResolver(){
        HashMap<String, Object> map = new HashMap<>();
        map.put("status",500);
        map.put("msg","操作失败!");
        return map;
    }
    //  自定义Result返回值,适合调用次数多的
//    @ExceptionHandler(Exception.class)
//    @ResponseBody
//    public Result ExceptionResolver(){
//        Result result = new Result();
//        result.setStatus(500);
//        result.setMsg("出错了!");
//        return result;
//    }
}

//class Result{
//    private Integer status;
//    private String msg;
//
//    public Integer getStatus() {
//        return status;
//    }
//
//    public void setStatus(Integer status) {
//        this.status = status;
//    }
//
//    public String getMsg() {
//        return msg;
//    }
//
//    public void setMsg(String msg) {
//        this.msg = msg;
//    }
//
//    public Result() {
//    }
//
//    public Result(Integer status, String msg) {
//        this.status = status;
//        this.msg = msg;
//    }
//}

模拟controller层错误:

java 复制代码
package com.hg.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashMap;
import java.util.Map;

@Controller
public class ExceptionController {

    @RequestMapping("/exception")
    @ResponseBody
    public Map showInfo2(){
        HashMap<String, Object> map = new HashMap<>();
        map.put("status",200);
        map.put("msg","ks开播了!");
        int a = 10/0;
        return map;
    }
}

2.2 整合非 AJAX 全局异常处理器(了解)

通过实现HandlerExceptionResolver接口,可针对不同异常类型跳转不同错误页面。非前后端分离

2.2.1 全局异常处理器实现
复制代码
/**
 * 通过实现HandlerExceptionResolver接口做全局异常处理
 */
@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");
		}else if(ex instanceof NullPointerException){
			mv.setViewName("error2");
		}
		mv.addObject("error", ex.toString());
		
		return mv;
	}
}
2.2.2 对应错误页面

error1.html(处理算术异常):

html

复制代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>错误提示页面-ArithmeticException</title>
</head>
<body>
	出错了,请与管理员联系。。。
	<span th:text="${error}"></span>
</body>
</html>

error2.html(处理空指针异常):

html

复制代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>错误提示页面-NullPointerException</title>
</head>
<body>
	出错了,请与管理员联系。。。
	<span th:text="${error}"></span>
</body>
</html>

三、SpringBoot 整合 Junit

SpringBoot 提供了专门的 Junit 启动器,简化了单元测试的配置流程。

3.1 引入 Junit 启动器依赖

xml

复制代码
<!--junit启动器 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>

3.2 编写业务代码

3.2.1 DAO 层

java

复制代码
@Repository
public class UserDaoImpl {
	public void saveUser(){
		System.out.println("insert into users.....");
	}
}
3.2.2 Service 层
复制代码
@Service
public class UserServiceImpl {
	@Autowired
	private UserDaoImpl userDaoImpl;
	
	public void addUser(){
		this.userDaoImpl.saveUser();
	}
}
3.2.3 启动类

java

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

3.3 编写单元测试

运行

java 复制代码
import com.hg.junitApp;
import com.hg.service.UserServiceImpl;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.junit4.SpringRunner;

/*
    1、main方法启动spring
        new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
    2、spring整合junit
        @RunWith(SpringJUnit4ClassRunner.class)
        @Contextconfiguartion("classpath:applicationContext.xml")
    3、spring boot 整合junit
      ①
        @RunWith(SpringJUnit4ClassRunner.class)
        @SpringBootTest(classes={junitApp.class})
      ②
        @RunWith(SpringRunner.class)
        @SpringBootTest(classes={junitApp.class})
      ③
        @RunWith(SpringRunner.class)
        @SpringBootTest
      ④
        @SpringBootTest
 */

@RunWith(SpringRunner.class)
@SpringBootTest(classes={junitApp.class})
public class UserServiceTest {

    @Autowired
    private UserServiceImpl userServiceImpl;

    @Test
    public void testAddUser(){
        this.userServiceImpl.addUser();
    }
}

四、SpringBoot 多环境配置

在实际开发中,项目需要适配开发、测试、生产等不同环境,SpringBoot 支持通过多配置文件或单 YML 多文档块实现环境切换。

4.1 多配置文件方式

4.1.1 配置文件命名规范
  • 开发环境:application-dev.yml(端口 8090)
  • 测试环境:application-test.yml(端口 8091)
  • 生产环境:application-prod.yml(端口 8092)
4.1.2 激活指定环境

application.yml中配置:

复制代码
#激活指定的配置文件
spring.profiles.active=dev

4.2 单 YML 多文档块方式(了解)

YML 支持多文档块分隔(---),可在单个文件中定义所有环境配置:

yml

复制代码
spring:
  profiles:
    active: prod #激活prod环境
---
#开发环境
spring:
  profiles: dev #环境名称
server:
  port: 8090 #端口号
---
#测试环境
spring:
  profiles: test #环境名称
server:
  port: 8091 #端口号
---
#生产环境
spring:
  profiles: prod #环境名称
server:
  port: 8092 #端口号

4.3 多 YML 文档方式(推荐)

application-dev.yml

java 复制代码
spring:
  profiles: dev #环境名称
server:
  port: 8090 #端口号

以此类推...

五、SpringBoot 日志(logback)

logback 是 log4j 的改良版本,性能更优、功能更丰富,是 SpringBoot 默认的日志框架。

5.1 logback 核心优势

  • 性能提升:内核重写,内存占用更小,执行速度更快;
  • 动态配置:支持自动重新加载配置文件;
  • 环境适配:通过<if><else><then>标签适配不同环境,无需多配置文件;
  • 异步压缩:RollingFileAppender 可异步压缩日志文件,不影响主线程。

5.2 logback.xml 配置示例

xml

复制代码
<?xml version="1.0" encoding="UTF-8" ?>
 <configuration>
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->  
    <property name="LOG_HOME" value="${catalina.base:-.}/logs/" />  
    <!-- 控制台输出 -->   
    <appender name="Stdout" class="ch.qos.logback.core.ConsoleAppender">
       <!-- 日志输出编码 -->  
        <layout class="ch.qos.logback.classic.PatternLayout">   
             <!--
				      日志输出格式:
			            %d表示日期时间,
			            %thread表示线程名,
			            %-5level:级别从左显示5个字符宽度
			            %logger{50} 表示class的全名最长50个字符,否则按照句点分割
			            %msg:日志消息
			            %n是换行符
			--> 
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n   
            </pattern>   
        </layout>   
    </appender>   
    <!-- 按照每天生成日志文件 -->   
    <appender name="RollingFile"  class="ch.qos.logback.core.rolling.RollingFileAppender">   
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}/server.%d{yyyy-MM-dd}.log</FileNamePattern>   
            <MaxHistory>30</MaxHistory>
        </rollingPolicy>   
        <layout class="ch.qos.logback.classic.PatternLayout">  
           <!--
				      日志输出格式:
			            %d表示日期时间,
			            %thread表示线程名,
			            %-5level:级别从左显示5个字符宽度
			            %logger{50} 表示class的全名最长50个字符,否则按照句点分割
			            %msg:日志消息
			            %n是换行符
			--> 
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n   
            </pattern>   
       </layout> 
        <!--日志文件最大的大小-->
       <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
         <MaxFileSize>10MB</MaxFileSize>
       </triggeringPolicy>
    </appender>     

    <!-- 日志输出级别 -->
    <root level="DEBUG">   
        <appender-ref ref="Stdout" />   
        <appender-ref ref="RollingFile" />   
    </root> 

<!--日志异步到数据库 -->  
<!--     <appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
        日志异步到数据库 
        <connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">
           连接池 
           <dataSource class="com.mchange.v2.c3p0.ComboPooledDataSource">
              <driverClass>com.mysql.jdbc.Driver</driverClass>
              <url>jdbc:mysql://127.0.0.1:3306/databaseName</url>
              <user>root</user>
              <password>root</password>
            </dataSource>
        </connectionSource>
  </appender> -->

</configuration>

六、总结

本文详细讲解了 SpringBoot 中异常处理(自定义页面、全局处理器)、Junit 单元测试、多环境配置(多文件 / 单 YML)、logback 日志配置四大核心技能。这些技能是 SpringBoot 开发的基础,掌握后能有效提升项目的健壮性和可维护性。在实际项目中,可根据业务需求灵活调整配置,比如异常处理器可扩展更多异常类型、日志可配置异步写入数据库等。

相关推荐
代码探秘者2 小时前
【算法篇】6.分治
java·数据结构·后端·python·算法·排序算法
biubiubiu07062 小时前
Spring Boot 中如何自定义一个 Starter
java·spring boot·后端
xiaohe072 小时前
SpringBoot教程(三十二) SpringBoot集成Skywalking链路跟踪
spring boot·后端·skywalking
zdl6862 小时前
SpringBoot返回文件让前端下载的几种方式
前端·spring boot·后端
拾贰_C2 小时前
【Vue | vue3 | spring boot】前端前台项目搭建
前端·vue.js·spring boot
回到原点的码农2 小时前
Spring Boot实时推送技术详解:三个经典案例
spring boot·后端·状态模式
mldlds2 小时前
Spring Boot 集成 Kettle
java·spring boot·后端
zopple10 小时前
常见的 Spring 项目目录结构
java·后端·spring