Java 向404未找到异常添加正文

Java 向404未找到异常添加正文,java,rest,spring-mvc,spring-boot,jhipster,Java,Rest,Spring Mvc,Spring Boot,Jhipster,在用JHipster生成的RESTAPI中,我想抛出一些404异常。这通常是用 return new ResponseEntity<>(HttpStatus.NOT_FOUND); 当404是实际响应时,这样的结果是空的,这使得解析失败 如果我指向一个未映射的URI,比如说/api/user,而我的控制器映射到/api/users(注意复数形式)我从api获得的404有一个主体: { "timestamp": "2016-04-25T18:33:19.947+0000",

在用JHipster生成的RESTAPI中,我想抛出一些404异常。这通常是用

return new ResponseEntity<>(HttpStatus.NOT_FOUND);
当404是实际响应时,这样的结果是空的,这使得解析失败

如果我指向一个未映射的URI,比如说
/api/user
,而我的控制器映射到
/api/users
(注意复数形式)我从api获得的404有一个主体:

{
    "timestamp": "2016-04-25T18:33:19.947+0000",
    "status": 404,
    "error": "Not Found",
    "message": "No message available",
    "path": "/api/user/myuser/contact"
}
这是正确的角度解析

我怎样才能创建这样的实体?这个异常是spring抛出的还是tomcat抛出的

我试过这样做:但我无法设置响应的参数。

基本想法
第一个选项是定义错误对象并将其返回为
404notfound
body。大致如下:

Map<String, String> errors = ....;
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errors);
@RestController
public class APIExceptionHandler extends AbstractErrorController {
    private static final String ERROR_PATH = "/error";
    private final ErrorAttributes errorAttributes;

    @Autowired
    public APIExceptionHandler(ErrorAttributes errorAttributes) {
        super(errorAttributes);
        this.errorAttributes = errorAttributes;
    }

    @RequestMapping(path = ERROR_PATH)
    public ResponseEntity<?> handleError(HttpServletRequest request) {
        HttpStatus status = getStatus(request);

        Map<String, Object> errors = getErrorAttributes(request, false);
        getApiException(request).ifPresent(apiError -> {
            errors.put("message" , apiError.message());
            errors.put("code", apiError.code());
        });
        // If you don't want to expose exception!
        errors.remove("exception");


        return ResponseEntity.status(status).body(errors);
    }

    @Override
    public String getErrorPath() {
        return ERROR_PATH;
    }

    private Optional<APIException> getApiException(HttpServletRequest request) {
        RequestAttributes attributes = new ServletRequestAttributes(request);
        Throwable throwable = errorAttributes.getError(attributes);
        if (throwable instanceof APIException) {
            APIException exception = (APIException) throwable;
            return Optional.of(exception);
        }

        return Optional.empty();
    }
}
然后,如果在控制器中抛出此异常,您将看到如下内容:

{  
   "timestamp":1461621047967,
   "status":404,
   "error":"Not Found",
   "exception":"NotFoundException",
   "message":"No message available",
   "path":"/greet"
}
如果要自定义消息和正文的其他部分,应该为
NotFoundException
定义一个
ExceptionHandler

引入异常层次结构
如果您正在创建RESTful API,并且希望针对不同的异常情况有不同的错误代码和错误消息,那么可以创建表示这些情况的异常层次结构,并从每个异常中提取消息和代码

例如,您可以引入一个异常,例如,
APIException
,它是控制器引发的所有其他异常的超类。此类定义了一个代码/消息对,如:

public class APIException extends RuntimeException {
    private final int code;
    private final String message;

    APIException(int code, String message) {
        this.code = code;
        this.message = message;
    }

    public int code() {
        return code;
    }

    public String message() {
        return message;
    }
}
根据异常的性质,每个子类都可以为这对异常提供一些合理的值。例如,我们可能有一个
InvalidStateException

@ResponseStatus(code = HttpStatus.BAD_REQUEST)
public class InvalidStateException extends APIException {
    public InvalidStateException() {
        super(1, "Application is in invalid state");
    }
}
或是找不到的:

@ResponseStatus(code = HttpStatus.NOT_FOUND)
public class SomethingNotFoundException extends APIException {
    public SomethingNotFoundException() {
        super(2, "Couldn't find something!");
    }
}
然后我们应该定义一个
ErrorController
,它捕获这些异常并将它们转换为有意义的JSON表示。该错误控制器可能如下所示:

Map<String, String> errors = ....;
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errors);
@RestController
public class APIExceptionHandler extends AbstractErrorController {
    private static final String ERROR_PATH = "/error";
    private final ErrorAttributes errorAttributes;

    @Autowired
    public APIExceptionHandler(ErrorAttributes errorAttributes) {
        super(errorAttributes);
        this.errorAttributes = errorAttributes;
    }

    @RequestMapping(path = ERROR_PATH)
    public ResponseEntity<?> handleError(HttpServletRequest request) {
        HttpStatus status = getStatus(request);

        Map<String, Object> errors = getErrorAttributes(request, false);
        getApiException(request).ifPresent(apiError -> {
            errors.put("message" , apiError.message());
            errors.put("code", apiError.code());
        });
        // If you don't want to expose exception!
        errors.remove("exception");


        return ResponseEntity.status(status).body(errors);
    }

    @Override
    public String getErrorPath() {
        return ERROR_PATH;
    }

    private Optional<APIException> getApiException(HttpServletRequest request) {
        RequestAttributes attributes = new ServletRequestAttributes(request);
        Throwable throwable = errorAttributes.getError(attributes);
        if (throwable instanceof APIException) {
            APIException exception = (APIException) throwable;
            return Optional.of(exception);
        }

        return Optional.empty();
    }
}

如果您想返回一些消息或使用错误代码进行测试,我想您可以这样做

@ResponseBody
public ResponseEntity somthing() {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json; charset=utf-8");
return new ResponseEntity<>(new Gson().toJson("hello this is my message"), headers, HttpStatus.NOT_FOUND);
}
@ResponseBody
公众的反应{
HttpHeaders=新的HttpHeaders();
添加(“内容类型”、“应用程序/json;字符集=utf-8”);
返回新的ResponseEntity(new Gson().toJson(“你好,这是我的消息”)、headers、HttpStatus.NOT_FOUND);
}

谢谢你,阿里,但这样我无法定义消息。我尝试在@ResponseStatus(value=HttpStatus.NOT_FOUND,reason=“Resource NOT FOUND”)中添加reason属性,但是响应类似于{“message”:“error.404”,“description”:“Resource NOT FOUND”,“fieldErrors”:null},通过这种方式抛出,返回可选的.ofNullable(entity).map(result->new ResponseEntity)(result,HttpStatus.OK)).orelsetrow(HTTPNotFoundException::new);您知道我是否可以轻松地记录使用
@ResponseStatus
映射的所有异常吗?此代码不起作用:errorAttributes.getError预期的WebRequest不是RequestAttributes
@ResponseBody
public ResponseEntity somthing() {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json; charset=utf-8");
return new ResponseEntity<>(new Gson().toJson("hello this is my message"), headers, HttpStatus.NOT_FOUND);
}