飞天班第29节:项目集成SpringCloud

2020/05/02

1、整合Eureka

基于之前的edu实战项目,把服务注册到eureka进行服务治理,已有的服务如下

工程名称(服务名称) 说明
jude-edu-parent 版本管理
jude-edu-edu 主要业务模块
jude-edu-admin-login 后台登录注销模块
jude-edu-common 公共模块
jude-edu-oss 阿里云存储模块
jude-edu-vod 阿里云视频点播模块

服务注册中心 edu-eureka

新建module maven工程 edu-eureka , parent选择edu-parent

1、导入依赖

edu-parent的pom.xml添加

<!--Spring Cloud-->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-dependencies</artifactId>
  <version>Hoxton.SR4</version>
  <type>pom</type>
  <scope>import</scope>
</dependency>

edu-eureka的pom.xml添加

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

2、配置文件,edu-eureka的application.yaml 添加

server:
  port: 8220

spring:
  application:
    name: jude-edu-eureka
  profiles:
    active: dev

eureka:
  instance:
    hostname: localhost
  client:
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

3、edu-eureka的启动类添加注解@EnableEurekaServer开启服务注册

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
   public static void main(String[] args) {
      SpringApplication.run(EurekaServerApplication.class,args);
   }
}

服务注册到edu-eureka

1、添加依赖,edu-admin-login的pom.xml 添加

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

2、配置文件,edu-admin-login.application.yaml 添加

# 服务注册中心
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8220/eureka/

3、edu-admin-login的启动类增加注解@EnableEurekaClient

@SpringBootApplication
@EnableEurekaClient
public class AdminLoginApplication {
	public static void main(String[] args) {
		SpringApplication.run(AdminLoginApplication.class,args);
	}
}

启动edu-eureka,edu-admin-login,浏览器访问http://localhost:8220/ 可以看到edu-admin-login 服务已经注册到eureka了,其他服务同样配置。

Eureka server 自我保护机制失效配置,不建议关闭

# 关闭自我保护机制, 不可用的微服务就会自动剔除,默认开启
# eureka.server.enable-self-preservation=false
# 清理失效的时间 5s,默认60秒
# eureka.server.eviction-interval-timer-in-ms=5000

Eureka client 的心跳配置,保持默认

# 每5s发送一个心跳!默认30秒
# eureka.instance.lease-renewal-interval-in-seconds=5
# 如果10s 之后,服务端没有收到心跳,就代表微服务挂了!默认90秒
# eureka.instance.lease-expiration-duration-in-seconds=10

生产环境中,集群至少两台,合理的是3台,尽量单数。

2、用户中心微服务

新建数据库coding_ucenter

新建module maven工程edu-ucenter,parent选择edu-parent,一个微服务与一个数据库对应,使用myabtis-plus的代码生成器,自动生成mapper\service\controller

参考edu-admin-login把 edu-ucenter 注册到Eureka中

web层接口-统计用户今日注册数

web层接口的定义MemberAdminController

@ApiOperation(value = "统计用户今日注册数")
@GetMapping(value = "count-register/{day}")
public R registerCount(
  @ApiParam(name = "day",value = "统计日期")
  @PathVariable("day") String day){

  Integer count = memberService.countRegister(day);
  return R.ok().data("countRegister",count);
}

3、统计中心微服务

新建数据库coding_statistics,

新建module maven工程edu-statistics,parent选择edu-parent,一个微服务与一个数据库对应,使用myabtis-plus的代码生成器,自动生成mapper\service\controller

参考edu-admin-login把 edu-ucenter 注册到Eureka中

4、Feign调用

Feign总结:

  • 声明式、模板化、Http客户端
  • 默认集成Ribbon结合实现负载均衡,
  • 默认集成HyStrix,实现服务降级!

任务:edu-statistics 通过feign调用edu-ucenter 的web层接口-统计用户今日注册数,获取注册数,生成今日统计记录

1、edu-statistics的pom.xml添加依赖

<!--添加feign依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <version>2.2.2.RELEASE</version>
</dependency>

2、edu-statistics的主启动类添加 Feign的支持注解@EnableFeignClients

@SpringBootApplication
@ComponentScan(basePackages = {"com.jude.statistics","com.jude.common"})
@EnableEurekaClient
@EnableDiscoveryClient
@EnableFeignClients
public class StatisticsApplication {
	public static void main(String[] args) {
		SpringApplication.run(StatisticsApplication.class,args);
	}
}

3、edu-statistics的feign接口UcenterClient

@FeignClient("edu-ucenter")
public interface UcenterClient {
	@GetMapping("/admin/ucenter/member/count-register/{day}")
	 R countRegister(@PathVariable String day);
}

4、edu-statistics的业务层接口实现类DailyServiceImpl

@Autowired
UcenterClient ucenterClient;

@Override
public void saveStatisticsByDay(String day) {
  // 删除已存在的统计
  QueryWrapper<Daily> dailyQueryWrapper = new QueryWrapper<>();
  dailyQueryWrapper.eq("date_calculated",day);
  baseMapper.delete(dailyQueryWrapper);

  // 获取统计信息
  Integer registerNum = (Integer) ucenterClient.countRegister(day).getData().get("countRegister");

  // TODO 作业:这里的数据也可以远程调用,根据实际情况来操作
  Integer loginNum = RandomUtils.nextInt(100,200); // 登录数
  Integer videoViewNum = RandomUtils.nextInt(100,200); // 视频播放数
  Integer courseNum = RandomUtils.nextInt(100,200);   // 每日课程新增个数

  // 添加到统计表中
  Daily daily = new Daily();
  daily.setRegisterNum(registerNum);
  daily.setLoginNum(loginNum);
  daily.setVideoViewNum(videoViewNum);
  daily.setCourseNum(courseNum);
  daily.setDateCalculated(day);
  this.save(daily);
}

5、edu-statistics的web层接口的定义DailyAdminController

@ApiOperation(value = "新增每日统计数据记录")
@GetMapping("{day}")
public R createStatisticsByDay(@ApiParam(name = "day",value = "日期",example = "2020-05-08",required = true)
       @PathVariable String day){
  dailyService.saveStatisticsByDay(day);
  return R.ok();
}

启动edu-eureka、edu-ucenter、edu-statistics,使用swagger测试

成功,edu-statistics通过feign请求edu-ucenter的count-register获取注册数,保存到数据库

4、前端配置统计分析

前端后台vue工程web-admin,

1、/src/router/index.js增加菜单路由

{
  path: '/statistics/daily',
    component: Layout,
      meta: { title: '统计分析', icon: 'chart' },
        name: 'statisticsDaily',
          children: [
            {
              path: 'create',
              component: () => import('@/views/statistics/create'),
              name: 'StatisticsDailyCreate',
              meta: { title: '生成统计', icon: 'form' }
            }
          ]
},

2、/src/api/statistics/daily.js 接口函数

import request from '@/utils/request'

const api_name = '/admin/statistics/daily'
export default{

  createStatistics(day) {
    return request({
      url: `${api_name}/${day}`,
      method: 'get'
    })
  }
}

3、/src/views/statistics/create.vue 模版页面

<template>
  <div class="app-container">
    <el-form :inline="true">
      <!-- 日期 -->
      <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>
</template>

<script>
import daily from '@/api/statistics/daily'
export default {
  data() {
    return {
      day: '',
      btnDisabled: false
    }
  },
  methods: {
    create() {
      this.btnDisabled = true
      daily.createStatistics(this.day).then(response => {
        this.btnDisabled = false
        this.$message({
          type: 'success',
          message: '生成成功'
        })
      })
    }
  }
}
</script>

启动edu-eureka、edu-admin-login、edu-ucenter、edu-statistics ,登录测试:

5、Echarts 图表

ECharts,一个使用 JavaScript 实现的开源可视化库,可以流畅的运行在 PC 和移动设备上,兼容当前绝大部分浏览器(IE8/9/10/11,Chrome,Firefox,Safari等),底层依赖矢量图形库 ZRender,提供直观,交互丰富,可高度个性化定制的数据可视化图表。

官网示例:https://echarts.apache.org/examples/zh/index.html

集成到项目中

前端后台vue工程web-admin,安装echarts

npm install echarts --save

1、/src/router/index.js 增加菜单路由统计图表

{
  path: '/statistics/daily',
  component: Layout,
  meta: { title: '统计分析', icon: 'dashboard' },
  name: 'statisticsDaily',
  children: [
    {
      path: 'create',
      component: () => import('@/views/statistics/create'),
      name: 'StatisticsDailyCreate',
      meta: { title: '生成统计' }
    },
    {
      path: 'chart',
      component: () => import('@/views/statistics/chart'),
      name: 'StatisticsDailyChart',
      meta: { title: '统计图表'}
    }
  ]
}

2、/src/api/statistics/daily.js 增加接口函数

// 获取统计数据
showChart(searchObj) {
  return request({
    url: `${api_name}/show-chart/${searchObj.begin}/${searchObj.end}/${searchObj.type}`,
    method: 'get'
  })
}

3、/src/views/statistics/chart.vue 模版页面

<template>
  <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>
</template>

<script>
import echarts from 'echarts'
import daily from '@/api/statistics/daily'

export default {
  data() {
    return {
      // 查询条件
      searchObj: {
        type: '',
        begin: '',
        end: ''
      },
      btnDisabled: false,
      // 图表数据
      chart: null,
      title: '',
      xData: [],
      yData: []
    }
  },
  methods: {
    showChart() {
      this.initChartData()
      // this.setChart()//放在initChartData回调中执行
    },

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

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

        // 当前统计类别
        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 = {
        title: {
          text: this.title
        },
        // x轴是类目轴(离散数据),必须通过data设置类目数据
        xAxis: {
          type: 'category',
          data: this.xData// -------绑定数据
        },
        // y轴是数据轴(连续数据)
        yAxis: {
          type: 'value'
        },
        // 系列列表。每个系列通过 type 决定自己的图表类型
        series: [{
          // 系列中的数据内容数组
          data: this.yData, // -------绑定数据
          // 折线图
          type: 'line'
        }],
        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
        }]
      }

      this.chart.setOption(option)
    }
  }
}
</script>

后端接口

1、edu-statistics 统计中心服务的业务层接口实现类DailyServiceImpl

@Override
public Map<String, Object> getChartData(String begin, String end, String type) {
  List<Daily> dayList = this.list(new QueryWrapper<Daily>().select(type,"date_calculated")
    .between("date_calculated",begin,end));

  Map<String, Object> map = new HashMap<>();
  List<Integer> dataList = new ArrayList<Integer>();
  List<String> dateList = new ArrayList<String>();
  map.put("dataList", dataList);
  map.put("dateList", dateList);


  for (int i = 0; i < dayList.size(); i++) {
    Daily daily = dayList.get(i);
    dateList.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;
}

2、edu-statistics 统计中心服务的web层接口定义DailyAdminController

@ApiOperation(value = "查询统计报表数据")
@GetMapping("show-chart/{begin}/{end}/{type}")
public R showChart(@ApiParam(name = "begin",value = "开始日期",required = true) @PathVariable String begin,
                    @ApiParam(name = "end",value = "截止日期",required = true) @PathVariable String end,
                    @ApiParam(name = "type",value = "报表类型",required = true) @PathVariable String type){
  Map<String, Object> map = dailyService.getChartData(begin, end, type);
  return R.ok().data(map);
}

启动测试,获取后端数据渲染图表

拓展:L7 地理空间数据可视化

旧版本官网:http://antv-2018.alipay.com/zh-cn/l7/1.x/index.html

新版本官网:https://antv.gitee.io/zh

好炫酷!

Post Directory