spring mvc 同时支持多种视图jsp,velocity等

spring mvc大致流程

  1. http请求到Controller
  2. Controller执行完成返回逻辑视图名(字符串)
  3. spring用ViewResolver解析逻辑视图名到具体的视图对象
  4. 具体的视图对象可以渲染成html输出到浏览器

如果要支持多种视图一种方法就是在ViewResolver动动手脚了。DispatcherServlet(spring mvc核心前端控制器)中解析视图的代码如下所示:

    protected View resolveViewName(String viewName, Map model, Locale locale,
            HttpServletRequest request) throws Exception {

        //迭代容器中所有的viewResolver
        for (ViewResolver viewResolver : this.viewResolvers) { 
            View view = viewResolver.resolveViewName(viewName, locale);
            if (view != null) { //找到一个视图就返回了
                return view;
            }
        }
        return null;
    }

这里就是迭代spring容器中所有的viewResolver,如果有一个viewResover解析出视图(view!=null),就用这个视图了。

spring对jsp,velocity等视图技术早就有相应的viewResolver支持,但是如果只是简单的都配置到容器中又不能和谐的工作。所以我们可以自己写一个viewResolver,来协调已有的这些viewResolver和谐的工作,那么依据什么来协调呢?可以根据视图的扩展名,就是说controller返回逻辑视图名的时候带上扩展名。我们自定义的viewResolver根据逻辑视图名的扩展名来协调返回那种视图技术来渲染。

自定义viewResolver如下

/**
 * 根据逻辑视图名的扩展名来决定用那种视图(View)技术渲染
 * Created by yanglikun on 2016/9/3.
 */
public class ViewNameExtensionViewResolver implements ViewResolver, Ordered {

    private static final Log logger = LogFactory.getLog(ViewNameExtensionViewResolver.class);

    private int order = 0;

    Map viewResolvers = new HashMap();

    public View resolveViewName(String viewName, Locale locale) throws Exception {
        String viewExtension = StringUtils.getFilenameExtension(viewName);
        if (StringUtils.isEmpty(viewExtension)) {
            return null;
        }

        ViewResolver viewResolver = viewResolvers.get(viewExtension);
        if (viewResolver != null) {
            View view = viewResolver.resolveViewName(viewName, locale);
            if (logger.isDebugEnabled()) {
                logger.debug("Returning [" + view + "] based on view extension '"
                        + viewExtension + "'");
            }
            return view;
        }
        if (logger.isWarnEnabled()) {
            logger.warn("No view found with view extension[" + viewExtension + "]; returning null");
        }
        return null;
    }

    public void setViewResolvers(Map viewResolvers) {
        this.viewResolvers.putAll(viewResolvers);
    }

    public Map getViewResolvers() {
        return viewResolvers;
    }

    public int getOrder() {
        return order;
    }

    public void setOrder(int order) {
        this.order = order;
    }
}

这里不仅实现了ViewResolver接口,还实现了Ordered 接口,是因为,系统会配置多个viewresolver,spring容器会根据Ordered接口的getOrder返回的值把容器中所有的viewResolver进行排序,值越小,优先级越高。

xml的配置如下

其中internalResourceViewResolver和velocityViewResolver就是常规的resolver的配置了,详细的配置见
https://github.com/yanglikun/spring-mvc/blob/master/src/main/resources/spring/spring-config-mvc.xml

    <bean class="org.btlas.framework.viewresolver.ViewNameExtensionViewResolver">
        <property name="order" value="0"/>
        <property name="viewResolvers">
            <map>
                <entry key="jsp" value-ref="internalResourceViewResolver"/>
                <entry key="vm" value-ref="velocityViewResolver"/>
            map>
        property>
    bean>

这里我们把自己的viewResolver的order配置为0,这样spring在解析视图的时候也会提高一些效率,因为根据上面spring的源码,解析到view后,就不会迭代后面的viewResolver进行处理了。

示例代码:
clone 项目 https://github.com/yanglikun/spring-mvc.git
其中的org.btlas.controller.MultiViewController就是区分不同视图技术的

你可能感兴趣的:(spring)