SpringBoot

本文详述了SpringBoot的起源与特性,探讨了其零XML配置的优势,并逐步介绍了如何构建基于SpringBoot的SpringMVC项目。文章还涵盖了SpringBoot的配置文件管理、目录结构,以及与Mybatis、PageHelper、Druid、LogBack、FreeMarker等的整合。此外,还讲解了Thymeleaf模板引擎的使用、SpringBoot开发者工具、异常处理、单元测试和Quartz任务调度等内容,全面解析SpringBoot的核心功能与实战应用。
摘要由CSDN通过智能技术生成

SpringBoot(零xml配置的Spring框架)

1Spring缺点

(1)Spring组件是轻量级的,但是它的配置确是重量级的

(2)依赖版本之间的冲突

2SpringBoot概念

SpringBoot是Spring公司的一个顶级项目,使用它在编写项目时不需要编写xml文件了,它主要用到的是启动器,启动器实际就是一个依赖,这个依赖中包含了整个这个技术的相关jar包,还包含了这个技术的自动配置,当然还需我们少量配置,在properties文件和yml文件中,使用SpringBoot整合其他技术时首先需要考虑导入启动器。

如果是Spring自己封装的启动器的artifact id名字满足:spring-boot-starter-xxxx

如果是第三方公司提供的启动器的artifact id名字满足:xxxx-spring-boot-starter

3SpringBoot特征

  1. 使用SpringBoot可以创建独立的Spring应用程序
  2. SpringBoot中直接嵌入了Tomcat、Jetty等web容器,所以不需部署war文件
  3. 通过使用启动器,简化项目构建配置
  4. 尽量的自动配置Spring和第三方库
  5. 绝对没有代码生成,也不需要xml配置

4SpringBoot版本介绍

SNAPSHOT:快照版,即开发版

CURRENT:最新版,但不一定是最稳定版

GA:正式发布的版本(2.2.10和2.1.17)

5SpringBoot的核心

起步依赖:起步依赖本质是一个Maven对象模型,简单说是将某种功能的坐标打包到一起,并提供一些默认的功能

自动配置:自动配置是SpringBoot的应用程序在启动的过程中,考虑众多因素,才决定配置该用哪个,不该用哪个

6第一个基于SpringBoot的SpringMVC项目

  (1)  spring-boot-starter-parent

spring-boot-starter-web

(2)新建启动类并添加注解并添加代码

启动类在启动时会做注解扫描,扫描位置为同包或者子包下的注解,所以启动类的位置应放于包的根下(一般放在和controller,service,mapper,pojo平级)

//启动类:是springboot项目程序入口

  @SpringBootApplication

  public class MyApplication {

    public static void main(String[] args) {

        SpringApplication.run(MyApplication.class,args);

    }

}

7启动类与启动器区别

(1)启动类表示项目的启动入口

(2)启动器表示jar包的坐标

8SpringBoot继承的实现方式

1中就是一个简单的继承方式

9SpringBoot依赖的实现方式

公司中可能出现必须继承某个项目,如果SpringBoot用了继承,就不能继承别的项目了,所以SpringBoot还提供了依赖的方式

<dependencyManagement>

    <dependencies>

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-parent</artifactId>

            <version>2.2.7.RELEASE</version>

            <type>pom</type>

            <scope>import</scope>

        </dependency>

    </dependencies>

  </dependencyManagement>
打包可能出问题

10IDEA快速构建SpringBoot项目

(1)

(2)

(3)

(4)

11SpringBoot原理分析

  1. 起步依赖原理分析
  2. 自动配置

12SpringBoot核心注解

@SpringBootApplication

@Target({ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

@SpringBootConfiguration

@EnableAutoConfiguration

@ComponentScan
@SpringBootConfiguration

@EnableAutoConfiguration

ServletWebServerFactoryAutoConfiguration,

底层会创建tomcat对象

开启自动配置
@ComponentScan

包扫描

13SpringBoot配置文件

学习文档:

https://docs.spring.io/spring-boot/docs/2.1.18.RELEASE/reference/html/common-application-properties.html   Common application properties

(1)properties格式

   配置Tomcat端口 server.port=8888

例如

server.port=8888

  spring.datasource.driver-class-name=

  spring.datasource.url=

  spring.datasource.data-username=

  spring.datasource.data-password=

   (2)yml格式

   yml格式要求:   【1】通过首行缩进表示上下级

                             【2】注意空格

                             【3】相同的部分只出现一次

                             【4】大小写敏感

例如          

server:

  port: 9999

  spring:

  datasource:

    password:

    url:

    driver-class-name:

    data-username:
  yml格式支持json

person: {age:18,name:zs}

person2:

  age: 18

  name: zs
  yml格式支持数组
city: [beijing,tianjin,shanghai,shenzhen]

city2:

  - beijing

  - tinajin

  - sahnghai

  - shenzhen

14配置文件存放位置

(1)当前项目根目录中【a】其次

效果图

(2)当前项目根目录下的一个/config子目录中【b】优先级最高

  

  (3)项目的resources即classpath根路径中(脚手架默认的位置)【c】最后

   (4)项目的resources即classpath根路径下的/config目录中【d】一般

15SpringBoot配置文件加载顺序(也就是优先级)

  1. 【1】同一个目录下,yml和properties都有,默认读取properties

          【2】同一个配置属性,在多个配置文件都配置了,默认使用第一个读取到的,后面读取的不覆盖前面读取到的

      2.不同位置配置文件的加载顺序,看13

b>a>d>c

总结c是脚手架,但是优先级最低

有config文件夹的优先级更高

根目录最高

16bootstrap配置文件加载优先于application

17SpringBoot目录结构

F:\workspace\springboot\demo1\src\main\resources

这个文件夹下不止有config文件夹,还应有三个文件夹

其中,public放公共的请求资源

static放静态资源,可以有js、css、图片、不被服务器解析(不用配静态资源放行),访问图片时不需要输入static了,因为是特殊含义的目录

templates放页面,不推荐使用jsp,官方推荐themleaf,这个文件夹相当于web下的webinfo,webinfo不能直接访问,只能通过转发的方式访问

 用public和templates做视图显示

18SpringBoot整合Mybatis

<!--springboot整合mybatis-->

  <dependency>

    <groupId>org.mybatis.spring.boot</groupId>

    <artifactId>mybatis-spring-boot-starter</artifactId>

    <version>2.1.1</version>

  </dependency>

  <!--mysql的驱动-->

  <dependency>

    <groupId>mysql</groupId>

    <artifactId>mysql-connector-java</artifactId>

    <version>8.0.11</version>

  </dependency>

桥梁也不需要了,但是web需要(ssm)

<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-web</artifactId>

  </dependency>
在启动类上加注解扫描mapper

此时在mapper层是用注解写的sql,如果想用xml写sql,则需要在pom.xml中写资源拷贝插件,如果不用资源拷贝插件,则把xml放在resource下,在resource下新建一个文件夹放xml,在配置文件中配置数据库的四部分和给实体类起别名,还要配置mapper-locations知名xml文件路径。

接口和xml分开写,可以使用插件MybatisX来定位

19SpringBoot整合PageHelper

SpringBoot整合PageHelper不需要做任何配置文件的配置,添加依赖后就可以直接使用

(1)添加依赖

<dependency>

    <groupId>com.github.pagehelper</groupId>

    <artifactId>pagehelper-spring-boot-starter</artifactId>

    <version>1.2.12</version>

</dependency>

PageInfo对象把集合对象和分页参数信息全部封装到一起

20SpringBoot整合Druid

在内存中一块空间,空间中放置N多个数据库连接对象。对象可以是处于活动状态,也可以是空闲(Idle)状态的。数据库获取连接对象时不在从数据库中获取连接对象,而是从数据库连接池中获取到连接对象,当获取到连接对象后,对象处于活动状态(Active),当连接对象使用完成后,在代码中进行连接关闭,实际上是把连接对象从活动状态变为空闲状态,不是真正的关闭。

在频繁访问数据库(访问频率特别高的)的应用中,使用数据库连接池效率高。

Druid是由阿里巴巴推出的数据库连接池。它结合了C3P0、DBCP、PROXOOL等数据库连接池的优点。之所以从众多数据库连接池中脱颖而出,还有一个重要的原因就是它包含控制台。

不要使用高版本的

spring:

  datasource:

    # 使用阿里的Druid连接池

    type: com.alibaba.druid.pool.DruidDataSource

    driver-class-name: com.mysql.cj.jdbc.Driver

    # 填写你数据库的url、登录名、密码和数据库名

    url: jdbc:mysql://127.0.0.1:3306/tingyu?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
username: root

    password: root

    druid:

      # 连接池的配置信息

      # 初始化大小,最小,最大

      initial-size: 5

      min-idle: 5

      maxActive: 20

      # 配置获取连接等待超时的时间

      maxWait: 60000

      # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒

      timeBetweenEvictionRunsMillis: 60000

      # 配置一个连接在池中最小生存的时间,单位是毫秒

      minEvictableIdleTimeMillis: 300000

      validationQuery: SELECT 1

      testWhileIdle: true

      testOnBorrow: false

      testOnReturn: false

      # 打开PSCache,并且指定每个连接上PSCache的大小

      poolPreparedStatements: true

      maxPoolPreparedStatementPerConnectionSize: 20

      # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙

      filters: stat,wall,slf4j

      # 通过connectProperties属性来打开mergeSql功能;慢SQL记录

      connectionProperties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000

      # 配置DruidStatFilter

      web-stat-filter:

        enabled: true

        url-pattern: "/*"

        exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"

      # 配置DruidStatViewServlet

      stat-view-servlet:

        url-pattern: "/druid/*"

        # IP白名单(没有配置或者为空,则允许所有访问)

        allow: 127.0.0.1,192.168.163.1
        # IP黑名单 (存在共同时,deny优先于allow)

        deny: 192.168.1.188

        禁用HTML页面上的“Reset All”功能

        reset-enable: false

        # 登录名

        login-username: admin

        # 登录密码

        login-password: 123456

  mybatis:

  mapper-locations: classpath:mybatis/*.xml

21SpringBoot整合LogBack

不需额外添加LogBack的依赖,启动器spring-boot-starter或者spring-boot-starter-web已经包含了LogBack的依赖

  1. 在classpath下查找文件logback-test.xml
  2. 如果文件不存在,则查找logback.xml

22SpringBoot整合FreeMarker

    (1)FreeMarker是一种模板引擎(非ajax)

板引擎是一种基于模板和要改变的数据来生成输出文本的通用工具

模板+数据模型=输出

freemarker并不关心数据的来源,只是根据模板的内容,将数据模型在模板中显示并输出文件(通常为html,也可以生成其它格式的文本文件)

   (2) FreeMarker的入门案例

    【1】导入FreeMarker启动器

    【2】在templates下新建html,然后改变后缀为.ftl

(3)前台接收值使用FreeMarker的语法 ${Request.msg},msg不是固定的,是后台设置的

(4)FreeMarker常用指令

    【1】注释: <#--和-->

    【2】插值:${Request.msg}

    【3】FTL指令:和HTML标记类似 <#开头

           1)循环指令:<#list 要遍历的集合名 as 遍历集合中每一个对象>

</#list>

例如:li是后台传过来的值,stu后边的属性其实用的反射get方法获得的,_index得到的是循环的下标,从0开始

<#list li as stu>

<tr>

   <th>${stu_index}</th>

<th>${stu.id}</th>

<th>${stu.name}</th>

<th>${stu.sex}</th>

</tr>

</#list>

           2)if指令   <#if >

</#if>

   例如: <#if  stu_index%2==0>

            <tr bgcolor=”red”>

</#if>

 <#if  stu_index%2!=0>

            <tr bgcolor=”black”>

</#if>

           3)支持运算符

           4)空值处理:??

   <#if stus??>

   <list stus as stu>

</#list>

</#if>

           5)内建函数

 内建函数语法格式:变量+?+函数名称

【4】文本:

23Thymeleaf

Thymeleaf将html在浏览器中正确显示,Thymeleaf放在SpringBoot项目中放入到resources/templates中。这个文件夹中的内容分是无法通过浏览器URL直接访问的(和WEB-INF效果一样),所有Thymeleaf必须先走控制器

使用步骤

(1)在pom.xml中添加Thymeleaf启动器

<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-thymeleaf</artifactId>

    <version>2.4.2</version>

  </dependency>

(2)为了有提示,修改html页面中<html>标签

 修改为<html xmlns:th="http://www.thymeleaf.org" >

(3)写控制器,因为必须走控制器

 自动增加前缀后缀
【1】thymeleaf的前缀后缀
 

【2】freemarker的前缀后缀
 

它是根据加的启动器的不同来区分是thymeleaf还是freemarker
 

 
怎么使用thymeleaf接受后台数据?
th:text 是把值放到双标签内部
th:value是把值放到单标签的value属性中
 

效果
 

 

24Thymeleaf语法

(1)th:text(双标签)

<!--直接向标签内部填充内容,清空原有内容-->

  <span th:text="shuai"></span>

  <!--从作用域中获取name输入到标签-->

  <span th:text="${name}"></span>

(2)th:value(单标签)

表单元素,设置表单元素value属性值

<input type="text" th:value="${name}"/>

(3)th:if

进行逻辑判断,如果成立该标签生效(显示),如果不成立,该标签无效(不显示)

注意:判断条件中逻辑判断符号写在${}外面

(4)th:each

li是后台传的集合,stu是集合中每一个对象,$不能直接用,必须依附于标签

<table>

    <tr th:each="stu:${li}">

        <th th:text="${stu.id}"></th>

        <th th:text="${stu.name}"></th>

        <th th:text="${stu.age}"></th>

        <th th:text="${stu.sex}"></th>

        <th>操作</th>

    </tr>

  </table>

如果想要判断奇数行还是偶数行在每一个对象后面加一个属性(随便起)i,然后在${i}去打点调方法

如果想要实现隔行变色,使用th:class

th:class=${i.even}?a:b

(5)th:href

删除时这样写不行<th <a href="remove?id=${id}">删除</a></th>

删除时这样写也不行<th<a th:href="remove?id=${id}">删除</a></th>

怎么写呢?

<th<a th:href="@{remove(id=${stu.id},name='zs')}">删除</a></th>

(6)th:onclick

在触发事件时

<th<a href="javascript:void(0)" onclick="remove(${stu.id})">删除</a></th>

以上写法不行

怎么写呢?(加引号)

<th<a href="javascript:void(0)" onclick="remove('+${stu.id}+')">删除</a></th>

总结:什么时候加th,什么时候不加th呢?

如果用到后台的值了(java代码),就需要加th,如果是正常的写法则不用

25Thymeleaf字符串操作

Thymeleaf提供了一些内置对象,内置对象可直接在模板中使用。这些对象是以#引用的。

(1)使用内置对象的语法

【1】引用内置对象需要使用#

【2】大部分内置对象的名称都以s结尾。如:strings、numbers、dates

${#strings.isEmpty(key)}

判断字符串是否为空,如果为空返回true,否则返回false

${#strings.contains(msg,'T')}

判断字符串是否包含指定的子串,如果包含返回true,否则返回false

${#strings.startsWith(msg,'a')}

判断当前字符串是否以子串开头,如果是返回true,否则返回false

${#strings.endsWith(msg,'a')}

判断当前字符串是否以子串结尾,如果是返回true,否则返回false

${#strings.length(msg)}

返回字符串的长度

${#strings.indexOf(msg,'h')}

查找子串的位置,并返回该子串的下标,如果没找到则返回-1

(2)日期格式化处理

${#dates.format(key)}

格式化日期,默认的以浏览器默认语言为格式化标准

${#dates.format(key,'yyyy/MM/dd')}

按照自定义的格式做日期转换

${#dates.year(key)}

${#dates.month(key)}

${#dates.day(key)}

Year:取年

Month:取月

Day:取日

26Thymeleaf操作域对象

(1)HttpServletRequest

request.setAttribute("req", "HttpServletRequest");

<span th:text="${#httpServletRequest.getAttribute('req')}"></span>

<span th:text="${#request.getAttribute('req')}"></span>

(2) HttpSession

request.getSession().setAttribute("ses", "HttpSession");

<span th:text="${session.ses}"></span><br/>

<span th:text="${#session.getAttribute('ses')}"></span><br/>

(3) ServletContext

request.getSession().getServletContext().setAttribute("app", "Application");

<span th:text="${application.app}"></span>

<span th:text="${#servletContext.getAttribute('app')}"></span>

27SpringBoot开发者工具

使用开发者工具包不需要重启。监听内容改变

(1)在pom.xml中添加依赖

<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-devtools</artifactId>

    <version>2.4.2</version>

  </dependency>

(2)设置IDEA自动编译

(3)修改Registry

Ctrl+Shift+Alt+/

28SpringBoot打包

点击IDEA右侧Maven -- > Lifecycle --> install

打包后的内容出现在target根目录

1.1运行jar包项目

① 在本地windows系统中运行

把此jar粘贴到任意目录,示例粘贴到D根目录下

启动windows命令行。依次输入:

# d:

# java-jar 文件名.jar

也可以新建一个批处理文件,例如:run.bat,在文件中添加

d:

java -jar 文件名.jar

② 部署到linux

和windows步骤一样。把jar上传到linux后放入到任意目录中,进入到jar所在目录       后执行java -jar 文件.jar 就可以运行。

也可以在jar所在文件夹中新建一个文件,执行运行文件。

# vim startup.sh

文件中输入java -jar 文件.jar

# chmod a+x startup.sh

# ./startup

1.2 SpringBoot项目打包成war包

① 如果我们当前的maven项目本身就是war类型的项目,直接打包即可

但是如果我们当前的maven项目是jar类型的项目,我们需要将项目修改

为war类型,修改项目的pom文件,使用packaging标签设置值为war

并且需要在项目中创建webApp文件夹,并设置为资源文件夹。

② 在SpringBoot的pom文件中将web启动器中的tomcat依赖排除

因为我们打包的war项目要放在自己的tomcat服务器中运行,需要

排出SpringBoot项目内置的tomcat。然后再手动的将tomcat插件

依赖过来,并设置其scope值为provided。

<!--配置SpringBoot的web启动器-->

    <dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-web</artifactId>

    <!--排除web启动中自动依赖的tomcat插件-->

    <exclusions>

        <exclusion>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-tomcat</artifactId>

        </exclusion>

    </exclusions>

    </dependency>

    <!--

    手动依赖tomcat插件,但是表明项目打包时该依赖不会被打进去,目的主要是保证开发阶段本地SpringBoot

    项目可以正常运行

-->

    <dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-tomcat</artifactId>

    <!--打包的时候可以不用包进去,别的设施会提供。事实上该依赖理论上可以参与编译,测试,运行等周期。

        相当于compile,但是打包阶段做了exclude操作-->

    <scope>provided</scope>

    </dependency>

③   SpringBoot的启动类继承SpringBootServletInitializer,并重写configure

@SpringBootApplication

@MapperScan("com.bjsxt.mapper")

    public class MyApplication extends SpringBootServletInitializer {

    //重写配置方法

    @Override

    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {

        return application.sources(MyApplication.class);

    }

    public static void main(String[] args) {

        //启动SpringBoot

        SpringApplication.run(MyApplication.class,args);

    }

}

④ 使用install命令打包项目,并将war包放到tomcat下的webapps下,启动
              tomcat即可。

⑤如果我们使用的是tomcat7则需要将javax.el-api-3.0.0.jar包放到tomcat下   的lib目录中。

29异常页面

默认情况,Spring Boot项目错误页面如下。

当项目实际上线,如果给用户显示这个页面就不是很友好。当系统出现异常时应该给用户显示更加友好的错误页面。

  1. 设置具体的状态码页面

在templates/下新建error文件夹,在error中新建:状态.html的页面。例如当出现500时显示的页面为500.html

2使用x进行模糊匹配

当出现5开头状态码的错误时,显示页面可以命名为5xx.html

当出现50开头状态码的错误时,显示页面可以命名为50x.html

3统一错误显示页面

在templates下新建error.html。如果项目中不存在具体状态码的页面或没有使用x成功匹配的页面时,显示error.html作为错误显示页面。

十七、异常处理机制

在Spring Boot项目中除了设置错误页面,还可以通过注解实现错误处理。

常见方式如下:

在控制器类中添加一个方法,结合@ExceptionHandler。但是只能对当前控制器中方法出现异常进行解决。

新建全局异常类,通过@ControllerAdvice结合@ExceptionHandler。当全局异常处理和局部处理同时存在时,局部生效(就近原则)

    1. 通过@ExceptionHandler注解处理异常
      1. 修改Controller
@Controller

    public class UsersController {

    

    @RequestMapping("showInfo")

    public String showInfo(){

        String str = null;

        str.length();

        return "ok";

    }

    

    @ExceptionHandler(value = {java.lang.NullPointerException.class} )

    public ModelAndView nullpointExcepitonHandler(Exception e){

        ModelAndView mv = new ModelAndView();

        mv.addObject("err",e.toString());

        mv.setViewName("error1");

        return mv;

    }

}

    1. 通过@ControllerAdvice与@ExceptionHandler注解处理异常
      1. 创建全局异常处理类
/**

 * 全局异常处理类

 */

    @ControllerAdvice

    public class GlobalException {

    

    @ExceptionHandler(value = {java.lang.NullPointerException.class} )

    public ModelAndView nullpointExcepitonHandler(Exception e){

        ModelAndView mv = new ModelAndView();

        mv.addObject("err",e.toString());

        mv.setViewName("error1");

        return mv;

    }

    

    @ExceptionHandler(value = {java.lang.ArithmeticException.class} )

    public ModelAndView arithmeticExceptionHandler(Exception e){

        ModelAndView mv = new ModelAndView();

        mv.addObject("err",e.toString());

        mv.setViewName("error2");

        return mv;

    }

}

    1. 通过SimpleMappingExceptionResolver对象处理异常
      1. 创建全局异常处理类
/**

 * 全局异常

 * SimpleMappingExceptionResolver

 */

    @Configuration

    public class GlobalException2 {

    

    /**

     * 此方法返回值必须是SimpleMappingExceptionResolver对象

     * @return

     */

    @Bean

    public SimpleMappingExceptionResolver getSimpleMappingExceptionResolver(){

        SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();

        Properties properties = new Properties();

        /**

         * 参数一:异常类型,并且是全名

         * 参数二:视图名称

         */

        properties.put("java.lang.NullPointerException","error3");

        properties.put("java.lang.ArithmeticException","error4");

    

        resolver.setExceptionMappings(properties);

        return resolver;

    }

    

}

    1. 通过自定义HandlerExceptionResolver对象处理异常
      1. 创建全局异常处理类
/**

 * 自定义HandlerExceptionResolver对象处理异常

 * 必须要实现HandlerExceptionResolver

 */

    @Configuration

    public class GlobalException3 implements HandlerExceptionResolver {

    @Override

    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler, Exception e) {

        ModelAndView mv = new ModelAndView();

        //判断不同异常类型,做不同视图的跳转

        if(e instanceof NullPointerException){

                mv.setViewName("error5");

        }

        if(e instanceof ArithmeticException){

                mv.setViewName("error6");

        }

        mv.addObject("error",e.toString());

        return mv;

    }

}

30SpringBoot整合junit

  1. 添加启动器
<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-test</artifactId>

    </dependency>

  1. 编写测试类

在src/main/test里面新建com.bjsxt.MyTest

注意:

  1. 测试类不能叫做Test
  2. 测试方法必须是public
  3. 测试方法返回值必须是void
  4. 测试方法必须没有参数
//告诉SpringBoot使用哪个单元测试工具

    @RunWith(SpringJUnit4ClassRunner.class)

    //当前类为测试类,classes指定哪个类为启动类

    @SpringBootTest(classes = MyApplication.class)

    public class MyTest {

    @Autowired

    UserMapper userMapper;

    @Autowired

    private UserService userService;

    @Test

    public void test(){

        User user = userMapper.selectById(1L);

        System.out.println(user);

        System.out.println(userService.test());

    }

}

31SpringBoot整合Quartz

  1. SpringBoot中Scheduled代码实现

新建Maven项目SpringQuartz。

    1. 添加依赖

由于spring-boot-starter-web并没有依赖spring-conext-support,所以需要单独添加此依赖。

<parent>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-parent</artifactId>

    <version>2.1.13.RELEASE</version>

    </parent>

    <dependencies>

    <dependency>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-web</artifactId>

    </dependency>

    <dependency>

        <groupId>org.springframework</groupId>

        <artifactId>spring-context-support</artifactId>

    </dependency>

    </dependencies>
    1. 创建启动类

新建com.bjsxt.QuartzApplication启动类

@SpringBootApplication

@EnableScheduling

    public class QuartzApplication {

    public static void main(String[] args) {

        SpringApplication.run(QuartzApplication.class,args);

    }

}

    1. 新建定时任务

新建com.bjsxt.scheduled.DemoScheduled类。

注意类上有@Component注解,启动项目就需要加载类及类中的@Scheduled注解。

@Component

    public class DemoScheduled {

    @Scheduled(cron="0/2 * * * * *")

    public void testScheduled(){

        System.out.println("test scheduled");

    }

}

  1.  cron表达式

Cron表达式是一个字符串,分为6或7个域,每一个域代表一个含义

Cron有如下两种语法格式:

(1) Seconds Minutes Hours Day Month Week Year

(2)Seconds Minutes Hours Day Month Week

    1. 结构

corn从左到右(用空格隔开):

秒 分 小时 月份中的日期 月份 星期中的日期 年份

    1. 各字段的含义

位置

时间域名

允许值

允许的特殊字符

1

0-59

, - * /

2

分钟

0-59

, - * /

3

小时

0-23

, - * /

4

1-31

, - * / L W C

5

1-12

, - * /

6

星期

1-7

, - * ? / L C #

7

年(可选)

1970-2099

, - * /

Cron表达式的时间字段除允许设置数值外,还可使用一些特殊的字符,提供列表、范围、通配符等功能,细说如下:

●星号(*):可用在所有字段中,表示对应时间域的每一个时刻,例如,*在分钟字段时,表示“每分钟”;

●问号(?):该字符只在日期和星期字段中使用,它通常指定为“无意义的值”,相当于占位符;

●减号(-):表达一个范围,如在小时字段中使用“10-12”,则表示从10到12点,即10,11,12;

●逗号(,):表达一个列表值,如在星期字段中使用“MON,WED,FRI”,则表示星期一,星期三和星期五;

●斜杠(/):x/y表达一个等步长序列,x为起始值,y为增量步长值。如在分钟字段中使用0/15,则表示为0,15,30和45秒,而5/15在分钟字段中表示5,20,35,50,你也可以使用*/y,它等同于0/y;

●L:该字符只在日期和星期字段中使用,代表“Last”的意思,但它在两个字段中意思不同。L在日期字段中,表示这个月份的最后一天,如一月的31号,非闰年二月的28号;如果L用在星期中,则表示星期六,等同于7。但是,如果L出现在星期字段里,而且在前面有一个数值X,则表示“这个月的最后X天”,例如,6L表示该月的最后星期五;

●W:该字符只能出现在日期字段里,是对前导日期的修饰,表示离该日期最近的工作日。例如15W表示离该月15号最近的工作日,如果该月15号是星期六,则匹配14号星期五;如果15日是星期日,则匹配16号星期一;如果15号是星期二,那结果就是15号星期二。但必须注意关联的匹配日期不能够跨月,如你指定1W,如果1号是星期六,结果匹配的是3号星期一,而非上个月最后的那天。W字符串只能指定单一日期,而不能指定日期范围;

●LW组合:在日期字段可以组合使用LW,它的意思是当月的最后一个工作日;

●井号(#):该字符只能在星期字段中使用,表示当月某个工作日。如6#3表示当月的第三个星期五(6表示星期五,#3表示当前的第三个),而4#5表示当月的第五个星期三,假设当月没有第五个星期三,忽略不触发;

● C:该字符只在日期和星期字段中使用,代表“Calendar”的意思。它的意思是计划所关联的日期,如果日期没有被关联,则相当于日历中所有日期。例如5C在日期字段中就相当于日历5日以后的第一天。1C在星期字段中相当于星期日后的第一天。

Cron表达式对特殊字符的大小写不敏感,对代表星期的缩写英文大小写也不敏感。

例子:

@Scheduled(cron = "0 0 1 1 1 ?")//每年一月的一号的1:00:00 执行一次

 @Scheduled(cron = "0 0 1 1 1,6 ?") //一月和六月的一号的1:00:00 执行一次

@Scheduled(cron = "0 0 1  1 1,4,7,10 ?") //每个季度的第一个月的一号的1:00:00 执行一次

@Scheduled(cron = "0 0 1  1 * ?")//每月一号 1:00:00 执行一次

 @Scheduled(cron="0 0 1 * * *") //每天凌晨1点执行一次

// 每月 星期12356  8点 10分 15s

Cron = 15 10  8  ?  *  1,2,3,5,6

  1.  Scheduled简介

Scheduled是Spring3.0后内置的定时任务器。通过Scheduled可以完成周期的执行一些功能。存在于spring-conext-support.jar中。

在SpringBoot中使用Scheduled非常简单,只需要在对应的方法上添加@Scheduled注解在配置对应的参数就可以完成。

  1.  Quartz
    1. 简介

官方解释

Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目。可以方便的继承在Java项目中完成任务调度功能。总体功能和java.util.Timer很像,但是要比Timer功能更加强大。且不像Scheduler执行一个固定的任务,在Quartz可以对任务进行操作,新增任务,删除任务等。

例如:

每天固定时间执行任务!

每隔2天执行一次任务!

这些都是任务调度。Quartz都可以轻松地完整这些事情。

5.2核心

Quartz核心包含四个概念。

5.2.1Job

表示一个工作,要执行的具体内容。

5.2.2JobDetail--完成一件怎样的事情

表示一个具体的可执行的调度任务。JobDetail除了包含Job还包含了任务调度和策略。

5.2.3Trigger--什么时候去调用

触发器。配置调度参数,定义什么时候去调用。

5.2.4Scheduler--结合上面两者什么时间完成XX事情

表示调度容器。Scheduler可以包含多个JobDetail和Trigger。

案例: 项文峰中午3点 抽田璐 

JobDetail:项文峰爱抚田璐

    Trigger:中午3点

Scheduler:我就是调度员--》中午3点项文峰爱抚田璐

4.3入门案例实现

1依赖引入

<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-web</artifactId>

    </dependency>

    <dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-quartz</artifactId>

    </dependency>

    

    <dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-test</artifactId>

    </dependency>

2Job工作定义

public class MyJob  implements Job {

    @Override

    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {

        System.out.println("执行了我的任务--时间为:"+new Date().toLocaleString());

    }

}

3定义实现执行过程

@RunWith(SpringJUnit4ClassRunner.class)

    @SpringBootTest(classes = SchedApplication.class)

    public class JobTest {

    @Test

    public void testAdd() {

        //[A]创建job对象--完成一样怎样的事情

        JobDetail jobDetail = JobBuilder.newJob(MyJob.class).build();

        //[B]创建触发器对象 --什么时间去做这件事情

         //每秒执行一次 永远执行

        Trigger   trigger=TriggerBuilder.newTrigger().withSchedule(SimpleScheduleBuilder.repeatSecondlyForever()).build();

        //[C]Scheduler 对象  相当于结合在什么时间做什么事情

        try {

            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

            scheduler.scheduleJob(jobDetail,trigger);

            //启动

            scheduler.start();

        } catch (SchedulerException e) {

            e.printStackTrace();

        }

        //为了看到执行过程所以加上了睡眠

        try {

            Thread.sleep(20000);

        } catch (InterruptedException e) {

            e.printStackTrace();

        } }}

5 SpringBoot整合Quartz引入数据库实现

新建Maven项目SpringQuartz

5.3新建数据库导入数据

在MySQL中新建数据库quartz。

运行quartz.sql文件,导入数据文件(在当前版本中使用数据库初始化文件属性always不生效。)

5.4添加依赖



    <dependencies>

    <dependency>

        <groupId>mysql</groupId>

        <artifactId>mysql-connector-java</artifactId>

        <version>8.0.11</version>

    </dependency>

    

    <dependency>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-jdbc</artifactId>

    </dependency>

    </dependencies>

5.5配置配置文件

新建application.yml,并配置数据源

spring:

    datasource:

  username: root

  driver-class-name: com.mysql.cj.jdbc.Driver

  password: root

  url: jdbc:mysql://127.0.0.1:3306/maven?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8

    quartz:
  jdbc:

    initialize-schema: never

  job-store-type: jdbc
转存失败重新上传取消

5.6新建静态类

新建com.bjsxt.statics.QuartzStatic。为了记录每次执行Job的时间,定义一个静态常量。

public class QuartzStatic {

    public static long preTime=0L;

}

5.7新建Job

新建com.bjsxt.job.MyJob定义Job的内容。

public class MyJob implements Job {

    @Override

    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {

        long currTime = System.currentTimeMillis();

        if(QuartzStatic.preTime==0L){

            QuartzStatic.preTime = currTime;

        }

        System.out.println("execute执行-- MyJob"+(currTime- QuartzStatic.preTime));

        QuartzStatic.preTime = currTime;

    }

}

5.8新建启动类

新建com.bjsxt.QuartzApplication

@SpringBootApplication

    public class QuartzApplication {

    public static void main(String[] args) {

        SpringApplication.run(QuartzApplication.class,args);

    }

}

5.9新建测试类

新建测试类com.bjsxt.MyTest。

在测试类中测试Quartz中新增、修改、删除、暂停、恢复、查询等功能。在每个功能执行完成后要注意数据库中数据的变化。

@Autowired

  private   Scheduler  scheduler;

    

    //添加定时器任务

    @Test

    public    void     add(){

     //引入目前的job

     JobDetail jobDetais = JobBuilder.newJob(MyJob.class).withIdentity("job1", "jobgroup1").build();

     jobDetais.getJobDataMap().put("data-key","data-value");

    

     //新建触发器

     Trigger trigger = TriggerBuilder.newTrigger()

                        .withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ?"))

                        .withIdentity("trigger1", "triggergroup1")

                        .build();

     try {

          //使用scheduler对象把job  trigger 进行关联

          Date date = scheduler.scheduleJob(jobDetais, trigger);

          scheduler.start();

     } catch (SchedulerException e) {

          e.printStackTrace();

     }}
//修改操作

    @Test

    public void update(){

     try {

          TriggerKey triggerKey = TriggerKey.triggerKey("trigger1", "triggergroup1");

    

          CronTrigger trigger = (CronTrigger)scheduler.getTrigger(triggerKey);

          trigger= trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?")).build();

    

          scheduler.rescheduleJob(triggerKey,trigger);

     } catch (SchedulerException e) {

          e.printStackTrace();

     }

}

//删除实现

    public void testDeleteJob(){

     try {

          boolean result = scheduler.deleteJob(new JobKey("job-name", "job-group"));

          System.out.println("果:"+result);

     } catch (SchedulerException e) {

          e.printStackTrace();

     }

}

@Test

    public void testQueryJobs(){

     try {

          GroupMatcher<JobKey> groupMatcher = GroupMatcher.anyJobGroup();

          Set<JobKey> jobKeySet = scheduler.getJobKeys(groupMatcher);

          for(JobKey jobKey : jobKeySet){

               List<? extends Trigger> listTriggers = scheduler.getTriggersOfJob(jobKey);

               System.out.println("=========================================");

               for(Trigger trigger : listTriggers){

                    System.out.println(jobKey.getName());

                    System.out.println(jobKey.getGroup());

                    System.out.println(scheduler.getTriggerState(trigger.getKey()));

                    System.out.println(((CronTrigger) trigger).getCronExpression());

               }

               System.out.println("==========================================");

          }

     } catch (SchedulerException e) {

          e.printStackTrace();

     }

    

}

//暂停工作

 public void testPauseJob(){

      try {

           JobKey jobKey = new JobKey("job-name", "job-group");

           scheduler.pauseJob(jobKey);

      } catch (SchedulerException e) {

           e.printStackTrace();

      }

 }

 //启动工作

 @Test

 public void testResumeJob(){

      try {

           JobKey jobKey = new JobKey("job-name", "job-group");

           scheduler.resumeJob(jobKey);

      } catch (SchedulerException e) {

           e.printStackTrace();

      }

 }

32SpringBoot中Bean管理

Spring Boot 由于没有XML文件,所以所有的Bean管理都放入在一个配置类中实现。

配置类就是类上具有@Configuration的类。这个类就相当于之前的applicationContext.xml

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JavaHenShuai

你的鼓励将是我创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值