微服务项目实战技术点汇总:“尚硅谷的谷粒在线教育”十一、统计分析模块(图表显示数据),定时任务(每天到达指定时间,执行指定程序)

一、环境搭建

1、数据库

# Host: 47.93.118.241:33306  (Version 5.7.21)
# Date: 2019-11-15 11:58:04
# Generator: MySQL-Front 6.1  (Build 1.26)


#
# Structure for table "statistics_daily"
#

CREATE TABLE `statistics_daily` (
  `id` char(19) NOT NULL COMMENT '主键',
  `date_calculated` varchar(20) NOT NULL COMMENT '统计日期',
  `register_num` int(11) NOT NULL DEFAULT '0' COMMENT '注册人数',
  `login_num` int(11) NOT NULL DEFAULT '0' COMMENT '登录人数',
  `video_view_num` int(11) NOT NULL DEFAULT '0' COMMENT '每日播放视频数',
  `course_num` int(11) NOT NULL DEFAULT '0' COMMENT '每日新增课程数',
  `gmt_create` datetime NOT NULL COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`),
  KEY `statistics_day` (`date_calculated`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='网站统计日数据';

#
# Data for table "statistics_daily"
#

INSERT INTO `statistics_daily` VALUES ('1078490017163833345','2018-12-28',0,0,154,170,'2018-12-28 11:17:12','2019-09-09 12:12:12'),('1087142127818768386','2019-01-02',2,0,167,177,'2019-01-21 08:17:36','2019-09-09 12:12:12'),('1087198321809457153','2019-01-01',1,0,130,189,'2019-01-21 12:00:54','2019-09-09 12:12:12'),('1087198383973236738','2019-01-03',0,0,114,130,'2019-01-21 12:01:09','2019-09-09 12:12:12'),('1087451681764982785','2019-01-04',0,0,118,155,'2019-01-22 04:47:39','2019-09-09 12:12:12'),('1087455336471785473','2019-01-05',0,0,184,186,'2019-01-22 05:02:11','2019-09-09 12:12:12'),('1105339962460491777','2019-03-01',0,143,168,136,'2019-03-12 13:29:18','2019-03-12 13:29:18'),('1105339977027309569','2019-03-02',0,165,171,158,'2019-03-12 13:29:21','2019-03-12 13:29:21'),('1105339990738489346','2019-03-03',0,143,147,194,'2019-03-12 13:29:25','2019-03-12 13:29:25'),('1105340000544772098','2019-03-04',0,155,106,153,'2019-03-12 13:29:27','2019-03-12 13:29:27'),('1105340011244441602','2019-03-05',0,186,102,155,'2019-03-12 13:29:30','2019-03-12 13:29:30'),('1105340020929089538','2019-03-06',0,140,192,129,'2019-03-12 13:29:32','2019-03-12 13:29:32'),('1105340029800042497','2019-03-07',0,186,139,116,'2019-03-12 13:29:34','2019-03-12 13:29:34'),('1105340038696161282','2019-03-08',0,120,166,112,'2019-03-12 13:29:36','2019-03-12 13:29:36'),('1105340049441968129','2019-03-09',0,182,147,119,'2019-03-12 13:29:39','2019-03-12 13:29:39'),('1105340059738984449','2019-03-10',0,199,141,103,'2019-03-12 13:29:41','2019-03-12 13:29:41'),('1105340070438653953','2019-03-11',0,127,137,156,'2019-03-12 13:29:44','2019-03-12 13:29:44');

2、搭建后端微服务

1、application.yml

server:
  port: 8007 #微服务端口号为8007
spring:
  application:
    name: service-statistics #服务名
  profiles:
    active: dev #环境设置 dev表示构建阶段,test表示测试阶段,prod表示发布阶段
  datasource: #数据源
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/gulischool?serverTimeZone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true
    username: root
    password: 123456
  jackson: #我们的时区是东八区,应该加8个小时,时区显示格式也需要改成我们想要的
    date-format: yyyy-MM-DD HH:mm:ss
    time-zone: GMT+8
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848 #nacos
feign:
  client:
    config:
      default:
        connect-timeout: 10000 #设置超时限制,必须超过10000ms才报错
        read-timeout: 10000 #设置Feign服务熔断机制的最大超时限制
  hystrix:
    enabled: true #开启熔断机制
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 6000 #设置hystri超时时间 默认1000ms(10s)


mybatis-plus:
  mapper-locations: classpath:com/yzpnb/statistics_service/mapper/xml/*.xml #配置mapper xml文件的路径

在这里插入图片描述

2、代码生成器,生成MVC结构

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3、启动类

package com.yzpnb.statistics_service;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@EnableFeignClients//开启Feign服务熔断
@EnableDiscoveryClient//启用Nacos
@MapperScan("com.yzpnb.statistics_service.mapper")//扫描mapper映射
@ComponentScan("com.yzpnb")//扫描组件
public class StatisticsApplication {
    public static void main(String[] args) {
        SpringApplication.run(StatisticsApplication.class,args);
    }
}

在这里插入图片描述

二、后端

需要统计的数据如下

在这里插入图片描述

1、统计某一天的注册人数

统计注册人数,这肯定是会员模块的东西,所以需要Feign远程调用

在这里插入图片描述

1、sql讲解

获取日期函数Date

在这里插入图片描述

详细sql语句,统计指定日期注册人数

在这里插入图片描述

1、controller

@ApiOperation("统计某一天的注册人数")
    @GetMapping(value = "countregister")
    public Integer registerCount(@ApiParam(name = "day",value = "天数")
                                @RequestParam(value = "day") String day){
        Integer count = ucenterMemberService.countRegisterByDay(day);
        return count;
    }

在这里插入图片描述

2、service

/**
     * 根据年-月-日格式字符串,查询指定日期的注册人数
     * @param day
     * @return
     */
    @Override
    public Integer countRegisterByDay(String day) {
        
        return baseMapper.countRegisterByDay(day);
    }

3、mapper

 Integer countRegisterByDay(String day);

<!--查询2019312号的注册用户-->
    <select id="countRegisterByDay" resultType="java.lang.Integer">
        select 
            count(1)
        from
            ucenter_member as uc
        where
            Date(uc.gmt_create)=#{day}
    </select>

在这里插入图片描述

4、测试

在这里插入图片描述
在这里插入图片描述

2、统计分析功能

1、远程调用统计注册人数接口

在这里插入图片描述

2、controller

package com.yzpnb.statistics_service.controller;


import com.yzpnb.common_utils.Result;
import com.yzpnb.statistics_service.service.StatisticsDailyService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

/**
 * <p>
 * 网站统计日数据 前端控制器
 * </p>
 *
 * @author testjava
 * @since 2020-06-08
 */
@RestController
@RequestMapping("/statistics_service/statistics-daily")
public class StatisticsDailyController {

    @Autowired
    private StatisticsDailyService statisticsDailyService;

    @ApiOperation("根据日期创建统计对象")
    @PostMapping("{day}")
    public Result createStatisticsByDate(@PathVariable String day) {
        statisticsDailyService.createStatisticsByDay(day);
        return Result.ok();
    }
}


在这里插入图片描述

3、service

package com.yzpnb.statistics_service.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yzpnb.statistics_service.entity.StatisticsDaily;
import com.yzpnb.statistics_service.feign.FeignToUcenterClient;
import com.yzpnb.statistics_service.mapper.StatisticsDailyMapper;
import com.yzpnb.statistics_service.service.StatisticsDailyService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.RandomUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * <p>
 * 网站统计日数据 服务实现类
 * </p>
 *
 * @author testjava
 * @since 2020-06-08
 */
@Service
public class StatisticsDailyServiceImpl extends ServiceImpl<StatisticsDailyMapper, StatisticsDaily> implements StatisticsDailyService {

    @Autowired
    private FeignToUcenterClient feignToUcenterClient;//远程调用接口

    /**
     * 根据日期创建统计对象
     * @param day
     */
    @Override
    public void createStatisticsByDay(String day) {
        //删除已存在的统计对象(如果数据更新,需要先删除已经存在的数据,重新获取数据添加)
        QueryWrapper<StatisticsDaily> dayQueryWrapper = new QueryWrapper<>();
        dayQueryWrapper.eq("date_calculated", day);
        baseMapper.delete(dayQueryWrapper);


        //获取统计信息
        Integer registerNum =feignToUcenterClient.registerCount(day);//统计注册人数
        Integer loginNum = RandomUtils.nextInt(100, 200);//TODO 登陆人数
        Integer videoViewNum = RandomUtils.nextInt(100, 200);//TODO 每日播放视频数
        Integer courseNum = RandomUtils.nextInt(100, 200);//TODO 每日新增课程数

        //创建统计对象
        StatisticsDaily daily = new StatisticsDaily();
        daily.setDateCalculated(day);       //设置统计日期
        daily.setRegisterNum(registerNum);  //设置注册人数
        daily.setLoginNum(loginNum);        //设置登陆人数
        daily.setVideoViewNum(videoViewNum);//设置每日播放视频数
        daily.setCourseNum(courseNum);      //设置每日新增课程数

        baseMapper.insert(daily);
    }
}

在这里插入图片描述

4、测试

在这里插入图片描述
在这里插入图片描述

3、定时任务功能

cron
计划任务,是任务在约定的时间执行已经计划好的工作,这是表面的意思。
在Linux中,我们经常用到 cron 服务器来完成这项工作。cron服务器可以根据配置文件约定的时间来执行特定的任务。
Cron表达式
在线生成Cron表达式网址:http://cron.qqe2.com/
cron表达式用来表示时间,比如0 0 0 * * * 就表示每天的晚上12:00
注意:我们在生成时,不可以带年,也就是生成的表达式只能为6位,因为spring默认是每年,我们不能指定年,记得生成后数一下,是不是6位

在这里插入图片描述
在这里插入图片描述

1、启动类加注解@EnableScheduling

在这里插入图片描述

2、创建定时任务类,在类中使用cron表达式指定方法执行规则

在这里插入图片描述
在这里插入图片描述

3、每天凌晨1点统计前一天的数据

package com.yzpnb.statistics_service.schedule;

import com.yzpnb.statistics_service.service.StatisticsDailyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

@Component
public class ScheduledTask {

    @Autowired
    private StatisticsDailyService statisticsDailyService;

    @Scheduled(cron = "0 0 1 * * ?")//每日凌晨一点执行
    public void task1(){
        //获取前一天的时间
        Calendar now =Calendar.getInstance();//反射对象
        now.setTime(new Date());             //设置时间为当前时间
        now.set(Calendar.DATE,(now.get(Calendar.DATE))-1);//设置DATE的值为当前DATE-1,也就是当前时间的前一天了
        Date time = now.getTime();//获取时间对象
        //格式化时间
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
        String day = sdf.format(time);//将前一天的时间格式化为字符串

        //统计数据
        statisticsDailyService.createStatisticsByDay(day);
    }
}

在这里插入图片描述

4、统计数据条件获取

分析

在这里插入图片描述

1、controller

@ApiOperation("根据起始日期结束日期和查询数据类型得到统计数据")
    @GetMapping("show-chart/{begin}/{end}/{type}")
    public Result showChart(@ApiParam(name = "begin",value = "起始时间") 
                            @PathVariable String begin,
                            @ApiParam(name = "end",value = "结束时间") 
                            @PathVariable String end,
                            @ApiParam(name = "type",value = "查询数据类型") 
                            @PathVariable String type){
        
        Map<String, Object> map = statisticsDailyService.getChartData(begin, end, type);
        return Result.ok().data(map);
    }

在这里插入图片描述

2、service

 /**
     * 根据起始日期结束日期和查询数据类型得到统计数据
     * @param begin
     * @param end
     * @param type
     * @return
     */
    @Override
    public Map<String, Object> getChartData(String begin, String end, String type) {

        QueryWrapper<StatisticsDaily> dayQueryWrapper = new QueryWrapper<>();
        dayQueryWrapper.select(type, "date_calculated");//指定要查询的字段
        dayQueryWrapper.between("date_calculated", begin, end);//指定查询的条件区间

        List<StatisticsDaily> dayList = baseMapper.selectList(dayQueryWrapper);

        Map<String, Object> map = new HashMap<>();
        List<Integer> dataList = new ArrayList<Integer>();//数据集合用来存储数据
        List<String> timeList = new ArrayList<String>();//日期集合,用来存储日期
        map.put("dataList", dataList);
        map.put("timeList", timeList);


        for (int i = 0; i < dayList.size(); i++) {//遍历查询出的结果

            StatisticsDaily daily = dayList.get(i);//取出集合中对象

            timeList.add(daily.getDateCalculated());//将对象的时间添加到日期集合中

            switch (type) {//看看需要统计的是哪种类型的数据
                case "register_num":    //统计注册人数
                    dataList.add(daily.getRegisterNum());
                    break;
                case "login_num":       //统计登陆人数
                    dataList.add(daily.getLoginNum());
                    break;
                case "video_view_num":  //统计视频播放人数
                    dataList.add(daily.getVideoViewNum());
                    break;
                case "course_num":      //课程新增人数
                    dataList.add(daily.getCourseNum());
                    break;
                default:
                    break;
            }
        }

        return map;
    }

在这里插入图片描述

3、测试

在这里插入图片描述

三、前端(后台管理系统)

1、统计分析功能

1、nginx配置

在这里插入图片描述

2、api接口

在这里插入图片描述

3、组件

<!-- 统计表单开始-->
      <div class="app-container">
        <!--表单-->
        <el-form :inline="true" class="demo-form-inline">

          <el-form-item label="日期">
            <el-date-picker
              v-model="day"
              type="date"
              placeholder="选择要统计的日期"
              value-format="yyyy-MM-dd" />
          </el-form-item>

          <el-button
            :disabled="btnDisabled"
            type="primary"
            @click="create()">生成</el-button>
        </el-form>

      </div>
      <!-- 统计表单结束-->

在这里插入图片描述

4、代码实现

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2、生成统计图表(使用ECharts组件生成图表)

ECharts
ECharts是百度的一个项目,后来百度把Echart捐给apa​che,用于图表展示,提供了常规的折线图、柱状图、散点图、饼图、K线图,用于统计的盒形图,用于地理数据可视化的地图、热力图、线图,用于关系数据可视化的关系图、treemap、旭日图,多维数据可视化的平行坐标,还有用于 BI 的漏斗图,仪表盘,并且支持图与图之间的混搭。
官方网站:https://echarts.baidu.com/
样式文档:https://echarts.baidu.com/option.html#title
参考官网的文档,可以快速入门
参考样式文档,可以快速美化图表
安装:npm install echarts --save
安装完成后,在需要的地方使用即可

在这里插入图片描述
在这里插入图片描述

1、api接口

在这里插入图片描述

2、组件

<!-- 图表表单开始 -->
      <div class="app-container">
      <!--表单-->
      <el-form :inline="true" class="demo-form-inline">

        <el-form-item>
          <el-select v-model="searchObj.type" clearable placeholder="请选择">
            <el-option label="学员登录数统计" value="login_num"/>
            <el-option label="学员注册数统计" value="register_num"/>
            <el-option label="课程播放数统计" value="video_view_num"/>
            <el-option label="每日课程数统计" value="course_num"/>
          </el-select>
        </el-form-item>

        <el-form-item>
          <el-date-picker
            v-model="searchObj.begin"
            type="date"
            placeholder="选择开始日期"
            value-format="yyyy-MM-dd" />
        </el-form-item>
        <el-form-item>
          <el-date-picker
            v-model="searchObj.end"
            type="date"
            placeholder="选择截止日期"
            value-format="yyyy-MM-dd" />
        </el-form-item>
        <el-button
          :disabled="btnDisabled"
          type="primary"
          icon="el-icon-search"
          @click="showChart()">查询</el-button>
      </el-form>

      <div class="chart-container">
        <div id="chart" class="chart" style="height:500px;width:100%" />
      </div>
    </div>
    <!-- 图表表单结束-->

在这里插入图片描述

3、代码

searchObj: {//表单数据
        type: '',//查询类型
        begin: '',//起始时间
        end: ''//结束时间
      },
      btnDisabled2: false,  //查询按钮是否可用
      chart: null,          //用来存储dom节点(Html标签)
      title: '',            //图表标题
      xData: [],            //x坐标轴数据,(我们项目x轴是时间)
      yData: []             //y坐标轴数据,(我们项目y轴是统计数据)
    }

/* 点击查询按钮后,展示图表*/
     showChart() {
       this.initChartData()
     },

     // 准备图表数据
     initChartData() {
        daily.showChart(this.searchObj).then(response => {
            // 数据
            this.yData = response.data.dataList

            // 横轴时间
            this.xData = response.data.timeList

            // 当前统计类别
            switch (this.searchObj.type) {
              case 'register_num':
                this.title = '学员注册数统计'
                break
              case 'login_num':
                this.title = '学员登录数统计'
                break
              case 'video_view_num':
                this.title = '课程播放数统计'
                break
              case 'course_num':
                this.title = '每日课程数统计'
                break
            }

            this.setChart()
          })
     },
 // 设置图标参数
     setChart() {
       // 基于准备好的dom,初始化echarts实例
       this.chart = echarts.init(document.getElementById('chart'))
       // console.log(this.chart)

       // 指定图表的配置项和数据
       var option = {
         // x轴是类目轴(离散数据),必须通过data设置类目数据
         xAxis: {
             type: 'category',
             data: this.xData//-------绑定数据
         },
         // y轴是数据轴(连续数据)
         yAxis: {
             type: 'value'
         },
         // 系列列表。每个系列通过 type 决定自己的图表类型
         series: [{
             // 系列中的数据内容数组
             data: this.yData,//-------绑定数据
             // 折线图
             type: 'line'
         }],
       }

       this.chart.setOption(option)
     },

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4、测试

在这里插入图片描述

因为我的数据是字符串,所以没有办法区分顺序,因为是测试数据,所以2号排在了1号前面,以后我们正常存入数据,不会有这种问题

在这里插入图片描述

5、添加样式

title: {
             text: this.title
         },
         tooltip: {
             trigger: 'axis'
         },
         dataZoom: [{
           show: true,
           height: 30,
           xAxisIndex: [
             0
           ],
           bottom: 30,
           start: 10,
           end: 80,
           handleIcon: 'path://M306.1,413c0,2.2-1.8,4-4,4h-59.8c-2.2,0-4-1.8-4-4V200.8c0-2.2,1.8-4,4-4h59.8c2.2,0,4,1.8,4,4V413z',
           handleSize: '110%',
           handleStyle: {
             color: '#d3dee5'

           },
           textStyle: {
             color: '#fff'
           },
           borderColor: '#90979c'
         },
         {
           type: 'inside',
           show: true,
           height: 15,
           start: 1,
           end: 35
         }],

在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/grd_java/article/details/106612925