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

2025 最新版 Node.js 下载安装及环境配置教程

一、版本选择说明 根据 Node.js 官方发布计划,截至 2025 年 9 月,当前处于Active LTS(长期支持)状态的版本为Node.js v22.x(代号 "Jod"),该版本于 2024 年 4 月发布,将提供长期支持至 2027 年 4 月,是生产环境的最优选择。 ⚠️ 注意:Node.js 的奇数版本(如 v23)为短期开发版本,已在 2025 年 5 月停止支持,不建议用于生产环境;官网默认展示的v22.19.0(LTS)

By Ne0inhk
Node.js 安装指南(Mac 版本)

Node.js 安装指南(Mac 版本)

目录 第一章 准备工作与环境检查 1.1 确认系统要求在开始安装 Node.js 之前,首先需要确认您的 Mac 系统是否符合要求: 1.2 检查现有 Node.js 安装 1.3 备份重要数据 1.4 清理可能的旧版本 第二章:安装方法概述与选择 2.1 主要安装方法比较 2.2 推荐安装方案 第三章:方法一 - 使用官方安装包 3.1 下载官方安装包 3.2 安装过程详解 3.3 验证安装 安装过程中遇到问题: 🧐 为什么会出现这个错误? ✅ 如何解决? 方案一:使用

By Ne0inhk

xxxwww在电商爬虫中的实际应用案例

快速体验 1. 打开 InsCode(快马)平台 https://www.inscode.net 2. 点击'项目生成'按钮,等待项目生成完整后预览效果 输入框内输入如下内容: 构建一个基于xxxwww的电商爬虫系统,能够自动抓取指定电商平台的商品信息(名称、价格、评价等),并将数据清洗后存储到MySQL数据库。要求实现定时任务和反爬虫策略,输出可视化报表。 电商数据爬虫的需求背景 在电商运营和市场竞争分析中,及时获取竞品价格、用户评价等数据至关重要。传统人工收集效率低下,而爬虫技术可以自动化这一过程。最近我用xxxwww技术实现了一个电商爬虫系统,能够定时抓取多个平台商品数据并生成可视化报表,大幅提升了团队的数据获取效率。 系统核心功能设计 整个系统主要分为四个模块,每个模块都针对电商数据特点做了优化: 1. 爬虫调度模块:负责管理爬取任务队列,协调多个平台的爬取节奏 2. 数据抓取模块:使用xxxwww技术实现商品详情页的精准定位和数据提取 3. 数据处理模块:对原始数据进行清洗、去重和格式标准化 4.

By Ne0inhk
Flutter 组件 dep_gen 的鸿蒙化适配实战 - 驾驭极致依赖注入大坝、实现 OpenHarmony 分布式端高性能模块化管理、依赖拓扑指纹预检与工业级服务定位核方案

Flutter 组件 dep_gen 的鸿蒙化适配实战 - 驾驭极致依赖注入大坝、实现 OpenHarmony 分布式端高性能模块化管理、依赖拓扑指纹预检与工业级服务定位核方案

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 组件 dep_gen 的鸿蒙化适配实战 - 驾驭极致依赖注入大坝、实现 OpenHarmony 分布式端高性能模块化管理、依赖拓扑指纹预检与工业级服务定位核方案 前言 在鸿蒙(OpenHarmony)生态的大规模、多模块协同开发、或者是对代码解耦有极其严苛要求的 0308 批次金融级应用中。“模块间依赖的清晰度与服务注入的极速寻找维度”是衡量整个系统架构鲁棒性的最终质量门禁。面对包含数百个业务 Feature、海量动态加载的插件、甚至是由于并发初始化产生的 0308 批次注入冲突。如果仅仅依靠简单的“硬编码单例”或者是干瘪的手动实例化。不仅会导致在处理大型复杂逻辑时让系统如同在逻辑废墟中盲人摸象。更会因为依赖链不透明,令开发者在进行功能重构时瞬间陷入由于循环依赖由于引起的死锁盲区。 我们需要一种“逻辑严密、代码生成对齐”的资产管理艺术。 dep_gen 是一套专注于无缝整合全球公认“依赖生成(Dependency Generation)”思

By Ne0inhk