我使用Spring MVC为一个简单的JSON API,使用@ResponseBody的方法,如下所示。(我已经有了一个直接生成JSON的服务层。)
@RequestMapping(value = "/matches/{matchId}", produces = "application/json")
@ResponseBody
public String match(@PathVariable String matchId) {
String json = matchService.getMatchJson(matchId);
if (json == null) {
// TODO: how to respond with e.g. 400 "bad request"?
}
return json;
}
在给定的场景中,响应HTTP 400错误的最简单、最干净的方法是什么?
我确实遇到过这样的方法:
return new ResponseEntity(HttpStatus.BAD_REQUEST);
...但我不能在这里使用它,因为我的方法的返回类型是字符串,而不是ResponseEntity。
这样的方法应该是可行的,但我不确定是否有更简单的方法:
@RequestMapping(value = "/matches/{matchId}", produces = "application/json")
@ResponseBody
public String match(@PathVariable String matchId, @RequestBody String body,
HttpServletRequest request, HttpServletResponse response) {
String json = matchService.getMatchJson(matchId);
if (json == null) {
response.setStatus( HttpServletResponse.SC_BAD_REQUEST );
}
return json;
}
这样的方法应该是可行的,但我不确定是否有更简单的方法:
@RequestMapping(value = "/matches/{matchId}", produces = "application/json")
@ResponseBody
public String match(@PathVariable String matchId, @RequestBody String body,
HttpServletRequest request, HttpServletResponse response) {
String json = matchService.getMatchJson(matchId);
if (json == null) {
response.setStatus( HttpServletResponse.SC_BAD_REQUEST );
}
return json;
}
使用带有状态代码的自定义响应。
是这样的:
class Response<T>(
val timestamp: String = DateTimeFormatter
.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSS")
.withZone(ZoneOffset.UTC)
.format(Instant.now()),
val code: Int = ResultCode.SUCCESS.code,
val message: String? = ResultCode.SUCCESS.message,
val status: HttpStatus = HttpStatus.OK,
val error: String? = "",
val token: String? = null,
val data: T? = null
) : : ResponseEntity<Response.CustomResponseBody>(status) {
data class CustomResponseBody(
val timestamp: String = DateTimeFormatter
.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSS")
.withZone(ZoneOffset.UTC)
.format(Instant.now()),
val code: Int = ResultCode.SUCCESS.code,
val message: String? = ResultCode.SUCCESS.message,
val error: String? = "",
val token: String? = null,
val data: Any? = null
)
override fun getBody(): CustomResponseBody? = CustomResponseBody(timestamp, code, message, error, token, data)
正如在一些回答中提到的,可以为您想要返回的每个HTTP状态创建一个异常类。我不喜欢为每个项目的每个状态创建一个类的想法。这是我想出的替代方案。
创建接受HTTP状态的通用异常
创建一个Controller Advice异常处理程序
让我们来看看代码
package com.javaninja.cam.exception;
import org.springframework.http.HttpStatus;
/**
* The exception used to return a status and a message to the calling system.
* @author norrisshelton
*/
@SuppressWarnings("ClassWithoutNoArgConstructor")
public class ResourceException extends RuntimeException {
private HttpStatus httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
/**
* Gets the HTTP status code to be returned to the calling system.
* @return http status code. Defaults to HttpStatus.INTERNAL_SERVER_ERROR (500).
* @see HttpStatus
*/
public HttpStatus getHttpStatus() {
return httpStatus;
}
/**
* Constructs a new runtime exception with the specified HttpStatus code and detail message.
* The cause is not initialized, and may subsequently be initialized by a call to {@link #initCause}.
* @param httpStatus the http status. The detail message is saved for later retrieval by the {@link
* #getHttpStatus()} method.
* @param message the detail message. The detail message is saved for later retrieval by the {@link
* #getMessage()} method.
* @see HttpStatus
*/
public ResourceException(HttpStatus httpStatus, String message) {
super(message);
this.httpStatus = httpStatus;
}
}
然后我创建一个控制器通知类
package com.javaninja.cam.spring;
import com.javaninja.cam.exception.ResourceException;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
/**
* Exception handler advice class for all SpringMVC controllers.
* @author norrisshelton
* @see org.springframework.web.bind.annotation.ControllerAdvice
*/
@org.springframework.web.bind.annotation.ControllerAdvice
public class ControllerAdvice {
/**
* Handles ResourceExceptions for the SpringMVC controllers.
* @param e SpringMVC controller exception.
* @return http response entity
* @see ExceptionHandler
*/
@ExceptionHandler(ResourceException.class)
public ResponseEntity handleException(ResourceException e) {
return ResponseEntity.status(e.getHttpStatus()).body(e.getMessage());
}
}
使用它
throw new ResourceException(HttpStatus.BAD_REQUEST, "My message");
http://javaninja.net/2016/06/throwing-exceptions-messages-spring-mvc-controller/
另一种方法是使用@ExceptionHandler和@ControllerAdvice将所有处理程序集中在同一个类中。如果不是,则必须将处理程序方法放入希望为其管理异常的每个控制器中。
你的处理程序类:
@ControllerAdvice
public class MyExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(MyBadRequestException.class)
public ResponseEntity<MyError> handleException(MyBadRequestException e) {
return ResponseEntity
.badRequest()
.body(new MyError(HttpStatus.BAD_REQUEST, e.getDescription()));
}
}
您的自定义异常:
public class MyBadRequestException extends RuntimeException {
private String description;
public MyBadRequestException(String description) {
this.description = description;
}
public String getDescription() {
return this.description;
}
}
现在,您可以从任何控制器抛出异常,并且可以在通知类中定义其他处理程序。
将您的返回类型更改为ResponseEntity<>,然后您可以使用下面的400:
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
对于正确的请求:
return new ResponseEntity<>(json,HttpStatus.OK);
Spring 4.1之后,ResponseEntity中有了帮助方法,可以用作:
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
and
return ResponseEntity.ok(json);