Spring MV 3.2异常响应映射 [英] Spring MV 3.2 Exception Response Mapping

查看:149
本文介绍了Spring MV 3.2异常响应映射的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Spring 3.2.15,基于MVC的REST API这里( not Spring Boot,可悲的是)。我试图实现符合以下条件的异常映射器/处理程序:




  • 无论发生什么(成功或错误),Spring应用程序总是返回一个响应实体 MyAppResponse (见下文);和

  • 如果成功处理请求,返回HTTP状态为200(典型值);和

  • 在处理请求并发生异常的情况下,我需要将特定异常的映射控制到特定的HTTP状态代码


    • Spring MVC框架错误(例如 BlahException )必须映射到HTTP 422

    • 自定义应用程序例外,例如我的 FizzBu​​zzException 有自己的状态映射方案:


      • FizzBu​​zzException - > HTTP 401

      • FooBarException - > HTTP 403

      • OmgException - > HTTP 404


    • 所有其他异常, Spring例外和非定制应用程序例外(上面列出的3个)应该产生一个HTTP 500




其中 MyAppResponse 对象是:

  / Groovy伪代码
@Canonical
class MyAppResponse {
String detail
String randomNumber
}

出现 ResponseEntityExceptionHandler 可能可以为我做这个,但我没有看到森林通过树木wrt它如何被传递参数。我希望我可以做一些像:

  // Groovy-伪代码
@ControllerAdvice
MyAppExceptionMapper类扩展了ResponseEntityExceptionHandler {
ResponseEntity< Object> handleFizzBu​​zzException(FizzBu​​zzException fbEx,HttpHeaders头,HttpStatus状态){
// TODO:如何将状态重置为401?
status = ???

new ResponseEntity(fbEx.message,headers,status)
}

ResponseEntity< Object> handleFooBarException(FooBarException fbEx,HttpHeaders头,HttpStatus状态){
// TODO:如何将状态重置为403?
status = ???

new ResponseEntity(fbEx.message,headers,status)
}

ResponseEntity< Object> handleOmgException(OmgException omgEx,HttpHeaders头,HttpStatus状态){
// TODO:如何将状态重置为404?
status = ???

new ResponseEntity(omgEx.message,headers,status)
}

//现在将所有Spring生成的异常映射到422
ResponseEntity< Object> ; handleAllSpringExceptions(SpringException springEx,HttpHeaders头,HttpStatus状态){
// TODO:如何将状态重置为422?
status = ???

new ResponseEntity(springEx.message,headers,status)
}

//其他都是一个500 ...
ResponseEntity< Object> handleAllOtherExceptions(Exception ex,HttpHeaders headers,HttpStatus status){
// TODO:如何将状态重置为500?
status = ???

new ResponseEntity(糟糕,发生了什么事,Lol。,标题,状态)
}
}

任何想法我如何可以完全实现这个映射逻辑,以及实体要求是一个 MyAppResponse 实例,而不是只是一个字符串?



然后,使用 @ControllerAdvice 注释类,我唯一​​需要做的配置Spring使用它?

解决方案

为了减少@ bond-java-bond答案,您不需要构建 ResponseEntity 自己:


  1. 使用 @ResponseStatus 对于每个 handleSomeException 方法(例如 @ResponseStatus(HttpStatus.UNAUTHORIZED)

  2. 从这些方法返回自定义 MyAppResponse

但是,如果每种异常将以相同的方式处理(仅通过HTTP状态的差异)我建议减少 MyAppEx ceptionMapper 像这样:

  @ControllerAdvice 
public class MyAppExceptionMapper {
private最终地图< Class<?>,HttpStatus>地图;
{
map = new HashMap<>();
map.put(FizzBu​​zzException.class,HttpStatus.UNAUTHORIZED);
map.put(FooBarException.class,HttpStatus.FORBIDDEN);
map.put(NoSuchRequestHandlingMethodException.class,HttpStatus.UNPROCESSABLE_ENTITY);
/ *列出Spring特定的异常,如@ bond-java-bond建议* /
map.put(Exception.class,HttpStatus.INTERNAL_SERVER_ERROR);
}

//处理所有异常
@ExceptionHandler(Exception.class)
@ResponseBody
public ResponseEntity< MyAppResponse> handleException(异常异常){
MyAppResponse response = new MyAppResponse();
//填写响应细节

HttpStatus status = map.get(exception.getClass());
if(status == null){
status = map.get(Exception.class); //默认
}

返回新的ResponseEntity<> (回应,状态);
}
}

优点:


  1. 相当短暂。

  2. 没有代码重复。

  3. 稍微更有效。
  4. 易于扩展。

此外,您可以将映射配置移动到外部并注入。

如何配置MVC Dispatcher Servlet



首先,检查 mvc-dispatcher-servlet.xml (或另一个 contextConfigLocation web.xml )包含:

 < context:component-scan base-package =base.package/> 
< mvc:注释驱动/>

其次,检查@ControllerAdvice注释类和@Controller注释类是否都属于<$ c的子包$ c> base.package 。



请参阅 Spring MVC中的异常处理 Spring MVC @ExceptionHandler示例了解更多详细信息。


Spring 3.2.15, MVC-based REST API here (not Spring Boot, sadly!). I am trying to implement an exception mapper/handler that meets the following criteria:

  • No matter what happens (success or error), the Spring app always returns a response entity of MyAppResponse (see below); and
  • In the event of processing a request successfully, return an HTTP status of 200 (typical); and
  • In the event of processing a request and an exception occurs, I need to control the mapping of the specific exception to a particular HTTP status code
    • Spring MVC framework errors (such as BlahException) must map to HTTP 422
    • Custom app exceptions, such as my FizzBuzzException have their own status mapping schemes:
      • FizzBuzzException -> HTTP 401
      • FooBarException -> HTTP 403
      • OmgException -> HTTP 404
    • All other exceptions, that is, non-Spring exceptions, and non-custom app exceptions (the 3 listed above), should produce an HTTP 500

Where the MyAppResponse object is:

// Groovy pseudo-code
@Canonical
class MyAppResponse {
    String detail
    String randomNumber
}

It appears like ResponseEntityExceptionHandler might be able to do this for me, but I'm not seeing the forest through the trees w.r.t. how it gets passed arguments. I'm hoping I can do something like:

// Groovy-pseudo code
@ControllerAdvice
class MyAppExceptionMapper extends ResponseEntityExceptionHandler {
    ResponseEntity<Object> handleFizzBuzzException(FizzBuzzException fbEx, HttpHeaders headers, HttpStatus status) {
        // TODO: How to reset status to 401?
        status = ???

        new ResponseEntity(fbEx.message, headers, status)
    }

    ResponseEntity<Object> handleFooBarException(FooBarException fbEx, HttpHeaders headers, HttpStatus status) {
        // TODO: How to reset status to 403?
        status = ???

        new ResponseEntity(fbEx.message, headers, status)
    }

    ResponseEntity<Object> handleOmgException(OmgException omgEx, HttpHeaders headers, HttpStatus status) {
        // TODO: How to reset status to 404?
        status = ???

        new ResponseEntity(omgEx.message, headers, status)
    }

    // Now map all Spring-generated exceptions to 422
    ResponseEntity<Object> handleAllSpringExceptions(SpringException springEx, HttpHeaders headers, HttpStatus status) {
        // TODO: How to reset status to 422?
        status = ???

        new ResponseEntity(springEx.message, headers, status)
    }

    // Everything else is a 500...
    ResponseEntity<Object> handleAllOtherExceptions(Exception ex, HttpHeaders headers, HttpStatus status) {
        // TODO: How to reset status to 500?
        status = ???

        new ResponseEntity("Whoops, something happened. Lol.", headers, status)
    }
}

Any idea how I can fully implement this mapping logic and the requirement for the entity to be a MyAppResponse instance and not just a string?

Then, is annotating the class with @ControllerAdvice the only thing that I need to do to configure Spring to use it?

解决方案

To reduce @bond-java-bond answer you do not need to build ResponseEntity by yourself:

  1. Use @ResponseStatus for each handleSomeException method (e.g. @ResponseStatus(HttpStatus.UNAUTHORIZED))
  2. Return custom MyAppResponse from those methods

But if each kind of exceptions will be processed by the same way (diffs by HTTP status only) I suggest to reduce MyAppExceptionMapper like this:

@ControllerAdvice
public class MyAppExceptionMapper {
    private final Map<Class<?>, HttpStatus> map;
    {
        map = new HashMap<>();
        map.put(FizzBuzzException.class, HttpStatus.UNAUTHORIZED);
        map.put(FooBarException.class, HttpStatus.FORBIDDEN);
        map.put(NoSuchRequestHandlingMethodException.class, HttpStatus.UNPROCESSABLE_ENTITY);
        /* List Spring specific exceptions here as @bond-java-bond suggested */
        map.put(Exception.class, HttpStatus.INTERNAL_SERVER_ERROR);
    }

    // Handle all exceptions
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ResponseEntity<MyAppResponse> handleException(Exception exception) {
        MyAppResponse response = new MyAppResponse();
        // Fill response with details

        HttpStatus status = map.get(exception.getClass());
        if (status == null) {
            status = map.get(Exception.class);// By default
        }

        return new ResponseEntity<>(response, status);
    }
}

Pros:

  1. Pretty short.
  2. No code duplication.
  3. Slightly more effective.
  4. Easy to extend.

Also, you can move mapping configuration outside and inject it.

How to configure MVC Dispatcher Servlet

First of all, check if mvc-dispatcher-servlet.xml (or another contextConfigLocation from web.xml) contains:

<context:component-scan base-package="base.package"/>
<mvc:annotation-driven/>

Secondly, check if @ControllerAdvice annotated class and @Controller annotated class both belong to subpackage of base.package.

See complete examples at Exception Handling in Spring MVC or Spring MVC @ExceptionHandler Example for more details.

这篇关于Spring MV 3.2异常响应映射的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆