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

news2024/11/27 11:43:29

前言

前面的文章我们讲述了获取详细个股数据的方法,并且使用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查询数据

    @Override
    public 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;
    }
    @Override
    public 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")
    @ResponseBody
    public 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}")
    @ResponseBody
    public 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层的代码

     @Override
    public 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}")
    @ResponseBody
    public Integer queryNumByCode(@PathVariable("code") String code) {
        int num = stockService.queryNumByCode(code);
        return num;
    }
    // 查询数据的总条数
    public int queryNumByCode(String code) {
        return sqLiteStockDao.queryNumByCode(code);
    }
    @Override
    public 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-table
          v-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-column
            prop="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-column
            prop="turnover"
            label="成交额(万)"
          ></el-table-column>
          <el-table-column
            prop="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.coloradmin.cn/o/1349327.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机网络课程设计-企业网三层架构

&#xff08;单人版&#xff09; 摘 要 本篇报告主要解决了为一家名为西宫的公司网络搭建问题&#xff0c;该网络采用企业网三层架构对完了过进行设计。首先使用以太网中继&#xff0c;主要使用VLAN划分的技术来划定不同部门。使用MSTP对每个组配置生成树&#xff0c;防止交换机…

TecoGAN视频超分辨率算法

1. 摘要 对抗训练在单图像超分辨率任务中非常成功&#xff0c;因为它可以获得逼真、高度细致的输出结果。因此&#xff0c;当前最优的视频超分辨率方法仍然支持较简单的范数&#xff08;如 L2&#xff09;作为对抗损失函数。直接向量范数作损失函数求平均的本质可以轻松带来时…

ubuntu:beyond compare 4 This license key has been revoked 解决办法

https://www.cnblogs.com/zhibei/p/12095431.html 错误如图所示&#xff1a; 解决办法&#xff1a; &#xff08;1&#xff09;先用find命令找到bcompare所在位置&#xff1a;sudo find /home/ -name *bcompare &#xff08;2&#xff09;进入 /home/whf/.config,删除/bco…

【UnityShader入门精要学习笔记】(1)了解渲染流水线

本系列为作者学习UnityShader入门精要而作的笔记&#xff0c;内容将包括&#xff1a; 书本中句子照抄 个人批注项目源码一堆新手会犯的错误潜在的太监断更&#xff0c;有始无终 总之适用于同样开始学习Shader的同学们进行有取舍的参考。 文章目录 渲染流水线什么是流水线什么…

BLP模型

本篇文章是调研了许多资料后对 BLP 模型的一个总结 首发公号&#xff1a;Rand_cs MLS&#xff0c;Multi-level Security&#xff0c;主要关心的是数据机密性 D. Elliott Bell 和 Leonard J. LaPadula 在 1996 年提出了基本的 BLP 模型&#xff0c;主要有两个性质&#xff1a;…

[线代]不挂科猴博士

行列式的性质 行列式的计算及应用 矩阵的运算上(加减,相乘,取行列式) 矩阵的运算下(转置,逆,秩) 向量组与线性空间 解方程组

openGauss学习笔记-182 openGauss 数据库运维-升级-升级前准备与检查

文章目录 openGauss学习笔记-182 openGauss 数据库运维-升级-升级前准备与检查182.1 升级前准备与检查清单182.2 收集节点信息182.3 备份数据182.4 获取升级包182.5 健康检查182.5.1 前提条件182.5.2 操作步骤 182.6 检查数据库节点磁盘使用率182.7 检查数据库状态182.7.1 验证…

exposure_line 是如何曝光的 ?

1、读者提问&#xff1a; exposure_line 是如何曝光的&#xff0c;我看网上说这个代表的是一帧曝光多少行&#xff0c; 那如果一帧 exposure_line 小于frame_length&#xff0c;那一帧后面的行就不曝光吗&#xff1f; 不知道怎么理解&#xff0c;是曝光到1500行&#xff0c;…

动态内存分配函数

malloc void* malloc( unsigned size) 申请size个字节的地址连续的内存单元 成功则返回指向内存块的指针, 失败则返回NULL malloc不对申请的空间初始化 calloc void*calloc&#xff08;unsigned n&#xff0c;unsigmed size&#xff09; 申请n* size字节的个地址连续的内…

骑砍战团MOD开发(30)-游戏大地图map.txt

骑砍1战团mod开发-大地图制作方法_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1rz4y1c7wH/ 一.骑砍游戏大地图 骑砍RTS视角游戏大地图 大地图静态模型(map.txt) 军团/城镇图标(module_parties.py). 骑砍大地图的战争迷雾和天气通过API进行管理和控制: # Weather-h…

数据库视图学习

视图 视图&#xff08;view&#xff09;是一种虚拟存在的表。视图中的数据并不在数据库中实际存在&#xff0c;行和列数据来自定义视图的查询中使用的表&#xff0c;并且是在使用视图时动态生成的。通俗的讲&#xff0c;视图只保存了查询的SQL逻辑&#xff0c;不保存查询结果&…

Zookeeper注册中心实战

Java学习手册面试指南&#xff1a;https://javaxiaobear.cn Spring Cloud Zookeeper通过自动配置和绑定到 Spring 环境和其他 Spring 编程模型习惯用法&#xff0c;为 Spring Boot 应用程序提供Apache Zookeeper集成。通过一些简单的注释&#xff0c;您可以快速启用和配置应用…

一起学Elasticsearch系列-Mapping

本文已收录至Github&#xff0c;推荐阅读 &#x1f449; Java随想录 微信公众号&#xff1a;Java随想录 文章目录 Mapping 的基本概念查看索引 Mapping 字段数据类型数字类型基本数据类型Keywords 类型日期类型对象类型空间数据类型文档排名类型文本搜索类型 两种映射类型自动映…

IRQ Handler 的使用——以USART串口接收中断分别在标准库与HAL库版本下的举例

前言&#xff1a; 1.中断系统及EXTI外部中断知识点见我的博文&#xff1a; 9.中断系统、EXTI外部中断_eirq-CSDN博客文章浏览阅读301次&#xff0c;点赞7次&#xff0c;收藏6次。EXTI&#xff08;Extern Interrupt&#xff09;外部中断EXTI可以监测指定GPIO口的电平信号&…

Group k-fold解释和代码实现

Group k-fold解释和代码实现 文章目录 一、Group k-fold解释和代码实现是什么&#xff1f;二、 实验数据设置2.1 实验数据生成代码2.2 代码结果 三、实验代码3.1 实验代码3.2 实验结果3.3 结果解释 四、总结 一、Group k-fold解释和代码实现是什么&#xff1f; 0&#xff0c;1…

MP4文件中mvhd容器中的“下一个track ID”字段的作用是什么?(下一个轨道id)(新轨道id)

文章目录 mvhd容器中有以下字段其中有个“下一个track ID”字段不知道是干什么用的&#xff0c;它被放在这个mvhd容器的最后“下一个track ID”什么是“下一个track ID”“下一个track ID”的作用唯一性标识轨道管理 “下一个track ID”的必要性命令/代码演示 新轨道ID的含义和…

MySQL8.0 ROW_NUMBER 调用案例

ROW_NUMBER()是一个窗口函数或分析函数&#xff0c;它为从1开始应用的每一行分配一个序号。 创建表和生成所需要的数据 CREATE TABLE chapter11 ( shopname VARCHAR(255) NULL, sales VARCHAR(255) NULL, sale_date DATE NULL ); INSERT INTO chapter11 (shopname, sales, sal…

C语言之scanf浅析

前言&#xff1a; 当有了变量&#xff0c;我们需要给变量输入值就可以使用scanf函数&#xff0c;如果需要将变量的值输出在屏幕上的时候可以使用printf函数&#xff0c;如&#xff1a; #include <stdio.h> int main() {int score 0;printf("请输⼊成绩:");sc…

《2023年企业IoT和OT威胁报告》:物联网恶意软件攻击增长400%

内容概括&#xff1a; 物联网&#xff08;IoT&#xff09;设备无疑改变了我们生活、工作和管理运营技术&#xff08;OT&#xff09;环境的方式。总体而言&#xff0c;到2027年&#xff0c;全球物联网设备数量预计将超过290亿&#xff0c;比2023年的167亿大幅增加。设备和智能技…

中文数字的魅力:古今中外的传承与创新

一、引言 中文数字&#xff0c;作为世界上最古老、最具特色的数字系统之一&#xff0c;已经伴随着中华文化走过了几千年的历史。它既是我们祖先智慧的结晶&#xff0c;也是现代生活中不可或缺的元素。本文将从各个方面介绍和解释中文数字的用途&#xff0c;带领大家领略中文数…