首页 > 编程语言 >领导友好型数据展示:Java后端到可视化实战汇报

领导友好型数据展示:Java后端到可视化实战汇报

时间:2024-09-18 18:51:27浏览次数:3  
标签:comment Java 后端 default charset utf8mb4 可视化 varchar null

舒一笑的网站:www.shuyixiao.cloud 里面:面试八股文、BAT面试真题、工作内推、工作经验分享、技术专栏等等什么都有,欢迎收藏和转发。

优化数据呈现:打造领导友好的数据库汇报方案

在本次分享中,我将探讨一个完整的数据处理与可视化流程,旨在将复杂的系统日志信息转化为直观、易懂的图形展示,以便非技术背景的领导能够轻松理解数据背后的故事。整个过程包括使用DataGrip高效查询日志数据、Java进行数据二次加工以及利用jfreechart库实现数据可视化。此外,我们还将简要介绍如何利用easyexcel和lombok等Java库来辅助数据处理和代码简化,共同构建一个高效、友好的数据展示解决方案。

本次日志涉及库表信息展示

操作日志表结构展示

-- auto-generated definition
create table log_operate_log
(
    id               bigint auto_increment comment '日志主键'
        primary key,
    trace_id         varchar(64) charset utf8mb4        null,
    user_id          bigint                             null comment '用户编号',
    user_type        tinyint  default 0                 not null comment '用户类型',
    module           varchar(50) charset utf8mb4        null,
    name             varchar(50) charset utf8mb4        null,
    type             bigint   default 0                 not null comment '操作分类',
    content          varchar(2000) charset utf8mb4      null,
    exts             varchar(512) charset utf8mb4       null,
    request_method   varchar(16) charset utf8mb4        null,
    request_url      varchar(255) charset utf8mb4       null,
    user_ip          varchar(50) charset utf8mb4        null,
    user_agent       varchar(200) charset utf8mb4       null,
    java_method      varchar(512) charset utf8mb4       null,
    java_method_args varchar(7936) charset utf8mb4      null,
    start_time       datetime                           not null comment '操作时间',
    duration         int                                not null comment '执行时长',
    result_code      int      default 0                 not null comment '结果码',
    result_msg       varchar(512) charset utf8mb4       null,
    result_data      varchar(4000) charset utf8mb4      null,
    creator          varchar(64) charset utf8mb4        null,
    creator_dept     varchar(64) charset utf8mb4        null,
    create_time      datetime default CURRENT_TIMESTAMP not null comment '创建时间',
    updater          varchar(64) charset utf8mb4        null,
    update_time      datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
    deleted          bit      default b'0'              not null comment '是否删除',
    tenant_id        bigint   default 0                 not null comment '租户编号'
)
    comment '操作日志记录' collate = utf8mb4_unicode_ci;

菜单权限表结构展示

-- auto-generated definition
create table sys_menu
(
    id                   bigint auto_increment comment '菜单ID'
        primary key,
    parent_id            bigint                                             null comment '父id',
    name                 varchar(255) charset utf8                          null comment '菜单标题',
    url                  varchar(255) charset utf8                          null comment '路径',
    component            varchar(255) charset utf8                          null comment '组件',
    menu_role_type       tinyint(1)                                         null comment '菜单角色类别(1:管理角色,2:业务角色)',
    iz_route             tinyint(1)               default 1                 null comment '是否路由菜单: 0:不是  1:是(默认值1)',
    component_name       varchar(255) charset utf8                          null comment '组件名字',
    redirect             varchar(255) charset utf8                          null comment '一级菜单跳转地址',
    menu_type            int                                                null comment '菜单类型(0:一级菜单; 1:子菜单:2:按钮权限)',
    permission           varchar(255) charset utf8                          null comment '菜单权限编码',
    permission_type      varchar(10) charset utf8 default '0'               null comment '权限策略1显示2禁用',
    sort                 double(8, 2)                                       not null comment '菜单排序',
    always_show          tinyint(1)                                         null comment '聚合子路由: 1是0否',
    icon                 varchar(255) charset utf8                          null comment '菜单图标',
    iz_leaf              tinyint(1)                                         null comment '是否叶子节点:    1是0否',
    keep_alive           tinyint(1)                                         null comment '是否缓存该页面:    1:是   0:不是',
    hidden               int(2)                   default 0                 null comment '是否隐藏路由: 0否,1是',
    hide_tab             int(2)                   default 0                 null comment '是否隐藏tab: 0否,1是',
    description          varchar(255) charset utf8                          null comment '描述',
    rule_flag            int(3)                   default 0                 null comment '是否添加数据权限1是0否',
    status               int(2)                                             null comment '按钮权限状态(1无效0有效)',
    internal_or_external tinyint(1)                                         null comment '外链菜单打开方式 0/内部打开 1/外部打开',
    creator              varchar(64) charset utf8mb4                        null,
    creator_dept         varchar(64) charset utf8mb4                        null,
    create_time          datetime                 default CURRENT_TIMESTAMP not null comment '创建时间',
    updater              varchar(64) charset utf8mb4                        null,
    update_time          datetime                 default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
    deleted              bit                      default b'0'              not null comment '是否删除'
)
    comment '菜单权限表' collate = utf8mb4_unicode_ci;

用户表结构展示

-- auto-generated definition
create table sys_users
(
    id            bigint auto_increment comment '用户ID'
        primary key,
    usercode      varchar(64)                           null,
    username      varchar(30)                           null,
    password      varchar(100)                          null,
    nickname      varchar(30)                           null,
    remark        varchar(2000)                         null,
    dept_id       bigint                                null comment '部门ID',
    post_ids      varchar(255)                          null,
    user_type     tinyint     default 1                 null comment '用户类型 1业务  2管理',
    email         varchar(50)                           null,
    mobile        varchar(11)                           null,
    sex           tinyint     default 0                 null comment '用户性别',
    avatar        varchar(2000)                         null,
    status        tinyint     default 0                 not null comment '帐号状态(0正常 1停用)',
    login_ip      varchar(50)                           null,
    login_date    datetime    default CURRENT_TIMESTAMP null comment '最后登录时间',
    password_date datetime                              null comment '最后修改密码时间',
    lock_date     datetime                              null comment '最后锁定时间',
    valid_date    datetime                              null comment '账号有效时间',
    creator       varchar(64)                           null,
    creator_dept  varchar(64) default ''                null comment '创建者部门',
    create_time   datetime    default CURRENT_TIMESTAMP null comment '创建时间',
    updater       varchar(64)                           null,
    update_time   datetime    default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间',
    deleted       bit         default b'0'              null comment '是否删除',
    tenant_id     bigint      default 0                 null comment '租户编号',
    constraint index_id
        unique (id)
);

本次展示需要实现的效果

如何需要根据系统的日志信息得出不同人员访问不同菜单的频率、以及对应的次数情况。当然这些信息能使用到sql直接查询得出。但是本地介绍如何使用Java代码的方式进行对得到的数据进行二次加工,并且使用jfreechart三方库进行对可视化图表的渲染与展示,下面进行一下基础查询的SQL展示。

统计每个菜单访问次数情况SQL示例

SELECT
    m.name AS menu_name,                -- 菜单名称
    COUNT(l.start_time) AS access_count -- 统计每个菜单的访问次数
FROM
    log_operate_log l
JOIN
    sys_menu m ON l.request_url LIKE CONCAT(m.url, '%') -- 关联菜单表
JOIN
    sys_users u ON l.user_id = u.id     -- 关联用户表
GROUP BY
    m.name                              -- 按菜单名称分组
ORDER BY
    access_count DESC;                  -- 按访问次数降序排序

这里给大家介绍一个技巧就是可以使用DataGrip中的导出为excel然后使用Java代码方式,结合EasyExcel进行对数据的处理

领导友好型数据展示:Java后端到可视化实战汇报_ci

只需要在这里进行进行选择位置之后,导出相对应的excel数据。

领导友好型数据展示:Java后端到可视化实战汇报_Java_02

如何使用Java代码的方式进行读取数据&&使用jfreechart进行可视化渲染。

这里需要注意一下就是需要在POM文件中配置jfreechart等三方的依赖然后使用下面的代码逻辑就可以实现对图片的渲染

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>4.0.3</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>org.jfree</groupId>
            <artifactId>jfreechart</artifactId>
            <version>1.5.5</version>
        </dependency>
    </dependencies>

折线图图片展示

/**
 * Copyright © 2024年 integration-projects-maven. All rights reserved.
 * ClassName QuickExcelReading.java
 * author 舒一笑 [email protected]
 * version 1.0.0
 * Description 快速Excel读取次数与频率
 * createTime 2024年09月18日 11:11:00
 */
@Slf4j
public class QuickExcelReading {

    public static void main(String[] args) {
        new QuickExcelReading().simpleRead();
    }

    public void simpleRead() {
        String fileName = "excel-quick-java/src/main/resources/菜单访问总数汇总.xlsx";

        // 使用PageReadListener读取数据,修改批处理数量为200
        EasyExcel.read(fileName, DemoData.class, new PageReadListener<DemoData>(dataList -> {
                    // 使用Map<String, Integer> 来统计每个menu_name的访问次数
                    Map<String, Integer> menuAccessCountMap = new HashMap<>();
                    int totalAccessCount = 0;

                    // 遍历每条数据
                    for (DemoData demoData : dataList) {
                        log.info("读取到一条数据: {}", demoData);

                        // 累计各menu_name的访问次数
                        menuAccessCountMap.merge(demoData.getMenuName(), demoData.getAccessCount(), Integer::sum);
                        totalAccessCount += demoData.getAccessCount();
                    }

                    // 对map按照访问次数进行倒序排序,并只取前10项
                    Map<String, Integer> sortedMenuAccessCountMap = menuAccessCountMap.entrySet()
                            .stream()
                            .sorted((e1, e2) -> e2.getValue().compareTo(e1.getValue()))  // 按访问次数降序排序
                            .limit(10)  // 只取前10个
                            .collect(java.util.stream.Collectors.toMap(
                                    Map.Entry::getKey,
                                    Map.Entry::getValue,
                                    (oldValue, newValue) -> oldValue,
                                    java.util.LinkedHashMap::new
                            ));

                    // 开始构建Markdown表格
                    StringBuilder markdownTable = new StringBuilder();
                    markdownTable.append("| 功能名称 | 访问次数 | 占比 |\n");
                    markdownTable.append("| --- | --- | --- |\n");

                    // 计算每个menu_name的访问次数占比并生成Markdown表格行
                    int finalTotalAccessCount = totalAccessCount;
                    sortedMenuAccessCountMap.forEach((menuName, count) -> {
                        double percentage = (count * 100.0) / finalTotalAccessCount;
                        markdownTable.append(String.format("| %s | %d次 | %.2f%% |\n", menuName, count, percentage));
                    });

                    // 输出Markdown表格
                    System.out.println(markdownTable.toString());

                    // 渲染饼图
                    renderPieChart(sortedMenuAccessCountMap);

                }, 200)) // 批处理大小设为200
                .sheet().doRead();
    }

    // 渲染饼图的方法
    public void renderPieChart(Map<String, Integer> sortedMenuAccessCountMap) {
        DefaultPieDataset dataset = new DefaultPieDataset();

        // 将sortedMenuAccessCountMap数据放入dataset中
        sortedMenuAccessCountMap.forEach(dataset::setValue);

        // 创建饼图
        JFreeChart pieChart = ChartFactory.createPieChart(
                "功能访问次数分布(前10项)",  // 图表标题
                dataset,             // 数据集
                true,                // 是否显示图例
                true,                // 是否使用工具提示
                false                // 是否生成URLs
        );

        // 自定义饼图样式
        PiePlot plot = (PiePlot) pieChart.getPlot();
        plot.setLabelFont(new java.awt.Font("SansSerif", java.awt.Font.PLAIN, 12));  // 设置字体大小
        plot.setNoDataMessage("没有数据");
        plot.setCircular(true);  // 设置为圆形饼图
        plot.setLabelGap(0.02);  // 设置标签与饼图的距离

        // 设置标签在饼图外部显示
        plot.setSimpleLabels(false);  // 使用连接线将标签显示在饼图外部

        // 保存饼图为图片
        int width = 960;    // 增加图片宽度
        int height = 720;   // 增加图片高度
        File pieChartFile = new File("功能访问次数分布饼图.png");
        try {
            ChartUtils.saveChartAsPNG(pieChartFile, pieChart, width, height);
            System.out.println("饼图已生成: " + pieChartFile.getAbsolutePath());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

折线图图片性质展示

运行代码之后就可以在资源路径下得到图片的信息

领导友好型数据展示:Java后端到可视化实战汇报_数据_03

渲染的图片图片展示(这里有一个坑需要注意就是这个三方框架对中文好像不是很友好,然后就是出现这下面图片的效果)

领导友好型数据展示:Java后端到可视化实战汇报_Java_04

柱状图效果展示

代码展示

/**
 * Copyright © 2024年 integration-projects-maven. All rights reserved.
 * ClassName QuickExcelReading2.java
 * author 舒一笑 [email protected]
 * version 1.0.0
 * Description 快速Excel读取次数与频率人员访问情况
 * createTime 2024年09月18日 12:59:00
 */
@Slf4j
public class QuickExcelReading2 {

    public static void main(String[] args) {
        new QuickExcelReading2().simpleRead();
    }

    public void simpleRead() {
        String fileName = "E:\\ALearn\\code-improves-excel-efficiency\\excel-quick-java\\src\\main\\resources\\用户访问次数.xlsx";

        // 使用PageReadListener读取数据,修改批处理数量为200
        EasyExcel.read(fileName, DemoData.class, new PageReadListener<DemoData>(dataList -> {
                    // 使用Map<String, Integer> 来统计每个menu_name的访问次数
                    Map<String, Integer> menuAccessCountMap = new HashMap<>();
                    int totalAccessCount = 0;

                    // 遍历每条数据
                    for (DemoData demoData : dataList) {
                        log.info("读取到一条数据: {}", demoData);
                        if (menuAccessCountMap.get(demoData.getNickName()) == null){
                            menuAccessCountMap.put(demoData.getNickName(), demoData.getAccessCount());
                            totalAccessCount += demoData.getTotalAccessCount();
                        }
                        // 累计各menu_name的访问次数
//                        menuAccessCountMap.merge(demoData.getNickName(), demoData.getAccessCount(), Integer::sum);
//                        totalAccessCount += demoData.getTotalAccessCount();
                    }

                    // 对map按照访问次数进行倒序排序,并只取前10项
                    Map<String, Integer> sortedMenuAccessCountMap = menuAccessCountMap.entrySet()
                            .stream()
                            .sorted((e1, e2) -> e2.getValue().compareTo(e1.getValue()))  // 按访问次数降序排序
                            .limit(10)  // 只取前10个
                            .collect(java.util.stream.Collectors.toMap(
                                    Map.Entry::getKey,
                                    Map.Entry::getValue,
                                    (oldValue, newValue) -> oldValue,
                                    java.util.LinkedHashMap::new
                            ));

                    // 开始构建Markdown表格
                    StringBuilder markdownTable = new StringBuilder();
                    markdownTable.append("| 功能名称 | 访问次数 | 占比 |\n");
                    markdownTable.append("| --- | --- | --- |\n");

                    // 计算每个menu_name的访问次数占比并生成Markdown表格行
                    int finalTotalAccessCount = totalAccessCount;
                    sortedMenuAccessCountMap.forEach((menuName, count) -> {
                        double percentage = (count * 100.0) / finalTotalAccessCount;
                        markdownTable.append(String.format("| %s | %d次 | %.2f%% |\n", menuName, count, percentage));
                    });

                    // 输出Markdown表格
                    System.out.println(markdownTable.toString());

                    // 渲染饼图
                    renderPieChart(sortedMenuAccessCountMap);
                    // 渲染柱状图
                    renderBarChart(sortedMenuAccessCountMap);

                }, 65588)) // 批处理大小设为200
                .sheet().doRead();
    }

    // 渲染饼图的方法
    public void renderPieChart(Map<String, Integer> sortedMenuAccessCountMap) {
        DefaultPieDataset dataset = new DefaultPieDataset();

        // 将sortedMenuAccessCountMap数据放入dataset中
        sortedMenuAccessCountMap.forEach(dataset::setValue);

        // 创建饼图
        JFreeChart pieChart = ChartFactory.createPieChart(
                "功能访问次数分布(前10项)",  // 图表标题
                dataset,             // 数据集
                true,                // 是否显示图例
                true,                // 是否使用工具提示
                false                // 是否生成URLs
        );

        // 自定义饼图样式
        PiePlot plot = (PiePlot) pieChart.getPlot();
        plot.setLabelFont(new java.awt.Font("SansSerif", java.awt.Font.PLAIN, 12));  // 设置字体大小
        plot.setNoDataMessage("没有数据");
        plot.setCircular(true);  // 设置为圆形饼图
        plot.setLabelGap(0.02);  // 设置标签与饼图的距离

        // 设置标签在饼图外部显示
        plot.setSimpleLabels(false);  // 使用连接线将标签显示在饼图外部

        // 保存饼图为图片
        int width = 960;    // 增加图片宽度
        int height = 720;   // 增加图片高度
        File pieChartFile = new File("人员访问次数分布饼图.png");
        try {
            ChartUtils.saveChartAsPNG(pieChartFile, pieChart, width, height);
            System.out.println("饼图已生成: " + pieChartFile.getAbsolutePath());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 渲染柱状图的方法
    public void renderBarChart(Map<String, Integer> sortedMenuAccessCountMap) {
        DefaultCategoryDataset dataset = new DefaultCategoryDataset();

        // 将sortedMenuAccessCountMap数据放入dataset中
        sortedMenuAccessCountMap.forEach((menuName, count) -> {
            dataset.addValue(count, "访问次数", menuName);
        });

        // 创建柱状图
        JFreeChart barChart = ChartFactory.createBarChart(
                "功能访问次数分布(前10项)",  // 图表标题
                "功能名称",                // X轴标签
                "访问次数",                // Y轴标签
                dataset,                   // 数据集
                PlotOrientation.VERTICAL,  // 图表方向:垂直
                true,                      // 是否显示图例
                true,                      // 是否使用工具提示
                false                      // 是否生成URLs
        );

        // 自定义柱状图样式
        CategoryPlot plot = barChart.getCategoryPlot();
        plot.setRangeGridlinePaint(java.awt.Color.BLACK);  // 设置网格线颜色
        BarRenderer renderer = (BarRenderer) plot.getRenderer();
        renderer.setDrawBarOutline(false);  // 不绘制边框

        // 设置柱状图的柱子颜色
        renderer.setSeriesPaint(0, new java.awt.Color(79, 129, 189));  // 自定义颜色

        // 保存柱状图为图片
        int width = 960;    // 图片宽度
        int height = 720;   // 图片高度
        File barChartFile = new File("人员访问次数分布柱状图.png");
        try {
            ChartUtils.saveChartAsPNG(barChartFile, barChart, width, height);
            System.out.println("柱状图已生成: " + barChartFile.getAbsolutePath());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

领导友好型数据展示:Java后端到可视化实战汇报_ci_05

好了,本次的分享就先到这里,下次再给大家分享一下如何使用python结合三方库进行图片的渲染,这方面不得不说确实python要强很多~

标签:comment,Java,后端,default,charset,utf8mb4,可视化,varchar,null
From: https://blog.51cto.com/u_16656615/12047580

相关文章

  • JavaSE——Java基础语法(黑马个人听课笔记)
    1.关键字介绍关键字:被Java赋予了特定含义的英文单词关键字的字母全部小写 常用的代码编辑器,针对关键字由特殊的颜色标记,非常直观2.常量2.1常量概述常量:在程序的执行过程中,其值不会发生改变的量(数据)  2.2常量的分类:字符串常量:被双引号包裹的内容整数常量:所......
  • [Java基础]集合的删除操作
    在Java中,直接在遍历集合时删除元素会引发ConcurrentModificationException,因为集合的结构在迭代过程中发生了变化。为了避免这种问题,可以使用Iterator或ListIterator来进行安全删除。下面介绍几种常见的方式。1.使用Iterator进行删除使用Iterator是在遍历集合时删除......
  • 基于springboot的就业信息管理系统。Javaee项目,springboot项目。
    演示视频:基于springboot的就业信息管理系统。Javaee项目,springboot项目。项目介绍:采用M(model)V(view)C(controller)三层体系结构,通过Spring+SpringBoot+Mybatis+Maven来实现,前端采用了layui框架。MySQL数据库作为系统数据储存平台,采用JDBC技术进行数据库连接,实现了基......
  • 基于SSM的抗疫物资管理系统(数据库表结构文档)。Javaee项目。
    演示视频基于SSM的抗疫物资管理系统(数据库表结构文档)。Javaee项目。项目介绍:采用M(model)V(view)C(controller)三层体系结构,通过Spring+SpringMvc+Mybatis+Jsp+Bootstrap来实现。MySQL数据库作为系统数据储存平台,采用JDBC技术进行数据库连接,实现了基于B/S结构的Web系......
  • 基于SSM的美妆商城网站(有报告)。Javaee项目。
    演示视频:基于SSM的美妆商城网站(有报告)。Javaee项目。项目介绍:采用M(model)V(view)C(controller)三层体系结构,通过Spring+SpringMvc+Mybatis+Jsp+Vue+layui+Elementui来实现。MySQL数据库作为系统数据储存平台,实现了基于B/S结构的Web系统。系统设计思想一个成......
  • Java JNA、JNI、ProcessBuilder、Runtime.getRuntime.exec()详解
    Java提供了几种方式与非Java代码进行交互(比如调用本地库或执行外部程序),其中包括JNA、JNI、ProcessBuilder和Runtime.getRuntime().exec()。下面是对每种方式的详细解释。1.JNA(JavaNativeAccess)简介JNA是Java与本地代码进行交互的一种高层次API,它允许Java......
  • java.lang.UnsatisfiedLinkError: dlopen failed: library "libc++_shared.so" not fo
    一、概述在AndroidStudio中集成opencv,使用其native函数时报的一个错误 二、解决办法opencv提供的native文件夹中提供的是动态库但是在gradle中的配置中,配置的stl是静态的,将其改为shared就行了externalNativeBuild{cmake{cp......
  • 准备好了吗?JAVA从业AI开发的学习路线详解
    作为一个拥有扎实Java基础的人,想要涉足人工智能(AI)应用开发,你已经在编程能力方面打下了很好的基础。Java是一种通用的、强类型的语言,非常适合于开发高性能的应用程序,尤其是在后端服务和大规模分布式系统方面。AI领域是一个高度跨学科的领域,涵盖了机器学习、深度学习、数据科学、......
  • 【他山之石】优化 JavaScript 的乐趣与价值(下)
    前言继本文的上篇发表之后,没想到反响还挺好,看来大家在JS优化的问题上越来越注重“与国际接轨”了。一起来看本文的下篇,也是干货满满。文章目录6.AvoidlargeobjectsWhattheeffshouldIdoaboutthis?7.Useeval8.Usestrings,carefullyWhattheeffs......
  • 期末所需分数.java
    原始问题描述期末考试满分100分,平时成绩满分40分。总评成绩由期末考成绩的60%和平时成绩组成。已知平时成绩,求期末考试至少需得多少分,以确保总评成绩不低于60分。原始版本参考代码importjava.util.Scanner;publicclassFishTank{publicstaticvoidmain(String[]ar......