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. @Description
 2. @Author liqinglong
 3. @DateTime 2022-03-30 19:05
 4. @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 {
 @Override
    public 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、生成exel
        Map<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">
        SELECT
        o.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_amount
        FROM
        air_order_info o
        LEFT JOIN air_out_order d ON d.tab_id = o.id
        left join air_order_receive b on b.order_id = o.id
        left join air_customer e on e.id = o.cust_id
        left join air_order_goods f on f.order_id = o.id
        <where>
            o.del_flag = 0
            and o.source_type = 0
            AND 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 1
                from air_out_order_detail e,air_out_good_record f
                where e.order_id = d.id
                and f.order_detail_id = e.id
                AND (f.scan_bottlecode like concat('%', #{bottleCode}, '%') OR f.scan_barcode like concat('%', #{bottleCode}, '%')))
            </if>
        </where>
        group by
        o.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
        order 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;
    /**
     * 身份证号码
     */
    @SensitiveField
    private String idNumber;
    /**
     * 联系人电话
     */
    @SensitiveField
    private 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”

导出效果

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

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

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

相关文章

Vue Mixin 代码重用与逻辑共享

✨ 专栏介绍 在当今Web开发领域中&#xff0c;构建交互性强、可复用且易于维护的用户界面是至关重要的。而Vue.js作为一款现代化且流行的JavaScript框架&#xff0c;正是为了满足这些需求而诞生。它采用了MVVM架构模式&#xff0c;并通过数据驱动和组件化的方式&#xff0c;使…

海外云手机:跨境养号的新趋势

近年来&#xff0c;市场综合数据显示&#xff0c;利用海外云手机进行跨境养号已经成为跨境电商发展的新潮流。特别是在社交电商营销和短视频引流领域&#xff0c;海外云手机不仅能够提高流量的质量&#xff0c;还能让商家实现业务翻倍增长。接下来&#xff0c;本文将简要阐述海…

软件测试|使用matplotlib绘制气泡图

简介 气泡图&#xff08;Bubble Chart&#xff09;是一种数据可视化工具&#xff0c;通常用于展示三维数据的分布情况&#xff0c;其中数据点以气泡的形式显示在二维平面上&#xff0c;每个气泡的位置表示两个变量的值&#xff0c;气泡的大小表示第三个变量的值。在Python中&a…

Java21 + SpringBoot3集成Spring Data JPA

Java21 SpringBoot3集成Spring Data JPA 文章目录 Java21 SpringBoot3集成Spring Data JPA前言相关技术简介ORM&#xff08;Object-Relational Mapping&#xff0c;对象-关系映射&#xff09;JPA&#xff08;Java Persistence API&#xff0c;Java持久层API&#xff09;Hiber…

复现PointNet++(语义分割网络):Windows + PyTorch + S3DIS语义分割 + 代码

一、平台 Windows 10 GPU RTX 3090 CUDA 11.1 cudnn 8.9.6 Python 3.9 Torch 1.9.1 cu111 所用的原始代码&#xff1a;https://github.com/yanx27/Pointnet_Pointnet2_pytorch 二、数据 Stanford3dDataset_v1.2_Aligned_Version 三、代码 分享给有需要的人&#xf…

2.6、云负载均衡产品详述

一、定义 弹性负载均衡(Elastic Load Balance&#xff0c;简称ELB)可将来自公网的访问流量分发到后端云主机&#xff0c;可选多种负载均衡策略&#xff0c;并支持自动检测云主机健康状况&#xff0c;消除单点故障&#xff0c;保障应用系统的高可用。 二、产品架构 1&am…

GEE:随机森林分类器投票方法的优化与修改

作者:CSDN @ _养乐多_ 在随机森林中,每棵决策树都对输入数据进行分类或回归,并产生一个输出。对于分类问题,这个输出通常是一个类别标签,而对于回归问题,输出通常是一个连续的数值。在分类问题中,每棵决策树会为每个样本投票,然后采用众数来确定最终的类别。例如,如果…

P3952 [NOIP2017 提高组] 时间复杂度————C++

目录 [NOIP2017 提高组] 时间复杂度题目背景题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示 解题思路Code运行结果 [NOIP2017 提高组] 时间复杂度 题目背景 NOIP2017 提高组 D1T2 题目描述 小明正在学习一种新的编程语言 A&#xff0c;刚学会循环语句的他激动…

ilqr 算法说明

1 Introduction 希望能用比较简单的方式将ilqr算法进行整理和总结。 2 HJB方程 假定我们现在需要完成一个从A点到B点的任务&#xff0c;执行这段任务的时候&#xff0c;每一步都需要消耗能量&#xff0c;可以用下面这个图表示。 我们在执行这个A点到B点的任务的时候&#xf…

项目架构之Zabbix部署

1 项目架构 1.1 项目架构的组成 业务架构&#xff1a;客户端 → 防火墙 → 负载均衡&#xff08;四层、七层&#xff09; → web缓存/应用 → 业务逻辑&#xff08;动态应用&#xff09; → 数据缓存 → 数据持久层 运维架构&#xff1a;运维客户端 → 跳板机/堡垒机&#x…

2023年第十四届蓝桥杯软件赛省赛总评

报名明年4月蓝桥杯软件赛的同学们&#xff0c;如果你是大一零基础&#xff0c;目前懵懂中&#xff0c;不知该怎么办&#xff0c;可以看看本博客系列&#xff1a;备赛20周合集 20周的完整安排请点击&#xff1a;20周计划 每周发1个博客&#xff0c;共20周。 在QQ群上交流答疑&am…

VUE工程化--vue组件注册

组件注册的两种方式&#xff1a; 1. 局部注册&#xff1a;只能在注册的组件内使用 2. 全局注册&#xff1a;所有组件内都能使用 局部注册步骤&#xff1a; 1、导入 import MyHeader from "./components/myHeader.vue"; import MyMain from "./components/myMa…

TCP连接TIME_WAIT

TCP断开过程: TIME_WAIT的作用: TIME_WAIT状态存在的理由&#xff1a; 1&#xff09;可靠地实现TCP全双工连接的终止 在进行关闭连接四次挥手协议时&#xff0c;最后的ACK是由主动关闭端发出的&#xff0c;如果这个最终的ACK丢失&#xff0c;服务器将重发最终的FIN&#xf…

LLM漫谈(三)| 使用Chainlit和LangChain构建文档问答的LLM应用程序

一、Chainlit介绍 Chainlit是一个开源Python包&#xff0c;旨在彻底改变构建和共享语言模型&#xff08;LM&#xff09;应用程序的方式。Chainlit可以创建用户界面&#xff08;UI&#xff09;&#xff0c;类似于由OpenAI开发的ChatGPT用户界面&#xff0c;Chainlit可以开发类似…

虚拟机CentOS7.5编译安装Qt4.8.7

虚拟机CentOS7.5编译安装Qt4.8.7 一.下载Qt二.安装步骤 一.下载Qt 官网下载链接&#xff1a;Qt4.8.7 官网下载速度可能会非常慢&#xff0c;本人已上传至CSDN&#xff0c;点此下载&#xff0c;下载后需要先用7z软件解压成zip包。 二.安装步骤 环境安装 yum install libX11…

go语言(三)----函数

1、函数单变量返回 package mainimport "fmt"func fool(a string,b int) int {fmt.Println("a ",a)fmt.Println("b ",b)c : 100return c}func main() {c : fool("abc",555)fmt.Println("c ",c)}2、函数多变量返回 pack…

Nsis打包Unity Exe文件(通用)

Nsi 脚本 !include "MUI2.nsh"#使用现代UI Unicode true #使用Unicode !define EXENAME "exeName" #定义常量 exe名称 !define SHORTCUT "快捷方式名称" #定义桌面快捷方式的中文名称Name ${EXENAME} #安装程序的title OutFile "${EXENAME…

【C++】入门C++前想要了解的小知识

个人主页 &#xff1a; zxctsclrjjjcph 文章封面来自&#xff1a;艺术家–贤海林 如有转载请先通知 目录 1. 前言2. 什么是C3. C的发展史4. C的重要性4.1 语言的使用广泛度4.2 在工作领域中4.3 在校招领域中 5. 如何学习C5.1 看看别人怎么学习的5.2 自己怎么学 1. 前言 今天开…

FFmpeg之SwrRessample

文章目录 一、概述二、重采样流程三、重要结构体3.1、SwrContext3.2、ResamplerContext 四、重要函数4.1、swr_alloc4.2、swr_alloc_set_opts4.3、av_opt_set_*4.4、swr_init4.5、av_samples_alloc_array_and_samples4.6、av_samples_alloc4.7、swr_convert4.8、swr_get_delay4…

uniapp微信小程序投票系统实战 (SpringBoot2+vue3.2+element plus ) -投票帖子排行实现

锋哥原创的uniapp微信小程序投票系统实战&#xff1a; uniapp微信小程序投票系统实战课程 (SpringBoot2vue3.2element plus ) ( 火爆连载更新中... )_哔哩哔哩_bilibiliuniapp微信小程序投票系统实战课程 (SpringBoot2vue3.2element plus ) ( 火爆连载更新中... )共计21条视频…