# Spring REST 异常处理示例

> 原文： [https://howtodoinjava.com/spring-restful/exception-handling-example/](https://howtodoinjava.com/spring-restful/exception-handling-example/)

在使用 **Spring REST** 模块创建的 [REST API](https://restfulapi.net) 中学习处理异常（请求验证，错误数据或其他请求处理错误）。 我们将研究一种使用`@ControllerAdvice`和`@ExceptionHandler`的方法。

要使用`@ControllerAdvice`全局处理 REST 异常，我们需要遵循以下步骤。

## 1\. 使用`@ControllerAdvice`和`@ExceptionHandler`创建处理器

*   [`@ControllerAdvice`](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/ControllerAdvice.html)注解是`@Component`注解的特化，其方法（以[`@ExceptionHandler`](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/ExceptionHandler.html)注解）在全球范围内跨多个`@Controller`类共享。
*   通过类路径扫描自动检测带有`@ControllerAdvice`的类。
*   使用选择器`annotations()`，`basePackageClasses()`和`basePackages()`定义目标控制器的更窄子集。
*   我们可以在选择器中应用 OR 运算符，即如果遇到给定异常中的任何一个，则将执行给定方法。

请注意，[`ResponseEntityExceptionHandler`](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/mvc/method/annotation/ResponseEntityExceptionHandler.html)是`@ControllerAdvice`类的便捷基类，这些类希望通过`@ExceptionHandler`方法跨所有`@RequestMapping`方法提供集中的[异常处理](https://howtodoinjava.com/best-practices/java-exception-handling-best-practices/) 。

`CustomExceptionHandler.java`

```java
import java.util.ArrayList;
import java.util.List;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

@ControllerAdvice
public class CustomExceptionHandler extends ResponseEntityExceptionHandler 
{
	private String INCORRECT_REQUEST = "INCORRECT_REQUEST";
	private String BAD_REQUEST = "BAD_REQUEST";

	@ExceptionHandler(RecordNotFoundException.class)
	public final ResponseEntity<ErrorResponse> handleUserNotFoundException
						(RecordNotFoundException ex, WebRequest request) 
	{
		List<String> details = new ArrayList<>();
		details.add(ex.getLocalizedMessage());
		ErrorResponse error = new ErrorResponse(INCORRECT_REQUEST, details);
		return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
	}

	@ExceptionHandler(MissingHeaderInfoException.class)
	public final ResponseEntity<ErrorResponse> handleInvalidTraceIdException
						(MissingHeaderInfoException ex, WebRequest request) {
		List<String> details = new ArrayList<>();
		details.add(ex.getLocalizedMessage());
		ErrorResponse error = new ErrorResponse(BAD_REQUEST, details);
		return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
	}
}

```

## 2\. 创建异常模型类

我们需要识别业务异常用例，并用异常类来表示它们。 这些类将扩展`RuntimeException`类。 也可以根据需要随意创建更多错误响应表示。

`MissingHeaderInfoException.java`

```java
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(HttpStatus.BAD_REQUEST)
public class MissingHeaderInfoException extends RuntimeException
{
	private static final long serialVersionUID = 1L;

	public MissingHeaderInfoException(String message) {
        super(message);
    }
}

```

`RecordNotFoundException.java`

```java
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(HttpStatus.NOT_FOUND)
public class RecordNotFoundException extends RuntimeException
{
	private static final long serialVersionUID = 1L;

	public RecordNotFoundException(String message) {
        super(message);
    }
}

```

`ErrorResponse.java`

```java
import java.util.List;

public class ErrorResponse
{
    public ErrorResponse(String message, List<String> details) {
        super();
        this.message = message;
        this.details = details;
    }

    private String message;
    private List<String> details;

	//getters and setters
}

```

## 3\. 配置视图解析器

如果尚未完成，我们需要配置视图解析器以将异常消息转换为 XML 或 JSON 形式。

在 Spring Boot 中，此配置是自动完成的。 没有 SpringBoot，我们需要像下面这样。

> 重要说明：确保已启用`mvc: annotation-driven`配置，或已使用`@EnableWebMvc`注解。

`rest-servlet.xml`

```java
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:jpa="http://www.springframework.org/schema/data/jpa"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans.xsd
	http://www.springframework.org/schema/context
	http://www.springframework.org/schema/context/spring-context.xsd
	http://www.springframework.org/schema/data/jpa 
    http://www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
	http://www.springframework.org/schema/mvc
	http://www.springframework.org/schema/mvc/spring-mvc.xsd">

	<mvc:annotation-driven />

	<context:component-scan base-package="com.howtodoinjava.demo" />

	<mvc:view-resolvers>
        <mvc:content-negotiation>
            <mvc:default-views>
                <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
            </mvc:default-views>
        </mvc:content-negotiation>
    </mvc:view-resolvers>

	<!-- JPA Config -->
</beans>

```

## 4\. REST 控制器更改

从 rest 控制器处理器方法中，我们需要抛出要转换并作为响应发送给 API 使用者的异常。 在这种情况下，如果`id`搜索了一个雇员并且该雇员在数据库中不存在，我们将发送`RecordNotFoundException`。

`EmployeeRESTController.java`

```java
@GetMapping("/employees/{id}")
Employee getEmployeeById(@PathVariable Long id) 
{
	return repository.findById(id)
			.orElseThrow(() -> new RecordNotFoundException("Employee id '" + id + "' does no exist"));
}

```

## 5\. Spring REST 异常处理演示

尝试按 ID（在数据库中不存在 ID）获取员工。

`API Request`

```java
HTTP GET : http://localhost:8080/SpringRestExample/api/rest/employee-management/employees/101

```

`API Response`

```java
{
	"message": "INCORRECT_REQUEST",
	"details": [
	  	"Employee id '101' does no exist"
	],
}

```

请把关于 Spring Rest API 中的**异常处理**的问题交给我。

学习愉快！

[下载源码](https://howtodoinjava.com/wp-content/downloads/SpringRestExample.zip)