目录
四、Spring MVC auto-configuration
8.3.2使用ResourceBundleMessageSource管理国际化资源文件
一、简介
1.1步骤
1)、新建SpringBoot应用,选中需要的模块;
2)、SpringBoot已经默认将这些场景配置好了,只需要在配置文件中指定少量配置就可以运行;
3)、自己编写业务代码;
1.2SpringBoot帮我们配置了什么?
******AutoConfiguration: 帮我们给容器中自动配置组件
******Properties: 配置类来封装配置文件的内容
二、SpringBoot对静态资源的映射规则
可以看WebMvcAutoConfiguration里
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
} else {
Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
if (!registry.hasMappingForPattern("/webjars/**")) {
this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"}).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(WebMvcAutoConfiguration.getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
}
}
2.1 /webjars/**
都去 classpath:/META-INF/resources/webjars/找资源;
其中:webjars:以jar包的方式引入静态资源;官网:https://www.webjars.org/(springboot是通过webjars管理静态资源)
比如访问:Jquery
1)、添加依赖:
<!--引入jquery的webjar-->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.1.1</version>
</dependency>
2)、就可以看见:
3)、访问:http://localhost:8080/webjars/jquery/3.1.1/jquery.js
2.2 /** 如果访问的资源未知,会去以下文件夹里面找
"classpath:/META-INF/resources/"
"classpath:/resources/"
"classpath:/static/"
"classpath:/public/"
2.3欢迎页 映射配置
2.4图标修改 favicon.ico
(当然可通过 spring.resources.static-location = 来修改资源文件路径)
三、模板引擎
3.1背景
以前开发,我们需要将HTML转换为jsp页面,转jsp的好处就是,我们可以用<c:foreach>等,也能写java代码。
而springboot首先以jar包的方式,不是war包方式,其次,我们使用的是嵌入式的tomcat,默认是不支持jsp。
因此呢,springboot推荐使用模板引擎。
模板引擎的作用就是:页面上的某些值是动态的,我们用一些表达式表示,这些值从哪来呢?我们组装一些数据,然后把页面模板和数据交给模板引擎,模板引擎将数据填充到对应位置,生成一个最终内容,显示出来。
3.2springboot推荐的Thymeleaf
语法简单、功能强大
3.3引入Thymeleaf
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
3.4Thymeleaf使用&语法
3.4.1源码,原理
public class ThymeleafProperties {
private static final Charset DEFAULT_ENCODING;
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
private boolean checkTemplate = true;
private boolean checkTemplateLocation = true;
private String prefix = "classpath:/templates/"; //只要放在这个路径下就能自动渲染了
private String suffix = ".html";
private String mode = "HTML";
官网:https://www.thymeleaf.org/https://www.thymeleaf.org/
3.4.2使用
1)导入thymeleaf的名称空间
<html lang="en" xmlns:th="http://www.thymeleaf.org">
2)放数据
3)显示
3.4.3语法规则
表达式: 4 Standard Expression Syntax
Simple expressions: //表达式语法
Variable Expressions: ${...} //获取值 OGNL
//1.获取对象的属性、调用方法
//2.使用内置的基本对象
//#ctx : the context object.
//#vars: the context variables.
//#locale : the context locale.
//#request : (only in Web Contexts) the HttpServletRequest object. ${session.foo}
//#response : (only in Web Contexts) the HttpServletResponse object.
//#session : (only in Web Contexts) the HttpSession object.
//#servletContext : (only in Web Contexts) the ServletContext object.
//3.内置的工具对象
//#execInfo : information about the template being processed.
//#messages : methods for obtaining externalized messages inside variables expressions, in the same way as they
would be obtained using #{…} syntax.
//#uris : methods for escaping parts of URLs/URIs
//#conversions : methods for executing the configured conversion service (if any).
//#dates : methods for java.util.Date objects: formatting, component extraction, etc.
//#calendars : analogous to #dates , but for java.util.Calendar objects.
//#numbers : methods for formatting numeric objects.
//#strings : methods for String objects: contains, startsWith, prepending/appending, etc.
//#objects : methods for objects in general.
//#bools : methods for boolean evaluation.
//#arrays : methods for arrays.
//#lists : methods for lists.
//#sets : methods for sets.
//#maps : methods for maps.
//#aggregates : methods for creating aggregates on arrays or collections.
//#ids : methods for dealing with id attributes that might be repeated (for example, as a result of an iteration).
Selection Variable Expressions: *{...} //选择表达式,和${}一样,
//补充:配合th:Object 使用
Message Expressions: #{...} //获取国际化内容
Link URL Expressions: @{...} //定义url
//<!-- Will produce '/gtvg/order/details?orderId=3' (plus rewriting) -->
// <a href="details.html" th:href="@{/order/details(orderId=${o.id})}">view</a>
Fragment Expressions: ~{...} //片段表达式
Literals //字面量
Text literals: 'one text' , 'Another one!' ,…
Number literals: 0 , 34 , 3.0 , 12.3 ,…
Boolean literals: true , false
Null literal: null
Literal tokens: one , sometext , main ,…
Text operations: //文本操作
String concatenation: +
Literal substitutions: |The name is ${name}|
Arithmetic operations: //数字运算
Binary operators: + , - , * , / , %
Minus sign (unary operator): -
Boolean operations: //布尔运算
Binary operators: and , or
Boolean negation (unary operator): ! , not
Comparisons and equality: //比较运算
Comparators: > , < , >= , <= ( gt , lt , ge , le )
Equality operators: == , != ( eq , ne )
Conditional operators: //条件运算 (三元运算符)
If-then: (if) ? (then)
If-then-else: (if) ? (then) : (else)
Default: (value) ?: (defaultvalue)
Special tokens: //不操作写 -
No-Operation: _
演示:
四、Spring MVC auto-configuration
五、如何修改SpringBoot的默认配置
模式:
1)、SpringBoot在自动化配置很多组件的时候,先看容器中有没有用户自己配置的(@Bean @Component)如果有就用用户自己配置的,如果没有,才自动配置,如果有些组件可以有多个(ViewResolver)将用户配置的和自己默认的组合起来
六、扩展SpringMvc
编写一个配置类(@Configuration),是WebMvcConfigurerAdapter类型,不能标注@EnableWebMvc
即保留了自动配置,也可以使用自定义的配置。
原理:
1)、WebMvcAutoConfiguration是SpringMvc自动配置类;
2)、在做其他自动配置时会导入:@Import(EnableWebMvcConfiguration.class);
3)、容器中所有的WebMvcConfiguration会一起起作用;
4)、我们的配置类也会被调用。
七、全面接管SpringMvc
springboot对springmvc的自动配置就不需要了,所有都是我们自己配,那么在配置类中加@EnableWebMvc即可。
原理:
@Import({DelegatingWebMvcConfiguration.class})
public @interface EnableWebMvc {
}
@Configuration(
proxyBeanMethods = false
)
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnWebApplication(
type = Type.SERVLET
)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class}) //容器中没有这个组件的时候,这个自动配置类才生效
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration {
@EnableWebMvc将WebMvcConfigurationSupport组件导入进来;
导入的WebMvcConfigurationSupport只是Springmvc最基本的功能;
八、实际使用
8.1引入依赖
<!--引入BootStarp的webjar-->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>4.4.1</version>
</dependency>
8.2页面引用
<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 th:href="@{/webjars/bootstrap/4.4.1/css/bootstrap.css}" rel="stylesheet">
<!-- Custom styles for thiss template --><!-- 自定义css文件 任意一个方式都行-->
<link href="asserts/css/signin.css" th:href="@{/asserts/css/signin.css}" rel="stylesheet">
</head>
好处:会自动修改引用路径!
8.3国际化
8.3.1编写国际化配置文件
结果:
8.3.2使用ResourceBundleMessageSource管理国际化资源文件
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnMissingBean(
name = {"messageSource"},
search = SearchStrategy.CURRENT
)
@AutoConfigureOrder(-2147483648)
@Conditional({MessageSourceAutoConfiguration.ResourceBundleCondition.class})
@EnableConfigurationProperties
public class MessageSourceAutoConfiguration {
private static final Resource[] NO_RESOURCES = new Resource[0];
public MessageSourceAutoConfiguration() {
}
@Bean
@ConfigurationProperties(
prefix = "spring.messages"
)
public MessageSourceProperties messageSourceProperties() {
return new MessageSourceProperties();
}
@Bean
public MessageSource messageSource(MessageSourceProperties properties) {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
if (StringUtils.hasText(properties.getBasename())) {
//设置国际化资源文件的基础名(去掉语言国家代码的)
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;
}
protected static class ResourceBundleCondition extends SpringBootCondition {
private static ConcurrentReferenceHashMap<String, ConditionOutcome> cache = new ConcurrentReferenceHashMap();
protected ResourceBundleCondition() {
}
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
//通过 spring.messages.basename 指定文件
String basename = context.getEnvironment().getProperty("spring.messages.basename", "messages");
ConditionOutcome outcome = (ConditionOutcome)cache.get(basename);
if (outcome == null) {
outcome = this.getMatchOutcomeForBasename(context, basename);
cache.put(basename, outcome);
}
return outcome;
}
8.3.3在页面使用国际化内容
看参考3.4.3知:#{}来获取
国际化Locale(区域信息对象),LocaleResolver(获取区域信息对象)
原理:
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(
prefix = "spring.mvc",
name = {"locale"}
)
public LocaleResolver localeResolver() {
if (this.mvcProperties.getLocaleResolver() == org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties.LocaleResolver.FIXED) {
return new FixedLocaleResolver(this.mvcProperties.getLocale());
} else {
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
return localeResolver;
}
}
//默认的就是根据request带来的区域信息获取Local进行国际化
定义自己的Locale:
加入到容器:
8.3.4html代码:
<!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 th:href="@{/webjars/bootstrap/4.4.1/css/bootstrap.css}" rel="stylesheet">
<!-- Custom styles for thiss template -->
<link th:href="@{/asserts/css/signin.css}" rel="stylesheet">
</head>
<body class="text-center">
<form class="form-signin" action="dashboard.html" method="post">
<img class="mb-4" th: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" name="username" class="form-control" placeholder="Username" th:placeholder="#{login.username}" required="" autofocus="">
<label class="sr-only" th:text="#{login.password}" >Password</label>
<input type="password" name="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" th:href="@{/login.html(l='zh_CN')}" >中文</a>
<a class="btn btn-sm" th:href="@{/login.html(l='en_US')}">English</a>
</form>
</body>
</html>
8.3.5效果
九、模板引擎实时生效
9.1禁用缓存
spring.thymeleaf.cache=false
9.2重新编译: Ctrl + F9
9.3登录错误信息提示
<p style="color: red" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>
9.4拦截器进行登录检查
/*
*登录检查
* */
public class LoginHandlerInterceptor implements HandlerInterceptor {
//目标方法执行之前
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Object user = request.getSession().getAttribute("loginUser");
if(user == null){
request.setAttribute("msg","没有权限请先登录!");
request.getRequestDispatcher("/index.html").forward(request,response);
return false;
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
@Bean
public WebMvcConfigurer webMvcConfigurerAdapter(){
return new WebMvcConfigurer(){
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("login");
registry.addViewController("/index.html").setViewName("login");
registry.addViewController("/main.html").setViewName("dashboard");
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/","/index.html","/asserts/**","/webjars/**","/user/login");
}
};
}