Jxls 实现动态导出功能

目录

  • 引言
  • 前端页面
  • 后端代码
  • excel模板
  • 导出效果

引言

在实际做项目的过程中,导出报表时需要根据每个人所关注的点不一样,所需导出的字段也不一样,这时后端就需要根据每个所选的字段去相应的报表,这就是本文要讲的动态导出报表。

前端页面

  1. 用户在页面上选择要导出的字段,后端根据所选的字段进行导出
    在这里插入图片描述
  2. 将要导出的所有字段做成字典进行管理方便后端进行转换,具体思路请看后端代码
    在这里插入图片描述
    在这里插入图片描述

后端代码

  1. 请求参数实体 OutOrderParam.java
package com.hw.admin.domain.outer.vo;import com.alibaba.fastjson.JSONObject;
import lombok.Data;import java.util.Date;
import java.util.List;/**1. @Description2. @Author liqinglong3. @DateTime 2022-03-30 19:054. @Version 1.0*/
@Data
public class OutOrderParam {/** 搜索关键字 */private String searchValue;/** 出库单状态 */private Integer status;/** 创建日期 */private Date createDate;/** 扫描条码 */private String scanBarcode;/** 导出字段 */private JSONObject fields;private Integer pageSize;private Integer startIndex;private List<String> exportFields;
}
  1. controller方法
 /*** 出库单导出** @param response* @param request*/@Log(title = "出库单导出", businessType = BusinessType.EXPORT)@GetMapping("exportOutOrderXls")public void downStockExcel(HttpServletResponse response,HttpServletRequest request,OutOrderParam param) throws IOException, NoSuchFieldException, IllegalAccessException {String fileFullName = airOutOrderService.exportOutOrderXls(param);String fileName = fileFullName.split("\\|")[1];FileUtils.downloadFile(fileFullName.split("\\|")[0], fileName, response, request);}
  1. 服务层方法
    接口 IOutOrderService.java
/*** 出库单服务接口* @author liql* @date 2022-03-30 16:29:15*/
public interface IOutOrderService extends IBaseService<OutOrder>  {/*** @Description 服务层导出出库单方法* @param param* @return java.lang.String*/
String exportOutOrderXls(OutOrderParam param) throws NoSuchFieldException, IllegalAccessException;
}

实现类 OutOrderServiceImpl.java

Slf4j
@Service
public class OutOrderServiceImpl extends IBaseServiceImpl<OutOrderMapper, AirOutOrder> implements IOutOrderService {@Overridepublic String exportOutOrderXls(OutOrderParam param) throws NoSuchFieldException, IllegalAccessException {log.info("开始执行导出出库单,返回参数:{}",param);//1、获取参数-导出数据限制条数SysConfig config = new SysConfig();config.setConfigKey("export.excel.count");SysConfig retConfig = configMapper.selectConfig(config);int exportCount = Integer.parseInt(retConfig.getConfigValue());//2、获取导出记录总条数int total = mapper.countOutTotal(param);//3、导出的总条数不能超过限制的总条数total = total > exportCount ? exportCount : total;//4、获取选取的字段,默认导出所有字段List<String> fieldsList = param.getExportFields();//获取字典字段列表List<SysDictData> outFieldList = sysDictTypeService.selectDictDataByType("out_field_list");JSONObject paramObject = new JSONObject();//表头List<String> headerList = new ArrayList();if(ObjectUtils.isEmpty(fieldsList)){fieldsList = new ArrayList<>();for (SysDictData dicData:outFieldList) {paramObject.put(dicData.getDictValue(),1);headerList.add(dicData.getDictLabel());fieldsList.add(dicData.getDictValue());}}else{for (String field: fieldsList) {paramObject.put(field,1);for (SysDictData dicData:outFieldList) {if(field.equals(dicData.getDictValue())){headerList.add(dicData.getDictLabel());break;}}}}param.setFields(paramObject);//5、获取数据字典转换字段//出库状态Map<String,String> statusDictMap = new HashMap();List<SysDictData> statusDictDatas = sysDictTypeService.selectDictDataByType("outbound_status");for(SysDictData dictData : statusDictDatas){statusDictMap.put(dictData.getDictValue(),dictData.getDictLabel());}//出库类型Map<String,String> outTypeMap = new HashMap();List<SysDictData> outTypeDatas = sysDictTypeService.selectDictDataByType("outbound_type");for(SysDictData dictData : outTypeDatas){outTypeMap.put(dictData.getDictValue(),dictData.getDictLabel());}//6、计算分页查询次数//每次查询条数int pageSize = 1000;int totalPage = (total / pageSize) + (total % pageSize > 0 ? 1 : 0);//7、循环查询数据//excel表实际上是一个二维表List<List<Object>> lastResult = new ArrayList<>();param.setPageSize(pageSize);for(int i = 0;i < totalPage;i++){param.setStartIndex(i * pageSize);List<ExportOutOrderVo> outOrderList = mapper.queryExportOutOrderList(param);for(ExportOutOrderVo orderVo:outOrderList){// 出库类型转化为中文orderVo.setOutTypeStr(outTypeMap.get(String.valueOf(orderVo.getOutType())));// 出库状态转化为中文orderVo.setStatusStr(statusDictMap.get(String.valueOf(orderVo.getStatus())));//excel中的一行数据List<Object> rowList = new ArrayList<>();for (String header:fieldsList){Field field = orderVo.getClass().getDeclaredField(header);field.setAccessible(true);if("tabId".equals(header)){//将长整型转化为字符串rowList.add(String.valueOf(field.get(orderVo)));}else if("outTime".equals(header)){//将出库时间格式化Date outTime = (Date) field.get(orderVo);if(ObjectUtils.isEmpty(field.get(orderVo))){rowList.add(field.get(orderVo));}else{rowList.add(DateUtils.formatDate(outTime,"yyyy-MM-dd HH:mm:ss"));}}else{rowList.add(field.get(orderVo));}}lastResult.add(rowList);}}//8、生成exelMap<String, Object> model = new HashMap<>();model.put("cols",headerList);model.put("orders", lastResult);String xlsName = "出库单_"+ DateUtils.formatDate(new Date(),"yyyyMMddHHmmss") + ".xlsx";String filePath = "";String geneXlsName = "";try {String orderFileNameTemp = "exportOutOrder.xlsx";try {filePath = new File(ResourceUtils.getURL("classpath:").getPath()).getParentFile().getParentFile().getParent();filePath += File.separator + "report_file" + File.separator;} catch (FileNotFoundException e) {log.error("执行导出出库单,系统异常:" + e);e.printStackTrace();}File exportFilePath = new File(filePath);if (exportFilePath.exists() == false) {exportFilePath.mkdirs();}geneXlsName = filePath + xlsName;JxlsUtils.geneExcel(orderFileNameTemp, geneXlsName, model);} catch (IOException e) {e.printStackTrace();}log.info("结束执行导出出库单,返回参数:" + geneXlsName);return geneXlsName + "|" + xlsName;}}

mapper OrderInfoSpeMapper.java

public interface OrderInfoSpeMapper extends BaseMapper<OrderInfo> {/*** 查询订单导出列表** @param queryVo 订单查询信息* @return 订单导出列表*/List<OrderExportResultVo> selectOrderListExport(OrderQueryVo queryVo);}

xml OrderInfoSpeMapper.xml

  <resultMap type="com.hw.admin.domain.order.vo.OrderExportResultVo" id="OrderExportResult"></resultMap><!-- 查询订单导出列表 --><select id="selectOrderListExport" parameterType="com.hw.admin.domain.order.vo.OrderQueryVo" resultMap="OrderExportResult">SELECTo.id,o.cust_name,o.order_status,o.order_type,o.create_time,o.oper_name,b.address,d.logistics_no,e.id_number,e.contact_phone,f.mat_code,f.goods_name,f.unit_name,sum(f.sale_volume) sale_volume,sum(f.sale_amount) sale_amountFROMair_order_info oLEFT JOIN air_out_order d ON d.tab_id = o.idleft join air_order_receive b on b.order_id = o.idleft join air_customer e on e.id = o.cust_idleft join air_order_goods f on f.order_id = o.id<where>o.del_flag = 0and o.source_type = 0AND o.order_type in (0,1)<if test="searchValue != null and searchValue != ''">AND (o.order_name like concat('%', #{searchValue}, '%')OR o.cust_name like concat('%', #{searchValue}, '%'))</if><if test="beginTime != null and beginTime != ''">AND o.create_time >= STR_TO_DATE(#{beginTime}, '%Y-%m-%d %H:%i:%s')</if><if test="endTime != null and endTime != ''">AND o.create_time &lt;= STR_TO_DATE(#{endTime}, '%Y-%m-%d %H:%i:%s')</if><if test="bottleCode != null and bottleCode != ''">AND exists (select 1from air_out_order_detail e,air_out_good_record fwhere e.order_id = d.idand f.order_detail_id = e.idAND (f.scan_bottlecode like concat('%', #{bottleCode}, '%') OR f.scan_barcode like concat('%', #{bottleCode}, '%')))</if></where>group byo.id,o.cust_name,o.order_status,o.order_type,o.create_time,o.oper_name,b.address,d.logistics_no,e.id_number,e.contact_phone,f.mat_code,f.goods_name,f.unit_nameorder by o.id desc<if test="indexPage != null">LIMIT #{indexPage}, #{sizePage}</if></select>

vo ExportOutOrderVo.java

package com.hw.admin.domain.order.vo;import com.fasterxml.jackson.annotation.JsonFormat;
import com.hw.common.annotation.SensitiveEntity;
import com.hw.common.annotation.SensitiveField;
import lombok.Data;import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;/*** 功能描述: 导出结果信息** @author: liqinglong* @date: 2023/10/9* */
@Data
public class OrderExportResultVo implements Serializable {private static final long serialVersionUID = 1L;/*** 订单id*/private Long id;/*** 订单id*/private String idDesc;/*** 客户名称*/private String custName;/*** 订单状态: 0-审核中 1-待付款 2-待发货 3-待收货 4-已完成 5-售后 6-已关闭 7-酒业出库 8-物流出库*/private Integer orderStatus;/*** 订单状态: 0-审核中 1-待付款 2-待发货 3-待收货 4-已完成 5-售后 6-已关闭 7-出库 8-物流出库*/private String orderStatusDesc;/*** 订单类型 0-普通 1-换货销售*/private Integer orderType;/*** 订单类型 0-普通 1-换货销售*/private String orderTypeDesc;/*** 创建时间*/@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private Date createTime;/*** 创建时间*/private String createTimeDesc;/*** 操作员姓名*/private String operName;/*** 收货地址*/private String address;/*** 运单号*/private String logisticsNo;/*** 身份证号码*/@SensitiveFieldprivate String idNumber;/*** 联系人电话*/@SensitiveFieldprivate String contactPhone;/*** 物料编码*/private String matCode;/*** 商品名称,多个商品名称合并,如飞天茅台等产品*/private String goodsName;/*** 商品单位*/private String unitName;/*** 商品销售数量*/private Long saleVolume;/*** 销售金额*/private BigDecimal saleAmount;/*** 扫描物流条码*/private String scanBarcode;/*** 扫描物流瓶码*/private String scanBottlecode;
}

excel模板

在这里插入图片描述
A1的注解

jx:area(lastCell="A3") //区域范围
jx:mergeCells(cols="cols.size()" lastCell="A1") //标题合并居中

A2的注解

jx:grid(lastCell="A3" headers="cols" data="orders"  areas=["A2:A2,"A3:A3"])

在这里插入图片描述
注意:headers 设置为代码中的key :“cols”, data 设置为代码中的key:“orders”

导出效果

在这里插入图片描述
测试数据,仅供参考

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

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

相关文章

S/MIME电子邮件证书申请指南

近年来&#xff0c;邮件安全问题日益突出&#xff0c;电子邮件成为诈骗、勒索软件攻击的重灾区。恶意邮件的占比屡创新高&#xff0c;邮件泄密事件更是比比皆是。在如此严峻的网络安全形势下&#xff0c;使用S/MIME电子邮件证书进行邮件收发是当今最佳的邮件安全解决方案之一。…

生产消费者模型

生产消费者模型概念 生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯&#xff0c;而 通过阻塞队列来进行通讯&#xff0c;所以生产者生产完数据之后不用等待消费者处理&#xff0c;直接扔给阻塞队列&#xff0c;消费者不…

pygame学习(三)——支持多种类型的事件

大家好&#xff01;我是码银&#x1f970; 欢迎关注&#x1f970;&#xff1a; CSDN&#xff1a;码银 公众号&#xff1a;码银学编程 实时事件循环 为了保证程序的持续刷新、保持打开的状态&#xff0c;我们会创建一个无限循环&#xff0c;通常使用的是while语句&#xff0c;w…

Apache POI 导出Excel报表

大家好我是苏麟 , 今天聊聊Apache POI . Apache POI 介绍 Apache POI 是一个处理Miscrosoft Office各种文件格式的开源项目。简单来说就是&#xff0c;我们可以使用 POI 在 Java 程序中对Miscrosoft Office各种文件进行读写操作。 一般情况下&#xff0c;POI 都是用于操作 E…

实时云渲染服务:流式传输 VR 和 AR 内容

想象一下无需专用的物理计算机&#xff0c;甚至无需实物连接&#xff0c;就能获得高质量的 AR/VR 体验是种什么样的体验&#xff1f; 过去&#xff0c;与 VR 交互需要专用的高端工作站&#xff0c;并且根据头显、壁挂式传感器和专用的物理空间。VR 中的复杂任务会突破传感器范…

路由器初始化配置、功能配置

实验环境 拓扑图 Ip规划表&#xff08;各组使用自己的IP规划表&#xff09; 部门 主机数量 网络地址 子网掩码 网关 可用ip Vlan 市场部 38 192.168.131.0 255.255.255.0 192.168.131.1 2-254 11 研发部 53 192.168.132.0 255.255.255.0 192.168.132.1 2-2…

appium之联动pycharm

前置条件&#xff1a; 1.java环境安装好了 2.android-sdk安装好&#xff08;uiautomatorviewer 也可以把这个启动起来&#xff09; 3.appium安装好 4.adb devices查看下设备是否连接 pycharm入门代码--固定写法 from appium import webdriver# 定义字典变量 desired_caps …

【机器学习300问】9、梯度下降是用来干嘛的?

当你和我一样对自己问出这个问题后&#xff0c;分析一下&#xff01;其实我首先得知道梯度下降是什么&#xff0c;也就它的定义。其次我得了解它具体用在什么地方&#xff0c;也就是使用场景。最后才是这个问题&#xff0c;梯度下降有什么用&#xff1f;怎么用&#xff1f; 所以…

QT 原生布局和QML的区别

一、QML 与 Qt Quick的区别 1.1 从概念上区分 为了更精确地对两者进行说明&#xff0c;先看助手对 QML 的描述&#xff1a; QML is a user interface specification and programming language. QML 是一种用户界面规范和标记语言&#xff0c;允许开发人员和设计师创建高性能、流…

[go语言]输入输出

目录 知识结构 输入 1.Scan ​编辑 2.Scanf 3.Scanln 4.os.Stdin --标准输入&#xff0c;从键盘输入 输出 1.Print 2.Printf 3.Println 知识结构 输入 为了展示集中输入的区别&#xff0c;将直接进行代码演示。 三者区别的结论&#xff1a;Scanf格式化输入&#x…

Django项目中的默认文件都有什么用

manager.py&#xff1a; 是django用于管理本项目的命令行工具&#xff0c;之后进行站点运行&#xff0c;数据库自动生成等都是通过本文件完成。 djangoStudy/__init__.py&#xff1a; 告诉python该目录是一个python包&#xff0c;暂无内容&#xff0c;后期一些工具的初始化可…

从零开始的源码搭建:详解连锁餐饮行业中的点餐小程序开发

时下&#xff0c;点餐小程序成为了许多餐饮企业引入的一种创新工具&#xff0c;不仅方便了顾客的用餐体验&#xff0c;同时也提高了餐厅的运营效率。本文将详细探讨如何从零开始搭建一个源码&#xff0c;并深入解析连锁餐饮行业中的点餐小程序开发过程。 一、需求分析与规划 在…