SpringBoot入门到精通-Spring的基本使用

Posted 墨家巨子@俏如来

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot入门到精通-Spring的基本使用相关的知识,希望对你有一定的参考价值。

SpringBoot入门到精通系列


前言

上一篇文章我们讲的是SpringBoot的入门程序,万事开头难,本篇文章我们将学习SpringBoot的一些基础用法。

四.SpringBoot基本使用

1.独立运行

之前启动项目是在启动类执行main方法来启动,这种方式依赖于IDEA开发工具,如果我们项目要上线,就需要把项目打包(jar)后独立启动。

1.1.项目打包

第一步:导入打包插件

<build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>

第二步:使用terminal 执行命令 mvn package 打包

该命令回把项目按照pom.xml中指定的<packaging>jar</packaging> 打包方式把项目打成 jar包,输出到 target目录

当然了也可以直接点击 Maven窗口中的 package 菜单,效果是一样的

1.2.启动项目

使用CDM命令窗口,执行java -jar 启动项目,如下

这样我们如果要在linux部署项目,就只需要把项目的jar包推送上去,执行java -jar即可。

2.热部署

热部署就是当我们修改了项目代码,不需要重启就可以看到最新的效果,我们可以引入三方热部署插件来实现.SpringBoot提供了开发工具包可以实现热部署。

2.1.导入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>

2.2.编译代码

当我们修改了代码后,按住ctrl+F9 触发代码重新编译,SpringBoot检查到classpath变化,会重新加载字节码,达到无需手动重新即可看到最新效果的目的。

但是每次都去ctrl+f9显得特别麻烦,可以把编码配置成ctrl+s ,这样习惯性保存就编译。在setting中找到keymap,搜索build,找到Build Project ,右键 Add Keyboar Shortcut.增加ctrl+s按键。

重启项目,当修改了代码,按一下ctrl+s,即可触发热部署功能。当然还有一种方式是开启IDEA自动编译代码的功能,这样不用按ctrl+s就能自动触发热部署,但是这种方式对IDEA性能影响极大,每次修改代码都会重新热部署,个人不太建议。

3.YAML配置

3.1.认识yml

YAML (YAML Ain’t a Markup Language)YAML不是一种标记语言,通常以.yml为后缀的文件,是一种直观的能够被电脑识别的数据序列化格式,并且容易被人类阅读,容易和脚本语言交互的,可以被支持YAML库的不同的编程语言程序导入,一种专门用来写配置文件的语言。YML具有如下规范

  • yml以 k: v 键值结构书写,冒号后面必须有一个空格

  • 使用空格的缩进表示层级关系,空格数目不重要,只要是左对齐的一列数据,都是同一个层级的,同一级不能出现相同名字。

  • 大小写敏感

  • 缩进时不允许使用Tab键,只允许使用空格。

  • 松散表示,java中对于驼峰命名法,可用原名或使用-代替驼峰,如java中的lastName属性,在yml中使用lastName或 last-name都可正确映射。

3.2.常规配置

我们以普通的值(数字、字符串、布尔)、日期、对象、数组、集合为例来进行配置

  1. 字面量直接写,对于字符串有些特殊
#字符串配置
appName: "SprigBoot"
#不用加上引号也可以
#appName: SprigBoot

字符串默认不用加上单引号或者双绰号;

  • “”: 双引号;不会转义字符串里面的特殊字符;特殊字符会作为本身想表示的意思

  • name: “zhangsan \\n lisi”:输出;zhangsan 换行 lisi

  • ‘’:单引号;会转义特殊字符,特殊字符最终只是一个普通的字符串数据

  1. 日期
date: 2019/01/01
  1. 对象

map和对象的写法是一样的

#定义一个对象
user:
  id: 1
  name: zs

第二种写法

user: id:1,name:zs
  1. 数组(list ,set)

数组使用中划线 -表示其中一个元素 , list 和 set写法也是一样的

names:
  - zs
  - ls
  1. 对象数组(list,set)

list 和 set写法也是一样的

users:
  - id: 1
    name: zs
  - id: 2
    name: ww
  - id:3,name:zy

3.3.综合案例

java对象

public class ClassRoom 
    private Long id;
    private String name;


public class Teacher 
    private Long id;
    private String name;


public class Student 
    private Long id;
    private String username;
    private ClassRoom classRoom;
    private List<Teacher> teachers;
    private String hobby[];
    private Map<String,String> property;

yml配置

student:
  id: 1
  username: "zs"
  classRoom:
    id: 1,
    name: "一班"
  teachers:
    - id: 1,
      name: "张老师"
    - id: 2
      name: "王老师"
  hobby:
    - "篮球"
    - "跑步"
  property:
    hei: 170
    weight: 120

4.读取配置

在实际开发中,我们为了解除硬编码,往往需要把某些内容编写在配置文件中,然后读取到代码中使用,以至于修改的时候只需要修改配置文件而不需要修改代码。这里涉及到一个重要的环节就是如何把配置文件中的内容读取到代码中使用。介绍两种方式:@Value注解和@ConfigurationProperties注解。

4.1.使用@Value标签

我们来演示一个简单的案例,假如我们在 application.yml 有如下配置

user:
  username: ls
  password: 456
  age: 99

那我们在代码中如何使用配置文件中的内容呢?很简单,只需要在类中创建一个成员变量,做如下操作即可

@RestController
public class HelloController 

    //演示读取配置
    @Value("$user.username")
    private String username;

    //演示读取配置
    @Value("$user.password")
    private String password;

    //演示读取配置
    @Value("$user.age")
    private int age;


    @RequestMapping("/hello")
    public String hello()
        System.out.println("username = "+username);
        System.out.println("password = "+password);
        System.out.println("age = "+age);
        return "Hello Spring Boot";
    

这里我们使用了 @Value(" u s e r . u s e r n a m e " ) 方 式 来 取 值 , user.username") 方式来取值, user.username")是SPEL的写法,它可以自动从配置中拿到值赋值到被标记的字段上。启动项目,访问 /hello , 可以看到控制台输出了正确的值。

4.2.@ConfigurationProperties

对于@Value它的弊端是:它只能一个一个读取配置项,如果配置项目比较多的话就需要写很多的字段和@Value注解。我们可以使用@ConfigurationProperties来解决。

还是刚才的application.yml配置,我可以为他编写一个对应的实体类

//交给Spring管理
@Component
//读取配置的注解,以  user 为前缀过滤出配置项,同名注入到字段中
@ConfigurationProperties(prefix = "user")
public class UserProp 
    private Long id;
    private String username;
    private int age;

   ...省略get,set方法...

    @Override
    public String toString() 
        return "UserProp" +
                "id=" + id +
                ", username='" + username + '\\'' +
                ", age=" + age +
                '';
    


@ConfigurationProperties(prefix = “user”) : 它的作用是自动读取配置,以 prefix 为指定的值为前缀过滤出配置项,同名注入到字段中,该注解在SpringBoot源码中大量使用。记得需要贴:@Component,把当前类交给Spring管理。

随后我们只需要在代码中注入 UserProp 即可使用

@RestController
public class HelloController 

 
    @Autowired
    private UserProp userProp;

    @RequestMapping("/hello")
    public String hello()
        System.out.println(userProp);
        return "Hello Spring Boot";
    


控制台打印效果: UserPropid=null, username=‘ls’, age=99

总结一下: @Value适用于单个配置的读取 , @ConfigurationProperties合适把一堆拥有相同前缀的配置读取到一个类中。

5.多环境配置切换

在真实项目中往往涉及到相互环境的切换,比如:我们在自己的电脑上把代码写好之后,会把代码打包推送给测试人员进行测试,测试通过没有问题之后又会把代码推送到生成环境上线。随着环境的切换,相关配置也需要修改。就拿数据库来说,我们开发代码的时候使用我们自己电脑电脑上的数据库,测试的时候需要有专门的测试数据库,对于DataSource而言就需要重新配置,而生产放进又有专门的数据库,有需要切换配置。当配置项变多的时候,每次切换环境就是一个很麻烦的事情,SpringBoot提供了两种方式进行多环境支持。

5.1.使用文档块

第一种方式,我们使用yml的文档块来进行多个环境配置(为不同的环境做不同的配置),在application.yml中做如下配置

spring:
  profiles:
    active: test	#激活(选择)环境test
---
spring:
  profiles: dev		#指定环境名字dev
server:
  port: 9999
---
spring:
  profiles: test	#指定环境名字test
server:
  port: 8888

---是用来文档分块的,spring.profiles我们可以理解为是配置环境的名字 ,spring.profiles.active则是用来激活配置的,那么上面配置了2个环境,一个dev 开发环境 ,端口使用 9999 , 一个 test 测试环境,端口 8888 ;

然后使用spring.profiles.active=test 来激活测试环境配置,也就是说程序启动会使用 test的配置,端口会使用 8888

启动日志如下

如果你需要切换为 dev ,只需要修改spring.profiles.active=dev即可

5.2.使用多文件

第二种是使用多个配置文件,不同的环境使用不同的配置文件,首先创建一个名字为application-dev.yml 配置文件用作开发环境配置

server:
  port: 9999

再创建一个名字为 application-test.yml 的配置文件,用作测试环境配置

server:
  port: 8888

你应该看懂是什么意思了,没错 -dev 最后一个中划线后面的名字,代表的就是环境的名字。

接下来在主配置文件 application.yml 中来指定激活哪个配置

spring:
  profiles:
    active: dev #激活application-dev.yml

这里我激活了 dev环境的配置,启动测试如下

6.日志的使用

日志对于程序的调试和排错是非常重要的,遥想当年刚出道那会儿,我打印日志的方式就是System.out.println(),然后项目上线后控制台全是Sytem.out的输出,看起来非常凌乱,然后被老板批斗了一番。O(∩_∩)O哈哈~

使用System.out.println 调试程序确实比较方便,但是这个东西本身性能不好,而且没有开关,没办法做到关闭打印,除非你把打印的代码删除。同时打印出来的东西也没有规范的格式和时间,所以极其不推荐使用System.out.println来打印日志,除非你只是临时的调试,打印完之后就删除。

在实际项目中我们都是使用专业的日志框架去打印日志,这种日志有开关,有等级,有格式,同时可以做日志收集。

6.1.日志框架介绍

常见的日志框架有 Apache 的 Log4j ,Log4j2,Commons Logging,基于门面模式设计的Slf4jLogback(Slf4j阵营) ,和Java自带的Jul

日志框架的历史我这里不多说,你可以自己去百度,对于 Slf4j 而言,它的出现其实是为了整合市面上其他的日志框架使用标准不同统一的问题。它提供了 slf4j-api ,是一套简易Java日志门面,本身并无日志的实现,然后通过一些列的适配包来整合其他的日志框架,比如: slf4j-jdk14-1.7.13.jar 适配JDK原生的日志框架,比如:slf4j-log4j12-1.7.13.jar适配于log4j1.2日志框架。

总之我们在项目中需要引入 slf4j-api ,以及适配于其他日志框架的依赖如:slf4j-log4j12,对于SpringBoot而言,推荐使用Logback作为日志框架,且通过spring-boot-starter-web 已经引入了日志包,我们无需再导入日志包

6.2.打印日志

打印日志需要创建Logger,注意:我们要面向接口编程,使用slf4j总的Logger

@RestController
public class HelloController 

    //日志打印器
    private Logger log = LoggerFactory.getLogger(HelloController.class);

    @RequestMapping("/hello")
    public String hello()
        log.error("错误日志 错误信息为 = ","空指针异常");
        log.warn("警告日志");
        if(log.isDebugEnabled())
            log.debug("这是一个debug信息 " , "填充内容");
        
        log.info("info信息");
        log.trace("trace信息");

        return "Hello Spring Boot";
    

可以通过log.isDebugEnabled() 来判断是否开启该日志级别,可以通过 占位符的方式来传值。

打印效果如下

对于 info 和 trace 并没有被打印出来,那是因为SpringBoot默认的日志级别为 info,我们做如下修改即可打印所有级别日志

logging:
  level:
    cn.whale: trace #指定cn.whale包下的日志使用trace级别

注意:level 下面需要指定一个包名,测试效果如下

你知道日志级别有哪些吗?从内容打印的多到少排序 : trace > debug > info > warn > error 。比如你设置为debug,那么就可以打印出 deug,info,warn,error级别的日志。

6.3.Lombok打印日志

lombok提供了一个注解@Slf4j,可以省略到Logger的创建即可打印,但是需要导入lombok的依赖

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

然后安装Lombok的插件

然后在需要打印值的类上贴@Slf4j

@RestController
//自动创建 Logger log 
@Slf4j
public class HelloController 

    //日志打印器
    //private Logger log = LoggerFactory.getLogger(HelloController.class);

    @RequestMapping("/hello")
    public String hello()
        log.error("错误日志 错误信息为 = ","空指针异常");
        log.warn("警告日志");
        if(log.isDebugEnabled())
            log.debug("这是一个debug信息 " , "填充内容");
        
        log.info("info信息");
        log.trace("trace信息");

        return "Hello Spring Boot";
    

6.4.配置日志

如果要对日志做个性化配置,可以直接修改yml,如下

logging:
  level:
    root: info #全局使用info级别
    cn.whale: trace #指定cn.whale包下的日志使用trace级别
  file:
    path: logs #日志保存路径
    max-size: 10MB #最多10MB就会删除老的日志
    max-history: 7 #最多保留7天就会删除老的日志
    name: logs/springboot.log #日志文件名
  pattern: #指定日志的格式
    file: "%dyyyy-MM-dd HH:mm:ss.SSS [%thread] %-5level %logger50 - %msg%n" #输出到文件的格式
    console: "%dyyyy-MM-dd HH:mm:ss.SSS [%thread] %-5level %logger50 - %msg%n" #输出到控制台的格式

但是官方更推荐使用 logback-spring.xml ,或者logback.xml作为默认的logback配置文件,在resoures下创建文件logback-spring.xml会自动识别为日志配置, 下面是一个样板。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- 定义 日志格式 -->
    <property name="CONSOLE_LOG_PATTERN" value="%dyyyy-MM-dd HH:mm:ss.SSS [%thread] %-5level %logger50 - %msg%n"/>

    <!--ConsoleAppender 用于在屏幕上输出日志-->
    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
        <!--定义控制台输出格式-->
        <encoder>
            <pattern>$CONSOLE_LOG_PATTERN</pattern>
            <!-- 设置字符集 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!--打印到文件-->
    <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">

        <file>logs/springboot.log</file>
        <!--按照时间和大小分割日志文件-->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
			 <!--文件名,会按照时间和下标进行滚动,比如:2022111-0.log.gz ; 2022111-1.log.gz-->
            <fileNamePattern>logs/springboot-%dyyyyMMdd-%i.log.gz</fileNamePattern>
             <!--单个日志文件的内容大小-->
            <maxFileSize>10MB</maxFileSize>
            <!--保存历史30天-->
            <maxHistory>30</maxHistory>
            <!--总上限大小-->
            <totalSizeCap>5GB</totalSizeCap>
        </rollingPolicy>
        <!--定义控制台输出格式-->
        <encoder>
            <pattern>$CONSOLE_LOG_PATTERN</pattern>
            <!-- 设置字符集 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>


    <!--root是默认的logger 这里设定输出级别是info-->
    <root level="info">
        <!--定义了两个appender,日志会通过往这两个appender里面写,也就是说会打印到控制台,也会输出到文件-->
        <appender-ref ref="stdout"/>
        <appender-ref ref="file"/>
    </root>

    <!--如果没有设置 additivity="false" ,就会导致一条日志在控制台输出两次的情况-->
    <!--additivity表示要不要使用rootLogger配置的appender进行输出-->
    <logger name="cn.whale" level="trace" additivity="false">
        <appender-ref ref="stdout"/>
        <appender-ref ref="file"/>
    </logger>

</configuration>

以上是关于SpringBoot入门到精通-Spring的基本使用的主要内容,如果未能解决你的问题,请参考以下文章

SpringBoot入门到精通-SpringBoot入门

SpringBoot入门到精通-SpringBoot集成SSM开发项目

SpringBoot入门到精通-SpringBoot启动流程

SpringBoot入门到精通-SpringBoot自动配置原理

SpringBoot入门到精通-SpringBoot自定义starter

Spring Boot从入门到精通-项目搭建