我们之前的SSM还是使用起来不够爽。
SpringBoot就能很好的解决上述问题。
Spring Boot是基于Spring开发的全新框架,相当于对Spring做了又一层封装。
其设计目的是用来简化Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。(自动配置)
并且对第三方依赖的添加也进行了封装简化。(起步依赖)
所以Spring能做的他都能做,并且简化了配置。
并且还提供了一些Spring所没有的比如:
内嵌web容器,不再需要部署到web容器中
提供准备好的特性,如指标、健康检查和外部化配置
最大特点:自动配置、起步依赖
官网:https://spring.io/projects/spring-boot
JDK : 8
Maven :3.5.x
<mirrors>
<mirror>
<id>aliyunmavenid>
<mirrorOf>centralmirrorOf>
<name>aliyun mavenname>
<url>https://maven.aliyun.com/repository/public url>
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>
@echo off
rem create by NettQun
rem 这里写你的仓库路径
set REPOSITORY_PATH=E:\Develop\maven_rep
rem 正在搜索...
for /f "delims=" %%i in ('dir /b /s "%REPOSITORY_PATH%\*lastUpdated*"') do (
echo %%i
del /s /q "%%i"
)
rem 搜索完毕
pause
创建一个bat文件,然后复制上述脚本进去,修改其中maven本地仓库的地址,保存后双击执行即可。
①继承父工程
在pom.xml中添加一下配置,继承spring-boot-starter-parent这个父工程
org.springframework.boot
spring-boot-starter-parent
2.5.0
②添加依赖
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
dependencies>
③创建启动类
创建一个类在其实加上@SpringBootApplication注解标识为启动类。
@SpringBootApplication
public class HelloApplication {
public static void main(String[] args) {
SpringApplication.run(HelloApplication.class, args);
}
}
④定义Controller
创建Controller,主要Controller要放在启动类所在包或者其子包下。
@RestController
public class HelloController {
@RequestMapping("/hello")
public String hello(){
return "hello";
}
}
⑤运行测试
直接运行启动类的main方法即可。
①访问时404
检查Controller是不是在启动类所在的包或者其子包下,如果不是需要进行修改。
②依赖爆红
配置阿里云镜像后刷新maven项目让其下载。
我们可以把springboot的项目打成jar包直接去运行。
①添加maven插件
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
②maven打包
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hTUqm4Tf-1653278159429)(img\SpringBoot项目打包.png)]
③运行jar包
在jar包所在目录执行命令
java -jar jar包名称
即可运行。
https://start.spring.io/
SpringBoot依靠父项目中的版本锁定和starter机制让我们能更轻松的实现对依赖的管理。
一般程序在运行时发生类似于 java.lang.ClassNotFoundException,Method not found: ‘……’,或者莫名其妙的异常信息,这种情况一般很大可能就是 jar包依赖冲突的问题引起的了。
一般在是A依赖C(低版本),B也依赖C(高版本)。 都是他们依赖的又是不同版本的C的时候会出现。
如果出现了类似于 java.lang.ClassNotFoundException,Method not found: 这些异常检查相关的依赖冲突问题,排除掉低版本的依赖,留下高版本的依赖。
我们的SpringBoot模块都需要继承一个父工程:spring-boot-starter-parent。在spring-boot-starter-parent的父工程spring-boot-dependencies中对常用的依赖进行了版本锁定。这样我们在添加依赖时,很多时候都不需要添加依赖的版本号了。
我们也可以采用覆盖properties配置或者直接指定版本号的方式修改依赖的版本。
例如:
直接指定版本号
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.7.2version>
dependency>
覆盖properties配置
<properties>
<aspectj.version>1.7.2aspectj.version>
properties>
当我们需要使用某种功能时只需要引入对应的starter即可。一个starter针对一种特定的场景,其内部引入了该场景所需的依赖。这样我们就不需要单独引入多个依赖了。
命名规律
spring-boot-starter
开头后面跟上场景名称。例如:spring-boot-starter-data-jpa场景名-spring-boot-starter
的格式,例如:mybatis-spring-boot-starter SpringBoot中最重要的特性就是自动配置。
Springboot遵循“约定优于配置”的原则,自动进行了默认配置。这样我们就不需要做大量的配置。
当我们需要使用什么场景时,就会自动配置这个场景相关的配置。
如果他的默认配置不符合我们的需求时修改这部分配置即可。
YAML (YAML Ain’t a Markup Language)YAML不是一种标记语言,通常以.yml为后缀的文件,是一种直观的能够被电脑识别的数据序列化格式,并且容易被人类阅读,容易和脚本语言交互的,可以被支持YAML库的不同的编程语言程序导入,一种专门用来写配置文件的语言。
YAML试图用一种比XML更敏捷的方式,来完成XML所完成的任务。
例如:
student:
name: sangeng
age: 15
<student>
<name>sangengname>
<age>15age>
student>
YAML易于人们阅读。
更加简洁明了
k: v 表示键值对关系,冒号后面必须有一个空格
使用空格的缩进表示层级关系,空格数目不重要,只要是左对齐的一列数据,都是同一个层级的
大小写敏感
缩进时不允许使用Tab键,只允许使用空格。
java中对于驼峰命名法,可用原名或使用-代替驼峰,如java中的lastName属性,在yml中使用lastName或 last-name都可正确映射。
yml中注释前面要加#
k: v:字面量直接写;
字符串默认不用加上单引号或者双绰号;
“”: 双引号;转意字符能够起作用
name: “sangeng \n caotang”:输出;sangeng 换行 caotang
‘’:单引号;会转义特殊字符,特殊字符最终只是一个普通的字符串数据
name1: sangeng
name2: 'sangeng \n caotang'
name3: "sangeng \n caotang"
age: 15
flag: true
date: 2019/01/01
多行写法:
在下一行来写对象的属性和值的关系,注意缩进
student:
name: zhangsan
age: 20
行内写法:
student: {name: zhangsan,age: 20}
用- 值表示数组中的一个元素
多行写法:
pets:
- dog
- pig
- cat
行内写法:
pets: [dog,pig,cat]
students:
- name: zhangsan
age: 22
- name: lisi
age: 20
- {name: wangwu,age: 18}
可以使用 ${key:defaultValue} 的方式来赋值,若key不存在,则会使用defaultValue来赋值。
例如
server:
port: ${myPort:88}
myPort: 80
注意使用此注解只能获取简单类型的值(8种基本数据类型及其包装类,String,Date)
student:
lastName: sangeng
@RestController
public class TestController {
@Value("${student.lastName}")
private String lastName;
@RequestMapping("/test")
public String test(){
System.out.println(lastName);
return "hi";
}
}
注意:加了@Value的类必须是交由Spring容器管理的
yml配置
student:
lastName: sangeng
age: 17
student2:
lastName: sangeng2
age: 15
在类上添加注解@Component 和@ConfigurationProperties(prefix = “配置前缀”)
@Data
@AllArgsConstructor
@NoArgsConstructor
@Component
@ConfigurationProperties(prefix = "student")
public class Student {
private String lastName;
private Integer age;
}
从spring容器中获取Student对象
@RestController
public class TestController {
@Autowired
private Student student;
@RequestMapping("/test")
public String test(){
System.out.println(student);
return "hi";
}
}
注意事项:要求对应的属性要有set/get方法,并且key要和成员变量名一致才可以对应的上。
lombok讲解视频:
https://www.bilibili.com/video/BV1G54y1V7VG?p=12
https://www.bilibili.com/video/BV1G54y1V7VG?p=13
要求把下面实体类中的各个属性在yml文件中进行赋值。然后想办法读取yml配置的属性值,进行输出测试。
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private String lastName;
private Integer age;
private Boolean boss;
private Date birthday;
private Map<String,String> maps;
private Map<String,String> maps2;
private List<Dog> list;
private Dog dog;
private String[] arr;
private String[] arr2;
private Map<String,Dog> dogMap;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
class Dog {
private String name;
private Integer age;
}
# 练习
student:
lastName: sangeng
age: 15
boss: true
birthday: 2006/2/3
maps:
name: sangeng
age: 11
maps2: {name: caotang,age: 199}
list:
- name: 小白
age: 3
- name: 小黄
age: 4
- {name: 小黑,age: 1}
dog:
name: 小红
age: 5
arr:
- sangeng
- caotang
arr2: [sangeng,caotang]
dogMap:
xb: {name: 小白,age: 9}
xh:
name: 小红
age: 6
@Data
@AllArgsConstructor
@NoArgsConstructor
@Component
@ConfigurationProperties(prefix = "student")
public class Student {
private String lastName;
private Integer age;
private Boolean boss;
private Date birthday;
private Map<String,String> maps;
private Map<String,String> maps2;
private List<Dog> list;
private Dog dog;
private String[] arr;
private String[] arr2;
private Map<String,Dog> dogMap;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
class Dog {
private String name;
private Integer age;
}
我们可以使用一些网站非常方便的实现YML和properties格式配置的相互转换。
转换网站:https://www.toyaml.com/index.html
如果使用了@ConfigurationProperties注解,可以增加以下依赖,让我们在书写配置时有相应的提示。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-configuration-processorartifactId>
<optional>trueoptional>
dependency>
注意:添加完依赖加完注解后要运行一次程序才会有相应的提示。
SpringBoot为我们提供了一个方便我们开发测试的工具dev-tools。使用后可以实现热部署的效果。当我们运行了程序后对程序进行了修改,程序会自动重启。
原理是使用了两个ClassLoder,一个ClassLoader加载哪些不会改变的类(第三方jar包),另一个ClassLoader加载会更改的类.称之为Restart ClassLoader,这样在有代码更改的时候,原来的Restart Classloader被丢弃,重新创建一个Restart ClassLoader,由于需要加载的类相比较少,所以实现了较快的重启。
①设置IDEA自动编译
在idea中的setting做下面配置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yFxrTVCN-1653278159430)(D:\笔记\SpringBoot\img\自动编译配置.png)]
②设置允许程序运行时自动启动
ctrl + shift + alt + / 这组快捷键后会有一个小弹窗,点击Registry 就会进入下面的界面,找到下面的配置项并勾选,勾选后直接点close
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jr55shgJ-1653278159431)(D:\笔记\SpringBoot\img\允许运行时自动启动.png)]
①添加依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<optional>trueoptional>
dependency>
②触发热部署
当我们在修改完代码或者静态资源后可以切换到其它软件,让IDEA自动进行编译,自动编译后就会触发热部署。
或者使用Ctrl+F9手动触发重新编译。
我们可以使用SpringBoot整合Junit进行单元测试。
Spring Boot 2.2.0 版本开始引入 JUnit 5 作为单元测试默认库。
Junit5功能相比于Junit4也会更强大。但是本课程是SpringBoot的课程,所以主要针对SpringBoot如何整合Junit进行单元测试做讲解。暂不针对Junit5的新功能做介绍。如有需要会针对Junit5录制专门的课程进行讲解。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
dependency>
import com.sangeng.controller.HelloController;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class ApplicationTest {
@Autowired
private HelloController helloController;
@Test
public void testJunit(){
System.out.println(1);
System.out.println(helloController);
}
}
注意:测试类所在的包需要和启动类是在同一个包下。否则就要使用如下写法指定启动类。
import com.sangeng.controller.HelloController;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
//classes属性来指定启动类
@SpringBootTest(classes = HelloApplication.class)
public class ApplicationTest {
@Autowired
private HelloController helloController;
@Test
public void testJunit(){
System.out.println(1);
System.out.println(helloController);
}
}
如果是对老项目中的SpringBoot进行了版本升级会发现之前的单元测试代码出现了一些问题。
因为Junit5和之前的Junit4有比较大的不同。
先看一张图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nwFrMl3u-1653278159431)(D:\笔记\SpringBoot\img\junit5.jpeg)]
从上图可以看出 JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
虽然Junit5包含了JUnit Vintage来兼容JUnit3和Junit4,但是SpringBoot 2.4 以上版本对应的spring-boot-starter-test移除了默认对 **Vintage 的依赖。**所以当我们仅仅依赖spring-boot-starter-test时会发现之前我们使用的@Test注解和@RunWith注解都不能使用了。
我们可以单独在依赖vintage来进行兼容。
<dependency>
<groupId>org.junit.vintagegroupId>
<artifactId>junit-vintage-engineartifactId>
<scope>testscope>
dependency>
注意:
org.junit.Test对应的是Junit4的版本,就搭配@RunWith注解来使用。
SpringBoot2.2.0之前版本的写法
import com.sangeng.controller.HelloController;
//import org.junit.jupiter.api.Test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
//classes属性来指定启动类
@SpringBootTest
@RunWith(SpringRunner.class)
public class ApplicationTest {
@Autowired
private HelloController helloController;
@Test
public void testJunit(){
System.out.println(1);
System.out.println(helloController);
}
}
①数据准备
/*Table structure for table `user` */
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`address` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;
/*Data for the table `user` */
insert into `user`(`id`,`username`,`age`,`address`) values (2,'pdd',25,'上海'),(3,'UZI',19,'上海11'),(4,'RF',19,NULL),(6,'三更',14,'请问2'),(8,'test1',11,'cc'),(9,'test2',12,'cc2');
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
②实体类
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer id;
private String username;
private Integer age;
private String address;
}
github: https://github.com/mybatis/spring-boot-starter/
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.2.0version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<scope>runtimescope>
dependency>
spring:
datasource:
url: jdbc:mysql://localhost:3306/test?characterEncoding=utf-8&serverTimezone=UTC
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
mapper-locations: classpath:mapper/*Mapper.xml # mapper映射文件路径
type-aliases-package: com.sangeng.domain # 配置哪个包下的类有默认的别名
注意在接口上加上@Mapper 和@Repository 注解
@Repository
@Mapper
public interface UserMapper {
public List<User> findAll();
}
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sangeng.mapper.UserMapper">
<select id="findAll" resultType="com.sangeng.domain.User">
select * from user
select>
mapper>
@SpringBootTest(classes = HelloApplication.class)
public class SpringMyTest {
@Autowired
UserMapper userMapper;
@Test
public void tesMapper(){
System.out.println(userMapper.findAll());
}
}
由于SpringBoot的项目是打成jar包的所以没有之前web项目的那些web资源目录(webapps)。
那么我们的静态资源要放到哪里呢?
从SpringBoot官方文档中我们可以知道,我们可以把静态资源放到 resources/static
(或者 resources/public
或者resources/resources
或者 resources/META-INF/resources
) 中即可。
静态资源放完后,
例如我们想访问文件:resources/static/index.html 只需要在访问时资源路径写成/index.html即可。
例如我们想访问文件:resources/static/pages/login.html 访问的资源路径写成: /pages/login.html
SpringBoot默认的静态资源路径匹配为/** 。如果想要修改可以通过 spring.mvc.static-path-pattern
这个配置进行修改。
例如想让访问静态资源的url必须前缀有/res。例如/res/index.html 才能访问到static目录中的。我们可以修改如下:
在application.yml中
spring:
mvc:
static-path-pattern: /res/** #修改静态资源访问路径
我们可以修改 spring.web.resources.static-locations 这个配置来修改静态资源的存放目录。
例如:
spring:
web:
resources:
static-locations:
- classpath:/sgstatic/
- classpath:/static/
详细讲解:https://www.bilibili.com/video/BV1AK4y1o74Y P5-P12
该注解可以加到方法上或者是类上。(查看其源码可知)
我们可以用其来设定所能匹配请求的要求。只有符合了设置的要求,请求才能被加了该注解的方法或类处理。
path或者value属性都可以用来指定请求路径。
例如:
我们期望让请求的资源路径为**/test/testPath的请求能够被testPath**方法处理则可以写如下代码
@RestController
@RequestMapping("/test")
public class HelloController {
@RequestMapping("/testPath")
public String testPath(){
return "testPath";
}
}
@RestController
public class HelloController {
@RequestMapping("/test/testPath")
public String testPath(){
return "testPath";
}
}
method属性可以用来指定可处理的请求方式。
例如:
我们期望让请求的资源路径为**/test/testMethod的POST请求能够被testMethod**方法处理。则可以写如下代码
@RestController
@RequestMapping("/test")
public class TestController {
@RequestMapping(value = "/testMethod",method = RequestMethod.POST)
public String testMethod(){
System.out.println("testMethod处理了请求");
return "testMethod";
}
}
注意:我们可以也可以运用如下注解来进行替换
@PostMapping 等价于 @RequestMapping(method = RequestMethod.POST)
@GetMapping 等价于 @RequestMapping(method = RequestMethod.GET)
@PutMapping 等价于 @RequestMapping(method = RequestMethod.PUT)
@DeleteMapping 等价于 @RequestMapping(method = RequestMethod.DELETE)
例如:
上面的需求我们可以使用下面的写法实现
@RestController
@RequestMapping("/test")
public class TestController {
@PostMapping(value = "/testMethod")
public String testMethod(){
System.out.println("testMethod处理了请求");
return "testMethod";
}
}
我们可以使用params属性来对请求参数进行一些限制。可以要求必须具有某些参数,或者是某些参数必须是某个值,或者是某些参数必须不是某个值。
例如:
我们期望让请求的资源路径为**/test/testParams的GET请求,并且请求参数中具有code参数**的请求能够被testParams方法处理。则可以写如下代码
@RestController
@RequestMapping("/test")
public class TestController {
@RequestMapping(value = "/testParams",method = RequestMethod.GET,params = "code")
public String testParams(){
System.out.println("testParams处理了请求");
return "testParams";
}
}
如果是要求不能有code这个参数可以把改成如下形式
@RestController
@RequestMapping("/test")
public class TestController {
@RequestMapping(value = "/testParams",method = RequestMethod.GET,params = "!code")
public String testParams(){
System.out.println("testParams处理了请求");
return "testParams";
}
}
如果要求有code这参数,并且这参数值必须是某个值可以改成如下形式
@RestController
@RequestMapping("/test")
public class TestController {
@RequestMapping(value = "/testParams",method = RequestMethod.GET,params = "code=sgct")
public String testParams(){
System.out.println("testParams处理了请求");
return "testParams";
}
}
如果要求有code这参数,并且这参数值必须不是某个值可以改成如下形式
@RestController
@RequestMapping("/test")
public class TestController {
@RequestMapping(value = "/testParams",method = RequestMethod.GET,params = "code!=sgct")
public String testParams(){
System.out.println("testParams处理了请求");
return "testParams";
}
}
我们可以使用headers属性来对请求头进行一些限制。
例如:
我们期望让请求的资源路径为**/test/testHeaders的GET请求,并且请求头中具有deviceType**的请求能够被testHeaders方法处理。则可以写如下代码
@RestController
@RequestMapping("/test")
public class TestController {
@RequestMapping(value = "/testHeaders",method = RequestMethod.GET,headers = "deviceType")
public String testHeaders(){
System.out.println("testHeaders处理了请求");
return "testHeaders";
}
}
如果是要求不能有deviceType这个请求头可以把改成如下形式
@RestController
@RequestMapping("/test")
public class TestController {
@RequestMapping(value = "/testHeaders",method = RequestMethod.GET,headers = "!deviceType")
public String testHeaders(){
System.out.println("testHeaders处理了请求");
return "testHeaders";
}
}
如果要求有deviceType这个请求头,并且其值必须是某个值可以改成如下形式
@RestController
@RequestMapping("/test")
public class TestController {
@RequestMapping(value = "/testHeaders",method = RequestMethod.GET,headers = "deviceType=ios")
public String testHeaders(){
System.out.println("testHeaders处理了请求");
return "testHeaders";
}
}
如果要求有deviceType这个请求头,并且其值必须不是某个值可以改成如下形式
@RestController
@RequestMapping("/test")
public class TestController {
@RequestMapping(value = "/testHeaders",method = RequestMethod.GET,headers = "deviceType!=ios")
public String testHeaders(){
System.out.println("testHeaders处理了请求");
return "testHeaders";
}
}
我们可以使用consumes属性来对Content-Type这个请求头进行一些限制。
我们期望让请求的资源路径为**/test/testConsumes**的POST请求,并且请求头中的Content-Type头必须为 multipart/from-data 的请求能够被testConsumes方法处理。则可以写如下代码
@RequestMapping(value = "/testConsumes",method = RequestMethod.POST,consumes = "multipart/from-data")
public String testConsumes(){
System.out.println("testConsumes处理了请求");
return "testConsumes";
}
如果我们要求请求头Content-Type的值必须不能为某个multipart/from-data则可以改成如下形式:
@RequestMapping(value = "/testConsumes",method = RequestMethod.POST,consumes = "!multipart/from-data")
public String testConsumes(){
System.out.println("testConsumes处理了请求");
return "testConsumes";
}
RestFul风格的接口一些参数是在请求路径上的。类似: /user/1 这里的1就是id。
如果我们想获取这种格式的数据可以使用**@PathVariable**来实现。
要求定义个RestFul风格的接口,该接口可以用来根据id查询用户。请求路径要求为 /user ,请求方式要求为GET。
而请求参数id要写在请求路径上,例如 /user/1 这里的1就是id。
我们可以定义如下方法,通过如下方式来获取路径参数:
@RestController
public class UserController {
@RequestMapping(value = "/user/{id}",method = RequestMethod.GET)
public String findUserById( @PathVariable("id")Integer id){
System.out.println("findUserById");
System.out.println(id);
return "findUserById";
}
}
如果这个接口,想根据id和username查询用户。请求路径要求为 /user ,请求方式要求为GET。
而请求参数id和name要写在请求路径上,例如 /user/1/zs 这里的1就是id,zs是name
我们可以定义如下方法,通过如下方式来获取路径参数:
@RestController
public class UserController {
@RequestMapping(value = "/user/{id}/{name}",method = RequestMethod.GET)
public String findUser(@PathVariable("id") Integer id,@PathVariable("name") String name){
System.out.println("findUser");
System.out.println(id);
System.out.println(name);
return "findUser";
}
}
RestFul风格的接口一些比较复杂的参数会转换成Json通过请求体传递过来。这种时候我们可以使用**@RequestBody**注解获取请求体中的数据。
SpringBoot的web启动器已经默认导入了jackson的依赖,不需要再额外导入依赖了。
要求定义个RestFul风格的接口,该接口可以用来新建用户。请求路径要求为 /user ,请求方式要求为POST。
用户数据会转换成json通过请求体传递。
请求体数据
{"name":"三更","age":15}
1.获取参数封装成实体对象
如果我们想把Json数据获取出来封装User对象,我们可以这样定义方法:
@RestController
public class UserController {
@RequestMapping(value = "/user",method = RequestMethod.POST)
public String insertUser(@RequestBody User user){
System.out.println("insertUser");
System.out.println(user);
return "insertUser";
}
}
User实体类如下:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Integer id;
private String name;
private Integer age;
}
2.获取参数封装成Map集合
也可以把该数据获取出来封装成Map集合:
@RequestMapping(value = "/user",method = RequestMethod.POST)
public String insertUser(@RequestBody Map map){
System.out.println("insertUser");
System.out.println(map);
return "insertUser";
}
如果请求体传递过来的数据是一个User集合转换成的json,Json数据可以这样定义:
[{"name":"三更1","age":14},{"name":"三更2","age":15},{"name":"三更3","age":16}]
方法定义:
@RequestMapping(value = "/users",method = RequestMethod.POST)
public String insertUsers(@RequestBody List<User> users){
System.out.println("insertUsers");
System.out.println(users);
return "insertUser";
}
如果需要使用**@RequestBody**来获取请求体中Json并且进行转换,要求请求头 Content-Type 的值要为: application/json 。
如果接口的参数是使用QueryString的格式的话,我们也可以使用SpringMVC快速获取参数。
我们可以使用**@RequestParam**来获取QueryString格式的参数。
要求定义个接口,该接口请求路径要求为 /testRequestParam,请求方式无要求。参数为id和name和likes。使用QueryString的格式传递。
1.参数单独的获取
如果我们想把id,name,likes单独获取出来可以使用如下写法:
在方法中定义方法参数,方法参数名要和请求参数名一致,这种情况下我们可以省略**@RequestParam**注解。
@RequestMapping("/testRquestParam")
public String testRquestParam(Integer id, String name, String[] likes){
System.out.println("testRquestParam");
System.out.println(id);
System.out.println(name);
System.out.println(Arrays.toString(likes));
return "testRquestParam";
}
如果方法参数名和请求参数名不一致,我们可以加上**@RequestParam**注解例如:
@RequestMapping("/testRquestParam")
public String testRquestParam(@RequestParam("id") Integer uid,@RequestParam("name") String name, @RequestParam("likes")String[] likes){
System.out.println("testRquestParam");
System.out.println(uid);
System.out.println(name);
System.out.println(Arrays.toString(likes));
return "testRquestParam";
}
2.获取参数封装成实体对象
如果我们想把这些参数封装到一个User对象中可以使用如下写法:
@RequestMapping("/testRquestParam")
public String testRquestParam(User user){
System.out.println("testRquestParam");
System.out.println(user);
return "testRquestParam";
}
User类定义如下:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Integer id;
private String name;
private Integer age;
private String[] likes;
}
测试时请求url如下:
http://localhost:8080/testRquestParam?id=1&name=三更草堂&likes=编程&likes=录课&likes=烫头
注意:实体类中的成员变量要和请求参数名对应上。并且要提供对应的set/get方法。
代表是否必须,默认值为true也就是必须要有对应的参数。如果没有就会报错。
如果对应的参数可传可不传则可以把其设置为fasle
例如:
@RequestMapping("/testRquestParam")
public String testRquestParam(@RequestParam(value = "id",required = false) Integer uid,@RequestParam("name") String name, @RequestParam("likes")String[] likes){
System.out.println("testRquestParam");
System.out.println(uid);
System.out.println(name);
System.out.println(Arrays.toString(likes));
return "testRquestParam";
}
如果对应的参数没有,我们可以用defaultValue属性设置默认值。
例如:
@RequestMapping("/testRquestParam")
public String testRquestParam(@RequestParam(value = "id",required = false,defaultValue = "777") Integer uid,@RequestParam("name") String name, @RequestParam("likes")String[] likes){
System.out.println("testRquestParam");
System.out.println(uid);
System.out.println(name);
System.out.println(Arrays.toString(likes));
return "testRquestParam";
}
无论是RestFul风格还是我们之前web阶段接触过的异步请求,都需要把数据转换成Json放入响应体中。
我们的SpringMVC为我们提供了**@ResponseBody**来非常方便的把Json放到响应体中。
@ResponseBody可以加在哪些东西上面?类上和方法上
具体代码请参考范例。
SpringBoot项目中使用了web的start后,不需要进行额外的依赖和配置
只要把要转换的数据直接作为方法的返回值返回即可。SpringMVC会帮我们把返回值转换成json。具体代码请参考范例。
要求定义个RestFul风格的接口,该接口可以用来根据id查询用户。请求路径要求为 /response/user ,请求方式要求为GET。
而请求参数id要写在请求路径上,例如 /response/user/1 这里的1就是id。
要求获取参数id,去查询对应id的用户信息(模拟查询即可,可以选择直接new一个User对象),并且转换成json响应到响应体中。
@Controller
@RequestMapping("/response")
public class ResponseController {
@RequestMapping("/user/{id}")
@ResponseBody
public User findById(@PathVariable("id") Integer id){
User user = new User(id, "三更草堂", 15, null);
return user;
}
}
浏览器出于安全的考虑,使用 XMLHttpRequest对象发起 HTTP请求时必须遵守同源策略,否则就是跨域的HTTP请求,默认情况下是被禁止的。 同源策略要求源相同才能正常进行通信,即协议、域名、端口号都完全一致。
CORS是一个W3C标准,全称是”跨域资源共享”(Cross-origin resource sharing),允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
它通过服务器增加一个特殊的Header[Access-Control-Allow-Origin]来告诉客户端跨域的限制,如果浏览器支持CORS、并且判断Origin通过的话,就会允许XMLHttpRequest发起跨域请求。
可以在支持跨域的方法上或者是Controller上加上@CrossOrigin注解
@RestController
@RequestMapping("/user")
@CrossOrigin
public class UserController {
@Autowired
private UserServcie userServcie;
@RequestMapping("/findAll")
public ResponseResult findAll(){
//调用service查询数据 ,进行返回
List<User> users = userServcie.findAll();
return new ResponseResult(200,users);
}
}
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
// 设置允许跨域的路径
registry.addMapping("/**")
// 设置允许跨域请求的域名
.allowedOriginPatterns("*")
// 是否允许cookie
.allowCredentials(true)
// 设置允许的请求方式
.allowedMethods("GET", "POST", "DELETE", "PUT")
// 设置允许的header属性
.allowedHeaders("*")
// 跨域允许时间
.maxAge(3600);
}
}
在前后端分离的场景中,很多时候会采用token的方案进行登录校验。
登录成功时,后端会根据一些用户信息生成一个token字符串返回给前端。
前端会存储这个token。以后前端发起请求时如果有token就会把token放在请求头中发送给后端。
后端接口就可以获取请求头中的token信息进行解析,如果解析不成功说明token超时了或者不是正确的token,相当于是未登录状态。
如果解析成功,说明前端是已经登录过的。
本案例采用目前企业中运用比较多的JWT来生成token。
使用时先引入相关依赖
<dependency>
<groupId>io.jsonwebtokengroupId>
<artifactId>jjwtartifactId>
<version>0.9.0version>
dependency>
然后可以使用下面的工具类来生成和解析token
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.Date;
import java.util.UUID;
/**
* JWT工具类
*/
public class JwtUtil {
//有效期为
public static final Long JWT_TTL = 60 * 60 *1000L;// 60 * 60 *1000 一个小时
//设置秘钥明文
public static final String JWT_KEY = "sangeng";
/**
* 创建token
* @param id
* @param subject
* @param ttlMillis
* @return
*/
public static String createJWT(String id, String subject, Long ttlMillis) {
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
if(ttlMillis==null){
ttlMillis=JwtUtil.JWT_TTL;
}
long expMillis = nowMillis + ttlMillis;
Date expDate = new Date(expMillis);
SecretKey secretKey = generalKey();
JwtBuilder builder = Jwts.builder()
.setId(id) //唯一的ID
.setSubject(subject) // 主题 可以是JSON数据
.setIssuer("sg") // 签发者
.setIssuedAt(now) // 签发时间
.signWith(signatureAlgorithm, secretKey) //使用HS256对称加密算法签名, 第二个参数为秘钥
.setExpiration(expDate);// 设置过期时间
return builder.compact();
}
/**
* 生成加密后的秘钥 secretKey
* @return
*/
public static SecretKey generalKey() {
byte[] encodedKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);
SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
return key;
}
/**
* 解析
*
* @param jwt
* @return
* @throws Exception
*/
public static Claims parseJWT(String jwt) throws Exception {
SecretKey secretKey = generalKey();
return Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(jwt)
.getBody();
}
}
数据准备
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) DEFAULT NULL,
`password` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
/*Data for the table `sys_user` */
insert into `sys_user`(`id`,`username`,`password`) values (1,'root','root'),(2,'sangeng','caotang');
实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SystemUser {
private Integer id;
private String username;
private String password;
}
SystemUserController
import com.sangeng.domain.ResponseResult;
import com.sangeng.domain.SystemUser;
import com.sangeng.service.SystemUserService;
import com.sangeng.utils.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@RestController
@RequestMapping("/sys_user")
public class SystemUserController {
@Autowired
private SystemUserService userService;
@PostMapping("/login")
public ResponseResult login(@RequestBody SystemUser user) {
//校验用户名密码是否正确
SystemUser loginUser = userService.login(user);
Map<String, Object> map;
if (loginUser != null) {
//如果正确 生成token返回
map = new HashMap<>();
String token = JwtUtil.createJWT(UUID.randomUUID().toString(), String.valueOf(loginUser.getId()), null);
map.put("token", token);
} else {
//如果不正确 给出相应的提示
return new ResponseResult(300, "用户名或密码错误,请重新登录");
}
return new ResponseResult(200, "登录成功", map);
}
}
Service
public interface SystemUserService {
public SystemUser login(SystemUser user);
}
@Service
public class SystemUserServcieImpl implements SystemUserService {
@Autowired
private SystemUserMapper systemUserMapper;
@Override
public SystemUser login(SystemUser user) {
SystemUser loginUser = systemUserMapper.login(user);
return loginUser;
}
}
dao
@Mapper
@Repository
public interface UserMapper {
List<User> findAll();
}
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sangeng.mapper.SystemUserMapper">
<select id="login" resultType="com.sangeng.domain.SystemUser">
select * from sys_user where username = #{username} and password = #{password}
select>
mapper>
见资料
如果我们想在多个Handler方法执行之前或者之后都进行一些处理,甚至某些情况下需要拦截掉,不让Handler方法执行。那么可以使用SpringMVC为我们提供的拦截器。
详情见 https://space.bilibili.com/663528522 SpringMVC课程中拦截器相关章节。
public class LoginInterceptor implements HandlerInterceptor {
}
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//获取请求头中的token
String token = request.getHeader("token");
//判断token是否为空,如果为空也代表未登录 提醒重新登录(401)
if(!StringUtils.hasText(token)){
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
return false;
}
//解析token看看是否成功
try {
Claims claims = JwtUtil.parseJWT(token);
String subject = claims.getSubject();
System.out.println(subject);
} catch (Exception e) {
e.printStackTrace();
//如果解析过程中没有出现异常说明是登录状态
//如果出现了异常,说明未登录,提醒重新登录(401)
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
return false;
}
return true;
}
}
@Configuration
public class LoginConfig implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor)//添加拦截器
.addPathPatterns("/**") //配置拦截路径
.excludePathPatterns("/sys_user/login");//配置排除路径
}
}
@ControllerAdvice
public class MyControllerAdvice {
}
定义异常处理方法,使用**@ExceptionHandler**标识可以处理的异常。
@ControllerAdvice
public class MyControllerAdvice {
@ExceptionHandler(RuntimeException.class)
@ResponseBody
public ResponseResult handlerException(Exception e){
//获取异常信息,存放如ResponseResult的msg属性
String message = e.getMessage();
ResponseResult result = new ResponseResult(300,message);
//把ResponseResult作为返回值返回,要求到时候转换成json存入响应体中
return result;
}
}
我们之前在web阶段我们经常要使用到request对象,response,session对象等。我们也可以通过SpringMVC获取到这些对象。(不过在MVC中我们很少获取这些对象,因为有更简便的方式,避免了我们使用这些原生对象相对繁琐的API。)
我们只需要在方法上添加对应类型的参数即可,但是注意数据类型不要写错了,SpringMVC会把我们需要的对象传给我们的形参。
@RestController
public class TestController {
@RequestMapping("/getRequestAndResponse")
public ResponseResult getRequestAndResponse(HttpServletRequest request, HttpServletResponse response, HttpSession session){
System.out.println(request);
return new ResponseResult(200,"成功");
}
}
如果我们想实现像获取请求体中的数据那样,在Handler方法的参数上增加一个@RepuestBody注解就可以获取到对应的数据的话。
可以使用HandlerMethodArgumentResolver来实现自定义的参数解析。
①定义用来标识的注解
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface CurrentUserId {
}
②创建类实现HandlerMethodArgumentResolver接口并重写其中的方法
注意加上@Component注解注入Spring容器
public class UserIdArgumentResolver implements HandlerMethodArgumentResolver {
//判断方法参数使用能使用当前的参数解析器进行解析
@Override
public boolean supportsParameter(MethodParameter parameter) {
//如果方法参数有加上CurrentUserId注解,就能把被我们的解析器解析
return parameter.hasParameterAnnotation(CurrentUserId.class);
}
//进行参数解析的方法,可以在方法中获取对应的数据,然后把数据作为返回值返回。方法的返回值就会赋值给对应的方法参数
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
//获取请求头中的token
String token = webRequest.getHeader("token");
if(StringUtils.hasText(token)){
//解析token,获取userId
Claims claims = JwtUtil.parseJWT(token);
String userId = claims.getSubject();
//返回结果
return userId;
}
return null;
}
}
③配置参数解析器
@Configuration
public class ArgumentResolverConfig implements WebMvcConfigurer {
@Autowired
private UserIdArgumentResolver userIdArgumentResolver;
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(userIdArgumentResolver);
}
}
④测试
在需要获取UserId的方法中增加对应的方法参数然后使用@CurrentUserId进行标识即可获取到数据
@RestController
@RequestMapping("/user")
//@CrossOrigin
public class UserController {
@Autowired
private UserServcie userServcie;
@RequestMapping("/findAll")
public ResponseResult findAll(@CurrentUserId String userId) throws Exception {
System.out.println(userId);
//调用service查询数据 ,进行返回s
List<User> users = userServcie.findAll();
return new ResponseResult(200,users);
}
}
直接在需要事务控制的方法上加上对应的注解**@Transactional**
@Service
public class UserServiceImpl implements UserServcie {
@Autowired
private UserMapper userMapper;
@Override
public List<User> findAll() {
return userMapper.findAll();
}
@Override
@Transactional
public void insertUser() {
//添加2个用户到数据库
User user = new User(null,"sg666",15,"上海");
User user2 = new User(null,"sg777",16,"北京");
userMapper.insertUser(user);
System.out.println(1/0);
userMapper.insertUser(user2);
}
}
AOP详细知识学习见:https://space.bilibili.com/663528522 中的Spring教程
在SpringBoot中默认是开启AOP功能的。如果不想开启AOP功能可以使用如下配置设置为false
spring:
aop:
auto: false
①添加依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-aopartifactId>
dependency>
②自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface InvokeLog {
}
③定义切面类
@Aspect //标识这是一个切面类
@Component
public class InvokeLogAspect {
//确定切点
@Pointcut("@annotation(com.sangeng.aop.InvokeLog)")
public void pt(){
}
@Around("pt()")
public Object printInvokeLog(ProceedingJoinPoint joinPoint){
//目标方法调用前
Object proceed = null;
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
String methodName = signature.getMethod().getName();
System.out.println(methodName+"即将被调用");
try {
proceed = joinPoint.proceed();
//目标方法调用后
System.out.println(methodName+"被调用完了");
} catch (Throwable throwable) {
throwable.printStackTrace();
//目标方法出现异常了
System.out.println(methodName+"出现了异常");
}
return proceed;
}
}
④在需要正确的地方增加对应的注解
@Service
public class UserServiceImpl implements UserServcie {
@Autowired
private UserMapper userMapper;
@Override
@InvokeLog //需要被增强方法需要加上对应的注解
public List findAll() {
return userMapper.findAll();
}
}
有的时候我们需要修改AOP的代理方式。
我们可以使用以下方式修改:
在配置文件中配置spring.aop.proxy-target-class为false这为使用jdk动态代理。该配置默认值为true,代表使用cglib动态代理。
@SpringBootApplication
@EnableAspectJAutoProxy(proxyTargetClass = false)//修改代理方式
public class WebApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(WebApplication.class, args);
}
}
如果想生效还需要在配置文件中做如下配置
spring:
aop:
proxy-target-class: false #切换动态代理的方式
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-thymeleafartifactId>
dependency>
在controller中往域中存数据,并且跳转
@Controller
public class ThymeleafController {
@Autowired
private UserServcie userServcie;
@RequestMapping("/thymeleaf/users")
public String users(Model model){
//获取数据
List<User> users = userServcie.findAll();
//望域中存入数据
model.addAttribute("users",users);
model.addAttribute("msg","hello thymeleaf");
//页面跳转
return "table-standard";
}
}
在resources\templates下存放模板页面。
在html标签中加上 xmlns:th=“http://www.thymeleaf.org”
获取域中的name属性的值可以使用: ${name} 注意要在th开头的属性中使用
<html lang="en" class="no-ie" xmlns:th="http://www.thymeleaf.org">
.....
<div class="panel-heading" th:text="${msg}">Kitchen Sinkdiv>
如果需要引入静态资源,需要使用如下写法。
<link rel="stylesheet" th:href="@{/app/css/bootstrap.css}">
<link rel="stylesheet" th:href="@{/vendor/fontawesome/css/font-awesome.min.css}">
<link rel="stylesheet" th:href="@{/vendor/animo/animate+animo.css}">
<link rel="stylesheet" th:href="@{/vendor/csspinner/csspinner.min.css}">
<link rel="stylesheet" th:href="@{/app/css/app.css}">
<script th:src="@{/vendor/modernizr/modernizr.js}" type="application/javascript">script>
<script th:src="@{/vendor/fastclick/fastclick.js}" type="application/javascript">script>
遍历语法:遍历的语法 th:each=“自定义的元素变量名称 : ${集合变量名称}”
<tr th:each="user:${users}">
<td th:text="${user.id}">td>
<td th:text="${user.username}">td>
<td th:text="${user.age}">td>
<td th:text="${user.address}">td>
tr>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
spring:
redis:
host: 127.0.0.1 #redis服务器ip地址
port: 6379 #redis端口号
@Autowired
private StringRedisTemplate redisTemplate;
@Test
public void testRedis(){
redisTemplate.opsForValue().set("name","三更");
}
在实际开发环境中,我们存在开发环境的配置,部署环境的配置,测试环境的配置等等,里面的配置信息很多时,例如:端口、上下文路径、数据库配置等等,若每次切换环境时,我们都需要进行修改这些配置信息时,会比较麻烦,profile的出现就是为了解决这个问题。它可以让我们针对不同的环境进行不同的配置,然后可以通过激活、指定参数等方式快速切换环境。
我们可以用application-xxx.yml的命名方式 创建配置文件,其中xxx可以根据自己的需求来定义。
例如
我们需要一个测试环境的配置文件,则可以命名为:application-test.yml
需要一个生产环境的配置文件,可以命名为:application-prod.yml
我们可以不同环境下不同的配置放到对应的profile文件中进行配置。然后把不同环境下都相同的配置放到application.yml文件中配置。
我们可以再application.yml文件中使用spring.profiles.active属性来配置激活哪个环境。
也可以使用虚拟机参数来指定激活环境。例如 : -Dspring.profiles.active=test
也可以使用命令行参数来激活环境。例如: –spring.profiles.active =test
开启日志
debug: true #开启日志
logging:
level:
com.sangeng: debug #设置日志级别
我们在日常开发中需要对程序内部的运行情况进行监控, 比如:健康度、运行指标、日志信息、线程状况等等 。而SpringBoot的监控Actuator就可以帮我们解决这些问题。
①添加依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
②访问监控接口
http://localhost:81/actuator
③配置启用监控端点
management:
endpoints:
enabled-by-default: true #配置启用所有端点
web:
exposure:
include: "*" #web端暴露所有端点
端点名称 | 描述 |
---|---|
beans |
显示应用程序中所有Spring Bean的完整列表。 |
health |
显示应用程序运行状况信息。 |
info |
显示应用程序信息。 |
loggers |
显示和修改应用程序中日志的配置。 |
metrics |
显示当前应用程序的“指标”信息。 |
mappings |
显示所有@RequestMapping 路径列表。 |
scheduledtasks |
显示应用程序中的计划任务。 |
①创建SpringBoot Admin Server应用
要求引入spring-boot-admin-starter-server依赖
<dependency>
<groupId>de.codecentricgroupId>
<artifactId>spring-boot-admin-starter-serverartifactId>
dependency>
然后在启动类上加上@EnableAdminServer注解
②配置SpringBoot Admin client应用
在需要监控的应用中加上spring-boot-admin-starter-client依赖
<dependency>
<groupId>de.codecentricgroupId>
<artifactId>spring-boot-admin-starter-clientartifactId>
<version>2.3.1version>
dependency>
然后配置SpringBoot Admin Server的地址
spring:
boot:
admin:
client:
url: http://localhost:8888 #配置 Admin Server的地址