栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

springboot-08-Web启动器

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

springboot-08-Web启动器

spring-boot-starter-web(Web启动器)

简介

Spring MVC是Spring提供的一个基于MVC设计模式的轻量级开发框架,其本身是Spring框架的一部分,与Spring无缝集成。

Spring Boot是在Spring基础上创建的一款开源框架,它提供spring-boot-starter-web(Web场景启动器)为Web开发提供支持。其中spring-boot-starter-web为我们提供了大量的自动配置类,并嵌入了Servlet容器以及SpringMVC的依赖,使用于大多数Web开发场景

Spring Boot Web开发

Spring Boot为SpringMVC提供了大量的自动配置,并在对其进行了拓展:

    引入了 ContentNegotiatingViewResolver 和 BeanNameViewResolver(视图解析器)

    对包括 WebJars 在内的静态资源的支持

    自动注册 Converter、GenericConverter 和 Formatter (转换器和格式化器)

    对 HttpMessageConverters 的支持(Spring MVC 中用于转换 HTTP 请求和响应的消息转换器)

5.自动注册 MessageCodesResolver(用于定义错误代码生成规则)

    支持对静态首页(index.html)的访问

    自动使用 ConfigurableWebBindingInitializer(初始化数据绑定器)

只要pom.xml引入了spring-boot-starter-web,就可以直接运行web项目了。

示例

    创建一个名为spring-boot-springmvc-demo1的Spring Boot项目,发现在pom.xml已经帮我们导入了spring-boot-starter-web依赖
   
            org.springframework.boot
            spring-boot-starter-web
            RELEASE
            compile
        

    在项目的包名下添加一个controller的子包,创建一个名为UseController的类,代码如下:
package com.liang.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("hello")
public class UseController {
    @RequestMapping("/s")
    @ResponseBody
    public String test()
    {
        return "hello,springboot";
    }
}

    启动Spring Boot ,浏览器访问“http://localhost:8080/hello/s”

注意:如果我们要开发的是web项目,则不需要去导入spring-boot-starter包了,因为spring-boot-starter-web已经帮我们导入了


MVC自动配置原理

官方阅读

基于源码分析外:,我们可以通过官方文档来查看Spring Boot 对Spring MVC做了哪些配置,包括如何拓展,如何配置

Spring MVC Auto-configuration
// Spring Boot为Spring MVC提供了自动配置,它可以很好地与大多数应用程序一起工作。

Spring Boot provides auto-configuration for Spring MVC that works well with most applications.
// 自动配置在Spring默认设置的基础上添加了以下功能:

The auto-configuration adds the following features on top of Spring’s defaults:

// 包含视图解析器
Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.

// 支持静态资源文件夹的路径,以及webjars
Support for serving static resources, including support for WebJars 

// 自动注册了Converter:
// 转换器,这就是我们网页提交数据到后台自动封装成为对象的东西,比如把"1"字符串自动转换为int类型
// Formatter:【格式化器,比如页面给我们了一个2019-8-10,它会给我们自动格式化为Date对象】
Automatic registration of Converter, GenericConverter, and Formatter beans.

// HttpMessageConverters
// SpringMVC用来转换Http请求和响应的的,比如我们要把一个User对象转换为JSON字符串,可以去看官网文档解释;

Support for HttpMessageConverters (covered later in this document).
// 定义错误代码生成规则的
Automatic registration of MessageCodesResolver (covered later in this document).
// 首页定制

Static index.html support.
// 图标定制

Custom Favicon support (covered later in this document).
// 初始化数据绑定器:帮我们把请求数据绑定到JavaBean中!

Automatic use of a ConfigurableWebBindingInitializer bean (covered later in this document).


If you want to keep Spring Boot MVC features and you want to add additional MVC configuration 
(interceptors, formatters, view controllers, and other features), you can add your own 
@Configuration class of type WebMvcConfigurer but without @EnableWebMvc. If you wish to provide 
custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or 
ExceptionHandlerExceptionResolver, you can declare a WebMvcRegistrationsAdapter instance to provide such components.


// 如果您想完全控制Spring MVC,可以添加自己的@Configuration,并用@EnableWebMvc进行注释。
If you want to take complete control of Spring MVC, you can
 add your own @Configuration annotated with @EnableWebMvc.

首先配置了视图解析器,我们先看看它是怎么配置的

ContentNegotiatingViewResolver内容协商视图器

自动配置了ViewResolver,我们之前SpringMVC学习的视图解析器。

即根据方法的返回值取得视图对象(View),然后由视图对象决定如何渲染(转发,重定向)。

		@Bean
		@ConditionalOnBean(ViewResolver.class)
		//在ViewResolver在视图解析器的条件下
		@ConditionalOnMissingBean(name = "viewResolver", value = ContentNegotiatingViewResolver.class)
		public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
			ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
			resolver.setContentNegotiationManager(beanFactory.getBean(ContentNegotiationManager.class));
			// ContentNegotiatingViewResolver uses all the other view resolvers to locate
			// a view so it should have a high precedence
			resolver.setOrder(Ordered.HIGHEST_PRECEDENCE);
			  // ContentNegotiatingViewResolver使用所有其他视图解析器来定位视图,因此它应该具有较高的优先级
			return resolver;
		}

点进ContentNegotiationViewResolver类看看

 @Nullable  // 注解说明:@Nullable 即参数可为null
    public View resolveViewName(String viewName, Locale locale) throws Exception {
        RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
        Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes");
        List requestedMediaTypes = this.getMediaTypes(((ServletRequestAttributes)attrs).getRequest());
        if (requestedMediaTypes != null) {
                // 获取候选的视图对象
            List candidateViews = this.getCandidateViews(viewName, locale, requestedMediaTypes);
            View bestView = this.getBestView(candidateViews, requestedMediaTypes, attrs);
             // 选择一个最适合的视图对象,然后把这个对象返回
            if (bestView != null) {
                return bestView;
            }
        }

继续点击getCandidateViews()查看它是怎么获取候选视图的

    private List getCandidateViews(String viewName, Locale locale, List requestedMediaTypes) throws Exception {
        List candidateViews = new ArrayList();
        if (this.viewResolvers != null) {
            Assert.state(this.contentNegotiationManager != null, "No ContentNegotiationManager set");
            Iterator var5 = this.viewResolvers.iterator();
			//获取所有的解析视图器,进行while循环
            while(var5.hasNext()) {
                ViewResolver viewResolver = (ViewResolver)var5.next();
                View view = viewResolver.resolveViewName(viewName, locale);
                if (view != null) {
                    candidateViews.add(view);
                }

                Iterator var8 = requestedMediaTypes.iterator();

                while(var8.hasNext()) {
                    MediaType requestedMediaType = (MediaType)var8.next();
                    List extensions = this.contentNegotiationManager.resolveFileExtensions(requestedMediaType);
                    Iterator var11 = extensions.iterator();

                    while(var11.hasNext()) {
                        String extension = (String)var11.next();
                        String viewNameWithExtension = viewName + '.' + extension;
                        view = viewResolver.resolveViewName(viewNameWithExtension, locale);
                        if (view != null) {
                            candidateViews.add(view);
                        }
                    }
                }
            }
        }

通过getCandidateViews()方法中看到它是把所有的视图解析器拿来,进行while循环,挨个解析!

结论: ContentNegotiatingViewResolver 这个视图解析器就是用来组合所有的视图解析器的

查看ContentNegotiatingViewResolver的组合逻辑,有个viewResolvers,看看它是如何赋值的

protected void initServletContext(ServletContext servletContext) {
        Collection matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.obtainApplicationContext(), ViewResolver.class).values();
        //可以看到viewResolver 是从BeanFactoryUtils工具类获取容器中所有的视图解析器
        //viewResolver.class把所有的视图解析器组合
        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);
                }
            }
        }

        AnnotationAwareOrderComparator.sort(this.viewResolvers);
        this.cnmFactoryBean.setServletContext(servletContext);
    }


给容器添加自定义视图解析器

    我们在我们的主程序中写一个视图解析器
	@Bean
	public ViewResolver myViewResolver()
	{
		return new MyViewResolver();
	}

	//写一个静态内部类,将视图解析器需要实现ViewResolver接口
	private static class MyViewResolver implements ViewResolver{

		@Override
		public View resolveViewName(String viewName, Locale locale) throws Exception {
			return null;
		}
	}
    怎么看我们自己写的视图解析器有没有起作用呢?

我们给 DispatcherServlet 中的 doDispatch方法 加个断点进行调试一下(DispatcherServlet可以声明这个类),因为所有的请求都会走到这个方法中

    我们启动我们的项目,然后随便访问一个页面,看一下Debug信息;

如果想要使用自己定制化的东西,我们只需要给容器中添加这个组件就好了!剩下的事情SpringBoot就会帮我们做了!


转换器和格式化器

找到格式化转化器:

		@Bean
		@Primary
		@Override
		public RequestMappingHandlerMapping requestMappingHandlerMapping(
				@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
				@Qualifier("mvcConversionService") FormattingConversionService conversionService,
				@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
			// Must be @Primary for MvcUriComponentsBuilder to work
			return super.requestMappingHandlerMapping(contentNegotiationManager, conversionService,
					resourceUrlProvider);
		}

发现FormattingConversionService一个格式化转换服务


发现了有很多的格式化服务,我们也可以自己去配置自己的格式化方式。如果配置了自己的格式化方式,就会注册到Bean中生效,我们可以在配置文件中配置日期格式化的规则:

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/771308.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号