IDEA创建SpringBoot

New Project → Spring Initializr → Lombok+Spring Web+Thymeleaf+Mybatis Framework+MySQL Driver
【BUG】:
Maven没有完全下载依赖导致@SpringBootApplication不存在,刷新Maven仍无效。在Settings找到Maven,选择自带的Maven以及仓库,解决。


pom.xml解读

1.SpringBoot全部都是打成jar包
2.从pom父类<parent> → <artifactId>spring-boot-starter-parent</artifactId>的父类中可查看到到版本仲裁中心(整合了目前依赖的版本号,避免版本冲突,后续引入依赖不需要指定版本)
3.spring-boot-starter-webweb场景启动器,整合了web所需的各种jar包(json、tomcat、starter等)
【解读】:
SpringBoot将各个应用/三方框架设置成了一个个“场景”stater,以后要用哪个,只需要引入那个场景即可。选完之后,SpringBoot就会将 该场景所需要的所有依赖自动注入。如此次用的web。


@SpringBootApplication解读

@SpringBootApplication是SpringBoot的主配置类,包含如下部分注解:

一、@SpringBootConfiguration

@SpringBootConfiguration里面包含@Configuration
【解读】:
1.该类是一个配置类
2.加了@Configuration注解的类,会自动纳入Spring容器(相当于spring中的@Component

二、@EnableAutoConfiguration

(1)、@EnableAutoConfiguration里面包含@AutoConfigurationPackage,此注解内包含@Import(AutoConfigurationPackages.Registrar.class),该Registrar.class实现了获取当前包名cn.ctx.boot的方法.

    /**
     * {@link ImportBeanDefinitionRegistrar} to store the base package from the importing
     * configuration.
     */
    static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

        @Override
        public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
            register(registry, new PackageImport(metadata).getPackageName());
        }

        @Override
        public Set<Object> determineImports(AnnotationMetadata metadata) {
            return Collections.singleton(new PackageImport(metadata));
        }
    }

【解读】:
@AutoConfigurationPackage可以找到@SpringBootApplication所在类的包,并将该包及所有的子包全部纳入spring容器

(2)、@EnableAutoConfiguration里面包含@Import(AutoConfigurationImportSelector.class),实现获取第三方依赖(jar/配置)

    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        }
        AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
                .loadMetadata(this.beanClassLoader);
        AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
                annotationMetadata);
        return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
    }

其中getAutoConfigurationEntry中的getCandidateConfigurations中的SpringFactoriesLoader.loadFactoryNames()存在Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
【解读】:
在SpringBoot启动时,根据META-INF/spring.factories找到相应的三方依赖,并将这些依赖引入本项目

总结

编写项目时,一般会对自己写的代码以及三方依赖进行配置。但是spring boot可以自动进行配置:
a.自己写的代码,spring boot通过@SpringBootConfiguration自动帮我们配置;
b.三方依赖通过spring-boot-autoconfigure-2.0.3.RELEASE.jar中的META-INF/spring.factories进行声明,然后通过@EnableAutoConfiguration开启使用即可。该jar包中包含了J2EE整合体系中 需要的依赖。
c.如何自动装配(以HttpEncoding为例)

@Configuration
//标识此类是一个配置类、将此类纳入spring ioc容器
@EnableConfigurationProperties(HttpEncodingProperties.class)
//该注解内部给了默认编码utf8,并且提供了prefix+属性名的方式供我们修改编码。
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)
//当属性满足要求时,此条件成立(如果没有配置spring.http.encoding.enabled=xxx, 则成立)

每一个XxAutoConfiguration都有很多条件@ConditionalOnXxx,当这些条件都满足时,则此配置自动装配生效。但是我们可以手动修改自动装配:properties/yml文件中的prefix名.属性名=value

如何知道spring boot开启了哪些自动装配、禁止了哪些自动装配:
application.propertiesdebug=true
Positive matches列表 表示 spring boot自动开启的装配
Negative matches列表 表示spring boot在此时 并没有启用的自动装配。


配置文件properties/yml

注入值

  • application.properties
    k=v
student.name=zs
student.age=23
  • application.yml:
    k:空格v、通过垂直对齐指定层次关系行内写法
    (k: v(简单类型),[Set/List/数组], {map/对象类型的属性},并且 []可省,{}不能省)
    默认可以不写引号; ""会将其中的转义符进行转义,其他(单引号)不会

    简单类型=八种基本类型+String+Data
student:  
  sex: true
  birthday: 2019/02/12
  location:  {province: "陕222西",city: '西\n安',zone: 莲湖\n区}  # map 行内写法
      #province: 陕西1
      #city: 西安1
      #zone: 莲湖区1
  hobbies: [足球2,篮球22]    # 数组 行内写法 []可省略
     # - 足球
     # - 篮球
  skills: 编程333,金融33     # list 行内写法
     # - 编程
     # - 金融
  pet: {nick-name: wc555,strain: hsq}  # 对象 行内写法

JavaBean绑定

@ConfigurationProperties(yml/properties)@Value("xx") 二者可以互补

@Component //将此Javabean放入spring容器
@ConfigurationProperties(prefix="student")

public class Student {
    @Value("10000@qq.com")
    private String email ;
}
功能@ConfigurationProperties@Value
注值批量注入单个
松散语法(驼峰命名)支持
stuName:stu-name
不支持
SpEL不支持支持
@Value("${student.uname}")
JSR303数据校验支持
@Email
需要开启jsr303数据校验的注解@Validated
不支持
注入复杂类型支持不支持

占位符表达式

a.随机数

  • ${random.uuid}:uuid
  • ${random.value}:随机字符串
  • ${random.int}:随机整型数
  • ${random.long}:随机长整型数
  • ${random.int(10)}:10以内的整型数
  • ${random.int[1024,65536]}:指定随机数范围
    b.引用变量值
student:
  name: ${student.user.name:无名}

实际引用的是properties中的student.user.name=zl67,若name不存在则显示无名


@PropertySource

spring boot启动时,会默认加载application.properties/application.yml文件中的数据;若修改application此名称则需要在JavaBean中加入该注解才能识别。例如:

@PropertySource(value={"classpath:conf.properties"})
public class Student {
...
}

加载conf.properties文件中的数据;但是,@PropertySource只能加载properties,不能加载yml


@ImportResource

spring等配置文件默认会被spring boot自动给配置好。spring boot默认不识别自己编写spring.xml等配置文件,如果需要识别,则需要在spring boot主配置类上通过@ImportResource指定配置文件的路径:

@ImportResource(locations={"classpath:spring.xml"})
@SpringBootApplication
public class HelloWorldApplication {
    public static void main(String[] args) {
        SpringApplication.run(HelloWorldApplication.class, args);
    }
}

但是不推荐手写spring.xml等配置文件,而是通过注解配置:
写类@Configuration@Bean,一般放在与主配置类同级的config文件夹下(config.WebConfig.java)

@Configuration
public class AppConfig {
    @Bean        
    public StudentService stuService(){//<bean  id="xxxxxxxxxxxxx">
        StudentService stuService = new StudentService();    
//        StudentDao stuDao = new StudentDao()  ;
//        stuService.setStudentDao(stuDao);        
        return stuService;//返回值 <bean  class="xxxxxxxxxxxxx">
    }
}

常用写法:

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
    }
}

验证是否成功写入到spring的ioc容器中:

@RunWith(SpringRunner.class)
@SpringBootTest
public class HelloWorldApplicationTests {
    @Autowired
    ApplicationContext context ;//spring ioc容器
    @Test
    //查看指定
    public void test(){
        StudentService stuService = (StudentService)context.getBean("stuService") ;
        System.out.println(stuService);
    }

    //查看全部
    @Test
    public void test2(){
        String[] beanDefinitionNames = context.getBeanDefinitionNames();
        for(String beanDefinitionName : beanDefinitionNames){
            System.out.println(beanDefinitionName);
        }
    }
}

多环境切换

application-环境名.properties/yml
application-dev.properties/yml
application-test.properties/yml
默认boot会读取application.properties/yml环境
a.properties
如果要选择某一个具体的环境:application.properties中指定:spring.profiles.active=环境名(test/dev)
b.yml

server:
  port: 8883
#spring:
#  profiles:
#    active: dev
---
server:
  port: 8884
spring:
  profiles: dev
---  
server:
  port: 8885
spring:
  profiles: test

c.动态切换环境
i:通过运行参数指定环境
(1)Tomcat:Run Configuration - Argument - program Argument
--spring.profiles.active=环境名
(2)命令行方式:
java -jar 项目名.jar --spring.profiles.active=环境名
ii:通过vm参数指定环境
Tomcat :Run Configuration - Argument - VM
-Dspring.profiles.active=环境名


配置文件位置

配置项目名
默认端口访问时不需要项目名,可在application.properties文件中配置
server.servlet.context-path=/boot

项目内部的配置文件:
properties和yml中的配置,相互补充;如果冲突,则properties优先级高。

spring boot默认能够读取的application.properties/application.yml,这2个文件 可以存在于以下4个地方:

  • file:项目根目录/config
  • file:项目根目录
  • classpath:项目根目录/config
  • classpath:项目根目录

【注意】:
a.如果某项配置冲突,则优先级从上往下
b.如果不冲突,则互补结合使用

项目外部的配置文件: (补救/大范围修改配置文件)
1.编译器
Run/Debug Configurations → Configuration → argumenets:
--spring.config.location=D:/application.properties
2.命令行
java -jar 项目.jar --spring.config.location=D:/application.properties

项目运行参数: (补救/修改个别配置参数)
1.编译器
Run/Debug Configurations → Configuration → argumenets:
--server.port=8883
2.命令行
java -jar 项目.jar --server.port=8883
【注意】:
修改多个参数用空格隔开

优先级
命令参数(运行参数 > 调用外部的配置文件 )> 内部文件 (properties > yaml)
(具体参考官方文档:24. Externalized Configuration


日志

日志框架:
UCL、JUL、jboss-logging、logback、log4j、log4j2、slf4j...
SpringBoot默认选用:slf4jlogback

日志级别:
TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF
SpringBoot默认的日志级别是INFO(即只打印INFO及之后级别的信息)
可以自定义级别,

#properties: logging.level.主配置类所在包=级别
logging.level.cn.ctx.boot=warn

#yml
logging:
  level:
    cn.ctx.boot: warn

日志位置:

  • 存储到文件中(项目根目录):logging.file.name=springboot.log
  • 存储到文件中(指定路径):logging.file.name=D:/springboot.log
  • 存储到文件夹中(默认文件名spring.log):logging.file.path=D:/log/

日志格式

#控制台:
logging.pattern.console=%d{yyyy-MM-dd} [%thread] %-5level %logger{50} - %msg%n
#文件:
logging.pattern.file=%d{yyyy-MM-dd} [%thread] %-5level %logger{50} - %msg%n
  • %d:日期时间
  • %thread:线程名
  • %-5level:显示日志级别,-5表示从左显示5个字符宽度
  • %logger{50}:设置日志长度,不够显示则头名称缩写,例如o.s.w.s.m.m.a.
  • %msg:日志消息
  • %n:回车

默认的日志格式,是在 jar包中相应包的xml文件中进行配置。【日志的具体使用规范】


SpringBoot开发Web项目

Webjars存放静态资源

通过WebMvcAutoConfiguration类底下的addResourceHandlers()推出/webjars/

        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            if (!this.resourceProperties.isAddMappings()) {
                logger.debug("Default resource handling disabled");
                return;
            }
            if (!registry.hasMappingForPattern("/webjars/**")) {
                ResourceHandlerRegistration registration = registry.addResourceHandler("/webjars/**")
                        .addResourceLocations("classpath:/META-INF/resources/webjars/");
                configureResourceCaching(registration);
                customizeResourceHandlerRegistration(registration);
            }
            String staticPathPattern = this.webFluxProperties.getStaticPathPattern();
            if (!registry.hasMappingForPattern(staticPathPattern)) {
                ResourceHandlerRegistration registration = registry.addResourceHandler(staticPathPattern)
                        .addResourceLocations(this.resourceProperties.getStaticLocations());
                configureResourceCaching(registration);
                customizeResourceHandlerRegistration(registration);
            }
        }

WebJars是将Web前端JQuery和Bootstrap等资源打包成Java的Jar包,这样在Java Web开发中我们可以借助Maven这些依赖库的管理。
项目中需要的JQuery和Bootstrap的Maven依赖可以去WebJars官网找到相应的Maven依赖添加到pom.xml
【引入】从Jar目录结构的webjars开始写:
http://localhost:8080/webjars/jquery/3.3.1/jquery.js
<link th:href="@{/webjars/bootstrap/4.1.3/css/bootstrap.css}" rel="stylesheet">

SpringBoot存放静态资源

public class ResourceProperties {

    private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/",
            "classpath:/resources/", "classpath:/static/", "classpath:/public/" };
}

从上可知,SpringBoot的约定:SpringBoot将一些目录结构设置成静态资源存放目录,我们的静态资源直接放入这些目录即可。
【注意】:
在以上目录存放资源文件后,访问时不需要加前缀,直接访问即可:http://localhost:8080/world.html

自定义静态资源目录
Properties文件中的 prefix+属性,自定义静态资源目录后 以前默认的目录会失效:
spring.resources.static-locations=classpath:/res/, classpath:/img/

欢迎页/Logo

默认欢迎页:
WebMvcAutoConfiguration类中的welcomePageHandlerMapping()getIndexHtml()location + "index.html",可知,任意一个静态资源目录中的index.html就是欢迎页

默认Logo:
网站中网页标签的Logo是固定名字 :favicon.ico
阅读源码得知 :只需要将favicon.ico文件放入任意静态资源目录中即可。

访问static静态资源失效/无法访问templates问题

访问static静态资源失效:
从源码可知classpath下默认可以访问,若无法访问则在项目底下添加config/WebConfig

/**
 * WebMvc配置
 */
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
    }
}

无法访问templates问题:
SpringBoot默认不能直接访问templates下的资源文件,可以通过Controller修改所有.

@Controller
public class PageController {
    @RequestMapping("{module}/{url}.html")
    public String module(@PathVariable("module") String module, @PathVariable("url") String url){
        return module + "/" + url;
    }
}

SpringBoot整合JSP开发【了解】

SpringBoot整合JSP开发,需要单独配置一个外置的Tomcat,并且项目打war包

1.新建SpringBoot项目,选择War包,并修改Tomcat依赖

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

2.建立基本的web项目所需要的目录结构
webapps/WEB-INF
webapps/index.jsp
3.创建Tomcat实例、部署项目
访问:域名:端口/项目名/文件名
localhost:8080/SbJSP/index.jsp

【分析】
如果是一个war包的SpringBoot项目,在启动服务器Tomcat时,会自动调用ServletInitializer类中 的configure()方法,configure()方法会调用SpringBoot的主配置类从而启动SpringBoot。即在启动Tomcat服务器时,会先启动Tomcat,再自动启动SpringBoot

Last modification:May 4th, 2020 at 11:14 am
喵ฅฅ