springmvc中的异常处理程序

qfe3c7zg  于 2021-06-29  发布在  Java
关注(0)|答案(3)|浏览(343)

我想创建一个异常处理程序,它将拦截我的项目中的所有控制器。这可能吗?看起来我必须在每个控制器中放置一个处理程序方法。谢谢你的帮助。我有一个spring控制器,它发送json响应。因此,如果发生异常,我想发送一个可以从一个地方控制的错误响应。

insrf1ej

insrf1ej1#

定义异常处理程序的抽象类。然后让你的控制器继承它。

ep6jt1vc

ep6jt1vc2#

(我在Spring3.1中找到了一种实现它的方法,这个答案的第二部分对此进行了描述)
见第16.11章Spring参考异常处理
有比使用更多的方法 @ExceptionHandler (见古基的回答)
您可以实现一个handlerexceptionresolver(使用servlet而不是portlet包),它是某种全局@exceptionhandler
如果没有异常的特定逻辑,而只有特定视图,那么可以使用simplemappingexceptionresolver,它至少是 HandlerExceptionResolver 您可以在其中指定异常名称模式和抛出异常时显示的视图(jsp)。例如:

<bean
   class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"
   p:defaultErrorView="uncaughtException">
   <property name="exceptionMappings">
       <props>
           <prop key=".DataAccessException">dataAccessFailure</prop>
           <prop key=".TypeMismatchException">resourceNotFound</prop>
           <prop key=".AccessDeniedException">accessDenied</prop>
        </props>
    </property>
 </bean>

在Spring3.2+中,可以用 @ControllerAdvice ,全部 @ExceptionHandler 这个类中的方法以全局方式工作。
在Spring3.1中没有 @ControllerAdvice . 但只要稍加修改,就可以拥有类似的功能。
关键是对道路的理解 @ExceptionHandler 作品。在Spring3.1中有一个类 ExceptionHandlerExceptionResolver . 这个类实现(借助于它的超类)接口 HandlerExceptionResolver 负责调用 @ExceptionHandler 方法。
这个 HandlerExceptionResolver 接口只有一种方法:

ModelAndView resolveException(HttpServletRequest request,
                              HttpServletResponse response,
                              Object handler,
                              Exception ex);`.

当请求由Spring3.x控制器方法处理时,则此方法(由 org.springframework.web.method.HandlerMethod )是 handler 参数。
这个 ExceptionHandlerExceptionResolver 使用 handler ( HandlerMethod )获取控制器类并扫描它以查找带注解的方法 @ExceptionHandler . 如果其中一个方法与异常匹配( ex )然后调用这些方法来处理异常(其他 null 返回,以表示此异常解析程序没有责任)。
第一个想法是实现一个自己的 HandlerExceptionResolver 表现得像 ExceptionHandlerExceptionResolver ,而不是搜索 @ExceptionHandler 在控制器类中,它应该在一个特殊的bean中搜索它们。缺点是必须复制(或子类 ExceptionHandlerExceptionResolver )并且必须)手动配置所有nice消息转换器、参数解析器和返回值处理程序(只有真实的配置) ExceptionHandlerExceptionResolver 由Spring自动完成)。所以我想出了另一个主意:
实现一个简单的 HandlerExceptionResolver 将异常“转发”到(已配置) ExceptionHandlerExceptionResolver ,但带有修改的 handler 它指向包含全局异常处理程序的bean(我称它们为全局异常处理程序,因为它们为所有控制器做工作)。
这就是实现: GlobalMethodHandlerExeptionResolver ```
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;

public class GlobalMethodHandlerExeptionResolver
implements HandlerExceptionResolver, Ordered {

@Override
public int getOrder() {
    return -1; //
}

private ExceptionHandlerExceptionResolver realExceptionResolver;

private List<GlobalMethodExceptionResolverContainer> containers;

@Autowired
public GlobalMethodHandlerExeptionResolver(
        ExceptionHandlerExceptionResolver realExceptionResolver,
        List<GlobalMethodExceptionResolverContainer> containers) {
    this.realExceptionResolver = realExceptionResolver;
    this.containers = containers;
}

@Override
public ModelAndView resolveException(HttpServletRequest request,
                                     HttpServletResponse response,
                                     Object handler,
                                     Exception ex) {              
    for (GlobalMethodExceptionResolverContainer container : this.containers) {    
        ModelAndView result = this.realExceptionResolver.resolveException(
                request,
                response,
                handlerMethodPointingGlobalExceptionContainerBean(container),
                ex);
        if (result != null)
            return result;
    }
    // we feel not responsible
    return null;
}

protected HandlerMethod handlerMethodPointingGlobalExceptionContainerBean(
                           GlobalMethodExceptionResolverContainer container) {
    try {
        return new HandlerMethod(container,
                                 GlobalMethodExceptionResolverContainer.class.
                                      getMethod("fakeHanderMethod"));            
    } catch (NoSuchMethodException | SecurityException e) {
        throw new RuntimeException(e);
    }            
}

}

全局处理程序必须实现这个接口(以便找到并实现 `fakeHanderMethod` 用于 `handler` ```
public interface GlobalMethodExceptionResolverContainer {
    void fakeHanderMethod();
}

全局处理程序的示例:

@Component
public class JsonGlobalExceptionResolver
             implements GlobalMethodExceptionResolverContainer {

    @Override
    public void fakeHanderMethod() {
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public ValidationErrorDto handleMethodArgumentNotValidException(
                MethodArgumentNotValidException validationException,
                Locale locale) {

         ...
         /* map validationException.getBindingResult().getFieldErrors()
          * to ValidationErrorDto (custom class) */
         return validationErrorDto;
    }
}

顺便说一句:您不需要注册 GlobalMethodHandlerExeptionResolver 因为spring会自动注册所有实现 HandlerExceptionResolver 对于异常解析程序。这么简单 <bean class="GlobalMethodHandlerExeptionResolver"/> 够了。

eqfvzcg8

eqfvzcg83#

从Spring3.2开始,您可以使用@controlleradvice注解。您可以在@controlleradvice类中声明@exceptionhandler方法,在这种情况下,它处理来自所有控制器的@requestmapping方法的异常。

@ControllerAdvice
public class MyGlobalExceptionHandler {

    @ExceptionHandler(value=IOException.class)
    public @ResponseBody String iOExceptionHandler(Exception ex){
        //
        //
    }

    // other exception handler methods
    // ...

}

相关问题