详情可参考官方文档:SpringBoot2.4.0开发WEB应用官方文档
所有的请求/webjars/**
,都去classpath:/META-INF/resources/webjars/
找资源;使用webjars可以用jar包的方式引入静态资源:http://www.webjars.org/,想使用什么静态资源,导入对应的依赖就可以了。
例如:利用webjars访问jquery下的静态资源
localhost:8080/webjars/jquery/3.3.1/jquery.js
当然前提是需要导入jquery的webjars依赖:
<dependency>
<groupId>org.webjarsgroupId>
<artifactId>jqueryartifactId>
<version>3.5.1version>
dependency>
访问当前项目的任何资源,都去静态资源的文件夹找映射关系。
"classpath:/META‐INF/resources/",
"classpath:/resources/",
"classpath:/static/",
"classpath:/public/"
"/":当前项目的根路径
静态资源文件夹下的所有index.html
页面都被"/**
"映射;
所有的**/favicon.ico
都是在静态资源文件下寻找,但是在SpringBoot2.4.0中没有这一项了。
可以设置和静态资源有关的参数,缓存时间等,例如可以自定义静态资源的位置,定义之后,默认的静态资源位置将会失效。
spring.resources.static-locations=classpath:/hello/,classpath:/glp/
纯静态的页面开发会很麻烦,SpringBoot中使用模板引擎。模板引擎主要有:
JSP、Velocity、Freemarker、Thymeleaf等。它们都有着共同的思想:模板引擎负责将数据填入模板中的表达式中。
SpringBoot推荐使用Thymeleaf模板引擎。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
springBoot2.4.0提供的Thymeleaf默认版本是3.0.11
(1)thymeleaf的属性配置文件
属性配置文件中有一个默认的前缀和后缀,只要我们把HTML页面放在classpath:/templates/
,thymeleaf就能自动渲染了。
(2)Thymeleaf的语法
参考Thymeleaf的官方文档:https://www.thymeleaf.org/
1)导入名称空间
使用时需要导入 thymeleaf的名称空间,导入之后将会有Thymeleaf的语法提示:
<html lang="en" xmlns:th="http://www.thymeleaf.org">
2)简单测试
@RequestMapping("/t1")
public String test1(Model model){
//存入数据
model.addAttribute("hello","HelloWorld");
//classpath:/templates/test.html
return "test";
}
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF‐8">
<title>Titletitle>
head>
<body>
<h1>成功!h1>
<!‐‐th:text 将div里面的文本内容设置为 ‐‐>
<div th:text="${hello}">这是显示欢迎信息div>
body>
html>
注意:
开发期间模板引擎页面修改以后,要实时生效
spring.thymeleaf.cache=false
ctrl+f9
:重新编译 <thymeleaf.version>3.0.12.RELEASE</thymeleaf.version>
奈何在开始布置项目时,使用thymleaf访问模板老是报404。在百般测试之下,最后将本地仓库全部清空,然后重新加载依赖,最后成功解决。这应该是下载过程中网速不好,依赖包损坏的问题。
3)语法标签
th:text
:改变当前元素里面的文本内容
th:任意html属性
:可以替换原生属性的值
注意:
[ [ ] ]
等价于th:text
,[ ( ) ]
等价于th:utext
4)表达式语法
① ${...}
:获取变量值
② *{...}
:选择表达式:和${}
在功能上一样
th:object="${session.user}:
来使用。③ #{...}
:获取国际化内容
④ @{...}
:定义URL
th:href=@{/order/process(execId=${execId},execType='FAST')}
⑤ ~{...}
:片段引用表达式
⑥ 字面量
⑦ 文本操作
⑧ 数学运算:+ , ‐ , * , / , %
⑨ 布尔运算:and , or,! , not
⑩ 比较运算:> , < , >= , <=(gt , lt , ge , le)
11 条件运算:(if) ? (then) : (else)
12 _
:缺省:(if) ? (then) : _
5)简单应用
@RequestMapping("/t2")
public String test2(Map<String,Object> map){
//存入数据
map.put("msg","Hello
");
map.put("users", Arrays.asList("cbj","glp"));
return "test";
}
<h4 th:each="user :${users}" th:text="${user}">h4>
<h4>
<span th:each="user:${users}">[[${user}]]span>
h4>
6)公共页面抽取
将某页面的一部分加入th:fragment
,来抽取公共片段。
<div th:fragment="copy">
<h1>hello</h1>
</div>
在其它的html中使用th:insert
引入公共片段
<div th:insert="~{footer :: copy}"></div>
其中:footer为模板名,copy为抽取的片段名。
三种引入公共片段的th属性:
th:insert
:将公共片段整个插入到声明引入的元素中
th:replace
:将声明引入的元素替换为公共片段
th:include
:将被引入的片段的内容包含进这个标签中
三种引入方式举例:
抽取片段:
<footer th:fragment="copy">
© 2011 The Good Thymes Virtual Grocery
footer>
引入方式:
<div th:insert="footer :: copy">div>
<div th:replace="footer :: copy">div>
<div th:include="footer :: copy">div>
效果:
<div>
<footer>
© 2011 The Good Thymes Virtual Grocery
footer>
div>
<footer>
© 2011 The Good Thymes Virtual Grocery
footer>
<div>
© 2011 The Good Thymes Virtual Grocery
div>
注意:
th:insert
等属性进行引入,可以不用写~{}
:行内写法可以加上:[[~{}]];[(~{})]
; <div th:insert="~{dashboard::#sidebar}"></div>
7)引入片段时传入参数
在抽取的公共片段中做判断,然后在不同的引入页面传入不同的参数,可以对更改不同页面的参数,比如文字高亮的显示。
公共片段:
在不同页面引入时传递参数:
8)日期格式化
th:text="${#dates.format(emp.birth, 'yyyy/MM/dd HH:mm')}"
Spring Boot为Spring MVC提供了自动配置。以下是SpringBoot对SpringMVC的自动配置:
1)配置了视图解析器:ContentNegotiatingViewResolver和BeanNameViewResolver
2)提供静态资源的支持,包括对WebJars的支持。
3)自动注入了转换器Converter、GenericConverter和格式化器Formatter。
4)对HttpMessageConverters的支持。
5) MessageCodesResolver的自动注册。
6)静态index . html的支持。
7)自动使用ConfigurableWebBindingInitializer
注意:
(1)扩展配置的使用
如果您想要保留那些SpringBoot MVC定制并进行更多的MVC定制(拦截器、格式化器、视图控制器和其他特性),您可以添加自己的WebMvcConfigurer
类型的一个配置类,但是不能加@EnablewebMvc。
下面我们添加一个视图跳转测试一下:
@Configuration
public class webmvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/hello1").setViewName("test");
}
}
在做其它自动配置时,会导入EnableWebMvcConfiguration:
在EnableWebMvcConfiguration 的父类DelegatingWebMvcConfiguration 中:
举例:将所有的WebMvcConfigurer相关配置都来一起调用
(2)全面接管SpringMVC
在配置类中添加@EnableWebMvc
,所有的SpringMVC的自动配置就失效了
@EnableWebMvc
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {
}
原因:
@EnableWebMvc将WebMvcConfigurationSupport组件导入进来;
导入的WebMvcConfigurationSupport只是SpringMVC最基本的功能;
注意:
在SpringBoot中会有非常多的xxxConfigurer
帮助我们进行扩展配置
配置页面跳转:
@Configuration
public class MyMvcConfig extends 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;
}
}
(1)编写国际化配置文件i18n
i18n的由来:internationalization
当编写国际化配置文件时,idea会自动识别国际化配置文件:
建立一个login.properties文件,还有一个login_zh_CN.properties;发现IDEA自动识别了我们要做国际化操作,文件夹变了。
(2)ResourceBundleMessageSource
SpringBoot在MessageSourceAutoConfiguration中自动配置好了管理国际化资源文件的组件
寻找国际化配置文件,使用spring.messages.basename指定的基础名,或者使用默认的类路径下的messages作为基础名。(基础名为去掉语言国家代码的名称):
spring.messages.basename=i18n.login //login即为基础名
(3)获取国际化配置
注意:
对于input这种没有内容体的,我们需要使用[ [] ]
来代替th:text
LocaleResolver(获取区域信息对象):
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();
}
}
注意:
这里解析器的方法名要和mvc自动配置类中的方法名相同,必须为localeResolver()
,这样相当于与原来解析器的id名相同,可以替换掉原来的解析器。
(1)LoginController
登录时可以向前端传递错误信息:
<p style="color: red" th:text="${msg}"
th:if="${not #strings.isEmpty(msg)}"></p>
(2) HandlerIntercepter
(3)注册拦截器
注:
springBoot 2.xx后,配置拦截器时,静态资源也会被拦截,所以此处需要排除静态资源。
前端添加日期数据时,可以改变日期格式化的方式:
spring.mvc.date-format=yyyy-MM-dd
(1)错误页面的默认效果
(2)ErrorMvcAutoConfiguration——错误处理自动配置
默认给容器中添加了如下组件:
错误处理流程:
1)系统出现4xx或者5xx之类的错误时,ErrorPageCustomizer负责定制错误的响应规则,会根据error.path
制定的路径去请求错误页面,默认是进行/error
请求。
2)BasicErrorController负责处理/error请求:
BasicErrorController中有两种请求的处理方式:
一个产生html数据,一个产生json数据。
注意:
BasicErrorController如何选择请求的处理方式是根据请求头中的Accept
进行判断的:
① 浏览器的请求头为text/html
② 客户端的请求头为:*/*
3)查找错误视图解析器
BasicErrorController中对于浏览器请求的处理中,resolveErrorView负责解析所有的错误视图解析器:
而DefaultErrorViewResolver正是默认的错误视图解析器,也会被resolveErrorView解析。而DefaultErrorViewResolver决定了跳转到哪个错误页面。默认SpringBoot可以去找 error文件夹下的4xx或者5xx页面。
(1)有模板引擎的情况下
error/状态码:将错误页面命名为错误状态码.html
放在模板引擎文件夹里面的error
文件夹下,发生此状态码的错误就会来到对应的页面;
注:
我们可以使用4xx和5xx作为错误页面的文件名来匹配这种类型的所有错误,精确优先(优先寻找精确的状态码.html);
DefaultErrorAttributes负责为视图封装model属性
封装的属性如下:
(2)没有模板引擎(模板引擎找不到这个错误页面),就会去静态资源文件夹下找;
(3)以上都没有错误页面,就是默认来到SpringBoot默认的错误提示页面;
利用ExceptionHander进行j=异常捕获,可以返回自定义的json数据。但是此时客户端和浏览器收到的都是json数据,那么如何让浏览器收到html收据,而客户端收到json数据呢?
DefaultErrorAttributes中关于状态码的获取是通过一个Attribute来获取的:
@ControllerAdvice
public class MyExceptionHandler {
@ExceptionHandler(UserNotExistException.class)
public String handlerException(Exception e, WebRequest request){
//0代表请求域,1代表session域
request.setAttribute("javax.servlet.error.status_code",503,0);
Map<String,Object> map = new HashMap<>();
map.put("code:","User not Exists");
map.put("message:",e.getMessage());
request.setAttribute("ext",map,0);
return "forward:/error";
}
通过重定向到/error,让系统来处理html数据或者json数据,实现自动分发数据。
出现错误以后,会来到/error
请求,会被BasicErrorController处理,响应出去可以获取的数据是由getErrorAttributes
(AbstractErrorController规定的方法)得到的。
SpringBoot中配置了默认的ErrorAttributes:即默认使用DefaultErrorAttributes.getErrorAttributes()进行数据处理
DefaultErrorAttributes中默认配置了时间戳等属性:
我们可以通过自定义一个DefaultErrorAttributes来设置我们需要的属性:
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
Map<String, Object> map = super.getErrorAttributes(webRequest, options);
map.put("company","三味书屋");
Map<String,Object> ext = (Map<String,Object>)webRequest.getAttribute("ext", 0);
map.put("ext",ext);
return map;
}
}
注:
我们可以通过webRequest
来获取handlerException中定义的错误信息。
在SpringBoot之前,如果我们要发布项目,需要在外部配置好tomcat环境。而在springBoot中,我们已经嵌入了tomcat。‘
查看pom文件的依赖图:Springboot默认使用tomcat作为servlet容器。
(1)利用ServerProperties配置来修改和server有关的配置
可以进行的配置:
(2)WebServerFactoryCustomizer(Servlet容器的定制器)
使用定制器来修改Servlet容器的配置,定制器都在org.springframework.boot.web.server包下:
@Configuration
public class MyServerConfig {
@Bean
public WebServerFactoryCustomizer<ConfigurableTomcatWebServerFactory> myServerCustomizer(){
return new WebServerFactoryCustomizer<ConfigurableTomcatWebServerFactory>() {
@Override
public void customize(ConfigurableTomcatWebServerFactory factory) {
factory.setPort(8086);
}
};
}
}
SpringBoot默认是以jar包的方式启动嵌入式的Servlet容器,没有web.xml文件,那么注册三大组件需要用以下方式:
(1)注册组件ServletRegistrationBean
(2)注册组件FilterRegistrationBean
(3)ServletListenerRegistrationBean
拿启动和销毁的监听器ServletContextListener举例:
(4)DispatcherServletAutoConfiguration中的配置
DispatcherServletAutoConfiguration中通过DispatcherServletRegistrationBean配置拦截路径:
注:
我们可以在配置文件中spring.mvc.servlet.path=/
来配置dispatcherServlet的默认拦截路径。/
默认拦截除jsp外的所有文件,/*
拦截所有请求。
SpringBoot2.xx支持的嵌入Servlet容器有以下四个:
SpringBoot默认是支持tomcat的,如果要切换servlet容器,那么需要先将tomcat排除掉:
然后再pom.xml中加入所需容器的依赖:
以jetty启动了:
在 springboot2.x 版本中,通过EmbeddedWebServerFactoryCustomizerAutoConfiguration
自动创建对应的WebServerFactoryCustomizer
来定制servlet容器。
org.springframework.boot.autoconfigure
.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration
SpringBoot根据导入的依赖情况,给容器中添加相应的XXXXWebServerFactoryCustomizerConfiguration
参考博客:https://blog.csdn.net/weixin_44414492/article/details/111160732
(1)SpringBoot应用启动运行run方法
(2)运行run方法会创建并初始化IOC容器对象
创建对应类型的web容器,如果是web类型则创建web类型的容器:
初始化IOC容器:
getWebServerFactory()通过名称匹配最终能够获取到一个与当前应用所导入的Servlet类型(我们导入了Tomcat依赖)相匹配的web服务工厂,通过工厂就可以获取到相应的 WebServerFactoryCustomizer
(Web服务工厂定制器)
(3) createWebServer()执行后,
tomcatServletWebServerFactory
。WebServerFactoryCustomizer
)来定制Servlet容器的相关配置;
通过后置处理器获取到的TomcatWebServerFactoryCustomizer调用customize()
定制方法,获取到Servlet容器相关配置类ServerProperties,进行自动配置。
(1)嵌入式Servlet容器:应用可以打成可执行的jar
(2)外置的Servlet容器:
(3)使用外部Servlet容器的步骤:
服务器启动时会加载ServletInitializer,而ServletInitializer通过重写configure方法,来告诉SpringBoot主程序DemoApplication在哪。
启动原理:
jar包:执行SpringBoot主类的main方法,启动ioc容器,创建嵌入式的Servlet容器;
war包:先启动服务器,服务器再启动SpringBoot应用,最后启动ioc容器;