java mvc view_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 addObject.

* @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.

*

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 null 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 null 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等的处理。然后将生成的页面返回给客户端。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值