Spring Boot教程之二十四:Spring Boot 中的异常处理

Spring Boot 中的异常处理

Spring Boot 中的异常处理有助于处理 API 中存在的错误和异常,从而提供强大的企业应用程序。本文介绍了处理异常的各种方法以及如何在 Spring Boot 项目中向客户端返回有意义的错误响应。

以下是 Spring Boot 中异常处理的一些主要方法:

  • Spring Boot 的默认异常处理
  • 使用 @ExceptionHandler 注解
  • 用于 @ControllerAdvice 全局异常处理

让我们进行初始设置,以更深入地探索每种方法。

初始设置

要使用 Spring Initializer 创建一个简单的 Spring Boot 项目,请参阅本文。现在让我们开发一个 Spring Boot Restful Web 服务,对客户实体执行 CRUD 操作。我们将使用 MYSQL 数据库来存储所有必要的数据。

步骤 1:创建 JPA 实体类 Customer

Java

// Creating a JPA Entity class Customer with three fields: id, name, and address.
package com.customer.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Customer {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String address;
}

Customer 类用@Entity注释进行注释,并为字段定义 getter、setter 和构造函数。

步骤 2:创建 CustomerRepository 界面

Java

// Creating a repository interface extending JpaRepository
package com.customer.repository;

import com.customer.model.Customer;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface CustomerRepository extends JpaRepository<Customer, Long> {
}

CustomerRepository 接口用@Repository注释,并扩展了Spring Data JPA的 JpaRepository 。

步骤 3:创建自定义异常

CustomerAlreadyExistsException:当用户尝试添加数据库中已存在的客户时,可能会引发此异常。

Java

// Creating a custom exception that can be thrown when a user tries to add a customer that already exists
package com.customer.exception;

public class CustomerAlreadyExistsException extends RuntimeException {
    private String message;

    public CustomerAlreadyExistsException() {}

    public CustomerAlreadyExistsException(String msg) {
        super(msg);
        this.message = msg;
    }
}

NoSuchCustomerExistsException:当用户尝试删除或更新数据库中不存在的客户记录时,可能会引发此异常。

NoSuchCustomerExistsException 

Java

// Creating a custom exception that can be thrown when a user tries to update/delete a customer that doesn't exist
package com.customer.exception;

public class NoSuchCustomerExistsException extends RuntimeException {
    private String message;

    public NoSuchCustomerExistsException() {}

    public NoSuchCustomerExistsException(String msg) {
        super(msg);
        this.message = msg;
    }
}

注意:两个自定义异常类都扩展了RuntimeException。

步骤 4:创建服务层

CustomerService 接口定义了三种不同的方法:

  • Customer getCustomer(Long id):通过 id 获取客户记录。如果找不到具有指定 id 的客户记录,此方法将抛出 NoSuchElementException 异常。
  • String addCustomer(Customer customer):将新客户的详细信息添加到数据库。当用户尝试添加已存在的客户时,此方法将引发 CustomerAlreadyExistsException 异常。
  • String updateCustomer(Customer customer):更新已存在客户的详细信息。当用户尝试更新数据库中不存在的客户的详细信息时,此方法将引发 NoSuchCustomerExistsException 异常。

接口和服务实现类如下:

CustomerService 接口

Java

// Creating service interface
package com.customer.service;
import com.customer.model.Customer;

public interface CustomerService {

    // Method to get customer by its Id
    Customer getCustomer(Long id);

    // Method to add a new Customer
    // into the database
    String addCustomer(Customer customer);

    // Method to update details of a Customer
    String updateCustomer(Customer customer);
}

CustomerServiceImpl 实现

Java

// Implementing the service class
package com.customer.service;

// Importing required packages
import com.customer.exception.CustomerAlreadyExistsException;
import com.customer.exception.NoSuchCustomerExistsException;
import com.customer.model.Customer;
import com.customer.repository.CustomerRepository;
import java.util.NoSuchElementException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class CustomerServiceImpl
    implements CustomerService {

    @Autowired
    private CustomerRepository customerRespository;

    // Method to get customer by Id.Throws
    // NoSuchElementException for invalid Id
    public Customer getCustomer(Long id)
    {
        return customerRespository.findById(id).orElseThrow(
            ()
                -> new NoSuchElementException(
                    "NO CUSTOMER PRESENT WITH ID = " + id));
    }

    // Method to add new customer details to database.Throws
    // CustomerAlreadyExistsException when customer detail
    // already exist
    public String addCustomer(Customer customer)
    {
        Customer existingCustomer
            = customerRespository.findById(customer.getId())
                  .orElse(null);
        if (existingCustomer == null) {
            customerRespository.save(customer);
            return "Customer added successfully";
        }
        else
            throw new CustomerAlreadyExistsException(
                "Customer already exists!!");
    }

    // Method to update customer details to database.Throws
    // NoSuchCustomerExistsException when customer doesn't
    // already exist in database
    public String updateCustomer(Customer customer)
    {
        Customer existingCustomer
            = customerRespository.findById(customer.getId())
                  .orElse(null);
        if (existingCustomer == null)
            throw new NoSuchCustomerExistsException(
                "No Such Customer exists!!");
        else {
            existingCustomer.setName(customer.getName());
            existingCustomer.setAddress(
                customer.getAddress());
            customerRespository.save(existingCustomer);
            return "Record updated Successfully";
        }
    }
}

步骤 5:创建 CustomerController

Java

// Creating Rest Controller CustomerController which
// defines various API's.
package com.customer.controller;

// Importing required packages
import com.customer.exception.CustomerAlreadyExistsException;
import com.customer.exception.ErrorResponse;
import com.customer.model.Customer;
import com.customer.service.CustomerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class CustomerController {

    @Autowired private CustomerService customerService;

    // Get Customer by Id
    @GetMapping("/getCustomer/{id}")
    public Customer getCustomer(@PathVariable("id") Long id)
    {
        return customerService.getCustomer(id);
    }

    // Add new Customer
    @PostMapping("/addCustomer")
    public String
    addcustomer(@RequestBody Customer customer)
    {
        return customerService.addCustomer(customer);
    }

    // Update Customer details
    @PutMapping("/updateCustomer")
    public String
    updateCustomer(@RequestBody Customer customer)
    {
        return customerService.updateCustomer(customer);
    }
}

处理异常

现在让我们了解一下处理该项目中抛出的异常的各种方法。

Spring Boot 的默认异常处理:

CustomerController定义的 getCustomer() 方法用于获取具有给定 Id 的客户。当它找不到具有给定 id 的客户记录时,它会抛出NoSuchElementException 。在运行 Spring Boot 应用程序并使用无效客户 ID 访问/ getCustomer API 时,我们会得到一个完全由 Spring Boot 处理的NoSuchElementException,如下所示:

Spring Boot 向用户提供系统错误响应,其中包含时间戳、HTTP 状态代码、错误、消息和路径等信息。

使用 @ExceptionHandler 注解
  • Spring Boot 提供的@ExceptionHandler注解可以用来处理特定的Handler 类或Handler 方法中的异常。
  • 任何以此注释的方法都会被 Spring 配置自动识别为异常处理程序方法。
  • 异常处理程序方法处理在参数中传递的所有异常及其子类。
  • 它还可以配置为向用户返回特定的错误响应。

因此,让我们创建一个自定义的ErrorResponse类,以便以清晰简洁的方式向用户传达异常,如下所示:

Java

// Custom Error Response Class
package com.customer.exception;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ErrorResponse {

    private int statusCode;
    private String message;

    public ErrorResponse(String message)
    {
        super();
        this.message = message;
    }
}

当用户尝试添加数据库中已存在的客户时,CustomerController定义的 addCustomer() 方法将抛出CustomerAlreadyExistsException ,否则它会保存客户详细信息。

为了处理这个异常,我们在CustomerController中定义一个处理方法handleCustomerAlreadyExistsException()。所以现在当addCustomer()抛出一个CustomerAlreadyExistsException时,处理方法被调用,并向用户返回一个正确的ErrorResponse 。

Java

// Exception Handler method added in CustomerController to handle CustomerAlreadyExistsException
@ExceptionHandler(value = CustomerAlreadyExistsException.class)
@ResponseStatus(HttpStatus.CONFLICT)
public ErrorResponse handleCustomerAlreadyExistsException(CustomerAlreadyExistsException ex) {
    return new ErrorResponse(HttpStatus.CONFLICT.value(), ex.getMessage());
}

注意:Spring Boot 允许使用@ResponseStatus注释方法来返回所需的 Http 状态代码。

在运行 Spring Boot 应用程序并使用现有客户点击/addCustomer API 时, CustomerAlreadyExistsException将由处理程序方法完全处理,如下所示:

用于 @ControllerAdvice 全局异常处理

在以前的方法中,注释的方法只能处理该特定类抛出的异常。但是,如果我们想处理整个应用程序抛出的任何异常,我们可以定义一个全局异常处理程序类并用 注释它。此注释有助于将多个异常处理程序集成到单个全局单元中。 @ExceptionHandler @ControllerAdvice

如果用户尝试更新数据库中尚不存在的客户详细信息,则中定义的方法将抛出 。要处理此异常,请定义一个用 注释的类。 updateCustomer() CustomerController NoSuchCustomerExistsException GlobalExceptionHandler @ControllerAdvice

Java

// Class to handle exceptions globally
package com.customer.exception;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(value = NoSuchCustomerExistsException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public @ResponseBody ErrorResponse handleException(NoSuchCustomerExistsException ex) {
        return new ErrorResponse(HttpStatus.NOT_FOUND.value(), ex.getMessage());
    }
}

在运行 Spring Boot 应用程序并 /updateCustomer 使用无效的客户详细信息访问 API 时, NoSuchCustomerExistsException 会抛出该错误,该错误完全由类中定义的处理程序方法处理, GlobalExceptionHandler 如下所示:

最后

Spring Boot 提供了多种处理异常的方法,确保您的应用程序能够返回有意义的错误。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

潜洋

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值