spring异常处理程序不处理某些类型的异常

时间:2011-02-23 17:23:35

标签: exception-handling spring-mvc spring-security

我在我的spring 2.5 app中设置了一个简单的异常处理程序。目前它捕获所有Exception并显示堆栈跟踪页面。

这很好,但是现在Spring安全性没有正确地将未登录用户踢到登录页面,而是显示了弹出安全例外的异常页面:

org.springframework.security.AccessDeniedException

问题是这个应用程序没有自己的Exception子类,它用于它的所有Exceptions,所以我必须映射Exception但是unmap AccessDeniedException

这可能在春季2.5?

编辑:使用spring security 2.0.1

我的bean看起来像这样

<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <property name="exceptionMappings">
        <props>
            <prop key="java.lang.RuntimeException">common/error</prop>
        </props>
    </property>
</bean>**

6 个答案:

答案 0 :(得分:7)

处理此问题的一种方法是创建另一个实现 org.springframework.web.servlet.HandlerExceptionResolver org.springframework.core.Ordered 接口的处理程序。在您自己的实现中,您执行以下操作:

public class AccessDeniedExceptionResolver implements HandlerExceptionResolver, Ordered
{
    private int order;

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception)
    {
        if(exception instanceof AccessDeniedException)
        {
            return new ModelAndView("redirect:/login"); //Replace with redirect to your login-page
        }

        return null; //Null-return = pass the exception to next handler in order
    }

    public void setOrder(int order)
    {
        this.order = order;
    }

    @Override
    public int getOrder()
    {
        return order;
    }   
}

现在,Ordered接口实现允许您告诉调用异常处理程序的顺序。 SimpleMappingExceptionResolver 也实现了Ordered接口,因此您可以在bean定义中执行类似的操作:

<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <property name="exceptionMappings">
        <props>
            <prop key="java.lang.RuntimeException">common/error</prop>
        </props>
    </property>
    <property name="order" value="1"/>
</bean>

<bean class="package.to.your.handler.AccessDeniedExceptionResolver">
    <property name="order" value="0"/>
</bean>

具有LOWER order-value的bean具有更高的优先级(意味着它将在具有更大值的bean之前被调用,在这种情况下,在SimpleMappingExceptionResolver之前调用AccessDeniedExceptionResolver。

希望这会有所帮助。

答案 1 :(得分:4)

我们处理这个的方法是有一个自定义异常解析器类来处理其他处理程序没有捕获的任何异常 - 它实现了HandlerExceptionResolver,Ordered。

我们声明一个单独的SimpleMappingExceptionResolver bean来捕获特定的异常。

排序是这样的,我们的自定义解析器在SimpleMappingExceptionResolver之后运行。

结果是指定的异常(例如AccessDeniedException)由SimpleMappingExceptionResolver处理并定向到适当的页面。

自定义解析程序处理任何其他运行时异常,转发到通用错误页面。

<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <property name="exceptionMappings">
        <props>
            <prop key="org.springframework.security.AccessDeniedException">accessDenied</prop>
            <prop key="org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException">accessDenied</prop>
        </props>
    </property>
    <property name="order" value="0"/>
</bean>

<bean class="package.to.your.handler.DefaultExceptionResolver">
    <property name="order" value="1"/>
</bean>

这种安排允许您使用Spring解析器捕获尽可能多的异常(我在这里捕获2,AccessDenied和HibernateOptimisticLockingFailureException),其他一切都被自定义解析器捕获。在上面接受的解决方案中,您必须编写更多Java代码来捕获除AccessDenied之外的异常。

答案 2 :(得分:2)

根据Kartoch的回答,在您的映射中,您有几个选择。您可以在要捕获的异常中更具体,而不是RuntimeException,或者,您可以为AccessDeniedExcpetion的处理程序指定登录视图。像redirect:/ login?err = 401的视图名称。

查看此处完成的配置

http://www.mkyong.com/spring-mvc/spring-mvc-exception-handling-example/

他用一个bean处理多个异常的地方。您也可以这样做并重定向到您的登录视图。唯一的问题是它是否接受配置中的重定向:/ viewname,而我现在无法对其进行测试。

答案 3 :(得分:1)

另一个选择:创建一个SimpleMappingExceptionResolver的子类,它能够排除某些异常类(在你的情况下保留默认处理)。

public class ExclusionExceptionResolver extends SimpleMappingExceptionResolver implements InitializingBean {
  private Class[] excludedClasses;

  @Override
  protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
    for (Class<?> excludedClass : excludedClasses) {
      if (excludedClass.isInstance(ex)) {
        return null;
      }
    }
    return super.doResolveException(request, response, handler, ex);
  }
  public void setExcludedClasses(Class[] excludedClasses) {
    this.excludedClasses = excludedClasses;
  }

  @Override
  public void afterPropertiesSet() throws Exception {
    if (excludedClasses == null) {
      excludedClasses = new Class[]{};
    }
  }
}

答案 4 :(得分:1)

我已经晚了很多年,但是我遇到了这个确切的问题,所有提议的解决方案都无法很好地工作。

我发现,如果我从全部处理程序中抛出异常,那么Spring的默认处理程序将启动:

@ControllerAdvice
@Order(value = Ordered.LOWEST_PRECEDENCE) // Not enough, unfortunately
public class GeneralExceptionHandler {
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    public String processOtherExceptions(Exception ex) throws Exception {
        if (ex instanceof AccessDeniedException) {
            throw ex;
        }

        // Handler for other exceptions - log it and return some generic message.
        log.error("Uncaught exception", ex);
        return "Internal error";
    }

答案 5 :(得分:0)

似乎SimpleMappingExceptionHandler有一个属性MappedHandlerClasses,这是你正在寻找的,因为它可以接受一组例外。