目录

SpringBoot3实战从0快速搭建SpringBoot3工程全局异常处理器自定义封装结果类自定义异常2025详细教程1

目录

SpringBoot3实战(从0快速搭建SpringBoot3工程、全局异常处理器、自定义封装结果类、自定义异常)(2025详细教程)(1)


一、博客引言。

(1)SpringBoot3实战学习篇开篇介绍。
  • 《SpringBoot3实战学习篇》是博主是为了结合前段时间的Vue3实战学习完成 从0到1独立开发并快速搭建SpringBoot3+Vue3的实战项目 (管理系统)。

(2)Vue3实战学习篇回顾介绍。
  • 关于《Vue3实战学习篇》的所有详细教程( Vue3环境搭建 、 Vue3基础脚手架搭建 、 Vue3基础语法 、 Vue3集成Element-Plus 、 Vue3集成Vue-Router 、Vue3快速搭建管理系统)都在博主专栏 《Vue实战学习篇》 下。

二、从0快速搭建SpringBoot3工程。(详细步骤)

(1)项目层次结构说明。

https://i-blog.csdnimg.cn/direct/bf9b8511108e41f59fad06df497041f4.png

(2)SpringBoot3新工程正式搭建。
<1>新建项目(new project)。

https://i-blog.csdnimg.cn/direct/a17c6b2c906740e9be0b63a0bd87a7eb.png


<2>最新且稳定版(JDK21)下载、安装、配置系统环境。
  • 因为 SpringBoot3工程环境JDK版本最低JDK17+。IDEA版本最好2024+。
  • 官网地址:

https://i-blog.csdnimg.cn/direct/7dff4b6b200540f287a100f8b31d6197.png


  • 配置系统环境变量。

https://i-blog.csdnimg.cn/direct/0780599db9f543b78f8f05d494b9b8fc.png


https://i-blog.csdnimg.cn/direct/6000aa5a86b24cf281698cd75c9f864d.png


  • cmd命令行检测。
java -version

https://i-blog.csdnimg.cn/direct/ca2dc82e44af46809162ca4c08b9e227.png


<3>SpringBoot新工程的构建选择项。

https://i-blog.csdnimg.cn/direct/d4710dd78d0e4e159bb07c7c8c95d4b4.png


<4>SpringBoot新工程构建版本、依赖项选择。
  • SpringBoot版本对于新手——版本选择越低越好。(怕出错)

https://i-blog.csdnimg.cn/direct/9a86d62cd50f40128b72cc9b525b92fc.png


  • 依赖SpringWeb——接收前端数据、访问外部接口。

https://i-blog.csdnimg.cn/direct/6668b9f9b1154535919664f378b5d1c8.png


  • 依赖MySQL-Driver——MySQL数据库驱动。
  • 依赖持久层框架(MyBatis)——数据库的增删改查。

https://i-blog.csdnimg.cn/direct/f577756edd61449284ad8725bba6cbc8.png


<5>“精简"新工程无用的目录、文件。

https://i-blog.csdnimg.cn/direct/362d428a530d4d088dff9539c265e050.png


https://i-blog.csdnimg.cn/direct/3a97abe7ed43481ba2feff133fb9acdd.png


  • 继续修剪工程无用目录或文件。

https://i-blog.csdnimg.cn/direct/26c716955efe42189da2bc4869eac5a7.png


  • application.properties文件的修改。

https://i-blog.csdnimg.cn/direct/4be45f59bb984b2cb0f6bb0abde4b950.png


https://i-blog.csdnimg.cn/direct/019f8f115a9147e3840c864bafb04cd0.png


<6>“精简"pom.xml文件。
  • 删除 于本项目学习—— 无用标签。

https://i-blog.csdnimg.cn/direct/c6fd4f7211844e06bea433a65607ea41.png


  • 删去对于本项目学习——无用依赖项。

https://i-blog.csdnimg.cn/direct/0fb0b9ce7f2d42bf980c5d37017cb108.png


<7>设置项目编码。

https://i-blog.csdnimg.cn/direct/11b5f3d561fa4c2c83983a19df698e5d.png


<8>配置Maven。
  • 详细关于Maven的下载、安装、环境配置博客链接。

https://i-blog.csdnimg.cn/direct/cf49cc83c1df4e2d923d14643993ebe8.png


<9>pom文件添加为Maven项目。

https://i-blog.csdnimg.cn/direct/4f7915ca31694d14ab32a604a3d3059e.png


  • 解析完成后。依赖项也存在。但依旧"满江红”。重新打开项目即可。

https://i-blog.csdnimg.cn/direct/c4f17aa4fcfa4866bba224a2920fb279.png


  • 完成Maven依赖项的解析、下载和安装。

https://i-blog.csdnimg.cn/direct/e1859a68010f464ab3cbd035a99046ca.png

(3)启动并运行SpringBoot3工程。
<1>SpringBootApplication。(SpringBoot3工程启动类)
  • 右击启动运行对应的main()方法即可。

https://i-blog.csdnimg.cn/direct/bd80b5aad4624c7fbc93583994bb5cef.png


<2>java: 错误: 不支持发行版本 21!(解决)

https://i-blog.csdnimg.cn/direct/2b9a5912a9d14f27bf4f81163a3c9db9.png


  • 项目结构。

https://i-blog.csdnimg.cn/direct/f109b20950ab47d89ffa8fa0d1dc5a81.png


  • 启动类编辑配置。

https://i-blog.csdnimg.cn/direct/26841f783ca64da29735e0879801090f.png


https://i-blog.csdnimg.cn/direct/42ad6447a9d443f09ee006c3cccd0a66.png


<3>启动成功。但报错未配置DataSource!

https://i-blog.csdnimg.cn/direct/6b7d0473cd294e2f88193699d6a5bf80.png


<4>application.yml中配置数据库信息。
# 数据库配置(驱动)
spring:
  datasource:
    #连接到MySQL数据库所需的JDBC驱动(新的)
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: root123
    url: jdbc:mysql://localhost:3306/xm-pro?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2b8&allowPublicKeyRetrieval=true

<5> application.yml中修改默认端口号。
  • 默认端口号:8080。

https://i-blog.csdnimg.cn/direct/99c5071b380f4a97a6e85525d8deb8b3.png


#修改Spring Boot应用启动后监听的端口号为9090。
server:
  port: 9090

# 数据库配置(驱动)
spring:
  datasource:
    #连接到MySQL数据库所需的JDBC驱动(新的)
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: root123
    url: jdbc:mysql://localhost:3306/xm-pro?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2b8&allowPublicKeyRetrieval=true

  • 重新启动SpringBoot工程。

https://i-blog.csdnimg.cn/direct/9e3df4fcc4104c92908d80662647ae09.png

(4)新建测试接口。(验证SpringBoot程序)
<1>新建controller包。

https://i-blog.csdnimg.cn/direct/83dc404198314996bbbd7d8a54427ce4.png


<2>WebController类。(注解@RestController)
  • @RestController 是Spring框架里的一个注解。它把一个类标记成RESTful Web服务的控制器。这个注解 是

    @Controller和ResponseBody

    的组合 ,意味着控制器里所有方法的返回值都会被直接序列化为HTTP响应体。

package com.hyl.controller;

import org.springframework.web.bind.annotation.RestController;

//表示对外提供可访问接口的类
@RestController
public class WebController {
    
}

<3>WebController类的hello()方法。(注解@GetMapping)
  • @GetMapping("/hello”)表明:WebController类的hello()方法会 处理HTTP的GET请求 ,并且请求路径为"/hello"。
package com.hyl.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

//表示对外提供可访问接口的类
@RestController
public class WebController {
    @GetMapping("/hello")
    public String hello(){
        return "{'SpringBoot3':'Hello SpringBoot3!'}";
    }

}

<4>重新启动工程并测试接口。
  • 访问地址:localhost:9090/hello。

https://i-blog.csdnimg.cn/direct/2cde5f254fb54fd1a419643c2f3307f8.png


  • 404访问资源未找到原因与解决方法。
  • 在Spring Boot中,默认情况下带有@SpringBootApplication注解的主启动类会自动扫描其所在包及其子包下的组件。(如注解:@Controller、@Service、@Repository @ 等带有特定注解的类)

  • 仔细观察本案例项目中,主启动类SpringBootApplication位于com.hyl.springboot包下,而WebController类位于com.hyl.controller包下,com.hyl.controlle并非com.hyl.springboot的子包。
  • 所以可能会导致WebController类没有被正确扫描到并注册到Spring 容器中,进而使得访问相关路径时出现 404 错误。

https://i-blog.csdnimg.cn/direct/2b65c6af5b6949d9ac2ba8781fe8031f.png


  • 移动SpringBootApplication启动类。
  • 将SpringBootApplication启动类移动到com.hyl包下即可。
  • 删去原来的springboot包。

https://i-blog.csdnimg.cn/direct/0aa4748274ef45b5b2a9d265b8cbd568.png


https://i-blog.csdnimg.cn/direct/8521ed7e18ca4efda4d05447c1a8f347.png


  • 重新启动工程再次访问localhost:9090/hello。

https://i-blog.csdnimg.cn/direct/d4dd76e0d9b9494b85574d3356f77a13.png


<5>接口中返回Integer类型的方法。
package com.hyl.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

//表示对外提供可访问接口的类
@RestController
public class WebController {
    @GetMapping("/hello")
    public String hello(){
        return "{'SpringBoot3':'Hello SpringBoot3!'}";
    }

    @GetMapping("/count")
    public Integer count(){
        return 666;
    }

}
  • 访问地址栏: localhost:9090/count。

https://i-blog.csdnimg.cn/direct/361a15b40d6140708c073f48bafbd521.png


<6>接口中返回Map<String,Object>类型的方法。
@GetMapping("/map")
    public Map<String,Object> map(){
        Map<String,Object> map = new HashMap();
        map.put("username","岁岁岁平安");
        map.put("age",18);
        return map;
    }
  • 访问地址栏: localhost:9090/map。

https://i-blog.csdnimg.cn/direct/c69d87461a894221887179278ae48a11.png

(5)封装访问接口的结果类。(状态码code、请求信息msg、返回数据data)
<1>新建统一封装结果类。(Result类)
  • 请求状态码: code 。( 200:请求成功。500:系统错误。400:业务错误 )
  • 请求是否成功信息。 msg 。(如果请求成功,返回正确信息。请求失败,返回错误信息!)
  • 返回数据。 data 。(如果请求的方法有返回结果数据,就封装到data变量中并返回前端)

https://i-blog.csdnimg.cn/direct/2d038aa839814b4f8400a92fad2fe92e.png


<2>提供对应的getter、setter方法。
 //getter、setter方法
    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

<3>配置成功(success)静态方法。(成功、有无数据返回)
  • 请求成功且无数据返回。
//请求成功且无数据返回
    public static Result success(){
        Result result = new Result();
        result.setCode("200");
        result.setMsg("请求成功");
        return result;
    }

  • 请求成功且有数据返回。
//请求成功且有数据返回。
    public static Result success(Object data){
        //直接调用静态方法设置状态码、请求成功信息
        Result result = Result.success();
        result.setData(data);
        return result;
    }

  • 修改接口中的方法。使用封装类Result封装结果集。
  • 修改返回Integer类型的 count() 方法。
@GetMapping("/count")
    public Result count(){
        return Result.success(666);
    }

https://i-blog.csdnimg.cn/direct/9442a8c36c784be286b1004f880f5473.png


  • 修改返回String类型的 hello() 方法。
@GetMapping("/hello")
    public Result hello(){
        return Result.success("hello");
    }

https://i-blog.csdnimg.cn/direct/222671efc60643e7a167fb864c97c384.png


  • 再次修改返回Map<String,Object>类型的 map() 方法。
@GetMapping("/map")
    public Result map(){
        Map<String,Object> map = new HashMap();
        map.put("username","岁岁岁平安");
        map.put("age",18);
        return Result.success(map);
    }

https://i-blog.csdnimg.cn/direct/d5f8865aa78044599d7c25afc4990d65.png


<4>配置失败(error)静态方法。(失败、异常信息返回)
  • 如果请求的方法出现了异常(错误)。返回错误信息。
  • 请求失败且无数据返回。
//请求失败且无数据返回
    public static Result error(){
        Result result = new Result();
        result.setCode("500");
        result.setMsg("系统出错了!");
        return result;
    }

  • 全局异常处理器代码。(处理所有系统出现的异常!)
  • 新建包:exception。新建类GlobalExceptionHandler。

https://i-blog.csdnimg.cn/direct/4cce0e9f6e2d48beadd1a624b06b9d9b.png


package com.hyl.exception;

import com.hyl.common.Result;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

//标识全局异常处理器并设置捕获路径
//因为异常产生最终都会归宿到controller中,所有异常统一在controller包中接口中处理。
@ControllerAdvice("com.hyl.controller")
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class) //捕获所有系统异常
    @ResponseBody//返回json串
    public Result error(Exception e) {
        //更清晰看到后端控制台报的错误
        e.printStackTrace();
        //返回Result的error()方法设置的错误信息(code、msg)给前端
        return Result.error();
    }
}

  • 测试count()方法的算术异常。
@GetMapping("/count")
    public Result count(){
        int i = 1 / 0;
        return Result.success(666);
    }
  • 访问localhost:9090/count。出现异常。并成功向前端返回对应的错误信息!

https://i-blog.csdnimg.cn/direct/d58a176d90f14f5cae5735361a664cbd.png


  • 总分证明了全局异常处理器已经生效且成功捕获到系统产生的异常!

https://i-blog.csdnimg.cn/direct/4f0d30a009d144aaa19ca8be336659bc.png


  • 手动限制访问路径。(使用自定义异常)
  • 修改count()方法。在方法中手动抛出Runtime Exception。此时就不是系统错误或者代码的逻辑错误。(不是程序的bug)。是后台自己定义的逻辑。当访问该路径,被禁止访问。

https://i-blog.csdnimg.cn/direct/ab9a52920e704a6d8c05980567524bb6.png


https://i-blog.csdnimg.cn/direct/8d7a8fa2f7c24077afdfb053d840263f.png


  • 这时就需要手动的自定义异常。向用户、前端告知不是系统异常而是业务错误。
  • 对应的接口文档设置状态码:系统错误:500。业务错误:400。
  • 自定义异常类代码。
package com.hyl.exception;

public class CustomerException extends Exception{
    private String code;
    private String msg;

    public CustomerException(String msg, String code) {
        this.msg = msg;
        this.code = code;
    }

    //getter|setter方法
    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

  • 全局异常处理器类中——>配置自定义异常类。
package com.hyl.exception;

import com.hyl.common.Result;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

//标识全局异常处理器并设置捕获路径
//因为异常产生最终都会归宿到controller中,所有异常统一在controller包中接口中处理。
@ControllerAdvice("com.hyl.controller")
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class) //捕获所有系统异常
    @ResponseBody//返回json串
    public Result error(Exception e) {
        //更清晰看到后端控制台报的错误
        e.printStackTrace();
        //返回Result的error()方法设置的错误信息(code、msg)给前端
        return Result.error();
    }

    @ExceptionHandler(CustomerException.class) //捕获自定义异常
    @ResponseBody//返回json串
    public Result error(CustomerException e) {  //自定义异常的参数code、msg
        //更清晰看到后端控制台报的错误
        e.printStackTrace();
        //Result的error(String code,String Msg)方法设置获取到的错误信息(code、msg)
        return Result.error(e.getCode(),e.getMsg());
    }

}

  • 请求失败且无参数返回。(有参数)
//请求失败且无数据返回。适配自定义异常(传递code、msg)
    public static Result error(String code,String msg){
        Result result = new Result();
        result.setCode(code);
        result.setMsg(msg);
        return result;
    }

  • 再次重新测试count()方法。count()抛出自定义异常。
@GetMapping("/count")
    public Result count() throws CustomerException {
        throw new CustomerException("400","错误!禁止访问该路径");
    }
  • 全局异常处理器中成功捕获自定义异常。并向前端返回400状态码、错误信息。

https://i-blog.csdnimg.cn/direct/5c28971343544c3cb3018e47ead442bd.png


https://i-blog.csdnimg.cn/direct/77285b7f213e40579e1eebd40021de49.png


<5>最终的自定义封装结果类(Result)。
package com.hyl.common;

/**
 * 统一后端返回的数据结果类型
 */
public class Result {
    //请求状态码
    private String code;
    //成功或错误信息
    private String msg;
    //返回数据结果
    private Object data;

    //常用静态方法

    //请求成功且无数据返回
    public static Result success(){
        Result result = new Result();
        result.setCode("200");
        result.setMsg("请求成功");
        return result;
    }

    //请求成功且有数据返回。
    public static Result success(Object data) {
        //直接调用静态方法设置状态码、请求成功信息
        Result result = Result.success();
        result.setData(data);
        return result;
    }

    //请求失败且无数据返回
    public static Result error(){
        Result result = new Result();
        result.setCode("500");
        result.setMsg("系统出错了!");
        return result;
    }

    //请求失败且无数据返回。适配自定义异常(传递code、msg)
    public static Result error(String code,String msg){
        Result result = new Result();
        result.setCode(code);
        result.setMsg(msg);
        return result;
    }

    //getter、setter方法
    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }
}