day03-股票数据报表与导出

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*/@Overridepublic R<PageResult> getStockPageInfo(Integer page, Integer pageSize) {//1.设置PageHelper分页参数PageHelper.startPage(page,pageSize);//2.获取当前最新的股票交易时间点Date curDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();//todocurDate= 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">selectsri.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 tradePricefrom stock_rt_info as   sriwhere 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();

接口实现

    @Overridepublic 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时间分组,统计出每分钟对应的数量,而这个数量就是涨停的数量
selecttmp.time,count(*) as count
from () as tmp
group by tmp.time;
# 填充sql
selecttmp.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;# 跌停
selectdate_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*/@Overridepublic R<Map> getStockUpdownCount() {//1.获取最新的交易时间范围 openTime  curTime//1.1 获取最新股票交易时间点DateTime curDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());Date curTime = curDateTime.toDate();//TODOcurTime= 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();//TODOopenTime= 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">selectdate_format(tmp.time,'%Y%m%d%H%i') as time ,count(*) as countfrom (select(sri.cur_price-sri.pre_close_price)/sri.pre_close_price as ud,sri.cur_time as timefrom stock_rt_info sriwhere 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 tmpgroup by tmp.timeorder 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;}/*** 直接导出后,表头名称默认是实体类中的属性名称*/@Testpublic 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)@ExcelIgnoreprivate 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)@ExcelIgnoreprivate 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数据格式必须与实体类定义一致,否则数据读取不到*/@Testpublic void readExcel(){ArrayList<User> users = new ArrayList<>();//读取数据EasyExcel.read("C:\\Users\\46035\\Desktop\\ex\\用户.xls", User.class, new AnalysisEventListener<User>() {@Overridepublic void invoke(User o, AnalysisContext analysisContext) {System.out.println(o);users.add(o);}@Overridepublic 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 每页大小*/
@Overridepublic 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 会导致各种问题,请直接用浏览器或者用postmanresponse.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.mzph.cn/news/689440.shtml

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

相关文章

【spring】@Transactional 注解失效的原因及解决办法

文章目录 前言一、Transactional 属性介绍1.事务的传播行为&#xff1a;propagation2.事务的隔离级别&#xff1a;isolation3.事务的超时时间&#xff1a;timeout4.事务的回滚类型&#xff1a;rollbackFor 二、Transactional 失效场景1.同一个类中方法调用&#xff0c;注解失效…

Visual Studio+C#实现信道与信息率失真函数

1. 要求 设计一款信道与信息率失真函数计算系统&#xff0c;要求如下&#xff1a; 系统能够通过输入的转移概率矩阵计算对称以及非对称离散无记忆信道的信道容量系统能够通过输入的概率分布以及失真矩阵来计算与信息率失真函数有关的相关参数&#xff0c;例如Dmin&#xff0c…

分布式学习笔记

1. CAP理论 Consistency&#xff08;一致性&#xff09;&#xff1a;用户访问分布式系统中的任意节点&#xff0c;得到的数据必须一致。 Availability&#xff08;可用性&#xff09;&#xff1a;用户访问集群中的任意健康节点&#xff0c;必须得到相应&#xff0c;而不是超时…

vue3-渲染机制

渲染机制 Vue 是如何将一份模板转换为真实的 DOM 节点的&#xff0c;又是如何高效地更新这些节点的呢&#xff1f;我们接下来就将尝试通过深入研究 Vue 的内部渲染机制来解释这些问题。 虚拟 DOM 你可能已经听说过“虚拟 DOM”的概念了&#xff0c;Vue 的渲染系统正是基于这…

基于Java SSM框架实现精准扶贫管理系统项目【项目源码】计算机毕业设计

基于java的SSM框架实现精准扶贫管理系统演示 JSP技术介绍 JSP技术本身是一种脚本语言&#xff0c;但它的功能是十分强大的&#xff0c;因为它可以使用所有的JAVA类。当它与JavaBeans 类进行结合时&#xff0c;它可以使显示逻辑和内容分开&#xff0c;这就极大的方便了用户的需…

一文了解Web3.0真实社交先驱ERA

Web2时代&#xff0c;少数科技巨头垄断了全球近60亿人口的网络社交数据&#xff0c;并用之为自己牟利&#xff0c;用户无法掌控个人数据&#xff0c;打破该局面逐渐成为共识&#xff0c;于是&#xff0c;不少人看到了Web3社交赛道蕴含的巨大机遇&#xff0c;标榜着去中心化和抗…

【STM32】硬件SPI读写W25Q64芯片

目录 基础知识回顾&#xff1a; SPI外设简介 SPI框图 主模式全双工连续传输 非连续传输 初始化SPI外设 核心代码 - 交换一个字节 硬件接线图 Code 程序配置过程 MySPI.c MySPI.h W25Q64.c W25Q64.h W25Q64_Ins.h main.c 基础知识回顾&#xff1a; 【STM32】SP…

php实现讯飞星火大模型3.5

前期准备 vscode下载安装好 composer下载安装好 php环境安装好 &#xff08;以上可以自行网上查阅资料&#xff09; 开始实现 1.注册讯飞星火用户&#xff0c;获取token使用 讯飞星火认知大模型-AI大语言模型-星火大模型-科大讯飞 2.修改对应php文件中的key等 可以参考…

【精选】Java面向对象进阶——接口和抽象类的案例

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏 …

『运维备忘录』之 SSH 命令详解

运维人员不仅要熟悉操作系统、服务器、网络等知识&#xff0c;甚至对于开发相关的也要有所了解。很多运维工作者可能一时半会记不住那么多命令、代码、方法、原理或者用法等等。这里我将结合自身工作&#xff0c;持续给大家更新运维工作所需要接触到的知识点&#xff0c;希望大…

C++学习:list

1.list的定义和结构 list的使用频率不高&#xff0c;在做题时几乎遇不到需要使用list的情景。list是一种双向链表容器&#xff0c;它是标准模板库(STL)提供的一种序列容器。list容器以节点(node的形式存储元素&#xff0c;并使用指针将这些节点链接在一起&#xff0c;形成一个…

苹果电脑深度清理工具CleanMyMac X2025中文版

苹果电脑用户们&#xff0c;你们是否经常感到你们的Mac变得不再像刚拆封时那样迅速、流畅&#xff1f;可能是时候对你的苹果电脑进行一次深度清理了。在这个时刻&#xff0c;拥有一些高效的深度清理工具就显得尤为重要。今天&#xff0c;我将介绍几款优秀的苹果电脑深度清理工具…

java的泛型【详解】

定义类、接口、方法时&#xff0c;同时声明了一个或者多个类型变量&#xff08;如&#xff1a;<E>&#xff09; &#xff0c;称为泛型类、泛型接口&#xff0c;泛型方法、它们统称为泛型。 作用&#xff1a;泛型提供了在编译阶段约束所能操作的数据类型&#xff0c;并自…

【Python】【Pycharm】Python Script头文件设置

1、步骤&#xff1a;File->settings->Editor->File and CodeTemplates->Python Script 2、复制粘贴以下代码&#xff0c;应用即可&#xff1a; #!/usr/bin/env python # -*- coding: utf-8 -*-# Time :${DATE} ${TIME} # Author : admin # Site :${SITE} …

数据库应用:kylin 部署 达梦数据库DM8

目录 一、实验 1.环境 2.部署前规划 3.部署达梦数据库DM8 4.创建数据库及数据库事例管理 5.达梦数据库的基本操作 二、问题 1.xhost命令报错 2.执行安装程序DMInstall.bin 报错 3.解压安装程序报错 4.安装程序找不到文件 5.图像化界面打不开 6.安装内存太小 7.打开…

【HarmonyOS】【DevEco ohpm ERROR: NOTFOUND package “@ohos/hypium“如何解决

参考 &#xff1a;&#xff08;无效&#xff09; 华为开发者论坛 DevEco创建项目时的错误解决_6 月 优质更文活动_路北路陈_InfoQ写作社区 解决&#xff1a; HormonyOS-DevEco Studio新建空项目ERROR解决_oh_modules\ohos\hypium-CSDN博客 将 .ohpm文件夹中的hypium文件夹复…

【Node-RED】安全登陆时,账号密码设置

【Node-RED】安全登陆时&#xff0c;账号密码设置 前言实现步骤密码生成setting.js 文件修改 安全权限 前言 Node-RED 在初始下载完成时&#xff0c;登录是无账号密码的。基于安全性考虑&#xff0c;本期博文介绍在安全登陆时&#xff0c;如何进行账号密码设置。当然&#xff…

相机图像质量研究(35)常见问题总结:图像处理对成像的影响--运动噪声

系列文章目录 相机图像质量研究(1)Camera成像流程介绍 相机图像质量研究(2)ISP专用平台调优介绍 相机图像质量研究(3)图像质量测试介绍 相机图像质量研究(4)常见问题总结&#xff1a;光学结构对成像的影响--焦距 相机图像质量研究(5)常见问题总结&#xff1a;光学结构对成…

备战蓝桥杯 Day5

1191&#xff1a;流感传染 【题目描述】 有一批易感人群住在网格状的宿舍区内&#xff0c;宿舍区为n*n的矩阵&#xff0c;每个格点为一个房间&#xff0c;房间里可能住人&#xff0c;也可能空着。在第一天&#xff0c;有些房间里的人得了流感&#xff0c;以后每天&#xff0c;得…

【python】python入门之计算

“数字”&#xff1a; 介绍一下不同形式的数字们 字符串“6”数字6浮点数6.0 注意&#xff1a;输入时的内容自定义为字符串&#xff0c;需要用int&#xff08;&#xff09;进行强制转换 优先级&#xff1a; 常见优先级如下&#xff08;优先级指的是一个算式中先算的部分&…