Jxls 实现动态导出功能

news2024/11/27 18:52:28

目录

  • 引言
  • 前端页面
  • 后端代码
  • 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”

导出效果

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

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

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

相关文章

线程的使用

线程的创建方式 1、实现Runnable Runnable规定的方法是run()&#xff0c;无返回值&#xff0c;无法抛出异常 实现Callable 2、Callable规定的方法是call()&#xff0c;任务执行后有返回值&#xff0c;可以抛出异常 3、继承Thread类创建多线程 继承java.lang.Thread类&#xff0…

Docker registry镜像仓库,私有仓库及harbor管理详解

目录 registry镜像仓库概述 Docker 镜像仓库&#xff08;Docker Registry&#xff09;&#xff1a; registry 容器&#xff1a; 私有仓库概述 搭建本地私有仓库示例 Harbor概述 harbor架构 详解构成 Harbor由容器构成 Harbor部署示例 环境准备 部署Docker-Compose服…

uniapp中uview组件库的NoticeBar 滚动通知 使用方法

目录 #平台差异说明 #基本使用 #配置主题 #配置图标 #配置滚动速度 #控制滚动的开始和暂停 #事件回调 #API #Props #Events 该组件用于滚动通告场景&#xff0c;有多种模式可供选择 #平台差异说明 AppH5微信小程序支付宝小程序百度小程序头条小程序QQ小程序√√√√…

【不需要网络不需要显卡】本地部署GPT

【不需要网络/不需要显卡】本地部署GPT 大家好&#xff0c;我是老 J 我们都知道ChatGPT目前只有两种使用方式&#xff0c;一种是直接去官网访问&#xff0c;适合个人用户&#xff1b;另一种是API调用&#xff0c;适合企业或者网站使用。这两种方式的门槛都比较高&#xff0c;…

10个用于Android开发的有用的Kotlin库及示例

10个用于Android开发的有用的Kotlin库及示例 在Android开发领域&#xff0c;Kotlin已成为一门领先的语言&#xff0c;带来了现代语法和功能的浪潮。随着Kotlin的崛起&#xff0c;涌现出了许多专为其定制的库&#xff0c;进一步增强了开发体验。本文将深入介绍其中的10个库&…

【论文阅读】One For All: Toward Training One Graph Model for All Classification Tasks

目录 0、基本信息1、研究动机2、创新点——One For All &#xff1a;unique features3、准备4、具体实现4.1、用TAGs统一来自不同领域的图数据4.2、用NOI&#xff08;NODES-OF-INTEREST&#xff09;统一不同图任务4.2.1、NOI子图4.2.2、NOI提示结点 4.3、用于图的上下文学习&am…

Rust之构建命令行程序(三):重构改进模块化和错误处理

开发环境 Windows 10Rust 1.74.1 VS Code 1.85.1 项目工程 这次创建了新的工程minigrep. 重构改进模块化和错误处理 为了改进我们的程序&#xff0c;我们将修复与程序结构及其处理潜在错误的方式有关的四个问题。首先&#xff0c;我们的main函数现在执行两项任务:解析参数和…

Find My相机|苹果Find My技术与相机结合,智能防丢,全球定位

相机是一种利用光学成像原理形成影像并使用底片记录影像的设备&#xff0c;是用于摄影的光学器械。相机让我们能够记录下美丽的风景和珍贵的时刻。当我们到达一个迷人的地方,或者经历了一个特别难忘的时刻时,我们可以使用照相机来拍摄照片,记录下这些美好的回忆。照相机可以帮助…

最新 生成pdf文字和表格

生成pdf文字和表格 先看效果 介绍 java项目&#xff0c;使用apache的pdfbox工具&#xff0c;可分页&#xff0c;自定义列 依赖 <dependency><groupId>org.apache.pdfbox</groupId><artifactId>pdfbox</artifactId><version>2.0.22<…

鸿蒙开发(四)UIAbility和Page交互

通过上一篇的学习&#xff0c;相信大家对UIAbility已经有了初步的认知。在上篇中&#xff0c;我们最后实现了一个小demo&#xff0c;从一个UIAbility调起了另外一个UIAbility。当时我提到过&#xff0c;暂不实现比如点击EntryAbility中的控件去触发跳转&#xff0c;而是在Entry…

Qt编程之仿gnome-terminal终端样式 +颜色文字显示

Qt仿linux 终端样式 颜色文字 1.说再多废话不如直接show code2.实现效果 本文采用QTextBrowser作为文本显示窗口&#xff0c;进行文本的显示。本文实例实现的效果并没有终端的输入效果&#xff0c;这里只是提供一些仿终端样式思路。 1.说再多废话不如直接show code 1.ui文件…

Openwrt 下动态路由协议(quagga-OSPF)配置与验证

文章目录 前言网络拓扑静态路由方式动态路由方式Openwrt下 Quagga 安装Quagga 配置R1路由器zebra配置R1路由器ospf配置R2路由器zebra配置R2路由器ospf配置OSPF协议分析REF本文将在两台openwrt系统上安装配置quagga, 搭建一套完整环境,来验证OSPF动态路由的基本功能和实际效果,…

关于变量在多个.C文件中使用(Undefined symbol tempbuff (referred from main.o).问题解决)

1、如图结构&#xff0c;想在multimenu.C和usart1.c中使用变量tempbuff 于是&#xff0c;就将使用的代码移动了过来&#xff0c;为SetTxData1_toLCD(0x00,0x01);和UserUart1Send( tempbuff1,sizeof(tempbuff1));&#xff0c;编译后提示错误如下&#xff1a; communication_prot…

从零开始学习Python基础语法:打开编程大门的钥匙

文章目录 一、引言1.1 Python作为一种流行的编程语言的介绍1.2 Python的应用领域和适用性 二、为什么选择Python2.1 Python的简洁性和易读性2.2 Python的跨平台特性 三、Python在数据科学和人工智能领域的应用3.1 第一个Python程序3.1.1 Hello, World!&#xff1a;编写并运行你…

XXL-Job的搭建接入Springboot项目(详细)

一、XXL-Job介绍 XXL-Job 是一款开源的分布式任务调度平台&#xff0c;由 Xuxueli&#xff08;徐雪里&#xff09;开发。它基于 Java 技术栈&#xff0c;提供了一套简单易用、高可靠性的任务调度解决方案。 XXL-Job 的主要作用是帮助开发者实现定时任务的调度和执行。它可以用…

安装脚手架Vue CLI详解!!!

Vue CLI基本介绍&#xff1a; Vue CLI是Vue官方提供的一个全局命令工具。可以帮助我们快速创建一个开发Vue项目的标准化基础架子【集成了webpack配置】 安装脚手架好处&#xff1a; 开箱即用&#xff0c;零配置&#xff1b;内置babel等工具&#xff1b;标准化 安装步骤&#…

vscode中关于python的一些常用配置

文章目录 python cv2 提示配置第一步 配置提示信息第二部 重启vs 可能还不行&#xff0c;那就重新安装以下opencv-python 配置pytest还是如上&#xff0c;将下入的位置打开编写测试用例 配置跨文件import在工作目录中新建一个.env文件输入内容如下打开.vscode中的setting.json …

react umi/max 封装页签组件

1. models/tabs // 全局共享数据示例 import { useState } from react;const useUser () > {const [items, setItems] useState<any[]>([]); // 页签的全局Item数据const [key, setKey] useState<string>(/home); // 页签的高亮Keyreturn {items,setItems…

leetcode热题100.路径总和 III

Problem: 437. 路径总和 III 文章目录 题目思路1复杂度1Code1思路2复杂度2Code2 题目 给定一个二叉树的根节点 root &#xff0c;和一个整数 targetSum &#xff0c;求该二叉树里节点值之和等于 targetSum 的 路径 的数目。 路径 不需要从根节点开始&#xff0c;也不需要在叶…

Leetcode:128. 最长连续序列

128. 最长连续序列 乍一看感觉很简单&#xff0c;一看要用O(n)??? 因为我觉得题目很难而且题目看起来很简单&#xff0c;感觉以后会用到&#x1f606;&#xff0c;做个记录 1.朴素做法 思路 答:任何一段连续的数都有一个左端点&#xff1a;比如&#xff08;1&#xff0c;…