发布时间:2022-12-24 14:30
1、尚硅谷/SpringBoot2核心技术与响应式编程
2、springboot官网
3、版本升级变化
<mirrors>
<mirror>
<id>nexus-aliyunid>
<mirrorOf>centralmirrorOf>
<name>Nexus aliyunname>
<url>http://maven.aliyun.com/nexus/content/groups/publicurl>
mirror>
mirrors>
<profiles>
<profile>
<id>jdk-1.8id>
<activation>
<activeByDefault>trueactiveByDefault>
<jdk>1.8jdk>
activation>
<properties>
<maven.compiler.source>1.8maven.compiler.source>
<maven.compiler.target>1.8maven.compiler.target>
<maven.compiler.compilerVersion>1.8maven.compiler.compilerVersion>
properties>
profile>
profiles>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.6.3version>
parent>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
dependencies>
https://docs.spring.io/spring-boot/docs/current/reference/html/
服务器配置
这里通过简单使用配置文件,修改tomcat的端口
创建可执行 Jar
在pom.xml的dependencies部分下方添加打包插件
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-resources-pluginartifactId>
<version>3.1.0version>
plugin>
plugins>
build>
使用maven进行项目的打包
生成jar包
使用命令行代替服务器启动项目
一样可以访问:说明这打包时将tomcat等环境一起打包成jar包了,这样这服务器就可以不用安装tomcat等工具,节约成本
父项目做依赖管理
1、自定义版本,替换spring boot引入的默认版本
查看spring-boot-dependencies里面规定当前依赖的版本 用的 key。
在当前项目里面重写配置,这样就导进来自己安装的数据库版本
2、开发导入starter场景启动器
官方文档:https://docs.spring.io/spring-boot/docs/current/reference/html/
1、见到很多 spring-boot-starter-* : *就某种场景
2、只要引入starter,这个场景的所有常规需要的依赖我们都自动引入
3、SpringBoot所有支持的场景
https://docs.spring.io/spring-boot/docs/current/reference/html/using.html#using.build-systems.starters
4、见到的 *-spring-boot-starter: 第三方为我们提供的简化开发的场景启动器。
5、所有场景启动器最底层的依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starterartifactId>
<version>2.3.4.RELEASEversion>
<scope>compilescope>
dependency>
1、● 自动配好Tomcat
○ 引入Tomcat依赖。
○ 配置Tomcat(默认自动配置)
2、● 自动配好SpringMVC
○ 引入SpringMVC全套组件
○ 自动配好SpringMVC常用组件(功能)
3、● 自动配好Web常见功能,如:字符编码问题
○ SpringBoot帮我们配置好了所有web开发的常见场景
4、● 默认的包结构
○ 主程序所在包及其下面的所有子包里面的组件都会被默认扫描进来
○ 无需以前的包扫描配置
○ 想要改变扫描路径,@SpringBootApplication(scanBasePackages=“com.atguigu”)
或者@ComponentScan 指定扫描路径
//@SpringBootApplication //等同下面的三个注解
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(“com.atguigu.boot”)//指定包扫描的基包
5、● 各种配置拥有默认值
○ 默认配置最终都是映射到某个类上,如:MultipartProperties
○ 配置文件的值最终会绑定每个类上,这个类会在容器中创建对象
6、● 按需加载所有自动配置项
○ 非常多的starter
○ 引入了哪些场景这个场景的自动配置才会开启
○ SpringBoot所有的自动配置功能都在 spring-boot-autoconfigure 包里面
一、使用@Configuration和@Bean注解方式
二、给容器导入组件@Import
1、 基本使用
MyConfig.java
/**
* @Configuration:告诉SpringBoot这是一个配置类 == 配置文件
* proxyBeanMethods:表示代理bean的方法
* Full(proxyBeanMethods = true)、【保证每个@Bean方法被调用多少次返回的组件都是单实例的】
* Lite(proxyBeanMethods = false)【每个@Bean方法被调用多少次返回的组件都是新创建的】
* 组件依赖必须使用Full模式默认。其他默认是否Lite模式
*/
@Import({User.class, DBHelper.class})
@Configuration(proxyBeanMethods = true)
public class MyConfig {
@Bean //给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例
public User user01(){
User zhangsan = new User("zhangsan", 18);
//因为proxyBeanMethods = true,所以user组件依赖了Pet组件,单实例
zhangsan.setPet(tomcatPet());
return zhangsan;
}
@Bean("tom")//使用参数自定义组件id
public Pet tomcatPet(){
return new Pet("tomcat");
}
}
MainApplication.java
/*
* 主程序类:所有程序的启动入口
* @SpringBootApplication作用:这是一个springboot运用
*/
//@SpringBootApplication //等同下面的三个注解
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.atguigu.boot")//指定包扫描的基包
public class MainApplication {
/*===========main方法===========*/
public static void main(String[] args) {
//1、返回我们IOC容器,里面包含各种组件
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
//2、查看容器里面的所有组件
// String[] names = run.getBeanDefinitionNames();
// System.out.println("================");
// for (String name : names) {
// System.out.println(name);
// }
//3、从容器中获取组件,验证是否单实例组件
Pet tom01 = run.getBean("tom", Pet.class);
Pet tom02 = run.getBean("tom", Pet.class);
System.out.println("是否单实例组件:" + (tom01 == tom02));
System.out.println("================");
//4、配置类本身也是一个组件
MyConfig bean = run.getBean(MyConfig.class);
System.out.println("配置类本身也是一个组件:"+bean);
System.out.println("================");
//5、如果@Configuration(proxyBeanMethods = true)代理对象调用方法。
//SpringBoot总会检查这个组件是否在容器中有保持组件单实例
User user = bean.user01();
User user1 = bean.user01();
System.out.println("user == user1:" + (user == user1));
System.out.println("================");
//6、组件依赖
User user01 = run.getBean("user01", User.class);
Pet tom = run.getBean("tom", Pet.class);
System.out.println("用户的宠物:"+(user01.getPet() == tom));
//使用@Import导入自定义和外部组件测试
String[] beanNamesForType = run.getBeanNamesForType(User.class);
System.out.println("======获取组件");
for (String s : beanNamesForType) {
System.out.println(s);
}
DBHelper dbHelperBean = run.getBean(DBHelper.class);
System.out.println("dbHelperBean"+dbHelperBean);
}
}
条件装配:满足Conditional指定的条件,则进行组件注入
@Import({User.class, DBHelper.class})
@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(name = "tom")//也可以注解在类上,表示容器中存在tom组件时,才加载这个类里面的组件
public class MyConfig {
//@ConditionalOnBean(name = "tom")//容器中存在tom组件时才加载user01组件,
@Bean //给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例
public User user01(){
User zhangsan = new User("zhangsan", 18);
//因为proxyBeanMethods = true,所以user组件依赖了Pet组件,单实例
//zhangsan.setPet(tomcatPet());
return zhangsan;
}
@Bean("tom22")//使用参数自定义组件id
public Pet tomcatPet(){
return new Pet("tomcat");
}
}
解决问题:一些公司还是使用xml文件配置方式,所以需要将这些文件引进来,进行解析配置
MainApplication.java
/*
* 主程序类:所有程序的启动入口
* @SpringBootApplication作用:这是一个springboot运用
*/
//@SpringBootApplication //等同下面的三个注解
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.atguigu.boot")//指定包扫描的基包
public class MainApplication {
/*===========main方法===========*/
public static void main(String[] args) {
//1、返回我们IOC容器,里面包含各种组件
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
//2、查看容器里面的所有组件
// String[] names = run.getBeanDefinitionNames();
// System.out.println("================");
// for (String name : names) {
// System.out.println(name);
// }
//3、从容器中获取组件,验证是否单实例组件
// Pet tom01 = run.getBean("tom", Pet.class);
// Pet tom02 = run.getBean("tom", Pet.class);
// System.out.println("是否单实例组件:" + (tom01 == tom02));
// System.out.println("================");
//
// //4、配置类本身也是一个组件
// MyConfig bean = run.getBean(MyConfig.class);
// System.out.println("配置类本身也是一个组件:"+bean);
// System.out.println("================");
//
// //5、如果@Configuration(proxyBeanMethods = true)代理对象调用方法。
// //SpringBoot总会检查这个组件是否在容器中有保持组件单实例
// User user = bean.user01();
// User user1 = bean.user01();
// System.out.println("user == user1:" + (user == user1));
// System.out.println("================");
//
// //6、组件依赖
// User user01 = run.getBean("user01", User.class);
// Pet tom = run.getBean("tom", Pet.class);
// System.out.println("用户的宠物:"+(user01.getPet() == tom));
//
// //使用@Import导入自定义和外部组件测试
// String[] beanNamesForType = run.getBeanNamesForType(User.class);
// System.out.println("======获取组件");
// for (String s : beanNamesForType) {
// System.out.println(s);
// }
//
// DBHelper dbHelperBean = run.getBean(DBHelper.class);
// System.out.println("dbHelperBean"+dbHelperBean);
//原生配置文件引入@ImportResource测试
boolean haha = run.containsBean("haha");
boolean hehe = run.containsBean("hehe");
System.out.println("haha:"+haha);//true
System.out.println("hehe:"+hehe);//true
}
}
使用
@Component
@ConfigurationProperties(prefix = “mycar”)
properties配置文件
接收解析properties配置文件的bean
@ConfigurationProperties(prefix = “mycar”)
public class Car {
@EnableConfigurationProperties(Car.class)
public class MyConfig {
1、● 引入场景依赖
○ https://docs.spring.io/spring-boot/docs/current/reference/html/using.html#using.build-systems.starters
2、● 查看自动配置了哪些(选做)
○ 自己分析,引入场景对应的自动配置一般都生效了
○ 配置文件中debug=true开启自动配置报告。控制台打印的Negative(不生效)、Positive(生效),如下:
3、● 是否需要修改
○ 参照文档修改配置项
■ https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html#application-properties
■ 自己分析。xxxxProperties绑定了配置文件的哪些。
实例:修改banner图
4、 ○ 自定义加入或者替换组件
■ @Bean、@Component…
○ 自定义器 XXXXXCustomizer;
○ …
作用:简化JavaBean开发
使用@Data注解,不用再写get、set方法
使用@ToString注解,不用再写tostring方法。
使用@NoArgsConstructor注解,不用再写无参构造方法。
使用@AllArgsConstructor注解,不用再写有参构造方法。
步骤一:引入依赖
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
步骤二:安装插件
file->settting->plugin
步骤三:
使用注解实现简化JavaBean开发
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<optional>trueoptional>
dependency>
使用
Ctrl+F9即可重新编译加载,并启动项目
引入场景依赖和选择springboot版本
删除多余的文件
项目展开
同以前的properties用法
一、简介
YAML 是 “YAML Ain’t Markup Language”(YAML 不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:“Yet Another Markup Language”(仍是一种标记语言)。 适合用来做以数据为中心的配置文件
二、基本语法
● key: value;kv之间有空格
● 大小写敏感
● 使用缩进表示层级关系
● 缩进不允许使用tab,只允许空格
● 缩进的空格数不重要,只要相同层级的元素左对齐即可
● '#'表示注释
● 字符串无需加引号,如果要加,单引号会将/n作为字符串输出,双引号会将/n转译成换行输出
三、数据类型
1、字面量:单个的、不可再分的值。date、boolean、string、number、null
k: v
2、对象:键值对的集合。map、hash、set、object
行内写法: k: {k1:v1,k2:v2,k3:v3}
#或
k:
k1: v1
k2: v2
k3: v3
3、数组:一组按次序排列的值。array、list、queue
行内写法: k: [v1,v2,v3]
#或者
k:
- v1
- v2
- v3
== 实例 ==
person:
# 字面量:单个的、不可再分的值。date、boolean、string、number、null
userName: 'zhangsan \n 王二毛' # 单引号会将\n作为字符串输出,双引号会将\n作为换行输出
boss: false
birth: 2019/12/12 20:12:33
age: 18
pet:
name: tomcat
weight: 23.4
# 数组:一组按次序排列的值。array、list、queue
interests: [篮球,游泳]
animal:
- jerry
- mario
# 对象:键值对的集合。map、hash、set、object ,下面展示三种写法
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} # 数组list
- {name: jerry,weight: 47}
health: [{name: mario,weight: 47}]
这样在编写yaml文件时就会有提示信息,可以快速准确开发
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-configuration-processorartifactId>
<optional>trueoptional>
dependency>
配置注释处理器只是为了开发方便,所以在打包的时候就不要将该工具添加到包中,因此需要进行一下配置
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
exclude>
<exclude>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-configuration-processorartifactId>
exclude>
excludes>
configuration>
plugin>
plugins>
build>
1、静态资源目录
只要静态资源放在类路径下
: /static or /public or /resources or /META-INF/resources
访问方式: 当前项目根路径/ + 静态资源名
例如:http://localhost:8080/earth.png
原理:静态映射/**。
请求进来,先去找Controller看能不能处理。不能处理的所有请求又都交给静态资源处理器。静态资源也找不到则响应404页面
2、改变默认的静态资源访问路径
访问方式:http://localhost:8080/res/earth.png,就是在静态资源前加多一个前缀res
3、改变默认的静态资源的存放位置
spring:
mvc:
static-path-pattern: /res/** #当前项目下的res/访问路径访问的都是静态资源
#改变默认的静态资源的存放位置
web:
resources:
static-locations: [classpath:/haha/]
访问地址:
http://localhost:8080/res/public/1.jpg
http://localhost:8080/res/resources/earth.png
<dependency>
<groupId>org.webjars.npmgroupId>
<artifactId>jqueryartifactId>
<version>3.6.0version>
dependency>
访问地址:http://localhost:8080/webjars/jquery/3.6.0/src/jquery.js 后面地址要按照依赖里面的包路径
● 方式一:直接在静态资源路径下 添加index.html
注意:
○ 可以配置静态资源路径
○ 但是不可以配置静态资源的访问前缀。否则导致 index.html不能被默认访问
spring:
# mvc:
# static-path-pattern: /res/** #当前项目下的res/访问路径访问的都是静态资源
#改变默认的静态资源的存放位置
web:
resources:
static-locations: [classpath:/haha/]
访问根路径即可来到欢迎页
● 方式二:controller能处理/index
但是,下面这些要关闭
#spring:
# mvc:
# static-path-pattern: /res/** #当前项目下的res/访问路径访问的都是静态资源
#改变默认的静态资源的存放位置
# web:
# resources:
# static-locations: [classpath:/haha/]
Rest原理(表单提交要使用REST的时候)
开启映射,默认是关闭的
Controller
@RestController
public class HelloController {
@RequestMapping("/earth.png")
public String hello() {
return "aaaa";
}
@GetMapping("/user")
public String getUser(){
return "GET-张三";
}
@PostMapping("/user")
public String saveUser(){
return "POST-张三";
}
@PutMapping("/user")
public String putUser(){
return "PUT-张三";
}
@DeleteMapping("/user")
public String deleteUser(){
return "DELETE-张三";
}
// 扩展点:如何把 _method 这个名字换成我们自己喜欢的
}
基于上面的程序,解决扩展点:如何把 _method 这个名字换成我们自己喜欢的
1、注解:
@PathVariable 获取请求路径中占位符的值例如:@PathVariable(“id”) Integer id
@RequestHeader
@RequestParam
@CookieValue
@RequestBody
@MatrixVariable 处理矩阵变量
@ModelAttribute
// car/3/owner/lisi
@GetMapping("/car/{id}/owner/{username}")
public Map<String,Object> getCar(//获取请求路径中占位符的值
@PathVariable("id") Integer id,
@PathVariable("username") String name,
@PathVariable Map<String,String> pv,//将请求路径中占位符都封装到Map中
//获取请求头信息
@RequestHeader("User-Agent") String userAgent,//获取指定请求头信息
@RequestHeader Map<String,String> header,//获取所有请求头信息
//获取请求参数的值
@RequestParam("age") Integer age,
@RequestParam("inters") List<String> inters,
@RequestParam Map<String,String> params,
//获取Cookie的值
@CookieValue("originURI") String originURI,
@CookieValue("originURI") Cookie cookie
){
Map<String,Object> map = new HashMap<>();
// map.put("id",id);
// map.put("name",name);
// map.put("pv",pv);
// map.put("userAgent",userAgent);
// map.put("headers",header);
map.put("age",age);
map.put("inters",inters);
map.put("params",params);
map.put("originURI",originURI);
System.out.println(cookie.getName()+"===>"+cookie.getValue());
return map;
}
}
@RequestBody 的使用实例
post请求才有请求体
@PostMapping("/save")
public Map postMethod(@RequestBody String content){
Map<String,Object> map = new HashMap<>();
map.put("content",content);
return map;
}
@MatrixVariable 处理矩阵变量的实例(比较复杂)
2、Servlet API:
WebRequest、ServletRequest、MultipartRequest、 HttpSession、javax.servlet.http.PushBuilder、Principal、InputStream、Reader、HttpMethod、Locale、TimeZone、ZoneId
3、复杂参数:
Map、Model(map、model里面的数据会被放在request的请求域 request.setAttribute)、Errors/BindingResult、RedirectAttributes( 重定向携带数据)、ServletResponse(response)、SessionStatus、UriComponentsBuilder、ServletUriComponentsBuilder
Map
request.getAttribute();
4、自定义对象参数POJO:
可以自动类型转换与格式化,可以级联封装。
SpringMVC到底支持哪些返回值
ModelAndView
Model
View
ResponseEntity
ResponseBodyEmitter
StreamingResponseBody
HttpEntity
HttpHeaders
Callable
DeferredResult
ListenableFuture
CompletionStage
WebAsyncTask
有 @ModelAttribute 且为对象类型的
@ResponseBody 注解 ---> RequestResponseBodyMethodProcessor;
1、内容协商
根据客户端接收能力不同,返回不同媒体类型的数据。
引入xml依赖
<dependency>
<groupId>com.fasterxml.jackson.dataformatgroupId>
<artifactId>jackson-dataformat-xmlartifactId>
dependency>
基于请求头的内容协商策略:
(获取客户端Accept请求头字段)【application/xml】则服务端响应xml格式数据
【application/json】则服务端响应json格式数据
开启基于浏览器参数方式内容协商功能
为了方便内容协商,开启基于请求参数的内容协商功能。
spring:
contentnegotiation:
favor-parameter: true #开启请求参数内容协商模式
发请求: http://localhost:8080/test/person?format=json
http://localhost:8080/test/person?format=xml
自定义 MessageConverter
实现多协议数据兼容。json、xml、x-guigu
0、@ResponseBody 响应数据出去 调用 RequestResponseBodyMethodProcessor 处理
1、Processor 处理方法返回值。通过 MessageConverter 处理
2、所有 MessageConverter 合起来可以支持各种媒体类型数据的操作(读、写)
3、内容协商找到最终的 messageConverter;
SpringMVC的什么功能。一个入口给容器中添加一个 WebMvcConfigurer
现代化、服务端
Java模板引擎
一、基本语法
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、特殊操作
无操作: _
二、设置属性值-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}">
三、迭代
<tr th:each="prod : ${prods}">
<td th:text="${prod.name}">Onionstd>
<td th:text="${prod.price}">2.41td>
<td th:text="${prod.inStock}? #{true} : #{false}">yestd>
tr>
<tr th:each="prod,iterStat : ${prods}" th:class="${iterStat.odd}? 'odd'">
<td th:text="${prod.name}">Onionstd>
<td th:text="${prod.price}">2.41td>
<td th:text="${prod.inStock}? #{true} : #{false}">yestd>
tr>
四、条件运算
<a href="comments.html"
th:href="@{/product/comments(prodId=${prod.id})}"
th:if="${not #lists.isEmpty(prod.comments)}">viewa>
<div th:switch="${user.role}">
<p th:case="'admin'">User is an administratorp>
<p th:case="#{roles.manager}">User is a managerp>
<p th:case="*">User is some other thingp>
div>
1、引入tarter
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-thymeleafartifactId>
dependency>
表格数据的提交
修改标签属性,接受表格数据,显示在前端页面
遍历数据显示数据在前端页面
内容的引用和替换
官方例子说明
实例
1、● 自定义错误页
○ error/404.html error/5xx.html;有精确的错误状态码页面就匹配精确,没有就找 4xx.html;如果都没有就触发白页
2、@ControllerAdvice+@ExceptionHandler处理全局异常;底层是 ExceptionHandlerExceptionResolver 支持的
下面是数学异常处理结果
3、@ResponseStatus+自定义异常 ;底层是 ResponseStatusExceptionResolver ,把responsestatus注解的信息底层调用 response.sendError(statusCode, resolvedReason);tomcat发送的/error
4、● Spring底层的异常,如 参数类型转换异常;DefaultHandlerExceptionResolver 处理框架底层的异常。
○ response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.getMessage());
5、自定义实现 HandlerExceptionResolver 处理异常;可以作为默认的全局异常处理规则
6、● ErrorViewResolver 实现自定义处理异常;
○ response.sendError 。error请求就会转给controller
○ 你的异常没有任何人能处理。tomcat底层 response.sendError。error请求就会转给controller
○ basicErrorController 要去的页面地址是 ErrorViewResolver ;
@ServletComponentScan(basePackages = “com.atguigu.admin”) :指定原生Servlet组件都放在那里
@WebServlet(urlPatterns = “/my”):效果:直接响应,没有经过Spring的拦截器?
@WebFilter(urlPatterns={"/css/","/images/"})
@WebListener
1、Servlet
ServletRegistrationBean, FilterRegistrationBean, and ServletListenerRegistrationBean
首先,将上面的组件中的这些注释掉
@WebServlet(urlPatterns = “/my”):效果:直接响应,没有经过Spring的拦截器?
@WebFilter(urlPatterns={"/css/","/images/"})
@WebListener
**
* 1、MyServlet --> /my
* 2、DispatcherServlet --> /
*/
// (proxyBeanMethods = true):保证依赖的组件始终是单实例的
@Configuration(proxyBeanMethods = true)
public class MyRegistConfig {
@Bean
public ServletRegistrationBean myServlet(){
MyServlet myServlet = new MyServlet();
return new ServletRegistrationBean(myServlet,"/my","/my02");
}
@Bean
public FilterRegistrationBean myFilter(){
MyFilter myFilter = new MyFilter();
//拦截myServlet指定的路径
// return new FilterRegistrationBean(myFilter,myServlet());
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(myFilter);
//拦截路径
filterRegistrationBean.setUrlPatterns(Arrays.asList("/my","/css/*"));
return filterRegistrationBean;
}
@Bean
public ServletListenerRegistrationBean myListener(){
MySwervletContextListener mySwervletContextListener = new MySwervletContextListener();
return new ServletListenerRegistrationBean(mySwervletContextListener);
}
}
1、导入JDBC场景
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-jdbcartifactId>
dependency>
2、导入mysql驱动
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.26version>
dependency>
3、配置数据源——修改配置项application.yaml
spring:
datasource:
url: jdbc:mysql://localhost:3306/db_account
username: root
password: 75688
driver-class-name: com.mysql.cj.jdbc.Driver
4、测试
Slf4j
@SpringBootTest
class Boot05WebAdminApplicationTests {
@Autowired
JdbcTemplate jdbcTemplate;
@Test
void contextLoads() {
// jdbcTemplate.queryForObject("select * from account_tbl")
// jdbcTemplate.queryForList("select * from account_tbl",)
Long aLong = jdbcTemplate.queryForObject("select count(*) from account_tbl", Long.class);
log.info("记录总数:{}",aLong);
}
}
整合第三方技术的两种方式
● 自定义
● 找starter
1、创建数据源
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.1.17version>
dependency>
2、创建配置文件
spring:
datasource:
url: jdbc:mysql://localhost:3306/db_account
username: root
password: 75688
driver-class-name: com.mysql.cj.jdbc.Driver
3、创建配置类
@Configuration
public class MyDataSourceConfig {
// 默认的自动配置是判断容器中没有才会配@ConditionalOnMissingBean(DataSource.class)
@ConfigurationProperties("spring.datasource")
@Bean
public DataSource dataSource() throws SQLException {
DruidDataSource druidDataSource = new DruidDataSource();
return druidDataSource;
}
}
启动项目,访问http://localhost:8080/druid/index.html
/**
* WebStatFilter 用于采集web-jdbc关联监控的数据。
*/
@Bean
public FilterRegistrationBean webStatFilter(){
WebStatFilter webStatFilter = new WebStatFilter();
FilterRegistrationBean<WebStatFilter> filterRegistrationBean =
new FilterRegistrationBean<>(webStatFilter);
filterRegistrationBean.setUrlPatterns(Arrays.asList("/*"));//拦截路径
//排除一些请求路径
filterRegistrationBean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
return filterRegistrationBean;
}
1、引入druid-starter
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druid-spring-boot-starterartifactId>
<version>1.1.17version>
dependency>
2、使用配置文件
spring:
datasource:
url: jdbc:mysql://localhost:3306/db_account
username: root
password: 75688
driver-class-name: com.mysql.cj.jdbc.Driver
druid:
stat-view-servlet: #监控页的配置
enabled: true #开启配置
login-username: admin #用户名
login-password: 123456 #用户密码
reset-enable: false #没有重置按钮
web-stat-filter:
enabled: true #开启配置
url-pattern: /*
exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*'
aop-patterns: com.atguigu.admin.* #springbean监控
filters: stat,wall,slf4j # 底层开启功能,stat(sql监控),wall(防火墙)
filter: # 对上面filters里面的stat的详细配置
stat: #sql监控
slow-sql-millis: 1000 #超过1000毫秒就是慢查询
logSlowSql: true #是否记录慢查询
enabled: true #开启配置
wall: #防火墙
enabled: true #开启配置
config:
drop-table-allow: false #不允许删除数据库表格
jdbc:
template:
query-timeout: 3 #请求超时(秒)
1、引进依赖
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.1.4version>
dependency>
● 导入mybatis官方starter
● 编写mapper接口。标准@Mapper注解
● 编写sql映射文件并绑定mapper接口
● 在application.yaml中指定Mapper配置文件的位置,以及指定全局配置文件的信息 (建议;配置在mybatis.configuration)
最佳实战:
● 引入mybatis-starter
● 配置application.yaml中,指定mapper-location位置即可
● 编写Mapper接口并标注@Mapper注解
● 简单方法直接注解方式
● 复杂方法编写mapper.xml进行绑定映射
● @MapperScan(“com.atguigu.admin.mapper”) 简化,其他的接口就可以不用标注@Mapper注解
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.4.1version>
dependency>
@Configuration
public class MyBatisConfig {
@Bean
public MybatisPlusInterceptor paginationInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
// 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
// paginationInterceptor.setOverflow(false);
// 设置最大单页限制数量,默认 500 条,-1 不受限制
// paginationInterceptor.setLimit(500);
// 开启 count 的 join 优化,只针对部分 left join
//这是分页拦截器
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
paginationInnerInterceptor.setOverflow(true);//最大页后跳回首页
paginationInnerInterceptor.setMaxLimit(500L);//单页最大数
mybatisPlusInterceptor.addInnerInterceptor(paginationInnerInterceptor);
return mybatisPlusInterceptor;
}
}
controller
@GetMapping("/dynamic_table")
public String dynamic_table(@RequestParam(value="pn",defaultValue = "1") Integer pn,Model model){
//从数据库中查出user表中的用户进行展示
//构造分页参数
Page<User> page = new Page<>(pn, 2);
//调用page进行分页,用户数据 和 分页信息都在userPage中
Page<User> userPage = userService.page(page, null);
model.addAttribute("users",userPage);
return "table/dynamic_table";
}
Service
ServiceImpl
Mapper/dao
分页
Spring Boot 2.2.0 版本开始引入 JUnit 5 作为单元测试默认库
作为最新版本的JUnit框架,JUnit5与之前版本的Junit框架有很大的不同。由三个不同子项目的几个不同模块组成。
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
JUnit Platform: Junit Platform是在JVM上启动测试框架的基础,不仅支持Junit自制的测试引擎,其他测试引擎也都可以接入。
JUnit Jupiter: JUnit Jupiter提供了JUnit5的新的编程模型,是JUnit5新特性的核心。内部 包含了一个测试引擎,用于在Junit Platform上运行。
JUnit Vintage: 由于JUint已经发展多年,为了照顾老的项目,JUnit Vintage提供了兼容JUnit4.x,Junit3.x的测试引擎。
注意:
SpringBoot 2.4 以上版本移除了默认对 Vintage 的依赖。如果需要兼容junit4需要自行引入(不能使用junit4的功能 @Test)
JUnit 5’s Vintage Engine Removed from spring-boot-starter-test,如果需要继续兼容junit4需要自行引入vintage
<dependency>
<groupId>org.junit.vintagegroupId>
<artifactId>junit-vintage-engineartifactId>
<scope>testscope>
<exclusions>
<exclusion>
<groupId>org.hamcrestgroupId>
<artifactId>hamcrest-coreartifactId>
exclusion>
exclusions>
dependency>
● @Test :表示方法是测试方法。但是与JUnit4的@Test不同,他的职责非常单一不能声明任何属性,拓展的测试将会由Jupiter提供额外测试
● @ParameterizedTest :表示方法是参数化测试,下方会有详细介绍
● @RepeatedTest :表示方法可重复执行,下方会有详细介绍
● @DisplayName :为测试类或者测试方法设置展示名称
● @BeforeEach :表示在每个单元测试之前执行
● @AfterEach :表示在每个单元测试之后执行
● @BeforeAll :表示在所有单元测试之前执行
● @AfterAll :表示在所有单元测试之后执行
● @Tag :表示单元测试类别,类似于JUnit4中的@Categories
● @Disabled :表示测试类或测试方法不执行,类似于JUnit4中的@Ignore
● @Timeout :表示测试方法运行如果超过了指定时间将会返回错误
● @ExtendWith :为测试类或测试方法提供扩展类引用
● @Transactional 标注测试方法,测试完成后自动回滚
@SpringBootTest
@DisplayName("junit5功能测试类")
public class Junit5Test {
@Autowired
JdbcTemplate jdbcTemplate;
@DisplayName("测试displayname注解")
@Test
void testDisplayName() {
System.out.println(1);
System.out.println(jdbcTemplate);
}
@Disabled
@DisplayName("测试方法2")
@Test
void test2() {
System.out.println(2);
}
@RepeatedTest(5)
@Test
void test3() {
System.out.println(5);
}
@BeforeEach
void testBeforeEach() {
System.out.println("测试就要开始了...");
}
@AfterEach
void testAfterEach() {
System.out.println("测试结束了...");
}
@BeforeAll
static void testBeforeAll() {
System.out.println("所有测试就要开始了...");
}
@AfterAll
static void testAfterAll() {
System.out.println("所有测试以及结束了...");
}
}
断定一些事情一定会发生,不发生就是有问题
断言(assertions)是测试方法中的核心部分,用来对测试需要满足的条件进行验证。这些断言方法都是 org.junit.jupiter.api.Assertions 的静态方法。JUnit 5 内置的断言可以分成如下几个类别:
检查业务逻辑返回的数据是否合理。
所有的测试运行结束以后,会有一个详细的测试报告;
用来对单个值进行简单的验证。如:
方法 说明
assertEquals 判断两个对象或两个原始类型是否相等
assertNotEquals 判断两个对象或两个原始类型是否不相等
assertSame 判断两个对象引用是否指向同一个对象
assertNotSame 判断两个对象引用是否指向不同的对象
assertTrue 判断给定的布尔值是否为 true
assertFalse 判断给定的布尔值是否为 false
assertNull 判断给定的对象引用是否为 null
assertNotNull 判断给定的对象引用是否不为 null
/**
* 断言:前面断言失败,后面的代码都不会执行
*/
@DisplayName("测试简单断言")
@Test
void testSimpleAssertions() {
int cal = cal(3, 2);
//相等
assertEquals(6, cal, "业务逻辑计算失败");
Object obj1 = new Object();
Object obj2 = new Object();
assertSame(obj1, obj2, "两个对象不一样");
}
int cal(int i, int j) {
return i + j;
}
通过 assertArrayEquals 方法来判断两个对象或原始类型的数组是否相等
@Test
@DisplayName("array assertion")
void array() {
assertArrayEquals(new int[]{1, 2}, new int[]{1, 2}, "数组内容不相等");
}
assertAll 方法接受多个 org.junit.jupiter.api.Executable 函数式接口的实例作为要验证的断言,可以通过 lambda 表达式很容易的提供这些断言
@Test
@DisplayName("组合断言")
void all() {
/**
* 所有断言全部需要成功
*/
assertAll("test",
() -> assertTrue(true && true, "结果不为true"),
() -> assertEquals(1, 2, "结果不是1"));
System.out.println("=====");
}
在JUnit4时期,想要测试方法的异常情况时,需要用@Rule注解的ExpectedException变量还是比较麻烦的。而JUnit5提供了一种新的断言方式Assertions.assertThrows() ,配合函数式编程就可以进行使用。
@DisplayName("异常断言")
@Test
void testException() {
//断定业务逻辑一定出现异常
assertThrows(ArithmeticException.class, () -> {
int i = 10 / 2;
}, "业务逻辑居然正常运行?");
}
Junit5还提供了Assertions.assertTimeout() 为测试方法设置了超时时间
/**
* 规定方法超时时间。超出时间测试出异常
*
* @throws InterruptedException
*/
@Timeout(value = 500, unit = TimeUnit.MILLISECONDS)
@Test
void testTimeout() throws InterruptedException {
Thread.sleep(600);
}
通过 fail 方法直接使得测试失败
@DisplayName("快速失败")
@Test
void testFail(){
//xxxxx
if(1 == 2){
fail("测试失败");
}
}
JUnit 5 中的前置条件(assumptions【假设】)类似于断言,不同之处在于不满足的断言会使得测试方法失败,而不满足的前置条件只会使得测试方法的执行终止。前置条件可以看成是测试方法执行的前提,当该前提不满足时,就没有继续执行的必要。
/**
* 测试前置条件
*/
@DisplayName("测试前置条件")
@Test
void testassumptions(){
Assumptions.assumeTrue(false,"结果不是true");
System.out.println("111111");
}
JUnit 5 可以通过 Java 中的内部类和@Nested 注解实现嵌套测试,从而可以更好的把相关的测试方法组织在一起。在内部类中可以使用@BeforeEach 和@AfterEach 注解,而且嵌套的层次没有限制。
@DisplayName("嵌套测试")
public class TestingAStackDemo {
Stack<Object> stack;
@Test
@DisplayName("new Stack()")
void isInstantiatedWithNew() {
new Stack<>();
//嵌套测试情况下,外层的Test不能驱动内层的Before(After)Each/All之类的方法提前/之后运行
assertNull(stack);
}
@Nested
@DisplayName("when new")
class WhenNew {
@BeforeEach
void createNewStack() {
stack = new Stack<>();
}
@Test
@DisplayName("is empty")
void isEmpty() {
assertTrue(stack.isEmpty());
}
@Test
@DisplayName("throws EmptyStackException when popped")
void throwsExceptionWhenPopped() {
assertThrows(EmptyStackException.class, stack::pop);
}
@Test
@DisplayName("throws EmptyStackException when peeked")
void throwsExceptionWhenPeeked() {
assertThrows(EmptyStackException.class, stack::peek);
}
@Nested
@DisplayName("after pushing an element")
class AfterPushing {
String anElement = "an element";
@BeforeEach
void pushAnElement() {
stack.push(anElement);
}
/**
* 内层的Test可以驱动外层的Before(After)Each/All之类的方法提前/之后运行
*/
@Test
@DisplayName("it is no longer empty")
void isNotEmpty() {
assertFalse(stack.isEmpty());
}
@Test
@DisplayName("returns the element when popped and is empty")
void returnElementWhenPopped() {
assertEquals(anElement, stack.pop());
assertTrue(stack.isEmpty());
}
@Test
@DisplayName("returns the element when peeked but remains not empty")
void returnElementWhenPeeked() {
assertEquals(anElement, stack.peek());
assertFalse(stack.isEmpty());
}
}
}
}
参数化测试是JUnit5很重要的一个新特性,它使得用不同的参数多次运行测试成为了可能,也为我们的单元测试带来许多便利。
利用@ValueSource等注解,指定入参,我们将可以使用不同的参数进行多次单元测试,而不需要每新增一个参数就新增一个单元测试,省去了很多冗余代码。
@ValueSource: 为参数化测试指定入参来源,支持八大基础类以及String类型,Class类型
@NullSource: 表示为参数化测试提供一个null的入参
@EnumSource: 表示为参数化测试提供一个枚举入参
@CsvFileSource:表示读取指定CSV文件内容作为参数化测试入参
@MethodSource:表示读取指定方法的返回值作为参数化测试入参(注意方法返回需要是一个流)
当然如果参数化测试仅仅只能做到指定普通的入参还达不到让我觉得惊艳的地步。让我真正感到他的强大之处的地方在于他可以支持外部的各类入参。如:CSV,YML,JSON 文件甚至方法的返回值也可以作为入参。只需要去实现ArgumentsProvider接口,任何外部文件都可以作为它的入参。
@ParameterizedTest
@DisplayName("参数化测试")
@ValueSource(ints = {1,2,3,4,5})
void testParameterized(int i){
System.out.println(i);
}
@ParameterizedTest
@DisplayName("参数化测试")
@MethodSource("stringProvider")
void testParameterized2(String i){
System.out.println(i);
}
static Stream<String> stringProvider() {
return Stream.of("apple", "banana","atguigu");
}
在进行迁移的时候需要注意如下的变化:
● 注解在 org.junit.jupiter.api 包中,断言在 org.junit.jupiter.api.Assertions 类中,前置条件在 org.junit.jupiter.api.Assumptions 类中。
● 把@Before 和@After 替换成@BeforeEach 和@AfterEach。
● 把@BeforeClass 和@AfterClass 替换成@BeforeAll 和@AfterAll。
● 把@Ignore 替换成@Disabled。
● 把@Category 替换成@Tag。
● 把@RunWith、@Rule 和@ClassRule 替换成@ExtendWith。
简介
未来每一个微服务在云上部署以后,我们都需要对其进行监控、追踪、审计、控制等。SpringBoot就抽取了Actuator场景,使得我们每个微服务快速引用即可获得生产级别的应用监控、审计等功能。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
如何使用
● 引入场景
● 访问 http://localhost:8080/actuator/**
暴露所有监控信息为HTTP
management:
endpoints:
enabled-by-default: true #暴露所有端点信息
web:
exposure:
include: '*' #以web方式暴露
● 测试
http://localhost:8080/actuator/beans
http://localhost:8080/actuator/configprops
http://localhost:8080/actuator/metrics
http://localhost:8080/actuator/metrics/jvm.gc.pause
http://localhost:8080/actuator/endpointName/detailPath
。。。。。。
1、最常使用的端点
auditevents 暴露当前应用程序的审核事件信息。需要一个AuditEventRepository组件。
beans 显示应用程序中所有Spring Bean的完整列表。
caches 暴露可用的缓存。
conditions 显示自动配置的所有条件信息,包括匹配或不匹配的原因。
configprops 显示所有@ConfigurationProperties。
env 暴露Spring的属性ConfigurableEnvironment
flyway 显示已应用的所有Flyway数据库迁移。
需要一个或多个Flyway组件。
health 显示应用程序运行状况信息。
httptrace 显示HTTP跟踪信息(默认情况下,最近100个HTTP请求-响应)。需要一个HttpTraceRepository组件。
info 显示应用程序信息。
integrationgraph 显示Spring integrationgraph 。需要依赖spring-integration-core。
loggers 显示和修改应用程序中日志的配置。
liquibase 显示已应用的所有Liquibase数据库迁移。需要一个或多个Liquibase组件。
metrics 显示当前应用程序的“指标”信息。
mappings 显示所有@RequestMapping路径列表。
scheduledtasks 显示应用程序中的计划任务。
sessions 允许从Spring Session支持的会话存储中检索和删除用户会话。需要使用Spring Session的基于Servlet的Web应用程序。
shutdown 使应用程序正常关闭。默认禁用。
startup 显示由ApplicationStartup收集的启动步骤数据。需要使用SpringApplication进行配置BufferingApplicationStartup。
threaddump 执行线程转储。
如果您的应用程序是Web应用程序(Spring MVC,Spring WebFlux或Jersey),则可以使用以下附加端点:
heapdump 返回hprof堆转储文件。
jolokia 通过HTTP暴露JMX bean(需要引入Jolokia,不适用于WebFlux)。需要引入依赖jolokia-core。
logfile 返回日志文件的内容(如果已设置logging.file.name或logging.file.path属性)。支持使用HTTPRange标头来检索部分日志文件的内容。
prometheus 以Prometheus服务器可以抓取的格式公开指标。需要依赖micrometer-registry-prometheus。
最常用的Endpoint
● Health:监控状况
● Metrics:运行时指标
● Loggers:日志记录
修改端口号:server.port=8081