Decoupling Controllers from View Technologies Using a View Interface

Let's review the way in which the MVC web app framework described in decouples controllers from views. It uses the named view strategy to provide a layer of indirection allowing a controller to select a view by name without knowing anything about the view's implementation. This means that all views must implement a common Java interface. Most view technologies hold presentation information such as (X)HTML formatting in templates such as JSP pages, rather than Java classes. However, as the details of templates vary between view technologies such as JSP and XSLT, this decoupling depends on different implementations of a Java view interface that manages content rendering using the appropriate technology and template. I use the term view interface to refer to Java objects that provide such decoupling between controller and view, and the term view to refer to the resource (such as a JSP page) that holds the actual layout for the page. In some cases, a single Java class may perform both roles. Implementations of view interfaces are normally multi-threaded, and work on behalf of all users of the app. Typically one instance of a view wraps a particular template, implementing a single, stateless, method that accepts model data and builds a dynamic page. Normally only a template such as a JSP page needs to be provided as part of an app, with the necessary view implementation being a standard class supplied by the framework. In the framework discussed in , a view interface must implement com.interface21.web.servlet.View interface, which is based around the following method, which generates dynamic content given a data model:

 void render(Map model,
 HttpServletRequest request,
 HttpServletResponse response)
 throws IOException, ServletException;

The model parameter contains a number of model objects exposed by the controller. In some cases, it will be empty, if a view doesn't require any model information. The com.interface21.web.servlet.View interface also allows static attributes to be added to the model exposed by the underlying view technology. This enables additional presentation-specific data (such as arguments to template pages or default page titles) to be added in app configuration without polluting the model returned by controllers, which shouldn't be tailored to any particular view technology. Static attributes can be added to views only when they are first created. Once a view is in use, its data (including its static attributes) is immutable to ensure thread safety. The AbstractView base class used by the view implementations discussed in this chapter allows static attributes to be defined in CSV format as follows. This property defines three static attributes: header, contentWell, and footer.

 welcomeView.attributesCSV=header=[/jsp/header.jsp], \

As model data returned by controllers and static attributes are presentation-agnostic, implementations of the View interface can work with any view technology. We'll look at implementations of the View interface in detail below, but let's take a more detailed look at how particular view implementations may fulfill the basic requirements we identified in :

In our app framework, View objects are normally JavaBeans, configured on app initialization. This means that configuration can be held outside Java code. Typically there is one view instance per view template (such as a JSP page). How view definitions are stored, depends on the implementation of the ViewResolver interface used. The com.interface21.web.servlet.ViewResolver interface, discussed in , defines the following single method, to return a View instance for a given name and Locale (taken from the request):

 View resolveViewname(String viewName, Locale locale)
 throws ServletException;

It's easy to provide a custom, app-specific implementation of this interface, which might hold view definitions in a custom format or even perform view resolution wholly in Java code.

However, normally we can rely on the default ViewResolver implementation, used in the sample app. In this implementation, which we'll use for the examples in this appendix, view definitions are JavaBean definitions in the /WEB-INF/classes/ file, or a resource bundle with the appropriate localized name, such as /WEB-INF/classes/, which overrides some or all of the view definitions. As we look at each view technology below, we'll look at the necessary bean definitions for the default ViewResolver.