如何使用自定义参数注释 return 自定义 spring 错误响应?

how to return a custom spring error response with custom parameter annotations?

我是 spring 的新手,所以请原谅我的无知。 当给定的方法参数 "required" 为空时,我正在尝试 "return" 自定义响应。 来自 spring 的当前回复是:

{
  "timestamp": 1477060294961,
  "status": 400,
  "error": "Bad Request",
  "exception": "org.springframework.web.bind.MissingServletRequestParameterException",
  "message": "Required String parameter 'bookname' is not present",
  "path": "/getbook"
}

我正在努力达到 "returns":

{
  "status": 400,
  "error": {
    // custom error body
  }
}

我认为一个很好的方法是自定义 "parameter annotation"。这也将使代码更具可读性并存储有关此端点参数的有用信息。

我遵循了给定的示例 ,但我不确定在哪里或如何 return 自定义响应?

到目前为止我有注释:

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface customParameter {

String value() default "";
boolean required() default false;
String defaultValue() default ValueConstants.DEFAULT_NONE;
String customInfo() default  "blar blar";
}

"endpoint" :

  @RequestMapping(value = "/getbook", method = {RequestMethod.POST})
  public ResponseEntity<BookResponse> getBookInfo(
      @customParameter(value = "bookname", required = true, customInfo = "extremely valuable book")
      final String bookname
   ) {
    return new bookRequest(bookname).getResponse;
}

并有一个自定义解析器:

public class CustomAnnotationResolver implements HandlerMethodArgumentResolver {


  @Override
  public boolean supportsParameter(MethodParameter parameter) {
    return parameter.getParameterAnnotation(customParameter.class) != null;
  }


  @Override
  public Object resolveArgument(MethodParameter methodparameter, ModelAndViewContainer mavContainer,
      NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

    CustomParameter customParameter = methodparameter.getParameterAnnotation(CustomParameter.class);

    String parameter = webRequest.getParameter(CustomParameter.value());

    // todo: do Validation here
    if (customParameter == null) {
      if (Parameter.required()) {
        String customInfo = customParameter.customInfo();
        String body getBody(customInfo);
        new ResponseEntity(body, 400); // so the problem is here!! how do I return this response??  
      }
    }

    return webRequest.getParameter(customParameter.value());

  }
}

我也有 "registered" 这个带有 webConfig 的解析器:

@EnableWebMvc
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {

  @Override
  public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
    argumentResolvers.add(new CustomAnnotationResolver());
  }
}

任何有关此实现的帮助或任何其他有关如何执行此操作的建议都将非常棒。谢谢大家:)

如果您需要自定义 MissingServletRequestParameterException 处理,我会将其添加到控制器或控制器建议中:

@ExceptionHandler
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Map<String, Object> handleMissingParam(MissingServletRequestParameterException e) {


    Map<String, Object> result = new HashMap();

    result.put("status", Integer.toString(400));

    Map<String, String> error = new HashMap();
    error.put("param", e.getParameterName());

    result.put("error", error);
    return result;
}

您当然可以将 Map 的用法替换为 java 对象。我个人建议您使用原始错误处理,除非您有真正的理由。

谢谢@growlingchaos,太棒了,这就是解决方案。

@ControllerAdvice
@RestController
public class customExceptionAdvice {

  @ExceptionHandler(Exception.class)
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  public ResponseEntity handleConflict(BadRequestException e, HttpServletResponse response)
      throws IOException {

    return new ResponseEntity(e.getErrorBody(), HttpStatus.BAD_REQUEST);
  }

我要迟到了,这是一个简单的示例,说明如何捕获 rumtime 错误并以简单的方式翻译响应。

翻译控制器:

@ControllerAdvice
public class ExceptionTranslator {

private final Logger log = LoggerFactory.getLogger(ExceptionTranslator .class);

@ExceptionHandler(RuntimeException.class)
public ResponseEntity<ErrorDTO> processRuntimeException(HttpServletRequest req, RuntimeException ex) throws Exception {
    ErrorDTO errorDTO;
    ResponseStatus responseStatus = AnnotationUtils.findAnnotation(ex.getClass(), ResponseStatus.class);
    if (responseStatus != null) {
        errorDTO = new ErrorDTO(req.getRequestURI(), responseStatus.value().toString(), ex.getMessage());
    } else {
        errorDTO = new ErrorDTO(req.getRequestURI(), HttpStatus.INTERNAL_SERVER_ERROR.toString(), ex.getMessage());
    }
    log.debug(errorDTO.toString());
    return new ResponseEntity(errorDTO, HttpStatus.valueOf(Integer.valueOf(errorDTO.getCode())));
}
}

DTO class 定义要显示的属性

public class ErrorDTO implements Serializable {

    private static final long serialVersionUID = 1L;

    private final String uri;
    private final String code;
    private final String description;

    public ErrorDTO(String message) {
        this(null, message, null);
    }

    public ErrorDTO(String uri, String code, String description) {
        this.uri = uri;
        this.code = code;
        this.description = description;
    }

    public String getUri() {
       return uri;
    }

    public String getCode() {
       return code;
    }

    public String getDescription() {
        return description;
    }

    @Override
    public String toString() {
        return "ErrorDTO{" + "uri=" + uri + ", code=" + code + ", description=" + description + '}';
    }
 }