Spring Boot初阶篇笔记

news/2024/12/2 19:50:47/

SpringBoot笔记

SpringBoot官方文档

一、SpringBoot的常用注解

@ConfigurationProperties、@PropertySource、@ImportResource的区别

1.@ConfigurationProperties:

@ConfigurationProperties:告诉SpringBoot将本类中的所有属性与配置文件中的相关属性进行绑定;
如:@ConfigurationProperties(prefix = "person") 就是将配置文件中前缀为person下边的属性与该注解所在类中的属性进行绑定

2.@PropertySource:

@PropertySource:加载指定的配置文件
如:@PropertySource("classpath:person.properties")

3.@ImportResource:

@ImportResource:导入Spring的配置文件xxx.xml,让配置文件中的内容生效;:@ImportResource(location={"classpath:bean.xml"})(作用在启动类上)

4.@Configuration:

@Configuration:指明当前类是一个配置类;用来代替之前的Spring配置文件.xml

二、Profile多环境支持

1.多文件

约定文件名:application-{profile}.properties 使用spring-profiles.active={profile}激活对应的环境

application-dev.properties

application-prod.properties

2.yml多文档块


server:port: 8080
spring:profiles:active: prod
---
server:port: 8081
spring:profiles: dev
---
server:port: 8082
spring:profiles: prod

三、配置文件加载位置

SpringBoot启动会扫描一下位置的application.properties或application.yml文件作为SpringBoot的默认配置文件。

file:./config/

file:./

classpath:/config/

classpath:/

优先级由高到低,高优先级的配置会覆盖低优先级的配置;SpringBoot会从这四个位置全部加载主配置文件,故会形成一个互补配置

四、外部配置加载顺序

1.命令行参数

如:java -jar xxx.jar --server.port=8087

由jar包外向jar包内

优先加载带profile的

2.jar包外部的application-{profile}.properties或application.ym|(带spring.profile)配置文件
3.jar包内部的application-{profile}.properties或application.yml(带spring.profile)配置文件

再来加载不带profile的

4.jar包外部的application.properties或application.yml(不带spring.profile)配置文件

5.jar包内部的application.properties或application.yml(不带spring.profile)配置文件

五、自动配置原理(面试必问题)

application.properties配置文件参考

@EnableAutoConfiguration
->@Import({AutoConfigurationImportSelector.class})
->getCandidateConfigurations(annotationMetadata, attributes);
->SpringFactoriesLoader.loadFactoryNames();
->classLoader.getResources(“META-INF/spring.factories”)

①配置原理:

1.SpringBoot启动时加载主配置类,开启了自动配置功能 @EnableAutoConfiguration

2.@EnableAutoConfiguration的作用:
●利用@EnableAutoConfigurationImportSelector给容器中导入一些组件?
●List configurations = this.getCandidateConfigurations(annotationMetadata, attributes);获取候选的配置
●SpringFactoriesLoader.loadFactoryNames()扫描所有jar包类路径下 META-INF/spring.factoryies,把扫描到的这些文件的内容包装成properties对象,从properties中获取到EnableAutoConfiguration.class类(类名)对应的值,然后把它们添加在容器中

将类路径下 META-INF/spring.factories里面配置的所有EnableAutoConfiguration的值加入到了容器中;

每一个xxxAutoConfiguration类都是容器中的一个组件,都加入到容器中;用他们来做自动配置

3.每一个配置类进行自动配置功能

4.以HttpEncodingAutoConfiguration为例解释自动配置原理:

@Configuration
@EnableConfigurationProperties({ServerProperties.class})//启动指定类的ConfigurationProperties功能;将配置文件中对应的值和HttpEncodingProperties绑定起来;并把这个类加入到ioc容器中@ConditionalOnWebApplication//Spring底层@Conditional注解,根据不同的条件,如果满足指定的条件,整个配置类中的配置就会生效   判断当前类是不是Web应用,如果是则生效;@ConditionalOnClass({CharacterEncodingFilter.class})//判断当前项目有没有这个类@ConditionalOnProperty(prefix = "server.servlet.encoding",value = {"enabled"},matchIfMissing = true
)//判断配置文件中是否存在某个配置 如:server.servlet.encoding.enable ; 如果不存在,判断也是成立的
public class HttpEncodingAutoConfiguration {private final Encoding properties;////只有一个有参构造方法的情况下,参数的值就会从容器中拿public HttpEncodingAutoConfiguration(ServerProperties properties) {this.properties = properties.getServlet().getEncoding();}@Bean//给容器中添加一个组件,这个组件的某些值需要从properties中获取@ConditionalOnMissingBean//判断容器中没有这个组件才会加入该组件public CharacterEncodingFilter characterEncodingFilter() {CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();filter.setEncoding(this.properties.getCharset().name());filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.REQUEST));filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.RESPONSE));return filter;}

一但这个自动配置类生效,这个配置类就会给容器中添加组件,这些组件的属性是从对应的properties类中获取的,这些类里面的每一个属性又是和配置文件绑定的;

精髓:

1)、SpringBoot启动会加载大量的自动配置类

2)、看我们需要的功能有没有SpringBoot默认写好的自动配置类

3)、我们再来看这个自动配置类中到底配置了那些组件;

4)、给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们就可在配置文件中指定这些属性的值;

xxxAutoConfiguration自动配置类

给容器中添加组件

xxxProperties封装配置文件中相关属性

②细节:

@Conditional派生注解

作用:必须是@Conditional指定的条件成立,才给容器中添加组件,配置里面的内容才生效。

@Conditional扩展注解作用(判断是否满足当前指定条件)
@ConditionalOnJava系统的java版本是否符合要求
@ConditionalOnBean容器中存在指定的Bean
@ConditionalOnMissingBean容器中不存在指定的Bean
@ConditionalOnExpression满足SpEL表达式指定
@ConditionalOnClass系统中有指定的类
@ConditionalOnMissingClass系统中没有指定的类
@ConditionalOnSingleCandidate容器中只有一个指定的Bean,或者这个Bean是首选Bean
@ConditionalOnProperty系统中指定的属性是否有指定的值
@ConditionalOnResource类路径下是否存在指定资源文件
@ConditionalOnWebApplication当前是Web环境
@ConditionalOnNotWebApplication当前不是Web环境
@ConditionalOnJndiJNDI存在指定项

自动配置类必须在一定条件下才能生效

故该怎么知道哪些自动配置类是否生效?

只需在配置文件中开启debug=true 来让控制台打印自动配置报告

六、Spring Boot与日志

1.市面上常用的日志框架:

JUL、JCL、Jboss-logging、logback、log4j、log4j2、slf4j…

日志门面(日志的抽象层)日志实现
JCL(Jakarta Commons Logging)
SLF4j(Simple Logging Facade for Java)
Jboss-logging
log4j JUL (java.util.logging)
log4j2 Logback

左边选个日志门面、右边选一个来实现;

日志门面:SLF4J;

日志实现:Logback;

SpringBoot:底层是Spring框架,Spring框架默认使用JCL;

SpringBoot选用SLF4j和Logback;

2.SLF4j使用

1> 如何在系统中使用SLF4J

以后开发的时候,日记方法的调用,不应该来直接调用日志的实现类,而是调用日志抽象层里面的方法;

给系统里面导入slf4j的jar和logback的实现;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class HelloWorld {public static void main(String[] args) {Logger logger = LoggerFactory.getLogger(HelloWorld.class);logger.info("Hello World");}
}

image-20220730075858149

每一个日志的实现框架都有自己的配置文件,使用slf4j后,配置文件还是使用日志实现框架自己本身的配置文件

2 >遗留问题

SpringBoot使用的是slf4j+logback,但其他框架本身也可能在使用别的日志框架,如Spring(commons-logging)、Hibernate(jboss-logging)、Mybatis…故需要统一使用slf4j进行输出

image-20220730075944379

3.SpringBoot日志间的关系

如何让系统中的日志都统一到slf4j:

1.将系统的中其他日志框架先排出去

2.用中间包来替换原有的日志框架

3.再导入slf4j其他的实现

image-20220730080004727

总结:

1)、SpringBoot底层也是使用slf4j+logback的方式进行日志记录

2)、SpringBoot把其他的日志都替换成了slf4j

3)、中间替换包(log4j-to-slf4j、jul-to-slf4j)

一句话:SpringBoot能适应所有的日志,而且底层使用slf4j的方式记录日志,引入其他框架的时候,只需要把这个框架依赖的日志框架排除掉。

4.日志使用

1.默认配置

 //记录器Logger logger = LoggerFactory.getLogger(getClass());@Testvoid contextLoads() {//日志的级别: trace<debug<info<warn<error  由低到高,低于当前级别的则不显示,默认为info级别,可自定义在配置文件中指定级别logger.trace("这是trace日志");logger.debug("这是debug日志");logger.info("这是info日志");logger.warn("这是warn日志");logger.error("这是error日志");}

2.日志输出格式:

%d表示时间、

%thread表示线程名、

%-5level表示级别从左显示5个字符宽度、

%logger{50}表示logger名字最长50个字符,否则按照句点分割

%msg日志消息、

%n 换行

如:%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} -%msg%n

SpringBoot修改日志配置:
#指定级别 (可具体到哪个包)
logging.level.com=trace
#不指定路径则在当前项目下生成日志文件,也可以指定路径
logging.file=
#在当前磁盘的根路径下创建spring文件夹和里面的log文件夹;使用spring.log作为默认文件
logging.file.path=/spring/log
#在控制台输出的日志格式
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} -%msg%n
#指定文件中输出的日志格式
logging.pattern.file=

3.logback.xml配置样例

<?xml version="1.0" encoding="UTF-8"?>
<!--
scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒当scan为true时,此属性生效。默认的时间间隔为1分钟。
debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<configuration scan="false" scanPeriod="60 seconds" debug="false"><!-- 定义日志的根目录 --><property name="LOG_HOME" value="/app/log" /><!-- 定义日志文件名称 --><property name="appName" value="atguigu-springboot"></property><!-- ch.qos.logback.core.ConsoleAppender 表示控制台输出 --><appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"><!--日志输出格式:%d表示日期时间,%thread表示线程名,%-5level:级别从左显示5个字符宽度%logger{50} 表示logger名字最长50个字符,否则按照句点分割。 %msg:日志消息,%n是换行符--><layout class="ch.qos.logback.classic.PatternLayout"><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern></layout></appender><!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 -->  <appender name="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"><!-- 指定日志文件的名称 --><file>${LOG_HOME}/${appName}.log</file><!--当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名TimeBasedRollingPolicy: 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动。--><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!--滚动时产生的文件的存放位置及文件名称 %d{yyyy-MM-dd}:按天进行日志滚动 %i:当文件大小超过maxFileSize时,按照i进行文件滚动--><fileNamePattern>${LOG_HOME}/${appName}-%d{yyyy-MM-dd}-%i.log</fileNamePattern><!-- 可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。假设设置每天滚动,且maxHistory是365,则只保存最近365天的文件,删除之前的旧文件。注意,删除旧文件是,那些为了归档而创建的目录也会被删除。--><MaxHistory>365</MaxHistory><!-- 当日志文件超过maxFileSize指定的大小是,根据上面提到的%i进行日志文件滚动 注意此处配置SizeBasedTriggeringPolicy是无法实现按文件大小进行滚动的,必须配置timeBasedFileNamingAndTriggeringPolicy--><timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><maxFileSize>100MB</maxFileSize></timeBasedFileNamingAndTriggeringPolicy></rollingPolicy><!-- 日志输出格式: -->     <layout class="ch.qos.logback.classic.PatternLayout"><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%n</pattern></layout></appender><!-- logger主要用于存放日志对象,也可以定义日志类型、级别name:表示匹配的logger类型前缀,也就是包的前半部分level:要记录的日志级别,包括 TRACE < DEBUG < INFO < WARN < ERRORadditivity:作用在于children-logger是否使用 rootLogger配置的appender进行输出,false:表示只用当前logger的appender-ref,true:表示当前logger的appender-ref和rootLogger的appender-ref都有效--><!-- hibernate logger --><logger name="com.atguigu" level="debug" /><!-- Spring framework logger --><logger name="org.springframework" level="debug" additivity="false"></logger><!-- root与logger是父子关系,没有特别定义则默认为root,任何一个类只会和一个logger对应,要么是定义的logger,要么是root,判断的关键在于找到这个logger,然后判断这个logger的appender和level。 --><root level="info"><appender-ref ref="stdout" /><appender-ref ref="appLogAppender" /></root>
</configuration> 

log4j.properties配置样例

### set log levels ###
log4j.rootLogger = debug ,  stdout ,  D ,  E### 输出到控制台 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern =  %d{ABSOLUTE} %5p %c{ 1 }:%L - %m%n#### 输出到日志文件 ###
#log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
#log4j.appender.D.File = logs/log.log
#log4j.appender.D.Append = true
#log4j.appender.D.Threshold = DEBUG ## 输出DEBUG级别以上的日志
#log4j.appender.D.layout = org.apache.log4j.PatternLayout
#log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
#
#### 保存异常信息到单独文件 ###
#log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
#log4j.appender.D.File = logs/error.log ## 异常日志文件名
#log4j.appender.D.Append = true
#log4j.appender.D.Threshold = ERROR ## 只输出ERROR级别以上的日志!!!
#log4j.appender.D.layout = org.apache.log4j.PatternLayout
#log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

七.Web开发

1.SpringBoot对静态资源的映射规则

private final ResourceProperties resourceProperties;//设置和静态资源有关的参数,如缓存时间
public void addResourceHandlers(ResourceHandlerRegistry registry) {if (!this.resourceProperties.isAddMappings()) {logger.debug("Default resource handling disabled");} else {Duration cachePeriod = this.resourceProperties.getCache().getPeriod();CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();if (!registry.hasMappingForPattern("/webjars/**")) {this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"}).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));}String staticPathPattern = this.mvcProperties.getStaticPathPattern();if (!registry.hasMappingForPattern(staticPathPattern)) {this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(WebMvcAutoConfiguration.getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));}}}//映射欢迎页
@Beanpublic WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext, FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(new TemplateAvailabilityProviders(applicationContext), applicationContext, this.getWelcomePage(), this.mvcProperties.getStaticPathPattern());welcomePageHandlerMapping.setInterceptors(this.getInterceptors(mvcConversionService, mvcResourceUrlProvider));welcomePageHandlerMapping.setCorsConfigurations(this.getCorsConfigurations());return welcomePageHandlerMapping;}

1) 所有/webjars/**,都去classpath:/META-INF/resources/webjars/找资源

webjars:以jar包的方式引入静态资源 (即在pom.xml文件中引入资源的依赖https://www.webjars.org/ 或https://mvnrepository.com/ )

2)“/**”:访问当前项目所有资源(静态济源文件夹)

"classpath:/META-INF/resources/", 
"classpath:/resources/", 
"classpath:/static/", 
"classpath:/public/"
"/" :当前项目所有的根路径

3)欢迎页;静态资源文件夹下的所有index.html页面被"/**"映射。

4)所有的**/favicon.ico 都是在静态资源文件下找。

2.模板引擎

SpringBoot推荐Thmeleaf,功能强大,语法简单。

1)引入thymeleaf
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
2)Thymeleaf使用&语法
@ConfigurationProperties(prefix = "spring.thymeleaf"
)
public class ThymeleafProperties {private static final Charset DEFAULT_ENCODING;public static final String DEFAULT_PREFIX = "classpath:/templates/";public static final String DEFAULT_SUFFIX = ".html";private boolean checkTemplate = true;private boolean checkTemplateLocation = true;private String prefix = "classpath:/templates/";private String suffix = ".html";...
}

1.表达式:

Simple expressions:(表达式语法)Variable Expressions: ${...}:获取变量值;OGNL;1)、获取对象的属性、调用方法2)、使用内置的基本对象:#ctx : the context object.#vars: the context variables.#locale : the context locale.#request : (only in Web Contexts) the HttpServletRequest object.#response : (only in Web Contexts) the HttpServletResponse object.#session : (only in Web Contexts) the HttpSession object.#servletContext : (only in Web Contexts) the ServletContext object.${session.foo}3)、内置的一些工具对象:
#execInfo : information about the template being processed.
#messages : methods for obtaining externalized messages inside variables expressions, in the same way as they would be obtained using #{…} syntax.
#uris : methods for escaping parts of URLs/URIs
#conversions : methods for executing the configured conversion service (if any).
#dates : methods for java.util.Date objects: formatting, component extraction, etc.
#calendars : analogous to #dates , but for java.util.Calendar objects.
#numbers : methods for formatting numeric objects.
#strings : methods for String objects: contains, startsWith, prepending/appending, etc.
#objects : methods for objects in general.
#bools : methods for boolean evaluation.
#arrays : methods for arrays.
#lists : methods for lists.
#sets : methods for sets.
#maps : methods for maps.
#aggregates : methods for creating aggregates on arrays or collections.
#ids : methods for dealing with id attributes that might be repeated (for example, as a result of an iteration).Selection Variable Expressions: *{...}:选择表达式:和${}在功能上是一样;补充:配合 th:object="${session.user}:<div th:object="${session.user}"><p>Name: <span th:text="*{firstName}">Sebastian</span>.</p><p>Surname: <span th:text="*{lastName}">Pepper</span>.</p><p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p></div>Message Expressions: #{...}:获取国际化内容Link URL Expressions: @{...}:定义URL;@{/order/process(execId=${execId},execType='FAST')}Fragment Expressions: ~{...}:片段引用表达式<div th:insert="~{commons :: main}">...</div>Literals(字面量)Text literals: 'one text' , 'Another one!' ,…Number literals: 0 , 34 , 3.0 , 12.3 ,…Boolean literals: true , falseNull literal: nullLiteral tokens: one , sometext , main ,…
Text operations:(文本操作)String concatenation: +Literal substitutions: |The name is ${name}|
Arithmetic operations:(数学运算)Binary operators: + , - , * , / , %Minus sign (unary operator): -
Boolean operations:(布尔运算)Binary operators: and , orBoolean negation (unary operator): ! , not
Comparisons and equality:(比较运算)Comparators: > , < , >= , <= ( gt , lt , ge , le )Equality operators: == , != ( eq , ne )
Conditional operators:条件运算(三元运算符)If-then: (if) ? (then)If-then-else: (if) ? (then) : (else)Default: (value) ?: (defaultvalue)
Special tokens:No-Operation: _ 

3.SpringMVC自动配置原理

Spring Boot Reference Guide

Spring Boot自动配置好了SpringMVC

1.以下是SpringBoot对SpringMVC的默认:

  • Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.

    • 自动配置了ViewResolver(视图解析器:根据方法的返回值得到视图对象(View),视图对象决定如何渲染(转发?重定向?))
    • ContentNegotiatingViewResolver:组合所有的视图解析器
    • 如何定制:我们可以自己给容器中添加一个视图解析器;自动的将其组合起来;
  • Support for serving static resources, including support for WebJars (see below).静态资源文件夹路径,webjars。

  • Automatic registration of Converter, GenericConverter, Formatter beans.

    • 自动注册了
    • Converter:类型转换器
    • GenericConverter,
    • Formatter:格式化器
    • 自己添加的格式化转换器,我们只需要放在容器中即可;
  • Support for HttpMessageConverters (see below).

    • HttpMessageConverter :SpringMVC用来转换请求和响应的;
    • HttpMessageConverters:是从容器中确定;获取所有的HttpMessageConverter ;
    • 自己给容器中添加HttpMessageConverter ,只需将自己的组件注册到容器中(@Bean,@Component)
  • Automatic registration of MessageCodesResolver (see below).定义错误代码生成规则

  • Static index.html support.静态首页访问

  • Custom Favicon support (see below).

  • Automatic use of a ConfigurableWebBindingInitializer bean (see below).

    • 我们可以配置一个ConfigurableWebBindingInitializer添加到容器来替换默认的;

If you want to keep Spring Boot MVC features, and you just want to add additional MVC configuration (interceptors, formatters, view controllers etc.) you can add your own @Configuration class of type WebMvcConfigurerAdapter, but without @EnableWebMvc. If you wish to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter or ExceptionHandlerExceptionResolver you can declare a WebMvcRegistrationsAdapter instance providing such components.

If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc.

2.扩展SpringMVC

编写一个配置类(@Configuration)是WebMvcConfigurerAdapter类型;不能标注@EnableWebMvc;

既保留了所有的自动配置,也能用我们扩展的配置;

/*** 使用WebMvcConfigurerAdapter可以来扩展SpringMvc的功能*/
//@EnableWebMvc//能全权接管SpringMvc
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {//注册拦截器@Overridepublic void addInterceptors(InterceptorRegistry registry) {
//        SpringBoot2.0+ 会拦截静态资源registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**").excludePathPatterns("/index.html", "/", "/user/login", "/asserts/**", "/webjars/**");}@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/static/**", "/asserts/**").addResourceLocations(ResourceUtils.CLASSPATH_URL_PREFIX + "/static");}//所有的组件会一起起作用@Overridepublic void addViewControllers(ViewControllerRegistry registry) {//登录页视图解析registry.addViewController("/").setViewName("login");registry.addViewController("/index.html").setViewName("login");//主页视图解析registry.addViewController("/purchase_order.html").setViewName("main");}
}

原理:

​ 1)、WebMvcAutoConfiguration是SpringMvc的自动配置类

​ 2)、在做其他自动配置时,会导入:@Import(EnableWebMvcConfiguration.class)

 public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();//从容器中获取所有的WebMvcConfigurer@Autowired(required = false)public void setConfigurers(List<WebMvcConfigurer> configurers) {if (!CollectionUtils.isEmpty(configurers)) {this.configurers.addWebMvcConfigurers(configurers);}}//一个参考实现//protected void addViewControllers(ViewControllerRegistry registry) {//this.configurers.addViewControllers(registry);// }}

3)、容器中所有的WebMvcConfiguration都会一起起作用;

4)、我们的配置类也会被调用

效果:SpringMVC的自动配置和我们自己扩展的自动配置都会起作用;

3.全面接管SpringMVC

SpringBoot对SpringMVC的自动配置不需要了,所有的都是自己配置的;只需要在配置类上添加@EnableWebMvc注解

4.如何修改SpringBoot的默认配置

模式:

1)SpringBoot在自动配置很多组建的时候,先看容器中有没有用户自己配置的(@Bean、@Component)如果有就用用户自己配置的,如果没有才自动配置;如果有写组件有多个(如:ViewResolver)将用户配置的和默认的组个起来;

5.RestfulCRUD

1.Thymeleaf公共页面元素抽取

1、抽取公共片段
<div th:fragment="copy">
&copy; 2011 The Good Thymes Virtual Grocery
</div>
2、在需要的地方引入公共片段
<body>
...
<div th:insert="~{footer :: copy}"></div>
</body>
~{templatename::selector}  模板名::选择器
~{templatename::fragmentname}  模板名::片段名
3、默认效果
insert的功能片段在div标签中

三种引入功能片段的th属性:

**th:insert ** :将整个公共片段插入到声明引入的元素中

th:replace :将声明引入的元素替换为公共片段

th:include :将被引入的片段的内容包含近这个标签中

<footer th:fragment="copy">
&copy; 2011 The Good Thymes Virtual Grocery
</footer>//三种引入方式
<div th:insert="footer :: copy"></div>
<div th:replace="footer :: copy"></div>
<div th:include="footer :: copy"></div>
//效果
<div><footer>&copy; 2011 The Good Thymes Virtual Grocery</footer>
</div><footer>&copy; 2011 The Good Thymes Virtual Grocery</footer>
<div>&copy; 2011 The Good Thymes Virtual Grocery
</div>

6.错误处理机制

1、SpringBoot默认的错误处理机制

1)、默认:浏览器返回一个默认的网页

image-20220730080127662

2)、客户端会返回 Json格式数据

image-20220730080138411

参照ErrorMvcAutoConfiguration:错误处理的自动配置

给容器中添加了一下组件:

DefaultErrorAttributes:帮我们在页面共享信息

@Override
public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes,boolean includeStackTrace) {Map<String, Object> errorAttributes = new LinkedHashMap<String, Object>();errorAttributes.put("timestamp", new Date());addStatus(errorAttributes, requestAttributes);addErrorDetails(errorAttributes, requestAttributes, includeStackTrace);addPath(errorAttributes, requestAttributes);return errorAttributes;
}

BasicErrorController:处理默认/error请求

@Controller
@RequestMapping({"${server.error.path:${error.path:/error}}"})
public class BasicErrorController extends AbstractErrorController {@RequestMapping(produces = {"text/html"})//产生html类型数据;浏览器发送的请求被这个方法处理public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {HttpStatus status = this.getStatus(request);Map<String, Object> model = Collections.unmodifiableMap(this.getErrorAttributes(request, this.getErrorAttributeOptions(request, MediaType.TEXT_HTML)));response.setStatus(status.value());ModelAndView modelAndView = this.resolveErrorView(request, response, status, model);return modelAndView != null ? modelAndView : new ModelAndView("error", model);}@RequestMapping//产生json数据;客户端发送的请求被这个方法处理public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {HttpStatus status = this.getStatus(request);if (status == HttpStatus.NO_CONTENT) {return new ResponseEntity(status);} else {Map<String, Object> body = this.getErrorAttributes(request, this.getErrorAttributeOptions(request, MediaType.ALL));return new ResponseEntity(body, status);}}

ErrorPageCustomizer:

public class ErrorProperties {@Value("${error.path:/error}")private String path = "/error";//系统出现错误后来到/error请求进行处理

DefaultErrorViewResolver:

public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {ModelAndView modelAndView = this.resolve(String.valueOf(status.value()), model);if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {modelAndView = this.resolve((String)SERIES_VIEWS.get(status.series()), model);}return modelAndView;}private ModelAndView resolve(String viewName, Map<String, Object> model) {//默认SpringBoot去找error/404这个页面String errorViewName = "error/" + viewName;//模板引擎可以解析这个页面就用模板引擎解析TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName, this.applicationContext);//模板引擎可用的情况下返回到errorViewName指定的视图地址,模板引擎不能用就在静态资源文件夹下找errorViewName对应的页面  error/404.htmlreturn provider != null ? new ModelAndView(errorViewName, model) : this.resolveResource(errorViewName, model);}

步骤:

一但系统出现4xx或5xx之类的错误,ErrorPageCustomizer就会生效(定制错误的响应规则),继而发送/error请求,继而被BasicErrorController处理

响应页面;去哪个页面是由DefaultErrorViewResolver解析得到的

 protected ModelAndView resolveErrorView(HttpServletRequest request, HttpServletResponse response, HttpStatus status, Map<String, Object> model) {Iterator var5 = this.errorViewResolvers.iterator();ModelAndView modelAndView;do {if (!var5.hasNext()) {return null;}ErrorViewResolver resolver = (ErrorViewResolver)var5.next();modelAndView = resolver.resolveErrorView(request, status, model);} while(modelAndView == null);return modelAndView;}
2.如何定制错误响应

1)、如何定制错误的页面:

有模板引擎的情况下:error/状态码:将错误页面命名为 错误状态码.html放在模板引擎文件夹里的error文件夹下,发生此状态码错误就会来到对应的页面;

我们可以使用4xx和5xx作为错误页面的文件名来匹配这种类型的所有错误,精确状态码页面优先。

页面能获取的信息:

​ timestamp:时间戳

​ status:状态码

​ error:错误提示

​ exception:异常对象

​ message:异常消息

​ errors:JSR303数据校验的错误都在这里

**无模板引擎的情况:**模板引擎找不到错误页面,静态资源文件夹下找

以上都没有错误页面,就默认来到SpringBoot默认的错误页面提示

2)、如何定制错误的 Json数据:

①:自定义异常处理&返回定制json数据(不能自适应效果)

@ControllerAdvice //异常处理注解
public class MyExceptionController {//SpringBoot不能自动识别是客户端访问还是浏览器访问,返回的全部时Json数据// @ResponseBody//@ExceptionHandler(Exception.class)//处理所有的异常,也可以处理特定的异常//public Map<String,Object> myException_1(Exception e){//  Map<String,Object> map = new HashMap<>();//  map.put("code","自己定义的异常" );// map.put("message",e.getMessage() );//  return map;
}

②:转发到/error进行自适应响应效果处理

@ControllerAdvice //异常处理注解
public class MyExceptionController { 
//可以根据客户端或浏览器 自适应返回数据类型@ExceptionHandler(Exception.class)//处理所有的异常,也可以处理特定的异常public String myException_2(Exception e, HttpServletRequest request){Map<String,Object> map = new HashMap<>();//传入自己的状态码request.setAttribute("javax.servlet.error.status_code", 400);map.put("code","自己定义的异常" );map.put("message",e.getMessage() );return "forward:/error";}
}

③:携带自定义错误信息数据

出现错误后回来到/error请求,会被BasicErrorController处理,向应出去可以获取的数据是由getErrorAttributes得到的(是AbstractErrorController(ErrorController)规定的方法)

1.完全来编写一个ErrorController的实现类【或者是编写AbstractErrorController的子类】,放在容器中

2.页面上能用的数据,或者是json返回能用的数据都是通过errorAttributes.getAttributes得到,容器中DefaultErrorAttributes.getAttributes(),默认进行处理的;

自定义ErrorAttributes

/*** 能够在浏览器或者客户端访问时显示自定义的错误信息*/
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {@Overridepublic Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {Map<String,Object> map = super.getErrorAttributes(webRequest, options);map.put("company","com");//我们的异常处理器携带的数据Map<String,Object> ext = (Map<String, Object>) webRequest.getAttribute("ext", 0);map.put("ext",ext );return map;}
}

最终结果:响应是自适应的,可以通过定制ErrorAttributes改变需要返回的内容

7.配置嵌入式Servlet容器

SpringBoot默认使用内嵌式Tomcat.

1)、如何定制和修改Servlet容器的相关配置

①:修改和server有关的配置(serverProperties)

server.port=8080
server.servlet.context-path=/curd
server.tomcat.uri-encoding=UTF-8#通用的Servlet容器设置
server.xxx
#Tomcat的设置
server.tomcat.xxx

②:编写一个WebServerFactoryCustomizer(嵌入式Servlet定制器)来修改servlet容器的配置

/*** 2.0+的SpringBoot中EmbeddedServletContainerCustomizer已经不存在,被WebServerFactoryCustomizer替代了* @return*/@Beanpublic WebServerFactoryCustomizer<ConfigurableWebServerFactory> webServerFactoryWebServerFactoryCustomizer(){return new WebServerFactoryCustomizer<ConfigurableWebServerFactory>() {//定制嵌入式的Servlet规则@Overridepublic void customize(ConfigurableWebServerFactory factory) {factory.setPort(9999);}};}

2)、注册Servlet三大组件【servlet、Filter、Listener】

由于SpringBoot默认是以jar包的形式启动嵌入式的Servlet容器来启动SpringBoot的web应用,没有web.xml文件

注册三大件用一下方法:

ServletRegistrationBean

// SpringBoot注册Web三大组件(servlet、filter、listener)//1.注册Servlet@Beanpublic ServletRegistrationBean myServlet() {ServletRegistrationBean registrationBean = new ServletRegistrationBean(new MyServlet(), "/myServlet");return registrationBean;}

FilterRegistrationBean

//2.注册Filter@Beanpublic FilterRegistrationBean myFilter() {FilterRegistrationBean registrationBean = new FilterRegistrationBean<>();registrationBean.setFilter(new MyFilter());registrationBean.setUrlPatterns(Arrays.asList("/hello", "/myServlet"));return registrationBean;}

ServletListenerRegistrationBean

//3.注册Listener@Beanpublic ServletListenerRegistrationBean myListener() {ServletListenerRegistrationBean<MyListener> registrationBean = new ServletListenerRegistrationBean<>(new MyListener());return registrationBean;}

SpringBoot自动配置SpringMVC时,自动注册了SpringMVC的前端控制器:DispatcherServlet

@Bean( name = {"dispatcherServletRegistration"} )
@ConditionalOnBean(value = {DispatcherServlet.class},name = {"dispatcherServlet"})
public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet, WebMvcProperties webMvcProperties, ObjectProvider<MultipartConfigElement> multipartConfig) {DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet, webMvcProperties.getServlet().getPath());
//默认拦截 "/" 所有请求,包括静态资源,但是不拦截JSP,"/*"拦截JSP
registration.setName("dispatcherServlet");
registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());multipartConfig.ifAvailable(registration::setMultipartConfig);return registration;}

3)、替换为其它嵌入式Servlet容器

默认支持:

Tomcat(默认使用):

Jetty:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><artifactId>spring-boot-starter-tomcat</artifactId><groupId>org.springframework.boot</groupId></exclusion></exclusions></dependency><!--引入其他的Servlet容器--><dependency><artifactId>spring-boot-starter-jetty</artifactId><groupId>org.springframework.boot</groupId></dependency>
</dependency>

Undertow:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><artifactId>spring-boot-starter-tomcat</artifactId><groupId>org.springframework.boot</groupId></exclusion></exclusions></dependency><!--引入其他的Servlet容器--><dependency><artifactId>spring-boot-starter-jetty</artifactId><groupId>org.springframework.boot</groupId></dependency>
</dependency>

8.使用外置Servlet容器

嵌入式Servlet应打成Jar包

​ 优点:简单、便捷

​ 缺点:默认不支持JSP、优化定制比较复杂

外置的Servlet容器:外面安装Tomcat 应用打成War包

步骤:

1、创建一个War项目

2、将嵌入式Tomcat指定为provided

<dependency><artifactId>spring-boot-starter-tomcat</artifactId><groupId>org.springframework.boot</groupId><scope>provided</scope>
</dependency>

3、必须编写一个SpringBootServletInitializer的子类,并调用configure方法

public class ServletInitializer extends SpringBootServletInitializer {@Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {//传入SpringBoot应用主程序return builder.sources(SpringBootRestfulcrudApplication.class);}
}

4、启动Tomcat服务器即可使用。

原理:

jar包:执行SpringBoot主启动类的main方法,启动ioc容器,创建嵌入式的Servlet容器。

war包:启动服务器,服务器启动SpringBoot应用(SpringBootServletInitializer),启动ioc容器。

八、SpringBoot与Docker

1、简介

Docker是一个开源的应用容器引擎;

Docker支持将软件编译成一个镜像,然后在镜像中配置好各种软件,将镜像发布出去,其他使用者可以直接使用这个镜像。运行中的这个镜像称为容器,容器启动是非常快的。

image-20220730080320998

image-20220730080332329

2、核心概念

docker主机(host):安装了Docker程序的机器(Docker直接安装在操作系统上)

docker客户端(Client):连接docker主机进行操作

docker仓库(Registry):用来保存各种打包好的软件镜像

docker镜像(Images):软件打包好的镜像;放在docker仓库中

docker容器(Container):镜像启动后的实例称为一个容器;容器是独立运行的一个或一组应用

image-20220730080355673

使用Docker的步骤:

1)、安装Docker

2)、去Docker仓库找到这个软件对应的镜像

3)、使用Docker运行这个镜像,这个镜像就会生成一个Docker容器

4)、对容器启动的停止就是对软件的启动停止

3、安装Docker

1)、安装Linux虚拟机

​ 1、VMWare、VirtualBox(轻量)

​ 2、导入虚拟机文件

​ 3、双击启动导入的虚拟机(用户名:root 密码:123456)

​ 4、使用客户端连接Linux服务器进行命令操作

​ 5、设置虚拟机网络 (桥接网络>根据实机选择网络选择界面名称>接入网线)

​ 6、重启虚拟机网卡

service network restart

​ 7、查看虚拟机IP地址

ip addr

2)、在Linux虚拟机上安装Docker

1、查看Centos版本(要求Centos版本内核高于3.10)
# uname -r
2、安装docker
# yum install docker
3、启动docker
# systemctl start docker
注:如果启动时报错:Job for docker.service failed because the control process exited with error code. See "systemctl status docker.service" and "journalctl -xe" for details.
解决:vi进入 /etc/sysconfig/docker
OPTIONS='--selinux-enabled --log-driver=journald --signature-verification=false'改为OPTIONS='--selinux-enabled=false --log-driver=journald --signature-verification=false'即可。
4、查看docker版本
# docker -v
Docker version 1.13.1, build 7d71120/1.13.1
5、开机自启docker
# systemctl enable docker
Created symlink from /etc/systemd/system/multi-user.target.wants/docker.service to /usr/lib/systemd/system/docker.service.

4、Docker常用命令&操作

1)、镜像操作

操作命令说明
检索docker search xxx 如 docker search mysql与docker hub官网一样,可以检索镜像的信息,如镜像的Tag
拉取docker pull 镜像名 : tagtag是可选的,tag表示标签,多为软件的版本,默认是latest
列表docker images查看本地所有镜像
删除docker rmi image-id删除指定的本地镜像

docker hub官网搜索镜像

2)、容器操作

软件镜像(xxx.exe)----运行镜像----产生一个容器(正在运行的软件)

步骤:

1、搜索镜像
[root@localhost ~]# docker search tomcat
2、拉取镜像
[root@localhost ~]# docker pull tomcat  //拉取的tomcat镜像不要新版本
3、根据镜像启动容器
[root@localhost ~]# docker run --name mytomcat -d containerName // -d代表后台运行
f4991f8cf0bf0573f9549929aa98985b7148afd71bbe9c1f37c70aaa00acf461
4、停止运行中的容器
# docker stop 容器的id/docker container stop 容器ID
5、查看运行中的容器 
# docker ps
6、查看所有的容器
# docker ps -a 
7、启动容器
# docker start 容器的id/docker container start 容器ID
8、删除一个容器
# docker rm 容器的id
9、启动一个做了端口映射的tomcat
# docker run -d -it -p 8888:8080 tomcat;
-p:主机的端口映射到容器的一个端口  #(主机端口8888:映射虚拟机容器中的端口8080)
#注:docker容器运行必须有一个前台进程, 如果没有前台进程执行,容器认为空闲,容器运行的命令如果不是那些一直挂起的命令(eg. 运行top,tail等),就会自行退出,
# docker run -d -it -p 8080:8080 tomcat /bin/bash
10、查看日志
# docker logs containerName/containerId

更多docker命令参考

3)、安装MySQL示例

拉取mysql镜像

# docker pull mysql:5.7.38

错误启动演示:

# docker run -d mysql:5.7.38
使用docker ps查看没有后台运行的容器
查看日志docker logs mysql容器的id 
Database is uninitialized and password option is not specifiedYou need to specify one of the following:- MYSQL_ROOT_PASSWORD- MYSQL_ALLOW_EMPTY_PASSWORD- MYSQL_RANDOM_ROOT_PASSWORD  这三个参数必须指定一个

正确启动演示:

# docker run  -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7.38   未做端口映射
# docker run -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7.38   做了端口映射

其他带参高级操作:

# docker run --name some-mysql -v /conf/mysql:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag   
-v /conf/mysql:/etc/mysql/conf.d   把主机的/conf/mysql挂载到mysql容器的/etc/mysql/conf.d文件夹里面,改mysql的配置文件放在/conf/mysql下# docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
指定mysql的一些参数 

九、SpringBoot与数据访问

1、JDBC

导入依赖:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId>
</dependency>

2.0+版本的SpringBoot默认使用的数据源:com.zaxxer.hikari.HikariDataSource

数据源的相关配置都在DataSourceProperties.class中

自动配置原理:

和数据源有关的配置都在这个包下:

org.springframework.boot.autoconfigure.jdbc

1)、参考DataSourceConfiguration.class,根据配置创建数据源,默认使用Hikari连接池,可以使用spring.datasource.type指定自定义的数据源类型;

2)、SpringBoot默认支持以下数据源

org.apache.tomcat.jdbc.pool.DataSourceHikariDataSourceBasicDataSource

3)、也可以使用以下方法自定义数据源类型


@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean({DataSource.class})
@ConditionalOnProperty(name = {"spring.datasource.type"})
static class Generic {Generic() {}@BeanDataSource dataSource(DataSourceProperties properties) {return properties.initializeDataSourceBuilder().build();}
}

使用DataSourceBuilder来创建数据源,其中有一个build()方法,通过BeanUtils进行反射创建相应的type的数据源,并且绑定相关属性

4)、还有一处配置:DataSourceAutoConfiguration ,代表数据源的自动配置。

由于2.0版本以上的SpringBoot源码变动,DataSourceAutoConfiguration 中没有DataSourceInitializer 。不过,有一个DataSourceInitializerInvoker,是一个ApplicationListener监听器,其中则有。

其作用:

2.0版本以上是
1createSchema():运行建表语句
2initSchema():运行插入数据的SQL语句
二者都调用runScripts()方法,但2.0版本以上要在配置文件中加入
# 初始化模式
spring.datasource.initialization-mode=always
其有三个值:always为始终执行初始化,embedded只初始化内存数据库(默认值),如h2等,never为不执行初始化
是应为2.0版本有个isEnabled()方法,用来判断类型的。
2.0版本以下:
1runSchemaScripts():运行建表语句
2runDataScripts():运行插入数据的sql语句。

默认只需将文件命名为:

schame-*.sql、data-*.sql
默认规则:schame.sql或schema-all.sql
如果不是用默认规则,则需要在配置文件中使用spring.datasource.schema=xxx
指定sql脚本文件的路径,如spring.datasource.schema=classpath:department.sql

在运行建表语句时,先通过getScripts()方法获取sql脚本文件。可以通过resources指定文件的位置,如果找不到,就去找类路径下找fallback,而fallback就是schema

5)、操作数据库:自动配置了jdbcTemplate操作数据库

注:每次启动项目都会重新执行建表语,可以删除sql脚本文件,也可在配置文件中将spring.datasource.initialization-mode改为never

2、整合Druid数据源

添加Druid数据源依赖:

<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.8</version>
</dependency>

给容器中注入Druid数据源:

@Configuration
public class DruidConf {@Bean@ConfigurationProperties(prefix = "spring.datasource")//绑定数据元的其他配置public DataSource druid(){return new DruidDataSource() ;}/*** 配置druid监控* 配置一个管理后台的Servlet:statViewServlet* @return*/@Beanpublic ServletRegistrationBean statViewServlet(){ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");Map<String,Object> map = new HashMap<>();map.put("loginUsername", "admin");map.put("loginPassword", "123456");map.put("allow", ""); //""或null为访问所有map.put("deny","192.168.2.175" );//拒绝访问//为此注册设置初始化参数。调用此方法将替换任何现有的初始化参数。bean.setInitParameters(map);return bean;}/*** 配置一个监控Web的filter:webStatFilter* @return*/@Beanpublic FilterRegistrationBean webStatFilter(){FilterRegistrationBean bean = new FilterRegistrationBean(new WebStatFilter());Map<String,Object> map = new HashMap<>();//释放这些请求map.put("exclusions", "*.js,*.css,/druid/*");bean.setInitParameters(map);//拦截所有请求bean.setUrlPatterns(Arrays.asList("/*"));return  bean;}
}

application.properties

# 应用名称
spring.application.name=spring-boot-data-jdbc
# 应用服务 WEB 访问端口
server.port=8080
# 数据库驱动:
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# 数据源名称
spring.datasource.name=defaultDataSource
# 初始化模式
spring.datasource.initialization-mode=never
# 数据库脚本文件路径
spring.datasource.schema=classpath:department.sql
# 数据库连接地址
spring.datasource.url=jdbc:mysql://192.168.2.175:3306/jdbc?serverTimezone=UTC
# 自定义数据源
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
# 数据源其他配置
spring.datasource.initialSize=5
spring.datasource.minIdle=5
spring.datasource.maxActive=20
spring.datasource.maxWait=60000
spring.datasource.timeBetweenEvictionRunsMillis=60000
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1 FROM DUAL
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
spring.datasource.poolPreparedStatements=true
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
spring.datasource.filters=stat,wall,log4j2
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
spring.datasource.useGlobalDataSourceStat=true  
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500#是否启用StatViewServlet(监控页面)默认值为false(考虑到安全问题默认并未启动,如需启用建议设置密码或白名单以保障安全)
#spring.datasource.druid.stat-view-servlet.enabled=true
# 数据库用户名&密码:
spring.datasource.username=root
spring.datasource.password=root

Druid监控

3、整合MyBatis

1)、引入MyBatis依赖

<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.4</version>
</dependency>

2)、注解版

image-20220730080619895

注解版不能配置xxx.xml,所以注解版的配置需要使用MybatisAutoConfiguration类中的ConfigurationCustomizer定制一个MyBatis配置类加入到容器中

@Configuration
public class MybatisConf {@Beanpublic ConfigurationCustomizer configurationCustomizer(){return new ConfigurationCustomizer() {@Overridepublic void customize(org.apache.ibatis.session.Configuration configuration) {configuration.setMapUnderscoreToCamelCase(true);//开启驼峰命名法}};}
}

注:如果mapper包下的mapper太多,可以在SpringBoot启动类上使用@MapperScan注解扫描mapper包。

3)、配置文件版

创建一个Mybatis全局配置文件:mybatis-conf.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><settings><setting name="mapUnderscoreToCamelCase" value="true"/></settings>
</configuration>

在SpringBoot配置文件application.properties中增加以下配置:

# 指定MyBatis全局配置文件路径
mybatis.config-location=classpath:mybatis/mybatis-conf.xml
#指定mapper映射文件路径
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml

创建mapper.xml映射文件:

<?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.atcpl.springboot.mapper.Mappers"><select id="queryEmpById" resultType="com.atcpl.springboot.entity.Employee">select * from employee where id = #{id}</select>
</mapper> 

注: ,namespace的值为mapper接口文件的全类名。

<select id=" “>,id的值为mapper接口中抽象方法的方法名。

更多配置参考Mybatis官方文档

4、整合SpringData JPA

1)、SpringData简介

image-20220729112327635

2)、整合SpringData JPA

jpa:ORM(Object Relational Mapping)

步骤:

①:编写一个实体类(bean)和数据表进行映射,并且配置好映射关系

/*** 使用JPA注解配置映射关系*/
@Entity //告诉JPA这是一个实体类 (与数据表映射的类)
@Table(name = "user_table") // @Table指定和哪个数据表对应;默认是实体类类名小写user
public class User {@Id // @Id 主键@GeneratedValue(strategy = GenerationType.IDENTITY) // 主键自增private Integer id;@Column(name = "email",length = 25) // 这是和数据表对应的一个列; name指定字段名  length指定长度private String email;@Column  //字段名默认为属性名private String userName;
}

②:创建一个Dao接口来操作实体类对应的数据表(Repository)

/*** 这是一个Dao接口,来操作实体类对应的数据表(Repository)* JpaRepository<T,ID> :* 泛型T:代表要操作的实体类* 泛型ID:实体类主键*/
public interface UserRepository extends JpaRepository<User,Integer> {}

③:JPA的基本配置

spring:jpa:hibernate:# 更新或者创建数据表结构ddl-auto: update# 在控制台显示sqlshow-sql: true

所有的JPA配置都在JpaProperties.class类中。

findOne()与findById():

调用findByid方法,返回实体类的Optional,再调用isPresent进行判断是否不为空,若是就调用get获取对象,然后判断对象是否存在,删除

Optional<Permission> permissions = permissionDao.findById(id);
if (permissions.isPresent()){Permission permission = permissions.get();if (permission != null){permissionDao.delete(permission);}
}

调用findById()方法和orElse(null)方法,获取实体类对象,然后再判断实体类是否为空

permissionDao.findById(id).ifPresent(permission -> {if (permission != null){permissionDao.delete(permission);}
});

十、启动配置原理

几个重要的事件回调机制

配置在META-INF/spring.factories

ApplicationContextInitializer

SpringApplicationRunListener

只需要放在ioc容器中

ApplicationRunner

CommandLineRunner

启动原理:

1、创建SpringApplication对象

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {this.resourceLoader = resourceLoader;Assert.notNull(primarySources, "PrimarySources must not be null");//保存主配置类this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));//判断当前应用是否为Web应用this.webApplicationType = WebApplicationType.deduceFromClasspath();//从类路径下找到META‐INF/spring.factories配置的所有ApplicationContextInitializer;然后保存起来setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));//从类路径下找到ETA‐INF/spring.factories配置的所有ApplicationListenersetListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));//从多个配置类中找到有main方法的主配置类this.mainApplicationClass = deduceMainApplicationClass();}private Class<?> deduceMainApplicationClass() {try {StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();for (StackTraceElement stackTraceElement : stackTrace) {if ("main".equals(stackTraceElement.getMethodName())) {return Class.forName(stackTraceElement.getClassName());}}}catch (ClassNotFoundException ex) {// Swallow and continue}return null;}

2、调用run()方法

public ConfigurableApplicationContext run(String... args) {StopWatch stopWatch = new StopWatch();stopWatch.start();ConfigurableApplicationContext context = null;Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();configureHeadlessProperty();//从类路径META-INF/spring.factories下获取SpringApplicationRunListenersSpringApplicationRunListeners listeners = getRunListeners(args);//回调所有的获取SpringApplicationRunListener.starting()方法listeners.starting();try {//封装命令行参数ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);//准备环境ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);//创建环境完成后回调SpringApplicationRunListener.environmentPrepared();表示环境准备完成configureIgnoreBeanInfo(environment);//打印banner图,就是控制台中那个大SpringBanner printedBanner = printBanner(environment);//创建ApplicationContext;决定创建web的ioc还是普通的ioccontext = createApplicationContext();//做异分析报告exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context);//准备上下文环境;将environment保存到ioc中;而且applyInitializers()方法回调之前保存的所有的ApplicationContextInitializer的initialize方法;listeners.contextPrepared(context)则回调所有的SpringApplicationRunListener的contextPrepared();//prepareContext运行完成以后回调所有的SpringApplicationRunListener的contextLoaded();prepareContext(context, environment, listeners, applicationArguments, printedBanner);//刷新容器;ioc容器初始化(如果是web应用还会创建嵌入式的Tomcat);
//扫描,创建,加载所有组件的地方;(配置类,组件,自动配置)refreshContext(context);//从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调//ApplicationRunner先回调,CommandLineRunner再回调afterRefresh(context, applicationArguments);stopWatch.stop();if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}listeners.started(context);callRunners(context, applicationArguments);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, listeners);throw new IllegalStateException(ex);}try {listeners.running(context);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, null);throw new IllegalStateException(ex);}//整个SpringBoot应用启动完成以后返回启动的ioc容器;return context;
}

3、事件监听机制

配置在META-INF/spring.factories

ApplicationContextInitializer

public class HelloApplicationContextInitializer implementsApplicationContextInitializer<ConfigurableApplicationContext> {@Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {System.out.println("ApplicationContextInitializer...initialize..."+applicationContext);}
}

SpringApplicationRunListener

public class HelloSpringApplicationRunListener implements SpringApplicationRunListener {//必须有的构造器public HelloSpringApplicationRunListener(SpringApplication application, String[] args){}@Overridepublic void starting() {System.out.println("SpringApplicationRunListener...starting...");}@Overridepublic void environmentPrepared(ConfigurableEnvironment environment) {Object o = environment.getSystemProperties().get("os.name");System.out.println("SpringApplicationRunListener...environmentPrepared.."+o);}@Overridepublic void contextPrepared(ConfigurableApplicationContext context) {System.out.println("SpringApplicationRunListener...contextPrepared...");}@Overridepublic void contextLoaded(ConfigurableApplicationContext context) {System.out.println("SpringApplicationRunListener...contextLoaded...");}@Overridepublic void finished(ConfigurableApplicationContext context, Throwable exception){System.out.println("SpringApplicationRunListener...finished...");}
}

配置(META-INF/spring.factories)

org.springframework.context.ApplicationContextInitializer=\
com.atguigu.springboot.listener.HelloApplicationContextInitializer
org.springframework.boot.SpringApplicationRunListener=\
com.atguigu.springboot.listener.HelloSpringApplicationRunListener

只需要放在ioc容器中

ApplicationRunner

@Component
public class HelloApplicationRunner implements ApplicationRunner {@Overridepublic void run(ApplicationArguments args) throws Exception {System.out.println("ApplicationRunner...run....");}
}

CommandLineRunner

@Component
public class HelloCommandLineRunner implements CommandLineRunner {@Overridepublic void run(String... args) throws Exception {System.out.println("CommandLineRunner...run..."+ Arrays.asList(args));}
}

十一、自定义Starter

starter:又叫场景启动器

1、这个场景需要使用到的依赖是什么?

2、如何编写自动配置

@Configuration //指定这个类是一个配置类
@ConditionalOnXXX //在指定条件成立的情况下自动配置类生效
@AutoConfigureAfter //指定自动配置类的顺序
@Bean //给容器中添加组件
@ConfigurationPropertie结合相关xxxProperties类来绑定相关的配置
@EnableConfigurationProperties //让xxxProperties生效加入到容器中
自动配置类要能加载
将需要启动就加载的自动配置类,配置在META‐INF/spring.factories

3、模式

启动器只用来做依赖导入;

专门来写一个自动配置模块;

启动器依赖自动配置;别人只需要引入启动器(starter)

启动器命名规约

  • 官方命名空间
    • 前缀:“spring-boot-starter-”
    • 模式:“spring-boot-starter-模块名”
    • 如:spring-boot-starter-web、spring-boot-starter-jdbc
  • 自定义命名空间
    • 后缀:“-spring-boot-starter”
    • 模式:模块-spring-boot-starter
    • 如:mybatis-spring-boot-starter

即:自定义启动器名-spring-boot-starter

xtLoaded…");
}
@Override
public void finished(ConfigurableApplicationContext context, Throwable exception){
System.out.println(“SpringApplicationRunListener…finished…”);
}
}


**配置(META-INF/spring.factories)** ```properties
org.springframework.context.ApplicationContextInitializer=\
com.atguigu.springboot.listener.HelloApplicationContextInitializer
org.springframework.boot.SpringApplicationRunListener=\
com.atguigu.springboot.listener.HelloSpringApplicationRunListener

只需要放在ioc容器中

ApplicationRunner

@Component
public class HelloApplicationRunner implements ApplicationRunner {@Overridepublic void run(ApplicationArguments args) throws Exception {System.out.println("ApplicationRunner...run....");}
}

CommandLineRunner

@Component
public class HelloCommandLineRunner implements CommandLineRunner {@Overridepublic void run(String... args) throws Exception {System.out.println("CommandLineRunner...run..."+ Arrays.asList(args));}
}

十一、自定义Starter

starter:又叫场景启动器

1、这个场景需要使用到的依赖是什么?

2、如何编写自动配置

@Configuration //指定这个类是一个配置类
@ConditionalOnXXX //在指定条件成立的情况下自动配置类生效
@AutoConfigureAfter //指定自动配置类的顺序
@Bean //给容器中添加组件
@ConfigurationPropertie结合相关xxxProperties类来绑定相关的配置
@EnableConfigurationProperties //让xxxProperties生效加入到容器中
自动配置类要能加载
将需要启动就加载的自动配置类,配置在META‐INF/spring.factories

3、模式

启动器只用来做依赖导入;

专门来写一个自动配置模块;

启动器依赖自动配置;别人只需要引入启动器(starter)

启动器命名规约

  • 官方命名空间
    • 前缀:“spring-boot-starter-”
    • 模式:“spring-boot-starter-模块名”
    • 如:spring-boot-starter-web、spring-boot-starter-jdbc
  • 自定义命名空间
    • 后缀:“-spring-boot-starter”
    • 模式:模块-spring-boot-starter
    • 如:mybatis-spring-boot-starter

即:自定义启动器名-spring-boot-starter


http://www.ppmy.cn/news/471350.html

相关文章

13.推荐系统

例如一个电影推荐系统&#xff0c;一共有n个用户&#xff0c;m个电影&#xff0c;每部电影都有一定的特征&#xff0c;例如爱情片的比例、动作片的比例。n个用户对看过的电影进行评分&#xff0c;推荐系统如何给用户推荐新电影&#xff0c;预测用户对新电影的评分&#xff1f; …

学习HCIP的day.15

目录 三层架构 一、网络拓扑冗余 1、线路冗余 2、设备冗余 3、网关冗余 4、电源冗余 二、三和一&#xff08;网关、根网桥、SVI&#xff09; 三、管理vlan 四、三层交换机 五、网关冗余 六、名词注解&#xff1a; 七、数据交换方法&#xff1a; 1、原始交…

内核模块代码解析与模块的传参和依赖

一、内核模块基础代码解析 Linux内核的插件机制——内核模块 类似于浏览器、eclipse这些软件的插件开发&#xff0c;Linux提供了一种可以向正在运行的内核中插入新的代码段、在代码段不需要继续运行时也可以从内核中移除的机制&#xff0c;这个可以被插入、移除的代码段被称为…

Sony/索尼 NW-ZX300A ZX300 无损音乐播放器4.4口

https://item.taobao.com/item.htm?spma1z0d.7625083.1998302264.6.5c5f4e69ELHOcm&id557859816402 &#xff08;特价3天&#xff09;Sony/索尼 NW-ZX300A ZX300 无损音乐播放器4.4口 转载于:https://www.cnblogs.com/pengmn/p/10381174.html

【ZLR-T81 200A漏电继电器】

系列型号&#xff1a; ZLR-T81漏电继电器 ZLR-T81&#xff0b;ZCT-35漏电继电器 ZLR-T81&#xff0b;ZCT-80漏电继电器 ZLR-T81&#xff0b;ZCT-120漏电继电器 一、产品用途 ZLR-T81漏电继电器&#xff08;以下简称继电器&#xff09;适用于交流电压为380.660V.至1140V系统中…

运算放大器---虚短和虚断

运算放大器—虚短和虚断 前言 运算放大器两板斧&#xff1a;“虚短”“虚断” 虚短&#xff1a;在分析运算放大器处于线性状态时&#xff0c;可把两输入端视为等电位&#xff0c;这一特性称为虚假短路&#xff0c;简称虚短&#xff1b;当某一端接地的时候&#xff1a;V- V …

在职族必看!不露痕迹面试,拿到心仪offer的4个绝密技巧!求职软件屏蔽功能根本毫无作用!...

为了无缝衔接&#xff0c;许多人都会选择在职找工作&#xff0c;但如果被当前公司发现&#xff0c;很可能会酿成职业生涯的一次悲剧。 一位网友问&#xff1a;在职面试怎么避免被当前公司发现&#xff1f;boss直聘上的屏蔽功能是不是没用&#xff1f; 网友扎心回复&#xff1a;…

运放(一)-虚短虚断与深度负反馈

一、深度负反馈 一个运算放大器&#xff0c;其输出电压 其中A为运放的开环增益。 对于上图所示的负反馈电路&#xff0c;反馈系数为F&#xff0c;其负相输入电压 (1)与(2)联立可以得到 其中1AF称为反馈深度&#xff0c;当1AF远大于1时&#xff0c;称电路处于深度负反馈状态。 对…