在今天的学习中,我们深入研究了全局异常处理,以提升系统的稳定性和用户体验。通过建立全局异常处理器,我们能够捕获和处理应用程序中产生的各种异常,并向前端返回更加友好的错误信息。接下来,我们将详细介绍一些常用的全局异常处理注解,同时提供相应的示例代码,帮助您更好地理解和应用这些异常处理机制。

创新互联专业为企业提供依安网站建设、依安做网站、依安网站设计、依安网站制作等企业网站建设、网页设计与制作、依安企业网站模板建站服务,10余年依安做网站经验,不只是建网站,更提供有价值的思路和整体网络服务。
在 Spring Boot 中,通过使用 @ControllerAdvice 注解结合不同的注解,我们可以实现全局异常的处理。以下是一些常用的全局异常注解的详细介绍及示例代码:
@ControllerAdvice
public class GlobalExceptionHandler {
    // ...
}@ExceptionHandler(Exception.class)
public ResponseEntity handleException(Exception e) {
    return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
            .body("An unexpected error occurred: " + e.getMessage());
} @ExceptionHandler(CustomException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ResponseEntity handleCustomException(CustomException e) {
    return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Custom exception: " + e.getMessage());
} @RestControllerAdvice
public class RestExceptionHandler {
    // ...
}@PostMapping("/create")
public ResponseEntity createUser(@Validated @RequestBody User user) {
    // 处理用户创建逻辑
    return ResponseEntity.ok("用户创建成功");
} 以上是一些常用的全局异常处理注解及参数校验注解的详细介绍及示例代码。通过合理使用这些注解,可以使全局异常处理更加灵活和规范。
让我们开始全局异常处理的探索之旅吧,共同深入研究如何提升系统的稳定性和用户体验。通过建立全局异常处理器,我们将能够捕获并处理应用程序中产生的各种异常,并向前端返回更加友好的错误信息。
首先,进入项目根目录:
cd springboot60days创建 Day 8 子模块:
mkdir day8-global-exception
cd day8-global-exception在 Day 7 子模块的基础上,创建 Day 8 子模块。在父模块的 pom.xml 中添加 Day 8 子模块的配置:
    day4-database-magic 
    day5-mybatis-mystery 
    day6-mybatis-plus-journey 
    day7-data-validation 
    day8-global-exception 
 
    4.0.0 
    
          com.icoderoad.springboot60days 
          springboot60days 
          1.0-SNAPSHOT 
       
  day8-global-exception 
  1.0-SNAPSHOT 
  
      
      
          org.projectlombok 
          lombok 
          true 
       
      
      
          org.springframework.boot 
          spring-boot-starter-web 
       
      
      
          org.springframework.boot 
          spring-boot-starter 
       
      
      
          com.baomidou 
          mybatis-plus-boot-starter 
          3.5.4.1 
       
       
      
          org.springframework.boot 
          spring-boot-starter-validation 
       
    
      
      
          com.h2database 
          h2 
          runtime 
       
   
  
      
          
              org.springframework.boot 
              spring-boot-maven-plugin 
           
       
   
 在 src/main/resources 目录下创建 application.properties :
# springboot60days/day8-global-exception/src/main/resources/application.properties
# Spring Boot 应用程序名称
spring.application.name=day8-global-exception
# 数据库配置
spring.datasource.url=jdbc:h2:mem:userdb;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;MODE=MYSQL
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.h2.console.enabled=true
# MyBatis-Plus 配置
mybatis-plus.mapper-locations=classpath:mapper/*.xml
# 分页插件配置
mybatis-plus.configuration.plugins=com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor
mybatis-plus.configuration.plugins.pagination.type=com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor// springboot60days/day8-global-exception/src/main/java/com/icoderoad/springboot60days/day8/exception/GlobalExceptionHandler.java
package com.icoderoad.springboot60days.day8.exception;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import java.util.List;
import java.util.stream.Collectors;
@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ResponseEntity handleException(Exception e) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body("An unexpected error occurred: " + e.getMessage());
    }
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResponseEntity handleValidationException(MethodArgumentNotValidException e) {
        List fieldErrors = e.getBindingResult().getFieldErrors();
        String errorMessage = fieldErrors.stream()
                .map(fieldError -> fieldError.getField() + ": " + fieldError.getDefaultMessage())
                .collect(Collectors.joining(", "));
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorMessage);
    }
    @ExceptionHandler(BindException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResponseEntity handleBindingException(BindException e) {
        List fieldErrors = e.getBindingResult().getFieldErrors();
        String errorMessage = fieldErrors.stream()
                .map(fieldError -> fieldError.getField() + ": " + fieldError.getDefaultMessage())
                .collect(Collectors.joining(", "));
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorMessage);
    }
}     创建一个具有年龄和邮箱属性的用户实体类 User,并在该属性上添加 Validation 注解,进行最大值、最小值和邮箱格式的验证。
// springboot60days/day8-global-exception/src/main/java/com/icoderoad/springboot60days/day8/entity/User.java
package com.icoderoad.springboot60days.day8.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
@Data
@TableName(value = "my_user")
public class User {
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    
    @NotBlank(message = "用户名不能为空")
    private String username;
    @Max(value = 60, message = "年龄不能大于60岁")
    @Min(value = 18, message = "年龄不能小于18岁")
    private Integer age;
    @Email(message = "邮箱格式不正确")
    private String email;
}// springboot60days/day8-global-exception/src/main/java/com/icoderoad/springboot60days/day8/mapper/UserMapper.java
package com.icoderoad.springboot60days.day8.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.icoderoad.springboot60days.day8.entity.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper extends BaseMapper {
} 创建一个 MyBatis-Plus Service 接口 UserService 和其实现类 UserServiceImpl,用于处理与数据库的交互。
UserService.java
// springboot60days/day8-global-exception/src/main/java/com/icoderoad/springboot60days/day8/service/UserService.java
package com.icoderoad.springboot60days.day8.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.icoderoad.springboot60days.day8.entity.User;
public interface UserService extends IService {
    // 可以添加自定义业务方法...
} UserServiceImpl.java
// springboot60days/day8-global-exception/src/main/java/com/icoderoad/springboot60days/day8/service/impl/UserServiceImpl.java
package com.icoderoad.springboot60days.day8.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.icoderoad.springboot60days.day8.entity.User;
import com.icoderoad.springboot60days.day8.mapper.UserMapper;
import com.icoderoad.springboot60days.day8.service.UserService;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl extends ServiceImpl implements UserService {
    // 可以添加自定义业务方法...
} 更新 UserController 类,调用 MyBatis-Plus Service 接口处理用户的 CRUD 操作。
// springboot60days/day8-global-exception/src/main/java/com/icoderoad/springboot60days/day8/controller/UserController.java
package com.icoderoad.springboot60days.day8.controller;
import com.icoderoad.springboot60days.day8.entity.User;
import com.icoderoad.springboot60days.day8.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import jakarta.validation.Valid;
import java.util.List;
@RestController
@RequestMapping("/users")
@Validated
public class UserController {
    private final UserService userService;
    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }
    @GetMapping
    public ResponseEntity> getAllUsers() {
        List users = userService.list();
        return new ResponseEntity<>(users, HttpStatus.OK);
    }
    @PostMapping
    public String createUser(@Valid @RequestBody User user) {
        userService.save(user);
        return "用户创建成功!";
    }
    @GetMapping("/{id}")
    public User getUserById(@PathVariable Long id) {
        return userService.getById(id);
    }
    @PutMapping("/{id}")
    public String updateUser(@PathVariable Long id, @Valid @RequestBody User user) {
        user.setId(id);
        userService.updateById(user);
        return "用户更新成功!";
    }
    @DeleteMapping("/{id}")
    public String deleteUser(@PathVariable Long id) {
        userService.removeById(id);
        return "用户删除成功!";
    }
} 
// springboot60days/day8-global-exception/src/main/java/com/icoderoad/springboot60days/day8/init/DatabaseInitializer.java
package com.icoderoad.springboot60days.day8.init;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import org.springframework.jdbc.core.JdbcTemplate;
@Component
public class DatabaseInitializer implements CommandLineRunner {
    private final JdbcTemplate jdbcTemplate;
    public DatabaseInitializer(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
    @Override
    public void run(String... args) throws Exception {
        // 初始化数据库表
        jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS my_user (" +
                "id INT AUTO_INCREMENT PRIMARY KEY," +
                "username VARCHAR(255)," +
                "email VARCHAR(255)," +
                "age INT" +
                ")");
    }
}// springboot60days/day8-global-exception/src/main/java/com/icoderoad/springboot60days/day8/config/MyBatisPlusConfig.java
package com.icoderoad.springboot60days.day8.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan({"com.icoderoad.springboot60days.day8.mapper"})
public class MyBatisPlusConfig {
    /**
     * 分页插件,自动识别数据库类型
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}// springboot60days/day8-global-exception/src/main/java/com/icoderoad/springboot60days/day8/Day8GlobalExceptionApplication.java
package com.icoderoad.springboot60days.day8;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Day8GlobalExceptionApplication {
    public static void main(String[] args) {
        SpringApplication.run(Day8GlobalExceptionApplication.class, args);
    }
}Mapper 文件 UserMapper.xml
  
      
           
           
           
           
          
       
   在 day8-global-exception 子模块的根目录下,执行以下命令启动 Spring Boot 应用程序:
mvn spring-boot:run在 Apifox 或 Postman 中,你可以使用以下命令测试 RESTful API 的增、删、改、查操作:
获取所有用户信息(GET请求)
创建用户(POST请求)
{
  "username": "icoderoad",
  "age": 25,
  "email": "icoderoad@cdxwcx.com"
}更新用户信息(PUT请求)
{
  "username": "newUsername",
  "age": 26,
  "email": "newEmail@cdxwcx.com"
}删除用户(DELETE请求)
测试异常处理 - 数据校验失败(POST请求)
{
  "username": "icoderoad",
  "age": 15,  // 年龄小于最小值
  "email": "icoderoad@cdxwcx.com"
}测试异常处理 - 数据校验失败(PUT请求)
{
  "username": "newUsername",
  "age": 8,  // 年龄小于最小值
  "email": "newEmail@cdxwcx.com"
}测试异常处理 - 数据校验失败(GET请求,ID为负数)
以上测试用例覆盖了正常的 CRUD 操作以及异常处理情况,确保全局异常处理器能够返回友好的错误信息。
通过今天的学习,我们成功踏上了全局异常处理的探索之旅,为提升系统的稳定性和用户体验打下了坚实的基础。通过建立全局异常处理器,我们能够更加灵活地捕获和处理应用程序中各种异常,从而提供更友好、更有针对性的错误信息。在这一过程中,我们深入了解了一系列常用的全局异常处理注解,并通过详细的示例代码展示了它们的应用方式,为今后更加自信地应对异常情况奠定了基础。
Copyright © 2009-2022 www.wtcwzsj.com 青羊区广皓图文设计工作室(个体工商户) 版权所有 蜀ICP备19037934号