2

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

以下是我的 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>

这是我的小服务程序:

 @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) );
    }
}

当我尝试将其翻译成 guice (然后注册此模块):

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);
    }       
}      

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

4

1 回答 1

3

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

该解决方案有效,但它涉及创建我不满意的空体子类。当我有两个子类时这不是问题,但是随着它们的增加,代码变得很麻烦。

于 2011-10-08T14:42:56.730 回答