Spring Boot
(后面有时间再更新吧)
spring boot 入门篇
一、spring boot >hello spring
1、导入spring boot 需要得依赖
<!--
导入spring boot 为父项目
-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.10</version>
</parent>
<!-- 导入spring boot 场景启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
构建应用程序主要入口:
@SpringBootApplication
/*
*
* @SpringBootApplication: 标注为该程序是spring boot程序
* */
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class,args);
}
}
创建控制器(web 逻辑)
@RestController
/*
@Controller
@ResponseBody
* @RestController: 是@Controller和@ResponseBody结合体
声明这个类是一个控制器类并且这个类只会返回字符信息给浏览器
* */
public class messageHandle {
@RequestMapping("/hello")
public String handle01() {
return "hello spring boot 2!";
}
}
spring boot 配置简化
在资源路径下创建 application.properties(固定名称)
即可(该配置文件可以配置sprng mvc以及tomcat等等)
server.port=8000 //修改tomcat端口
spring boot 部署 导出为可执行jar包
<!-- 放在dependencies中导入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.5.1</version>
</dependency>-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
也可在放在dependencies中导入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.5.1</version>
</dependency>
后在maven管理中选中生命周期下得clean 与package 运行打包即可
找到jar包后 cmd窗口运行 java -jar 名字.jar
注意点 springboot 打包后jar包很多 所以体积较大
二、自动配置原理
1、依赖管理:在依赖管理中spring boot 得父项目中构建了大量常用的依赖版本 所以在导入依赖时无需关心版本
如果想要自定义自己的需要的依赖版本 需要在maven 文件中创建
<properties>
<mysql.version>需要的版本好</mysql.version>
</properties>
2、场景启动
spring-boot-start-* 代表某个场景的启动器
比如spring-boot-start-web 将会把web所需要的启动场景全部引入
spring-boot 所有能支持的场景 在官网中
所有的场景启动器 中最底层的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.5.10</version>
<scope>compile</scope>
</dependency>
因为springboot 自动配置帮我们指定了一个包扫描 所以我们无需指定包的扫描路径
自己指定可以采用
将@SpringBootApplication(basePackages="自定义包名")
同时也可以将@SpringBootApplication(basePackages="自定义包名")改为
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("包名")
三、底层注解 详解
1、@Configuration
package org.Dwx.boot.config;
import org.Dwx.boot.bean.Pet;
import org.Dwx.boot.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
/*
告诉spring boot 这是一个配置组件
*/
public class MyConfig {
@Bean
/*
告诉spring 这个是一个<bean> bean的id就是方法名 返回类型就是<bean>的
*/
public User userVip (){
return new User("zhansan",18);
}
@Bean
/*
* 也可以自定义组件名
*
* @Bean("name")
* */
public Pet tomcat(){
return new Pet("Tomcat");
}
}
如果 @Configuration(proxyBeanMethods=true时)
spring 启动代理对象我们每次从spring容器中获取的对象都是单实例 所以不管获取多少次 对象都是同一个
如果 @Configuration(proxyBeanMethods=false时)
不启动代理将返回单独的对象
2、@import({User.class…})
可以给容器中导入多个组件
容器自动创建出这两个类型的组件
3、 @Conditional 条件装配 满足Conditional 指定条件则进行组件注入
run.contaunsBean(“”) 判断容器中是否存在容器中
4、@ImportResource(“classpath:*.xml”)
将beans文件中的bean添加到容器中
5、配置绑定
方法一:
@Compoent // 注入到ioc容器
@ConfigurationProperties(prefix=“前缀”)
@Autowired
Car car;
@RequestMapping("/car")
public Car car(){
return car;
}
方法二
@EnableConfigurationProperties(Car.class)
//开启的组件配置绑定功能
//把car组件自动注入ioc
@ConfigurationProperties(prefix="前缀")
@RequestMapping("/car")
public Car car(){
return car;
}
四、自动配置原理剖析
关键注解:
@SpringBootConfiguration //告诉spring 这个是一个配置类
@EnableAutoConfiguration
@ComponentScan //指定包扫描
@EnableAutoConfiguration
-
@AutoConfigurationPackage 将指定包下的所有组件全部导入ioc(main程序所在包)
- @Import({Registrar.class}) //利用 registrar 导入一系列组件
-
AutoConfigurationImportSelector.class
-
this.getAutoConfigurationEntry(annotationMetadata); 利用该方法到一系列组件
- this.getCandidateConfigurations(annotationMetadata, attributes);
- 利用他来获取所有需要导入到容器的配置组件
- SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
- 使用spring的工厂加载器加载组件
- 利用工厂加载 Map<String, List> loadSpringFactories(@Nullable ClassLoader classLoader);得到所有的组件
- 从META-INF/spring.factories位置来加载一个文件。
默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件
spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面也有META-INF/spring.factories - 文件里面写死了spring-boot一启动就要给容器中加载的所有配置类
spring-boot-autoconfigure-2.3.4.RELEASE.jar/META-INF/spring.factories - Auto Configure 的127个配置项 最后也会按需加载
- 最后根据按需装配 导入场景需要的组件
-
五、修改默认配置
SpringBoot默认会在底层配好所有的组件。但是如果用户自己配置了以用户的优先
使用@Bean 导入用户所配置的组件即可
总结:
-
SpringBoot先加载所有的自动配置类 xxxxxAutoConfiguration
-
每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。xxxxProperties里面拿。xxxProperties和配置文件进行了绑定
-
生效的配置类就会给容器中装配很多组件
-
只要容器中有这些组件,相当于这些功能就有了
-
定制化配置
-
- 用户直接自己@Bean替换底层的组件
- 用户去看这个组件是获取的配置文件什么值就去修改。
xxxxxAutoConfiguration —> 组件 —> xxxxProperties里面拿值 ----> application.properties
六、最佳实践
打开debug模式将会开启自动配置报告 negative 不生效的 / positive 生效的
参照文档修改配置项
案例修改banner 图 spring.banner.image.loacation=资源路径下的图片
自定义加入组件或替换组件
使用@Bean @Compent
自定义器 XXXXCustomizer;
开发小技巧
lombok 插件:
1、导入lombok依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
2、安装插件
idea 搜索lombok
3、使用
在实体上@Data 生产get set@toString @AllArgsConstructor @NolArgsConstructor
源代码不会有相应的代码生成 在字节码文件中是存在的
@Slf4j 日志记录
dev-tools 插件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
ctrl+F9 使项目重编译(快捷重启)
使用热更新 安装JRebel
spring initaillzr
快速创建spring boot 引用
springboot2 核心功能
1、配置文件
1、yaml配置
YAML 是 “YAML Ain’t Markup Language”(YAML 不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:“Yet Another Markup Language”(仍是一种标记语言)。
语法:
-
key: value;kv之间有空格
-
大小写敏感
-
使用缩进表示层级关系
-
缩进不允许使用tab,只允许空格
-
缩进的空格数不重要,只要相同层级的元素左对齐即可
-
'#'表示注释
-
字符串无需加引号,如果要加,''与""表示字符串内容 会被 转义/不转义
-
字面量:单个的、不可再分的值。date、boolean、string、number、null
-
k: v
●对象:键值对的集合。map、hash、set、object
YAML
复制代码
1
行内写法: k: {k1:v1,k2:v2,k3:v3}
2
#或
3
k:
4
k1: v1
5
k2: v2
6
k3: v3
●数组:一组按次序排列的值。array、list、queue
YAML
复制代码
行内写法: k: [v1,v2,v3]
#或者
k:
- v1
- v2
- v3
样例:
# yaml表示以上对象
person:
userName: zhangsan
boss: false
birth: 2019/12/12 20:12:33
age: 18
pet:
name: tomcat
weight: 23.4
interests: [篮球,游泳]
animal:
- jerry
- mario
score:
english:
first: 30
second: 40
third: 50
math: [131,140,148]
chinese: {first: 128,second: 136}
salarys: [3999,4999.98,5999.99]
allPets:
sick:
- {name: tom}
- {name: jerry,weight: 47}
health: [{name: mario,weight: 47}]
2、web文件开发
1、静态资源目录 类路径下 /static or /public or /resource /META-INF/resource
只要资源放在静态资源目录下就可访问到
访问:当前项目根路径/+资源名
原理:静态映射/**
请求进来,先找动态资源看能不能处理。不能处理的所有请求又交给静态资源处理器。静态资源处理器也无法处理 就返回404页面
静态资源访问前缀:默认无
配置修改
spring
mvc:
static-path-pattern:/res/**
//静态资源放行规则
//配置静态资源路径
spring:
mvc:
static-path-pattern: /res/**
resources:
static-locations: [classpath:/haha/]
webJARS 把常用的静态文件做成jar包 导入以后会自动映射
2、欢迎页设置
在静态资源路径下 index.html
spring
mvc:
static-path-pattern:/res/**
会导致静态资源失效(html)
mvc:
static-path-pattern: /res/**
动态下路由为index 所返回的欢迎页
3、自定义Favicon (网站icon )
放在静态资源中 命名为favicon.ico
4、静态配置原理
- springboot启动默认加载 自动配置类
- springMVC功能自动配置 WebMvcAutoCon…
3、请求参数处理
采用Rest风格
/user get 获取用户 delete 删除用户 put修改用户 post 保存用户
核心Filter;HiddenHttpMethodFilter(拦截器)
-
用法 表单method=post,隐藏域 _method=put
-
手动开启
spring:
mvc:
hiddenmethod:
filter:
enabled: true #开启页面表单的Rest功能Rest原理:
-
表单提交一个 name=”_method“ value=”PUT“
-
请求发送到服务器后被HiddenHttpMethodFilter拦截
关键点
-
获取到_method的值
-
兼容 PUT,DELETE,PATCH
-
原生request(post) ,包装模式requesWrapper重写getMethod方法,返回的是传入的值.
-
过滤器链放行的时候用wrapper。以后的方法调用getMethod是调用requesWrapper
-
-
2、请求映射原理
SpringMVC功能分析都从 org.springframework.web.servlet.DispatcherServlet-》doDispatch()
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 找到当前请求使用哪个Handler(Controller的方法)处理
mappedHandler = getHandler(processedRequest);
//HandlerMapping:处理器映射。/xxx->>xxxx
RequestMappingHandlerMapping:保存了所有@RequestMapping 和handler的映射规则。
所有的请求映射都在HandlerMapping中。
-
SpringBoot自动配置欢迎页的 WelcomePageHandlerMapping 。访问 /能访问到index.html;
-
SpringBoot自动配置了默认 的 RequestMappingHandlerMapping
-
请求进来,挨个尝试所有的HandlerMapping看是否有请求信息。
-
- 如果有就找到这个请求对应的handler
- 如果没有就是下一个 HandlerMapping
-
我们需要一些自定义的映射处理,我们也可以自己给容器中放HandlerMapping。自定义 HandlerMapping
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
普通参数 与基本注解
1、注解
@PathVariable、 获取路径变量
@RequestMapping("/User/{id}/{username}")
public Map<String, Object> handle01(@PathVariable Integer id,
@PathVariable String username,
@PathVariable Map<String, String> hash ){
Map<String, Object> map = new HashMap<>();
map.put("id",id);
map.put("username",username);
map.put("hash",hash);
return map;
}
@RequestHeader、获取请求头
@RequestMapping("getHeard")
public Map<String, Object> handle02(@RequestHeader("User-Agent") String userAgent,
@RequestHeader Map<String,String> headers){
Map<String, Object> map = new HashMap<>();
map.put("User-Agent",userAgent);
map.put("headers",headers);
return map;
}
@RequestParam、获取请求参数
@RequestMapping("getUser")
public String handle03(@RequestParam String username){
return username;
}
/*
自动封装数组以及对象
*/
@CookieValue、 获取cookie的值
@RequestMapping("getCookie")
public Map<String, Object> handle03(@CookieValue("_ga") String value,
@CookieValue("_ga") Cookie c
){
Map<String, Object> Map = new HashMap<>();
Map.put("_ga",value);
Map.put("cookie",c);
return Map;
}
@RequestBody 获取请求体(只有post才有请求体)
@MatrixVariable、 矩阵变量 (key=value;key=value;…)
@RequestMapping("/cars/{path}")
public Map Test01(@MatrixVariable("low") String low,
@MatrixVariable("price") String price,
@MatrixVariable("list") List<String> list,
@PathVariable("path") String path
){
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("low",low);
hashMap.put("price",price);
hashMap.put("list",list);
hashMap.put("path",path);
return hashMap;
}
@GetMapping("boos/{boosId}/{emId}")
public Map Test02(@MatrixVariable(value = "age",pathVar = "boosId") Integer boos,
@MatrixVariable(value = "age",pathVar = "emId") Integer em){
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("boos",boos);
hashMap.put("em",em);
return hashMap;
}
配置类
@Bean
public WebMvcConfigurer webMvcConfigurer(){
return new WebMvcConfigurer() {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
UrlPathHelper urlPathHelper = new UrlPathHelper();
urlPathHelper.setRemoveSemicolonContent(false);
configurer.setUrlPathHelper(urlPathHelper);
}
};
}
@ModelAttribute、
@RequestAttritbut 获取Attritbute域中的值
@GetMapping("/gotoPage")
public String goToPage(HttpServletRequest request){
request.setAttribute("msg","我们都是好孩子---王菲");
request.setAttribute("code",200);
return "forward:success";
}
@ResponseBody
@GetMapping("/success")
public Map<String,Object> showData(@RequestAttribute("msg") String msg, @RequestAttribute("code") Integer code,HttpServletRequest httpServlet ){
Map<String, Object> string = new HashMap<>();
string.put("msg",msg);
string.put("code",code);
string.put("__attribute",httpServlet.getAttribute("msg"));
return string;
}
2、POJO封装过程
3、参数处理
-
handlerMapping中找到处理请求的Handler
-
为当前Handler找一个适配器HandlerAdapt
-
适配器执行目标方法并确定方法参数的每一个值
1、HandlerAdapter
0-支持方法上标注@RequestMapping
1-支持函数式编程的
xxxxxx
2、执行目标方法
// Actually invoke the handler. //DispatcherServlet -- doDispatch mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
mav = invokeHandlerMethod(request, response, handlerMethod); //执行目标方法 //ServletInvocableHandlerMethod Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); //获取方法的参数值 Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
3、参数解析器
确定将要执行的目标方法的每一个参数值是什么
SpringMVC 目标方法能写多少个参数
5、视图解析
1、thymeleaf简介
Thymeleaf is a modern server-side Java template engine for both web and standalone environments, capable of processing HTML, XML, JavaScript, CSS and even plain text.
现代化、服务端Java模板引擎
2、基本语法
1、表达式
表达式名字 | 语法 | 用途 |
---|---|---|
变量取值 | ${…} | 获取请求域、session域、对象等值 |
选择变量 | *{…} | 获取上下文对象值 |
消息 | #{…} | 获取国际化等值 |
链接 | @{…} | 生成链接 |
片段表达式 | ~{…} | jsp:include 作用,引入公共页面片段 |
2、字面量
文本值: ‘one text’ , ‘Another one!’ **,…**数字: 0 , 34 , 3.0 , 12.3 **,…**布尔值: true , false
空值: null
变量: one,two,… 变量不能有空格
3、文本操作
字符串拼接: +
变量替换: |The name is ${name}|
4、数学运算
运算符: + , - , * , / , %
5、布尔运算
运算符: and , or
一元运算: ! , not
6、比较运算
比较: > , < , >= , <= ( gt , lt , ge , le **)**等式: == , != ( eq , ne )
7、条件运算
If-then: (if) ? (then)
If-then-else: (if) ? (then) : (else)
Default: (value) ?: (defaultvalue)
8、特殊操作
无操作: _
3、设置属性值-th:attr
设置单个值
<form action="subscribe.html" th:attr="action=@{/subscribe}">
<fieldset>
<input type="text" name="email" />
<input type="submit" value="Subscribe!" th:attr="value=#{subscribe.submit}"/>
</fieldset>
</form>
设置多个值
<img src="../../images/gtvglogo.png" th:attr="src=@{/images/gtvglogo.png},title=#{logo},alt=#{logo}" />
以上两个的代替写法 th:xxxx
<input type="submit" value="Subscribe!" th:value="#{subscribe.submit}"/>
<form action="subscribe.html" th:action="@{/subscribe}">
所有h5兼容的标签写法
https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#setting-value-to-specific-attributes
4、迭代
<tr th:each="prod : ${prods}">
<td th:text="${prod.name}">Onions</td>
<td th:text="${prod.price}">2.41</td>
<td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
</tr>
<tr th:each="prod,iterStat : ${prods}" th:class="${iterStat.odd}? 'odd'">
<td th:text="${prod.name}">Onions</td>
<td th:text="${prod.price}">2.41</td>
<td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
</tr>
5、条件运算
<a href="comments.html"
th:href="@{/product/comments(prodId=${prod.id})}"
th:if="${not #lists.isEmpty(prod.comments)}">view</a>
<div th:switch="${user.role}">
<p th:case="'admin'">User is an administrator</p>
<p th:case="#{roles.manager}">User is a manager</p>
<p th:case="*">User is some other thing</p>
</div>
6、属性优先级
Order
Feature
AttrIbutes
Fragmentinclusion
th:insert
th:replace
Fragmentiteration
th:each
Conditionalevaluation
th:if
th:unless
th:switch
butes
th:case
th:object
Localvariabledefinition
th:with
Generalattributemodification
th:attr
th:attrorepend
th:attrappend
Specificattributemodification
th:value
th:href
th:src
Text(tagbodymodification)
th:text
th:utext
Fragmentspecification
th:fragment
Fragmentremoval
th:remove
3、thymeleaf使用
1、引入Starter
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
2、自动配置好了thymeleaf
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(ThymeleafProperties.class)
@ConditionalOnClass({ TemplateMode.class, SpringTemplateEngine.class })
@AutoConfigureAfter({ WebMvcAutoConfiguration.class, WebFluxAutoConfiguration.class })
public class ThymeleafAutoConfiguration { }
自动配好的策略
●1、所有thymeleaf的配置值都在 ThymeleafProperties
●2、配置好了 SpringTemplateEngine
●3、配好了 ThymeleafViewResolver
●4、我们只需要直接开发页面
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html"; //xxx.html
3、页面开发
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1 th:text="${msg}">哈哈</h1>
<h2>
<a href="www.atguigu.com" th:href="${link}">去百度</a> <br/>
<a href="www.atguigu.com" th:href="@{link}">去百度2</a>
</h2>
</body>
</html>