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

2023-05-16

这里写自定义目录标题

  • 第 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 {

    @Autowired
    private ProductStatsMapper productStatsMapper;

    @Override
    public 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 {

    @Autowired
    private 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.Default
    Long display_ct=0L;
    @Builder.Default
    Long click_ct=0L;
    @Builder.Default
    Long cart_ct=0L;
    @Builder.Default
    Long order_sku_num=0L;
    @Builder.Default
    BigDecimal order_amount=BigDecimal.ZERO;
    @Builder.Default
    Long order_ct=0L;
    @Builder.Default
    BigDecimal payment_amount=BigDecimal.ZERO;
    @Builder.Default
    Long refund_ct=0L;
    @Builder.Default
    BigDecimal refund_amount=BigDecimal.ZERO;
    @Builder.Default
    Long comment_ct=0L;
    @Builder.Default
    Long 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 增加方法实现

 @Override
    public List<ProductStats> getProductStatsGroupBySpu(int date, int limit) {
        return productStatsMapper.getProductStatsGroupBySpu(date, limit);
    }
    @Override
    public List<ProductStats> getProductStatsGroupByCategory3(int date, int limit) {
        return productStatsMapper.getProductStatsGroupByCategory3(date, limit);
    }
    @Override
    public 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 {
    @Autowired
    ProvinceStatsMapper provinceStatsMapper;
    @Override
    public List<ProvinceStats> getProvinceStats(int date) {
        return provinceStatsMapper.selectProvinceStats(date);
    }
}

5.2.5 Controller 层:在 SugarController 中增加方法

  @Autowired
    ProvinceStatsService 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;
        }
    }
    //计算每次访问停留时间(秒) = 当日总停留时间(毫秒)/当日访问次数/1000
    public 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 {
    @Autowired
    VisitorStatsMapper visitorStatsMapper;
    @Override
    public List<VisitorStats> getVisitorStatsByNewFlag(int date) {
        return visitorStatsMapper.selectVisitorStatsByNewFlag(date);
    }
    @Override
    public List<VisitorStats> getVisitorStatsByHour(int date) {
        return visitorStatsMapper.selectVisitorStatsByHour(date);

    }
    @Override
    public Long getPv(int date) {
        return visitorStatsMapper.selectPv(date);
    }
    @Override
    public Long getUv(int date) {
        return visitorStatsMapper.selectUv(date);
    }
}

6.2.5 Controller 层:在 SugarController 中增加方法

  1. 新老访客流量对比
    @Autowired
    VisitorStatsService 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") int
            limit);
}

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 {
    @Autowired
    KeywordStatsMapper keywordStatsMapper;
    @Override
    public List<KeywordStats> getKeywordStats(int date, int limit) {
        return keywordStatsMapper.selectKeywordStats(date,limit);
    }
}

7.2.5 Controller 层:在 SugarController 中增加方法

    @Autowired
    private KeywordStatsService keywordStatsService;

    @RequestMapping("/keyword")
    public String getKeywordStats(@RequestParam(value = "date",defaultValue = "0") Integer date,
                                  @RequestParam(value = "limit",defaultValue = "20") int
                                          limit){
        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 实现数据大屏可视化配置,了解其中的地图、柱形图、饼图、折线图、
表格、轮播表、字符云等组件的使用预配置。
➢ 学会使用内网穿透工具,方便调试本地接口与互联网服务对接

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

  • Ubuntu向日葵锁定之后忘记密码后解除锁定状态

    此操作会重置本机识别码与本机验证码 我们在使用向日葵的时候会使用锁定按钮 设置完密码之后 xff0c 我们忘了 xff0c 就会导致无法使用向日葵 重新安装也不能解决问题 xff0c 这个时候我们找到etc orayconfig conf
  • 26.疲劳检测

    目录 1 项目介绍 2 代码实现 2 1 导入库 2 2 定义68个关键点 2 3 定义eye aspect ratio 2 4 定义参数 2 5 定义阈值 2 6 定义次数 2 7 创建检测器 2 8 获取左眼与右眼的起始点与终止点 2
  • NX点亮oled

    效果是这样的 目录 1 接线 2 配置环境 3 运行代码 4 显示开发板信息 1 接线 小屏幕的名称叫oled xff0c 使用芯片SSD1306驱动 上面有四个引脚 xff0c 与NX接线如下 VCC 5V GND GND SDA 3 S
  • 43.一维卷积-航空公司评论情感预测

    之前我们使用的都是二维卷积 xff0c 二维卷积处理图像问题 xff0c 这次我们使用一维卷积 xff0c 一维卷积处理序列问题 一维卷积就是在一个序列上进行滑动 xff0c 从而得出一维卷积的结果 xff0c 详细一维卷积的介绍可以看一下
  • serial库常见用法

    安装的时候要输入 pip install pyserial 进行安装 serial是python做串口通讯的库 xff0c 在这里介绍了NX与Windows串口通讯 NX串口通讯windows Suyuoa的博客 CSDN博客 目录 1 使
  • Ubuntu开机自启动一些东西

    有三种方式做开机自启动 目录 1 免除sudo密码 2 Startup 2 desktop 3 service 1 免除sudo密码 做完这一步你的所有sudo命令都不会再让你输密码了 如果你的开机自启动的东西需要sudo xff0c 那么
  • 附录3-动态组件 component与keep-alive setup()写法

    目录 1 基本使用 2 按钮切换组件 3 keep alive 3 1 在切换组件的时候 xff0c 默认情况下被切换的组件就会被销毁 3 1 1 数据情况 3 1 2 生命周期函数情况 3 2 使用 keep alive 3 3 keep
  • 附录11-插件ESLint与prettier

    ESLint是提示错误的 xff0c prettier是帮你解决错误的 目录 1 ESLint 1 1 安装 1 2 配置 1 3 效果 2 prettier 1 ESLint 1 1 安装 1 2 配置 在插件介绍中 xff0c 搜索 e
  • 用 C 语言编写 Windows 服务程序

    NTService cpp Defines the entry point for the console application include lt windows h gt include lt stdio h gt define S
  • 10.过滤器

    过滤器是做文本格式化的 xff0c 只能用在 插值表达式 与 v bind 上 xff0c 在vue3中已经被弃用了 xff0c 这里我简单记录一下并写一下在vue3的替代方法 目录 1 基本使用 1 1 vue2中的写法 1 2 vue3
  • 24.eslint

    eslint是约束代码写法的插件 xff0c 比如组件的命名必须要用驼峰命名这种 eslint官网 检测并修复 JavaScript 代码中的问题 ESLint 插件化的 JavaScript 代码检查工具 目录 1 vue cli的esl
  • CocoaPods的使用——pod install pod install --repo-update pod update pod update --repo-update

    Podfile文件中 xff0c 使用某个库时 不指定版本 xff0c 表示希望使用最新版本 xff0c 如 pod SDWebImage 指定明确版本 xff0c 表示只想要这个版本 xff0c 如 xff1a pod 39 SDWebI
  • SceneDelegate有什么作用?删除有什么影响

    自从Xcode11发布以来 xff0c 当你使用新XCode创建一个新的iOS项目时 xff0c SceneDelegate会被默认创建 xff0c 它到底有什么用呢 xff1f 在iOS 13 xff08 及以后版本 xff09 上 xf
  • UICollectionViewCell自适应宽度

    如图所示效果 xff0c 根据字符长度自适应UICollectionViewCell的大小 xff0c 同时进行左对齐处理 如何实现 继承UICollectionViewFlowLayout创建子类 xff0c 并实现相关的方法 xff0c
  • 微信小程序开发——JS中字符和数组的操作

    字符的操作 span class token keyword var span word span class token operator 61 span span class token string 34 hello world 34
  • 微信小程序开发——字体样式设置

    font style文字样式 normal 正常字体italic 斜体字oblique 倾斜字体 font weight文字粗细 取值范围 100 900normal 相当于400bold 粗体 相当于700bolderlighter fo
  • 异常处理——richview不显示cloud路径的图片

    图片上传后 xff0c 得到的文件路径为cloud xxx png格式 xff0c 使用image组件时 xff0c 正常显示 xff0c 但使用richview富文本组件时 xff0c 未显示出来 此时 xff0c 需要通过使用wx cl
  • 编译错误“Too many arguments to function call....”

    运行编译过程中出现错误 xff0c 并提示 Too many arguments to functions call expected 的信息 xff0c 如图一 遇到这种情况时 xff0c 该如何解决呢 xff1f 解决方法是将属性 En
  • CocoaPods的使用——cocoapods的升级更新

    最近使用cocoa pods时提示版本过低需要升级才能正常使用 但是在升级过程中又出现了问题 首先我是直接使用语句 xff1a sudo gem install cocoapods 进行更新升级的 xff0c 没想到又报错了 接着我在想是不
  • http请求方法(GET、POST、HEAD、OPTIONS、PUT、DELETE、TRACE、CONNECT)

    根据HTTP标准 xff0c HTTP请求可以使用多种请求方法 HTTP的1 0版本中只有三种请求方法 xff1a GET POST 和 HEAD方法 到了1 1版本时 xff0c 新增加了五种请求方法 xff1a OPTIONS PUT

随机推荐

  • MongoDB可视化工具 Studio 3T

    告别终端使用可视化工具Studio 3T对MongoDB进行数据库的操作 简单的使用步骤介绍 1 启动MongoDB服务器 xff08 方法见MongoDB介绍与安装中的介绍 xff09 2 连接MongoDB服务器 3 操作数据库
  • 微信小程序开发——form表单

    WeChat小程序交流 xff08 QQ群 xff1a 769977169 xff09 效果图 代码示例 1 xxx wxml lt form bindsubmit 61 39 submitClick 39 bindreset 61 39
  • 苹果电脑(Mac mini或Macbook或iMac)恢复出厂设置

    苹果电脑 xff08 Mac mini或Macbook或iMac xff09 恢复出厂设置 xff0c 首先要做好如下的准备 xff1a 第一 xff1a 数据的备份 xff1b 第二 xff1a 保证正常的wifi连接 xff1b 第三
  • VSLAM基础(一)————常见特征点提取算法及匹配优化

    过年期间闲来无事 xff0c 就想来把这半年学习的一些视觉知识 xff08 视觉slam相关 xff09 做个梳理 xff0c 就以这篇图像特征点提取与匹配作为开头吧 一 关键点与描述子 关键点 xff1a 图像上某些特殊的 具有代表的点
  • 【2017CS231n】第十五讲:神经网络模型压缩和加速(硬件、算法层面)

    一 算法 1 剪枝 不是所有的神经网络连接都有用 减少连接 xff0c 但不降低准确性 尝试性 xff1a 剪枝 xff0c 训练不断重复 xff0c 找到对准确性影响最高的那一部分连接 2 参数共享 1 98 2 09 1 92 1 87
  • 程序员面试等通知一般多久?

    最近面试的人比较多 xff0c 毕竟是金三银四嘛 xff0c 竞争也挺大的 xff0c 很多人在面试之后 xff0c 久久没有收到入职通知 xff0c 等待是一件非常痛苦的事情 那么程序员面试等通知一般多久 xff1f 多久没有发通知就等于
  • 程序员简历项目经验怎么写?

    我是一个典型的互联网公司程序员 xff0c 也见过无数的程序员简历 xff0c 包括很多优秀的程序员简历 xff0c 看了可以让人眼前一亮 xff0c 优美简洁的简历模板 xff0c 项目经验工作重点突出 也见过更多的写得不好的简历 程序员
  • OpenRAVE

    机器人的高级功能 机械手臂控制 软件方面 在ros里 有moveit 研究的过程中 扩展到了openrave专业包 Welcome to OpenRAVE Latest Official Release 0 8 2 OpenRAVE pro
  • C++——STL初识

    一 为什么需要STL xff1f 目的 xff1a 为了建立一套重复利用的东西 使用STL可以避免从事大量重复的工作 为建立数据结构的一套标准 xff0c 诞生了STL 二 基本概念 STL是标准模板库 STL从广义上分为 xff1a 容器
  • Showing progress bar in a status bar pane

    This article was contributed by Brad Mann This code creates a progress bar anywhere in the status window and the control
  • 大小端字节序转换

    特点 各主机的字节序可能不同 xff0c 网络协议指定的通讯字节序为大端 只有在多字节数据处理时才需要考虑字节序 运行在同一台计算机的进程互相通信时 xff0c 不需要考虑字节序 二 字节序转换函数 头文件 xff1a include lt
  • 51单片机控制0.96寸OLED(IIC接口)

    1 OLED初步认识 OLED Organic Light Emitting Diode xff0c 即有机发光二极管 OLED由于同时具备自发光 xff0c 不需背光源 xff0c 对比度高 xff0c 厚度薄 xff0c 视角广 xff
  • 51单片机控制LCD1602模块

    51单片机控制LCD1602模块 视频播放 xff1a LCD1602视频 xff08 1 xff09 LCD1602概述 先来看看LCD1602什么意思 xff1f Liquid Crystal Display LCD 表示液晶显示 xf
  • LCD1602模块如何显示自定义字符

    相信大家现在知道了如何通过查字库表的方法来显示表中的任意一个字符 假如现在我想显示某个温度值 xff0c 需要标志出温度符号 C xff0c 现在你去字库表里面查找 xff0c 发现根本找不到这个符号 xff0c 那怎么办 xff1f 下面
  • 51单片机控制温度传感器DS18B20

    xff08 1 xff09 DS18B20初步认识 DS18B20是美国DALLAS半导体公司推出的一种数字化单总线器件 xff0c 属于新一代适配微处理器的改进型智能温度传感器 我们先来看看DS18B20在芯片手册上的标题 DS18B20
  • ESP8266模块手机端和电脑端网络调试助手

    ESP8266模块手机端和电脑端网络调试助手 使用方法比较简单 xff0c 如下界面所示 xff1a 电脑端 xff1a 确定 协议类型 xff0c 34 IP地址 34 和 34 端口 34 xff0c 然后点击连接即可 xff0c 如下
  • Micro Python 入门教程-pyboard V1.1控制LCD1602液晶显示模块

    11 LCD1602液晶显示模块 11 1 初识LCD1602液晶模块 LCD1602什么意思 xff0c LCD表示Liquid Crystal Display xff0c 1602表示一行可以显示16个字符 xff0c 一共有两行 实物
  • 常见无人机自组网路由协议

    常见无人机自组网路由协议 无人机自组网路由协议静态路由协议先验式路由协议反应式路由协议 无人机自组网路由协议 为了适应无人机组网节点高速移动带来的网络拓扑结构快速变化 xff0c 无人机自组网使用的路由协议主要有以下几种 静态路由协议 这种
  • 尚硅谷大数据项目之Flink实时数仓-踩坑记录和笔记记录

    这里写自定义目录标题 1 关于Slf4j注解配置文件logback xml不生效问题2 判断新老用户的时候 xff0c 什么时候会出问题 xff1a 3 为什么维度数据选择存储在Hbase中 xff0c 而不是Redis xff0c Mys
  • 【学习笔记】尚硅谷大数据项目之Flink实时数仓---数据可视化接口实现

    这里写自定义目录标题 第 1 章 数据可视化接口1 1 设计思路1 2 需求梳理1 2 1 最终显示效果图1 2 2 分析可视化大屏1 2 3 接口执行过程 第 2 章 Sugar 数据大屏2 1 产品介绍2 2 使用入口2 3 创建数据大