SpringBoot
1.基础篇
文件优先级:properties(最高)> yml > yaml(最低)
读取配置注解:@ConfigurationProperties(prefix = "spring") (只能是bean读取)
注:基础篇只需学会使用SpringBoot+Myabtis+Junit实现简单的CRUD即可
2.运维篇
2.1项目打包
打包流程:程序包打好以后,就可以直接执行了。在程序包所在路径下,执行指令。
java -jar 工程包名.jar
2.2高级配置1
-
打包时临时配置 优先级大于配置文件
java –jar springboot.jar –-server.port=80 --logging.level.root=debug java –jar springboot.jar –-server.port=80
-
idea中的临时配置 优先级小于配置文件 但是可以选择加载配置文件
-
四种配置文件
-
file :config/application.yml 【最高】
-
file :application.yml
-
classpath:config/application.yml
-
classpath:application.yml 【最低】
-
自定义加载配置文件 通过启动参数设定
//1.配置名不带扩展名 --spring.config.name=application //2.全路径名 --spring.confi.location=classpath:/application.yml //3.加载多个配置文件 --spring.confi.location=classpath:/application.yml,classpath:/application2.yml
2.3多环境配置
-
单一yml配置
spring: profiles: active: pro # 启动pro --- #使用---作为分割线 spring: config: activate: on-profile: pro server: port: 80 --- spring: config: activate: on-profile: dev server: port: 81
-
多yml配置
application-dev.yml
server: port: 81
application-pro.yml
server: port: 80
application.yml 主文件
spring: profiles: active: dev
多yml配置技巧
spring: profiles: active: dev #属文件优先执行 group: "dev": devDB,devRedis,devMVC "pro": proDB,proRedis,proMVC "test": testDB,testRedis,testMVC
-
使用maven中pom文件加载配置文件
<profiles> <profile> <id>env_dev</id> <properties> <profile.active>dev</profile.active> </properties> <activation> <activeByDefault>true</activeByDefault> <!--默认启动环境--> </activation> </profile> <profile> <id>env_pro</id> <properties> <profile.active>pro</profile.active> </properties> </profile> </profiles> 主配置文件读取maven值 spring: profiles: active: @profile.active@
注:如果在Idea下测试工程时pom.xml每次更新需要手动compile方可生效
2.4日志
-
设置日志级别
# 开启debug模式,输出调试信息,常用于检查系统运行状况 debug: true logging: # 设置日志组 group: # 自定义组名,设置当前组中所包含的包 ebank: com.example.controller level: root: warn # 为对应组设置日志级别 ebank: debug # 为对包设置日志级别 com.example.controller: debug
-
lombok自带日志注解
private static final Logger log = LoggerFactory.getLogger(BookController.class); @Slf4j
-
设置日志输出文件
logging: logback: rollingpolicy: max-file-size: 3KB file-name-pattern: server.%d{yyyy-MM-dd}.%i.log #%d标识日期,%i是一个递增变量 file: name: server.log
3.开发篇
3.1热部署
-
手动热部署
1.导入开发者工具依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency>
2.快捷键构建项目:**<ctrl>+<F9>
-
自动热部署
1.设置自动构建项目:Build project automatically
2.允许程序在运行时自动构建项目:快捷键【Ctrl】+【Alt】+【Shit】+【/】打开维护面
注:idea设置当idea工具失去焦点5秒后进行热部署。其实就是你从idea工具中切换到其他工具时进行热部署,比如改完程序需要到浏览器上去调试,这个时候idea就自动进行热部署操作
-
设置热部署控制文件配置范围或者关闭热部署
配置中默认不参与热部署的目录信息如下
/META-INF/maven /META-INF/resources /resources /static /public /templates
修改配置,增加不参与热部署文件
devtools: restart: exclude: static/**,templates/**,config/application.yml #设置文件不进行热部署 enabled: false #关闭热部署 //系统参数关闭热部署,优先级大于配置文件但小于命令行参数 @SpringBootApplication public class SSMPApplication { public static void main(String[] args) { System.setProperty("spring.devtools.restart.enabled","false"); SpringApplication.run(SSMPApplication.class); } }
-
热部署原理:
重启与重载
一个springboot项目在运行时实际上是分两个过程进行的,根据加载的东西不同,划分成base类加载器与restart类加载器。
-
base类加载器:用来加载jar包中的类,jar包中的类和配置文件由于不会发生变化,因此不管加载多少次,加载的内容不会发生变化
-
restart类加载器:用来加载开发者自己开发的类、配置文件、页面等信息,这一类文件受开发者影响
当springboot项目启动时,base类加载器执行,加载jar包中的信息后,restart类加载器执行,加载开发者制作的内容。当执行构建项目后,由于jar中的信息不会变化,因此base类加载器无需再次执行,所以仅仅运行restart类加载即可,也就是将开发者自己制作的内容重新加载就行了,这就完成了一次热部署的过程,也可以说热部署的过程实际上是重新加载restart类加载器中的信息。
3.2高级配置2
-
使用@ConfigurationProperties为第三方bean加载属性
@Bean @ConfigurationProperties(prefix = "datasource") public DruidDataSource datasource(){ DruidDataSource ds = new DruidDataSource(); return ds; } datasource: driverClassName: com.mysql.jdbc.Driver
-
使用@EnableConfigurationProperties注解标注那些bean进行了属性绑定
@SpringBootApplication @EnableConfigurationProperties(ServerConfig.class) public class Springboot13ConfigurationApplication { }
-
计量单位配置
配置文件:
servers: ip-address: 192.168.0.1 port: 2345 timeout: -1
绑定bean:
@Component @Data @ConfigurationProperties(prefix = "servers") public class ServerConfig { @DurationUnit(ChronoUnit.HOURS) private Duration timeout; @DataSizeUnit(DataUnit.MEGABYTES) private DataSize dataSize; }
Duration:表示时间间隔,可以通过@DurationUnit注解描述时间单位,例如上例中描述的单位为小时(ChronoUnit.HOURS)
DataSize:表示存储空间,可以通过@DataSizeUnit注解描述存储空间单位,例如上例中描述的单位为MB(DataUnit.MEGABYTES)
-
配置校验
1.引入校验框架
<!--1.导入JSR303规范--> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> </dependency> <!--使用hibernate框架提供的校验器做实现--> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> </dependency>
2.添加校验注解@Validated,并设置属性值范围
@Component @Data @ConfigurationProperties(prefix = "servers") //开启对当前bean的属性注入校验 @Validated public class ServerConfig { //设置具体的规则 @Max(value = 8888,message = "最大值不能超过8888") @Min(value = 202,message = "最小值不能低于202") private int port; }
3.3测试
-
添加测试临时属性
//properties属性可以为当前测试用例添加临时的属性配置 @SpringBootTest(properties = {"test.prop=testValue1"}) public class PropertiesAndArgsTest { @Value("${test.prop}") private String msg; @Test void testProperties(){ System.out.println(msg); } } //args属性可以为当前测试用例添加临时的命令行参数 @SpringBootTest(args={"--test.prop=testValue2"}) public class PropertiesAndArgsTest { @Value("${test.prop}") private String msg; @Test void testProperties(){ System.out.println(msg); } } //注:此设定应用范围仅适用于当前测试用例
-
加载专用配置
@SpringBootTest @Import({MsgConfig.class}) public class ConfigurationTest { @Autowired private String msg; @Test void testConfiguration(){ System.out.println(msg); } }
-
模拟Web环境测试
基础:必须启动web环境
能力:测试程序中具备发送web请求的能力
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) //启动web环境,采用随机端口 @AutoConfigureMockMvc //开启虚拟MVC调用 class JavaSpringbootApplicationTests { //定义发起虚拟调用的对象MockMVC @Autowired private MockMvc mvc; @Test void testWeb() throws Exception { //创建虚拟请求,当前访问/books(仅指定请求的具体路径即可) MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get("/book"); //执行对应的请求 ResultActions result = mvc.perform(builder); //状态结果匹配器 StatusResultMatchers status = MockMvcResultMatchers.status(); //预计结果状态为200 ResultMatcher resultStatus = status.isOk(); //匹配状态结果 result.andExpect(resultStatus); //响应体匹配 ContentResultMatchers content = MockMvcResultMatchers.content(); ResultMatcher resultContent = content.string("ok"); //匹配响应体结果 result.andExpect(resultContent); //响应头匹配 HeaderResultMatchers header = MockMvcResultMatchers.header(); ResultMatcher resultHeader = header.string("Content-Type", "application/json"); } }
-
数据库事务测试
在原始测试用例中添加注解@Transactional即可实现当前测试用例的事务不提交
再添加一个@RollBack的注解,设置回滚状态为true即可正常提交事务
@SpringBootTest @Transactional @Rollback(true) public class DaoTest { }
-
随机用例测试
testcase: book: id: ${random.int} id2: ${random.int(10)} type: ${random.int(5,10)} name: ${random.value} uuid: ${random.uuid} publishTime: ${random.long} #注:其中()可以是任意字符,例如[],!!均可 @Component @Data @ConfigurationProperties(prefix = "testcase.book") public class BookCase { private int id; private int id2; private int type; private String name; private String uuid; private long publishTime; }
3.4整合第三方技术
3.4.1缓存
3.4.2任务
-
Quartz
工作(Job):用于定义具体执行的工作
工作明细(JobDetail):用于描述定时工作相关的信息
触发器(Trigger):描述了工作明细与调度器的对应关系
调度器(Scheduler):用于描述触发工作的执行规则,通常使用cron表达式定义规则
1.引入依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency>
2.创建任务
@Component public class MyQuartz extends QuartzJobBean { @Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException { System.out.println("quartz task run..."); } }
3.创建配置类
@Configuration public class QuartzConfig { @Bean public JobDetail jobDetail(){ //绑定具体的定时任务 return JobBuilder.newJob(MyQuartz.class).storeDurably().build(); } @Bean public Trigger trigger(){ //定时 ScheduleBuilder schedule = CronScheduleBuilder.cronSchedule("0/5 * * * * ?"); //绑定对应的工作明细和定时表达式 return TriggerBuilder.newTrigger().forJob(jobDetail()).withSchedule(schedule).build(); } }
使用newJob()操作传入对应的工作任务类型,使用forJob()操作传入绑定的工作明细对象
-
Task
1.spring自带的定时任务,不需要引入依赖,添加@EnableScheduling注解,开启定时任务功能
@SpringBootApplication //开启定时任务功能 @EnableScheduling public class SpringbootTaskApplication { public static void main(String[] args) { SpringApplication.run(Springboot22TaskApplication.class, args); } }
2.创建定时任务
@Component public class MyBean { @Scheduled(cron = "0/1 * * * * ?") public void print(){ System.out.println(Thread.currentThread().getName()+" :spring task run..."); } }
3.添加配置
spring: task: scheduling: pool: size: 1 # 任务调度线程池大小 默认 1 thread-name-prefix: ssm_ # 调度线程名称前缀 默认 scheduling- shutdown: await-termination: false # 线程池关闭时等待所有任务完成 await-termination-period: 10s # 调度线程关闭前最大等待时间,确保最后一定关闭
3.4.3邮件
1.添加springboot整合javamail的starter
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency>
2.配置登录信息
spring: mail: host: smtp.qq.com username: ******@qq.com password: ****** #加密后的密码
password并不是邮箱账号的登录密码,是邮件供应商提供的一个加密后的密码,可以到邮件供应商的设置页面找POP3或IMAP这些关键词找到对应的获取位置
3.创建发送邮件服务
public class SendMailServiceImpl implements SendMailService { @Autowired private JavaMailSender javaMailSender; //发送人 private String from = "******@qq.com"; //接收人 private String to = "*******@163.com"; //标题 private String subject = "测试邮件"; //正文 private String context = "测试邮件正文内容"; @Override public void sendMail() { SimpleMailMessage mailMessage = new SimpleMailMessage(); mailMessage.setFrom(from); mailMessage.setTo(to); mailMessage.setSubject(subject); mailMessage.setText(context); javaMailSender.send(mailMessage); } }
4.发送复杂邮件
//发送网页正文邮件 public class SendMailServiceImpl2 implements SendMailService { @Autowired private JavaMailSender javaMailSender; //发送人 private String from = "test@qq.com"; //接收人 private String to = "test@126.com"; //标题 private String subject = "测试邮件"; //正文 private String context = "<img src='ABC.JPG'/><a href='https://www.***.cn'>点开有惊喜</a>"; public void sendMail() { try { MimeMessage message = javaMailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(message); helper.setFrom(to); helper.setTo(from); helper.setSubject(subject); helper.setText(context,true); //此处设置正文支持html解析 javaMailSender.send(message); } catch (Exception e) { e.printStackTrace(); } } } //发送带附件的邮件 public class SendMailServiceImpl2 implements SendMailService { @Autowired private JavaMailSender javaMailSender; //发送人 private String from = "test@qq.com"; //接收人 private String to = "test@126.com"; //标题 private String subject = "测试邮件"; //正文 private String context = "测试邮件正文"; public void sendMail() { try { MimeMessage message = javaMailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(message,true); //此处设置支持附件 helper.setFrom(to); helper.setTo(from); helper.setSubject(subject); helper.setText(context); //添加附件 File f1 = new File("springboot_mail-0.0.1-SNAPSHOT.jar"); File f2 = new File("resources\\logo.png"); helper.addAttachment(f1.getName(),f1); helper.addAttachment("f2.png",f2); javaMailSender.send(message); } catch (Exception e) { e.printStackTrace(); } } }
3.4.4消息
3.5监控
采用Spring Boot Admin监控平台,配置流程如下
-
引入依赖
<dependency> <groupId>de.codecentric</groupId> <artifactId>spring-boot-admin-starter-server</artifactId> <version>3.3.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
-
添加@EnableAdminServer注解开启监控服务:访问地址:localhost:8080/applications
@SpringBootApplication @EnableAdminServer public class SpringbootAdminServerApplication { public static void main(String[] args) { SpringApplication.run(Springboot25AdminServerApplication.class, args); } }
-
制作客户端程序
<dependency> <groupId>de.codecentric</groupId> <artifactId>spring-boot-admin-starter-client</artifactId> <version>2.5.4</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> 设置当前客户端将信息上传到哪个服务器上 spring: boot: admin: client: url: http://localhost:8080
-
开放端点,开启http请求
一组是endpoints开头的,对所有端点进行配置,一组是endpoint开头的,对具体端点进行配置
management: endpoint: health: #端点名称 show-details: always #显示客户信息 info: enabled: true endpoints: web: exposure: include: "*" #使用“*”可以简化配置成开放所有端点的WEB端HTTP请求权限 enabled-by-default: true #是否开启默认端点,默认值true
-
自动定义端点:通过配置bean的方式为info端点添加信息
@Component public class InfoConfig implements InfoContributor { @Override public void contribute(Info.Builder builder) { builder.withDetail("runTime",System.currentTimeMillis()); //添加单个信息 Map infoMap = new HashMap(); infoMap.put("buildTime","2006"); builder.withDetails(infoMap); //添加一组信息 } } @Component public class HealthConfig extends AbstractHealthIndicator { @Override protected void doHealthCheck(Health.Builder builder) throws Exception { boolean condition = true; if(condition) { builder.status(Status.UP); //设置运行状态为启动状态 builder.withDetail("runTime", System.currentTimeMillis()); Map infoMap = new HashMap(); infoMap.put("buildTime", "2006"); builder.withDetails(infoMap); }else{ builder.status(Status.OUT_OF_SERVICE); //设置运行状态为不在服务状态 builder.withDetail("上线了吗?","你做梦"); } } } //自定义性能指标 @Service public class BookServiceImpl extends ServiceImpl<BookDao, Book> implements IBookService { @Autowired private BookDao bookDao; private Counter counter; public BookServiceImpl(MeterRegistry meterRegistry){ counter = meterRegistry.counter("用户付费操作次数:"); } @Override public boolean delete(Integer id) { //每次执行删除业务等同于执行了付费业务 counter.increment(); return bookDao.deleteById(id) > 0; } } //自定义端点 @Component @Endpoint(id="pay",enableByDefault = true) public class PayEndpoint { @ReadOperation public Object getPay(){ Map payMap = new HashMap(); payMap.put("level 1","300"); payMap.put("level 2","291"); payMap.put("level 3","666"); return payMap; } } 注:此端点数据spirng boot admin无法预知该如何展示,所以通过界面无法看到此数据,通过HTTP请求路径可以获取到当前端点的信息,但是需要先开启当前端点对外功能,或者设置当前端点为默认开发的端点