Spring Boot 数据可视化与图表集成

Spring Boot 数据可视化与图表集成

Spring Boot 数据可视化与图表集成

在这里插入图片描述
27.1 学习目标与重点提示

学习目标:掌握Spring Boot数据可视化与图表集成的核心概念与使用方法,包括数据可视化的定义与特点、图表工具的定义与特点、Spring Boot与图表工具的集成、Spring Boot的实际应用场景,学会在实际开发中处理数据可视化与图表集成问题。
重点:数据可视化的定义与特点图表工具的定义与特点Spring Boot与图表工具的集成Spring Boot的实际应用场景

27.2 数据可视化与图表工具概述

数据可视化与图表工具是Java开发中的重要组件。

27.2.1 数据可视化的定义

定义:数据可视化是指将数据通过图表、地图、仪表盘等形式直观地展示出来,帮助用户更好地理解和分析数据。
作用

  • 提高数据的可读性。
  • 帮助用户发现数据中的规律。
  • 支持快速决策。

常见的数据可视化工具

  • ECharts:ECharts是百度开源的一个数据可视化库。
  • Highcharts:Highcharts是一个基于JavaScript的数据可视化库。
  • D3.js:D3.js是一个基于JavaScript的数据可视化库。
  • Tableau:Tableau是一个商业数据可视化工具。

✅ 结论:数据可视化是指将数据通过图表、地图、仪表盘等形式直观地展示出来,作用是提高数据的可读性、帮助用户发现数据中的规律、支持快速决策。

27.2.2 图表工具的定义

定义:图表工具是一种用于创建和展示图表的软件工具,用于数据可视化。
作用

  • 实现图表的创建。
  • 实现图表的展示。
  • 提高数据的可视化效果。

常见的图表工具

  • ECharts:ECharts是百度开源的一个数据可视化库。
  • Highcharts:Highcharts是一个基于JavaScript的数据可视化库。
  • D3.js:D3.js是一个基于JavaScript的数据可视化库。
  • Tableau:Tableau是一个商业数据可视化工具。

✅ 结论:图表工具是一种用于创建和展示图表的软件工具,作用是实现图表的创建、展示、提高数据的可视化效果。

27.3 Spring Boot与图表工具的集成

Spring Boot与图表工具的集成是Java开发中的重要内容。

27.3.1 集成ECharts的步骤

定义:集成ECharts的步骤是指使用Spring Boot与ECharts集成的方法。
步骤

  1. 创建Spring Boot项目。
  2. 添加所需的依赖。
  3. 配置ECharts。
  4. 创建数据访问层。
  5. 创建业务层。
  6. 创建控制器类。
  7. 创建前端页面。
  8. 测试应用。

示例
pom.xml文件中的依赖:

<dependencies><!-- Web依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Thymeleaf依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><!-- 测试依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>

application.properties文件中的配置:

# 服务器端口 server.port=8080 # Thymeleaf配置 spring.thymeleaf.cache=false spring.thymeleaf.mode=HTML spring.thymeleaf.encoding=UTF-8 spring.thymeleaf.suffix=.html spring.thymeleaf.prefix=classpath:/templates/ 

实体类:

publicclassProduct{privateLong id;privateString productId;privateString productName;privatedouble price;privateint sales;publicProduct(){}publicProduct(Long id,String productId,String productName,double price,int sales){this.id = id;this.productId = productId;this.productName = productName;this.price = price;this.sales = sales;}// Getter和Setter方法publicLonggetId(){return id;}publicvoidsetId(Long id){this.id = id;}publicStringgetProductId(){return productId;}publicvoidsetProductId(String productId){this.productId = productId;}publicStringgetProductName(){return productName;}publicvoidsetProductName(String productName){this.productName = productName;}publicdoublegetPrice(){return price;}publicvoidsetPrice(double price){this.price = price;}publicintgetSales(){return sales;}publicvoidsetSales(int sales){this.sales = sales;}@OverridepublicStringtoString(){return"Product{"+"id="+ id +",+ productId +'\''+",+ productName +'\''+", price="+ price +", sales="+ sales +'}';}}

Repository接口:

importorg.springframework.stereotype.Repository;importjava.util.ArrayList;importjava.util.List;importjava.util.stream.Collectors;@RepositorypublicclassProductRepository{privateList<Product> products =newArrayList<>();publicProductRepository(){ products.add(newProduct(1L,"P001","手机",1000.0,100)); products.add(newProduct(2L,"P002","电脑",5000.0,50)); products.add(newProduct(3L,"P003","电视",3000.0,80)); products.add(newProduct(4L,"P004","手表",500.0,200)); products.add(newProduct(5L,"P005","耳机",300.0,150));}publicList<Product>getAllProducts(){return products;}publicProductgetProductById(Long id){return products.stream().filter(product -> product.getId().equals(id)).findFirst().orElse(null);}publicvoidaddProduct(Product product){ product.setId((long)(products.size()+1)); products.add(product);}publicvoidupdateProduct(Product product){Product existingProduct =getProductById(product.getId());if(existingProduct !=null){ existingProduct.setProductId(product.getProductId()); existingProduct.setProductName(product.getProductName()); existingProduct.setPrice(product.getPrice()); existingProduct.setSales(product.getSales());}}publicvoiddeleteProduct(Long id){ products.removeIf(product -> product.getId().equals(id));}}

Service类:

importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;importjava.util.List;@ServicepublicclassProductService{@AutowiredprivateProductRepository productRepository;publicList<Product>getAllProducts(){return productRepository.getAllProducts();}publicProductgetProductById(Long id){return productRepository.getProductById(id);}publicvoidaddProduct(Product product){ productRepository.addProduct(product);}publicvoidupdateProduct(Product product){ productRepository.updateProduct(product);}publicvoiddeleteProduct(Long id){ productRepository.deleteProduct(id);}}

控制器类:

importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Controller;importorg.springframework.ui.Model;importorg.springframework.web.bind.annotation.*;importjava.util.List;@Controller@RequestMapping("/api/products")publicclassProductController{@AutowiredprivateProductService productService;@GetMapping("/")publicStringgetAllProducts(Model model){List<Product> products = productService.getAllProducts(); model.addAttribute("products", products);return"product-list";}@GetMapping("/{id}")publicStringgetProductById(@PathVariableLong id,Model model){Product product = productService.getProductById(id); model.addAttribute("product", product);return"product-detail";}@GetMapping("/add")publicStringaddProductForm(Model model){ model.addAttribute("product",newProduct());return"product-form";}@PostMapping("/add")publicStringaddProduct(@ModelAttributeProduct product){ productService.addProduct(product);return"redirect:/api/products/";}@GetMapping("/edit/{id}")publicStringeditProductForm(@PathVariableLong id,Model model){Product product = productService.getProductById(id); model.addAttribute("product", product);return"product-form";}@PostMapping("/edit/{id}")publicStringeditProduct(@PathVariableLong id,@ModelAttributeProduct product){ product.setId(id); productService.updateProduct(product);return"redirect:/api/products/";}@GetMapping("/delete/{id}")publicStringdeleteProduct(@PathVariableLong id){ productService.deleteProduct(id);return"redirect:/api/products/";}}

前端页面(product-list.html):

<!DOCTYPEhtml><htmllang="zh-CN"xmlns:th="http://www.thymeleaf.org"><head><metacharset="UTF-8"><title>产品列表</title><scriptsrc="https://cdn.jsdelivr.net/npm/[email protected]/dist/echarts.min.js"></script></head><body><h1>产品列表</h1><ahref="/api/products/add">添加产品</a><tableborder="1"><thead><tr><th>ID</th><th>产品ID</th><th>产品名称</th><th>价格</th><th>销量</th><th>操作</th></tr></thead><tbody><trth:each="product : ${products}"><tdth:text="${product.id}"></td><tdth:text="${product.productId}"></td><tdth:text="${product.productName}"></td><tdth:text="${product.price}"></td><tdth:text="${product.sales}"></td><td><ath:href="@{/api/products/edit/{id}(id=${product.id})}">编辑</a><ath:href="@{/api/products/delete/{id}(id=${product.id})}">删除</a></td></tr></tbody></table><h2>产品销量图表</h2><divid="salesChart"style="width: 800px;height: 400px;"></div><script>// 初始化图表var chartDom = document.getElementById('salesChart');var myChart = echarts.init(chartDom);var option;// 准备数据var productNames =[];var productSales =[];<th:block th:each="product : ${products}"> productNames.push('[('+ product.productName +')]'); productSales.push('[('+ product.sales +')]');</th:block>// 配置图表 option ={title:{text:'产品销量图表',left:'center'},tooltip:{trigger:'item'},legend:{orient:'vertical',right:10,top:'center'},series:[{name:'销量',type:'pie',radius:['40%','70%'],avoidLabelOverlap:false,itemStyle:{borderRadius:10,borderColor:'#fff',borderWidth:2},label:{show:false,position:'center'},emphasis:{label:{show:true,fontSize:20,fontWeight:'bold'}},labelLine:{show:false},data:[<th:block th:each="product : ${products}">{value:[(' + product.sales + ')],name:'[('+ product.productName +')']},</th:block>]}]};// 渲染图表 option && myChart.setOption(option);</script></body></html>

应用启动类:

importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublicclassEChartsApplication{publicstaticvoidmain(String[] args){SpringApplication.run(EChartsApplication.class, args);}}

测试类:

importorg.junit.jupiter.api.Test;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.test.context.SpringBootTest;importorg.springframework.boot.test.web.client.TestRestTemplate;importorg.springframework.boot.web.server.LocalServerPort;importstaticorg.assertj.core.api.Assertions.assertThat;@SpringBootTest(webEnvironment =SpringBootTest.WebEnvironment.RANDOM_PORT)classEChartsApplicationTests{@LocalServerPortprivateint port;@AutowiredprivateTestRestTemplate restTemplate;@TestvoidcontextLoads(){}@TestvoidtestGetAllProducts(){String response = restTemplate.getForObject("http://localhost:"+ port +"/api/products/",String.class);assertThat(response).contains("产品列表");}}

✅ 结论:集成ECharts的步骤包括创建Spring Boot项目、添加所需的依赖、配置ECharts、创建数据访问层、创建业务层、创建控制器类、创建前端页面、测试应用。

27.4 Spring Boot的实际应用场景

在实际开发中,Spring Boot数据可视化与图表集成的应用场景非常广泛,如:

  • 实现产品信息的图表展示。
  • 实现用户信息的图表展示。
  • 实现订单信息的图表展示。
  • 实现销售数据的图表展示。

示例

importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Controller;importorg.springframework.ui.Model;importorg.springframework.web.bind.annotation.*;importjava.util.List;@Controller@RequestMapping("/api/products")classProductController{@AutowiredprivateProductService productService;@GetMapping("/")publicStringgetAllProducts(Model model){List<Product> products = productService.getAllProducts(); model.addAttribute("products", products);return"product-list";}@GetMapping("/{id}")publicStringgetProductById(@PathVariableLong id,Model model){Product product = productService.getProductById(id); model.addAttribute("product", product);return"product-detail";}@GetMapping("/add")publicStringaddProductForm(Model model){ model.addAttribute("product",newProduct());return"product-form";}@PostMapping("/add")publicStringaddProduct(@ModelAttributeProduct product){ productService.addProduct(product);return"redirect:/api/products/";}@GetMapping("/edit/{id}")publicStringeditProductForm(@PathVariableLong id,Model model){Product product = productService.getProductById(id); model.addAttribute("product", product);return"product-form";}@PostMapping("/edit/{id}")publicStringeditProduct(@PathVariableLong id,@ModelAttributeProduct product){ product.setId(id); productService.updateProduct(product);return"redirect:/api/products/";}@GetMapping("/delete/{id}")publicStringdeleteProduct(@PathVariableLong id){ productService.deleteProduct(id);return"redirect:/api/products/";}}@ServiceclassProductService{@AutowiredprivateProductRepository productRepository;publicList<Product>getAllProducts(){return productRepository.getAllProducts();}publicProductgetProductById(Long id){return productRepository.getProductById(id);}publicvoidaddProduct(Product product){ productRepository.addProduct(product);}publicvoidupdateProduct(Product product){ productRepository.updateProduct(product);}publicvoiddeleteProduct(Long id){ productRepository.deleteProduct(id);}}@RepositoryclassProductRepository{privateList<Product> products =newArrayList<>();publicProductRepository(){ products.add(newProduct(1L,"P001","手机",1000.0,100)); products.add(newProduct(2L,"P002","电脑",5000.0,50)); products.add(newProduct(3L,"P003","电视",3000.0,80)); products.add(newProduct(4L,"P004","手表",500.0,200)); products.add(newProduct(5L,"P005","耳机",300.0,150));}publicList<Product>getAllProducts(){return products;}publicProductgetProductById(Long id){return products.stream().filter(product -> product.getId().equals(id)).findFirst().orElse(null);}publicvoidaddProduct(Product product){ product.setId((long)(products.size()+1)); products.add(product);}publicvoidupdateProduct(Product product){Product existingProduct =getProductById(product.getId());if(existingProduct !=null){ existingProduct.setProductId(product.getProductId()); existingProduct.setProductName(product.getProductName()); existingProduct.setPrice(product.getPrice()); existingProduct.setSales(product.getSales());}}publicvoiddeleteProduct(Long id){ products.removeIf(product -> product.getId().equals(id));}}@SpringBootApplicationpublicclassEChartsApplication{publicstaticvoidmain(String[] args){SpringApplication.run(EChartsApplication.class, args);}}// 测试类@SpringBootTest(webEnvironment =SpringBootTest.WebEnvironment.RANDOM_PORT)classEChartsApplicationTests{@LocalServerPortprivateint port;@AutowiredprivateTestRestTemplate restTemplate;@TestvoidcontextLoads(){}@TestvoidtestGetAllProducts(){String response = restTemplate.getForObject("http://localhost:"+ port +"/api/products/",String.class);assertThat(response).contains("产品列表");}}

输出结果

  • 访问http://localhost:8080/api/products/:返回产品列表页面,包含产品销量图表。
  • 点击“添加产品”:跳转到添加产品页面。
  • 点击“编辑”:跳转到编辑产品页面。
  • 点击“删除”:删除产品。

✅ 结论:在实际开发中,Spring Boot数据可视化与图表集成的应用场景非常广泛,需要根据实际问题选择合适的图表工具。

总结

本章我们学习了Spring Boot数据可视化与图表集成,包括数据可视化的定义与特点、图表工具的定义与特点、Spring Boot与图表工具的集成、Spring Boot的实际应用场景,学会了在实际开发中处理数据可视化与图表集成问题。其中,数据可视化的定义与特点、图表工具的定义与特点、Spring Boot与图表工具的集成、Spring Boot的实际应用场景是本章的重点内容。从下一章开始,我们将学习Spring Boot的其他组件、微服务等内容。

Read more

Flutter 三方库 easy_money_formatter 的鸿蒙化适配指南 - 实现具备多种货币符号与千分位自动处理的金额格式化、支持端侧金融应用的动态金额渲染实战

Flutter 三方库 easy_money_formatter 的鸿蒙化适配指南 - 实现具备多种货币符号与千分位自动处理的金额格式化、支持端侧金融应用的动态金额渲染实战

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 easy_money_formatter 的鸿蒙化适配指南 - 实现具备多种货币符号与千分位自动处理的金额格式化、支持端侧金融应用的动态金额渲染实战 前言 在进行 Flutter for OpenHarmony 的电子钱包、电商支付或个人理财应用开发时,如何优雅、规范地展示金额数值?简单的 toStringAsFixed 无法处理千分位分割以及不同国家/地区的货币符号排列逻辑。easy_money_formatter 是一款轻量级、功能专注的金额处理库。本文将介绍如何在鸿蒙端快速构建符合金融规范的金额展示层。 一、原直观解析 / 概念介绍 1.1 基础原理 该库建立在“格式化掩码(Formatting Mask)”逻辑之上。它接收一段原始的数值(Double 或 String),根据预设的配置(如符号位置、

By Ne0inhk
Linux命名管道(FIFO)通信:从原理到实操,一文搞懂跨进程通信

Linux命名管道(FIFO)通信:从原理到实操,一文搞懂跨进程通信

🔥个人主页:Cx330🌸 ❄️个人专栏:《C语言》《LeetCode刷题集》《数据结构-初阶》《C++知识分享》 《优选算法指南-必刷经典100题》《Linux操作系统》:从入门到入魔 《Git深度解析》:版本管理实战全解 🌟心向往之行必能至 🎥Cx330🌸的简介: 目录 前言: 一、先搞懂:命名管道(FIFO)是什么? 1. 命名管道的本质 2. 命名管道的核心特点 3. 命名管道与匿名管道的对比 二. 命名管道的创建方式 2.1 命令行创建(mkfifo 命令) 2.2 代码创建(mkfifo 函数) 2.3 命名管道的打开规则 三、实操实现:手搓命名管道通信 3.1 前置准备(

By Ne0inhk

Flutter 三方库 release_updater 的鸿蒙化适配指南 - 在鸿蒙系统上构建极致、自动化的应用安装包与资源静默热更新引擎

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 release_updater 的鸿蒙化适配指南 - 在鸿蒙系统上构建极致、自动化的应用安装包与资源静默热更新引擎 在鸿蒙(OpenHarmony)系统开发中,如何绕过漫长的 HAP 全量包上架审核,实现对应用特定资源、脚本或配置文件的高速增量更新?release_updater 为开发者提供了一套工业级的、基于本地目录的安装/发布文件自动化版本管理与替换方案。本文将深入实战其在鸿蒙资源热更场景中的应用。 前言 什么是 Release Updater?它是一个轻量级的文件更新框架,专门用于监控远端版本、下载差异包并安全地覆盖到本地指定路径。在 Flutter for OpenHarmony 的实际开发中,利用该库,我们可以实现鸿蒙应用“资产目录(Assets)”的毫秒级静默更新。不管是动态 UI 配置文件还是离线算法包,都能在用户无感知的情况下完成“生命周期进化”。 一、

By Ne0inhk
鸿蒙APP开发从入门到精通:运维监控、生态运营与专属变现

鸿蒙APP开发从入门到精通:运维监控、生态运营与专属变现

《鸿蒙APP开发从入门到精通》第12篇:运维监控、生态运营与专属变现 📊🚀💰 内容承接与核心价值 这是《鸿蒙APP开发从入门到精通》的第12篇——运维监控、生态运营与专属变现篇,承接第11篇的「性能优化与Next原生合规」,100%复用项目架构,完成鸿蒙电商购物车全栈项目的最终上线与华为应用市场上架变现。 学习目标: * 掌握鸿蒙APP运维监控的定义与架构; * 实现实时监控、日志分析、报警系统等运维监控功能; * 理解生态运营的原理与实现方式; * 开发用户运营、内容运营、社区运营等生态运营功能; * 掌握专属变现的原理与实现方式; * 开发华为应用市场上架、应用内付费、广告变现等专属变现功能。 学习重点: * 鸿蒙APP运维监控的开发流程; * 运维监控的分类与使用场景; * 实时监控、日志分析、报警系统的实现; * 生态运营的设计与实现; * 专属变现的设计与实现。 一、 运维监控基础 🎯 1.1 运维监控定义 运维监控是指对应用进行实时监控、日志分析、报警系统等,主要包括以下方面: * 实时监控:实时监控应用的运行状态;

By Ne0inhk