推荐淘宝秋冬男装热卖网店

追求无止境

我的程序人生
随笔 - 31, 文章 - 2, 评论 - 20, 引用 - 0
数据加载中……

Spring MVC框架学习笔记 之 View技术

以前,我们详细介绍了Spring的Controller技术。Spring的面向接口编程,使Controller的实现多种多样。View技术也一样。今天的分析先从在Controller中的ModelAndView开始。

public class ModelAndView {     
  private Object view; //View实例或者view的字符串    
/** Model Map */  
  private ModelMap model; //model
 /* * Convenient constructor when there is no model data to expose.     * Can also be used in conjunction with <code>addObject</code>.    
 * @param view View object to render   
  * @see #addObject     */  
 public ModelAndView(View view) {        
    this.view = view;    
}
public ModelAndView(String viewName){ 
   this.view = viewName;
}

 
可以看到view实例可以指向一个View对象或者字符串。现在先看看View接口:
public interface View { 

    /**
     * Return the content type of the view, if predetermined.
     * <p>Can be used to check the content type upfront,
     * before the actual rendering process.
     * @return the content type String (optionally including a character set),
     * or <code>null</code> if not predetermined.
     */
    String getContentType(); 

    /**
     * 绘制视图
     * 绘制视图的第一步是准备请求: 如果是JSP的视图技术
     * 首先会把model设为request的属性。
     * 第二步则是真正的绘制视图
     * @param model Map with name Strings as keys and corresponding model
     * objects as values (Map can also be <code>null</code> in case of empty model)
     * @param request current HTTP request
     * @param response HTTP response we are building
     * @throws Exception if rendering failed
     */
    void render(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception; 

}
在这之后,我们再来看看View的实现继承类图,可以看到Spring支持多种类型视图:

org.springframework.web.servlet.view.AbstractView (implements org.springframework.beans.factory.BeanNameAware, org.springframework.web.servlet.View)

  • org.springframework.web.servlet.view.document.AbstractExcelView
  • org.springframework.web.servlet.view.document.AbstractJExcelView
  • org.springframework.web.servlet.view.document.AbstractPdfView
  • org.springframework.web.servlet.view.AbstractUrlBasedView (implements org.springframework.beans.factory.InitializingBean)
    • org.springframework.web.servlet.view.jasperreports.AbstractJasperReportsView
      • org.springframework.web.servlet.view.jasperreports.AbstractJasperReportsSingleFormatView
        • org.springframework.web.servlet.view.jasperreports.ConfigurableJasperReportsView
        • org.springframework.web.servlet.view.jasperreports.JasperReportsCsvView
        • org.springframework.web.servlet.view.jasperreports.JasperReportsHtmlView
        • org.springframework.web.servlet.view.jasperreports.JasperReportsPdfView
        • org.springframework.web.servlet.view.jasperreports.JasperReportsXlsView
      • org.springframework.web.servlet.view.jasperreports.JasperReportsMultiFormatView
    • org.springframework.web.servlet.view.document.AbstractPdfStamperView
    • org.springframework.web.servlet.view.AbstractTemplateView
      • org.springframework.web.servlet.view.freemarker.FreeMarkerView
      • org.springframework.web.servlet.view.velocity.VelocityView
        • org.springframework.web.servlet.view.velocity.VelocityToolboxView
          • org.springframework.web.servlet.view.velocity.VelocityLayoutView
    • org.springframework.web.servlet.view.InternalResourceView
      • org.springframework.web.servlet.view.JstlView
      • org.springframework.web.servlet.view.tiles.TilesView
        • org.springframework.web.servlet.view.tiles.TilesJstlView
    • org.springframework.web.servlet.view.RedirectView
    • org.springframework.web.servlet.view.tiles2.TilesView
    • org.springframework.web.servlet.view.xslt.XsltView
  • org.springframework.web.servlet.view.xslt.AbstractXsltView
 
和Controller一样,View的第一个实现也是AbstractView。所以先让我们看看AbstractView对render函数的实现:

 

public void render(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isTraceEnabled()) {
logger.trace("Rendering view with name '" + this.beanName + "' with model " + model +
" and static attributes " + this.staticAttributes);
}

// Consolidate static and dynamic model attributes.
Map mergedModel = new HashMap(this.staticAttributes.size() + (model != null ? model.size() : 0));
mergedModel.putAll(this.staticAttributes);
if (model != null) {
mergedModel.putAll(model);
}

// Expose RequestContext?
if (this.requestContextAttribute != null) {
mergedModel.put(this.requestContextAttribute, createRequestContext(request, mergedModel));
}

prepareResponse(request, response);
renderMergedOutputModel(mergedModel, request, response);
}

第一步,将静态属性和model的属性都添加到mergedModel里面。如果需要请求上下文,则将请求上下文添加到model中。

静态属性是继承AbstractView进行设置的属性。而请求上下文如果设置的名字就会创建一个request上下文。在requestContext中定义了一些包括本地化和主题的处理工具。

第二步,对响应进行预处理。最后调用子类需要实现的函数renderMergedOutputModel。

对PDF和EXCEL格式我们暂且不管,且Spring支持多种视图技术,这里我们主要关注JSTL技术,

接着我们来看AbstractUrlBasedView 类。在AbstractUrlBasedView 只定义了一个url属性。别的没有什么特殊处理。

接着继承AbstractUrlBasedView 的是InternalResourceView。他对renderMergedOutputModel进行实现,实现如下:

/**
* Render the internal resource given the specified model.
* This includes setting the model as request attributes.
*/
protected void renderMergedOutputModel(
Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {

// 获取要暴露的request,一般都是传入的参数request
HttpServletRequest requestToExpose = getRequestToExpose(request);

// 将model的数据添加到request属性中
        exposeModelAsRequestAttributes(model, requestToExpose);

// 设置helper,如果存在的话
exposeHelpers(requestToExpose);

// 对绘制进行预处理,从而获得到要分发的url
String dispatcherPath = prepareForRendering(requestToExpose, response);

// 获取请求分发对象
RequestDispatcher rd = requestToExpose.getRequestDispatcher(dispatcherPath);
if (rd == null) {
throw new ServletException(
"Could not get RequestDispatcher for [" + getUrl() + "]: check that this file exists within your WAR");
}

// 决定使用RequestDispatcher的include方法还是forward方法
if (useInclude(requestToExpose, response)) {
response.setContentType(getContentType());
if (logger.isDebugEnabled()) {
logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
}
rd.include(requestToExpose, response);
}

else {
// Note: The forwarded resource is supposed to determine the content type itself.
exposeForwardRequestAttributes(requestToExpose);
if (logger.isDebugEnabled()) {
logger.debug("Forwarding to resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
}
rd.forward(requestToExpose, response);
}
}
可以看到InternalResourceView对请求进行了转发。转发到url上。最后我们看看JSTLView的实现:

 
public class JstlView extends InternalResourceView {

    private MessageSource messageSource;

    public JstlView() {
    }

    
    public JstlView(String url) {
        super(url);
    }

    public JstlView(String url, MessageSource messageSource) {
        this(url);
        this.messageSource = messageSource;
    }

    protected void initServletContext(ServletContext servletContext) {
        if (this.messageSource != null) {
            this.messageSource = JstlUtils.getJstlAwareMessageSource(servletContext, this.messageSource);
        }
        super.initServletContext(servletContext);
    }

    protected void exposeHelpers(HttpServletRequest request) throws Exception {
        if (this.messageSource != null) {
            JstlUtils.exposeLocalizationContext(request, this.messageSource);
        }
        else {
            JstlUtils.exposeLocalizationContext(new RequestContext(request, getServletContext()));
        }
    }

}

 

在InternalResourceView  中,基本上所有的处理都差不多了。在JSTLView对两个方法进行了覆盖。第一个initServletContext,主要初始化了MessageResource

第二个exposeHelpers将messageSource放在了request里面。

这样view的解析就结束了。接下来容器对jsp进行解析,并进行tag等的处理。然后将生成的页面返回给客户端。

posted on 2009-11-26 13:25 追求无止境 阅读(8199) 评论(2)  编辑  收藏

评论

# re: Spring MVC框架学习笔记 之 View技术  回复  更多评论   

不错。。。。
2009-11-27 09:39 | 字典

# re: Spring MVC框架学习笔记 之 View技术  回复  更多评论   

99098
2016-05-19 17:23 | 888

只有注册用户登录后才能发表评论。


网站导航: