day03-股票数据报表与导出

news2024/10/6 2:30:17

day03-股票数据表报与导出

目标

  1. 理解涨幅榜业务需求;
  2. 理解涨停跌停概念,并涨停跌停基本实现;
  3. 理解涨停跌停SQL分析流程,并根据接口文档自定义实现;
  4. 理解echarts基本使用;
  5. 掌握easyExcel基本使用,并实现涨幅榜数据导出功能;

第一章 股票涨幅统计

1、涨幅榜更多数据功能实现

1.1 涨幅榜更多数据功能分析

1.1.1 原型效果

在这里插入图片描述

1.1.2 涨幅榜分页查询功能分析

功能描述:分页查询最新股票交易时间点下沪深两市个股行情数据,并根据涨幅降序排序展示

服务路径:/api/quot/stock/all
服务方法:GET
请求参数:

参数说明参数名称是否必须数据类型备注
当前页pagefalseInteger默认值:1
每页大小pageSizefalseInteger默认值:20

响应数据格式:

{
    "code": 1,
    "data": {
        "totalRows": 46750,//总行数
        "totalPages": 4675,//总页数
        "pageNum": 2,//当前页
        "pageSize": 10,//每页大小
        "size": 10,//当前页大小
        "rows": [
            {
                "tradeAmt": 4594802,//交易量
                "preClosePrice": 18.78,//前收盘价
                "amplitude": 0.059638,//振幅
                "code": "000004",//股票编码
                "name": "国华网安",//股票名称
                "curDate": "2021-12-30 10:20",//当前日期
                "tradeVol": 4594802,//交易金额
                "increase": 0.039936,//涨跌
                "upDown": 0.75,//涨幅
                "tradePrice": 19.53//当前价格
            },
           //省略......
        ]
    }
}

说明:

1.项目第一天已配置好PageHelper分页插件;

2.相关参数:

​ 涨跌:当前价-前收盘价
​ 涨幅:(当前价-前收盘价)/ 前收盘价 * 100%
​ 振幅:(最高成交价-最低成交价)/ 前收盘价 * 100%

1.1.3 实体类封装

1)查询记录实体封装

在stock_common工程下封装查询行记录数据:

package com.itheima.stock.pojo.domain;

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.math.BigDecimal;
import java.util.Date;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class StockUpdownDomain {

    private String code;

    private String name;

    private BigDecimal preClosePrice;

    private BigDecimal tradePrice;

    private BigDecimal increase;

    private BigDecimal upDown;

    private BigDecimal amplitude;

    private Long tradeAmt;

    private BigDecimal tradeVol;

    /**
     * 日期
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm")
    private Date curDate;
}

2)封装分页实体类

分页实体类是前端响应对象,我们维护到stock_backend工程下即可;

分页实体对象的数据来自分页PageInfo对象,所以我们在构造器中传入PageInfo直接转化即可:

package com.itheima.stock.vo.resp;

import com.github.pagehelper.PageInfo;
import lombok.Data;
import java.io.Serializable;
import java.util.List;

/**
 * 分页工具类
 */
@Data
public class PageResult<T> implements Serializable {
    /**
     * 总记录数
     */
    private Long totalRows;

    /**
     * 总页数
     */
    private Integer totalPages;

    /**
     * 当前第几页
     */
    private Integer pageNum;
    /**
     * 每页记录数
     */
    private Integer pageSize;
    /**
     * 当前页记录数
     */
    private Integer size;
    /**
     * 结果集
     */
    private List<T> rows;

    /**
     * 分页数据组装
     * @param pageInfo
     * @return
     */
    public PageResult(PageInfo<T> pageInfo) {
        totalRows = pageInfo.getTotal();
        totalPages = pageInfo.getPages();
        pageNum = pageInfo.getPageNum();
        pageSize = pageInfo.getPageSize();
        size = pageInfo.getSize();
        rows = pageInfo.getList();
    }
}

分页实体类维护到stock_backend下vo/resp下即可;

直接导入:day03\资料\后端资料\PageResult.java;

1.2 涨幅榜更多SQL分析

方式1:全表数据根据时间和涨幅降序排序

# 分析:统计国内A股股票的最新数据,根据涨幅排序取前4
# 方式1:根据日期和涨幅降序排序取前4即可
select 
	sri.trade_amount as tradeAmt,
	sri.pre_close_price as preClosePrice,
	(sri.max_price- sri.min_price)/sri.pre_close_price as amplitude,
	sri.stock_code as code,
	sri.stock_name as name,
	sri.cur_time   as curDate,
	sri.trade_volume as tradeVol,
	(sri.cur_price-sri.pre_close_price) as upDown,
	(sri.cur_price- sri.pre_close_price)/sri.pre_close_price as increase,
	sri.cur_price as tradePrice
from stock_rt_info as sri 
order by sri.cur_time desc,upDown desc
# 分析:存在的问题:全表排序查询开下太大,不适合大数据量的查询;

方式2:先根据最新股票交易时间点走索引查询,然后再根据涨幅排序

# 好处:走索引,避免全表排序查询,速度更快
select 
	sri.trade_amount as tradeAmt,
	sri.pre_close_price as preClosePrice,
	(sri.max_price- sri.min_price)/sri.pre_close_price as amplitude,
	sri.stock_code as code,
	sri.stock_name as name,
	sri.cur_time   as curDate,
	sri.trade_volume as tradeVol,
	(sri.cur_price-sri.pre_close_price) as upDown,
	(sri.cur_price- sri.pre_close_price)/sri.pre_close_price as increase,
	sri.cur_price as tradePrice
from stock_rt_info as sri 
where sri.cur_time='2021-12-30 09:42:00'
order by upDown desc

1.3 更多涨幅信息功能实现

1.3.1 定义服务访问接口方法
    /**
     * 分页查询股票最新数据,并按照涨幅排序查询
     * @param page
     * @param pageSize
     * @return
     */
    @GetMapping("/stock/all")
    public R<PageResult> getStockPageInfo(@RequestParam(name = "page",required = false,defaultValue = "1") Integer page,
                                          @RequestParam(name = "pageSize",required = false,defaultValue = "20") Integer pageSize){
            return stockService.getStockPageInfo(page,pageSize);
    }
1.3.2 定义服务接口方法和实现

接口方法

    /**
     * 分页查询股票最新数据,并按照涨幅排序查询
     * @param page
     * @param pageSize
     * @return
     */
    R<PageResult> getStockPageInfo(Integer page, Integer pageSize);

实现

    /**
     * 分页查询股票最新数据,并按照涨幅排序查询
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public R<PageResult> getStockPageInfo(Integer page, Integer pageSize) {
        //1.设置PageHelper分页参数
        PageHelper.startPage(page,pageSize);
        //2.获取当前最新的股票交易时间点
        Date curDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //todo
        curDate= DateTime.parse("2022-06-07 15:00:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //3.调用mapper接口查询
        List<StockUpdownDomain> infos= stockRtInfoMapper.getNewestStockInfo(curDate);
        if (CollectionUtils.isEmpty(infos)) {
            return R.error(ResponseCode.NO_RESPONSE_DATA);
        }
        //4.组装PageInfo对象,获取分页的具体信息,因为PageInfo包含了丰富的分页信息,而部分分页信息是前端不需要的
        //PageInfo<StockUpdownDomain> pageInfo = new PageInfo<>(infos);
//        PageResult<StockUpdownDomain> pageResult = new PageResult<>(pageInfo);
        PageResult<StockUpdownDomain> pageResult = new PageResult<>(new PageInfo<>(infos));
        //5.封装响应数据
        return R.ok(pageResult);
    }
1.3.3 定义mapper接口方法和xml

在StockRtInfoMapper接口下定义:

    /**
     * 查询指定时间点下股票的数据,并按照涨幅降序排序
     * @param curDate
     * @return
     */
    List<StockUpdownDomain> getNewestStockInfo(@Param("timePoint") Date curDate);

在StockRtInfoMapper.xml下定义绑定sql:

    <select id="getNewestStockInfo" resultType="com.itheima.stock.pojo.domain.StockUpdownDomain">
        select
            sri.trade_amount as tradeAmt,
            sri.pre_close_price as preClosePrice,
            (sri.max_price-sri.min_price)/sri.pre_close_price as amplitude,
            sri.stock_code as code,
            sri.stock_name as  name,
            sri.cur_time as curDate,
            sri.trade_volume as tradeVol,
            sri.cur_price-sri.pre_close_price as increase,
            (sri.cur_price-sri.pre_close_price) /pre_close_price as upDown,
            sri.cur_price as tradePrice
        from stock_rt_info as   sri
        where sri.cur_time=#{timePoint}
        order by upDown desc
    </select>
1.3.4 web接口测试
  • postman测试:http://127.0.0.1:8091/api/quot/stock/all?page=2&pageSize=10

在这里插入图片描述

  • 页面展示效果:

在这里插入图片描述

2、涨幅榜功能实现(作业)

2.1 股票涨幅榜功能分析

2.1.1 涨幅榜原型效果

在这里插入图片描述

2.1.2 股票表结构分析

表:stock_rt_info流水表:

在这里插入图片描述

2.1.3 涨幅榜功能分析

功能描述:统计沪深两市个股最新交易数据,并按涨幅降序排序查询前4条数据
服务路径:/api/quot/stock/increase
服务方法:GET
前端请求频率:每分钟
请求参数:无

响应数据格式:

{
    "code": 1,
    "data": [
        {
            "code": "000004",//股票编码
            "name": "国华网安",//股票名称
            "preClosePrice": 18.78,//前收盘价
            "tradePrice": 19.53//当前价格
             "tradeAmt": 4594802,//交易量
            "tradeVol": 4594802,//交易金额
            "increase": 0.039936,//涨跌
            "upDown": 0.75,//涨幅
            "amplitude": 0.059638,//振幅
            "curDate": "2021-12-30 10:30",//当前日期
        },
       //省略......
    ]
}

2.2涨幅榜功能实现

2.2.1定义访问接口
    @GetMapping("stock/increase")
    public R<List<StockUpdownDomain>>stockIncrease(){
        return stockService.stockIncrease();
    }
2.2.2定义服务接口方法与实现

服务接口定义

/**
     * 涨幅榜
     * @return
     */
    R<List<StockUpdownDomain>> stockIncrease();

接口实现

    @Override
    public R<List<StockUpdownDomain>> stockIncrease() {
        //获取股票最新交易时间点
        Date lastDate=DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //TODO mock数据,后续删除
        lastDate=DateTime.parse("2022-07-07 14:55:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.调用mapper接口查询
        List<StockUpdownDomain>infos=stockRtInfoMapper.getNewestStockInfo(lastDate);
        if(CollectionUtils.isEmpty(infos)){
            return R.error(ResponseCode.NO_RESPONSE_DATA);
        }
        return R.ok(infos);
    }

3.涨停跌停数据统计功能

3.1 涨跌停数据统计业务分析

3.1.1 涨跌停原型效果

在这里插入图片描述

说明:

A股市场有涨幅±10%限制;

股票是否涨停和跌停并不以我们的统计结果为基准,而是由证券交易所来确定,可能真实情况是涨幅超过10%或者低于-10%;

3.1.2 涨停跌停接口说明

功能描述:统计沪深两市T日(当前股票交易日)每分钟达到涨跌停股票的数据

​ 注意:如果不在股票的交易日内,则统计最近的股票交易日下的数据

服务路径:/api/quot/stock/updown/count
服务方法:GET
前端请求频率:每分钟
请求参数:无

响应数据格式:

{
    "code": 1,
    "data": {
        "upList": [
            {
                "count": 1,//涨停数量
                "time": "202112311412"//当天分时
            },
           {
                "count": 3,//涨停数量
                "time": "202112311413"//当天分时
            },
          	//省略......
        ],
        "downList": [
            {
                "count": 2,//跌停数量
                "time": "202112310925"//当天分时
            },
			//省略......
        ]
    }
}

总之,业务要求获取最新交易日下每分钟达到涨跌停数股票的数量;

关于SQL日期函数,详见:今日指数资料\V3\day03-股票数据报表与导出\资料\预习基础知识点\SQL日期函数.md

3.2 T日涨跌停统计SQL分析

3.2.1 SQL分析思路
# 1.以统计当前股票交易日下,每分钟对应的涨停数量为例
# 思考:涨停与涨幅有关,但是我们的股票流水表中没有涨幅的数据,需要自己去就是那
# 1.先统计指定日期下(开盘时间点到最新时间点)涨幅达到涨停的数据
# 查询后的条件过滤,使用关键字:having
select
    (sri.cur_price-sri.pre_close_price)/sri.pre_close_price as ud,
    sri.cur_time as time
from stock_rt_info sri
where sri.cur_time BETWEEN '2022-01-06 09:30:00' and '2022-01-06 14:25:00'
having ud>=0.1;

# 2.将上述结果作为一张表,然后根据time时间分组,统计出每分钟对应的数量,而这个数量就是涨停的数量
select
   tmp.time,
   count(*) as count
from () as tmp
group by tmp.time;
# 填充sql
select
   tmp.time,
    count(*) as count
from (select
    (sri.cur_price-sri.pre_close_price)/sri.pre_close_price as ud,
    sri.cur_time as time
from stock_rt_info sri
where sri.cur_time BETWEEN '2022-01-06 09:30:00' and '2022-01-06 14:25:00'
having ud>=0.1) as tmp
group by tmp.time
order by tmp.time asc;

# 跌停
select
    date_format(tmp.time,'%Y%m%d%H%i') as time ,
    count(*) as count
from (select
    (sri.cur_price-sri.pre_close_price)/sri.pre_close_price as ud,
    sri.cur_time as time
from stock_rt_info sri
where sri.cur_time BETWEEN '2022-01-06 09:30:00' and '2022-01-06 14:25:00'
having ud<=-0.1) as tmp
group by tmp.time
order by tmp.time asc;
3.2.2 查询数据组装思路
  • 涨跌停数据包含了涨停统计数据和跌停统计数据,而每个数据组中的元素又仅仅包含时间和数量,这些数据是高度聚合得出的结果,所以我们可以把每组数据封装到map下,数据类型为:Map<String,List>
  • 涨停统计SQL和跌停统计的SQL除了条件外,结构是一致的,我们可定义一个flag标识,mapper中传入时,0代表涨停,1代表跌停;

3.3 T日涨跌停统计功能实现

3.3.1 定义访问接口
    /**
     * 统计最新交易日下股票每分钟涨跌停的数量
     * @return
     */
    @GetMapping("/stock/updown/count")
    public R<Map> getStockUpdownCount(){
        return stockService.getStockUpdownCount();
    }
3.3.2 定义服务接口方法与实现

服务接口定义:

    /**
     * 统计最新交易日下股票每分钟涨跌停的数量
     * @return
     */
    R<Map> getStockUpdownCount();

方法实现:

    /**
     * 统计最新交易日下股票每分钟涨跌停的数量
     * @return
     */
    @Override
    public R<Map> getStockUpdownCount() {
        //1.获取最新的交易时间范围 openTime  curTime
        //1.1 获取最新股票交易时间点
        DateTime curDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        Date curTime = curDateTime.toDate();
        //TODO
        curTime= DateTime.parse("2022-01-06 14:25:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //1.2 获取最新交易时间对应的开盘时间
        DateTime openDate = DateTimeUtil.getOpenDate(curDateTime);
        Date openTime = openDate.toDate();
        //TODO
        openTime= DateTime.parse("2022-01-06 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.查询涨停数据
        //约定mapper中flag入参: 1-》涨停数据 0:跌停
        List<Map> upCounts=stockRtInfoMapper.getStockUpdownCount(openTime,curTime,1);
        //3.查询跌停数据
        List<Map> dwCounts=stockRtInfoMapper.getStockUpdownCount(openTime,curTime,0);
        //4.组装数据
        HashMap<String, List> mapInfo = new HashMap<>();
        mapInfo.put("upList",upCounts);
        mapInfo.put("downList",dwCounts);
        //5.返回结果
        return R.ok(mapInfo);
    }
3.3.3 mapper接口方法定义与xml

Mapper接口定义:

    /**
     * 查询指定时间范围内每分钟涨停或者跌停的数量
     * @param openTime 开始时间
     * @param curTime 结束时间 一般开始时间和结束时间在同一天
     * @param flag 约定:1->涨停 0:->跌停
     * @return
     */
    List<Map> getStockUpdownCount(@Param("openTime") Date openTime, @Param("curTime") Date curTime, @Param("flag") int flag);

xml定义:

    <select id="getStockUpdownCount" resultType="map">
        select
            date_format(tmp.time,'%Y%m%d%H%i') as time ,
            count(*) as count
        from (select
                    (sri.cur_price-sri.pre_close_price)/sri.pre_close_price as ud,
                    sri.cur_time as time
              from stock_rt_info sri
              where sri.cur_time BETWEEN #{openTime} and #{curTime}
             having ud
             <if test="flag==1">
                 >=0.1
             </if>
             <if test="flag==0">
                 &lt;=-0.1
             </if>
             )
       as tmp
        group by tmp.time
        order by tmp.time asc
    </select>
3.3.4 web接口测试
  • postman测试地址:http://localhost:8091/api/quot//stock/updown/count

在这里插入图片描述

第二章 EchartJs报表展示

1、Echarts介绍

我们当前项目下的图形报表是使用echarts实现,所以接下来我们学习下echart的基本使用。

echarts Apache官网:https://echarts.apache.org/zh/index.html

在这里插入图片描述

点击所有示例,可快速学习echarts的基本使用:

在这里插入图片描述

我们以折线图为例,演示echarts的基本使用:

在这里插入图片描述

我们发现对于不同的图形展示方式,只需提供x轴和y轴数据即可;

2、Vue整合Echarts快速入门

2.1 Vue架手架安装echarts

1) 打开Vue脚手架工程

​ vscode打开: day03\资料\echart_vue_project 工程,启动命令:npm run serve

2)工程安装echarts依赖

​ 运行安装命令:npm install echarts -S

说明:-D:仅仅用于开发环境 -S:既用于开发环境,又可用于生产环境

命令执行完毕后,我们发现工程package.json文件下已经引入了echarts依赖:

  "dependencies": {
    "core-js": "^3.6.5",
    "echarts": "^5.2.2",
    "vue": "^2.6.11"
  }

2.2 配置echarts

在main.js入口文件下引入echarts,并将echarts对象挂在Vue对象下;

import Vue from 'vue'
import App from './App.vue'
//引入echarts对象
import * as echarts from 'echarts'

Vue.config.productionTip = false

//挂在在Vue全局对象下
Vue.prototype.$echarts=echarts
new Vue({
  render: h => h(App),
}).$mount('#app')

2.3 vue使用echarts

在App.vue组件下添加echarts视图资源:

<template>
  <div id="app" >
    <h1>echartjs入门</h1>
    <div ref="echartDiv" :style="{width: '100%', height: '500px'}"></div>
  </div>
</template>

<script>

export default {
  name: 'App',
  methods:{
    drawLine(){
           this.myChart = this.$echarts.init(this.$refs.echartDiv);
           let eOption = {
              xAxis: {
                type: 'category',
                data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
              },
            yAxis: {
              type: 'value'
            },
            series: [
              {
                data: [150, 230, 224, 218, 135, 147, 260],
                type: 'line'
              }
            ]
    };
    this.myChart.setOption(eOption);
    }
  },
  mounted(){
    this.drawLine();
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

2.4 页面效果

在这里插入图片描述

3、项目中Echarts的使用

3.1 配置和使用流程说明

我们当前项目的前端也是同样的使用方式,在package.json中已经引入了echart依赖:

  "dependencies": {
    "echarts": "^4.7.0",
   	//省略.......
  }   

main.js中也已经引入echarts:

import echarts from 'echarts'
Vue.prototype.$echarts = echarts

home组件下使用echarts:

在这里插入图片描述

3.2 前端显示效果

在这里插入图片描述

注意:点击涨停和跌停,也可单独显示;

第三章 EasyExcel使用

1、EasyExcel介绍

1.1 官网介绍

传统操作Excel大多都是利用Apach POI进行操作的,但是POI框架并不完善,使用过程非常繁琐且有较多的缺陷:

  • 动态操作Excel非常繁琐,对于新手来说,很难在短时间内上手;
  • 读写时需要占用较大的内存,当数据量大时容易发生内存溢出问题(OOM);

基于上述原因,阿里开源出一款易于上手,且比较节省内存的Excel框架:EasyExcel

注意:easyExcel底层也是使用POI实现的;

官网地址:https://www.yuque.com/easyexcel/doc/easyexcel

在这里插入图片描述

依赖资源:

<!--引入easyexcel-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>3.0.4</version>
</dependency>

注意:目前版本与JDK8较为契合,高版本的JDK可能会出现兼容性问题;

1.2 Excel相关结构说明

在这里插入图片描述

2、EasyExcel导出数据快速入门

2.1 构建测试实体类

package com.itheima.stock.pojo;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.Date;

/**
 * @author by itheima
 * @Date 2021/12/19
 * @Description
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User implements Serializable {
    private String userName;
    private Integer age;
    private String address;
    private Date birthday;
}

2.2 数据导出到excel

package com.itheima.stock;

import com.alibaba.excel.EasyExcel;
import com.itheima.stock.pojo.User;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author by itheima
 * @Date 2021/12/31
 * @Description
 */
public class TestEasyExcel {

    public List<User> init(){
        //组装数据
        ArrayList<User> users = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            User user = new User();
            user.setAddress("上海"+i);
            user.setUserName("张三"+i);
            user.setBirthday(new Date());
            user.setAge(10+i);
            users.add(user);
        }
        return users;
    }
    /**
     * 直接导出后,表头名称默认是实体类中的属性名称
     */
    @Test
    public void test02(){
        List<User> users = init();
        //不做任何注解处理时,表头名称与实体类属性名称一致
        EasyExcel.write("C:\\Users\\46035\\Desktop\\ex\\用户.xls",User.class).sheet("用户信息").doWrite(users);
    }
}

在这里插入图片描述

2.3 自定义表头

修改User实体类,设置表头数据和排序规则:

package com.itheima.stock.pojo;

import com.alibaba.excel.annotation.ExcelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;

/**
 * @author by itheima
 * @Date 2021/12/19
 * @Description
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
/**
  * 通过注解自定义表头名称 注解添加排序规则,值越大 越靠近右边
*/
public class User implements Serializable {
    @ExcelProperty(value = {"用户名"},index = 1)
    private String userName;
    @ExcelProperty(value = {"年龄"},index = 2)
    private Integer age;
    @ExcelProperty(value = {"地址"} ,index = 4)
    private String address;
    @ExcelProperty(value = {"生日"},index = 3)
    private Date birthday;
}

在这里插入图片描述

3、EasyExcel导出数据高级设置

3.1 自定义日期格式

package com.itheima.stock.pojo;

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.Date;

/**
 * @author by itheima
 * @Date 2021/12/19
 * @Description
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User implements Serializable {
    @ExcelProperty(value = {"用户名"},index = 1)
    private String userName;
    @ExcelProperty(value = {"年龄"},index = 2)
    private Integer age;
    @ExcelProperty(value = {"地址"} ,index = 4)
    private String address;
    @ExcelProperty(value = {"生日"},index = 3)
    //注意:日期格式注解由alibaba.excel提供
    @DateTimeFormat("yyyy/MM/dd HH:mm")
    private Date birthday;
}

在这里插入图片描述

3.2 合并表头

添加合并表头信息:

package com.itheima.stock.pojo;

import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.Date;

/**
 * @author by itheima
 * @Date 2021/12/19
 * @Description
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User implements Serializable {
    @ExcelProperty(value = {"用户基本信息","用户名"},index = 1)
    private String userName;
    @ExcelProperty(value = {"用户基本信息","年龄"},index = 2)
    private Integer age;
    @ExcelProperty(value = {"用户基本信息","地址"} ,index = 4)
    private String address;
    @ExcelProperty(value = {"用户基本信息","生日"},index = 3)
    //注意:日期格式注解由alibaba.excel提供
    @DateTimeFormat("yyyy/MM/dd HH:mm")
    private Date birthday;
}

效果:

在这里插入图片描述

3.3 忽略指定表头信息

/**
 * @author by itheima
 * @Date 2021/12/19
 * @Description
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User implements Serializable {
    @ExcelProperty(value = {"用户基本信息","用户名"},index = 1)
    @ExcelIgnore
    private String userName;
    @ExcelProperty(value = {"用户基本信息","年龄"},index = 2)
    private Integer age;
    @ExcelProperty(value = {"用户基本信息","地址"} ,index = 4)
    private String address;
    @ExcelProperty(value = {"用户基本信息","生日"},index = 3)
    //注意:日期格式注解由alibaba.excel提供
    @DateTimeFormat("yyyy/MM/dd HH:mm")
    private Date birthday;
}

效果:

在这里插入图片描述

3.4 设置单元格大小

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@HeadRowHeight(value = 35) // 表头行高
@ContentRowHeight(value = 25) // 内容行高
@ColumnWidth(value = 50) // 列宽
public class User implements Serializable {
    @ExcelProperty(value = {"用户基本信息","用户名"},index = 1)
    @ExcelIgnore
    private String userName;
    @ExcelProperty(value = {"用户基本信息","年龄"},index = 2)
    private Integer age;
    @ExcelProperty(value = {"用户基本信息","地址"} ,index = 4)
    private String address;
    @ExcelProperty(value = {"用户基本信息","生日"},index = 3)
    //注意:日期格式注解由alibaba.excel提供
    @DateTimeFormat("yyyy/MM/dd HH:mm")
    private Date birthday;
}

效果:

在这里插入图片描述

4、EasyExcel导入数据

    /**
     * excel数据格式必须与实体类定义一致,否则数据读取不到
     */
    @Test
    public void readExcel(){
        ArrayList<User> users = new ArrayList<>();
        //读取数据
        EasyExcel.read("C:\\Users\\46035\\Desktop\\ex\\用户.xls", User.class, new AnalysisEventListener<User>() {
            @Override
            public void invoke(User o, AnalysisContext analysisContext) {
                System.out.println(o);
                users.add(o);
            }
            @Override
            public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                System.out.println("完成。。。。");
            }
        }).sheet().doRead();
        System.out.println(users);
    }

第四章 股票涨幅数据导出

1、涨幅榜数据导出功能分析

1.1 原型效果

通过点击【导出数据】按钮,将当前页的数据导出到excel下:

在这里插入图片描述

1.2 数据导出接口说明

功能说明:将分页涨幅榜下指定页码的数据导出到excel表格下
请求地址:/api/quot/stock/export
请求方式:GET

请求参数:

参数名称参数说明是否必须数据类型备注
当前页pagefalseInteger默认值:1
每页大小pageSizefalseInteger默认值:20

响应:excel格式的文件流

1.3 功能实现准备

在stock_common工程下引入easyExcel依赖:

<!--引入easyExcel-->
<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>easyexcel</artifactId>
</dependency>

调整StockUpdownDomain实体类:

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class StockUpdownDomain {
    @ExcelProperty(value = {"股票涨幅信息统计表","股票编码"},index = 0)
    private String code;

    @ExcelProperty(value = {"股票涨幅信息统计表","股票名称"},index = 1)
    private String name;

    @ExcelProperty(value = {"股票涨幅信息统计表","前收盘价格"},index = 2)
    private BigDecimal preClosePrice;

    @ExcelProperty(value = {"股票涨幅信息统计表","当前价格"},index= 3)
    private BigDecimal tradePrice;

    @ExcelProperty(value = {"股票涨幅信息统计表","涨跌"},index= 4)
    private BigDecimal increase;

    @ExcelProperty(value = {"股票涨幅信息统计表","涨幅"},index= 5)
    private BigDecimal upDown;

    @ExcelProperty(value = {"股票涨幅信息统计表","振幅"},index= 6)
    private BigDecimal amplitude;

    @ExcelProperty(value = {"股票涨幅信息统计表","交易总量"},index = 7)
    private Long tradeAmt;

    @ExcelProperty(value = {"股票涨幅信息统计表","交易总金额"},index = 8)
    private BigDecimal tradeVol;

    @ExcelProperty(value = {"股票涨幅信息统计表","日期"},index = 9)
    @DateTimeFormat("yyy-MM-dd HH:mm")//easyExcel的注解-》excel
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm")//springmvc支持的注解-》json格式数据
    private Date curDate;
}

详见:day03\资料\后端资料\easyExcel修饰\StockUpdownDomain.java

2、涨幅信息数据导出功能实现

2.1 定义web访问方法

    @GetMapping("/stock/export")
    public void exportPageStockInfos(
            @RequestParam(value = "page", required = false, defaultValue = "1") Integer page,
            @RequestParam(value = "pageSize", required = false, defaultValue = "20") Integer pageSize,
            HttpServletResponse response) {
        stockService.exportPageStockInfos(page,pageSize,response);
    }

2.2 定义服务接口及实现

接口定义:

   /**
     * 导致指定页码的股票涨幅数据到excel
     * @param page
     * @param pageSize
     * @param response
     */
    void exportPageStockInfos(Integer page, Integer pageSize, HttpServletResponse response);

接口实现:

    /**
     * 将指定页的股票数据导出到excel表下
     * @param response
     * @param page  当前页
     * @param pageSize 每页大小
     */
@Override
    public void exportPageStockInfos(Integer page, Integer pageSize, HttpServletResponse response) {
        //1.获取分页数据
        Date lastDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //TODO 伪造数据,后续删除
        lastDate=DateTime.parse("2022-07-07 14:43:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        PageHelper.startPage(page,pageSize);
        List<StockUpdownDomain> infos=stockRtInfoMapper.getNewestStockInfo(lastDate);
        response.setCharacterEncoding("utf-8");
        try {
            //2.判断分页数据是否为空,为空则响应json格式的提示信息
            if (CollectionUtils.isEmpty(infos)) {
                R<Object> error = R.error(ResponseCode.NO_RESPONSE_DATA);
                //将error转化成json格式字符串
                String jsonData = new ObjectMapper().writeValueAsString(error);
                //设置响应的数据格式 告知浏览器传入的数据格式
                response.setContentType("application/json");
                //设置编码格式
                //            response.setCharacterEncoding("utf-8");
                //响应数据
                response.getWriter().write(jsonData);
                return;
            }
            //3.调动EasyExcel数据导出
            // 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
            response.setContentType("application/vnd.ms-excel");
//        response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String fileName = URLEncoder.encode("股票涨幅数据表格", "UTF-8");
            //指定excel导出时默认的文件名称,说白了就是告诉浏览器下载文件时默认的名称为:股票涨幅数据表格
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
            EasyExcel.write(response.getOutputStream(), StockUpdownDomain.class).sheet("股票涨幅信息").doWrite(infos);
        } catch (Exception e) {
            log.error("导出时间:{},当初页码:{},导出数据量:{},发生异常信息:{}",lastDate,page,pageSize,e.getMessage());
        }

    }

2.3 访问测试效果

测试方式:

  • 通过浏览器直接访问http://localhost/aip/quot/stock/export?page=1&pageSize=20,可直接获取stockRt.xlsx文件
  • 通过前端点击按钮获取,则会获取其它名称的文件,因为前端对文件进行了重命名操作;

最终效果:

在这里插入图片描述

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

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

相关文章

【C++关键字】auto以及指针空值nullpr

&#x1f4d9; 作者简介 &#xff1a;RO-BERRY &#x1f4d7; 学习方向&#xff1a;致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f4d2; 日后方向 : 偏向于CPP开发以及大数据方向&#xff0c;欢迎各位关注&#xff0c;谢谢各位的支持 目录 前言1.类型别名思考2…

SQL110 插入记录(一)(插入和interval关键字的用法)

代码 insert into exam_record(uid,exam_id,start_time,submit_time,score) values(1001,9001,2021-09-01 22:11:12,2021-09-01 22:11:12interval 50 minute,90), (1002,9002,2021-09-04 07:01:02,null,null)知识点 interval关键字的用法 INTERVAL关键字一般使用格式为&#x…

牛客网 HJ76 尼克彻斯定理

题目&#xff1a; 思路&#xff1a; 主要是要找规律&#xff0c;即m^3&#xff08;m*m-m1j&#xff09;……&#xff0c;j从0每次递增2 然后就是注意输出格式 答案&#xff1a; #include <stdio.h> int main() {int m0; again:scanf("%d",&m);if(m<…

基于Springboot+Vue的在线考试系统源码

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 随着现代教育和职业培…

实习日志15

1.大改了一下界面 1.1.识别与验真 1.2.历史记录 2.改了几个bug 2.1.改json格式用JSON.stringify(value,null,2); 2.2.内嵌页面值与原页面值重复 2.3.验真条件判断 if (isVerifyCell.getValue() "不需要") {if (verifyResultCell.getValue() ! "未查验")…

ChromeDriver | 谷歌浏览器驱动下载地址 及 浏览器版本禁止更新

在使用selenoum时&#xff0c;需要chrome浏览器的版本和chrome浏览器驱动的版本一致匹配&#xff0c;才能进行自动化测试 一、ChromeDriver驱动镜像网址 国内可以搜到的谷歌浏览器下载地址里面最新的驱动器只有114版本的CNPM Binaries Mirror 在其他博主那找到了最新版本12X的…

Unity3d Mesh篇(一)— 创建简单三角面

文章目录 前言一、Mesh组成二、使用步骤三、效果四、总结 前言 Mesh&#xff08;网格&#xff09;是一种常用的3D图形表示方法&#xff0c;它由顶点&#xff0c;法线&#xff0c;UV 坐标&#xff0c;和三角形等组成。您可以使用 Mesh 类的方法来创建或修改网格&#xff0c;也可…

山西电力市场日前价格预测【2024-02-20】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2024-02-20&#xff09;山西电力市场全天平均日前电价为354.58元/MWh。其中&#xff0c;最高日前电价为579.21元/MWh&#xff0c;预计出现在18:30。最低日前电价为247.23元/MWh&#xff0c;预计…

金蝶云星空协同平台导出单据类型

文章目录 金蝶云星空协同平台导出单据类型需求具体操作 金蝶云星空协同平台导出单据类型 需求 导出A账套的其他出库单的单据类型 具体操作 然后可以再你要同步的数据中心打开应用执行脚本&#xff1a;

[] == ! [] 为什么返回 true ?

1. Undefined 、Null、0 比较 null null; // true null undefined; // true 0 -0; // true null 0; // false undefined 0; // false2. NaN 比较 NaN NaN; // false NaN与任何值比较都返回false(包括NaN)3. 字符串 与 数字…

二叉搜索树题目:修剪二叉搜索树

文章目录 题目标题和出处难度题目描述要求示例数据范围 解法一思路和算法代码复杂度分析 解法二思路和算法代码复杂度分析 题目 标题和出处 标题&#xff1a;修剪二叉搜索树 出处&#xff1a;669. 修剪二叉搜索树 难度 3 级 题目描述 要求 给定二叉搜索树的根结点 roo…

SQL-Labs靶场“1-5”关通关教程

君衍. 一、准备工作二、第一关 基于GET单引号字符型注入1、源码分析2、联合查询注入过程 三、第二关 基于GET整型注入1、源码分析2、联合查询注入过程 四、第三关 基于GET单引号变形注入1、源码分析2、联合查询注入过程 五、第四关 基于GET双引号字符型注入1、源码分析2、联合查…

leetcode:416.分割等和子集

解题思路&#xff1a; 转化为01背包问题&#xff0c;集合中每个元素只能用一次&#xff0c;看能不能凑出sum//2这个重量。&#xff08;重量值价值值&#xff09; dp含义&#xff1a;前重量j所获得的最大价值 递推公式&#xff1a;dp[j] max(dp[j],dp[j-numbers[i]] number…

AI嵌入式K210项目(29)-模型加载

文章目录 前言一、下载部署包二、C部署三、搭建文件传输环境四、文件传输五、调试六、MicroPython部署总结 前言 上一章节介绍了如何进行在线模型训练&#xff0c;生成部署包后&#xff0c;本章介绍加载模型&#xff1b; 一、下载部署包 训练结束后&#xff0c;在训练任务条…

幻兽帕鲁 0基础小白如何快速部署服务器

看了许多关于如何部署服务器的&#xff0c;大部分都是要买阿里云或者腾讯云的服务器并且至少四核以上才能保证流畅运行。 但是对于想搭建私服但又没有技术的小白&#xff0c;确实是有点难度了。购买云服务器后还要配置服务器&#xff0c;配置OpenVPN、PalServer&#xff0c;doc…

虚拟机centos7 网络IP冲突

修改其中一个虚拟机IP 1&#xff1a; 设置虚拟机网络配置器的模式为NAT模式&#xff0c;操作方式如下图所示 2&#xff1a;点击虚拟网络编辑器 3&#xff1a;点击NAT设置 4&#xff1a;点击DHCP配置 5&#xff1a; 修改配置文件来指定IP并可以连接到外网&#xff0c;在roo…

基于docker安装HDFS

1.docker一键安装见 docker一键安装 2.拉取镜像 sudo docker pull kiwenlau/hadoop:1.03.下载启动脚本 git clone https://github.com/kiwenlau/hadoop-cluster-docker4.创建网桥 由于 Hadoop 的 master 节点需要与 slave 节点通信&#xff0c;需要在各个主机节点配置节点…

前端技巧之svg精灵图svg-sprite-loader

首先说明精灵图的必要性&#xff0c;其可以让我们只需要向服务器请求一次图片资源&#xff0c;就能加载很多图片&#xff0c;即能够减轻http请求造成的服务器压力。 然后这里要说明的是这个插件是webpack上面的&#xff0c;所以在vue2中比较好用&#xff0c;如果在vue3中&…

RabbitMQ的安装与使用

RabbitMQ的安装与使用 介绍一、RabbitMQ的安装1 查找镜像2 拉取镜像3 查看镜像4 创建容器5 查看容器6 访问测试 二、RabbitMQ的使用1 创建项目2 配置文件3 队列配置文件4 消费者5 生产者6 测试 三、交换器四、普通队列Demo五、死信队列Demo1 介绍2 示例2.1 配置2.2 生产者2.3 消…

Linux下多核CPU指定程序运行的核

设置程序在指定CPU核心运行 一、如何查看程序运行的CPU信息 1.1 查看当前系统CPU有几个核心 查看CPU核心数量&#xff1a;lscpu 1.2 查看程序的PID ps aux|grep cpu_test1.3 查看程序可运行的CPU taskset -c -p pid1.4 设置程序在指定核心上运行 1.4.1 通过运行时的参数设…