美文网首页
SpringBoot教程——检视阅读(下)

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

作者: 卡斯特梅的雨伞 | 来源:发表于2020-05-21 16:34 被阅读0次

    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 也有自己的语法。

    image.png

    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>
    

    输出:

    image.png

    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";
        }
      }
    

    输出:

    image.png

    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;
        }
    }
    

    启动类不变,输出:

    image.png

    整合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;
        }
      }
    

    输出:

    image.png

    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=艾米哈珀
    

    输出:

    image.png

    报错: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 框架主要核心组件包括调度器、触发器和作业。调度器作为作业的总指挥,触发器 作为作业的操作者,作业为应用的功能模块。其关系如图:

    image.png

    示例:

    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组件 。

    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插件安装,重启 。

    image.png
    常用注解
    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

    相关文章

      网友评论

          本文标题:SpringBoot教程——检视阅读(下)

          本文链接:https://www.haomeiwen.com/subject/echtahtx.html