SpringBoot程序的创建以及特点,配置文件,LogBack记录日志,配置过滤器、拦截器、全局异常
一、创建一个SpringBoot程序
在之前写过一篇如何创建SpringBoot程序,两种方式,方法1:通过maven创建SpringBoot项目
方法2:使用Spring Initialzr创建一个SpringBoot项目(缺点:当创建项目时网络中断,会导致程序有部分缺失,并且在程序初始加载的时候不会报错,在后续的项目进程中可能会无法发现报错的原因)
SpringBoot--入门、创建一个SpringBoot项目、测试_springboot创建测试类-CSDN博客
二、SpringBoot的特点
①主要特点
- 为基于Spring的开发提供更快的入门体(不需要写测试类,有启动类,不用配置tomcat)
- 开箱即用,没有代码生成,也无需XML配置。同时也可以修改默认值来满足特定的需求(例如:server.port即端口号的默认值为8080,SpringBoot可以修改这个值)
- 提供了一些大型项目中常见的非功能性特性,如嵌入式服务器(Tomcat)、安全、指标,健康检测、外部配置等
- SpringBoot不是对Spring功能上的增强,而是提供了一种快速使用Spring的方式
②其他特点
- SpringBoot在项目创建时会添加一个<parent>标签,其意义是帮助开发者进行统一的项目版本管理
- SpringBoot使用starter可以帮助开发者减少依赖配置(
二者的区别:(一)starter是一个坐标中定了若干个坐标,以前写多个的,现在写一个,是用来减少依赖配置的书写量的。
(二)parent是定义了几百个依赖版本号,以前写依赖需要自己手工控制版本,现在由SpringBoot统一管理,这样就不存在版本冲突了,是用来减少依赖冲突的。
)
- 这个
spring-boot-dependencies
中定义了两组信息:第一组是各式各样的依赖版本号属性,第二组是各式各样的依赖坐标信息
③热部署
什么是热部署?
在服务器启动后改动程序不需要再重启服务器,服务器会自己悄悄把更新后的程序加载一遍
启动热部署
第一步:在pom.xml文件中导入依赖
第二步:构建项目,可以使用快捷键(Ctrl+F9)激活此功能
以上为手动开启热部署,现在介绍如何自动开启热部署
第一步:打开【File】,选择【settings...】,在面板左侧的菜单中找到【Compile】选项,然后勾选【Build project automatically】,意思是自动构建项目
第二步:允许在程序运行时进行自动构建(因为我的idea为2023版,所以介绍的是2023版的方式)
勾选:settings->Advanced Settings->编译器->编译器中的第一个选项,如下图,点击应用
关闭热部署
线上环境运行时是不可能使用热部署功能的,所以需要强制关闭此功能,通过配置可以关闭此功能。
spring:devtools:restart:enabled: false
如果担心配置文件层级过多导致相符覆盖最终引起配置失效,可以提高配置的层级,在更高层级中配置关闭热部署。例如在启动容器前通过系统属性设置关闭热部署功能。
@SpringBootApplication public class Application {public static void main(String[] args) {System.setProperty("spring.devtools.restart.enabled","false");SpringApplication.run(Application.class);} }
三、SpringBoot的配置文件
①SpringBoot三种配置文件的格式(以设置端口号为例):
properties格式
yml格式
yaml格式
application.properties(properties格式)
server.port=8080
application.yml(yml格式)
server:port: 8081
application.yaml(yaml格式)
server:port: 8082
②配置文件的优先级
测试:在三种配置文件中分别设置不同的端口号,看哪一个端口号访问时会生效,则哪一个配置文件的优先级更高
application.yaml
application.properties
application.yml
测试成功,8082端口成功显示数据,即表示application.properties文件的端口生效了
测试失败,则表示application.yaml文件的端口号无法生效
但是这就表示该配置文件的其他配置没有生效吗,事实表明生效了,在.yaml文件中配置了一个关闭运行日志图表 ,控制台则并没有打印出日志图标,所以得出结论:每个配置文件中的项都会生效,只不过如果多个配置文件中有相同类型的配置会优先级高的文件覆盖优先级的文件中的配置。如果配置项不同的话,所有的配置项都会生效。
关于其他的配置项,可以去SpringBoot官网上了解
打开查看附录中的Application Properties就可以获取到对应的配置项了,网址奉上:https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html#application-properties
③常见配置项
在编写配置文件时,我们可以选择更关键的单词,idea会提示需要的配置项
1.配置数据源
# 配置Spring Boot应用的数据库源 spring:datasource:# 数据库连接URL,包含数据库的地址、端口、数据库名以及连接参数# 参数包括:useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC# 说明:使用Unicode编码,字符编码为UTF-8,不使用SSL,服务器时区为UTCurl: jdbc:mysql://localhost:3306/myd?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC# 数据库用户名username: root# 数据库密码password: 123456# 数据库驱动类名driver-class-name: com.mysql.cj.jdbc.Driver# 数据源类型,这里使用的是阿里巴巴的Druid数据源type: com.alibaba.druid.pool.DruidDataSource
打datasource会更快出现需要的配置标签
2.关闭日志图标(banner)
spring:main:banner-mode: off
能够关闭运行日志中的此图标
3.设置运行日志的显示级别
#日志配置 logging:level:root: infocom.myd: debug
能够显示数据库语句
④读取yaml和yml文件中的数据
1.读取单一数据
yaml中保存的单个数据,可以使用Spring中的注解@Value读取单个数据,属性名引用方式:${一级属性名.二级属性名……}
2.读取全部数据
读取单一数据可以解决少量数据读取的问题,但是如果数据多的话,这样写会很麻烦,SpringBoot提供了一个对象,能够把所有的数据都封装到这一个对象中,这个对象叫做Environment,使用自动装配注解可以将所有的yaml数据封装到这个对象中
3.读取对象数据
首先定义一个对象,并将该对象纳入Spring管控的范围,也就是定义成一个bean,然后使用注解@ConfigurationProperties指定该对象加载哪一组yaml中配置的信息。
⑤多种环境开发(yaml单文件版)
什么是多环境?其实就是说你的电脑上写的程序最终要放到别人的服务器上去运行。每个计算机环境不一样,这就是多环境。常见的多环境开发主要兼顾3种环境设置,开发环境——自己用的,测试环境——自己公司用的,生产环境——甲方爸爸用的。因为这是绝对不同的三台电脑,所以环境肯定有所不同,比如连接的数据库不一样,设置的访问端口不一样等等。
1.配置激活选项
spring:profiles:active: dev
2.在不同的配置环境下添加英文三个横杠(---)可以让idea区分不同的环境
spring:profiles:active: prod # 启动prod --- spring:profiles: prod server:port: 8080 --- spring:profiles: dev server:port: 8081 --- spring:profiles: test server:port: 8082
四、logback记录日志
日志就是记录程序运行的信息,主要作用如下:
- 编程期调试代码
- 运营期记录信息
- 记录日常运营重要信息
- 记录应用报错信息
- 记录运维过程数据
默认情况下,Spring Boot会用Logback来记录日志,并用INFO级别输出到控制台
Logback继承自log4j。Logback的架构非常的通用,适用于不同的使用场景。
①logback初始化步骤
logback会在类路径下寻找名为logback-test.xml的文件
如果没有找到,logback会继续寻找名为logback.groovy的文件
如果没有找到,logback会继续寻找名为logback.xml的文件
如果没有找到,将会在类路径下寻找文件META-INFO/services/ch.qos.logback.classic.spi.Configurator,该文件的内容为实现了Configurator接口的实现类的全限定类名
如果以上都没有成功,logback会通过BasicConfigurator为自己进行配置,并且日志将会全部在控制台打印出来
②使用日志文件记录日志
1.导入依赖:spring-boot-starter-logging
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId><version>2.5.2</version> </dependency>
2.在配置文件中设置日志文件的名字
3.创建一个logback的配置文件logback.xml,日志输出到哪个目录的哪个文件下,输出的格式输出的日志级别
<?xml version="1.0" encoding="UTF-8"?><configuration><!-- 输出到控制台 --><appender name="console" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder></appender><!-- 输出到文件 --><appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>log/demo.log</file><encoder><pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>log/demo.%d{yyyy-MM-dd}.log</fileNamePattern></rollingPolicy></appender><!-- 设置日志输出级别 --><root level="INFO"><appender-ref ref="console" /><appender-ref ref="file" /></root> </configuration>
注意:
- spring boot默认会加载classpath:logback-spring.xml或者classpath:logback-spring.groovy或者:classpath:logback.xml
- 自定义配置文件(不要使用logback-logback.xml这个来命名,否则spring boot将不能完全实例化 ),文件格式为:
logging: config: classpath:logback-suke.xml
4.创建log对象去写日志,检测是否能够打印运行日志
import com.minyudie.spring_boot_basic1.pojo.Datasource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;@RestController @RequestMapping("/test") public class TestController {@Autowiredprivate Datasource datasource;private static final Logger logger =LoggerFactory.getLogger(TestController.class);@PostMapping("/hello")public String hello() {logger.info("I'm logger");return "hello";}}
使用apifox测试网址,使用post方法访问:
网址正确,访问成功!!!
控制台输出:
日志文件中成功记录到:
五、配置过滤器,拦截器,全局异常捕获
①使用SpringBoot的配置类来添加过滤器
1.编写Filter类
import jakarta.servlet.*; import java.io.IOException;public class MyFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {Filter.super.init(filterConfig);}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("MyFilter doFilter");}@Overridepublic void destroy() {Filter.super.destroy();} }
2.使用SpringBoot提供的FilterRegistrationBean来对Filter进行配置
import com.minyudie.spring_boot_basic1.filter.MyFilter; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;@Configuration public class FilterConfig {@Beanpublic FilterRegistrationBean<MyFilter> myFilter(){FilterRegistrationBean<MyFilter> registrationBean = new FilterRegistrationBean<>();registrationBean.setFilter(new MyFilter());registrationBean.addUrlPatterns("/*");registrationBean.setName("myFilter");registrationBean.setOrder(1);return registrationBean;} }
3.测试
成功执行!!
②配置拦截器
1.实现一个Intercepter类
这里我们需要实现HandlerInterceptor这个接口,这个接口包括三个方法,preHandle是请求执行前执行的,postHandler是请求结束执行的
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView;public class MyIntercept implements HandlerInterceptor {private long start;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {start = System.currentTimeMillis();return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("耗时:" + (System.currentTimeMillis() - start));}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {} }
2.写一个配置类
import com.minyudie.spring_boot_basic1.intercept.MyIntercept; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration public class InterceptConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new MyIntercept()).addPathPatterns("/user");} }
3.测试
没有出现hello,表示已被拦截
③设置全局捕获异常
1.创建一个异常类,在其class上注解@ControllerAdvice,在其方法上加上注解@ExceptionHandler(value=Exception.class)
import jakarta.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody;@ControllerAdvice public class GlobleException {Logger logger = LoggerFactory.getLogger(GlobleException.class);@ExceptionHandler(value = Exception.class)@ResponseBodypublic String defaultErrorHandler(HttpServletRequest request, Exception e) {logger.error("请求地址:{},发生异常:{}", request.getRequestURL(), e.getMessage());return "页面无法加载";} }
2.测试,做一个会让程序报错的动作,去查看是否会显示“页面无法加载”
例如:输入一个不存在的网址,查看是否会显示我们想要的结果
测试成功!!
注意:
在测试之前,我们需要把过滤器的过滤文件路径改为不属于我们需要测试的这个路径,否则我们无法看到报错,只会有"MyFilter doFilter"。