【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查询数据

    @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.mfbz.cn/a/284742.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【SpringBoot开发】之商城项目案例(实现登陆版)

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是君易--鑨&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的博客专栏《SpringBoot开发之商城项目系列》。&#x1f3af…

【NLP论文】02 TF-IDF 关键词权值计算

之前写了一篇关于关键词词库构建的文章&#xff0c;没想到反响还不错&#xff0c;最近有空把接下来的两篇补完&#xff0c;也继续使用物流关键词词库举例&#xff0c;本篇文章承接关键词词库构建并以其为基础&#xff0c;将计算各关键词的 TF-IDF 权值&#xff0c;TF-IDF 权值主…

霹雳吧啦Wz《pytorch图像分类》-p2AlexNet网络

《pytorch图像分类》p2AlexNet网络基础及代码 一、零碎知识点1.过拟合2.使用dropout后的正向传播3.正则化regularization4.代码中所用的知识点 二、总体架构分析1.ReLU激活函数2.手算3.模型代码 三、训练花分类课程代码1.model.py2.train.py3.predict.py 一、零碎知识点 1.过拟…

FPGA项目(14)——基于FPGA的数字秒表设计

1.功能设计 设计内容及要求: 1.秒表最大计时范围为99分59. 99秒 2.6位数码管显示&#xff0c;分辨率为0.01秒 3.具有清零、启动计时、暂停及继续计时等功能 4.控制操作按键不超过二个。 2.设计思路 所采用的时钟为50M&#xff0c;先对时钟进行分频&#xff0c;得到100HZ频率…

【Maven】下载配置maven以及IDEA配置maven详情

目录 1、下载maven 2、配置settings.xml 2.1、配置本地仓库 2.2、配置阿里云镜像仓库 2.3、配置JDK 3、配置环境变量 4、IDEA配置maven 1、下载maven maven官网&#xff1a;https://maven.apache.org/ 2、配置settings.xml 2.1、配置本地仓库 <localRepository>C:\…

oracle 9i10g编程艺术-读书笔记1

根据书中提供的下载代码链接地址&#xff0c;从github上找到源代码下载地址。 https://github.com/apress下载好代码后&#xff0c;开始一段新的旅行。 设置 SQL*Plus 的 AUTOTRACE 设置 SQL*Plus 的 AUTOTRACE AUTOTRACE 是 SQL*Plus 中一个工具&#xff0c;可以显示所执行…

GPT4-AIl本地部署-chat AI本地使用

文章目录 GPT4-AIl本地部署GPT4客户端下载地址&#xff1a;对应的下载下载后的文件点击安装&#xff0c;改一下文件存放路径&#xff0c;下面都是默认下一步进度条100%后&#xff0c;点击完成 安装完桌面生成图标&#xff0c;点击选择都是NO&#xff0c;不进行数据上传点击后&a…

Python编程新技能:如何优雅地实现水仙花数?

水仙花数&#xff08;Narcissistic number&#xff09;也被称为阿姆斯特朗数&#xff08;Armstrong number&#xff09;或自恋数等&#xff0c;它是一个非负整数&#xff0c;其特性是该数的每个位上的数字的n次幂之和等于它本身&#xff0c;其中n是该数的位数。简单来说&#x…

一起学Elasticsearch系列-写入原理

本文已收录至Github&#xff0c;推荐阅读 &#x1f449; Java随想录 微信公众号&#xff1a;Java随想录 文章目录 写入过程写操作写流程写一致性策略 写入原理RefreshMergeFlushTranslog图解写入流程 ES作为一款开源的分布式搜索和分析引擎&#xff0c;以其卓越的性能和灵活的扩…

29 UVM Command Line Processor (CLP)

随着设计和验证环境的复杂性增加&#xff0c;编译时间也增加了&#xff0c;这也影响了验证时间。因此&#xff0c;需要对其进行优化&#xff0c;以便在不强制重新编译的情况下考虑新的配置或参数。我们已经看到了function or task如何基于传递参数进行行为。类似地&#xff0c;…

均方差损失推导

一、损失函数&#xff08;Cost function&#xff09; 定义&#xff1a;用于衡量模型预测结果与真实结果之间差距的函数。&#xff08;有的地方称之为代价函数&#xff0c;但是个人感觉损失函数这个名称更贴近实际用途&#xff09; 理解&#xff1a;&#xff08;以均方差损失函…

Python浪漫520表白代码

系列文章 序号文章目录直达链接表白系列1浪漫520表白代码https://want595.blog.csdn.net/article/details/1306668812满屏飘字表白代码https://want595.blog.csdn.net/article/details/1349149703无限弹窗表白代码https://want595.blog.csdn.net/article/details/1297945184跳…

使用.Net nanoFramework 驱动ESP32的OLED显示屏

本文介绍如何使用.Net nanoFramework 驱动ESP32的OLED显示屏。我们将会从最基础的部分开始&#xff0c;逐步深入&#xff0c;让你能够理解并实现整个过程。无论你是初学者还是有一定经验的开发者&#xff0c;这篇文章都会对你有所帮助。 1. 硬件准备 1.1 ESP32开发板 这里我们…

搭建flink集群 —— 筑梦之路

Apache Flink 是一个框架和分布式处理引擎&#xff0c; 用于在无边界和有边界数据流上进行有状态的计算。 Flink 能在所有常见集群环境中运行&#xff0c;并能以内存速度和任意规模进行计算。 Flink并没有依靠自身实现所有分布式系统需要解决的问题&#xff0c; 而是在已有集群…

c语言之将输入的十进制转换成二进制数并打印原码反码补码

十进制转二进制 首先&#xff0c;我们要知道的是十进制转换成二进制数的方法。我们一般采用的除二取余的方法&#xff0c;在这里我用32位数组来进行转换。 int main() {printf("请输入一个十进制数\n");int n 0;scanf("%d", &n);int arr[32];int* p…

实战入门 K8s剩下三个模块

1.Label Label是kubernetes系统中的一个重要概念。它的作用就是在资源上添加标识&#xff0c;用来对它们进行区分和选择。 Label的特点&#xff1a; 一个Label会以key/value键值对的形式附加到各种对象上&#xff0c;如Node、Pod、Service等等 一个资源对象可以定义任意数量…

VMware虚拟机和Centos7镜像安装

文章目录 安装VMware虚拟机1、下载2、激活 安装Centos7镜像启动虚拟机 安装VMware虚拟机 1、下载 建议还是安装16版本 VMware16下载 https://www.123pan.com/s/HQeA-aX1Sh VMware15 链接&#xff1a;https://pan.baidu.com/s/11UD1hb6IydbxNNPxmh-MqA?pwd0630 提取码&am…

【熔断限流组件resilience4j和hystrix】

文章目录 &#x1f50a;博主介绍&#x1f964;本文内容起因resilience4j落地实现pom.xml依赖application.yml配置接口使用 hystrix 落地实现pom.xml依赖启动类上添加注解接口上使用 &#x1f4e2;文章总结&#x1f4e5;博主目标 &#x1f50a;博主介绍 &#x1f31f;我是廖志伟…

使用YOLOv8和Grad-CAM技术生成图像热图

目录 yolov8导航 YOLOv8&#xff08;附带各种任务详细说明链接&#xff09; 概述 环境准备 代码解读 导入库 定义letterbox函数 调整尺寸和比例 计算填充 应用填充 yolov8_heatmap类定义和初始化 后处理函数 绘制检测结果 类的调用函数 热图生成细节 参数解释 we…

QT上位机开发(带配置文件的倒计时软件)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 前面我们用qt写过倒计时软件&#xff0c;但是那个时候界面只有分钟和秒钟&#xff0c;这一次我们希望在之前的基础上拓展一下。第一&#xff0c;可…