我正在春季启动中编写REST API应用程序。我希望我的json响应的签名是这样的:
示例:1
{
"status": "Error"
"httpcode": 500
"dev_message": "ServerException"
"user_message": "Oops..something went wrong with the app. Please try again."
"response": {
...
}
}
示例:2
{
"status": "Success"
"httpcode": 200
"dev_message": "APICallSuccess"
"user_message": "Successfully called API"
"response": {
"userid": "test",
"age": 31
...
"country": "India"
}
}
其中status, httpcode, dev_message
和user_message
在请求生命周期的不同阶段动态更新。例如,如果API令牌不正确,授权过滤器应将httpstatus
字段更新为401
,将dev_message
更新为AuthException
。另一方面,如果用户试图访问另一个不允许的用户数据,则控制器应更新这些字段。
我在这里有两个部分的问题:
RequestHandlerInterceptor
和Filters
,但是信息太多了,我无法缩小范围。编辑1: 以下是针对控制器级别的许多答案。我希望使用过滤器以更高的执行级别处理此问题。假设验证失败,那么我的请求甚至不会到达控制器。在所有这些情况下,我都希望在一个地方实施成功和失败消息,以使其简洁明了。
答案 0 :(得分:-1)
我相信您正在寻找:使用Spring ResponseEntity来处理HTTP响应 https://www.baeldung.com/spring-response-entity
@GetMapping("/age")
ResponseEntity<String> age(
@RequestParam("yearOfBirth") int yearOfBirth) {
if (isInFuture(yearOfBirth)) {
return new ResponseEntity<>(
"Year of birth cannot be in the future",
HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<>(
"Your age is " + calculateAge(yearOfBirth),
HttpStatus.OK);
}
您可以根据需要设置错误404、403。请让我知道它是否有效
答案 1 :(得分:-1)
在两种情况下,无论是错误还是响应,我都使用了非常相似的JSON响应。您可以尝试一下,它可能会对您有所帮助:)
错误JSON:
{
"data": null,
"message": "Content type 'text/plain;charset=UTF-8' not supported",
"infoType": "ERROR",
"statusCode": 415,
"errors": [
"text/plain;charset=UTF-8 media type is not supported. Supported media types are application/octet-stream text/plain application/xml text/xml application/x-www-form-urlencoded application/*+xml multipart/form-data application/json application/*+json */"
]
}
响应JSON:
{
"data": "{
"id": 0,
"name": null,
"nestedObject": {
"id": 0,
"name": "",
"url": "",
// Other Details
},
"address": "address",
"city": null,
"country": "country"
}",
"message": "Your success message comes here",
"infoType": "INFO",
"statusCode": 200
}
我创建了一个抽象类,即Message。响应和错误这两个类扩展了Message。
您可以查看以下代码:
1。信息类型使用的枚举:
public enum InfoType {
ERROR, INFO, WARNING
}
2。消息的抽象类:
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.springframework.http.HttpStatus;
public abstract class Message {
private String message;
private InfoType infoType;
@JsonIgnore
private HttpStatus status;
private int statusCode;
public Message(){
}
public Message(String message, InfoType infoType, HttpStatus status) {
this.message = message;
this.infoType = infoType;
this.status = status;
this.statusCode = status.value();
}
//Getters and Setters
}
3。 POJO用于响应:
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import org.springframework.http.HttpStatus;
@JsonPropertyOrder({ "data", "message", "infoType", "status", "statusCode"})
public class ResponseMessage extends Message{
private Object data;
private ResponseMessage() {
}
public ResponseMessage(Object data, String message, InfoType infoType, HttpStatus status) {
super(message, infoType, status);
this.data = data;
}
//Getters and Setters
}
4。 POJO用于错误:
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import org.springframework.http.HttpStatus;
import java.util.Collections;
import java.util.List;
@JsonPropertyOrder({ "data", "message", "infoType", "status", "statusCode", "errors"})
public class ErrorMessage extends Message {
private Object data;
private List<String> errors;
private ErrorMessage() {
}
public ErrorMessage(Object data, String message, InfoType infoType, HttpStatus status) {
super(message, infoType, status);
this.data = data;
}
public ErrorMessage(String message, InfoType infoType, HttpStatus status) {
super(message, infoType, status);
this.data = null;
}
public ErrorMessage(String message, InfoType infoType, HttpStatus status, List<String> errors) {
super(message, infoType, status);
this.errors = errors;
this.data = null;
}
public ErrorMessage(String message, InfoType infoType, HttpStatus status, String error) {
super(message, infoType, status);
this.errors = Collections.singletonList(error);
this.data = null;
}
//Getters and Setters
}
5。用于警告/错误/响应的服务:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
@Component
public class ResponseMessageService {
@Autowired
private ResponseMessages responseMessages;
@Autowired
private ErrorMessages errorMessages;
public ResponseMessage generateResponseMessage(Object data, String messageKey, HttpStatus status) {
return new ResponseMessage(data,responseMessages.getProperty(messageKey), InfoType.INFO, status);
}
public ResponseMessage generateWarningMessage(Object data,String messageKey, HttpStatus status) {
return new ResponseMessage(data,responseMessages.getProperty(messageKey), InfoType.WARNING , status);
}
public ErrorMessage generateErrorMessage(Object data,String messageKey, HttpStatus status) {
return new ErrorMessage(data,errorMessages.getProperty(messageKey), InfoType.ERROR , status);
}
}
6。用于从属性文件读取错误的服务:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import java.text.MessageFormat;
import java.util.List;
@Component
@PropertySource("classpath:errormessage.properties")
public class ErrorMessages {
@Autowired
private Environment env;
public String getProperty(String property) {
return env.getProperty(property);
}
}
7。从属性文件读取消息的服务:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import java.text.MessageFormat;
import java.util.List;
@Component
@PropertySource("classpath:responsemessage.properties")
public class ResponseMessages {
@Autowired
private Environment env;
public String getProperty(String property) {
return env.getProperty(property);
}
}
8。最后利用以上内容的资源/ API类:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@RestController
@RequestMapping("user")
public class UserResource {
@Autowired
ResponseMessageService responseMessageService;
@RequestMapping(value="/register", method = RequestMethod.POST)
public ResponseEntity register(@RequestBody User user){
if(success){
return ResponseEntity.ok(responseMessageService.generateResponseMessage(null,"register.success",HttpStatus.OK));
}else{
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(responseMessageService.generateErrorMessage(null,"register.fail",HttpStatus.BAD_REQUEST));
}
}
@RequestMapping(value="/login", method = RequestMethod.POST)
public ResponseEntity login(@RequestBody User user){
if(success){
return ResponseEntity.ok().body(responseMessageService.generateResponseMessage(data,"login.success",HttpStatus.OK));
}else{
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(responseMessageService.generateResponseMessage(null, "login.fail",HttpStatus.BAD_REQUEST));
}
}
}
对于处理异常,我正在使用CustomExceptionHandler。同样在此处理程序中,我使用的是相同的错误格式。
import org.springframework.beans.TypeMismatchException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
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.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.ArrayList;
import java.util.List;
@ControllerAdvice
public class CustomExceptionHandler extends ResponseEntityExceptionHandler {
// 400
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(final MethodArgumentNotValidException ex, final HttpHeaders headers, final HttpStatus status, final WebRequest request) {
logger.info(ex.getClass().getName());
//
final List<String> errors = new ArrayList<String>();
for (final FieldError error : ex.getBindingResult().getFieldErrors()) {
errors.add(error.getField() + ": " + error.getDefaultMessage());
}
for (final ObjectError error : ex.getBindingResult().getGlobalErrors()) {
errors.add(error.getObjectName() + ": " + error.getDefaultMessage());
}
final ErrorMessage errorMessage = new ErrorMessage(ex.getLocalizedMessage(), InfoType.ERROR, HttpStatus.BAD_REQUEST, errors);
return handleExceptionInternal(ex, errorMessage, headers, errorMessage.getStatus(), request);
}
@Override
protected ResponseEntity<Object> handleBindException(final BindException ex, final HttpHeaders headers, final HttpStatus status, final WebRequest request) {
logger.info(ex.getClass().getName());
//
final List<String> errors = new ArrayList<String>();
for (final FieldError error : ex.getBindingResult().getFieldErrors()) {
errors.add(error.getField() + ": " + error.getDefaultMessage());
}
for (final ObjectError error : ex.getBindingResult().getGlobalErrors()) {
errors.add(error.getObjectName() + ": " + error.getDefaultMessage());
}
final ErrorMessage errorMessage = new ErrorMessage(ex.getLocalizedMessage(), InfoType.ERROR, HttpStatus.BAD_REQUEST, errors);
return handleExceptionInternal(ex, errorMessage, headers, errorMessage.getStatus(), request);
}
@Override
protected ResponseEntity<Object> handleTypeMismatch(final TypeMismatchException ex, final HttpHeaders headers, final HttpStatus status, final WebRequest request) {
logger.info(ex.getClass().getName());
//
final String error = ex.getValue() + " value for " + ex.getPropertyName() + " should be of type " + ex.getRequiredType();
final ErrorMessage errorMessage = new ErrorMessage(ex.getLocalizedMessage(), InfoType.ERROR, HttpStatus.BAD_REQUEST, error);
return new ResponseEntity<Object>(errorMessage, new HttpHeaders(), errorMessage.getStatus());
}
@Override
protected ResponseEntity<Object> handleMissingServletRequestPart(final MissingServletRequestPartException ex, final HttpHeaders headers, final HttpStatus status, final WebRequest request) {
logger.info(ex.getClass().getName());
//
final String error = ex.getRequestPartName() + " part is missing";
final ErrorMessage errorMessage = new ErrorMessage(ex.getLocalizedMessage(), InfoType.ERROR, HttpStatus.BAD_REQUEST, error);
return new ResponseEntity<Object>(errorMessage, new HttpHeaders(), errorMessage.getStatus());
}
@Override
protected ResponseEntity<Object> handleMissingServletRequestParameter(final MissingServletRequestParameterException ex, final HttpHeaders headers, final HttpStatus status, final WebRequest request) {
logger.info(ex.getClass().getName());
//
final String error = ex.getParameterName() + " parameter is missing";
final ErrorMessage errorMessage = new ErrorMessage(ex.getLocalizedMessage(), InfoType.ERROR, HttpStatus.BAD_REQUEST, error);
return new ResponseEntity<Object>(errorMessage, new HttpHeaders(), errorMessage.getStatus());
}
//
@ExceptionHandler({ MethodArgumentTypeMismatchException.class })
public ResponseEntity<Object> handleMethodArgumentTypeMismatch(final MethodArgumentTypeMismatchException ex, final WebRequest request) {
logger.info(ex.getClass().getName());
//
final String error = ex.getName() + " should be of type " + ex.getRequiredType().getName();
final ErrorMessage errorMessage = new ErrorMessage(ex.getLocalizedMessage(), InfoType.ERROR, HttpStatus.BAD_REQUEST, error);
return new ResponseEntity<Object>(errorMessage, new HttpHeaders(), errorMessage.getStatus());
}
@ExceptionHandler({ ConstraintViolationException.class })
public ResponseEntity<Object> handleConstraintViolation(final ConstraintViolationException ex, final WebRequest request) {
logger.info(ex.getClass().getName());
//
final List<String> errors = new ArrayList<String>();
for (final ConstraintViolation<?> violation : ex.getConstraintViolations()) {
errors.add(violation.getRootBeanClass().getName() + " " + violation.getPropertyPath() + ": " + violation.getMessage());
}
final ErrorMessage errorMessage = new ErrorMessage(ex.getLocalizedMessage(), InfoType.ERROR, HttpStatus.BAD_REQUEST, errors);
return new ResponseEntity<Object>(errorMessage, new HttpHeaders(), errorMessage.getStatus());
}
// 404
@Override
protected ResponseEntity<Object> handleNoHandlerFoundException(final NoHandlerFoundException ex, final HttpHeaders headers, final HttpStatus status, final WebRequest request) {
logger.info(ex.getClass().getName());
//
final String error = "No handler found for " + ex.getHttpMethod() + " " + ex.getRequestURL();
final ErrorMessage errorMessage = new ErrorMessage(ex.getLocalizedMessage(), InfoType.ERROR, HttpStatus.NOT_FOUND, error);
return new ResponseEntity<Object>(errorMessage, new HttpHeaders(), errorMessage.getStatus());
}
// 405
@Override
protected ResponseEntity<Object> handleHttpRequestMethodNotSupported(final HttpRequestMethodNotSupportedException ex, final HttpHeaders headers, final HttpStatus status, final WebRequest request) {
logger.info(ex.getClass().getName());
//
final StringBuilder builder = new StringBuilder();
builder.append(ex.getMethod());
builder.append(" method is not supported for this request. Supported methods are ");
ex.getSupportedHttpMethods().forEach(t -> builder.append(t + " "));
final ErrorMessage errorMessage = new ErrorMessage(ex.getLocalizedMessage(), InfoType.ERROR, HttpStatus.METHOD_NOT_ALLOWED, builder.toString());
return new ResponseEntity<Object>(errorMessage, new HttpHeaders(), errorMessage.getStatus());
}
// 415
@Override
protected ResponseEntity<Object> handleHttpMediaTypeNotSupported(final HttpMediaTypeNotSupportedException ex, final HttpHeaders headers, final HttpStatus status, final WebRequest request) {
logger.info(ex.getClass().getName());
//
final StringBuilder builder = new StringBuilder();
builder.append(ex.getContentType());
builder.append(" media type is not supported. Supported media types are ");
ex.getSupportedMediaTypes().forEach(t -> builder.append(t + " "));
final ErrorMessage errorMessage = new ErrorMessage(ex.getLocalizedMessage(), InfoType.ERROR, HttpStatus.UNSUPPORTED_MEDIA_TYPE, builder.substring(0, builder.length() - 2));
return new ResponseEntity<Object>(errorMessage, new HttpHeaders(), errorMessage.getStatus());
}
// 500
@ExceptionHandler({ Exception.class })
public ResponseEntity<Object> handleAll(final Exception ex, final WebRequest request) {
logger.error("Error Occurred in Class " + ex.getClass().getName() + " ", ex);
String message = ex.getMessage();
String stackTrace = ex.fillInStackTrace().toString();
final ErrorMessage errorMessage = new ErrorMessage(message, InfoType.ERROR, HttpStatus.INTERNAL_SERVER_ERROR, stackTrace);
return new ResponseEntity<Object>(errorMessage, new HttpHeaders(), errorMessage.getStatus());
}
}
以下是我使用过的参考文献:
1。。https://www.baeldung.com/global-error-handler-in-a-spring-rest-api
2。 https://github.com/eugenp/tutorials/blob/master/spring-security-rest/src/main/java/org/baeldung/web/CustomRestExceptionHandler.java