springboot入门(六)——springmvc自动配置

SpringMVC自动配置

https://docs.spring.io/spring-boot/docs/2.2.5.BUILD-SNAPSHOT/reference/html/spring-boot-features.html#boot-features-spring-mvc-auto-configuration

springboot自动配置好了Springmvc.
以下是SpringBootSpringMVC的默认配置:

1.自动配置了ViewResolver(视图解析器:根据方法的返回值得到视图对象view,视图对象决定如何渲染,转发或者重定向)
ContentNegotiatingViewResolver->initServletContext():组合所有的视图解析器
如何定制:我们可以给容器中添加一个视图解析器,自动将其组合进来

测试:
启动类里

 @Bean
 public ViewResolver myViewResolver(){
     return new MyViewResolver();
 }
 private static class MyViewResolver implements ViewResolver{
     @Override
     public View resolveViewName(String s, Locale locale) throws Exception {
         return null;
     }
 }

DispatcherServlet类里:所有请求一进来回来到doDispatch方法
在这里插入图片描述
以调试的方式启动,看一下DispatcherServlet用到的视图解析器是什么。
随便发起一个请求
在这里插入图片描述
2.HttpMessageConverters:消息转换器, SpringMVC用来转换Http请求响应的,比如:方法返回了User类型,我想以json的形式写出去,那么我们就需要有一个能把Userjson写出去的HttpMessageConverters
WebMvcAutoConfiguration自动配置类里有一个配置类WebMvcAutoConfigurationAdapter,这个配置有只有一个有参数的构造器,那么这个构造器的参数都从容器中获取,这些参数就包括,ObjectProvider<HttpMessageConverters> messageConvertersProvider,所以只需要将自己的组件注册到容器中(@Bean,@Component

扩展springmvc

编写一个配置类(@Configuration),是WebMvcConfigurerAdapter类型;不能标注@EnableWebMvc; springtboot2.x版本WebMvcConfigurerAdapter过时了。使用 implements WebMvcConfigurer
例如:添加视图解析器,启动访问http://localhost:8082/atguigu

//使用WebMvcConfigurer可以扩展springmvc的功能
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
    /**
     * 发一个请求来一个页面,只要不放数据,就不用写controller空方法了,直接做视图映射
     * @param registry
     */
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        //要把什么请求映射到什么页面
        //浏览器发送 /atguigu 请求来到 success页面
        registry.addViewController("/atguigu").setViewName("success");
    }
}

既保留了所有的自动配置,也能用我们扩展的配置;

原理:
1),WebMvcAutoConfigurationSpringMVC的自动配置类
2),再做其他自动配置时会导入;@Import(EnableWebMvcConfiguration.class)
这个类的描述如下,重要的是父类DelegatingWebMvcConfiguration

@Configuration(proxyBeanMethods = false)
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {

父类DelegatingWebMvcConfiguration:有这么一段代码
自动装配一旦标注在方法上,方法的参数就要从容器中获取

//从容器中获取所有的WebMvcConfigurer
 @Autowired(required = false)  
 public void setConfigurers(List<WebMvcConfigurer> configurers) {
     if (!CollectionUtils.isEmpty(configurers)) {
     	//将获取到的WebMvcConfigurer添加到configurers中
         this.configurers.addWebMvcConfigurers(configurers);
     }
 }

configurers将所有的WebMvcConfigurer相关配置都来一起调用
例如:

//还是父类`DelegatingWebMvcConfiguration`:
 protected void addViewControllers(ViewControllerRegistry registry) {
      this.configurers.addViewControllers(registry);
  }
//WebMvcConfigurerComposite:configurers就是WebMvcConfigurerComposite,delegates保存着所有的WebMvcConfigurer
 public void addViewControllers(ViewControllerRegistry registry) {
 Iterator var2 = this.delegates.iterator();
 //遍历所有的WebMvcConfigurer
 while(var2.hasNext()) {
     WebMvcConfigurer delegate = (WebMvcConfigurer)var2.next();
     //然后把它们添加视图解析器的方法都调一遍
     delegate.addViewControllers(registry);
 }
}

3),容器中所有的WebMvcConfigurer都会一起起作用
4),我们的配置类也会被调用
效果:springmvc的自动配置和我们的扩展配置都会起作用;

全面接管SpringMVC

springbootspringmvc的自动配置不需要了,所有都是我们自己配;所有的SpringMVC的自动配置都失效。
我们需要在配置类中添加@EnableWebMvc
比如对静态资源的访问:
在静态资源文件夹下放置index.jsp

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>首页</h1>
</body>
</html>

启动项目,http://localhost:8082/,是可以正常访问的。
然后在配置类上加上注解@EnableWebMvc,重启发现访问不了。

原理:
为什么加了@EnableWebMvc自动配置就失效了?
1),@EnableWebMvc的核心

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

2),DelegatingWebMvcConfiguration

@Configuration(proxyBeanMethods = false)
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {

3),WebMvcAutoConfiguration

@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
//容器中没有这个组件的时候,这个自动配置类才生效
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
		ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {

4)、@EnableWebMvcWebMvcConfigurationSupport组件导入进来;那么WebMvcAutoConfiguration 自然不能生效
5)、导入的WebMvcConfigurationSupport只是SpringMVC最基本的功能;

如何修改SpringBoot的默认配置

模式:
1)、SpringBoot在自动配置很多组件的时候,先看容器中有没有用户自己配置的(@Bean、@Component)如果有就用用户配置的,如果没有,才自动配置(在自动配置类里,可以看到很多@ConditionalOnMissingBean,如果用户没有自己配置的组件,就是用自动配置的组件);如果有些组件可以有多个(ViewResolver)将用户配置的和自己默认的组合起来;
2)、在SpringBoot中会有非常多的xxxConfigurer帮助我们进行扩展配置 ,例如前面的WebMvcConfigurer
3)、在SpringBoot中会有很多的xxxCustomizer帮助我们进行定制配置

添加视图解析器

访问模板引擎里的login.html,登陆页,但是这里不涉及到数据,可以不写controller空方法,直接做视图映射

    //访问模板引擎里的login.html,登陆页
    //因为不涉及数据,也可以写在视图解析器里
    @RequestMapping({"/","/login.html"})
    public String login(){
        return "login";
    }
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
	 //方式一
     //发一个请求来一个页面,只要不放数据,就不用写controller空方法了,直接做视图映射
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        //要把什么请求映射到什么页面
        //浏览器发送 /atguigu 请求来到 success页面
        registry.addViewController("/atguigu").setViewName("success");
//        registry.addViewController("/").setViewName("login");
//        registry.addViewController("/login.html").setViewName("login");
    }
    //另一种方式  利用前面分析扩展springmvc的原理
    //所有的WebMvcConfigurer都会一起起作用
    @Bean
    public WebMvcConfigurer webMvcConfigurer(){
        WebMvcConfigurer webMvcConfigurer = new WebMvcConfigurer() {
            @Override
            public void addViewControllers(ViewControllerRegistry registry) {
                registry.addViewController("/").setViewName("login");
                registry.addViewController("/login.html").setViewName("login");
            }
        };
        return webMvcConfigurer;
    }
}

国际化

以前springmvc
1),编写国际化配置文件
2),使用ResourceBundleMessageSource管理国际化资源文件
3)、如果使用jsp页面,在页面使用fmt:message取出国际化内容

springboot国际化:
1),编写国际化配置文件,抽取页面需要显示的国际化消息
例如:在登陆页面页面
在这里插入图片描述
新建国际化文件:
login.properties 没有指定语言信息情况下默认的国际化配置
login_zh_CN.properties 中文的
login_en_US.properties 英文的

在这里插入图片描述
login_zh_CN.properties 语言代码zh+国家代码CN,当新建了一个login_zh_CN.propertiesidea自动切换到国际化视图
在这里插入图片描述
在这里插入图片描述
写配置:随便进一个国际化配置文件
在这里插入图片描述
在这里插入图片描述
2),Springboot自动配置好了管理国际化资源文件的组件
MessageSourceAutoConfiguration:

//启动指定类的ConfigurationProperties功能
@EnableConfigurationProperties
public class MessageSourceAutoConfiguration {
	@Bean
	//将配置文件中以spring.messages开头的配置与MessageSourceProperties绑定到一起,
	//并通过@Bean注解将MessageSourceProperties 注入到容器中
	//有些xxxProperties标注了@ConfigurationProperties(prefix = "。。。"),但是这个是没标注。而是在这里标注
	@ConfigurationProperties(prefix = "spring.messages")
	public MessageSourceProperties messageSourceProperties() {
		return new MessageSourceProperties();
	}
	//参数properties从容器中获取,就是上面那个
	@Bean
	public MessageSource messageSource(MessageSourceProperties properties) {
		ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
		if (StringUtils.hasText(properties.getBasename())) {
			//设置国际化资源文件的基础名(去掉语言国家代码的) 
			//比如:login_en_US.properties  login就叫基础名
			//进入MessageSourceProperties ,可以看到基础名默认叫messages
			messageSource.setBasenames(StringUtils
					.commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(properties.getBasename())));
		}
		if (properties.getEncoding() != null) {
			messageSource.setDefaultEncoding(properties.getEncoding().name());
		}
		messageSource.setFallbackToSystemLocale(properties.isFallbackToSystemLocale());
		Duration cacheDuration = properties.getCacheDuration();
		if (cacheDuration != null) {
			messageSource.setCacheMillis(cacheDuration.toMillis());
		}
		messageSource.setAlwaysUseMessageFormat(properties.isAlwaysUseMessageFormat());
		messageSource.setUseCodeAsDefaultMessage(properties.isUseCodeAsDefaultMessage());
		return messageSource;
	}

在这里插入图片描述
配置:spring.messages.basename=i18n.login

3),去页面获取国际化的值
如果使用jsp页面,在页面使用fmt:message取出国际化内容
但是现在springboot推荐使用的是thymeleaf,如何获取呢
文本:th:text="#{login.tip}

<h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">Please sign in</h1>

placeholder:th:placeholder="#{login.username}"

<input type="text" class="form-control" placeholder="Username" required="" autofocus="" th:placeholder="#{login.username}">

行内写法:[[#{login.remenber}]]

 <input type="checkbox" value="remember-me" /> [[#{login.remenber}]]

更多下载thymeleaf文档查看:

https://www.thymeleaf.org/documentation.html   官网

在这里插入图片描述
上面的参考自第4,12章

测试国际化:
启动项目,打开谷歌浏览器,查看语言,设置-》高级里查看
在这里插入图片描述
访问:http://localhost:8082/crud/login.html
在这里插入图片描述
乱码解决:
在这里插入图片描述
然后到国际化文件中,把中文重写。重新启动,访问即可。把浏览器的语言换成美国英语,刷新页面又会变成英文
在这里插入图片描述

这里是通过改变浏览器的语言来实现国际化的切换,那如何实现通过点按钮来切换呢
原理
国际化Locale(区域信息对象);LocaleResolver(获取区域信息对象);
WebMvcAutoConfiguration

@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;
}

进入WebMvcProperties发现,所以默认LocaleResolverACCEPT_HEADER

private LocaleResolver localeResolver = LocaleResolver.ACCEPT_HEADER;

AcceptHeaderLocaleResolver

    public Locale resolveLocale(HttpServletRequest request) {
        Locale defaultLocale = this.getDefaultLocale();
        if (defaultLocale != null && request.getHeader("Accept-Language") == null) {
            return defaultLocale;
        } else {
        	//从请求头中拿到区域信息
            Locale requestLocale = request.getLocale();

默认的区域信息解析器就是根据请求头带来的区域信息获取Locale进行国际化
可以看看:
在这里插入图片描述
自己写一个LocaleResolver,不使用WebMvcAutoConfiguration下自动配置的LocaleResolver

public class MyLocalResolver implements LocaleResolver {
    @Override
    public Locale resolveLocale(HttpServletRequest httpServletRequest) {
        String l = httpServletRequest.getParameter("l");
        //如果链接没带区域信息就使用系统默认的
        //也可以使用httpServletRequest.getLocale()获取请求头的
        Locale locale = Locale.getDefault();
        if (!StringUtils.isEmpty(l)){
            String[] s = l.split("_");
            locale=new Locale(s[0],s[1] );
        }
        return locale;
    }
    @Override
    public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
    }
}
//在配置类中注入
   @Bean
   public LocaleResolver localeResolver(){
       return new MyLocalResolver();
   }

可以在连接上携带区域信息:

<a class="btn btn-sm" th:href="@{/login.html(l='zh_CN')}">中文</a>
<a class="btn btn-sm" th:href="@{/login.html(l='en_US')}">English</a>

测试:点击中文,英文即可切换。连接不带区域信息的使用系统默认的
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值