我开发了一个用于管理useres的应用程序spring-boot。我需要像这个对象一样处理异常:
{
"general_errors": "service_unavailable"
"errors": [
{
"key": "email",
"value": "is empty"
},
{
"key": "postal_code",
"value": "required"
}
]
}
例如,在我的服务方面,当验证是KO时,我需要将其添加到错误列表中。这样的事情:
if (email == null )
errors.addToErrorList("email", "is empty"
...
然后是否存在运行时异常
try {
...
}catch (InterruptedException e){
errors.addgeneral("general_errors", e.getMessage());
}
你有什么想法我能做到吗?
我试过@ControllerAdvice但是我不知道如何实现它
@ControllerAdvice
@RestController
public class GlobalExceptionHandler {
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(value = BaseException.class)
public ErrorResponseWrapper handleBaseException(BaseException e) {
ErrorResponseWrapper error = new ErrorResponseWrapper();
// error.setMessage(e.getMessage());
return error;
}
祝你好运
答案 0 :(得分:2)
要正确处理验证错误,您可以使用JSR-303网络附带的Spring。例如,假设您的控制器有两个参数postalCode
和email
。您可以创建一个名为ApiParameters
的对象:
public class ApiParameters {
@NotNull(message = "is empty")
@Email(message = "is not an email")
private String email;
@NotNull(message = "is required")
private String postalCode;
public ApiParameters() {
}
// Getters + Setters
}
现在,在您的控制器上,您现在可以放置:
@GetMapping
public String doStuff(@Valid ApiParameters parameters) {
// ...
}
由于@Valid
注释,如果任何参数错误,则抛出BindException
,您可以在控制器建议类中捕获,如下所示:
@ControllerAdvice
public class ErrorHandler {
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(BindException.class)
@ResponseBody
public ErrorResponse errorResponse(BindException ex) {
return new ErrorResponse("Validation failed", ex.getFieldErrors()
.stream()
.map(err -> new SpecificError(err.getField(), err.getDefaultMessage()))
.collect(Collectors.toList()));
}
}
这里发生的是我调用getFieldErrors()
的{{1}}方法,其中包含所有错误的列表。然后我将这些映射到类似于您想要的响应的响应类(BindException
和ErrorResponse
):
SpecificErorr
如果您使用参数不足调用API,现在将获得以下JSON响应:
public class ErrorResponse {
@JsonProperty("general_errors")
private String generalErrors;
private List<SpecificError> errors;
public ErrorResponse(String generalErrors, List<SpecificError> errors) {
this.generalErrors = generalErrors;
this.errors = errors;
}
public String getGeneralErrors() {
return generalErrors;
}
public List<SpecificError> getErrors() {
return errors;
}
}
public class SpecificError {
private String key;
private String value;
public SpecificError(String key, String value) {
this.key = key;
this.value = value;
}
public String getKey() {
return key;
}
public String getValue() {
return value;
}
}
与此类似,您也可以抓住{
"errors": [
{
"key": "postalCode",
"value": "is required"
},
{
"key": "email",
"value": "is empty"
}
],
"general_errors": "Validation failed"
}
:
RuntimeException
但是,如果要将两者结合起来,则必须手动调用验证器,因为它的工作方式是抛出异常后,它将停止处理该方法。
这意味着如果您的方法抛出@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(RuntimeException.class)
@ResponseBody
public ErrorResponse errorResponse(RuntimeException ex) {
return new ErrorResponse(ex.getMessage(), null);
}
,如果已经抛出验证错误,则不会发生这种情况。
答案 1 :(得分:0)
我真的很喜欢这种模式。这是我的实施:
@ControllerAdvice
public class GlobalExceptionHandler {
private final Logger LOG = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(RuntimeException.class)
@ResponseBody
public ResponseEntity<ErrorWrapper> RunTimeException(RuntimeException e) {
e.printStackTrace();
LOG.error("Error: {}", e.getMessage());
return new ResponseEntity<ErrorWrapper>(new ErrorWrapper(e.getMessage()), HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(ValidationException.class)
@ResponseBody
public ResponseEntity<List<ValidationError>> validationExceptionHandle(ValidationException e) {
e.printStackTrace();
return new ResponseEntity<List<ValidationError>>(e.getErrors(), HttpStatus.BAD_REQUEST);
}
}
这是我的验证方法:
private void validate(VisitTO to) {
List<ValidationError> errors = new ArrayList<>();
Visit visit = new Visit();
if (to.getDate() == null) {
LOG.error("Date was null.");
errors.add(new ValidationError("date", MAY_NOT_BE_NULL));
} else {
Calendar cal = Calendar.getInstance();
cal.setTime(to.getDate());
if (cal.get(Calendar.HOUR_OF_DAY) < 15 || cal.get(Calendar.HOUR_OF_DAY) > 18) {
errors.add(new ValidationError("date", NOT_ALLOWED));
}
to.setDate(roundTime(to.getDate()));
}
if (to.getId() != null) {
LOG.error("Id wasn't null.");
errors.add(new ValidationError("id", NOT_ALLOWED));
}
if (to.getUserUuid() == null) {
LOG.error("UUID was null.");
errors.add(new ValidationError("user.uuid", MAY_NOT_BE_NULL));
} else {
if (!LoggedUserUtils.isDoctor(LoggedUserUtils.getLoggedUser())) {
if (!to.getUserUuid().equals(LoggedUserUtils.getLoggedUser().getPesel())) {
throw new SecurityException();
}
}
}
if (to.getCompleted() == null ) {
LOG.error("Completed was null.");
errors.add(new ValidationError("completed", MAY_NOT_BE_NULL));
}
if (userRepository.findByPesel(to.getUserUuid()) == null) {
LOG.error("User not found.");
errors.add(new ValidationError("pesel", NO_SUCH_USER));
}
if (!errors.isEmpty()){
throw new ValidationException(errors);
}
}