前言:
小伙伴们,大家好,我是狂奔の蜗牛rz,当然你们可以叫我蜗牛君,我是一个学习Java半年多时间的小菜鸟,同时还有一个伟大的梦想,那就是有朝一日,成为一个优秀的Java架构师。
这个SpringBoot基础学习系列用来记录我学习SpringBoot框架基础知识的全过程 (这个系列是参照B站狂神的SpringBoot最新教程来写的,由于是之前整理的,但当时没有发布出来,所以有些地方可能有错误,希望大家能够及时指正!)
之后我将会以一天一更的速度更新这个系列,还没有学习SpringBoot的小伙伴可以参照我的博客学习一下;当然学习过的小伙伴,也可以顺便跟我一起复习一下基础。
最后,希望能够和大家一同进步吧!加油吧!少年们!
由于SpringBoot Web开发涉及的内容比较多,所以蜗牛君打算把这部分将会分成上中下三篇博客,上篇主要分析SpringBoot开发Web的优缺点以及静态资源的配置和使用;中篇主要介绍模板引擎和MVC配置原理,下篇是项目实战,基于SpringBoot构建一个简单的员工管理系统!
废话不多说,让我们开始今天的学习内容吧,由于今天我们来到了SpringBoot基础学习的第五站:SpringBoot Web开发(上篇)!
SpringBoot的核心就是:自动装配
从以下四个维度去进行思考:
SpringBoot到底帮我们配置了什么?我们能不能进行修改?能修改哪些东西?能不能扩展?
package com.kuang.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
//实现Controller接口并且使返回值为字符串形式
@RestController
public class HelloController {
//设置请求映射路径:http://localhost:8080/hello
@RequestMapping("/hello")
public String hello() {
return "Hello,SpringBoot!";
}
}
结果:访问失败,出现了"空白标签错误页面"提示
因此我们需要定制首页,这个后面会提到,目前先不用管它
结果:访问/hello请求成功!
@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 })
//WebMVC自动配置类
public class WebMvcAutoConfiguration {
......
}
@Configuration(proxyBeanMethods = false)
@Import(EnableWebMvcConfiguration.class)
@EnableConfigurationProperties({ WebMvcProperties.class,
org.springframework.boot.autoconfigure.web.ResourceProperties.class, WebProperties.class })
@Order(0)
//WebMvc的自动配置适配器
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
......
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(WebProperties.class)
//WebMvc的能够自动配置
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {
......
}
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
super.addResourceHandlers(registry);
//如果静态资源的东西已经被自定义了,直接返回
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
ServletContext servletContext = getServletContext();
addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (servletContext != null) {
registration.addResourceLocations(new ServletContextResource(servletContext, SERVLET_LOCATION));
}
});
}
@Configuration(proxyBeanMethods = false)
@Import(EnableWebMvcConfiguration.class)
@EnableConfigurationProperties({ WebMvcProperties.class,
org.springframework.boot.autoconfigure.web.ResourceProperties.class, WebProperties.class })
@Order(0)
//WebMvc的自动配置适配器
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
......
}
//封装绑定了配置文件spring.mvc的所有属性
@ConfigurationProperties(prefix = "spring.mvc")
public class WebMvcProperties {
......
//静态资源的路径
private String staticPathPattern = "/**";
}
spring.mvc.static-path-pattern=
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
super.addResourceHandlers(registry);
//如果静态资源的东西已经被自定义了,直接返回,即默认的资源失效
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
ServletContext servletContext = getServletContext();
//添加静态资源到/webjars/**中,位置在classpath:/META-INF/resources/webjars/
addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (servletContext != null) {
registration.addResourceLocations(new ServletContextResource(servletContext, SERVLET_LOCATION));
}
});
}
<dependency>
<groupId>org.webjarsgroupId>
<artifactId>jqueryartifactId>
<version>3.6.0version>
dependency>
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
super.addResourceHandlers(registry);
//如果静态资源的东西已经被自定义了,直接返回,即默认的资源失效
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
ServletContext servletContext = getServletContext();
//添加静态资源到/webjars/**中,位置在classpath:/META-INF/resources/webjars/
addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
//getStaticPathPattern:获取静态资源的路径
addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (servletContext != null) {
registration.addResourceLocations(new ServletContextResource(servletContext, SERVLET_LOCATION));
}
});
}
在SpringBoot中,我们可以使用以下方式处理静态资源:
除了 /**"外,还有classpath:/METAINF/resources/;以及classpath:/resources/、classpath:/static/ 和 classpath:/public/
Hello,JavaScript
Hello,Spring
Hello,JavaScript
Hello,Spring
结果:存放在 classpath:/resources/ 下比classpath:/public/ 下优先级高
Hello,JavaScript
Hello,Spring
Hello,SpringMVC
结论:存放在 classpath:/resources/ 下也比classpath:/static/ 下优先级高
Hello,JavaScript
Hello,SpringMVC
结论:存放 classpath:/static/ 路径下优先级比存放 classpath:/public/ 下高
# 在配置文件下自定义资源访问路径
spring.mvc.static-path-pattern=/hello/**
结论:如果在配置文件下自定义资源访问路径,那么存放在resources、static以及public下的文件都会失效
优先级比较结果:classpath:/resources/ > classpath:/static/ (默认使用) > classpath:/public/
资源存放总结:
@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 })
//WebMVC自动配置类
public class WebMvcAutoConfiguration {
......
//欢迎页控制映射
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,
FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
......
}
......
private Resource getIndexHtml(String location) {
return getIndexHtml(this.resourceLoader.getResource(location));
}
//获取页面资源
private Resource getIndexHtml(Resource location) {
......
}
}
@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 })
//WebMVC自动配置类
public class WebMvcAutoConfiguration {
......
//欢迎页控制映射
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,
FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
//获取欢迎页面控制器映射(WelcomePageHandlerMapping)对象
WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(
new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(),
//获得静态路径参数
this.mvcProperties.getStaticPathPattern());
//设置拦截器
welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));
welcomePageHandlerMapping.setCorsConfigurations(getCorsConfigurations());
//返回到欢迎页面映射
return welcomePageHandlerMapping;
}
......
//获取页面资源
private Resource getIndexHtml(String location) {
//通过定位来返回获取到的html页面
return getIndexHtml(this.resourceLoader.getResource(location));
}
//获取页面资源
private Resource getIndexHtml(Resource location) {
try {
//创建index.html页面资源
Resource resource = location.createRelative("index.html");
//判断资源是否存在或者获取到的资源UR链接是否为空
if (resource.exists() && (resource.getURL() != null)) {
//如果满足条件则返回资源
return resource;
}
}
catch (Exception ex) {
}
//如果不满足条件就返回空
return null;
}
}
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<h1>首页h1>
body>
html>
结论:直接存放在根目录不能直接访问!
与2-2中的主页代码相同
package com.kuang.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
//在templates目录下的所有页面,只能通过controller来跳转
//这个需要模板应请支持:thymeleaf
//使用@Controller注解来实现Controller接口
@Controller
public class IndexController {
//真实访问路径为:http://loclahost:8080/index
//使用@RequestMapping注解,设置请求映射路径
@RequestMapping("/goIndex")
public String index() {
//返回的视图逻辑名
return "index";
}
}
结果:访问失败,可能需要通过控制器来访问主页!
结果:仍然访问失败,应该是为导入模板引擎 (thymeleaf) 的资源jar包所导致的 !
与2-2主页代码相同
与3-3控制类代码相同
直接访问主页
结果:访问成功!同时也印证了之前说的,可以把大家都会访问的资源放在static文件下
通过goIndex请求访问
结果:访问主页失败!应该是视图逻辑名拼接出了问题,因为我们并不清楚SpringBoot中视图解析器如何处理返回的视图逻辑名
# 关闭默认图标
spring.mvc.favicon.enabled=false
新版SpringBoot已经不支持favicon了,不过可以在html的link标签中实现
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<link rel="icon" href="/favicon.ico">
head>
<body>
<h1>首页h1>
body>
html>
结果:定制图标成功!
好了,今天的有关 SpringBoot基础学习之SpringBoot Web开发(上篇) 的学习就到此结束啦,欢迎小伙伴们积极学习和讨论,喜欢的可以给蜗牛君点个关注,顺便来个一键三连,我们下期见,拜拜啦!
参考视频链接:https://www.bilibili.com/video/BV1PE411i7CV(【狂神说Java】SpringBoot最新教程IDEA版通俗易懂)