2011-10-06 103 views
2

我正在开发继承的jsp/java ee应用程序,我想向我的应用程序介绍Guice IoC容器。但是,我发现了一些障碍。如果有多个使用不同url的路由到单个servlet,我无法将web.xml条目转换为guice注册。问题在于init参数。使用guice servlets将请求路由到匹配页面

下面是我的web.xml一部分摘录:

这一个是无关的问题,但它是我们如何使用初始化参数很好的例子。基本上,它将系统中不同角色的用户映射到适当的页面。

<!-- LIST INTERNSHIPS SERVLET --> 
<servlet> 
    <servlet-name>ListInternships</servlet-name> 
    <servlet-class>pl.poznan.put.ims.controllers.ListInternships</servlet-class> 
    <init-param> 
     <param-name>CoordinatorPage</param-name> 
     <param-value>WEB-INF/pages/coordinator/listinternships.jsp</param-value> 
    </init-param> 
    <init-param> 
     <param-name>MentorPage</param-name> 
     <param-value>WEB-INF/pages/mentor/listinternships.jsp</param-value> 
    </init-param> 
    <init-param> 
     <param-name>AdministratorPage</param-name> 
     <param-value>WEB-INF/pages/administrator/listinternships.jsp</param-value> 
    </init-param> 
    <init-param> 
     <param-name>AllowedRoles</param-name> 
     <param-value>Coordinator, Mentor, Administrator</param-value> 
    </init-param> 
</servlet> 
<servlet-mapping> 
    <servlet-name>ListInternships</servlet-name> 
    <url-pattern>/internships</url-pattern> 
</servlet-mapping> 

这两个都是麻烦的:

<!-- CHANGE PASSWORD SERVLET --> 
<servlet> 
    <servlet-name>ChangePassword</servlet-name> 
    <servlet-class>myapp.controllers.ContextForwarder</servlet-class> 
    <init-param> 
     <param-name>SharedPage</param-name> 
     <param-value>WEB-INF/pages/shared/password.jsp</param-value> 
    </init-param> 
    <init-param> 
     <param-name>AllowedRoles</param-name> 
     <param-value>*</param-value> 
    </init-param> 
</servlet> 
<servlet-mapping> 
    <servlet-name>ChangePassword</servlet-name> 
    <url-pattern>/changepassword</url-pattern> 
</servlet-mapping> 

<!-- HELP SERVLET --> 
<servlet> 
    <servlet-name>Help</servlet-name> 
    <servlet-class>myapp.controllers.ContextForwarder</servlet-class> 
    <init-param> 
     <param-name>SharedPage</param-name> 
     <param-value>WEB-INF/pages/help/help.jsp</param-value> 
    </init-param> 
    <init-param> 
     <param-name>AllowedRoles</param-name> 
     <param-value>*</param-value> 
    </init-param> 
</servlet> 
<servlet-mapping> 
    <servlet-name>Help</servlet-name> 
    <url-pattern>/help</url-pattern> 
</servlet-mapping> 

这里是我的servlet:

@Singleton 
public class ContextForwarder extends HttpServlet { 
    private static final long serialVersionUID = 1L; 
    private final IUserDao dao; 

    @Inject 
    public ContextForwarder(IUserDao dao) { 
     this.dao = dao; 
    } 

    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
      throws ServletException, IOException { 

      //trying to get rid of statics, using Ioc 
      Validator.checkUserLoggedIn (request); 
      Validator.checkUserAuthorized(this, request); 

      User currentUser  = UserManager.getCurrentUser(request); 
      //pick matching page for user 
      String userViewPage  = ServletUtils.getUserURL(this, currentUser, "Page"); 


      try { 
        dao.openSession(); 
        dao.beginTransaction(); 
        currentUser = UserManager.reloadCurrentUser(request, dao); 

        ServletUtils.forward(request, response, userViewPage); 
        dao.commit(); 
      } 
      catch(ServletException e) { 
        dao.rollback(); 
        throw e; 
      } 
      catch(Exception e) { 
        dao.rollback(); 
        throw new ServletException(e); 
      } 
      finally { 
        dao.closeSession(); 
      } 
    } 
} 

public class ServletUtils { 
    public static void forward(HttpServletRequest request, HttpServletResponse  response, String location) 
      throws ServletException, IOException { 
      RequestDispatcher view = request 
        .getRequestDispatcher(response.encodeRedirectURL(location)); 

      view.forward(request, response); 
    } 


    public static String getUserParameter(GenericServlet servlet, User user, String suffix) { 
      return servlet.getInitParameter(user.getRoles() + suffix); 
    } 

    public static String getUserURL(GenericServlet servlet, User user, String suffix) 
      throws ResourceNotFoundException { 
      String URL = getUserParameter(servlet, user, suffix); 

      if(URL == null) { 
        URL = servlet.getInitParameter("Shared" + suffix); 
        if(URL == null) 
          throw new ResourceNotFoundException(suffix); 
      } 

      return URL; 
    } 

    public static void redirect(HttpServletRequest request, HttpServletResponse response, String location) 
      throws ServletException, IOException { 
      response.sendRedirect(response.encodeRedirectURL(location)); 
    } 
} 

当我尝试把它翻译成吉斯(然后注册该模块):

public class MyServletModule extends ServletModule 
{ 

    @Override 
protected void configureServlets() { 
    configureHelp(); 
    configurePassword(); 
} 

    private void configureHelp() 
    { 
    Map<String, String> params = new HashMap<String, String>(); 
    params.put("SharedPage", "WEB-INF/pages/shared/help.jsp"); 
    params.put("AllowedRoles", "*"); 

    serve("/help").with(ContextForwarder.class, params); 
    } 

    private void configurePassword() 
    { 
    Map<String, String> params = new HashMap<String, String>(); 
    params.put("SharedPage", "WEB-INF/pages/shared/password.jsp"); 
    params.put("AllowedRoles", "*"); 

    // it's routing correctly to servlet, but it uses params from first registration, 
    // so that routing to jsp page is incorrect 
    serve("/changepassword").with(ContextForwarder.class, params); 
    }  
}  

问题是t帽子guice使用第一个注册方法的init参数创建ContextForwarder servlet作为单例,然后不管第一次注册时的参数是什么请求url。考虑到当前的用户角色,是否有其他解决方案将用户路由到不同的站点?是否可以使用两种不同的配置来配置相同的servlet类?

回答

3

我找到了解决办法,但是我对此并不完全满意。我发现,在没有guice的解决方案中,web容器(tomcat)使用相同的servlet类创建两个单独的servlet并注入不同的初始参数。 Guice默认将servlet限制为单例,所以要从web.xml解决方案中复制默认行为,我需要找到一种方法来创建同一个类的两个实例,并使用不同的参数注册两次。我通过创建两个子类到我的servlet类来解决这个问题,两个子类都是空的,然后我用不同的参数注册它们。

该解决方案有效,但它涉及创建我不满意的空体子类。当我有两个子类时,这不是问题,但其中更多的代码变得非常麻烦。

+0

这是正确的路要走。 Servlets应该是单身人士 - Guice是对的。 您可能已经发现,您之前的配置在某些servlet容器中导致了单个实例,因为据我所知,规范在这种情况下的实例数量不明确。 – mjaggard