示例
项目结构
.
├── build.gradle
└── src
└── main
└── java
└── hello
├── Application.java
├── BaseResponse.java
├── CustomExceptionHandler.java
├── Greeting.java
└── GreetingController.java
代码中使用了 Lombok 库,关于这个库的具体使用,可以参考:Java Lombok 库:为你减少样板代码。
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'
}
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 java.util.concurrent.atomic.AtomicLong;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
public class GreetingController {
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
/**
* 只允许 HTTP POST 方法
*/
@RequestMapping(value = "/greeting1", method = RequestMethod.POST)
public Greeting greeting1(@RequestParam(value="name", defaultValue="World") String name) {
return new Greeting(counter.incrementAndGet(),
String.format(template, name));
}
}
运行示例
上面我们少介绍了 CustomExceptionHandler 类,我们把该类删掉,运行 Application。
如果我们用 GET 方法请求 http://127.0.0.1:8080/greeting1
,响应状态是405,响应体是:
{
"timestamp": "2018-07-22T00:46:07.791+0000",
"status": 405,
"error": "Method Not Allowed",
"message": "Request method 'GET' not supported",
"path": "/greeting1"
}
如何自定义响应体?
增加CustomExceptionHandler
,内容如下:
@ControllerAdvice // 注意,这个必须有,用于声明是对 controller 控制器的增强。
public class CustomExceptionHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleHttpRequestMethodNotSupported(
HttpRequestMethodNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
Set<HttpMethod> supportedMethods = ex.getSupportedHttpMethods();
if (!CollectionUtils.isEmpty(supportedMethods)) {
headers.setAllow(supportedMethods);
}
return handleExceptionInternal(ex, null, headers, status, request);
}
}
继承抽象类 ResponseEntityExceptionHandler 后,ResponseEntityExceptionHandler 内部的下面这个方法会用来处理异常:
@ExceptionHandler({
HttpRequestMethodNotSupportedException.class,
HttpMediaTypeNotSupportedException.class,
HttpMediaTypeNotAcceptableException.class,
MissingPathVariableException.class,
MissingServletRequestParameterException.class,
ServletRequestBindingException.class,
ConversionNotSupportedException.class,
TypeMismatchException.class,
HttpMessageNotReadableException.class,
HttpMessageNotWritableException.class,
MethodArgumentNotValidException.class,
MissingServletRequestPartException.class,
BindException.class,
NoHandlerFoundException.class,
AsyncRequestTimeoutException.class
})
@Nullable
public final ResponseEntity<Object> handleException(Exception ex, WebRequest request) throws Exception {
HttpHeaders headers = new HttpHeaders();
if (ex instanceof HttpRequestMethodNotSupportedException) {
HttpStatus status = HttpStatus.METHOD_NOT_ALLOWED;
return handleHttpRequestMethodNotSupported((HttpRequestMethodNotSupportedException) ex, headers, status, request);
}
// 省略
}
其中,handleHttpRequestMethodNotSupported 用来处理请求方法不支持的异常。
运行 Application 类,用 GET 方法请求 http://127.0.0.1:8080/greeting1
,响应状态是405,而响应体已经变空。为什么?因为return handleExceptionInternal(ex, null, headers, status, request);
,第2个参数是null。
当然,我们也可以自定义第2个参数。我们将 handleHttpRequestMethodNotSupported 实现为:
@Override
protected ResponseEntity<Object> handleHttpRequestMethodNotSupported(
HttpRequestMethodNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
Set<HttpMethod> supportedMethods = ex.getSupportedHttpMethods();
if (!CollectionUtils.isEmpty(supportedMethods)) {
headers.setAllow(supportedMethods);
}
return handleExceptionInternal(ex, BaseResponse.fail("请求方法不支持", null), headers, status, request);
}
重新运行 Application 类,用 GET 方法请求 http://127.0.0.1:8080/greeting1
,响应状态是405,而响应体变成:
{
"msg": "请求方法不支持",
"result": null,
"success": false
}
还能学到什么?本文中出现了 @ExceptionHandler , 该注解在 Spring Boot Web:使用 @ExceptionHandler 处理异常会介绍。