1. 程式人生 > >SpringBoot中的SpringMVC分析

SpringBoot中的SpringMVC分析

首先,回顧下SpringMVC的工作原理以及各個元件的構成:

https://www.cnblogs.com/xiaoxi/p/6164383.html

接下來,看下在SpringBoot中,SpringMVC是如何實現運作機制的:

1. 先看下官方文件的描述

https://docs.spring.io/spring-boot/docs/1.5.10.RELEASE/reference/htmlsingle/#boot-features-developing-web-applications

27.1.1 Spring MVC auto-configuration
Spring Boot provides auto-configuration for Spring MVC that works well with most applications.

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

Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.
Support for serving static resources, including support for WebJars (see below).
Automatic registration of Converter, GenericConverter, Formatter beans.
Support for HttpMessageConverters (see below).
Automatic registration of MessageCodesResolver (see below).
Static index.html support.
Custom Favicon support (see below).
Automatic use of a ConfigurableWebBindingInitializer bean (see below).
If you want to keep Spring Boot MVC features, and you just want to add additional MVC configuration (interceptors, formatters, view controllers etc.) you can add your own @Configuration class of type WebMvcConfigurerAdapter, but without @EnableWebMvc. If you wish to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter or ExceptionHandlerExceptionResolver you can declare a WebMvcRegistrationsAdapter instance providing such components.

If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc.

2.接下來,逐條解析下說的是什麼意思
4、SpringMVC自動配置

https://docs.spring.io/spring-boot/docs/1.5.10.RELEASE/reference/htmlsingle/#boot-features-developing-web-applications

  1. Spring MVC auto-configuration

Spring Boot 自動配置好了SpringMVC

以下是SpringBoot對SpringMVC的預設配置:(WebMvcAutoConfiguration)

  • Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.

    • 自動配置了ViewResolver(檢視解析器:根據方法的返回值得到檢視物件(View),檢視物件決定如何渲染(轉發?重定向?))
    • ContentNegotiatingViewResolver:組合所有的檢視解析器的;
    • 如何定製:我們可以自己給容器中新增一個檢視解析器;自動的將其組合進來;
  • Support for serving static resources, including support for WebJars (see below).靜態資原始檔夾路徑,webjars

  • Static index.html support. 靜態首頁訪問

  • Custom Favicon support (see below). favicon.ico

  • 自動註冊了 of Converter, GenericConverter, Formatter beans.

    • Converter:轉換器; public String hello(User user):型別轉換使用Converter

    • Formatter 格式化器; 2017.12.17===Date;

      	@Bean
      	@ConditionalOnProperty(prefix = "spring.mvc", name = "date-format")//在檔案中配置日期格式化的規則
      	public Formatter<Date> dateFormatter() {
      		return new DateFormatter(this.mvcProperties.getDateFormat());//日期格式化元件
      	}
      

      自己新增的格式化器轉換器,我們只需要放在容器中即可

  • Support for HttpMessageConverters (see below).

    • HttpMessageConverter:SpringMVC用來轉換Http請求和響應的;User—Json;
    • HttpMessageConverters 是從容器中確定;獲取所有的HttpMessageConverter;
      自己給容器中新增HttpMessageConverter,只需要將自己的元件註冊容器中(@Bean,@Component)
  • Automatic registration of MessageCodesResolver (see below).定義錯誤程式碼生成規則

  • Automatic use of a ConfigurableWebBindingInitializer bean (see below).
    我們可以配置一個ConfigurableWebBindingInitializer來替換預設的;(新增到容器)
    初始化WebDataBinder;
    請求資料=====JavaBean;

org.springframework.boot.autoconfigure.web:web的所有自動場景;

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

If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc.

2、擴充套件SpringMVC

    <mvc:view-controller path="/hello" view-name="success"/>
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/hello"/>
            <bean></bean>
        </mvc:interceptor>
    </mvc:interceptors>

編寫一個配置類(@Configuration),是WebMvcConfigurerAdapter型別;不能標註@EnableWebMvc;

既保留了所有的自動配置,也能用我們擴充套件的配置;

//使用WebMvcConfigurerAdapter可以來擴充套件SpringMVC的功能
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
       // super.addViewControllers(registry);
        //瀏覽器傳送 /atguigu 請求來到 success
        registry.addViewController("/atguigu").setViewName("success");
    }
}

原理:

1)、WebMvcAutoConfiguration是SpringMVC的自動配置類

2)、在做其他自動配置時會匯入;@Import(EnableWebMvcConfiguration.class)

    @Configuration
	public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {
      private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();

	 //從容器中獲取所有的WebMvcConfigurer
      @Autowired(required = false)
      public void setConfigurers(List<WebMvcConfigurer> configurers) {
          if (!CollectionUtils.isEmpty(configurers)) {
              this.configurers.addWebMvcConfigurers(configurers);
            	//一個參考實現;將所有的WebMvcConfigurer相關配置都來一起呼叫;  
            	@Override
             // public void addViewControllers(ViewControllerRegistry registry) {
              //    for (WebMvcConfigurer delegate : this.delegates) {
               //       delegate.addViewControllers(registry);
               //   }
              }
          }
	}

3)、容器中所有的WebMvcConfigurer都會一起起作用;

4)、我們的配置類也會被呼叫;

效果:SpringMVC的自動配置和我們的擴充套件配置都會起作用;

3、全面接管SpringMVC;

SpringBoot對SpringMVC的自動配置不需要了,所有都是我們自己配置;所有的SpringMVC的自動配置都失效了

我們需要在配置類中新增@EnableWebMvc即可;

//使用WebMvcConfigurerAdapter可以來擴充套件SpringMVC的功能
@EnableWebMvc
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
       // super.addViewControllers(registry);
        //瀏覽器傳送 /atguigu 請求來到 success
        registry.addViewController("/atguigu").setViewName("success");
    }
}

原理:

為什麼@EnableWebMvc自動配置就失效了;

1)@EnableWebMvc的核心

@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {

2)、

@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {

3)、

@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class,
		WebMvcConfigurerAdapter.class })
//容器中沒有這個元件的時候,這個自動配置類才生效
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
		ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {

4)、@EnableWebMvc將WebMvcConfigurationSupport元件匯入進來;

5)、匯入的WebMvcConfigurationSupport只是SpringMVC最基本的功能;

5、如何修改SpringBoot的預設配置

模式:

1)、SpringBoot在自動配置很多元件的時候,先看容器中有沒有使用者自己配置的(@Bean、@Component)如果有就用使用者配置的,如果沒有,才自動配置;如果有些元件可以有多個(ViewResolver)將使用者配置的和自己預設的組合起來;

2)、在SpringBoot中會有非常多的xxxConfigurer幫助我們進行擴充套件配置

3)、在SpringBoot中會有很多的xxxCustomizer幫助我們進行定製配置

6、RestfulCRUD

1)、預設訪問首頁

//使用WebMvcConfigurerAdapter可以來擴充套件SpringMVC的功能
//@EnableWebMvc   不要接管SpringMVC
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
       // super.addViewControllers(registry);
        //瀏覽器傳送 /atguigu 請求來到 success
        registry.addViewController("/atguigu").setViewName("success");
    }

    //所有的WebMvcConfigurerAdapter元件都會一起起作用
    @Bean //將元件註冊在容器
    public WebMvcConfigurerAdapter webMvcConfigurerAdapter(){
        WebMvcConfigurerAdapter adapter = new WebMvcConfigurerAdapter() {
            @Override
            public void addViewControllers(ViewControllerRegistry registry) {
                registry.addViewController("/").setViewName("login");
                registry.addViewController("/index.html").setViewName("login");
            }
        };
        return adapter;
    }
}

2)、國際化

1)、編寫國際化配置檔案;

2)、使用ResourceBundleMessageSource管理國際化資原始檔

3)、在頁面使用fmt:message取出國際化內容

步驟:

1)、編寫國際化配置檔案,抽取頁面需要顯示的國際化訊息

2)、SpringBoot自動配置好了管理國際化資原始檔的元件;

@ConfigurationProperties(prefix = "spring.messages")
public class MessageSourceAutoConfiguration {
    
    /**
	 * Comma-separated list of basenames (essentially a fully-qualified classpath
	 * location), each following the ResourceBundle convention with relaxed support for
	 * slash based locations. If it doesn't contain a package qualifier (such as
	 * "org.mypackage"), it will be resolved from the classpath root.
	 */
	private String basename = "messages";  
    //我們的配置檔案可以直接放在類路徑下叫messages.properties;
    
    @Bean
	public MessageSource messageSource() {
		ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
		if (StringUtils.hasText(this.basename)) {
            //設定國際化資原始檔的基礎名(去掉語言國家程式碼的)
			messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray(
					StringUtils.trimAllWhitespace(this.basename)));
		}
		if (this.encoding != null) {
			messageSource.setDefaultEncoding(this.encoding.name());
		}
		messageSource.setFallbackToSystemLocale(this.fallbackToSystemLocale);
		messageSource.setCacheSeconds(this.cacheSeconds);
		messageSource.setAlwaysUseMessageFormat(this.alwaysUseMessageFormat);
		return messageSource;
	}

3)、去頁面獲取國際化的值;

<!DOCTYPE html>
<html lang="en"  xmlns:th="http://www.thymeleaf.org">
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
		<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
		<meta name="description" content="">
		<meta name="author" content="">
		<title>Signin Template for Bootstrap</title>
		<!-- Bootstrap core CSS -->
		<link href="asserts/css/bootstrap.min.css" th:href="@{/webjars/bootstrap/4.0.0/css/bootstrap.css}" rel="stylesheet">
		<!-- Custom styles for this template -->
		<link href="asserts/css/signin.css" th:href="@{/asserts/css/signin.css}" rel="stylesheet">
	</head>

	<body class="text-center">
		<form class="form-signin" action="dashboard.html">
			<img class="mb-4" th:src="@{/asserts/img/bootstrap-solid.svg}" src="asserts/img/bootstrap-solid.svg" alt="" width="72" height="72">
			<h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">Please sign in</h1>
			<label class="sr-only" th:text="#{login.username}">Username</label>
			<input type="text" class="form-control" placeholder="Username" th:placeholder="#{login.username}" required="" autofocus="">
			<label class="sr-only" th:text="#{login.password}">Password</label>
			<input type="password" class="form-control" placeholder="Password" th:placeholder="#{login.password}" required="">
			<div class="checkbox mb-3">
				<label>
          		<input type="checkbox" value="remember-me"/> [[#{login.remember}]]
        </label>
			</div>
			<button class="btn btn-lg btn-primary btn-block" type="submit" th:text="#{login.btn}">Sign in</button>
			<p class="mt-5 mb-3 text-muted">© 2017-2018</p>
			<a class="btn btn-sm">中文</a>
			<a class="btn btn-sm">English</a>
		</form>

	</body>

</html>

效果:根據瀏覽器語言設定的資訊切換了國際化;

原理:

國際化Locale(區域資訊物件);LocaleResolver(獲取區域資訊物件);

		@Bean
		@ConditionalOnMissingBean
		@ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
		public LocaleResolver localeResolver() {
			if (this.mvcProperties
					.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
				return new FixedLocaleResolver(this.mvcProperties.getLocale());
			}
			AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
			localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
			return localeResolver;
		}
預設的就是根據請求頭帶來的區域資訊獲取Locale進行國際化

4)、點選連結切換國際化

/**
 * 可以在連線上攜帶區域資訊
 */
public class MyLocaleResolver implements LocaleResolver {
    
    @Override
    public Locale resolveLocale(HttpServletRequest request) {
        String l = request.getParameter("l");
        Locale locale = Locale.getDefault();
        if(!StringUtils.isEmpty(l)){
            String[] split = l.split("_");
            locale = new Locale(split[0],split[1]);
        }
        return locale;
    }

    @Override
    public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {

    }
}


 @Bean
    public LocaleResolver localeResolver(){
        return new MyLocaleResolver();
    }
}

3. 最後,提供一份SpringBoot中SpringMVC執行機制的思維導圖
在這裡插入圖片描述

導圖中包含備註資訊,網盤地址為(不含密碼):

https://pan.baidu.com/s/1h5O0T-9aOEDaIUmwqyvgkQ