Spring Boot Web:使用 @ExceptionHandler 处理异常


#Spring Boot#


示例

项目结构

.
├── build.gradle
└── src
    └── main
        ├── java
        │   └── hello
        │       ├── Application.java
        │       ├── BaseResponse.java
        │       ├── CustomExceptionHandler.java
        │       ├── Greeting.java
        │       ├── GreetingController.java
        │       └── ex
        │           ├── CustomException01.java
        │           └── CustomException02.java
        └── resources

build.gradle

buildscript {
    repositories {
        maven { url 'http://mirrors.cloud.tencent.com/nexus/repository/maven-public/' }
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:2.1.3.RELEASE")
    }
}

apply plugin: 'java'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'


sourceCompatibility = 1.8
targetCompatibility = 1.8

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web")
    compile group: 'org.projectlombok', name: 'lombok', version: '1.18.0'
}

自定义异常

package hello.ex;

public class CustomException01 extends RuntimeException {

}
package hello.ex;

public class CustomException02 extends RuntimeException {
}

BaseResponse 类

package hello;

import lombok.Data;

import java.io.Serializable;

@Data
public class BaseResponse implements Serializable {

    private Boolean success;
    private String msg;
    private Object result;

    public static BaseResponse success(String msg, Object result) {
        return new BaseResponse(true, msg, result);
    }

    public static BaseResponse fail(String msg, Object result) {
        return new BaseResponse(false, msg, result);
    }

    private BaseResponse(Boolean isSuccess, String msg, Object result) {
        this.success = isSuccess;
        this.msg = msg;
        this.result = result;
    }

}

Greeting 类

package hello;

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class Greeting {

    private long id;
    private String content;

}

Application 类:程序主入口

package hello;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

GreetingController 类

package hello;


import hello.ex.CustomException01;
import hello.ex.CustomException02;
import org.springframework.web.bind.annotation.*;

@RestController
public class GreetingController {

    @RequestMapping(value = "/greeting1")
    public BaseResponse greeting1(@RequestParam(value="name", defaultValue="World") String name,
                                  @RequestParam(value="raiseEx", defaultValue="false") Boolean raiseEx) {
        if(raiseEx) {
            throw new CustomException01();
        }
        return BaseResponse.success("", new Greeting(1L, String.format("Hello, %s! This is greeting1", name)));
    }

    @RequestMapping(value = "/greeting2")
    public BaseResponse greeting2(@RequestParam(value="name", defaultValue="World") String name,
                                  @RequestParam(value="raiseEx", defaultValue="false") Boolean raiseEx) {
        if(raiseEx) {
            throw new CustomException02();
        }
        return BaseResponse.success("", new Greeting(2L, String.format("Hello, %s! This is greeting2", name)));
    }


}

CustomExceptionHandler 类:使用 @ExceptionHandler 处理controller抛出的异常

package hello;

import hello.ex.CustomException01;
import hello.ex.CustomException02;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.CollectionUtils;
import org.springframework.web.HttpRequestMethodNotSupportedException;
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;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import java.util.Set;

@ControllerAdvice // 注意,这个必须有,用于声明是对 controller 控制器的增强。
public class CustomExceptionHandler {

    @ExceptionHandler({CustomException01.class,})
    public ResponseEntity<Object> handleCustomException01Exception(CustomException01 ex, WebRequest request) throws Exception {
        return new ResponseEntity<>(BaseResponse.fail("CustomException01异常", null), HttpStatus.BAD_REQUEST);
    }

    @ExceptionHandler({CustomException02.class,})
    @ResponseBody
    @ResponseStatus(value = HttpStatus.BAD_REQUEST) // 自定义 HTTP 响应状态码
    public final BaseResponse handleCustomException02Exception(CustomException02 ex, WebRequest request) throws Exception {
        return BaseResponse.fail("CustomException02异常", null);
    }

}

是的,@ExceptionHandler要和@ControllerAdvice配合使用。

注意,同一个Exception不能被多次ExceptionHandler,否则会启动程序时会报错。

运行示例

浏览器请求http://127.0.0.1:8080/greeting1, 响应体:

{"success":true,"msg":"","result":{"id":1,"content":"Hello, World! This is greeting1"}}

浏览器请求http://127.0.0.1:8080/greeting1?raiseEx=true,响应400 Bad Request, 响应体:

{"success":false,"msg":"CustomException01异常","result":null}

浏览器请求http://127.0.0.1:8080/greeting2,响应体:

{"success":true,"msg":"","result":{"id":2,"content":"Hello, World! This is greeting2"}}

浏览器请求http://127.0.0.1:8080/greeting2?raiseEx=true,响应400 Bad Request, 响应体:

{"success":false,"msg":"CustomException02异常","result":null}

( 本文完 )