当前位置: 首页>后端>正文

SpringBoot教程——检视阅读(下)

Spring Boot整合Thymeleaf

thymeleaf怎么读?英 [taim li:f] 美 [ta?m lif] 。百里香叶。

关于模板引擎

  1. 市面上主流的 Java 模板引擎有:JSP、Velocity、Freemarker、Thymeleaf。
  2. JSP本质也是模板引擎,Spring Boot官方推荐使用“Thymeleaf”模板引擎。

模板引擎的原理

模板引擎原理图如下,模板引擎的作用都是将模板(页面)和数据进行整合然后输出显示,区别在于不同的模板使用不同的语法,如 JSP 的JSTL表达式,以及JSP 自己的表达式和语法,同理 Thymeleaf 也有自己的语法。

SpringBoot教程——检视阅读(下),第1张

Spring Boot整合Thymeleaf

示例:

pom.xml导入Thymeleaf的依赖.

<dependencies>
        <!--web起步依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- thymeleaf -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
    </dependencies>
@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/thyme")
    public String thymeLeaf(Model model){
        model.addAttribute("message","thymeLeaf show");
        //跳转到templates/show.html
        return "show";
    }
   }

注意以下几点:

  • 模板文件(即页面)必须放在/resources/templates目录下,否则无法渲染。
  • Thymeleaf标签都是以th开头的。

show.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>SpringBoot整合Thymeleaf</title>
</head>
<body>
<span th:text="${message}"></span>
</body>
</html>

输出:

SpringBoot教程——检视阅读(下),第2张

Thymeleaf基本语法

变量输出

方法代码

//变量输出
@RequestMapping("/demo2")
public String demo2(Model model){
    model.addAttribute("name", "张三");
    return "demo2";
}

页面代码

<h3>变量输出</h3>
<h4 th:text="${name}"></h4>
<h4 th:text="李四"></h4>
条件判断及迭代遍历、域对象使用、超链接

show.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>SpringBoot整合Thymeleaf</title>
</head>
<body>
<span th:text="${message}"></span>

<h3>条件判断</h3>
<div th:if="${gender} == '男'">
    这是一位男性朋友
</div>
<div th:if="${gender} == '女'">
    这是一位女性朋友
</div>
<br/>
<div th:switch="${grade}">
    <span th:case="1">这是1的情况</span>
    <span th:case="2">这是2的情况</span>
    <span th:case="3">这是3的情况</span>
</div>
<h3>迭代遍历</h3>
<table border="1">
    <tr>
        <td>编号</td>
        <td>姓名</td>
        <td>年龄</td>
    </tr>
    <tr th:each="user : ${list}">
        <td th:text="${user.id}"></td>
        <td th:text="${user.name}"></td>
        <td th:text="${user.age}"></td>
    </tr>
</table>
<h3>域对象数据的获取</h3>
request: <span th:text="${#httpServletRequest.getAttribute('request')}"></span><br/>
session: <span th:text="${session.session}"></span><br/>
application: <span th:text="${application.application}"></span><br/>
<h3>超链接的语法</h3>
<a th:href="@{~/user/thyme}">访问demo1</a><br/>

<a th:href="@{~/user/thyme(id=1,name=eric)}">访问demo1,传递参数</a>
</body>
</html>
@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/thyme")
    public String thymeLeaf(Model model, HttpServletRequest request){
        model.addAttribute("message","thymeLeaf show");
        model.addAttribute("gender","男");
        model.addAttribute("grade",2);
        List<User> list = new ArrayList<User>();
        for (int i = 0; i < 3; i++) {
            User user = new User();
            user.setId(ThreadLocalRandom.current().nextInt());
            user.setAge(ThreadLocalRandom.current().nextInt(100));
            user.setName(UUID.randomUUID().toString());
            list.add(user);
        }
        //把数据存入model
        model.addAttribute("list", list);
        //request
        request.setAttribute("request", "request's data");
        //session
        request.getSession().setAttribute("session", "session's data");
        //application
        request.getSession().getServletContext().setAttribute("application", "application's data");
        //跳转到templates/show.html
        return "show";
    }
  }

输出:

SpringBoot教程——检视阅读(下),第3张

Spring Boot整合FreeMarker

//跳过

Spring Boot整合MyBatis

前置条件:

CREATE TABLE `t_user` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
  `name` varchar(64) NOT NULL COMMENT '姓名',
  `dept` varchar(254) NOT NULL COMMENT '部门',
  `phone` varchar(16) NOT NULL COMMENT '电话',
  `height` decimal(10,2) DEFAULT NULL COMMENT '身高',
  `create_emp` bigint(20) NOT NULL COMMENT '创建人',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `modify_emp` bigint(20) DEFAULT NULL COMMENT '修改人',
  `modify_time` datetime DEFAULT NULL COMMENT '修改时间',
  PRIMARY KEY (`id`),
  KEY `idx_name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COMMENT='用户表';

示例:

pom.xml——导入mybatis和mysql驱动程序

<dependencies>
        <!--web起步依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--mybatis 起步依赖-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.1.1</version>
        </dependency>
        <!-- MySQL 连接驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.46</version>
        </dependency>
    </dependencies>

application.yml——配置数据源连接参数,及mybatis相关配置。

spring:
    datasource: #修改数据库连接配置
        url: jdbc:mysql://localhost:3306/hello_mybatis?characterEncoding=UTF8
        driver-class-name: com.mysql.jdbc.Driver
        username: root
        password: 123456

# mybatis配置
mybatis:
  type-aliases-package: com.self.pojo # 别名目录
public class User {

    private Integer id;

    @NotEmpty(message = "姓名不能为空")
    private String name;
    @Min(1)
    private Integer age;
    @Email(message = "邮箱地址不正确")
    private String email;
    @NotEmpty(message = "描述不能为空")
    @Length(min = 5, max = 100, message = "描述必须在5-100个字之间")
    private String desc;

    /**
     * 部门,帝国
     */
    private String dept;
    /**
     * 联系号码
     */
    private String phone;
    /**
     * 身高
     */
    private BigDecimal height;
    /**
     * 创建人
     */
    private Long createEmp;
    /**
     * 创建时间
     */
    private Date createTime;
    /**
     * 修改人
     */
    private Long modifyEmp;
    /**
     * 修改时间
     */
    private Date modifyTime;
    //...
    }
//必须给Dao接口加上@Mapper,这样Spring Boot在启动时才能扫描到Dao接口,并为其生成代理对象。
@Mapper
//装饰用,告诉spring这是个dao注册bean,不加@Repository的话IDEA会提示这个bean无法@Autowired自动依赖
@Repository
public interface UserDao {

    public List<User> getUsers();
}

UserDao.xml——Dao映射配置,在Dao接口相同目录下建立同名的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.self.dao.UserDao">

    <!-- 查询所有用户 -->
    <select id="getUsers" resultType="User">
        select * from t_user where 1=1
    </select>
</mapper>
@Controller
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserDao userDao;
    
    @RequestMapping("/showAll")
    @ResponseBody
    public List<User> list(){
        //模拟用户数据
        List<User> list = userDao.getUsers();
        return list;
    }
}

启动类不变,输出:

SpringBoot教程——检视阅读(下),第4张

整合Spring Data JPA

示例:

pom.xml——添加Spring Data JPA的依赖

<dependencies>
        <!--web起步依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- springBoot JPA 的起步依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <!-- MySQL 连接驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.46</version>
        </dependency>
    </dependencies>

application.yml

spring:
  datasource: #修改数据库连接配置
    url: jdbc:mysql://localhost:3306/mybatis?characterEncoding=UTF8
    driver-class-name: com.mysql.jdbc.Driver
    username: root
    password: root
# jpa配置
  jpa:
    show-sql: true #控制台输出生成的SQL语句
    generate-ddl: true # 自动建表

项目使用Spring Data JPA,所以在Pojo实体中必须添加Jpa的映射注解,和数据库表进行一一映射。

如果pojo字段不是一一映射,比如比数据库多了字段,则会导致执行失败。

import javax.persistence.*;
@Entity
@Table(name="t_user")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @NotEmpty(message = "姓名不能为空")
    private String name;
    /**
     * 部门,帝国
     */
    private String dept;
    /**
     * 联系号码
     */
    private String phone;
    /**
     * 身高
     */
    private BigDecimal height;
    /**
     * 创建人
     */
    private Long createEmp;
    /**
     * 创建时间
     */
    private Date createTime;
    /**
     * 修改人
     */
    private Long modifyEmp;
    /**
     * 修改时间
     */
    private Date modifyTime;
//...
}

Spring Data JPA提供了两个核心接口,我们项目中一般选择继承它们:

  • JpaRepository接口:拥有CRUD,分页,排序等方法
  • JpaSpecificationExecutor接口:拥有组合条件搜索方法

public interface ScheduleInfoDao extends JpaRepository<ScheduleInfo, Long>, JpaSpecificationExecutor<ScheduleInfo> {

    @Query(value = "select s from ScheduleInfo s where " +
            "(" +
            "(s.scheduleStartTime>?1 and s.scheduleEndTime<?2) " +
            "or (s.scheduleStartTime between ?1 and ?2 and s.scheduleEndTime between ?1 and ?2) " +
            "or (s.scheduleStartTime<?1 and s.scheduleEndTime>?2) " +
            "or (s.scheduleStartTime <?1 and s.scheduleEndTime >?1)" +
            "or (s.scheduleStartTime <?2 and s.scheduleEndTime >?2)" +
            "or (s.scheduleStartTime =?1 and s.scheduleEndTime =?2)) and s.childrenId IN ( ?4 ) and s.deleteFlag=0")
    List<ScheduleInfo> findByTimeCondition(String scheduleStartTime, String scheduleEndTime, Long id, List<Long> childrenId);
}
public interface UserDao extends JpaRepository<User, Integer>, JpaSpecificationExecutor<User> {
    /**
     * jpa语法根据username,group,deleteFlag查询
     */
    Children findByUsernameAndGroupAndDeleteFlag(String username, String group, Integer deleteFlag);

    /**
     * jpa语法查询group下deleteFlag状态下的列表
     */
    List<Children> findByGroupAndDeleteFlag(String group, Integer deleteFlag);

    /**
     * 查询小孩子列表
     *
     * @param list 入参
     */
    List<Children> getAllByIdInAndDeleteFlag(List<Long> list, Integer deleteFlag);
}
@Controller
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserDao userDao;

    @RequestMapping("/showAll")
    @ResponseBody
    public List<User> list(){
        //模拟用户数据
        List<User> list = userDao.findAll();
        return list;
    }
  }

输出:

SpringBoot教程——检视阅读(下),第4张

Spring Boot整合Redis

前提: 需要Windows启动Redis Server 。

解压redis压缩包。

打开一个 cmd 窗口 使用 cd 命令切换安装目录如 E:\redis 运行:

#启动redis服务器
redis-server.exe redis.windows.conf

验证redis是否启动成功,另外打开一个 cmd 窗口 使用 cd 命令切换安装目录如 E:\redis 运行:

#启动redis客户端
redis-cli.exe -h 127.0.0.1 -p 6379
#执行命令
set name mike
get name

示例:

pom.xml——导入Spring Data Redis依赖!

 <dependencies>
        <!--web起步依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 配置使用 redis 启动器 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
    </dependencies>

application.yml——Spring Boot的Redis配置

#host:代表Redis服务端地址
#port:Java连接Redis的端口
#database:操作的Redis的数据库索引
spring:
    redis:
        host: localhost # 默认localhost,需要远程服务器需要修改
        port: 6379  # 默认6379,如果不一致需要修改
        database: 0 # 代表连接的数据库索引,默认为0,

在Controller注入RedisTemplate模板对象,利用它来操作Redis数据库,这里写一个put方法,用于往Redis存入数据,一个get方法,从Redis获取数据。但需要注意的时候,如果操作的Pojo对象,该Pojo必须实现java.io.Serializable接口 。

@Controller
@RequestMapping("/user")
public class UserController {

    @Autowired
    private RedisTemplate redisTemplate;

    @RequestMapping("/load")
    @ResponseBody
    public String loadUsers(){
        List<User> list = userDao.findAll();
        for (User user : list) {
            redisTemplate.opsForValue().set(user.getName(),user);
        }
        return "success";
    }

    @RequestMapping(value = "/get",method = RequestMethod.GET)
    @ResponseBody
    public User getUser(String name){
       return (User) redisTemplate.opsForValue().get(name);
    }
  }
public class User implements Serializable {
    //...
}
请求:
先缓存redis
http://localhost:8080/user/load
从redis获取缓存数据
http://localhost:8080/user/get?name=艾米哈珀

输出:

SpringBoot教程——检视阅读(下),第6张

报错:Failed to serialize object using DefaultSerializer。这是因为传输对象没有实现序列号接口,无法序列号。

org.springframework.data.redis.serializer.SerializationException: Cannot serialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to serialize object using DefaultSerializer; nested exception is java.lang.IllegalArgumentException: DefaultSerializer requires a Serializable payload but received an object of type [com.self.pojo.User]

Spring Boot整合EhCache

EhCache简介

EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认CacheProvider。Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存,Java EE和轻量级容器。它具有内存和磁盘存储,缓存加载器,缓存扩展,缓存异常处理程序,一个gzip缓存servlet过滤器,支持REST和SOAP api等特点。

配置ehcache.xml——参数说明
参数名 说明
name 缓存名称
maxElementsInMemory 缓存最大个数
eternal 对象是否永久有效,一但设置了,timeout将不起作用
timeToIdleSeconds 设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大
timeToLiveSeconds 设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大
overflowToDisk 当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中
diskSpoolBufferSizeMB 这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区
maxElementsOnDisk 硬盘最大缓存个数
diskPersistent 是否缓存虚拟机重启期数据
diskExpiryThreadIntervalSeconds 磁盘失效线程运行时间间隔,默认是120秒。
memoryStoreEvictionPolicy 当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)
clearOnFlush 内存数量最大时是否清除

示例:

pom.xml

 <!--web起步依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--springboot 集成 junit 起步依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>2.1.6.RELEASE</version>
            <scope>test</scope>
        </dependency>

        <!-- 缓存坐标 -->
        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-cache -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
            <version>2.1.11.RELEASE</version>
        </dependency>
        <!-- Ehcache支持 -->
        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache</artifactId>
            <version>2.10.6</version>
        </dependency>

ehcache.xml

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">

    <diskStore path="java.io.tmpdir"/>

    <!-- defaultCache: 默认配置 -->
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            maxElementsOnDisk="10000000"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
        <persistence strategy="localTempSwap"/>
    </defaultCache>

    <!-- 缓存名称为user的配置 -->
    <cache name="user"
           maxElementsInMemory="10000"
           eternal="false"
           timeToIdleSeconds="120"
           timeToLiveSeconds="120"
           maxElementsOnDisk="10000000"
           diskExpiryThreadIntervalSeconds="120"
           memoryStoreEvictionPolicy="LRU">
        <persistence strategy="localTempSwap"/>
    </cache>
</ehcache>

application.yml

#配置EhCache的配置spring:
cache:
  ehcache:
    config: ehcache.xml

引导类中需要添加@EnableCaching注解,开启缓存功能 。

@SpringBootApplication
@EnableCaching // 开启缓存
public class MyBootApplication {

    public static void main(String[] args) {
        SpringApplication.run(MyBootApplication.class,args);
    }
}
@Service
public class UserService {

    @Cacheable(value = "user",key = "#id")
    public User findById(Integer id){
        System.out.println("执行了UserService获取User");
        User user = new User();
        user.setId(5);
        user.setName("林雨裳");
        user.setDept("艾米帝国");
        user.setPhone("911119");
        return user;
    }
}

@Cacheable的属性:

  • value:对应ehcache.xml的缓存配置名称(name属性值)
  • key:给缓存值起个key,便于Spring内部检索不同的缓存数据。#id这个语法代表把方法形参作为key。
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = MyBootApplication.class)
public class EhCacheTest {

    @Autowired
    private UserService userService;

    @Test
    public void testCache(){
        //第一次
        System.out.println(JSON.toJSONString(userService.findById(5)));
        //第二次
        System.out.println(JSON.toJSONString(userService.findById(5)));
    }
}

输出:

执行了UserService获取User
{"dept":"艾米帝国","id":5,"name":"林雨裳","phone":"911119"}
{"dept":"艾米帝国","id":5,"name":"林雨裳","phone":"911119"}

从结果可以看出,第一次调用Service的时候,到Service内部获取数据。但是第二次调用Service时已经不需要从Service获取数据,证明第一次查询的时候已经把Customer对象缓存到EhCache中。

EhCache常用注解

注解 说明
@Cacheable 主要针对方法配置,能够根据方法的请求参数对其进行缓存
@CacheConfig 统一配置本类的缓存注解的属性
@CachePut 保证方法被调用,又希望结果被缓存。与@Cacheable区别在于是否每次都调用方法,常用于更新
@CacheEvict 清空缓存

@Cacheable/@CachePut/@CacheEvict 主要的参数:

属性名 说明
value 缓存的名称,在 spring 配置文件中定义,必须指定至少一个 例如: @Cacheable(value=”mycache”) 或者 @Cacheable(value={”cache1”,”cache2”}
key 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写, 如果不指定,则缺省按照方法的所有参数进行组合 例如: @Cacheable(value=”testcache”,key=”#id”)
condition 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false, 只有为 true 才进行缓存/清除缓存 例如:@Cacheable(value=”testcache”,condition=”#userName.length()>2”)
unless 否定缓存。当条件结果为TRUE时,就不会缓存。 @Cacheable(value=”testcache”,unless=”#userName.length()>2”)
allEntries (@CacheEvict ) 是否清空所有缓存内容,缺省为 false,如果指定为 true, 则方法调用后将立即清空所有缓存 例如: @CachEvict(value=”testcache”,allEntries=true)
beforeInvocation (@CacheEvict) 是否在方法执行前就清空,缺省为 false,如果指定为 true, 则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法 执行抛出异常,则不会清空缓存 例如: @CachEvict(value=”testcache”,beforeInvocation=true)

具体参考一点

Spring Boot整合Junit

示例:

pom.xml

 <!--springboot 集成 junit 起步依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>2.1.6.RELEASE</version>
            <scope>test</scope>
        </dependency>
@RunWith(SpringJUnit4ClassRunner.class)
//重点是加入@SpringBootTest注解,属性classes用于加载引导类
@SpringBootTest(classes = MyBootApplication.class)
public class JUnitTest {

    @Test
    public void test() {
        System.out.println("Hello JUnit");
    }
}

输出:

Hello JUnit

Spring Boot整合Quartz

Quartz(石英)简介

Quartz 是一个完全由Java 编写的开源任务调度的框架,通过触发器设置作业定时运行规则,控制作业的运行时间。Quartz 定时器作用很多,比如,定时发送信息和定时生成报表等。 Quartz 框架主要核心组件包括调度器、触发器和作业。调度器作为作业的总指挥,触发器 作为作业的操作者,作业为应用的功能模块。其关系如图:

SpringBoot教程——检视阅读(下),第7张

示例:

pom.xml

  <!-- sping对schedule的支持 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
        </dependency>
        <!--Quartz运行必须依赖到spring-tx包 注意:spring-boot-starter-web已经依赖了,所以不需要再依赖,只需要知道Quartz运行必须依赖到spring-tx包 -->
<!--        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
        </dependency>-->
        <!-- Quartz支持 -->
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.2.1</version>
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-api</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
            </exclusions>
        </dependency>

Job任务类——我们想实现的定时任务业务代码写在这里。

public class CheckJob {

    public void task() {
        System.out.println("校验任务被触发,当前时间为:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
    }

}
public class ReminderJob {

    //具体定时任务
    public void task(){
        System.out.println("呼吸提醒任务被触发,当前时间为:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
    }
}

Quartz配置类——每个调度任务都对应一个配置类

@Configuration
public class CheckQuartzConfig {

    @Bean
    public CheckJob createCheckJob() {
        return new CheckJob();
    }

    /**
     * 创建任务
     */
    @Bean("checkJobDetail")
    public MethodInvokingJobDetailFactoryBean checkJobDetailFactoryBean(CheckJob job) {
        MethodInvokingJobDetailFactoryBean detailFactoryBean = new MethodInvokingJobDetailFactoryBean();
        //设置任务对象
        detailFactoryBean.setTargetObject(job);
        //设置任务方法
        detailFactoryBean.setTargetMethod("task");
        return detailFactoryBean;
    }
    /**
     * 触发器
     */
    @Bean("checkTrigger")
    public CronTriggerFactoryBean createTrigger(@Qualifier("checkJobDetail") MethodInvokingJobDetailFactoryBean bean) {
        CronTriggerFactoryBean triggerFactoryBean = new CronTriggerFactoryBean();
        triggerFactoryBean.setJobDetail(bean.getObject());
         // 每天11点30分触发执行一次
        triggerFactoryBean.setCronExpression("0 30 11 * * *");
        return triggerFactoryBean;
    }
    /**
     * 创建Schduler
     */
    @Bean("checkScheduler")
    public SchedulerFactoryBean createSchedulerFactoryBean(@Qualifier("checkTrigger") CronTriggerFactoryBean bean){
        SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
        //关联trigger
        schedulerFactoryBean.setTriggers(bean.getObject());
        return schedulerFactoryBean;
    }
}
@Configuration
public class QuartzConfig {

    @Bean
    public ReminderJob createReminderJob() {
        return new ReminderJob();
    }

    @Bean("reminderJobDetail")
    public MethodInvokingJobDetailFactoryBean reminderJobDetailFactoryBean(ReminderJob job) {
        MethodInvokingJobDetailFactoryBean detailFactoryBean = new MethodInvokingJobDetailFactoryBean();
        detailFactoryBean.setTargetObject(job);
        detailFactoryBean.setTargetMethod("task");
        return detailFactoryBean;
    }


    @Bean("reminderTrigger")
    public CronTriggerFactoryBean createTrigger(@Qualifier("reminderJobDetail") MethodInvokingJobDetailFactoryBean bean) {
        CronTriggerFactoryBean triggerFactoryBean = new CronTriggerFactoryBean();
        triggerFactoryBean.setJobDetail(bean.getObject());
         //定时任务3秒执行一次
        triggerFactoryBean.setCronExpression("0/3 * * * * *");
        return triggerFactoryBean;
    }

    @Bean("reminderScheduler")
    public SchedulerFactoryBean createSchedulerFactoryBean(@Qualifier("reminderTrigger") CronTriggerFactoryBean bean){
        SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
        schedulerFactoryBean.setTriggers(bean.getObject());
        return schedulerFactoryBean;
    }
}

运行引导类。

输出:

呼吸提醒任务被触发,当前时间为:2020-05-21 11:29:51
呼吸提醒任务被触发,当前时间为:2020-05-21 11:29:54
呼吸提醒任务被触发,当前时间为:2020-05-21 11:29:57
呼吸提醒任务被触发,当前时间为:2020-05-21 11:30:00
校验任务被触发,当前时间为:2020-05-21 11:30:00
呼吸提醒任务被触发,当前时间为:2020-05-21 11:30:03
呼吸提醒任务被触发,当前时间为:2020-05-21 11:30:06
呼吸提醒任务被触发,当前时间为:2020-05-21 11:30:09

Cron表达式扩展

Cron表达式在线工具

Cron表达式教程
CronTrigger

CronTriggers往往比SimpleTrigger更有用,如果您需要基于日历的概念,而非SimpleTrigger完全指定的时间间隔,复发的发射工作的时间表。 CronTrigger,你可以指定触发的时间表如“每星期五中午”,或“每个工作日9:30时”,甚至“每5分钟一班9:00和10:00逢星期一上午,星期三星期五“。 即便如此,SimpleTrigger一样,CronTrigger拥有的startTime指定的时间表时生效,指定的时间表时,应停止(可选)结束时间。

Cron表达式

cron的表达式被用来配置CronTrigger实例。 cron的表达式是字符串,实际上是由七子表达式,描述个别细节的时间表。这些子表达式是分开的空白,代表:

  1. Seconds
  2. Minutes
  3. Hours
  4. Day-of-Month
  5. Month
  6. Day-of-Week
  7. Year (可选字段)

例 "0 0 12 * WED" 在每星期三下午12:00 执行,

个别子表达式可以包含范围, 例如,在前面的例子里("WED")可以替换成 "MON-FRI", "MON, WED, FRI"甚至"MON-WED,SAT". “*” 代表整个时间段.

每一个字段都有一套可以指定有效值,如

Seconds (秒) :可以用数字0-59 表示,

Minutes(分) :可以用数字0-59 表示,

Hours(时) :可以用数字0-23表示,

Day-of-Month(天) :可以用数字1-31 中的任一一个值,但要注意一些特别的月份

Month(月) :可以用0-11 或用字符串 “JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV and DEC” 表示

Day-of-Week(每周):可以用数字1-7表示(1 = 星期日)或用字符口串“SUN, MON, TUE, WED, THU, FRI and SAT”表示

“/”:为特别单位,表示为“每”如“0/15”表示每隔15分钟执行一次,“0”表示为从“0”分开始, “3/20”表示表示每隔20分钟执行一次,“3”表示从第3分钟开始执行

“?”:表示每月的某一天,或第周的某一天

“L”:用于每月,或每周,表示为每月的最后一天,或每个月的最后星期几如“6L”表示“每月的最后一个星期五”

“W”:表示为最近工作日,如“15W”放在每月(day-of-month)字段上表示为“到本月15日最近的工作日”

““#”:是用来指定“的”每月第n个工作日,例 在每周(day-of-week)这个字段中内容为"6#3" or "FRI#3" 则表示“每月第三个星期五”

常用Cron表达式
0 15 10 * * * 每天10点15分触发
0 15 10 * * 2017 2017年每天10点15分触发
0 * 14 * * ? 每天下午的 2点到2点59分每分触发
0 0/5 14 * * ? 每天下午的 2点到2点59分(整点开始,每隔5分触发)
0 0/5 14,18 * * ? 每天下午的 2点到2点59分、18点到18点59分(整点开始,每隔5分触发)
0 0-5 14 * * ? 每天下午的 2点到2点05分每分触发
0 15 10 * 6L 每月最后一周的星期五的10点15分触发
0 15 10 * 6#3 每月的第三周的星期五开始触发

Spring Boot整合Task

Spring自身有一个定时任务技术,叫Spring Task,本文讲解在Spring Boot应用中如何使用Spring Task。

cron表达式复习:

序号 说明 必填 允许值 通配符
1 0-59 , - * /
2 0-59 , - * /
3 0-23 , - * /
4 1-31 , - * / L W
5 1-12 / JAN-DEC , - * /
6 1-7 or SUN-SAT , - * / L #
7 1970-2099 , - * /
  1. :表示匹配该域的任意值。假如在Minutes域使用, 即表示每分钟都会触发事件。
  2. ?:只能用在DayofMonth和DayofWeek两个域。它也匹配域的任意值,但实际不会。因为DayofMonth和DayofWeek会相互影响。例如想在每月的20日触发调度,不管20日到底是星期几,则只能使用如下写法: 13 13 15 20 * ?, 其中最后一位只能用?,而不能使用,如果使用表示不管星期几都会触发,实际上并不是这样。
  3. -:表示范围。例如在Minutes域使用5-20,表示从5分到20分钟每分钟触发一次
  4. /:斜杠前面值表示起始时间开始触发,后面值表示每隔固定时间触发一次。例如在Minutes域使用5/20,则意味着20分钟触发一次,从第5分钟开始,5,25,45等分别触发一次.
  5. ,:表示列出枚举值。例如:在Minutes域使用5,20,则意味着在5和20分每分钟触发一次。
  6. L:表示最后,只能出现在DayofWeek和DayofMonth域。如果在DayofWeek域使用5L,意味着在最后的一个星期四触发。
  7. W:表示有效工作日(周一到周五),只能出现在DayofMonth域,系统将在离指定日期的最近的有效工作日触发事件。例如:在 DayofMonth使用5W,如果5日是星期六,则将在最近的工作日:星期五,即4日触发。如果5日是星期天,则在6日(周一)触发;如果5日在星期一到星期五中的一天,则就在5日触发。另外一点,W的最近寻找不会跨过月份 。
  8. LW:这两个字符可以连用,表示在某个月最后一个工作日,即最后一个星期五。
  9. #:用于确定每个月第几个星期几,只能出现在DayofMonth域。例如在4#2,表示某月的第二个星期三。

示例:

pom.xml

 <dependencies>
        <!--web起步依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- sping对schedule的支持 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
        </dependency>
    </dependencies>
//引导类必须加上@EnableScheding注解启动SpringTask
@SpringBootApplication
@EnableScheduling // 开启Spring Task
public class MyBootApplication {

    public static void main(String[] args) {
        SpringApplication.run(MyBootApplication.class,args);
    }

}
@Component
public class WelcomeTask {
    //“5/20”表示每隔20秒执行一次,“5”表示为从“5”秒开始
    @Scheduled(cron = "5/20 * * * * ?")
    public void task(){
        System.out.println("欢迎任务被触发,当前时间为:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
    }
}

输出:

2020-05-21 14:04:33.166  INFO 17100 --- [  restartedMain] com.self.MyBootApplication               : Started MyBootApplication in 5.693 seconds (JVM running for 6.831)//启动成功时间33秒
欢迎任务被触发,当前时间为:2020-05-21 14:04:45
欢迎任务被触发,当前时间为:2020-05-21 14:05:05
欢迎任务被触发,当前时间为:2020-05-21 14:05:25
欢迎任务被触发,当前时间为:2020-05-21 14:05:45

spring-boot整合日志功能(logback、log4j2)

springboot为我们已经内置了log组件 。

SpringBoot教程——检视阅读(下),第8张
img

springboot内置log组件

application.yml

#在application.yml文件中修改springboot内置日志级别,默认是info
#方式一:
#debug: true
#方式二:
logging:
  level:
    root: debug

日志级别从低到高为TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF,级别越高,打印的日志越少。举例说明:说将日志级别设定为Debug,那么DEBUG, INFO, WARN, ERROR, FATAL, OFF这几类日志都会打印。

application.properties文件中日志key的第三级的含义为"路径":

  • 填写root,能够指定整个项目(包含jdk源代码打印的日志)的日志级别;
  • 填写某个包名,能够指定该包下所有Java文件的日志级别,其余为被指定的Java文件的日志级别为默认级别:Info
  • 甚至可以指定任意Java文件

整合参考

日志框架选型——都log4J2或者logback都差不多

springboot整合logback

springboot整合log4J2

springboot整合logback

springboot默认依赖了logback,所以不需要添加依赖。

基本配置:

#官方文档中有提到, SpringBoot 的 Logging 配置的级别有7个:TRACE , DEBUG , INFO , WARN , ERROR , FATAL , OFF
#root日志以INFO级别输出
logging.level.root=INFO
#springframework.web日志以WARN级别输出
logging.level.org.springframework.web=WARN
#hibernate日志以ERROR级别输出
logging.level.org.hibernate=ERROR

在resources下创建logback-spring.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!-- scan 配置文件如果发生改变,将会被重新加载  scanPeriod 检测间隔时间-->
<configuration scan="true" scanPeriod="60 seconds" debug="false">
   <contextName>spring-boot-log</contextName>
   <include resource="org/springframework/boot/logging/logback/base.xml"/>
   <!-- 普通日志 -->
   <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
       <file>log/spring-boot-log-info.log</file>
       <!-- 循环政策:基于时间创建日志文件 -->
       <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
           <!-- 日志命名:单个文件大于128MB 按照时间+自增i 生成log文件 -->
           <fileNamePattern>log/spring-boot-log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
           <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
               <maxFileSize>128MB</maxFileSize>
           </timeBasedFileNamingAndTriggeringPolicy>
           <!-- 最大保存时间:30天-->
           <maxHistory>30</maxHistory>
       </rollingPolicy>
       <append>true</append>
       <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
           <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
           <charset>utf-8</charset>
       </encoder>
       <filter class="ch.qos.logback.classic.filter.LevelFilter">
           <level>info</level>
           <onMatch>ACCEPT</onMatch>
           <onMismatch>DENY</onMismatch>
       </filter>
   </appender>
   <!-- 错误日志 -->
   <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
       <file>log/spring-boot-log-error.log</file>
       <!-- 循环政策:基于时间创建日志文件 -->
       <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
           <!-- 日志命名:单个文件大于2MB 按照时间+自增i 生成log文件 -->
           <fileNamePattern>log/spring-boot-log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
           <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
               <maxFileSize>2MB</maxFileSize>
           </timeBasedFileNamingAndTriggeringPolicy>
           <!-- 最大保存时间:180天-->
           <maxHistory>180</maxHistory>
       </rollingPolicy>
       <append>true</append>
       <!-- 日志格式 -->
       <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
           <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
           <charset>utf-8</charset>
       </encoder>
       <!-- 日志级别过滤器 -->
       <filter class="ch.qos.logback.classic.filter.LevelFilter">
           <!-- 过滤的级别 -->
           <level>ERROR</level>
           <!-- 匹配时的操作:接收(记录) -->
           <onMatch>ACCEPT</onMatch>
           <!-- 不匹配时的操作:拒绝(不记录) -->
           <onMismatch>DENY</onMismatch>
       </filter>
   </appender>
   <!-- 控制台 -->
   <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
       <!-- 日志格式 -->
       <encoder>
           <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
           <charset>utf-8</charset>
       </encoder>
       <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
       <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
           <level>INFO</level>
       </filter>
   </appender>
   <!-- additivity 避免执行2次 -->
   <logger name="com.itstyle"  level="INFO"  additivity="false">
       <appender-ref ref="STDOUT"/>
       <appender-ref ref="INFO_FILE"/>
       <appender-ref ref="ERROR_FILE"/>
   </logger>
   <root level="INFO">
       <appender-ref ref="STDOUT" />
       <appender-ref ref="INFO_FILE" />
       <appender-ref ref="ERROR_FILE" />
   </root>
</configuration>

springboot整合log4J2

pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions><!-- 去掉springboot默认配置 -->
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency> <!-- 引入log4j2依赖 -->
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

log4j2-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出-->
<!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数-->
<configuration monitorInterval="5">
    <!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->

    <!--变量配置-->
    <Properties>
        <!-- 格式化输出:%date表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符-->
        <!-- %logger{36} 表示 Logger 名字最长36个字符 -->
        <property name="LOG_PATTERN" value="%date{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" />
        <!-- 定义日志存储的路径 -->
        <property name="FILE_PATH" value="logs" />
        <property name="FILE_NAME" value="hellospringboot-log" />
    </Properties>

    <appenders>

        <console name="Console" target="SYSTEM_OUT">
            <!--输出日志的格式-->
            <PatternLayout pattern="${LOG_PATTERN}"/>
            <!--控制台只输出level及其以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
            <ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY"/>
        </console>

        <!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,适合临时测试用-->
        <File name="Filelog" fileName="${FILE_PATH}/test.log" append="false">
            <PatternLayout pattern="${LOG_PATTERN}"/>
        </File>

        <!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
        <RollingFile name="RollingFileInfo" fileName="${FILE_PATH}/info.log" filePattern="${FILE_PATH}/${FILE_NAME}-INFO-%d{yyyy-MM-dd}_%i.log.gz">
            <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
            <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="${LOG_PATTERN}"/>
            <Policies>
                <!--interval属性用来指定多久滚动一次,默认是1 hour-->
                <TimeBasedTriggeringPolicy interval="1"/>
                <SizeBasedTriggeringPolicy size="10MB"/>
            </Policies>
            <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
            <DefaultRolloverStrategy max="15"/>
        </RollingFile>

        <!-- 这个会打印出所有的warn及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
        <RollingFile name="RollingFileWarn" fileName="${FILE_PATH}/warn.log" filePattern="${FILE_PATH}/${FILE_NAME}-WARN-%d{yyyy-MM-dd}_%i.log.gz">
            <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
            <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="${LOG_PATTERN}"/>
            <Policies>
                <!--interval属性用来指定多久滚动一次,默认是1 hour-->
                <TimeBasedTriggeringPolicy interval="1"/>
                <SizeBasedTriggeringPolicy size="10MB"/>
            </Policies>
            <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
            <DefaultRolloverStrategy max="15"/>
        </RollingFile>

        <!-- 这个会打印出所有的error及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
        <RollingFile name="RollingFileError" fileName="${FILE_PATH}/error.log" filePattern="${FILE_PATH}/${FILE_NAME}-ERROR-%d{yyyy-MM-dd}_%i.log.gz">
            <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
            <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="${LOG_PATTERN}"/>
            <Policies>
                <!--interval属性用来指定多久滚动一次,默认是1 hour-->
                <TimeBasedTriggeringPolicy interval="1"/>
                <SizeBasedTriggeringPolicy size="10MB"/>
            </Policies>
            <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
            <DefaultRolloverStrategy max="15"/>
        </RollingFile>

    </appenders>

    <!--Logger节点用来单独指定日志的形式,比如要为指定包下的class指定不同的日志级别等。-->
    <!--然后定义loggers,只有定义了logger并引入的appender,appender才会生效-->
    <loggers>

        <!--过滤掉spring和mybatis的一些无用的DEBUG信息-->
        <logger name="org.mybatis" level="info" additivity="false">
            <AppenderRef ref="Console"/>
        </logger>
        <!--监控系统信息-->
        <!--若是additivity设为false,则 子Logger 只会在自己的appender里输出,而不会在 父Logger 的appender里输出。-->
        <Logger name="org.springframework" level="info" additivity="false">
            <AppenderRef ref="Console"/>
        </Logger>

        <root level="info">
            <appender-ref ref="Console"/>
            <appender-ref ref="Filelog"/>
            <appender-ref ref="RollingFileInfo"/>
            <appender-ref ref="RollingFileWarn"/>
            <appender-ref ref="RollingFileError"/>
        </root>
    </loggers>

</configuration>

配置参数详解

日志级别

机制:如果一条日志信息的级别大于等于配置文件的级别,就记录。

  • trace:追踪,就是程序推进一下,可以写个trace输出
  • debug:调试,一般作为最低级别,trace基本不用。
  • info:输出重要的信息,使用较多
  • warn:警告,有些信息不是错误信息,但也要给程序员一些提示。
  • error:错误信息。用的也很多。
  • fatal:致命错误。
输出源
  • CONSOLE(输出到控制台)
  • FILE(输出到文件)
格式
  • SimpleLayout:以简单的形式显示
  • HTMLLayout:以HTML表格显示
  • PatternLayout:自定义形式显示

PatternLayout自定义日志布局:

%d{yyyy-MM-dd HH:mm:ss, SSS} : 日志生产时间,输出到毫秒的时间
%-5level : 输出日志级别,-5表示左对齐并且固定输出5个字符,如果不足在右边补0
%c : logger的名称(%logger)
%t : 输出当前线程名称
%p : 日志输出格式
%m : 日志内容,即 logger.info("message")
%n : 换行符
%C : Java类名(%F)
%L : 行号
%M : 方法名
%l : 输出语句所在的行数, 包括类名、方法名、文件名、行数
hostName : 本地机器名
hostAddress : 本地ip地址

Log4j2配置详解

1、根节点Configuration

有两个属性:

  • status
  • monitorinterval

有两个子节点:

  • Appenders
  • Loggers(表明可以定义多个Appender和Logger).

status用来指定log4j本身的打印日志的级别.
monitorinterval用于指定log4j自动重新配置的监测间隔时间,单位是s,最小是5s.

2、Appenders节点

常见的有三种子节点:Console、RollingFile、File

Console节点用来定义输出到控制台的Appender.

  • name:指定Appender的名字.
  • target:SYSTEM_OUT 或 SYSTEM_ERR,一般只设置默认:SYSTEM_OUT.
  • PatternLayout:输出格式,不设置默认为:%m%n.

File节点用来定义输出到指定位置的文件的Appender.

  • name:指定Appender的名字.
  • fileName:指定输出日志的目的文件带全路径的文件名.
  • PatternLayout:输出格式,不设置默认为:%m%n.

RollingFile节点用来定义超过指定条件自动删除旧的创建新的Appender.

  • name:指定Appender的名字.
  • fileName:指定输出日志的目的文件带全路径的文件名.
  • PatternLayout:输出格式,不设置默认为:%m%n.
  • filePattern : 指定当发生Rolling时,文件的转移和重命名规则.
  • Policies:指定滚动日志的策略,就是什么时候进行新建日志文件输出日志.
  • TimeBasedTriggeringPolicy:Policies子节点,基于时间的滚动策略,interval属性用来指定多久滚动一次,默认是1 hour。modulate=true用来调整时间:比如现在是早上3am,interval是4,那么第一次滚动是在4am,接着是8am,12am...而不是7am.
  • SizeBasedTriggeringPolicy:Policies子节点,基于指定文件大小的滚动策略,size属性用来定义每个日志文件的大小.
  • DefaultRolloverStrategy:用来指定同一个文件夹下最多有几个日志文件时开始删除最旧的,创建新的(通过max属性)。

Loggers节点,常见的有两种:Root和Logger.
Root节点用来指定项目的根日志,如果没有单独指定Logger,那么就会默认使用该Root日志输出

  • level:日志输出级别,共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < AppenderRef:Root的子节点,用来指定该日志输出到哪个Appender.
  • Logger节点用来单独指定日志的形式,比如要为指定包下的class指定不同的日志级别等。
  • level:日志输出级别,共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF.
  • name:用来指定该Logger所适用的类或者类所在的包全路径,继承自Root节点.
  • AppenderRef:Logger的子节点,用来指定该日志输出到哪个Appender,如果没有指定,就会默认继承自Root.如果指定了,那么会在指定的这个Appender和Root的Appender中都会输出,此时我们可以设置Logger的additivity="false"只在自定义的Appender中进行输出。

实例:

LoggerFactory创建Logger类。

@Component
public class WelcomeTask {
    private static final Logger logger = LoggerFactory.getLogger(UserController.class);

    //“5/20”表示每隔20秒执行一次,“5”表示为从“5”秒开始
    @Scheduled(cron = "5/5 * * * * ?")
    public void task(){
        logger.debug("进入WelcomeTask 定时任务!");
        System.out.println("欢迎任务被触发,当前时间为:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        logger.error("完成WelcomeTask 定时任务!");
    }
}

lombok工具简化创建Logger类。

@Component
@Slf4j
public class WelcomeTask {
   //“5/20”表示每隔20秒执行一次,“5”表示为从“5”秒开始
   @Scheduled(cron = "5/5 * * * * ?")
   public void task(){
       log.debug("进入WelcomeTask 定时任务!");
       System.out.println("欢迎任务被触发,当前时间为:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
       log.error("完成WelcomeTask 定时任务!");
   }
}

lombok使用参考教程。

lombok就是一个注解工具jar包,能帮助我们省略一繁杂的代码。

lombok使用实践

pom.xml依赖

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.20</version>
</dependency>

IDEA插件里搜索lombok插件安装,重启 。

SpringBoot教程——检视阅读(下),第9张
常用注解
  1. @Setter 注解在类或字段,注解在类时为所有字段生成setter方法,注解在字段上时只为该字段生成setter方法。
  2. @Getter 使用方法同上,区别在于生成的是getter方法。
  3. @ToString 注解在类,添加toString方法。
  4. @EqualsAndHashCode 注解在类,生成hashCode和equals方法。
  5. @NoArgsConstructor 注解在类,生成无参的构造方法。
  6. @RequiredArgsConstructor 注解在类,为类中需要特殊处理的字段生成构造方法,比如final和被@NonNull注解的字段。
  7. @AllArgsConstructor 注解在类,生成包含类中所有字段的构造方法。
  8. @Data 注解在类,为类的所有字段注解@ToString、@EqualsAndHashCode、@Getter的便捷方法,同时为所有非final字段注解@Setter。

疑问

1、Q:软件版本的GA 代表什么意思?

A:GA:General Availability,正式发布的版本,在国外都是用GA来说明release版本的 .

引申:

参考

Alpha:是内部测试版,一般不向外部发布,会有很多Bug.一般只有测试人员使用。

Beta:也是测试版,这个阶段的版本会一直加入新的功能。在Alpha版之后推出。

RC:(Release Candidate) 顾名思义么 ! 用在软件上就是候选版本。系统平台上就是发行候选版本。RC版不会再加入新的功能了,主要着重于除错。

GA:General Availability,正式发布的版本,在国外都是用GA来说明release版本的。

RTM:(Release to Manufacture)是给工厂大量压片的版本,内容跟正式版是一样的,不过RTM版也有出限制、评估版的。但是和正式版本的主要程序代码都是一样的。

OEM:是给计算机厂商随着计算机贩卖的,也就是随机版。只能随机器出货,不能零售。只能全新安装,不能从旧有操作系统升级。包装不像零售版精美,通常只有一面CD和说明书(授权书)。

RVL:号称是正式版,其实RVL根本不是版本的名称。它是中文版/英文版文档破解出来的。

EVAL:而流通在网络上的EVAL版,与“评估版”类似,功能上和零售版没有区别。

RTL:Retail(零售版)是真正的正式版,正式上架零售版。在安装盘的i386文件夹里有一个eula.txt,最后有一行EULAID,就是你的版本。比如简体中文正式版是EULAID:WX.4_PRO_RTL_CN,繁体中文正式版是WX.4_PRO_RTL_TW。其中:如果是WX.开头是正式版,WB.开头是测试版。_PRE,代表家庭版;_PRO,代表专业版。

α、β、λ常用来表示软件测试过程中的三个阶段,α是第一阶段,一般只供内部测试使用;β是第二个阶段,已经消除了软件中大部分的不完善之处,但仍有可能还存在缺陷和漏洞,一般只提供给特定的用户群来测试使用;λ是第三个阶段,此时产品已经相当成熟,只需在个别地方再做进一步的优化处理即可上市发行。

2、Q:springboot的核心功能起步依赖和自动配置详解?

3、Q: 自定义配置怎么取值使用,什么场景使用?

4、Q: 每次发布的时候替换掉配置文件,这样太麻烦了,Spring Boot的Profile就给我们提供了解决方案,命令带上参数就搞定。 是指打包命令带上参数就能自动加载不同的环境变量配置么?我们一般是如何打生产包或测试包部署的?怎么通过jekeins实现不同环境的打包部署?

5、Q: yml配置文件属性值是大小写敏感的么?教程里说是,可实际测试中并不是?怎么理解?

#基本类型 注意:属性值大小写敏感
firstName: Bruce Wayne1111
age: 29
@Controller
public class ConfigController {

    @Value("${firstname}")
    private String name;
    @Value("${age}")
    private Integer age;

    @RequestMapping("/show")
    @ResponseBody
    public String showConfig() {
        return name + " : " + age;
    }
}

输出:

Bruce Wayne1111 : 29

6、Q: 下面@Value取值的表达式怎么理解符号#的作用?已经什么时候可以用split()方法

 @Value("#{'${user.list}'.split(',')}")
    private List<String> list;

7、Q: Spring Boot3种热部署方式前两种如何实现?

Spring Boot有3种热部署方式:

  1. 使用springloaded配置pom.xml文件,使用mvn spring-boot:run启动
  2. 使用springloaded本地加载启动,配置jvm参数
  3. 使用devtools工具包,操作简单,但是每次需要重新部署

8、Q: 什么是Thymeleaf ?

9、Q: @Configuration注解的作用?对于下面这个异常处理类的作用?

@Configuration
public class CommonHandlerExceptionResolver implements HandlerExceptionResolver {
}

10、Q: java注解和spring注解需要系统研究一遍。

11、Q: 启动类SpringbootDemoApplication其实就是一个标准的Spring纯注解下的启动类 。怎么理解Spring纯注解下的启动类?

12、Q: SPI 方案?

A:SPI 全称为 (Service Provider Interface),即服务提供商接口,是JDK内置的一种服务提供发现机制。目前有不少框架用它来做服务的扩展发现,简单来说,它就是一种动态替换发现服务实现者的机制

Java扩展方法之SPI

其他

1、COC: Convention over Configuration,即约定大于配置。
2、72法则

72法则指以1%的复利计息,72年后(72是约数,准确值是ln2/ln1.01),本金翻倍的规律。

3、如果我们不想用tomcat,可以更改 POM 来使用 Jetty 代替 Tomcat。如果不想用hibernate,改用mybatis,也可以这样操作。
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jetty</artifactId>
    </dependency>
</dependencies>

参考

SpringBoot教程——一点——springboot2.1.1


https://www.xamrdz.com/backend/3bq1942740.html

相关文章: