这里写自定义目录标题

  • 第 1 章 数据可视化接口
    • 1.1 设计思路
    • 1.2 需求梳理
      • 1.2.1 最终显示效果图
      • 1.2.2 分析可视化大屏
      • 1.2.3 接口执行过程
  • 第 2 章 Sugar 数据大屏
    • 2.1 产品介绍
    • 2.2 使用入口
    • 2.3 创建数据大屏
  • 第 3 章 总成交金额接口
    • 3.1 Sugar 组件:数字翻牌器
      • 3.1.1 添加组件
      • 3.1.2 配置组件
      • 3.1.3 查询组件需要的数据格式
      • 3.1.4 接口访问路径以及返回格式
    • 3.2 数据接口实现
      • 3.2.1 创建数据接口模块
      • 3.2.2 代码分层结构以及实现
      • 3.2.3 测试本地接口
    • 3.3 内网穿透
      • 3.3.1 作用
      • 3.3.2 工具
    • 3.4 配置 Sugar 大屏
      • 3.4.1 配置服务器全局 Host
      • 3.4.2 大屏刷新数据
      • 第 4 章 商品交易额不同维度的统计
    • 4.1 三个关于商品交易额方面的统计
    • 4.2 Sugar 组件:横向柱图、轮播饼图、轮播表格
      • 4.2.1 添加组件
      • 4.2.2 品牌排行的柱形图组件配置
      • 4.2.3 品类分布的饼形图组件配置
      • 4.2.4 商品排行的轮播表格组件配置
    • 4.3 数据接口实现
      • 4.3.1 创建商品交易额统计实体类 ProductStats
      • 4.3.2 Mapper 层:在 ProductStatsMapper 中添加方法
      • 4.3.3 Service 层:在 ProductStatsService 中增加方法
      • 4.3.4 Service 层:在 ProductStatsServiceImpl 增加方法实现
      • 4.3.5 Controller 层:在 SugarCongroller 添加方法
      • 4.3.6 本地接口测试
    • 4.4 刷新大屏图表数据
  • 第 5 章 分省市的热力图统计
    • 5.1 Sugar 组件:中国省份色彩
      • 5.1.1 添加组件
      • 5.1.2 配置组件
      • 5.1.3 接口访问路径以及返回格式
    • 5.2 数据接口实现
      • 5.2.1 创建地区交易额统计实体类 ProvinceStats
      • 5.2.2 Mapper 层:创建 ProvinceStatsMapper 接口
      • 5.2.3 Service 层:创建 ProvinceStatsService 接口
      • 5.2.4 Service 层:创建 ProvinceStatsServiceImpl 实现类
      • 5.2.5 Controller 层:在 SugarController 中增加方法
  • 第 6 章 流量统计数据
    • 6.1 Sugar 组件:表格
      • 6.1.1 添加组件
      • 6.1.2 新老访客对比的表格组件配置
      • 6.1.3 分时流量显示的折线组件配置
    • 6.2 数据接口实现
      • 6.2.1 创建访问流量统计实体类 VisitorStats
      • 6.2.2 Mapper 层:创建 VisitorStatsMapper
      • 6.2.3 Service 层:创建 VisitorStatsService 接口
      • 6.2.4 Service 层:创建 VisitorStatsServiceImpl 实现类
      • 6.2.5 Controller 层:在 SugarController 中增加方法
      • 6.2.6 本地接口测试
  • 第 7 章 热词字符云
    • 7.1 Sugar 组件:字符云
      • 7.1.1 添加组件
      • 7.1.2 配置组件
      • 7.1.3 接口访问路径以及返回格式
    • 7.2 数据接口实现
      • 7.2.1 创建关键词统计实体类
      • 7.2.2 Mapper 层:创建 KeywordStatsMapper
      • 7.2.3 Service 层:创建 KeywordStatsService 接口
      • 7.2.4 Service 层:创建 KeywordStatsServiceImpl
      • 7.2.5 Controller 层:在 SugarController 中增加方法
      • 7.2.6 本地接口测试
  • 第 9 章 总结

第 1 章 数据可视化接口

1.1 设计思路

之前数据分层处理,最后把轻度聚合的结果保存到 ClickHouse 中,主要的目的就是提供即时的数据查询、统计、分析服务。这些统计服务一般会用两种形式展现,一种是为专业的数据分析人员的 BI 工具,一种是面向非专业人员的更加直观的数据大屏。
以下主要是面向百度的 sugar 的数据大屏服务的接口开发。

1.2 需求梳理

1.2.1 最终显示效果图

1.2.2 分析可视化大屏


在可视化大屏中每个组件都需要一个单独的接口,图中一共涉及 8 个组件。

1.2.3 接口执行过程


之前我们实现了 DWS 层计算后写入到 ClickHouse 中,接下来就是要为可视化大屏服务,提供一个数据接口用来查询 ClickHouse 中的数据。这里主要有两项工作

➢ 配置可视化大屏服务。
➢ 编写数据查询接口以供可视化大屏进行访问。

第 2 章 Sugar 数据大屏

2.1 产品介绍

Sugar 是百度云推出的敏捷 BI 和数据可视化平台,目标是解决报表和大屏的数据 BI 分析和可视化问题,解放数据可视化系统的开发人力。

2.2 使用入口

https://cloud.baidu.com/product/sugar.html

2.3 创建数据大屏

第 3 章 总成交金额接口

3.1 Sugar 组件:数字翻牌器

3.1.1 添加组件

从大屏的编辑器上方选择【指标】→【数字翻牌器】

3.1.2 配置组件

点击组件,在右侧的菜单中选择【数据】,绑定方式改为【API 拉取】
下方的路径填写 $API_HOST/api/sugar/gmv
这个就是 sugar 会周期性访问的数据接口地址,可以自定义,其中$API_HOST 是个全局变量,需要在空间中配置(后面再说)。

3.1.3 查询组件需要的数据格式

在数据绑定的位置选择【静态 JSON】,可以看到数据需要的 JSON 格式

3.1.4 接口访问路径以及返回格式

➢ 访问路径

/api/sugar/gmv

➢ 返回格式

{"status": 0,"msg": "","data": 1201081.1632389291
}

3.2 数据接口实现

3.2.1 创建数据接口模块

  1. 在 gmall2021-parent 项目下创建新的模块 gmall2021-publisher
  2. 在 pom.xml 文件中添加需要的依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.atguigu</groupId><artifactId>gmall2021-publisher-test</artifactId><version>0.0.1-SNAPSHOT</version><name>gmall2021-publisher-test</name><description>gmall2021-publisher-test</description><properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.4.1</spring-boot.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.4</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.11</version></dependency><dependency><groupId>ru.yandex.clickhouse</groupId><artifactId>clickhouse-jdbc</artifactId><version>0.1.55</version></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>2.4.1</version><configuration><mainClass>com.atguigu.gmall2021publishertest.Gmall2021PublisherTestApplication</mainClass></configuration><executions><execution><id>repackage</id><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build></project>

3.2.2 代码分层结构以及实现

➢ 代码结构

  1. 修改 Springboot 核心配置文件 application.properties
server.port=8070
#配置 ClickHouse 驱动以及 URL
spring.datasource.driver-class-name=ru.yandex.clickhouse.ClickHouseDriver
spring.datasource.url=jdbc:clickhouse://hadoop102:8123/default
  1. 在 Application 中添加@MapperScan 的注解
package com.atguigu.gmall2021publishertest;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
@MapperScan(basePackages = "com.atguigu.gmall2021publishertest.mapper")
public class Gmall2021PublisherTestApplication {public static void main(String[] args) {SpringApplication.run(Gmall2021PublisherTestApplication.class, args);}}
  1. Mapper 层:创建 ProductStatsMapper 接口
package com.atguigu.gmall2021publishertest.mapper;import org.apache.ibatis.annotations.Select;import java.math.BigDecimal;public interface ProductStatsMapper {// select sum(order_amount) from product_stats_2021 where toYYYYMMDD(stt)=20210901;@Select("select sum(order_amount) from product_stats_2021 where toYYYYMMDD(stt)=#{date}")BigDecimal selectGMV(int date);
}
  1. Service 层:创建 ProductStatsService 接口
package com.atguigu.gmall2021publishertest.service;import com.atguigu.gmall2021publishertest.mapper.ProductStatsMapper;
import org.springframework.beans.factory.annotation.Autowired;import java.math.BigDecimal;public interface SugarService {//获取某一天的总交易额public BigDecimal getGMV(int date);
}
  1. Service 层:创建 ProductStatsServiceImpl 实现类
package com.atguigu.gmall2021publishertest.service.impl;import com.atguigu.gmall2021publishertest.mapper.ProductStatsMapper;
import com.atguigu.gmall2021publishertest.service.SugarService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.math.BigDecimal;@Service
public class SugarServiceImpl implements SugarService {@Autowiredprivate ProductStatsMapper productStatsMapper;@Overridepublic BigDecimal getGMV(int date){return productStatsMapper.selectGMV(date);}
}
  1. Controller 层:创建 SugarController 类
    该类主要接收用户请求,并做出相应。根据 sugar 不同的组件,返回不同的格式
package com.atguigu.gmall2021publishertest.controller;import com.atguigu.gmall2021publishertest.service.SugarService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import java.text.SimpleDateFormat;@RestController
@RequestMapping("/api/sugar")
public class SugerController {@Autowiredprivate SugarService sugarService;@RequestMapping("/gmv")public String getGmv(@RequestParam(value = "date", defaultValue = "0" ) int date){if(date == 0){date = getToday();}return "{ " +"  \"status\": 0, " +"  \"msg\": \"\", " +"  \"data\": " + sugarService.getGMV(date)+ " " +"}";}private int getToday() {SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");String dateTime = sdf.format(System.currentTimeMillis());return Integer.parseInt(dateTime);}
}

3.2.3 测试本地接口

  1. 启动 SpringBoot 应用程序
  2. 用浏览器访问测试接口
    http://localhost:8070/api/sugar/gmv
  3. 输出结果

3.3 内网穿透

3.3.1 作用

通常个人电脑无论是连接 WIFI 上网还是用网线上网,都是属于局域网里边的,外网无法直接访问到你的电脑,内网穿透可以让你的局域网中的电脑实现被外网访问功能。

3.3.2 工具

目前国内网穿透工具很多,常见的比如花生壳、Ngrok、网云穿等。
官网:
花生壳:https://hsk.oray.com
Ngrok: http://www.ngrok.cc
网云穿:http://www.neiwangchuantou.net/

3.4 配置 Sugar 大屏

3.4.1 配置服务器全局 Host

回到 Sugar 的空间管理中,在【空间设置】中增加$API_HOST

3.4.2 大屏刷新数据

然后回到大屏配置中,刷新图表数据,能看到数字已经显示

第 4 章 商品交易额不同维度的统计

4.1 三个关于商品交易额方面的统计

➢ 品牌,水平柱状图
➢ 品类,饼形图
➢ 商品 spu,轮播图
这三个的共同特征是可以根据商品统计信息计算出来。

4.2 Sugar 组件:横向柱图、轮播饼图、轮播表格

4.2.1 添加组件

  1. 横向柱图,用于显示品牌排行
  2. 轮播饼图,用于显示品类图
  3. 轮播表格,用于显示热门商品排行

4.2.2 品牌排行的柱形图组件配置

  1. 修改获取数据的方式,指定访问路径
    访问路径: ${API_HOST}/api/sugar/trademark?limit=5
  2. 修改排序规则
    因为排序规则是从下到上,所以排序定位从小到大
  3. 查看返回值数据格式
{"status": 0,"msg": "","data": {"categories": ["苹果","三星","华为","oppo","vivo","小米62"],"series": [{"name": "手机品牌","data": [9922,5774,5323,8043,7511,6487]}]}
}

4.2.3 品类分布的饼形图组件配置

  1. 修改获取数据的方式,指定访问路径
    访问路径:${API_HOST}/api/sugar/category3
  2. 查看返回值数据格式
{"status": 0,"msg": "","data": [{"name": "PC","value": 97,"url": "http://www.baidu.com"},{"name": "iOS","value": 50,"url": "http://www.baidu.com"},{"name": "Android","value": 59,"url": "http://www.baidu.com"},{"name": "windows phone","value": 29},{"name": "Black berry","value": 3},{"name": "Nokia S60","value": 2},{"name": "Nokia S90","value": 1}]
}

4.2.4 商品排行的轮播表格组件配置

  1. 修改获取数据的方式,指定访问路径
    访问路径:${API_HOST}/api/sugar/spu?limit=10
  2. 查看返回值数据格式
{"status": 0,"msg": "","data": {"columns": [{"name": "商品名称","id": "spu_name"},{"name": "成交金额","id": "amount"}],"rows": [{"spu_name": "商品 1","amount": "金额 1"},{"spu_name": "商品 2","amount": "金额 2"},{"spu_name": "商品 3","amount": "金额 3"}]}
}

4.3 数据接口实现

这三个图基本上都是根据用不同维度进行分组,金额进行聚合的方式查询商品统计表。
直接先实现三个 sql 查询

4.3.1 创建商品交易额统计实体类 ProductStats

package com.atguigu.gmall2021publishertest.bean;import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
/*** Desc: 商品交易额统计实体类*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ProductStats {String stt;String edt;Long sku_id;String sku_name;BigDecimal sku_price;Long spu_id;String spu_name;Long tm_id ;String tm_name;Long category3_id ;String category3_name ;@Builder.DefaultLong display_ct=0L;@Builder.DefaultLong click_ct=0L;@Builder.DefaultLong cart_ct=0L;@Builder.DefaultLong order_sku_num=0L;@Builder.DefaultBigDecimal order_amount=BigDecimal.ZERO;@Builder.DefaultLong order_ct=0L;@Builder.DefaultBigDecimal payment_amount=BigDecimal.ZERO;@Builder.DefaultLong refund_ct=0L;@Builder.DefaultBigDecimal refund_amount=BigDecimal.ZERO;@Builder.DefaultLong comment_ct=0L;@Builder.DefaultLong good_comment_ct=0L ;Long ts;
}

4.3.2 Mapper 层:在 ProductStatsMapper 中添加方法

    //统计某天不同 SPU 商品交易额排名@Select("select spu_id,spu_name,sum(order_amount) order_amount," +"sum(product_stats.order_ct) order_ct from product_stats_2021 " +"where toYYYYMMDD(stt)=#{date} group by spu_id,spu_name " +"having order_amount>0 order by order_amount desc limit #{limit} ")public List<ProductStats> getProductStatsGroupBySpu(@Param("date") int date, @Param("limit") int limit);//统计某天不同类别商品交易额排名@Select("select category3_id,category3_name,sum(order_amount) order_amount " +"from product_stats_2021 " +"where toYYYYMMDD(stt)=#{date} group by category3_id,category3_name " +"having order_amount>0 order by order_amount desc limit #{limit}")public List<ProductStats> getProductStatsGroupByCategory3(@Param("date")int date ,@Param("limit") int limit);//统计某天不同品牌商品交易额排名@Select("select tm_id,tm_name,sum(order_amount) order_amount " +"from product_stats_2021 " +"where toYYYYMMDD(stt)=#{date} group by tm_id,tm_name " +"having order_amount>0 order by order_amount desc limit #{limit} ")public List<ProductStats> getProductStatsByTrademark(@Param("date")int date,@Param("limit") int limit);

4.3.3 Service 层:在 ProductStatsService 中增加方法

    //统计某天不同 SPU 商品交易额排名public List<ProductStats> getProductStatsGroupBySpu(int date, int limit);//统计某天不同类别商品交易额排名public List<ProductStats> getProductStatsGroupByCategory3(int date,int limit);//统计某天不同品牌商品交易额排名public List<ProductStats> getProductStatsByTrademark(int date,int limit);

4.3.4 Service 层:在 ProductStatsServiceImpl 增加方法实现

 @Overridepublic List<ProductStats> getProductStatsGroupBySpu(int date, int limit) {return productStatsMapper.getProductStatsGroupBySpu(date, limit);}@Overridepublic List<ProductStats> getProductStatsGroupByCategory3(int date, int limit) {return productStatsMapper.getProductStatsGroupByCategory3(date, limit);}@Overridepublic List<ProductStats> getProductStatsByTrademark(int date, int limit) {return productStatsMapper.getProductStatsByTrademark(date, limit);}

4.3.5 Controller 层:在 SugarCongroller 添加方法

注意:Controller 方法的定义必须依照,定好的接口访问路径和返回值格式。

  1. 商品列表接口方法
    @RequestMapping("/spu")public String getProductStatsGroupBySpu(@RequestParam(value = "date", defaultValue = "0") Integer date,@RequestParam(value = "limit", defaultValue = "10") int limit) {if (date == 0) date = now();List<ProductStats> statsList = productStatsService.getProductStatsGroupBySpu(date, limit);//设置表头StringBuilder jsonBuilder =new StringBuilder(" " +"{\"status\":0,\"data\":{\"columns\":[" +"{\"name\":\"商品名称\",\"id\":\"spu_name\"}," +"{\"name\":\"交易额\",\"id\":\"order_amount\"}," +"{\"name\":\"订单数\",\"id\":\"order_ct\"}]," +"\"rows\":[");//循环拼接表体for (int i = 0; i < statsList.size(); i++) {ProductStats productStats = statsList.get(i);if (i >= 1) {jsonBuilder.append(",");}jsonBuilder.append("{\"spu_name\":\"" + productStats.getSpu_name() + "\"," +"\"order_amount\":" + productStats.getOrder_amount() + "," +"\"order_ct\":" + productStats.getOrder_ct() + "}");}jsonBuilder.append("]}}");return jsonBuilder.toString();}
  1. 品类接口方法
  @RequestMapping("/category3")public String getProductStatsGroupByCategory3(@RequestParam(value = "date", defaultValue = "0") Integer date,@RequestParam(value = "limit", defaultValue = "4") int limit) {if (date == 0) {date = now();}List<ProductStats> statsList= productStatsService.getProductStatsGroupByCategory3(date, limit);StringBuilder dataJson = new StringBuilder("{ \"status\": 0, \"data\": [");int i = 0;for (ProductStats productStats : statsList) {if (i++ > 0) {dataJson.append(",");};dataJson.append("{\"name\":\"").append(productStats.getCategory3_name()).append("\",");dataJson.append("\"value\":").append(productStats.getOrder_amount()).append("}");}dataJson.append("]}");return dataJson.toString();}
  1. 品牌接口方法
 @RequestMapping("/trademark")public String getProductStatsByTrademark(@RequestParam(value = "date", defaultValue = "0") Integer date,@RequestParam(value = "limit", defaultValue = "20") int limit) {if (date == 0) {date = now();}List<ProductStats> productStatsByTrademarkList= productStatsService.getProductStatsByTrademark(date, limit);List<String> tradeMarkList = new ArrayList<>();List<BigDecimal> amountList = new ArrayList<>();for (ProductStats productStats : productStatsByTrademarkList) {tradeMarkList.add(productStats.getTm_name());amountList.add(productStats.getOrder_amount());}String json = "{\"status\":0,\"data\":{" + "\"categories\":" +"[\"" + StringUtils.join(tradeMarkList, "\",\"") + "\"],\"series\":[" +"{\"data\":[" + StringUtils.join(amountList, ",") + "]}]}}";return json;}

4.3.6 本地接口测试

  1. 可以生成当前日期数据,具体步骤如下

➢ 启动 ZK、Kafka、ClickHouse、Redis、HDFS、Hbase、Maxwell
➢ 运行 BaseDBApp
➢ 运行 OrderWideApp
➢ 运行 ProductsStatsApp
➢ 运行 rt_dblog 目录下的 jar 包
➢ 查看 ClickHouse 中 products_stats_2021 表数据

  1. 启动 SpringBoot 项目,根据访问地址分别用浏览器测试一下接口

4.4 刷新大屏图表数据

第 5 章 分省市的热力图统计

5.1 Sugar 组件:中国省份色彩

5.1.1 添加组件

在上方地图栏位中选择【中国省份色彩】

5.1.2 配置组件

  1. 修改获取数据的方式,指定访问路径
    访问路径:${API_HOST}/api/sugar/province

5.1.3 接口访问路径以及返回格式

➢ 访问路径
${API_HOST}/api/sugar/province
➢ 返回值格式

{"status": 0,"data": {"mapData": [{"name": "北京","value": 9131},{"name": "天津","value": 5740}]}
}

5.2 数据接口实现

5.2.1 创建地区交易额统计实体类 ProvinceStats

package com.atguigu.gmall2021publishertest.bean;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
/*** Desc: 地区交易额统计实体类*/
@AllArgsConstructor
@Data
@NoArgsConstructor
public class ProvinceStats {private String stt;private String edt;private String province_id;private String province_name;private BigDecimal order_amount;private String ts;
}

5.2.2 Mapper 层:创建 ProvinceStatsMapper 接口

package com.atguigu.gmall2021publishertest.mapper;
import com.atguigu.gmall2021publishertest.bean.ProvinceStats;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/*** Desc: 地区维度统计 Mapper*/
public interface ProvinceStatsMapper {//按地区查询交易额@Select("select province_name,sum(order_amount) order_amount " +"from province_stats_2021 where toYYYYMMDD(stt)=#{date} " +"group by province_id ,province_name ")public List<ProvinceStats> selectProvinceStats(int date);
}

5.2.3 Service 层:创建 ProvinceStatsService 接口

package com.atguigu.gmall2021publishertest.service;import com.atguigu.gmall2021publishertest.bean.ProvinceStats;import java.util.List;/*** Desc: 地区维度统计接口*/
public interface ProvinceStatsService {public List<ProvinceStats> getProvinceStats(int date);
}

5.2.4 Service 层:创建 ProvinceStatsServiceImpl 实现类

package com.atguigu.gmall2021publishertest.service.impl;import com.atguigu.gmall2021publishertest.bean.ProvinceStats;
import com.atguigu.gmall2021publishertest.mapper.ProvinceStatsMapper;
import com.atguigu.gmall2021publishertest.service.ProvinceStatsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/*** Desc: 按地区维度统计 Service 实现*/
@Service
public class ProvinceStatsServiceImpl implements ProvinceStatsService {@AutowiredProvinceStatsMapper provinceStatsMapper;@Overridepublic List<ProvinceStats> getProvinceStats(int date) {return provinceStatsMapper.selectProvinceStats(date);}
}

5.2.5 Controller 层:在 SugarController 中增加方法

  @AutowiredProvinceStatsService provinceStatsService;@RequestMapping("/province")public String getProvinceStats(@RequestParam(value = "date", defaultValue = "0") Integer date) {if (date == 0) {date = now();}StringBuilder jsonBuilder = new StringBuilder("{\"status\":0,\"data\":{\"mapData\":[");List<ProvinceStats> provinceStatsList = provinceStatsService.getProvinceStats(date);if (provinceStatsList.size() == 0) {// jsonBuilder.append( "{\"name\":\"北京\",\"value\":0.00}");}for (int i = 0; i < provinceStatsList.size(); i++) {if (i >= 1) {jsonBuilder.append(",");}ProvinceStats provinceStats = provinceStatsList.get(i);jsonBuilder.append("{\"name\":\"" + provinceStats.getProvince_name() +"\",\"value\":" + provinceStats.getOrder_amount() + " }");}jsonBuilder.append("]}}");return jsonBuilder.toString();}

第 6 章 流量统计数据

6.1 Sugar 组件:表格

6.1.1 添加组件

  1. 表格,用于显示新老访客对比
    在上方【表格】栏位中选择【表格】
  2. 折线图,用于显示分时流量
    在上方【图表】栏位中选择【折线图】

6.1.2 新老访客对比的表格组件配置

  1. 修改获取数据的方式,指定访问路径
    访问路径: $API_HOST/api/sugar/visitor

  2. 查看返回值数据格式

{"status": 0,"data": {"combineNum": 1,"columns": [{"name": "类别","id": "type"},{"name": "新用户","id": "new"},{"name": "老用户","id": "old"}],"rows": [{"type": "用户数","new": 123,"old": 13},{"type": "总访问页面","new": 123,"old": 145},{"type": "跳出率","new": 123,"old": 145},{"type": "平均在线时长","new": 123,"old": 145},{"type": "平均访问页面数","new": 23,"old": 145}]}
}

6.1.3 分时流量显示的折线组件配置

  1. 修改获取数据的方式,指定访问路径
    访问路径: ${API_HOST}/api/sugar/hr
  2. 查看返回值数据格式
{"status": 0,"data": {"categories": ["01","02","03","04","05"],"series": [{"name": "uv","data": [888065,892945,678379,733572,525091]},{"name": "pv","data": [563998,571831,622419,675294,708512]},{"name": "新用户","data": [563998,571831,622419,675294,708512]}]}
}

6.2 数据接口实现

6.2.1 创建访问流量统计实体类 VisitorStats

package com.atguigu.gmall2021publishertest.bean;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.math.RoundingMode;
/*** Desc: 访客流量统计实体类*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class VisitorStats {private String stt;private String edt;private String vc;private String ch;private String ar;private String is_new;private Long uv_ct = 0L;private Long pv_ct = 0L;private Long sv_ct = 0L;private Long uj_ct = 0L;private Long dur_sum = 0L;private Long new_uv = 0L;private Long ts;private int hr;//计算跳出率 = 跳出次数*100/访问次数public BigDecimal getUjRate() {if (uv_ct != 0L) {return BigDecimal.valueOf(uj_ct).multiply(BigDecimal.valueOf(100)).divide(BigDecimal.valueOf(sv_ct), 2, RoundingMode.HALF_UP);} else {return BigDecimal.ZERO;}}//计算每次访问停留时间(秒) = 当日总停留时间(毫秒)/当日访问次数/1000public BigDecimal getDurPerSv() {if (uv_ct != 0L) {return BigDecimal.valueOf(dur_sum).divide(BigDecimal.valueOf(sv_ct), 0, RoundingMode.HALF_UP).divide(BigDecimal.valueOf(1000), 1, RoundingMode.HALF_UP);} else {return BigDecimal.ZERO;}}//计算每次访问停留页面数 = 当日总访问页面数/当日访问次数public BigDecimal getPvPerSv() {if (uv_ct != 0L) {return BigDecimal.valueOf(pv_ct).divide(BigDecimal.valueOf(sv_ct), 2, RoundingMode.HALF_UP);} else {return BigDecimal.ZERO;}}
}

6.2.2 Mapper 层:创建 VisitorStatsMapper

package com.atguigu.gmall2021publishertest.mapper;import com.atguigu.gmall2021publishertest.bean.VisitorStats;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/*** Desc: 访客流量统计 Mapper*/
public interface VisitorStatsMapper {//新老访客流量统计@Select("select is_new,sum(uv_ct) uv_ct,sum(pv_ct) pv_ct," +"sum(sv_ct) sv_ct, sum(uj_ct) uj_ct,sum(dur_sum) dur_sum " +"from visitor_stats_2021 where toYYYYMMDD(stt)=#{date} group by is_new")public List<VisitorStats> selectVisitorStatsByNewFlag(int date);//分时流量统计@Select("select sum(if(is_new='1', visitor_stats_2021.uv_ct,0)) new_uv,toHour(stt) hr," +"sum(visitor_stats_2021.uv_ct) uv_ct, sum(pv_ct) pv_ct, sum(uj_ct) uj_ct " +"from visitor_stats_2021 where toYYYYMMDD(stt)=#{date} group by toHour(stt)")public List<VisitorStats> selectVisitorStatsByHour(int date);@Select("select count(pv_ct) pv_ct from visitor_stats_2021 " +"where toYYYYMMDD(stt)=#{date} ")public Long selectPv(int date);@Select("select count(uv_ct) uv_ct from visitor_stats_2021 " +"where toYYYYMMDD(stt)=#{date} ")public Long selectUv(int date);
}

6.2.3 Service 层:创建 VisitorStatsService 接口

package com.atguigu.gmall2021publishertest.service;import com.atguigu.gmall2021publishertest.bean.VisitorStats;import java.util.List;public interface VisitorStatsService {public List<VisitorStats> getVisitorStatsByNewFlag(int date);public List<VisitorStats> getVisitorStatsByHour(int date);public Long getPv(int date);public Long getUv(int date);
}

6.2.4 Service 层:创建 VisitorStatsServiceImpl 实现类

package com.atguigu.gmall2021publishertest.service.impl;
import com.atguigu.gmall2021publishertest.bean.VisitorStats;
import com.atguigu.gmall2021publishertest.mapper.VisitorStatsMapper;
import com.atguigu.gmall2021publishertest.service.VisitorStatsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/*** Desc: 访问流量统计 Service 实现类*/
@Service
public class VisitorStatsServiceImpl implements VisitorStatsService {@AutowiredVisitorStatsMapper visitorStatsMapper;@Overridepublic List<VisitorStats> getVisitorStatsByNewFlag(int date) {return visitorStatsMapper.selectVisitorStatsByNewFlag(date);}@Overridepublic List<VisitorStats> getVisitorStatsByHour(int date) {return visitorStatsMapper.selectVisitorStatsByHour(date);}@Overridepublic Long getPv(int date) {return visitorStatsMapper.selectPv(date);}@Overridepublic Long getUv(int date) {return visitorStatsMapper.selectUv(date);}
}

6.2.5 Controller 层:在 SugarController 中增加方法

  1. 新老访客流量对比
    @AutowiredVisitorStatsService visitorStatsService;@RequestMapping("/visitor")public String getVisitorStatsByNewFlag(@RequestParam(value = "date", defaultValue = "0")Integer date) {if (date == 0) date = now();List<VisitorStats> visitorStatsByNewFlag =visitorStatsService.getVisitorStatsByNewFlag(date);VisitorStats newVisitorStats = new VisitorStats();VisitorStats oldVisitorStats = new VisitorStats();//循环把数据赋给新访客统计对象和老访客统计对象for (VisitorStats visitorStats : visitorStatsByNewFlag) {if (visitorStats.getIs_new().equals("1")) {newVisitorStats = visitorStats;} else {oldVisitorStats = visitorStats;}}//把数据拼接入字符串String json = "{\"status\":0,\"data\":{\"combineNum\":1,\"columns\":" +"[{\"name\":\"类别\",\"id\":\"type\"}," +"{\"name\":\"新用户\",\"id\":\"new\"}," +"{\"name\":\"老用户\",\"id\":\"old\"}]," +"\"rows\":" +"[{\"type\":\"用户数(人)\"," +"\"new\": " + newVisitorStats.getUv_ct() + "," +"\"old\":" + oldVisitorStats.getUv_ct() + "}," +"{\"type\":\"总访问页面(次)\"," +"\"new\":" + newVisitorStats.getPv_ct() + "," +"\"old\":" + oldVisitorStats.getPv_ct() + "}," +"{\"type\":\"跳出率(%)\"," +"\"new\":" + newVisitorStats.getUjRate() + "," +"\"old\":" + oldVisitorStats.getUjRate() + "}," +"{\"type\":\"平均在线时长(秒)\"," +"\"new\":" + newVisitorStats.getDurPerSv() + "," +"\"old\":" + oldVisitorStats.getDurPerSv() + "}," +"{\"type\":\"平均访问页面数(人次)\"," +"\"new\":" + newVisitorStats.getPvPerSv() + "," +"\"old\":" + oldVisitorStats.getPvPerSv()+ "}]}}";return json;}
  1. 分时流量统计
 @RequestMapping("/hr")public String getMidStatsGroupbyHourNewFlag(@RequestParam(value = "date",defaultValue ="0") Integer date ) {if(date==0) date=now();List<VisitorStats> visitorStatsHrList= visitorStatsService.getVisitorStatsByHour(date);//构建 24 位数组VisitorStats[] visitorStatsArr=new VisitorStats[24];//把对应小时的位置赋值for (VisitorStats visitorStats : visitorStatsHrList) {visitorStatsArr[visitorStats.getHr()] =visitorStats ;}List<String> hrList=new ArrayList<>();List<Long> uvList=new ArrayList<>();List<Long> pvList=new ArrayList<>();List<Long> newMidList=new ArrayList<>();//循环出固定的 0-23 个小时 从结果 map 中查询对应的值for (int hr = 0; hr <=23 ; hr++) {VisitorStats visitorStats = visitorStatsArr[hr];if (visitorStats!=null){uvList.add(visitorStats.getUv_ct()) ;pvList.add( visitorStats.getPv_ct());newMidList.add( visitorStats.getNew_uv());}else{ //该小时没有流量补零uvList.add(0L) ;pvList.add( 0L);newMidList.add( 0L);}//小时数不足两位补零hrList.add(String.format("%02d", hr));}//拼接字符串String json = "{\"status\":0,\"data\":{" + "\"categories\":" +"[\""+StringUtils.join(hrList,"\",\"")+ "\"],\"series\":[" +"{\"name\":\"uv\",\"data\":["+ StringUtils.join(uvList,",") +"]}," +"{\"name\":\"pv\",\"data\":["+ StringUtils.join(pvList,",") +"]}," +"{\"name\":\"新用户\",\"data\":["+ StringUtils.join(newMidList,",") +"]}]}}";return json;

6.2.6 本地接口测试

  1. 可以生成当前日期数据,具体步骤如下
    ➢ 启动 ZK、Kafka、Logger.sh、ClickHouse
    ➢ 运行 BaseLogApp
    ➢ 运行 UniqueVisitApp
    ➢ 运行 UserJumpDetailApp
    ➢ 运行 VisitorStatsApp
    ➢ 运行 rt_applog 目录下的 jar 包
    ➢ 查看 ClickHouse 中 visitor_stats_2021 表数据
  2. 启动 SpringBoot 项目,根据访问地址分别用浏览器测试一下接口

6.3 刷新大屏组件数据

第 7 章 热词字符云

7.1 Sugar 组件:字符云

7.1.1 添加组件

在上方【文字】栏位中选择【字符云】

7.1.2 配置组件

访问路径:${API_HOST}/api/sugar/keyword

7.1.3 接口访问路径以及返回格式

➢ 访问路径
${API_HOST}/api/sugar/keyword
➢ 返回值格式

{"status": 0,"data": [{"name": "data","value": 60679,},{"name": "dataZoom","value": 24347,}]
}

7.2 数据接口实现

7.2.1 创建关键词统计实体类

package com.atguigu.gmall2021publishertest.bean;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/*** Desc: 关键词统计实体类*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class KeywordStats {private String stt;private String edt;private String keyword;private Long ct;private String ts;
}

7.2.2 Mapper 层:创建 KeywordStatsMapper

  1. SQL 语句
    根据关键词的出现类型分配不同的热度分数
    ➢ 搜索关键词=10 分
    ➢ 下单商品=5 分
    ➢ 加入购物车=2 分
    ➢ 点击商品=1 分
    ➢ 其他=0 分
    其中 ClickHouse 函数 multiIf 类似于 case when
select keyword,
sum(keyword_stats_2021.ct *
multiIf(
source='SEARCH',10,
source='ORDER',5,
source='CART',2,
source='CLICK',1,0
)) ct
from
keyword_stats
where
toYYYYMMDD(stt)=#{date}
group by
keyword
order by
sum(keyword_stats.ct)
limit #{limit};
  1. 接口类
package com.atguigu.gmall2021publishertest.mapper;import com.atguigu.gmall2021publishertest.bean.KeywordStats;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/*** Desc: 关键词统计 Mapper*/
public interface KeywordStatsMapper {@Select("select keyword," +"sum(keyword_stats_2021.ct * " +"multiIf(source='SEARCH',10,source='ORDER',3,source='CART',2,source='CLICK',1,0)) ct"+" from keyword_stats_2021 where toYYYYMMDD(stt)=#{date} group by keyword " +"order by sum(keyword_stats_2021.ct) desc limit #{limit} ")public List<KeywordStats> selectKeywordStats(@Param("date") int date, @Param("limit") intlimit);
}

7.2.3 Service 层:创建 KeywordStatsService 接口

package com.atguigu.gmall2021publishertest.service;
import com.atguigu.gmall2021publishertest.bean.KeywordStats;import java.util.List;
/*** Desc: 关键词统计接口*/
public interface KeywordStatsService {public List<KeywordStats> getKeywordStats(int date, int limit);
}

7.2.4 Service 层:创建 KeywordStatsServiceImpl

package com.atguigu.gmall2021publishertest.service.impl;
import com.atguigu.gmall2021publishertest.bean.KeywordStats;
import com.atguigu.gmall2021publishertest.mapper.KeywordStatsMapper;
import com.atguigu.gmall2021publishertest.service.KeywordStatsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/*** Desc:关键词统计接口实现类*/
@Service
public class KeywordStatsServiceImpl implements KeywordStatsService {@AutowiredKeywordStatsMapper keywordStatsMapper;@Overridepublic List<KeywordStats> getKeywordStats(int date, int limit) {return keywordStatsMapper.selectKeywordStats(date,limit);}
}

7.2.5 Controller 层:在 SugarController 中增加方法

    @Autowiredprivate KeywordStatsService keywordStatsService;@RequestMapping("/keyword")public String getKeywordStats(@RequestParam(value = "date",defaultValue = "0") Integer date,@RequestParam(value = "limit",defaultValue = "20") intlimit){if(date==0){date=now();}//查询数据List<KeywordStats> keywordStatsList= keywordStatsService.getKeywordStats(date, limit);StringBuilder jsonSb=new StringBuilder( "{\"status\":0,\"msg\":\"\",\"data\":[" );//循环拼接字符串for (int i = 0; i < keywordStatsList.size(); i++) {KeywordStats keywordStats = keywordStatsList.get(i);if(i>=1){jsonSb.append(",");}jsonSb.append( "{\"name\":\"" + keywordStats.getKeyword() + "\"," +"\"value\":"+keywordStats.getCt()+"}");}jsonSb.append( "]}");return jsonSb.toString();}

7.2.6 本地接口测试

第 9 章 总结

数据接口部分开发的重点:
➢ 学会通过 springboot 搭建一个 web 服务。
➢ 学会在 Web 服务使用注解方式,通过 SQL 语句查询 ClickHouse。
➢ 学会通过 Sugar 实现数据大屏可视化配置,了解其中的地图、柱形图、饼图、折线图、
表格、轮播表、字符云等组件的使用预配置。
➢ 学会使用内网穿透工具,方便调试本地接口与互联网服务对接

【学习笔记】尚硅谷大数据项目之Flink实时数仓---数据可视化接口实现相关推荐

  1. 大数据项目之Flink实时数仓(数据采集/ODS层)

    项目概览 实时大屏效果

  2. 电商数仓描述_笔记-尚硅谷大数据项目数据仓库-电商数仓V1.2新版

    架构 项目框架 数仓架构 存储压缩 Snappy与LZO LZO安装: 读取LZO文件时,需要先创建索引,才可以进行切片. 框架版本选型Apache:运维麻烦,需要自己调研兼容性. CDH:国内使用最 ...

  3. maven学习笔记——尚硅谷

    文章目录 maven学习笔记--尚硅谷 第一章 Maven概述 第一节 为什么要学习Maven 1.Maven 作为依赖管理工具 1.1 jar 包的规模 1.2 jar 包的来源 1.3 jar 包 ...

  4. MySQL学习笔记——尚硅谷李玉婷经典版MySQL基础笔记(一)

    MySQL学习笔记--尚硅谷李玉婷经典版MySQL基础笔记(一) MySQL学习笔记目录 MySQL学习笔记--尚硅谷李玉婷经典版MySQL基础笔记(一) 一.基础知识 1.MySQL的语法规范 2. ...

  5. 【Flink实时数仓】数据仓库项目实战 《四》日志数据分流 【DWD】

    文章目录 [Flink实时数仓]数据仓库项目实战 <四>日志数据分流-流量域 [DWD] 1.流量域未经加工的事务事实表 1.1主要任务 1.1.1数据清洗(ETL) 1.1.2新老访客状 ...

  6. 实时数仓-数据时效性如何保障?

    实时数仓-数据时效性如何保障? 1.序篇 2.起因篇-为什么要做数据时效保障 3.定义篇-数据时效保障包含哪些内容 4.目标篇-时效性监控以及保障的目标 5.机制篇-怎么去做数据时效监控以及保障 5. ...

  7. Java学习笔记 | 尚硅谷项目三详解

    该笔记基于B站视频:尚硅谷Java入门视频教程 目录 1,目标 2,需求说明 2.1,功能实现 2.1,菜单显示 2.2,添加功能 2.3,删除功能 2.3,查看团队成员 3,软件设计结构 4,具体实 ...

  8. Rabbitmq学习笔记(尚硅谷2021)

    Rabbitmq学习笔记 (尚硅谷) 1.MQ 的概念 1.1 什么是 MQ? 1.2 为什么要用 MQ? 削峰 解耦 异步 1.3 MQ 的分类 ActiveMQ Kafka RocketMQ Ra ...

  9. 【HBase学习笔记-尚硅谷-Java API shell命令 谷粒微博案例】

    HBase学习笔记 HBase 一.HBase简介 1.HBase介绍 2.HBase的逻辑结构和物理结构 3.数据模型 4.基本架构 二.快速入门 1.配置HBase 2.命令 三.API 1.获取 ...

  10. Springboot学习笔记 | 尚硅谷雷神

    一.springboot入门 1.导入依赖 导入springboot版本仲裁中心 <parent><groupId>org.springframework.boot</g ...

最新文章

  1. c语言课程设计商品销售系统,c语言课程设计商品销售管理系统.pdf
  2. oracle有text字段吗,Oracle Text简介
  3. linux编程-open函数和write函数实现copy命令
  4. mysql explain insert_MySQL之EXPLAIN 执行计划详解
  5. 【Tomcat】Tomcat下设置项目为默认项目
  6. iOS开发过程中常见错误问题及解决方案
  7. matlab 音频处理、Python音频处理
  8. git解决 remote: Permission to wuheng1991/site-manager.git denied to XXX
  9. 【php】 php 的注释和结束符号之间的关系
  10. IDEA热更新插件-JRebel安装
  11. FME数据转换教程——MapGIS .WL/WP 转ArcGIS .Shp
  12. unity3D 如何提取游戏资源
  13. Java物流项目第一天 项目概述与基础数据服务开发
  14. TOM邮箱6.0版新功能体验—全新的交互设计
  15. 读良葛格初心者之路有感
  16. C# 处理PPT水印(二)——去除水印效果(文本水印、图片水印)
  17. Quartus 平台 FPGA 片内 RAM 使用
  18. 鉴源实验室丨汽车电子架构和CAN网络基础
  19. Python 计算思维训练——字典与字符串练习(一)
  20. IDE硬盘与SATA的表示

热门文章

  1. [Win]chrome 离线下载
  2. VS Code弹窗:尝试在目标目录创建文件时出错
  3. C#海康解码器上大屏代码事例
  4. 工业基础类IFC—概述
  5. 52个外文文献论文网站,写论文的你必囤!
  6. Android实现立体滚轮控件,Camera和Matrix实现真正的3D(WheelView)滚轮控件
  7. vue项目 echarts 中国地图,vue项目 echarts中国地图点击省份显示对应它的各个市,从零开始。
  8. 讲解wpe抓包,封包
  9. 商汤连发11款新品,把自己逼上“AI落地”极限
  10. linux mud 游戏,一笑天涯MUD游戏