控制器是否创建新视图?

时间:2009-05-31 22:56:22

标签: java model-view-controller dependency-injection dependencies

我正在开发一个简单的Java应用程序。目前,我有两个视图,一个用于登录,另一个用于登录。

所以我的问题是,一旦用户登录,登录视图的控制器是否应该创建第二个视图?

问题是,第一个控制器需要知道第二个视图的每个依赖关系......

编辑:这是一个Web应用程序。

7 个答案:

答案 0 :(得分:1)

我认为LoginController根本不应该创建SecondView。一旦用户登录,LoginController就会触发登录成功的事件,任何关心该事件的Controller都应该采取适当的行动。

如果您正在使用DI,您最好将视图注入控制器。

不完全确定你对上一个陈述的意思,但是没有答案。

答案 1 :(得分:1)

如果您的对象需要实例化一个类,但您不希望它依赖于实例化该类的细节,请注入一个工厂(如you've suggested)。

我喜欢使用接口,所以我可以插入我的依赖项的不同实现。这是一个例子:

public class RealLoginController implements LoginController {
    private LoginViewFactory viewFactory;

    public LoginController(LoginViewFactory viewFactory) {
        this.viewFactory = viewFactory;
    }

    public ModelAndView handleRequest(HttpServletRequest request,
                                      HttpServletResponse response) {
         if (isLoggedIn()) {
             return viewFactory.createLoggedInView();
         } else {
             return viewFactory.createLoggedOutView();
        }
    }

    // ...
}

public class RealLoggedInView implements LoginView {
    // Implementation for rendering stuff
}

public class RealLoggedOutView implements LoginView {
    // Implementation for rendering stuff
}


public interface LoginViewFactory {
    public LoginView createLoggedInView();
    public LoginView createLoggedInView();
}


public class RealLoginViewFactory implements LoginViewFactory {
    private FooModel fooEngine;
    private BarConfig barConfig;

    public RealLoginViewFactory(FooModel fooLayer, BarConfig barConfig) {
        this.fooEngine = fooEngine;
        this.barConfig = barConfig;
    }

    public LoginView createLoggedInView() {
        if (fooEngine.hasBaz()) {
            return new RealLoginView(barCongig.getQux());
        } else {
            return new RealLoginView(barCongig.getQux(),
                                     fooEngine.getBaz());
        }
    }

    public LoginView createLoggedOutView() {
        // ...
    }
}

public class RealLoginController implements LoginController {
    private LoginViewFactory viewFactory;

    public LoginController(LoginViewFactory viewFactory) {
        this.viewFactory = viewFactory;
    }

    public ModelAndView handleRequest(HttpServletRequest request,
                                      HttpServletResponse response) {
         if (isLoggedIn()) {
             return viewFactory.createLoggedInView();
         } else {
             return viewFactory.createLoggedOutView();
        }
    }

    // ...
}

然后,您可以将控制器与您喜欢的任何视图一起使用:

public class LoginControllerTest {
    public void testSomething() {
        // ...
        controller = new RealLoginController(fakeViewFactory);
        assertHasTag("td#row1", controller.getRenderedStuff());
        // ...
    }
}

如果您不需要复杂的实例化逻辑,并且您的框架知道如何通过名称获取依赖关系,您可以避免此问题(如bpappa suggests)。

答案 2 :(得分:0)

这是Spring MVC吗?

如果您在没有注释的情况下使用Spring MVC 2.5或更低版本,则在handleRequest方法结束时,将返回ModelAndView对象。它包含视图信息(无论是在重定向视图中的视图本身,还是视图的名称)。您可以根据某些逻辑有条件地返回不同的视图。例如 -

handleRequest(HttpServletRequest request, HttpServletResponse response) {
     // get user from session
     if (user.isLoggedIn())
         return new ModelAndView("loggedInView");
     else
         return new ModelAndView("notLoggedInView");
}

如果这是一个新项目,并且您可以访问Java 1.5,我建议使用annotations-based Spring MVC,因为这样您就可以返回所需的任何内容。

答案 3 :(得分:0)

我认为工厂可能会这样做:

public class LoginViewFactory
{
    private depA;
    private depB;

    public LoginViewFactory(dependencyA, dependencyB)
    {
        depA = dependencyA;
        depB = dependencyB;
    }

    LoginView create()
    {
        return new LoginView(depA, depB);
    }
}


//and then pass this factory to my controller
new Controller(new LoginViewFactory(new A(), new B());

您怎么看?

答案 4 :(得分:0)

你应该采用与Spring相同的方法,并让你的控制器返回一个视图名称。 然后让另一个类处理根据视图名称创建视图。

答案 5 :(得分:0)

我认为你的第一个“视图”(登录页面)可以被认为是一个静态页面,因为它通常是第一个可访问的页面,所以可能它背后没有控制器。

但是假设您的网络应用程序中还有其他一些页面,并且说您实际上有一个控制器A(一种DispatchController),它将用户引导到登录页面。

提交此页面后,您通常会有一个不同的控制器(比如LoginController),它将用户指向(如果登录成功)到第二个视图页面(登录页面)

所以底线是:对我而言,你看起来需要两个控制器,每个控制器都有不同的责任。

答案 6 :(得分:0)

如果您的登录是表格POST(应该是),我会在成功登录后重定向到主页。

这样,如果用户在登录后在主页上点击刷新,那么他们就不会收到有关重新提交POST的浏览器警告。
如果他们从主页单击链接然后单击后退按钮,则同样适用。

在Spring中,您可以使用此语法执行此操作。

return new ModelAndView(new RedirectView(homepage, true), model);

“homepage”参数将在spring配置中配置并作为参数注入 - 它应该是您网站主页的相对URL。

因为您正在重定向主页控制器,所以这会处理您的依赖项问题。