我想创建一个异常处理程序,它将拦截我的项目中的所有控制器。这可能吗?看起来我必须在每个控制器中放置一个处理程序方法。谢谢你的帮助。我有一个spring控制器,它发送json响应。因此,如果发生异常,我想发送一个可以从一个地方控制的错误响应。
insrf1ej1#
定义异常处理程序的抽象类。然后让你的控制器继承它。
ep6jt1vc2#
(我在Spring3.1中找到了一种实现它的方法,这个答案的第二部分对此进行了描述)见第16.11章Spring参考异常处理有比使用更多的方法 @ExceptionHandler (见古基的回答)您可以实现一个handlerexceptionresolver(使用servlet而不是portlet包),它是某种全局@exceptionhandler如果没有异常的特定逻辑,而只有特定视图,那么可以使用simplemappingexceptionresolver,它至少是 HandlerExceptionResolver 您可以在其中指定异常名称模式和抛出异常时显示的视图(jsp)。例如:
@ExceptionHandler
HandlerExceptionResolver
<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 接口只有一种方法:
@ControllerAdvice
ExceptionHandlerExceptionResolver
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;
org.springframework.web.method.HandlerMethod
handler
HandlerMethod
ex
null
GlobalMethodHandlerExeptionResolver
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 GlobalMethodHandlerExeptionResolverimplements 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"/> 够了。
<bean class="GlobalMethodHandlerExeptionResolver"/>
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 // ... }
3条答案
按热度按时间insrf1ej1#
定义异常处理程序的抽象类。然后让你的控制器继承它。
ep6jt1vc2#
(我在Spring3.1中找到了一种实现它的方法,这个答案的第二部分对此进行了描述)
见第16.11章Spring参考异常处理
有比使用更多的方法
@ExceptionHandler
(见古基的回答)您可以实现一个handlerexceptionresolver(使用servlet而不是portlet包),它是某种全局@exceptionhandler
如果没有异常的特定逻辑,而只有特定视图,那么可以使用simplemappingexceptionresolver,它至少是
HandlerExceptionResolver
您可以在其中指定异常名称模式和抛出异常时显示的视图(jsp)。例如:在Spring3.2+中,可以用
@ControllerAdvice
,全部@ExceptionHandler
这个类中的方法以全局方式工作。在Spring3.1中没有
@ControllerAdvice
. 但只要稍加修改,就可以拥有类似的功能。关键是对道路的理解
@ExceptionHandler
作品。在Spring3.1中有一个类ExceptionHandlerExceptionResolver
. 这个类实现(借助于它的超类)接口HandlerExceptionResolver
负责调用@ExceptionHandler
方法。这个
HandlerExceptionResolver
接口只有一种方法:当请求由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 {
}
全局处理程序的示例:
顺便说一句:您不需要注册
GlobalMethodHandlerExeptionResolver
因为spring会自动注册所有实现HandlerExceptionResolver
对于异常解析程序。这么简单<bean class="GlobalMethodHandlerExeptionResolver"/>
够了。eqfvzcg83#
从Spring3.2开始,您可以使用@controlleradvice注解。您可以在@controlleradvice类中声明@exceptionhandler方法,在这种情况下,它处理来自所有控制器的@requestmapping方法的异常。