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年PostgreSQL 详细安装教程(windows)

2025年PostgreSQL 详细安装教程(windows)

前言 PostgreSQL 是一个功能强大的开源关系型数据库管理系统(ORDBMS),以下是对它的全面介绍: 基本概况 * 名称:通常简称为 "Postgres" * 类型:对象-关系型数据库管理系统 * 许可:开源,采用类MIT许可证 * 首次发布:1996年(起源于1986年的POSTGRES项目) * 最新版本:PostgreSQL 16(截至2023年9月发布) 核心特性 1. 标准兼容性 * 完全符合ACID(原子性、一致性、隔离性、持久性) * 高度兼容SQL标准 2. 高级功能 * 复杂查询 * 外键 * 触发器 * 可更新视图 * 事务完整性 * 多版本并发控制(MVCC) 3. 扩展性 * 支持自定义数据类型 * 自定义函数 * 使用不同编程语言编写代码(如PL/pgSQL, PL/Python,

By Ne0inhk
Rust异步测试与调试的实践指南

Rust异步测试与调试的实践指南

Rust异步测试与调试的实践指南 一、异步测试的基础 1.1 异步测试的概念 💡异步测试是对异步代码的功能和性能进行验证的过程,确保异步操作能够正确、高效地执行。与同步测试相比,异步测试需要处理任务调度、I/O操作和资源管理等复杂问题。 在Rust中,异步测试通常使用tokio::test宏或async-std::test宏来标记测试函数,这些宏会自动创建异步运行时环境。 1.2 常用的异步测试框架 * Tokio测试框架:适用于使用Tokio异步运行时的项目,提供tokio::test宏和tokio::spawn函数。 * Async-std测试框架:适用于使用async-std异步运行时的项目,提供async-std::test宏和async-std::task::spawn函数。 * Proptest:用于属性测试,支持异步属性测试。 * Mockall:用于模拟依赖对象,支持异步模拟。 1.3 简单异步函数的测试 下面是一个简单的异步函数测试示例: // src/lib.rsusetokio::time::sleep;usestd::time::D

By Ne0inhk
从“多库并存”到“一库多能”:聊聊金仓KingbaseES的融合架构实践

从“多库并存”到“一库多能”:聊聊金仓KingbaseES的融合架构实践

干数据库这行快十年了,亲眼见证了企业数据架构的变迁。早年做项目,最头疼的就是“数据竖井”——交易系统用Oracle,用户行为日志扔到MongoDB,时序监控数据塞进InfluxDB,图谱关系又得搞个Neo4j。每个库都有自己的语法、管理工具和运维体系,开发团队整天在不同数据库之间做数据同步和格式转换,数据一致性难保证,系统复杂度却直线上升。 这几年“融合数据库”的概念越来越热,但很多厂商的理解还停留在“多模接口”层面。直到去年深度参与了某城商行的核心系统分布式改造项目,用金仓数据库KingbaseES 完整跑了一轮,才算真正体会到什么是“一库多能”的设计哲学。今天就跟大家聊聊我们的实践心得,特别是金仓在这方面的独特思考。 一、为什么是“一库多能”,不是“多库拼装”? 先看个真实场景。我们那个银行客户要做实时反欺诈,需要在一个查询里关联:用户账户信息(结构化)、近期交易流水(带时序特征)、设备指纹(JSON文档)、社交关系图谱(判断是否团伙),以及地理位置信息(空间数据)。如果按传统思路,至少要跨5个不同数据库做联合查询,光数据同步延迟就够受的,更别说保证事务一致性了。

By Ne0inhk
Java-Spring入门指南(十四)利用IDEA教你构建第一个SpringMVC系统

Java-Spring入门指南(十四)利用IDEA教你构建第一个SpringMVC系统

Java-Spring入门指南(十四)SpringMVC项目实战搭建 * 前言 * 一、首先导入我们的Maven * 二、接着导入SpringMVC相关的包 * 三、创建Servlet_web环境 * (1)配置springmvc.xml * (2)配置web.xml里面的中央处理器 * (3)为什么需要配置前端控制器? * 五、配置最新的tomcat 11 * 六、运行项目 前言 * 在上一篇博客中,我们系统学习了SpringMVC的核心流程与组件分工,明确了DispatcherServlet(前端控制器)、HandlerMapping(处理器映射器)等组件的协作逻辑。 * 理论之后更需实践,如何从0到1搭建一个可运行的SpringMVC项目,如何将核心组件配置落地,是本次实战的核心目标。 * 本文将基于Maven+IDEA+Tomcat 11环境,一步步完成SpringMVC项目的搭建、配置与运行,让你直观感受“理论”到“实战”的转化过程。 我的个人主页,欢迎来阅读我的其他文章 https:

By Ne0inhk