1. 前言

一般情况下,我们如果需要某个表,比如错误日志表,当这个表中的数量超过一定的阈值,系统自动会给我们发送一个警报,提醒我们要做一些处理。我们需要利用定时器(Schedule)来完成来实现这个功能。

2. 功能介绍

微服务和VUE入门教程(21): springboot中定时器_数据库

当警报关闭的时候,我们通过点击“开启警报”来启动后端的警报监控。后端每10秒(定时器时间)来访问一下student表,

若这个表中的数量超过了50(阈值),就会发邮件给2605121231@qq.com.

微服务和VUE入门教程(21): springboot中定时器_微服务_02

当经过启动的时候,操作按钮变成:关闭警报,重启警报。

3. 新建警报表

CREATE TABLE `alarm` (
  `threshold` INT(20) DEFAULT NULL,
  `cronTime` INT(20) DEFAULT NULL,
  `email` varchar(45) DEFAULT NULL,
  `alarmStatus` INT(20) DEFAULT NULL,
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

我们需要将警报信息持久化,这样才能每次打开页面的时候得到正确的警报设置信息。

4. StuApplication.java

加入

@EnableScheduling   //启动Scheduled定时任务机制
  • 1.

很重要!很重要!很重要!

5. xml

在mapper.xml文件中,我们主要实现三个方法,alarmSel,alarmUpdateThreshold,alarmUpdate。

pojo,dao,service 大同小异。

<?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">
<!--DAO的路径-->
<mapper namespace="com.student.dao.AlarmDAO">
    <!--实体类路径-->
    <resultMap id="BaseAlarmMap" type="com.student.pojo.Alarm">
        <result column="threshold"  property="threshold" />
        <result column="cron_time"  property="cronTime" />
        <result column="email"  property="email" />
        <result column="alarm_status"  property="alarmStatus" />
    </resultMap>

    <!--查询警报信息-->
    <select id="alarmSel" resultMap="BaseAlarmMap">
        select * from alarm
    </select>

    <!--更新阈值-->
    <update id="alarmUpdateThreshold" parameterType="java.util.Map">
        update alarm set threshold = #{threshold}
    </update>

    <!--更新信息-->
    <update id="alarmUpdate" parameterType="java.util.Map">
        update alarm set
        threshold = #{threshold},cron_time = #{cronTime},email = #{email},alarm_status = #{alarmStatus}
    </update>
</mapper>
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.

6. AlarmController

@RestController
@CrossOrigin
public class AlarmController {
    @Autowired
    AlarmService alarmService;
    @Autowired
    StuService stuService;

    /**
     * 定时器
     * */
    // 基本配置
    private  String DEFAULT_CRON = "0/5 * * * * ?";
    private int threshold = 50;
    private String email;

    @Autowired
    private ThreadPoolTaskScheduler threadPoolTaskScheduler;
    private ScheduledFuture<?> future;

    @Bean
    public ThreadPoolTaskScheduler threadPoolTaskScheduler(){
        return new ThreadPoolTaskScheduler();
    }
    //开启警报
    @RequestMapping(value = "/alarm/start",method = RequestMethod.POST)
    public JSONObject startAlarm(@RequestBody JSONObject jsonObject){
        threshold = jsonObject.getInteger("threshold");
        String cronTime = jsonObject.getString("cronTime");
        email = jsonObject.getString("email");
        DEFAULT_CRON = "0/" + cronTime + " * * * * ?";

        //开启定时器
        future = threadPoolTaskScheduler.schedule(new MyRunable(),new CronTrigger(DEFAULT_CRON));
        int i = alarmService.updateAlarm(jsonObject);
        JSONObject result = new JSONObject();
        if(i==1){
            result.put("state",200);
            result.put("alarmStatus",1);
        }else {
            result.put("state",400);
        }
        return result;
    }
    
    // 警报线程
    private class MyRunable implements Runnable{
        @Override
        public void run() {
            // 查找学生信息表总数量
            int count = stuService.getStuCount(null);
            if(count > threshold){
                //TODO: 发邮件
                System.out.println("已达到极限");
                // 提高阈值
                threshold = threshold + 50;
                JSONObject alarmThreshold = new JSONObject();
                alarmThreshold.put("threshold",threshold);
                alarmService.UpdateAlarmThreshold(alarmThreshold);
            }
            System.out.println("run," + new Date()+" ,count" + count);
        }
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.

可以看出,在这个controller类前面,定义了一堆参数,有阈值,定时器的间隔时间,还有一个定时器的方法。

启动警报方法中,通过使用定时器

future = threadPoolTaskScheduler.schedule(new MyRunable(),new CronTrigger(DEFAULT_CRON));

来执行MyRunable这个方法,并且设置了定时器时间为:DEFAULT_CRON ;

MyRunable继承了Runnable这个方法,开启了重写了run方法。

7. 停止警报和重启警报

//停止警报
    @RequestMapping(value = "/alarm/stop", method = RequestMethod.POST)
    public JSONObject stopAlarm(@RequestBody JSONObject jsonObject){
        //关闭定时器
        if(future != null){
            System.out.println("警报关闭");
            future.cancel(true);
        }
        int i = alarmService.updateAlarm(jsonObject);
        JSONObject result = new JSONObject();
        if(i == 1){
            result.put("state",200);
            result.put("alarmStatus",0);
        }else {
            result.put("state",400);
        }
        return result;
    }

    // 重启警报
    @RequestMapping(value = "/alarm/restart", method = RequestMethod.POST)
    public JSONObject restartAlarm(@RequestBody JSONObject jsonObject){
        System.out.println("重启");
        threshold = jsonObject.getInteger("threshold");
        String cronTime = jsonObject.getString("cronTime");
        email = jsonObject.getString("email");
        DEFAULT_CRON = "0/" + cronTime + " * * * * ?";

        //先停止再重启
        if(future != null){
            future.cancel(true);
        }
        future = threadPoolTaskScheduler.schedule(new MyRunable(),new CronTrigger(DEFAULT_CRON));

        //修改数据库中警报表的设置
        int i = alarmService.updateAlarm(jsonObject);
        JSONObject result = new JSONObject();
        if(i == 1){
            result.put("state",200);
            result.put("alarmStatus",1);
        }else {
            result.put("state",400);
        }
        return result;
    }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.

停止警报和重启警报,也是建立在定时器的基础上。

if(future != null){
        System.out.println("警报关闭");
        future.cancel(true);
   }
  • 1.
  • 2.
  • 3.
  • 4.

通过取消定时器future,从而停止警报。重启警报实现原理是先停止再重启,使更改的警报信息生效。

8. 前端代码

代码代码没有什么值得注意的地方,就不写了。