spring mvc之视图及restful(上篇视图篇)

开篇

本篇文章试图解释清楚一些我们比较模糊的springmvc概念,包括视图内容协商,restful内容协商,以及HandlerMethodReturnValueHandler,HandlerMethodReturnValueHandler也就是handler method 入参的处理和返回值得处理。谢谢大家。考虑内容篇幅过于臃肿,分为上下两篇,上篇spring mvc之视图,下篇restful及内容调停

视图

基本组成:

资源定位(模板来源 )


通用资源抽象,比如文件资源: File,ClassPath资源: ClassLoader,统一资源: URL,Web资源: ServletContext
但是Spring 为我们提供了资源的抽象,我们可以通过比如"classpath://location"来制定classpath下的资源 ,"file://location"指定file下的资源等等:Resource

渲染上下文(变量来源 )

Context :Thyemeaf 渲染上下文
Model :Spring Web MVC 模型
Attribute :Servlet 上下文

模板引擎(模板渲染)

我们通过简单的使用使用 Thymeleaf API 渲染内容:

public class ThymeleafTemplateEngineBootstrap {
    public static void main(String[] args) throws IOException {
        // 构建引擎
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        // 创建渲染上下文
        Context context = new Context();
        context.setVariable("message", "Hello,World");

        // 读取内容从 classpath:/thymeleaf/hello-world.html
        // ResourceLoader
        ResourceLoader resourceLoader = new DefaultResourceLoader();
        // 通过 classpath:/templates/thymeleaf/hello-world.html Resource
        Resource resource = resourceLoader.getResource("classpath:/thymeleaf/hello-world.html");
        File templateFile = resource.getFile();
        // 文件流
        FileInputStream inputStream = new FileInputStream(templateFile);
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        // Copy
        IOUtils.copy(inputStream, outputStream);

        inputStream.close();
        // 模板的内容
        String content = outputStream.toString("UTF-8");
        // 渲染(处理)结果
        String result = templateEngine.process(content, context);
        // 输出渲染(处理)结果
        System.out.println(result);
    }
}

视图处理

基本组件(接口)

ViewResolver :视图解析器
View : 视图组件
DispatcherServlet :总控(实现类)

Thymeleaf 整合 Spring Web MVC,对应的实现类
ViewResolver : ThymeleafViewResolver
View :  ThymeleafView
ITemplateEngine : SpringTemplateEngine

spring mvc之视图及restful(上篇视图篇)_第1张图片

springboot中使用jsp视图解析器

第一步:

导入内嵌式jsp servlet,和服务器依赖,以及标准标签库



org.springframework.boot
spring-boot-starter-tomcat


org.apache.tomcat.embed
tomcat-embed-jasper

第二步:

导入springboot的maven插件

 

第三步:

添加webapp/web-inf/jsp文件,并在application.properties中添加jsp视图解析器的前缀后缀。

 

视图内容协商

简介

关于什么是视图内容协商,其实就是springMVC自动为我们添加了一个视图解析器,且优先使用该视图解析器进行集成其他的视图解析器,并通过视图名称依次调用集成的视图解析器返回视图,并根据ContentNegotiationManager(内容调停管理器)筛选出最佳view,来进行视图的渲染工作。进而实现一个请求路径可以使用accecpt请求头实现返回不同视图内容,如xml或html。

工作流程

spring mvc之视图及restful(上篇视图篇)_第2张图片 视图内容调停策略执行流程图

现在介绍一下先关的调停策略:

固定  MediaType : FixedContentNegotiationStrategy
"Accept" 请求头: HeaderContentNegotiationStrategy
请求参数: ParameterContentNegotiationStrategy
路径扩展名: PathExtensionContentNegotiationStrategy
springboot默认的配置策略仅有一个HeaderContentNegotiationStrategy

springboot实现内容调停相关源码实现

1:内容调停视图解析器

 //webmvc自动配置配置  内容调停视图
public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
            ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
//我们看到这里从beanfactory中获取内容调停管理器            resolver.setContentNegotiationManager((ContentNegotiationManager)beanFactory.getBean(ContentNegotiationManager.class));
            resolver.setOrder(-2147483648);
            return resolver;
        }

2:解决其他视图解析器如何装在调停视图解析器的

/*
通过setApplicationContext机制进行模板方法的回调
setApplicationContext:78, ApplicationObjectSupport
initApplicationContext:81, WebApplicationObjectSupport
initServletContext:185, ContentNegotiatingViewResolver
*/

//加载上下文中的所有视图解析器
protected void initServletContext(ServletContext servletContext) {
        Collection matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.obtainApplicationContext(), ViewResolver.class).values();
        ViewResolver viewResolver;
        if (this.viewResolvers == null) {
            this.viewResolvers = new ArrayList(matchingBeans.size());
            Iterator var3 = matchingBeans.iterator();

            while(var3.hasNext()) {
                viewResolver = (ViewResolver)var3.next();
                if (this != viewResolver) {
                    this.viewResolvers.add(viewResolver);
                }
            }
        } else {
            for(int i = 0; i < this.viewResolvers.size(); ++i) {
                viewResolver = (ViewResolver)this.viewResolvers.get(i);
                if (!matchingBeans.contains(viewResolver)) {
                    String name = viewResolver.getClass().getName() + i;
                    this.obtainApplicationContext().getAutowireCapableBeanFactory().initializeBean(viewResolver, name);
                }
            }
        }

        if (this.viewResolvers.isEmpty()) {
            this.logger.warn("Did not find any ViewResolvers to delegate to; please configure them using the 'viewResolvers' property on the ContentNegotiatingViewResolver");
        }
	//并进行优先级的排序
        AnnotationAwareOrderComparator.sort(this.viewResolvers);
        this.cnmFactoryBean.setServletContext(servletContext);
    }

3:解决 contentNegotiationManager在何处创建的

//webmvc 自动配置
@Bean
        public ContentNegotiationManager mvcContentNegotiationManager() {
            //此处调用父类的方法获取
            ContentNegotiationManager manager = super.mvcContentNegotiationManager();
            List strategies = manager.getStrategies();
            ListIterator iterator = strategies.listIterator();

            while(iterator.hasNext()) {
                ContentNegotiationStrategy strategy = (ContentNegotiationStrategy)iterator.next();
                if (strategy instanceof PathExtensionContentNegotiationStrategy) {
                    iterator.set(new WebMvcAutoConfiguration.OptionalPathExtensionContentNegotiationStrategy(strategy));
                }
            }

            return manager;
        }

//父类的方法
@Bean
    public ContentNegotiationManager mvcContentNegotiationManager() {
        if (this.contentNegotiationManager == null) {
            ContentNegotiationConfigurer configurer = new ContentNegotiationConfigurer(this.servletContext);
            configurer.mediaTypes(this.getDefaultMediaTypes());
            this.configureContentNegotiation(configurer);
            this.contentNegotiationManager = configurer.buildContentNegotiationManager();
        }

        return this.contentNegotiationManager;
    }

//默认只有这摸一种策略:HeaderContentNegotiationStrategy

4:spring boot 如何配置内容调停策略

//ContentNegotiationConfigurer 相当于是一个build,每一步设置都是构建 ContentNegotiationManagerFactoryBean 的先关参数,然后 build时进行创建
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        //内容调停策略设置
        configurer.favorParameter(true).favorPathExtension(true);
    }
}

好,到此内容调停策略的内容解析完毕,谢谢大家的支持。

 

你可能感兴趣的:(spring)