【java爬虫】使用element-plus进行个股详细数据分页展示

前言

前面的文章我们讲述了获取详细个股数据的方法,并且使用echarts对个股的价格走势图进行了展示,本文将编写一个页面,对个股详细数据进行展示。别问涉及到了element-plus中分页的写法,对于这部分知识将会做重点讲解。

首先看一下效果

之前我一直认为前端分页很难写,不过今天写完这个页面之后我发现,有了element-plus这样的框架,前端真的变得非常简单。

获取所有有数据的股票代码

我们的页面主要分为两个部分,第一部分是获取所有有数据的股票代码,一旦选择了某一个股票代码,就会进行相对应数据的展示

本节我们先来说一下获取所有可展示的数据

和本页面相关的数据表一共有两张,一张是沪深300成分股表,表中记录了股票代码和股票名称

 

另一张表是个股详细数据表,就是我们在之前的文章介绍过的表

【java爬虫】基于springboot+jdbcTemplate+sqlite+OkHttp获取个股的详细数据-CSDN博客

这样表对应的详细信息如下图所示

我们要分页展示的也是这张表中的数据,之所以需要两张表联动,是因为这张表中没有股票名称,为了能够同时将股票代码和股票名称查出来,我们需要首先查询个股数据表,然后再从沪深300成分股表中查询出股票代码对应的股票名称

    public List<StockOptionVO> getAllCode() {List<StockEntity> stockEntities = sqLiteStockDao.queryAllCode();List<CSI300Entity> csi300Entities = sqlIteCSI300Dao.queryAllItems();List<StockOptionVO> stockOptionVOList = new ArrayList<>();for (int i=0; i<stockEntities.size(); i++) {StockOptionVO stockOptionVO = new StockOptionVO();stockOptionVO.setCode(stockEntities.get(i).getCode());for (int j=0; j<csi300Entities.size(); j++) {if (csi300Entities.get(j).getCode().equals(stockEntities.get(i).getCode())) {stockOptionVO.setName(csi300Entities.get(j).getName());break;}}stockOptionVOList.add(stockOptionVO);}return stockOptionVOList;}

 其中两个SQL语句都很简单,就是SELECT查询数据

    @Overridepublic List<StockEntity> queryAllCode() {String sql = "SELECT DISTINCT code FROM " + TABLE_NAME;log.info("执行sql:" + sql);List<StockEntity> stockEntities = jdbcTemplate.query(sql, new Object[]{}, new BeanPropertyRowMapper<>(StockEntity.class));return stockEntities;}
    @Overridepublic List<CSI300Entity> queryAllItems() {String sql = "SELECT * FROM " + tableName;List<CSI300Entity> csi300Entities = jdbcTemplate.query(sql, new Object[]{}, new BeanPropertyRowMapper<CSI300Entity>(CSI300Entity.class));return csi300Entities;}

控制层代码如下

    // 获取所有有详细数据的股票代码@RequestMapping("/queryCodeOptions")@ResponseBodypublic String queryCodeOptions() {List<StockOptionVO> stockOptionVOList = stockService.getAllCode();return JSON.toJSONString(stockOptionVOList);}

该接口调用的结果如下所示

[{"code":"000001","name":"平安银行"},{"code":"000063","name":"中兴通讯"},{"code":"000002","name":"万科A"},{"code":"688981","name":"中芯国际"},{"code":"000568","name":"泸州老窖"}]

然后我们回到前端,我们使用了<el-select>组件进行多个选项的选择,其中<el-option>是对应的选项,我们使用v-for将后端请求到的数据渲染成选项

     <el-card><el-form label-width="auto"><el-form-item label="选择要查询的股票"><el-select v-model="code" placeholder="请选择股票"><el-option@click="handleSelect(item)"v-for="item in options":label="item.code + ' ' + item.name":value="item.code":key="item.code"></el-option></el-select></el-form-item></el-form></el-card>

注意看,<el-option>中有一个@click选项,就是我们点击的时候会触发的相应操作,实际上这个函数的逻辑就是点击后就进行相对应股票数据的查询。

获取个股详细数据并分页展示

分页有非常多好处,在SQL端主要就是使用LIMIT和OFFSET这两个关键字来实现的

接口层面接收三个参数,分别是股票代码,每一页的数据量和当前页数

    // 分页查询某一只股票的详细数据@RequestMapping("/queryDataByPage/{code}/{pagesize}/{page}")@ResponseBodypublic String queryDataByPage(@PathVariable("code") String code,@PathVariable("pagesize") Integer pagesize,@PathVariable("page") Integer page) {List<StockEntity> stockEntities = stockService.queryDataByPage(code, pagesize, page);return JSON.toJSONString(stockEntities);}

在Service层将页数转换为SQL语句中的LIMIT和OFFSET,其中LIMIT是固定的,就是你的每一页的数据量,OFFSET的计算公式为(page - 1) * pagesize

    // 分页查询某一只股票的详细数据public List<StockEntity> queryDataByPage(String code, Integer pagesize, Integer page) {Integer limit = pagesize;Integer offset = (page - 1) * pagesize;List<StockEntity> stockEntities = sqLiteStockDao.queryDataByPage(code, limit, offset);return stockEntities;}

最后就是DAO层的代码

     @Overridepublic List<StockEntity> queryDataByPage(String code, Integer limit, Integer offset) {String sql = "SELECT * FROM " + TABLE_NAME +" WHERE code=? ORDER BY record_date DESC LIMIT ? OFFSET ?";log.info("执行sql:" + sql);List<StockEntity> stockEntities = jdbcTemplate.query(sql, new Object[]{code, limit, offset},new BeanPropertyRowMapper<>(StockEntity.class));return stockEntities;}

这样一来我们就编写好了分页查询的后端接口。

我们还需要一个获取数据总量的接口,从控制层到服务层再到Dao层的代码如下

    // 查询数据的总条数@RequestMapping("/queryNumByCode/{code}")@ResponseBodypublic Integer queryNumByCode(@PathVariable("code") String code) {int num = stockService.queryNumByCode(code);return num;}
    // 查询数据的总条数public int queryNumByCode(String code) {return sqLiteStockDao.queryNumByCode(code);}
    @Overridepublic int queryNumByCode(String code) {String sql = "SELECT COUNT(id) FROM " + TABLE_NAME + " WHERE code=?";log.info("执行sql:" + sql);int num = jdbcTemplate.queryForObject(sql, new Object[]{code},Integer.class);return num;}

下面来看一下前端的分页组件,element-plus提供了<el-pagintion>进行分页,我们拿一个官网的例子来讲解这个组件的用法

从上到下依次为:

  • current-page:表示当前页数,这是一个动态的值
  • page-size:表示每一页的数据量,这也是一个动态的值
  • small:是否采用小型分页样式
  • disabled:是否禁用分页
  • background:是否为分页按钮添加背景颜色(添加了背景颜色会更好看)
  • layout:组件的排版方式
  • total:总的数据量(这是需要提前获取的)
  • size-change:当每一页的数据量变化时触发的事件
  • current-change:当前页面变化时触发的事件

关于这个样式,我给大家举一个例子,比如我是这样写的

可以看到从左到右分别是sizes,prev,pager,next和total,那么对应的呈现的效果如下

这样子说不知道大家是否能更好地理解这个属性的用法。

那么有了基本的样式后,我们还需要编写当前页和每一页数据量这两个变量改变时的响应事件,其实逻辑都很简单,就是改变一下变量的值,然后再请求新的数据

    handleSizeChange(number) {this.current_size = number;var url ="http://localhost:9001/stock/queryDataByPage/" +this.current_code +"/" +this.current_size +"/" +this.current_page;this.loading = true;axios.get(url).then((response) => {this.table_data = response.data;console.log(response);this.loading = false;}).catch((error) => {console.log(error);this.loading = false;});},handleCurrentChange(number) {this.current_page = number;var url ="http://localhost:9001/stock/queryDataByPage/" +this.current_code +"/" +this.current_size +"/" +this.current_page;this.loading = true;axios.get(url).then((response) => {this.table_data = response.data;console.log(response);this.loading = false;}).catch((error) => {console.log(error);this.loading = false;});},

下面展示一下前端页面的完整代码

<template><el-container><el-main><el-card><el-form label-width="auto"><el-form-item label="选择要查询的股票"><el-select v-model="code" placeholder="请选择股票"><el-option@click="handleSelect(item)"v-for="item in options":label="item.code + ' ' + item.name":value="item.code":key="item.code"></el-option></el-select></el-form-item></el-form></el-card><el-card><template #header><div class="card-header"><span>{{ table_title }}</span></div></template><el-tablev-loading="loading":data="table_data":show-header="true":max-height="500"stripe><el-table-column prop="record_date" label="时间"></el-table-column><el-table-column prop="open_price" label="开盘价"></el-table-column><el-table-column prop="close_price" label="收盘价"></el-table-column><el-table-column prop="change_ament" label="涨跌额"></el-table-column><el-table-columnprop="change_range"label="涨跌幅":formatter="formatter1"></el-table-column><el-table-column prop="max_price" label="最高价格"></el-table-column><el-table-column prop="min_price" label="最低价格"></el-table-column><el-table-column prop="volume" label="成交量(手)"></el-table-column><el-table-columnprop="turnover"label="成交额(万)"></el-table-column><el-table-columnprop="turnover_rate"label="换手率":formatter="formatter2"></el-table-column></el-table><el-divider /><el-pagination:current-page="current_page":page-size="current_size":page-sizes="[10, 20, 30]":small="false":background="true"layout="sizes, prev, pager, next, total":total="total_num"@size-change="handleSizeChange"@current-change="handleCurrentChange"/></el-card></el-main></el-container>
</template><script>
import axios from "axios";
import { getCurrentInstance } from "vue";
export default {data() {return {update_status: "未开始",loading: false,// 当前选中的股票code: "",// 所有的选项options: [],table_title: "个股数据",// 个股详细信息table_data: [],// 分页相关选项// 当前查询的股票代码current_code: "",// 当前页current_page: 1,// 每一页的数量current_size: 10,// 数据总数total_num: 0,echarts: getCurrentInstance().appContext.config.globalProperties.$echarts,};},mounted() {this.init();},methods: {init() {var url = "http://localhost:9001/stock/queryCodeOptions";axios.get(url).then((response) => {this.options = response.data;console.log(response);}).catch((error) => {console.log(error);});},handleSelect(item) {this.current_code = item.code;this.current_page = 1;// 获取表格详细数据var url1 ="http://localhost:9001/stock/queryDataByPage/" +this.current_code +"/" +this.current_size +"/" +this.current_page;this.loading = true;this.table_title = item.code + " " + item.name;axios.get(url1).then((response) => {this.table_data = response.data;console.log(response);this.loading = false;}).catch((error) => {console.log(error);this.loading = false;});// 获取当前股票数据总数var url2 = "http://localhost:9001/stock/queryNumByCode/" + item.code;axios.get(url2).then((response) => {this.total_num = response.data;console.log(response);}).catch((error) => {console.log(error);});},formatter1(row) {return row.change_range + "%";},formatter2(row) {return row.turnover_rate + "%";},handleSizeChange(number) {this.current_size = number;var url ="http://localhost:9001/stock/queryDataByPage/" +this.current_code +"/" +this.current_size +"/" +this.current_page;this.loading = true;axios.get(url).then((response) => {this.table_data = response.data;console.log(response);this.loading = false;}).catch((error) => {console.log(error);this.loading = false;});},handleCurrentChange(number) {this.current_page = number;var url ="http://localhost:9001/stock/queryDataByPage/" +this.current_code +"/" +this.current_size +"/" +this.current_page;this.loading = true;axios.get(url).then((response) => {this.table_data = response.data;console.log(response);this.loading = false;}).catch((error) => {console.log(error);this.loading = false;});},},
};
</script><style scoped>
.card-header {display: flex;justify-content: space-between;align-items: center;
}
</style>

还有一点需要额外说一下,大家可以看一下我们表格中的数据

这两列是由百分号,但是数据库中存的数据是没有百分号的,我们选择在前端进行处理,在表格相应的列中添加一个formatter属性,属性的值是一个函数,函数返回值就是最后渲染到页面上的字符串。

这两个函数的具体实现如下

 

结语

本文介绍了后端分页接口以及基于element-plus的分页实现方法,希望对你有所帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/315350.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

强化学习:PPO

PPO简介 我们在之前的项目中介绍了基于价值的强化学习算法DQN,基于策略的强化学习算法REINFORCE,基于价值和策略的组合算法Actor-Critic. 对于基于策略分方法&#xff1a;参数化智能体的策略&#xff0c;并设计衡量策略好坏的目标函数&#xff0c;通过梯度上升的方法来最大化这…

python调用openai api报错self._sslobj.do_handshake()OSError: [Errno 0] Error

python调用openai api报错self._sslobj.do_handshake()OSError: [Errno 0] Error 废话不说&#xff0c;先上代码&#xff0c;根据官网的介绍写的,chatgpt3.5 api简单调用 import os from openai import OpenAI from dotenv import load_dotenv# 加载 .env 文件中的变量 load_…

三层架构概述

三层架构就是把整个软件的代码分为三个层次&#xff0c;分层的目的是&#xff1a;规范代码&#xff0c;大型软件需要团队配合的时候问题就来了&#xff0c;由于每个程序员风格不一样&#xff0c;而开发软件大量的代码风格不统一就会造成后期调试和维护出现问题&#xff0c;然而…

LeetCode刷题---有效的数独

解题思路&#xff1a; 该题通过哈希表(数组)计数来解决,因为矩阵是一个9*9的固定矩阵 定义二维数组rows,columns和三维度数组subboxes来对矩阵中第i行第j列数字在行、列和九宫格中出现的次数计数。 如果是一个有效的数独&#xff0c;那么矩阵中某个格子中的数字出现的次数在以上…

使用Redis进行搜索

文章目录 构建反向索引 构建反向索引 在Begin-End区域编写 tokenize(content) 函数&#xff0c;实现文本标记化的功能&#xff0c;具体参数与要求如下&#xff1a; 方法参数 content 为待标记化的文本&#xff1b; 文本标记的实现&#xff1a;使用正则表达式提取全小写化后的…

openssl 命令详解

openssl genrsa 命令产生私钥 openssl genrsa 命令是会用来生成 RSA 私有秘钥&#xff0c;不会生成公钥&#xff0c;因为公钥提取自私钥。生成时是可以指定私钥长度和密码保护。 如果需要查看公钥或生成公钥&#xff0c;可以使用 openssl rsa 命令。 命令语法&#xff1a; ope…

华为交换机入门(六):VLAN的配置

VLAN&#xff08;Virtual Local Area Network&#xff09;即虚拟局域网&#xff0c;是将一个物理的LAN在逻辑上划分成多个广播域的通信技术。VLAN内的主机间可以直接通信&#xff0c;而VLAN间不能直接互通&#xff0c;从而将广播报文限制在一个VLAN内。 VLAN 主要用来解决如何…

案例分享:Qt多国语言输入法软键盘

若该文为原创文章&#xff0c;转载请注明出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/135346374 红胖子(红模仿)的博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结…

一文带你了解,AGV和AMR有哪些区别和功能

AGV&#xff08;Automated Guided Vehicle&#xff09;和AMR&#xff08;Autonomous Mobile Robot&#xff09;是两种自动化移动设备&#xff0c;它们在某些方面相似&#xff0c;但也存在一些关键区别。 1、导航技术&#xff1a; AGV&#xff1a; AGV通常使用预先定义的路径或…

【C++】浅拷贝 / 深拷贝 / 写时拷贝

文章目录 1. 经典的string类问题2. 浅拷贝3. 深拷贝3.1 传统写法的String类3.2 现代写法的String类 4. 写时拷贝 1. 经典的string类问题 上一篇博客已经对string类进行了简单的介绍&#xff0c;大家只要能够正常使用即可。 链接&#xff1a;【C】string 在面试中&#xff0c;面…

什么是边缘计算:最全指南

什么是边缘计算 边缘计算是一个流行语&#xff0c;如云、物联网和人工智能。简单地说&#xff0c;边缘计算带来了网络的去中心化。边缘计算是即将到来的技术增强和进步。“边缘”一词的字面含义是地球上以分布式方式提供服务的地理位置。 边缘计算是一种分布式计算系统&#…

时隔五天,重温Redis基础总结

目录 字符串操作命令 Redis 字符串类型常用命令SET key value 设置指定key的值 ​编辑GET key 获取指定key的值 ​编辑SETEX key seconds value 设置指定key的值&#xff0c;并将 key 的过期时间设为 seconds 秒 SETNX key value 只有在key不存在时设置key的值 哈希操作命…