参考资料
1、尚硅谷/SpringBoot2核心技术与响应式编程 2、springboot官网 3、版本升级变化
maven环境配置
<mirrors>
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
</mirrors>
<profiles>
<profile>
<id>jdk-1.8</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.8</jdk>
</activation>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
</profile>
</profiles>
一、spring boot helloworld
参考官网
1.1、创建项目
1.2、pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.3</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
1.3、工程结构和主程序类
1.4、Controller
1.5、运行结果
二、spring boot通用配置(基于一spring boot helloworld)
https://docs.spring.io/spring-boot/docs/current/reference/html/ 这里通过简单使用配置文件,修改tomcat的端口
三、spring boot简化部署(基于一spring boot helloworld)
创建可执行 Jar 在pom.xml的dependencies部分下方添加打包插件
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
</plugin>
</plugins>
</build>
使用maven进行项目的打包 生成jar包 使用命令行代替服务器启动项目 一样可以访问:说明这打包时将tomcat等环境一起打包成jar包了,这样这服务器就可以不用安装tomcat等工具,节约成本
四、了解自动配置原理(基于一spring boot helloworld)
4.1、SpringBoot特点
父项目做依赖管理 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.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.3.4.RELEASE</version>
<scope>compile</scope>
</dependency>
4.2、自动配置
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 包里面
4.3、容器功能
4.3.1、注册组件两种方式
一、使用@Configuration和@Bean注解方式 二、给容器导入组件@Import 1、 基本使用 MyConfig.java
@Import({User.class, DBHelper.class})
@Configuration(proxyBeanMethods = true)
public class MyConfig {
@Bean
public User user01(){
User zhangsan = new User("zhangsan", 18);
zhangsan.setPet(tomcatPet());
return zhangsan;
}
@Bean("tom")
public Pet tomcatPet(){
return new Pet("tomcat");
}
}
MainApplication.java
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.atguigu.boot")
public class MainApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
Pet tom01 = run.getBean("tom", Pet.class);
Pet tom02 = run.getBean("tom", Pet.class);
System.out.println("是否单实例组件:" + (tom01 == tom02));
System.out.println("================");
MyConfig bean = run.getBean(MyConfig.class);
System.out.println("配置类本身也是一个组件:"+bean);
System.out.println("================");
User user = bean.user01();
User user1 = bean.user01();
System.out.println("user == user1:" + (user == user1));
System.out.println("================");
User user01 = run.getBean("user01", User.class);
Pet tom = run.getBean("tom", Pet.class);
System.out.println("用户的宠物:"+(user01.getPet() == tom));
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);
}
}
4.3.2、条件装配@Conditional
条件装配:满足Conditional指定的条件,则进行组件注入
@Import({User.class, DBHelper.class})
@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(name = "tom")
public class MyConfig {
@Bean
public User user01(){
User zhangsan = new User("zhangsan", 18);
return zhangsan;
}
@Bean("tom22")
public Pet tomcatPet(){
return new Pet("tomcat");
}
}
4.3.3、原生配置文件引入@ImportResource
解决问题:一些公司还是使用xml文件配置方式,所以需要将这些文件引进来,进行解析配置
MainApplication.java
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.atguigu.boot")
public class MainApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
boolean haha = run.containsBean("haha");
boolean hehe = run.containsBean("hehe");
System.out.println("haha:"+haha);
System.out.println("hehe:"+hehe);
}
}
4.3.4、配置绑定的properties文件的种方式
一、方式一,在bean上配置 使用 @Component @ConfigurationProperties(prefix = “mycar”)
properties配置文件 接收解析properties配置文件的bean 二:方式二,在配置类,和bean上同时配置 @ConfigurationProperties(prefix = “mycar”) public class Car {
@EnableConfigurationProperties(Car.class) public class MyConfig {
bean文件 配置类文件
4.4、最佳实践
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; ○ …
五、开发小技巧
5.1、Lombok,简化JavaBean开发
作用:简化JavaBean开发 使用@Data注解,不用再写get、set方法 使用@ToString注解,不用再写tostring方法。 使用@NoArgsConstructor注解,不用再写无参构造方法。 使用@AllArgsConstructor注解,不用再写有参构造方法。
步骤一:引入依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
步骤二:安装插件 file->settting->plugin 步骤三: 1、使用注解实现简化JavaBean开发 2、日志使用
5.2、dev-tools,热部署自动重启,加快项目的启动
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
使用 Ctrl+F9即可重新编译加载,并启动项目
5.3、pring Initailizr(项目初始化向导)
引入场景依赖和选择springboot版本 删除多余的文件 项目展开
六、SpringBoot2核心技术-核心功能
6.1、文件类型
6.1.1、properties
同以前的properties用法
6.1.2、yaml
一、简介 YAML 是 “YAML Ain’t Markup Language”(YAML 不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:“Yet Another Markup Language”(仍是一种标记语言)。 适合用来做以数据为中心的配置文件
二、基本语法 ● key: value;kv之间有空格 ● 大小写敏感 ● 使用缩进表示层级关系 ● 缩进不允许使用tab,只允许空格 ● 缩进的空格数不重要,只要相同层级的元素左对齐即可 ● '#‘表示注释 ● 字符串无需加引号,如果要加,’'与""表示字符串内容 会被 转义/不转义
三、数据类型 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:
userName: 'zhangsan \n 王二毛'
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}]
6.1.3、配置注释处理器
这样在编写yaml文件时就会有提示信息,可以快速准确开发
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
配置注释处理器只是为了开发方便,所以在打包的时候就不要将该工具添加到包中,因此需要进行一下配置
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
<exclude>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
6.2、Web开发
创建工程
6.2.1、静态资源访问
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/**
web:
resources:
static-locations: [classpath:/haha/]
访问地址: http://localhost:8080/res/public/1.jpg http://localhost:8080/res/resources/earth.png
6.2.2、webjars的使用:引入jQuery,bootstrap等的jar包
<dependency>
<groupId>org.webjars.npm</groupId>
<artifactId>jquery</artifactId>
<version>3.6.0</version>
</dependency>
访问地址:http://localhost:8080/webjars/jquery/3.6.0/src/jquery.js 后面地址要按照依赖里面的包路径
6.2.3、欢迎页
● 方式一:直接在静态资源路径下 添加index.html 注意: ○ 可以配置静态资源路径 ○ 但是不可以配置静态资源的访问前缀。否则导致 index.html不能被默认访问
spring:
web:
resources:
static-locations: [classpath:/haha/]
访问根路径即可来到欢迎页
● 方式二:controller能处理/index
6.2.4、自定义 Favicon
favicon.ico 放在静态资源目录下即可。
但是,下面这些要关闭
6.2.5、请求映射——rest使用与原理
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 这个名字换成我们自己喜欢的
6.2.6、普通参数与基本注解
1、注解: @PathVariable 获取请求路径中占位符的值例如:@PathVariable(“id”) Integer id @RequestHeader @RequestParam @CookieValue @RequestBody @MatrixVariable 处理矩阵变量 @ModelAttribute
@GetMapping("/car/{id}/owner/{username}")
public Map<String,Object> getCar(
@PathVariable("id") Integer id,
@PathVariable("username") String name,
@PathVariable Map<String,String> pv,
@RequestHeader("User-Agent") String userAgent,
@RequestHeader Map<String,String> header,
@RequestParam("age") Integer age,
@RequestParam("inters") List<String> inters,
@RequestParam Map<String,String> params,
@CookieValue("originURI") String originURI,
@CookieValue("originURI") Cookie cookie
){
Map<String,Object> map = new HashMap<>();
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<String,Object> map, Model model, HttpServletRequest request 都是可以给request域中放数据, request.getAttribute();
4、自定义对象参数POJO: 可以自动类型转换与格式化,可以级联封装。
使用格式化器,自定义Converter,实现级联封装
6.2.7、数据响应与内容协商——放回json或xml
SpringMVC到底支持哪些返回值
ModelAndView
Model
View
ResponseEntity
ResponseBodyEmitter
StreamingResponseBody
HttpEntity
HttpHeaders
Callable
DeferredResult
ListenableFuture
CompletionStage
WebAsyncTask
有 @ModelAttribute 且为对象类型的
@ResponseBody 注解 ---> RequestResponseBodyMethodProcessor;
1、内容协商 根据客户端接收能力不同,返回不同媒体类型的数据。 引入xml依赖
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</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
6.2.8、模板引擎-Thymeleaf(视图解析和模板引擎)
现代化、服务端 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}">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>
四、条件运算
<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>
thymeleaf使用 1、引入Starter
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
七、构建后台管理系统
7.1、Thymeleaf使用
表格数据的提交 修改标签属性,接受表格数据,显示在前端页面 遍历数据显示数据在前端页面 内容的引用和替换 官方例子说明 实例
7.2、拦截器检查
7.3、文件上传功能开发
7.4、错误处理
7.4.1、定制处理逻辑
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 ;
7.5、Web原生组件注入(Servlet、Filter、Listener)
7.5.1、使用Servlet API(推荐使用)
@ServletComponentScan(basePackages = “com.atguigu.admin”) :指定原生Servlet组件都放在那里 @WebServlet(urlPatterns = “/my”):效果:直接响应,没有经过Spring的拦截器? @WebFilter(urlPatterns={"/css/","/images/"}) @WebListener 1、Servlet
2、Filter 3、Listener
7.5.2、使用RegistrationBean
ServletRegistrationBean, FilterRegistrationBean, and ServletListenerRegistrationBean
首先,将上面的组件中的这些注释掉 @WebServlet(urlPatterns = “/my”):效果:直接响应,没有经过Spring的拦截器? @WebFilter(urlPatterns={"/css/","/images/"}) @WebListener
**
* 1、MyServlet --> /my
* 2、DispatcherServlet --> /
*/
@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();
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);
}
}
7.5.3、嵌入式Servlet容器
1、切换服务器 2、定制化
7.6、定制化原理
web自定义定制化(一定要掌握)
八、数据访问
8.1、SQL
1、导入JDBC场景
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
2、导入mysql驱动
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.26</version>
</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() {
Long aLong = jdbcTemplate.queryForObject("select count(*) from account_tbl", Long.class);
log.info("记录总数:{}",aLong);
}
}
整合第三方技术的两种方式 ● 自定义 ● 找starter
8.2.1、自定义方式——基础用法
1、创建数据源
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.17</version>
</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 {
@ConfigurationProperties("spring.datasource")
@Bean
public DataSource dataSource() throws SQLException {
DruidDataSource druidDataSource = new DruidDataSource();
return druidDataSource;
}
}
4、测试
8.2.2、自定义方式——开启Druid监控页功能
启动项目,访问http://localhost:8080/druid/index.html
8.2.3、自定义方式——开启监控统计功能
测试 发送sql请求 查看监控
8.2.4、自定义方式——开启web监控
代码如下
@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;
}
8.2.5、自定义方式——开启防火墙
优化监控页——监控页面的登录
8.2.6、自定义方式——通过配置文件实现上面功能
一样能正常访问
8.2.7、找starter方式——基础用法(简单高效)
1、引入druid-starter
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.17</version>
</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.*
filters: stat,wall,slf4j
filter:
stat:
slow-sql-millis: 1000
logSlowSql: true
enabled: true
wall:
enabled: true
config:
drop-table-allow: false
jdbc:
template:
query-timeout: 3
九、整合MyBatis操作
1、引进依赖
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
9.1、配置模式(和之前的使用方法一致)
● 导入mybatis官方starter ● 编写mapper接口。标准@Mapper注解 ● 编写sql映射文件并绑定mapper接口 ● 在application.yaml中指定Mapper配置文件的位置,以及指定全局配置文件的信息 (建议;配置在mybatis.configuration)
9.2、注解模式(不需要写mapper.xml)
9.3、混合模式
最佳实战: ● 引入mybatis-starter ● 配置application.yaml中,指定mapper-location位置即可 ● 编写Mapper接口并标注@Mapper注解 ● 简单方法直接注解方式 ● 复杂方法编写mapper.xml进行绑定映射 ● @MapperScan(“com.atguigu.admin.mapper”) 简化,其他的接口就可以不用标注@Mapper注解
十、整合mybatis-plus
安装mybatisX插件提高开发速度
10.1、引进依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
10.2、添加分页插件
@Configuration
public class MyBatisConfig {
@Bean
public MybatisPlusInterceptor paginationInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
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){
Page<User> page = new Page<>(pn, 2);
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.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
</exclusion>
</exclusions>
</dependency>
11.1、JUnit5常用注解
● @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("所有测试以及结束了...");
}
}
11.2、断言(assertions)
断定一些事情一定会发生,不发生就是有问题 断言(assertions)是测试方法中的核心部分,用来对测试需要满足的条件进行验证。这些断言方法都是 org.junit.jupiter.api.Assertions 的静态方法。JUnit 5 内置的断言可以分成如下几个类别: 检查业务逻辑返回的数据是否合理。 所有的测试运行结束以后,会有一个详细的测试报告;
1、简单断言
用来对单个值进行简单的验证。如: 方法 说明 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;
}
2、数组断言
通过 assertArrayEquals 方法来判断两个对象或原始类型的数组是否相等
@Test
@DisplayName("array assertion")
void array() {
assertArrayEquals(new int[]{1, 2}, new int[]{1, 2}, "数组内容不相等");
}
3、组合断言
assertAll 方法接受多个 org.junit.jupiter.api.Executable 函数式接口的实例作为要验证的断言,可以通过 lambda 表达式很容易的提供这些断言
@Test
@DisplayName("组合断言")
void all() {
assertAll("test",
() -> assertTrue(true && true, "结果不为true"),
() -> assertEquals(1, 2, "结果不是1"));
System.out.println("=====");
}
4、异常断言
在JUnit4时期,想要测试方法的异常情况时,需要用@Rule注解的ExpectedException变量还是比较麻烦的。而JUnit5提供了一种新的断言方式Assertions.assertThrows() ,配合函数式编程就可以进行使用。
@DisplayName("异常断言")
@Test
void testException() {
assertThrows(ArithmeticException.class, () -> {
int i = 10 / 2;
}, "业务逻辑居然正常运行?");
}
5、超时断言
Junit5还提供了Assertions.assertTimeout() 为测试方法设置了超时时间
@Timeout(value = 500, unit = TimeUnit.MILLISECONDS)
@Test
void testTimeout() throws InterruptedException {
Thread.sleep(600);
}
6、 快速失败
通过 fail 方法直接使得测试失败
@DisplayName("快速失败")
@Test
void testFail(){
if(1 == 2){
fail("测试失败");
}
}
11.3、 前置条件(assumptions)
JUnit 5 中的前置条件(assumptions【假设】)类似于断言,不同之处在于不满足的断言会使得测试方法失败,而不满足的前置条件只会使得测试方法的执行终止。前置条件可以看成是测试方法执行的前提,当该前提不满足时,就没有继续执行的必要。
@DisplayName("测试前置条件")
@Test
void testassumptions(){
Assumptions.assumeTrue(false,"结果不是true");
System.out.println("111111");
}
11.4 、嵌套测试
JUnit 5 可以通过 Java 中的内部类和@Nested 注解实现嵌套测试,从而可以更好的把相关的测试方法组织在一起。在内部类中可以使用@BeforeEach 和@AfterEach 注解,而且嵌套的层次没有限制。
@DisplayName("嵌套测试")
public class TestingAStackDemo {
Stack<Object> stack;
@Test
@DisplayName("new Stack()")
void isInstantiatedWithNew() {
new Stack<>();
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
@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());
}
}
}
}
11.5、参数化测试
参数化测试是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");
}
11.6、迁移指南
在进行迁移的时候需要注意如下的变化: ● 注解在 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。
十二、指标监控
12.1、SpringBoot Actuator
简介 未来每一个微服务在云上部署以后,我们都需要对其进行监控、追踪、审计、控制等。SpringBoot就抽取了Actuator场景,使得我们每个微服务快速引用即可获得生产级别的应用监控、审计等功能。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
如何使用 ● 引入场景 ● 访问 http://localhost:8080/actuator/** 暴露所有监控信息为HTTP
management:
endpoints:
enabled-by-default: true
web:
exposure:
include: '*'
● 测试 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 。。。。。。
12.2、Actuator Endpoint
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:日志记录
|