67,566
社区成员
1.配置maven文件中的conf下的setting.xml文件
修改setting.xml文件中的镜像
<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>
+++
1.pom.xml文件中添加
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
2.在com.test.boot包下创建MainApplication主程序
package com.test.boot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/*
* 主程序类
* */
@SpringBootApplication //这是springboot应用注解
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
}
3.在com.test.boot.controller包下创建HelloController类
package com.test.boot.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
//@ResponseBody
//@Controller
@RestController
public class HelloController {
@RequestMapping("/hello")
public String handle01() {
return "Hello,Spring Boot 2!!!";
}
}
4.在MainApplication测试
5.创建application.properties配置文件,可以在该文件下面修改配置(比如修改端口号,连接数据库等操作)
server.port=8888
6.简化部署,将项目打包成jar包,直接通过cmd方式运行即可
注意点:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
+++
依赖管理
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
</parent>
他的父项目
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.3.4.RELEASE</version>
</parent>
几乎声明了所有开发中常用的依赖的版本号,自动版本仲裁机制
1.所有场景启动器最底层的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.3.4.RELEASE</version>
<scope>compile</scope>
</dependency>
2.只要引入了starter,这个场景的所有常规依赖我们都自动引入
在pom.xml中添加
<properties>
<mysql.version>5.1.43</mysql.version>
</properties>
+++
二、自动配置
自动配置好tomcat,SpringMvc所有组件和Web中的一些字符编码问题
开启自动扫描
1.主程序MainApplication所在的包及其下面的所有子包里面的组件都会被默认扫描出来
2.不需要再另外添加扫描配置语句
+++
3.==如果类不在主程序所在的包及其子包里面就需要改变包的扫描路径==
方式一:@SpringBootApplication(scanBasePackages="com.test") 方式二:@ComponentScan 指定扫描路径
+++
@SpringBootApplication 等同于 @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan("com.test.boot")
+++
步骤:
- 在MyConfig类中添加@Configuration注解
- 给容器中添加组件,组件注释用@Bean //给容器中添加组件,方法名user01相当于id,返回类型相当于组件类型,返回值就是在组件中的实例
- 在主程序类MainApplication中进行测试
+++
@Bean的作用:
==//给容器中添加组件,方法名user01相当于id,返回类型相当于组件类型,返回值就是在组件中的实例==
配置类本身也是组件
proxyBeanMethods:
代理bean的方法
Full(proxyBeanMethods = true)
1. ==解释:==外部调用bean对象时,从容器中调用每次调用的是同一个bean对象
2. ==应用场景:==配置类组件之间==存在依赖关系时==方法会被调用到之前的单实例组件
Lite(proxyBeanMethods = false) 外部调用bean对象时
1. ==解释:==每次都要重新new一个新的bean对象
2. ==应用场景:==配置类组件之间==不存在依赖关系时==用Lite模式加速容器的启动过程减少判断
package com.test.boot.config;
import com.test.boot.bean.Pet;
import com.test.boot.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/*
* 1.配置类里面用@Bean标注在方法上面给容器注册组件,默认也是单例的
* 2.配置类本身也是组件
* 3.proxyBeanMethods:代理bean的方法
* Full(proxyBeanMethods = true) 外部调用bean对象时
* 从容器中调用每次调用的是同一个bean对象
* Lite(proxyBeanMethods = false) 外部调用bean对象时
* 每次都要重新new一个新的bean对象
*
* */
@Configuration(proxyBeanMethods = false) //配置类等同于spring的配置文件
public class MyConfig {
/**
* 无论外部对配置类中的组件注册方法调用多少次获取的都是之前注册容器中的单实例对象
*
* @return
*/
//给容器中添加组件,方法名user01相当于id,返回类型相当于组件类型,返回值就是在组件中的实例
@Bean
public User user01() {
//User组件依赖l了Pet组件
User zhangsan = new User("zhangsan", 18);
zhangsan.setPet(tomcatPet());
return zhangsan;
}
@Bean("tom")
public Pet tomcatPet() {
return new Pet("tomcat");
}
}
// 3.从容器中获取组件
Pet tom01 = run.getBean("tom", Pet.class);
Pet tom02 = run.getBean("tom", Pet.class);
System.out.println("组件:" + (tom01 == tom02));
MyConfig bean = run.getBean(MyConfig.class);
System.out.println(bean);
User user = bean.user01();
User user1 = bean.user01();
System.out.println(user == user1);
User user01 = run.getBean("user01", User.class);
Pet tom = run.getBean("tom", Pet.class);
System.out.println("用户的宠物:" + (user01.getPet() == tom));
+++
@Import({User.class, DBHelper.class})给容器中自动创建出这两个类型的组件
默认组件的名字就是全类名
@Import({User.class, DBHelper.class})
@Configuration(proxyBeanMethods = true) //配置类等同于spring的配置文件
public class MyConfig {
...
}
p9看完
如果容器中有tom这个组件再执行user01这个方法,没有就不执行
@ConditionalOnBean(name = "tom")
@Bean
public User user01() {
//User组件依赖l了Pet组件
User zhangsan = new User("zhangsan", 18);
zhangsan.setPet(tomcatPet());
return zhangsan;
}
如果容器中有组件tom就执行Myconfig类中的方法,没有就不执行
@ConditionalOnBean(name = "tom")
public class MyConfig {
...
}
如果容器没有组件tom就执行Myconfig类中的方法,否则就不执行
@ConditionalOnMissingBean(name = "tom")
public class MyConfig {
...
}
+++
导入beans.xml文件中的bean组件
1.MyConfig类代码
@ImportResource("classpath:beans.xml")
public class MyConfig {
...
}
2.beans.xml文件代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="haha" class="com.test.boot.bean.User">
<property name="name" value="zhangsan"></property>
<property name="age" value="18"></property>
</bean>
<bean id="hehe" class="com.test.boot.bean.Pet">
<property name="name" value="tomcat"></property>
</bean>
</beans>
3.MainApplication类代码
package com.test.boot;
import ch.qos.logback.core.db.DBHelper;
import com.test.boot.bean.Pet;
import com.test.boot.bean.User;
import com.test.boot.config.MyConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
/*
* 主程序类
* */
@SpringBootApplication //这是springboot应用注解
public class MainApplication {
public static void main(String[] args) {
// 1.返回IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
System.out.println("===========");
boolean haha = run.containsBean("haha");
boolean hehe = run.containsBean("hehe");
System.out.println(haha);
System.out.println(hehe);
}
}
1.在MyConfig类中添加注解@EnableConfigurationProperties(Car.class)
@EnableConfigurationProperties==作用:==
* 1、开启Car配置绑定功能 * 2、把Car这个组件自动注册到容器中
2.在Car类中添加注解@ConfigurationProperties(prefix = "mycar")
MyConfig类
@EnableConfigurationProperties(Car.class)
public class MyConfig {
...
}
Car类
package com.test.boot.bean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @Author:xuxuduoduomei
* @Date:2021/10/4 15:02
*/
//@Component
@ConfigurationProperties(prefix = "mycar")
public class Car {
private String brand;
private Integer price;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
@Override
public String toString() {
return "Car{" +
"brand='" + brand + '\'' +
", price=" + price +
'}';
}
}
package com.test.boot.bean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @Author:xuxuduoduomei
* @Date:2021/10/4 15:02
*/
@Component
@ConfigurationProperties(prefix = "mycar")
public class Car {
private String brand;
private Integer price;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
@Override
public String toString() {
return "Car{" +
"brand='" + brand + '\'' +
", price=" + price +
'}';
}
}
指定扫描哪些注解
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}
作用:相当于toString方法
二、@Data
作用:相当于getter和setter方法
三、@AllArgsConstructor和@NoArgsConstructor
作用:相当于有参构造函数和无参构造函数
作用:重写equals方法和hashCode方法
五、@Slf4j
作用:打印日志,放在控制层controller上面
作用:项目或者页面修改以后(ctrl+F9)重新启动
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
同之前的用法
YAML 是 "YAML Ain't Markup Language"(YAML 不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:"Yet Another Markup Language"(仍是一种标记语言)。
非常适合用来做以数据为中心的配置文件
String userName:
userName: "zhangsan \n 李四"
Boolean boos:
boos: true
Date birth:
birth: 2021/10/4
Integer age:
age: 18
String[] interests:
第一种:
#interests: [篮球,足球]
第二种:
interests:
- 篮球
- 足球
- 18
List animal :
animal: [阿猫,阿狗]
Map<String, Object> score:
score: {english: 80,math: 90}
Set salarys:
salarys:
- 9999.98
- 9999.99
Map<String, List> allPets:
allPets:
sick:
- {name: 阿狗,weight: 99.99}
- name: 阿猫
weight: 88.88
- name: 阿虫
weight: 77.77
health:
- {name: 阿花,weight: 199.99}
- {name: 阿明,weight: 199.99}
Pet pet:
pet:
name: 阿狗
weight: 99.99
person:
userName: "zhangsan \n 李四"
# 单引号会将\n作为字符串输出(单引号会转义)
# 双引号会将\n作为换行输出(双引号不会转义)
boos: true
birth: 2021/10/4
age: 18
#interests: [篮球,足球]
interests:
- 篮球
- 足球
- 18
animal: [阿猫,阿狗]
# score:
# english: 80
# math: 90
score: {english: 80,math: 90}
salarys:
- 9999.98
- 9999.99
pet:
name: 阿狗
weight: 99.99
allPets:
sick:
- {name: 阿狗,weight: 99.99}
- name: 阿猫
weight: 88.88
- name: 阿虫
weight: 77.77
health:
- {name: 阿花,weight: 199.99}
- {name: 阿明,weight: 199.99}
#spring:
# banner:
# location:
静态资源放在类路径下:/static or /public or /resources or /META-INF/resources
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zexXWlLs-1635088496335)(C:\Users\R490\AppData\Roaming\Typora\typora-user-images\image-20211005164428681.png)]
访问:当前路径名/+静态资源名 eg:http://localhost:8080/res/timg.jpg
==请求进来时先去找Controller控制层看能不能处理,不能处理就将请求交给静态资源处理器,如果静态资源处理器也找不到请求就响应404页面==
1.2改变默认的静态资源路径
spring:
mvc:
static-path-pattern: /res/**
web:
resources:
static-locations: classpath:/haha
第一种:http://localhost:8080/res/timg.jpg
第二种:在资源包resources下面新建haha包,将timg.jpg图片存入进去,则只能访问哈哈包下面的静态资源
1.静态资源路径下 index.html
spring:
# mvc:
# static-path-pattern: /res/**
web:
resources:
static-locations: classpath:/haha
spring:
# mvc:
# static-path-pattern: /res/** 这个会导致favicon小图标失效
解释:
获取路径当中变量的值
eg:
<a href="car/3/owner/lisi">car/{id}/owner/{username}</a>
解释:
获取请求头的信息
解释:
获取请求路径中设置的参数的值
<a href="car/3/owner/lisi?age=18&inters=basketball&inters=game">car/{id}/owner/{username}</a>
解释:
获取Cookie信息
解释:
获取请求体(比如:表单中的信息)
<form action="/save" method="post"> 测试@RequestBody获取数据 <br/> 用户名:<input name="userName"/> <br> 邮箱:<input name="email"/> <input type="submit" value="提交"/> </form>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>大厂欢迎您!!!</h1>
<ul>
<a href="car/3/owner/lisi?age=18&inters=basketball&inters=game">car/{id}/owner/{username}</a>
</ul>
<form action="/save" method="post">
测试@RequestBody获取数据 <br/>
用户名:<input name="userName"/> <br>
邮箱:<input name="email"/>
<input type="submit" value="提交"/>
</form>
</body>
</html>
package com.atguigu.boot.controller;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.Cookie;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Author:xuxuduoduomei
* @Date:2021/10/5 21:45
*/
@RestController
public class ParameterTestController {
@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("_ga") String _ga,
@CookieValue("_ga") Cookie cookie) {
HashMap<String, Object> map = new HashMap<>();
// map.put("id", id);
// map.put("name", name);
// map.put("pv", pv);
// map.put("headers", header);
map.put("age", age);
map.put("inters", inters);
map.put("params", params);
map.put("_ga", _ga);
System.out.println(cookie.getName() + "===>" + cookie.getValue());
return map;
}
@PostMapping("/save")
public Map postMethod(@RequestBody String content) {
HashMap<String, Object> map = new HashMap<>();
map.put("content", content);
return map;
}
}
解释:
获取请求request中的值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>大厂欢迎您!!!</h1>
<ul>
<a href="car/3/owner/lisi?age=18&inters=basketball&inters=game">car/{id}/owner/{username}</a>
<a href="/car/sell;low=18;brand=benci,baoma,aodi">@MatrixVariable(矩阵变量)</a>
<a href="/car/sell;low=18;brand=benci;brand=baoma;brand=aodi">@MatrixVariable(矩阵变量)</a>
</ul>
<form action="/save" method="post">
测试@RequestBody获取数据 <br/>
用户名:<input name="userName"/> <br>
邮箱:<input name="email"/>
<input type="submit" value="提交"/>
</form>
</body>
</html>
package com.atguigu.boot.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
/**
* @Author:xuxuduoduomei
* @Date:2021/10/6 15:26
*/
@Controller
public class RequestController {
@GetMapping("/goto")
public String goToPage(HttpServletRequest request) {
request.setAttribute("msg", "成功了.....");
request.setAttribute("code", 200);
return "forward:/success";
}
@ResponseBody
@GetMapping("/success")
public Map success(@RequestAttribute("msg") String msg,
@RequestAttribute("code") Integer code,
HttpServletRequest request) {
Object msg1 = request.getAttribute("msg");
Map<String, Object> map = new HashMap<>();
map.put("reqMethod_msg", msg1);
map.put("annotation_msg", msg);
map.put("annotation_code", code);
return map;
}
}
解释:
获取矩阵变量格式中的值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>大厂欢迎您!!!</h1>
<ul>
<a href="car/3/owner/lisi?age=18&inters=basketball&inters=game">car/{id}/owner/{username}</a>
<a href="/car/sell;low=18;brand=benci,baoma,aodi">@MatrixVariable(矩阵变量)</a>
<a href="/car/sell;low=18;brand=benci;brand=baoma;brand=aodi">@MatrixVariable(矩阵变量)</a>
<a href="/boss/1;age=20/2;age=10">@MatrixVariable(矩阵变量)</a>
</ul>
<form action="/save" method="post">
测试@RequestBody获取数据 <br/>
用户名:<input name="userName"/> <br>
邮箱:<input name="email"/>
<input type="submit" value="提交"/>
</form>
</body>
</html>
package com.atguigu.boot.controller;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.Cookie;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Author:xuxuduoduomei
* @Date:2021/10/5 21:45
*/
@RestController
public class ParameterTestController {
@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("_ga") String _ga,
// @CookieValue("_ga") Cookie cookie) {
{
HashMap<String, Object> map = new HashMap<>();
map.put("id", id);
map.put("name", name);
map.put("pv", pv);
map.put("headers", header);
map.put("age", age);
map.put("inters", inters);
map.put("params", params);
// map.put("_ga", _ga);
// System.out.println(cookie.getName() + "===>" + cookie.getValue());
return map;
}
@PostMapping("/save")
public Map postMethod(@RequestBody String content) {
HashMap<String, Object> map = new HashMap<>();
map.put("content", content);
return map;
}
// /car/sell;low=18;brand=benci;brand=baoma;brand=aodi
@ResponseBody
@GetMapping("/car/{path}")
public Map carsSell(@MatrixVariable("low") Integer low,
@MatrixVariable("brand") List<String> brand,
@PathVariable("path") String path) {
Map<String, Object> map = new HashMap<>();
map.put("low", low);
map.put("brand", brand);
map.put("path", path);
return map;
}
// /boss/1;age=20/2;age=10
@GetMapping("/boss/{bossId}/{empId}")
public Map boss(@MatrixVariable(value = "age", pathVar = "bossId") Integer bossAge,
@MatrixVariable(value = "age", pathVar = "empId") Integer empAge) {
Map<String, Object> map = new HashMap<>();
map.put("bossAge", bossAge);
map.put("empAge", empAge);
return map;
}
}
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
1、所有thymeleaf的配置值都在 ThymeleafProperties
2、配置好了 SpringTemplateEngine
3、配好了 ThymeleafViewResolver
4、我们只需要直接开发页面(Thymeleaf自动配置好了,并且设置好了前缀和后缀)
//将页面发在templates包下面,
public static final String DEFAULT_PREFIX = "classpath:/templates/";
//返回的页面有了后缀
public static final String DEFAULT_SUFFIX = ".html"; //xxx.html
1.使用Thymeleaf可以修改原先静态页面中的内容,但是要注意Thymeleaf的使用语法规则
ViewController.java
package com.atguigu.boot.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
/**
* @Author:xuxuduoduomei
* @Date:2021/10/8 20:44
*/
@Controller
public class ViewController {
@GetMapping("/baidu")
public String baidu(Model model) {
model.addAttribute("msg", "你好大厂我的梦想!!!");
model.addAttribute("link", "https://www.bytedance.com/");
return "success";
}
}
success.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1 th:text="${msg}">哈哈</h1>
<h2>
<a href="www.baidu.com" th:href="${link}">去字节跳动</a>
<a href="www.baidu.com" th:href="@{link}">去字节跳动</a>
</h2>
</body>
</html>
使用模板创建
1.将静态资源放在resources下面的static包下面
1.创建controler包,创建IndexController类
2.在IndexController类写login页面跳转
@GetMapping(value = {"/", "/login"})
public String loginPage() {
return "login";
}
3.创建bean包,创建User类
package com.atguigu.admin.bean;
import lombok.Data;
/**
* @Author:xuxuduoduomei
* @Date:2021/10/10 20:06
*/
@Data
public class User {
private String userName;
private String password;
}
4.修改login.html,将路径映射到/login下,并且添加name="userName"和name="password"属性
<form class="form-signin" action="main.html" th:action="@{/login}" method="post">
<input type="text" name="userName" class="form-control" placeholder="User ID" autofocus>
<input type="password" name="password" class="form-control" placeholder="Password">
5.修改IndexController类
重定向路径到/main.html
重定向的作用是防止表单重复提交
并且添加逻辑将登陆成功的用户信息保存到session中,否则就跳转到登录页面login.html中
//重定向防止表单重复提交
@PostMapping("/login")
public String main(User user, HttpSession session, Model model) {
if (!StringUtils.isEmpty(user.getUserName()) && "123456".equals(user.getPassword())) {
//把登录成功的用户保存起来
session.setAttribute("loginUser", user);
//登录成功就重定向到main.html页面
//重定向的作用是防止表单重复提交
return "redirect:/main.html";
} else {
model.addAttribute("msg", "账号密码错误");
//回到登陆页面
return "login";
}
}
6.重定向后的页面
设置逻辑如果登录成功就跳转到mian.html页面中否则就返回到login.html页面中
@GetMapping("/main.html")
public String mainPage(HttpSession session, Model model) {
//是否登录 拦截器,过滤器
Object loginUser = session.getAttribute("loginUser");
if (loginUser != null) {
return "main";
} else {
//回到登陆页面
model.addAttribute("msg", "请重新登录");
return "login";
}
}
IndexController类
package com.atguigu.admin.controller;
import com.atguigu.admin.bean.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.thymeleaf.util.StringUtils;
import javax.jws.WebParam;
import javax.servlet.http.HttpSession;
/**
* @Author:xuxuduoduomei
* @Date:2021/10/10 19:45
*/
@Controller
public class IndexController {
@GetMapping(value = {"/", "/login"})
public String loginPage() {
return "login";
}
//重定向防止表单重复提交
@PostMapping("/login")
public String main(User user, HttpSession session, Model model) {
if (!StringUtils.isEmpty(user.getUserName()) && "123456".equals(user.getPassword())) {
//把登录成功的用户保存起来
session.setAttribute("loginUser", user);
//登录成功就重定向到main.html页面
//重定向的作用是防止表单重复提交
return "redirect:/main.html";
} else {
model.addAttribute("msg", "账号密码错误");
//回到登陆页面
return "login";
}
}
@GetMapping("/main.html")
public String mainPage(HttpSession session, Model model) {
//是否登录 拦截器,过滤器
Object loginUser = session.getAttribute("loginUser");
if (loginUser != null) {
return "main";
} else {
//回到登陆页面
model.addAttribute("msg", "请重新登录");
return "login";
}
}
}
1、编写一个拦截器实现HandlerInterceptor接口
2、拦截器注册到容器中(实现WebMvcConfigurer的addInterceptors)
3、指定拦截规则【如果是拦截所有,静态资源也会被拦截】
1.创建LoginInterceptor类实现HandlerInterceptor接口
package com.atguigu.admin.interceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* @Author:xuxuduoduomei
* @Date:2021/10/14 17:36
*/
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String requestURI = request.getRequestURI();
log.info("拦截的请求路径是{}", requestURI);
HttpSession session = request.getSession();
Object loginUser = session.getAttribute("loginUser");
if (loginUser != null) {
return true;
}
request.setAttribute("msg", "请先登录");
request.getRequestDispatcher("/").forward(request, response);
return false;
}
}
2.创建AdminWebConfig类实现WebMvcConfigurer接口
package com.atguigu.admin.config;
import com.atguigu.admin.interceptor.LoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @Author:xuxuduoduomei
* @Date:2021/10/14 17:40
*/
@Configuration
public class AdminWebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor()) // 将拦截器注册到容器中
.addPathPatterns("/**") // 添加拦截的路径
.excludePathPatterns("/", "/login", "/css/**", "/fonts/**",
"/images/**", "/js/**"); // 添加放行的路径
}
}
1.multiple多文件上传
<input type="file" name="photos" multiple>
2.在application.properties中修改文件上传的大小
spring.servlet.multipart.max-file-size=10MB spring.servlet.multipart.max-request-size=100MB
3.参数
//MultipartFile自动封装上传过来的文件 //@RequestPart获取上传的文件注解 @RequestPart("headerImg") MultipartFile headerImg, @RequestPart("photos") MultipartFile[] photos)
4.页面表单上传文件
<form method="post" action="/upload" enctype="multipart/form-data"> <input type="file" name="file"><br> <input type="submit" value="提交"> </form>
1.创建FormTestController.java
package com.atguigu.admin.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
/**
* @Author:xuxuduoduomei
* @Date:2021/10/16 15:22
*/
@Slf4j
public class FormTestController {
@GetMapping("/form_layouts")
public String form_layouts() {
return "form/form_layouts";
}
@PostMapping("/upload")
public String upload(@RequestParam("email") String email,
@RequestParam("username") String username,
//MultipartFile自动封装上传过来的文件
//RequestPart获取上传的文件注解
@RequestPart("headerImg") MultipartFile headerImg,
@RequestPart("photos") MultipartFile[] photos) throws IOException {
log.info("上传的信息:email={},username={},headerImg={},photos={}",
email, username, headerImg.getSize(), photos.length);
if (!headerImg.isEmpty()) {
//保存到文件服务器
String originalFilename = headerImg.getOriginalFilename();//获取到文件源文件名
headerImg.transferTo(new File("..." + originalFilename));//将文件保存到指定的路径
}
if (photos.length > 0) {
for (MultipartFile photo : photos) {
if (!photo.isEmpty()) {
String originalFilename = photo.getOriginalFilename();//获取到文件源文件名
photo.transferTo(new File("..." + originalFilename));//将文件保存到指定的路径
}
}
}
return "main";
}
}
1.在Boot06WebAdminApplication.java中配置扫描Servlet的注解
@ServletComponentScan(basePackages = "com.atguigu.admin")
2.在MyServlet.java中配置Servlet组件
@WebServlet(urlPatterns = "/my") public class MyServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().write("66666"); } }
1.在MyFilter.java类中配置Filter组件
@WebFilter(urlPatterns = {"/css/*", "/images/*"}) @Slf4j public class MyFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { log.info("MyFilter初始化完成"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { log.info("MyFilter工作"); filterChain.doFilter(servletRequest, servletResponse); } @Override public void destroy() { log.info("MyFilter销毁"); } }
1.在MyServletContextListener中配置Listener组件
@WebListener @Slf4j public class MyServletContextListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { log.info("MyServletContextListener监听到项目初始化完成"); } @Override public void contextDestroyed(ServletContextEvent sce) { log.info("MyServletContextListener监听到项目项目销毁 "); } }
1.在MyRegistConfig.java中配置ServletRegistrationBean、FilterRegistrationBean、ServletListenerRegistrationBean组件并注入到容器中
@Configuration
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();
// 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.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
2.导入数据库驱动
<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/jdbctest?characterEncoding=UTF-8&serverTimezone=UTC
username: root
password: 12345678
driver-class-name: com.mysql.cj.jdbc.Driver
# jdbc:
# template:
# query-timeout: 0
4.测试JdbcTemplate
@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);
}
}
<!-- https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
spring:
datasource:
url: jdbc:mysql://localhost:3306/jdbctest?characterEncoding=UTF-8&serverTimezone=UTC
username: root
password: 12345678
driver-class-name: com.mysql.cj.jdbc.Driver
druid:
aop-patterns: com.atguigu.admin.* #监控SpringBean
filters: stat,wall # 底层开启功能,stat(sql监控),wall(防火墙)
stat-view-servlet: # 配置监控页功能
enabled: true
login-username: admin
login-password: admin
resetEnable: false
web-stat-filter: # 监控web
enabled: true
urlPattern: /*
exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*'
filter:
stat: # 对上面filters里面的stat的详细配置
slow-sql-millis: 1000
logSlowSql: true
enabled: true
wall:
enabled: true
config:
drop-table-allow: false
# jdbc:
# template:
# query-timeout: 0
导入mybatis官方starter
编写mapper接口。标准@Mapper注解
编写sql映射文件并绑定mapper接口
在application.yaml中指定Mapper配置文件的位置,以及指定全局配置文件的信息 (建议;配置在mybatis.configuration)
<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
#配置mybatis规则
mybatis:
# config-location: classpath:mybatis/mybatis-config.xml
mapper-locations: classpath:mybatis/mapper/*.xml
configuration: // 指定ybatis中相关的全局配置项
map-underscore-to-camel-case: true
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.admin.mapper.AccountMapper">
<!-- public Account getAcct(Long id); -->
<select id="getAcct" resultType="com.atguigu.admin.bean.Account">
select * from account_tbl where id=#{id}
</select>
</mapper>
package com.atguigu.admin.mapper;
import com.atguigu.admin.bean.Account;
import org.apache.ibatis.annotations.Mapper;
/**
* @Author:xuxuduoduomei
* @Date:2021/10/17 17:29
*/
@Mapper
public interface AccountMapper {
public Account getAcct(Long id);
}
package com.atguigu.admin.service;
import com.atguigu.admin.bean.Account;
import com.atguigu.admin.mapper.AccountMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @Author:xuxuduoduomei
* @Date:2021/10/17 17:40
*/
@Service
public class AccountService {
@Autowired
AccountMapper accountMapper;
public Account getAcctById(Long id) {
return accountMapper.getAcct(id);
}
}
@Autowired
AccountService accountService;
@ResponseBody
@GetMapping("/acct")
public Account getById(@RequestParam("id") Long id) {
return accountService.getAcctById(id);
}
p63看完
1.相比于配置模式,不用单独去写CityMapper.xml文件
只用修改CityMapper.java接口即可
package com.atguigu.admin.mapper;
import com.atguigu.admin.bean.City;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Options;
import org.apache.ibatis.annotations.Select;
/**
* @Author:xuxuduoduomei
* @Date:2021/10/21 16:04
*/
@Mapper
public interface CityMapper {
@Select("select * from city where id=#{id}")
public City getById(Long id);
@Insert("insert into city('name','state','country') values(#{name},#{state},#{country})")
@Options(useGeneratedKeys = true, keyProperty = "id")
public void insert(City city);
}
三、混合模式
1.混合模式就是结合配置模式与注解模式,两种方式同时使用。
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
1.==只需要我们的Mapper类继承了 BaseMapper 就可以拥有CRUD能力,无需再重写CRUD代码==
2.TableController类
@GetMapping("/user/delete/{id}")
public String deleteUser(@PathVariable("id") Long id,
@RequestParam(value = "pn",defaultValue = "1")Integer pn,
RedirectAttributes ra){
userService.removeById(id);
ra.addAttribute("pn",pn);
return "redirect:/dynamic_table";
}
@GetMapping("/dynamic_table")
public String dynamic_table(@RequestParam(value="pn",defaultValue = "1") Integer pn,Model model){
//构造分页参数
Page<User> page = new Page<>(pn, 2);
//调用page进行分页
Page<User> userPage = userService.page(page, null);
// userPage.getRecords()
// userPage.getCurrent()
// userPage.getPages()
model.addAttribute("users",userPage);
return "table/dynamic_table";
}
**@Test :**表示方法是测试方法。但是与JUnit4的@Test不同,他的职责非常单一不能声明任何属性,拓展的测试将会由Jupiter提供额外测试
**@ParameterizedTest :**表示方法是参数化测试,下方会有详细介绍
**@RepeatedTest :**表示方法可重复执行,下方会有详细介绍
**@DisplayName :**为测试类或者测试方法设置展示名称
**@BeforeEach :**表示在每个单元测试之前执行
**@AfterEach :**表示在每个单元测试之后执行
**@BeforeAll :**表示在所有单元测试之前执行
**@AfterAll :**表示在所有单元测试之后执行
**@Tag :**表示单元测试类别,类似于JUnit4中的@Categories
**@Timeout :**表示测试方法运行如果超过了指定时间将会返回错误
**@ExtendWith :**为测试类或测试方法提供扩展类引用
1.断言是测试方法中的核心部分,用来对测试需要满足的条件进行验证
2.断言用于检查业务逻辑返回的数据是否合理
3.所有的测试运行结束后,会有一个详细的报告
方法 | 说明 |
---|---|
assertEquals | 判断两个对象或两个原始类型是否相等 |
assertNotEquals | 判断两个对象或两个原始类型是否不相等 |
assertSame | 判断两个对象引用是否指向同一个对象 |
assertNotSame | 判断两个对象引用是否指向不同的对象 |
assertTrue | 判断给定的布尔值是否为 true |
assertFalse | 判断给定的布尔值是否为 false |
assertNull | 判断给定的对象引用是否为 null |
assertNotNull | 判断给定的对象引用是否不为 null |
@DisplayName("测试简单断言")
@Test
void testAssertions() {
int cal = cal(2, 3);
assertEquals(5, cal);
}
int cal(int i, int j) {
return i + j;
}
==通过 assertArrayEquals 方法来判断两个对象或原始类型的数组是否相等==
@Test
@DisplayName("array assertion")
public void array() {
assertArrayEquals(new int[]{1, 2}, new int[] {1, 2});
}
assertAll 方法接受多个 org.junit.jupiter.api.Executable 函数式接口的实例作为要验证的断言,可以通过 lambda 表达式很容易的提供这些断言
@Test
@DisplayName("assert all")
public void all() {
assertAll("Math",
() -> assertEquals(2, 1 + 1),
() -> assertTrue(1 > 0)
);
}
JUnit5提供了一种新的断言方式Assertions.assertThrows() ,配合函数式编程就可以进行使用
@Test
@DisplayName("异常测试")
public void exceptionTest() {
ArithmeticException exception = Assertions.assertThrows(
//扔出断言异常
ArithmeticException.class, () -> System.out.println(1 % 0));
}
Junit5还提供了Assertions.assertTimeout() 为测试方法设置了超时时间
@Test
@DisplayName("超时测试")
public void timeoutTest() {
//如果测试方法时间超过1s将会异常
Assertions.assertTimeout(Duration.ofMillis(1000), () -> Thread.sleep(500));
}
通过 fail 方法直接使得测试失败
@Test
@DisplayName("fail")
public void shouldFail() {
fail("This should fail");
}
JUnit 5 中的前置条件(assumptions【假设】)类似于断言,不同之处在于不满足的断言会使得测试方法失败,而不满足的前置条件只会使得测试方法的执行终止
@Test
@DisplayName("前置条件测试")
public void simpleAssume() {
assumeTrue(false,"假设失败方法不可以执行");
}
JUnit 5 可以通过 Java 中的内部类和@Nested 注解实现嵌套测试,从而可以更好的把相关的测试方法组织在一起。在内部类中可以使用@BeforeEach 和@AfterEach 注解,而且嵌套的层次没有限制。
@DisplayName("A stack")
class TestingAStackDemo {
Stack<Object> stack;
@Test
@DisplayName("is instantiated with new Stack()")
void isInstantiatedWithNew() {
new 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());
}
}
}
}
参数化测试是JUnit5很重要的一个新特性,它使得用不同的参数多次运行测试成为了可能,也为我们的单元测试带来许多便利。
@ValueSource: 为参数化测试指定入参来源,支持八大基础类以及String类型,Class类型
@NullSource: 表示为参数化测试提供一个null的入参
@EnumSource: 表示为参数化测试提供一个枚举入参
@CsvFileSource:表示读取指定CSV文件内容作为参数化测试入参
@MethodSource:表示读取指定方法的返回值作为参数化测试入参(注意方法返回需要是一个流)
@ParameterizedTest
@ValueSource(strings = {"one", "two", "three"})
@DisplayName("参数化测试1")
public void parameterizedTest1(String string) {
System.out.println(string);
Assertions.assertTrue(StringUtils.isNotBlank(string));
}
@ParameterizedTest
@MethodSource("method") //指定方法名
@DisplayName("方法来源参数")
public void testWithExplicitLocalMethodSource(String name) {
System.out.println(name);
Assertions.assertNotNull(name);
}
static Stream<String> method() {
return Stream.of("apple", "banana");
}
未来每一个微服务在云上部署以后,我们都需要对其进行监控、追踪、审计、控制等。SpringBoot就抽取了Actuator场景,使得我们每个微服务快速引用即可获得生产级别的应用监控、审计等功能。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
#management是所有actuator的配置
management:
endpoints:
enabled-by-default: true #默认开启全部监控端点
web:
exposure:
include: '*' #以web方式暴露
最常用的Endpoint
Health:监控状况
Metrics:运行时指标
Loggers:日志记录
#开启指定的监控(自定义)
endpoint:
health:
show-details: always #总是显示详细信息。可显示每个模块的状态信息
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HNOK5Y3h-1635088496342)(C:\Users\R490\AppData\Roaming\Typora\typora-user-images\image-20211023101406854.png)]
配置模式:
endpointName为要开启的变量名
management.endpoint.endpointName.enabled = true
eg:
management: endpoint: beans: enabled: true
management:
endpoints:
enabled-by-default: false
endpoint:
beans:
enabled: true
health:
enabled: true
为了方便多环境适配,springboot简化了profile功能。
1.配置默认的文件application.properties,任何时候都会加载
2.配置指定的文件 application-{env}.yaml
3.指定环境配置文件激活:
spring.profiles.active=prod #指定激活的环境
==注意:==
- 默认配置与环境配置同时生效,但是如果默认的与指定的有相同的属性则默认的会被指定的覆盖掉
- 同名配置项,profile配置优先
在指定的类上面添加@Profile("prod"),prod为激活的环境,其它的类就不会被加载
package com.atguigu.boot.bean;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
/**
* @Author:xuxuduoduomei
* @Date:2021/10/23 12:51
*/
@Component
@ConfigurationProperties("person")
@Data
@Profile("prod")
public class Person {
private String name;
private Integer age;
}
数")
public void testWithExplicitLocalMethodSource(String name) {
System.out.println(name);
Assertions.assertNotNull(name);
}
static Stream method() {
return Stream.of("apple", "banana");
}
## 二十一、指标监控
### 一、SpringBoot Actuator
#### 1.简介
未来每一个微服务在云上部署以后,我们都需要对其进行监控、追踪、审计、控制等。SpringBoot就抽取了Actuator场景,使得我们每个微服务快速引用即可获得生产级别的应用监控、审计等功能。
#### 2.在pom.xml文件中配置
~~~xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
#management是所有actuator的配置
management:
endpoints:
enabled-by-default: true #默认开启全部监控端点
web:
exposure:
include: '*' #以web方式暴露
最常用的Endpoint
Health:监控状况
Metrics:运行时指标
Loggers:日志记录
#开启指定的监控(自定义)
endpoint:
health:
show-details: always #总是显示详细信息。可显示每个模块的状态信息
[外链图片转存中...(img-HNOK5Y3h-1635088496342)]
配置模式:
endpointName为要开启的变量名
management.endpoint.endpointName.enabled = true
eg:
management: endpoint: beans: enabled: true
management:
endpoints:
enabled-by-default: false
endpoint:
beans:
enabled: true
health:
enabled: true
为了方便多环境适配,springboot简化了profile功能。
1.配置默认的文件application.properties,任何时候都会加载
2.配置指定的文件 application-{env}.yaml
3.指定环境配置文件激活:
spring.profiles.active=prod #指定激活的环境
==注意:==
- 默认配置与环境配置同时生效,但是如果默认的与指定的有相同的属性则默认的会被指定的覆盖掉
- 同名配置项,profile配置优先
在指定的类上面添加@Profile("prod"),prod为激活的环境,其它的类就不会被加载
package com.atguigu.boot.bean;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
/**
* @Author:xuxuduoduomei
* @Date:2021/10/23 12:51
*/
@Component
@ConfigurationProperties("person")
@Data
@Profile("prod")
public class Person {
private String name;
private Integer age;
}
整理不易,请一键三连哦!!!大家一起加油冲💪💪💪