0

注意: 跳到底部的两个更新以找到答案。

我有一个在 Tomcat 上运行的 Spring (3) MVC Web 应用程序。此 Web 应用程序用作远程 WSDL 服务层的 UI。我编写了一个自定义 AuthenticationProvider 来验证这个远程服务。这很好用。我的问题是这样的:

每个控制器方法或多或少都会导致对该远程 WSDL 的远程调用。我的计划是不让 Tomcat 或 Spring 过期会话,而是等到远程服务器告诉我会话已经过期,然后将用户重新路由到登录页面,告诉他们他们的会话已经过期。

BaseController 是所有其他 Controller 扩展的基础,具有以下方法:

protected void addBindingErrors(HttpSession session, MTAResponse response, BindingResult binding, boolean allowDefault) {
switch (response.getResponseCode()) {
case SESSION_EXPIRED:
     UserInfo nfo = (UserInfo)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
     SecurityContext context = SecurityContextHolder.getContext();
     System.out.println("token in handle session expired: " + nfo.getMtaCoreSessionId());
     if(session != null){
          System.out.println("invalidating session");
          session.invalidate();
          //1.  throw new SessionAuthenticationException("session expiredd");
          ModelAndView mav = new ModelAndView("error");
          throw new ModelAndViewDefiningException(mav);
          //3.  something else?
     }
     context.setAuthentication(null);
  break;      
case INVALID_PARAMETER_VALUE:
  binding.addError(...);
  break;
case ACCESS_DENIED:
  binding.addError(...);
  break;          
default:
  if(allowDefault){
    binding.addError(...);
    break;
  }
}

}

我找到了几个解决方案,但我是 Spring 新手,所以我不知道它们是否是“正确”的解决方案,或者是否存在潜伏在其中的问题。

  1. (有点作弊) BaseController.addBindingError() 方法中,如果收到远程会话过期代码,则抛出 SessionAuthenticationException
    • 优点:这有效,自动将用户重新路由到登录页面(我想是因为我设置了 authentication-failure-url?)
    • 缺点:我必须更改 addBindingError 的签名才能抛出这种异常。
    • 缺点:我还必须更改每个控制器方法的签名以引发这种异常,因为它们都对 WSDL 进行远程服务调用。
    • 缺点:用户不知道他们为什么回到登录页面,我不确定是否有办法让他们知道
  2. 在 BaseController.addBindingError() 方法中,如果收到远程会话过期代码,则抛出 ModelAndViewDefiningException

    • 优点:这可行,自动将用户重新路由到适当的错误页面,该页面可以包含指向登录页面的链接
    • Pro:我们可以在这个页面上向用户解释他们是如何到达这里的。
    • 缺点:我必须更改 addBindingError 的签名才能抛出这种异常。
    • 缺点:我还必须更改每个控制器方法的签名以引发这种异常,因为它们都对远程 WSDL 进行远程服务调用
  3. 在 BaseController.addBindingError() 方法中,如果接收到远程会话过期代码,则抛出 MyCustomRemoteSessionExpiredException,然后在 SimpleMappingExceptionResolver 中捕获它

    • 优点:这可行,自动将用户重新路由到适当的错误页面,该页面可以包含指向登录页面的链接
    • Pro:我们可以在这个页面上向用户解释他们是如何到达这里的。
    • 缺点:我必须更改 addBindingError 的签名才能抛出这种异常。
    • 缺点:我还必须更改每个控制器方法的签名以引发这种异常,因为它们都对远程 WSDL 进行远程服务调用

数字 2 和 #3 具有相同的优点/缺点。#3 似乎它可能是一个更“正确”的解决方案。有没有人有任何反馈、建议或替代方案?

2013 年 5 月 30 日更新:

我想我可能已经找到了我要找的东西,我认为这需要我升级到最新的 spring 3.2。@ControllerAdvice 在这里这篇文章: http ://www.javacodegeeks.com/2013/03/exception-handling-with-the-spring-3-2-controlleradvice-annotation.html 从 BaseController.addBindingError,我会抛出MyCustomException(它扩展了 RuntimeException 以便方法签名不需要声明 throws 语句)并在新的 @ControllerAdvice 类(将包含 @ExceptionHandler 方法)中处理它。
任何人都可以确认或否认这种方法吗?
有更好的建议吗?

谢谢!

2013 年 12 月 3 日更新**

这个问题的标题会更好:“如何在 Spring MVC 架构中实现站点范围的异常处理?”。所以,我正在更改标题(以前的标题是基于我的误解,即与远程 SOAP 服务器的交互与我的真正问题有关)。我实施了 5 月份讨论的解决方案,并且运行良好。我什至扩展了 @ControllerAdvice 类来处理其他 RuntimeExceptions。

4

0 回答 0