Springboot學習03-SpringMVC自動配置

Springboot學習03-SpringMVC自動配置

 

前言

在SpringBoot官網對於SpringMVCde 自動配置介紹html

1-原文介紹以下:

Spring MVC Auto-configuration

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

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

  • Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.
  • Support for serving static resources, including support for WebJars (covered later in this document)).
  • Automatic registration of ConverterGenericConverter, and Formatter beans.
  • 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).
  • 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 RequestMappingHandlerMappingRequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver, you can declare a WebMvcRegistrationsAdapter instance to provide such components.spring-mvc

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

 

2-谷歌翻譯以下

Spring MVC自動配置

Spring Boot爲Spring MVC提供自動配置,且適用於大多數應用程序。mvc

自動配置在Spring默認配置基礎上,添加了如下功能:app

  • 包括:ContentNegotiatingViewResolver和BeanNameViewResolver bean。
  • 支持提供靜態資源,包括對WebJars的支持。
  • 自動註冊Converter,GenericConverter和Formatter bean。
  • 支持HttpMessageConverters。
  • 自動註冊MessageCodesResolver(本文檔後面會介紹)。
  • 靜態 index.html 頁面支持。
  • 自定義Favicon支持。
  • 自動使用ConfigurableWebBindingInitializer bean)。

若是要保留Spring Boot MVC功能而且想要添加其餘MVC配置(interceptors,formatters,view controllers和其餘功能),能夠添加本身的@Configuration類,類型爲WebMvcConfigurer,但不包含@EnableWebMvc。若是您但願能夠自定義RequestMappingHandlerMapping,RequestMappingHandlerAdapter或ExceptionHandlerExceptionResolver實例,則能夠聲明WebMvcRegistrationsAdapter實例以提供此類組件。ide

若是您想徹底控制Spring MVC,可使用@EnableWebMvc添加本身的@Configuration註釋。spring-boot

 

如下正文,對上面標紅的內容進行分析學習

 

正文

 

1- ContentNegotiatingViewResolver and BeanNameViewResolver beans

1-1-源碼出處

 

public class WebMvcAutoConfiguration { //-在Springboot啓動初始化時,自動裝載WebMvcAutoConfiguration類, //其中包括WebMvcAutoConfiguration內部類WebMvcAutoConfigurationAdapter下的ContentNegotiatingViewResolver viewResolver()方法
    public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ResourceLoaderAware { @Bean @ConditionalOnBean({ViewResolver.class}) @ConditionalOnMissingBean( name = {"viewResolver"}, value = {ContentNegotiatingViewResolver.class} ) public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) { ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver(); resolver.setContentNegotiationManager((ContentNegotiationManager)beanFactory.getBean(ContentNegotiationManager.class)); resolver.setOrder(-2147483648); return resolver; } } }

 

public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport implements ViewResolver, Ordered, InitializingBean { //2-ContentNegotiatingViewResolver 執行其內部initServletContext()初始化方法,從BeanFactoryUtils中獲取所有ViewResolver
    protected void initServletContext(ServletContext servletContext) { Collection<ViewResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.obtainApplicationContext(), ViewResolver.class).values(); ViewResolver viewResolver; if (this.viewResolvers == null) { Iterator var3 = matchingBeans.iterator(); while(var3.hasNext()) { viewResolver = (ViewResolver)var3.next(); if (this != viewResolver) { this.viewResolvers.add(viewResolver); } } } …………………………省略 } //2-當一個請求進來時,調用ContentNegotiatingViewResolver 下的View resolveViewName()方法,,並返回bestView,主要包括beanName參數,即對應渲染的(好比:html)文件名稱
 @Nullable public View resolveViewName(String viewName, Locale locale) throws Exception { //ContentNegotiatingViewResolver 根據文件名和請求頭類型來決定返回什麼樣的View。而mediaTypes這個屬性存儲了 你請求後綴名 或者 參數 所對應 的mediaType 
        RequestAttributes attrs = RequestContextHolder.getRequestAttributes(); List<MediaType> requestedMediaTypes = this.getMediaTypes(((ServletRequestAttributes)attrs).getRequest()); if (requestedMediaTypes != null) { //獲取候選視圖對象
            List<View> candidateViews = this.getCandidateViews(viewName, locale, requestedMediaTypes); //選擇一個最適合的視圖對象
            View bestView = this.getBestView(candidateViews, requestedMediaTypes, attrs); if (bestView != null) { //返回視圖對象
                return bestView; } } ……………省略 } //2-1-獲取候選視圖對象
    private List<View> getCandidateViews(String viewName, Locale locale, List<MediaType> requestedMediaTypes) throws Exception { List<View> candidateViews = new ArrayList(); if (this.viewResolvers != null) { //獲取所有視圖解析器
            Iterator var5 = this.viewResolvers.iterator(); //篩選出候選View
            while(var5.hasNext()) { …………………………省略 while(var11.hasNext()) { String extension = (String)var11.next(); String viewNameWithExtension = viewName + '.' + extension; view = viewResolver.resolveViewName(viewNameWithExtension, locale); if (view != null) { candidateViews.add(view);//獲取view
 } } } } return candidateViews; } }

 

 

1-2-源碼解釋

  • 1-在Springboot啓動初始化時,自動裝載WebMvcAutoConfiguration類,其中包括WebMvcAutoConfiguration內部類WebMvcAutoConfigurationAdapter下的ContentNegotiatingViewResolver viewResolver()方法
  • 2-ContentNegotiatingViewResolver 執行其內部initServletContext()初始化方法,從BeanFactoryUtils中獲取所有ViewResolver
  • 3-當一個請求進來時,調用ContentNegotiatingViewResolver 下的View resolveViewName()方法根據方法的返回值獲得視圖對象(View),,並返回bestView,主要包括beanName參數,即對應渲染的(好比:html)文件名稱

1-3-自定義視圖解析器

1-3-1-自定義解析其源碼

@SpringBootApplication public class SpringbootdemoApplication { public static void main(String[] args) { SpringApplication.run(SpringbootdemoApplication.class, args); } //在Springboot啓動時,加載自定義的MyViewResolver類
 @Bean public ViewResolver myViewResolver(){ return new MyViewResolver(); } //(這裏爲了方便,在啓動類下寫了一個內部類) //MyViewResolver實現接口類ViewResolver
    private static class MyViewResolver implements ViewResolver{ @Override public View resolveViewName(String s, Locale locale) throws Exception { return null; } } }

 

1-3-2-源碼解析

  • 1-自定義MyViewResolver 類必須實現ViewResolver接口
  • 2-並在Springboot初始化是,被自動加載

1-3-3-使用結果:在Spring分發請求時,發現自定義的MyViewResolver被被加載

 

 

2-支持提供靜態資源,包括對WebJars的支持。請參考本人博客:http://www.javashuo.com/article/p-dyutlags-hs.html

 

3-自動註冊Converter,GenericConverter和Formatter bean

3-1-自定義Converter

 

//1-controller層
@Controller public class DemoController { Logger log = LoggerFactory.getLogger(DemoController.class); @RequestMapping(value="get/student") public String getStudent(Student student,Model model){ log.debug("student: " + student); model.addAttribute("student",student); return "student"; } } //2-自定義converter @Configuration public class StringToStudentConverrter implements Converter<String,Student> { @Override public Student convert(String s) { //student=tyj-18
        String[] split = s.split("-"); Student student = new Student(split[0],Integer.parseInt(split[1])); return student; } }

 

//3-html示例
<!
DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div th:text="${student.name}"></div> <div th:text="${student.age}"></div> <strong>success!</strong> </body> </html>

4-支持HttpMessageConverters:SpringMVC用來轉換Http請求和響應的;是從容器中肯定;獲取全部的HttpMessageConverter

4-2-自定義HttpMessageConverters

//1-自定義HttpMessageConverters
public class MyMessageConveter extends AbstractHttpMessageConverter<Student>{ public MyMessageConveter() { //Content-Type= application/xxx-tyj
        super(new MediaType("application", "xxx-tyj", Charset.forName("UTF-8"))); } @Override protected boolean supports(Class<?> aClass) { // 代表只處理UserEntity類型的參數。
        return Student.class.isAssignableFrom(aClass); } //重寫readlntenal 方法,處理請求的數據。代碼代表咱們處理由「-」隔開的數據,並轉成 Student類型的對象。
 @Override protected Student readInternal(Class<? extends Student> aClass, HttpInputMessage httpInputMessage) throws IOException, HttpMessageNotReadableException { String content = StreamUtils.copyToString(httpInputMessage.getBody(), Charset.forName("UTF-8")); String[] split = content.split("-"); return new Student(split[0],Integer.parseInt(split[1])); } //重寫writeInternal ,處理如何輸出數據到response。
 @Override protected void writeInternal(Student student, HttpOutputMessage httpOutputMessage) throws IOException, HttpMessageNotWritableException { String out = "hello: " +student.getName() + " ,你今年" + student.getAge() + "了麼?"; httpOutputMessage.getBody().write(out.getBytes()); } }
//2-加載自定義的MyMessageConveter 
@Configuration public class MySpringBootConfig { @Bean public MyMessageConveter MyMessageConveter (){ return new MyMessageConveter(); } }
//3-controller
@Controller public class DemoController { @RequestMapping(value="hello/student",method = POST) @ResponseBody public Student helloStudent(@RequestBody Student student){ return student; } }

 

接口測試 URL:POST localhost:8080/hello/student header: Content-Type = application/xxx-tyj body: tyj-21 返回值:hello: tyj ,你今年21了麼?

 

4-3-添加一個converter的方式有三種

@Configuration public class MyWebMvcConfigurerAdapter extends WebMvcConfigurerAdapter { // 添加converter的第一種方式,代碼很簡單,也是推薦的方式 // 這樣作springboot會把咱們自定義的converter放在順序上的最高優先級(List的頭部) // 即有多個converter都知足Accpet/ContentType/MediaType的規則時,優先使用咱們這個
 @Bean public MyMessageConveter MyMessageConveter (){ return new MyMessageConveter(); } // 添加converter的第二種方式 // 一般在只有一個自定義WebMvcConfigurerAdapter時,會把這個方法裏面添加的converter(s)依次放在最高優先級(List的頭部) // 雖然第一種方式的代碼先執行,可是bean的添加比這種方式晚,因此方式二的優先級 大於 方式一
 @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { // add方法能夠指定順序,有多個自定義的WebMvcConfigurerAdapter時,能夠改變相互之間的順序 // 可是都在springmvc內置的converter前面
        converters.add(new MyMessageConveter()); } // 添加converter的第三種方式 // 同一個WebMvcConfigurerAdapter中的configureMessageConverters方法先於extendMessageConverters方法執行 // 能夠理解爲是三種方式中最後執行的一種,不過這裏能夠經過add指定順序來調整優先級,也可使用remove/clear來刪除converter,功能強大 // 使用converters.add(xxx)會放在最低優先級(List的尾部) // 使用converters.add(0,xxx)會放在最高優先級(List的頭部)
 @Override public void extendMessageConverters(List<HttpMessageConverter<?>> converters) { converters.add(new MyMessageConveter()); } }

 

5-自動註冊MessageCodesResolver:定義錯誤代碼生成規則

 

6-靜態 index.html 頁面支持。請參考本人博客:http://www.javashuo.com/article/p-dyutlags-hs.html

 

7-自定義Favicon支持。請參考本人博客:http://www.javashuo.com/article/p-dyutlags-hs.html

 

8-自動使用ConfigurableWebBindingInitializer bean。

 

 

 

參考資料

1-https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/reference/htmlsingle/#boot-features-spring-mvc-auto-configuration

2-http://www.cnblogs.com/huhx/p/baseusespringbootconverter1.html

3-http://www.javashuo.com/article/p-pvlxbqjz-dq.html

4-http://www.cnblogs.com/hhhshct/p/9676604.html

相關文章
相關標籤/搜索