easypoi动态表头导出数据

需求:动态导出某年某月用户和用户评分数据信息,表头(序号、姓名、用户姓名),数据(所有用户对应的评分以及平均分);

分析:1、表头除过序号、姓名,用户姓名要动态生成;

            2、用户评分信息要和表头中的用户一一对应;

1、maven依赖

<!-- easypoi -->
<dependency>
    <groupId>cn.afterturn</groupId>
    <artifactId>easypoi-base</artifactId>
    <version>4.4.0</version>
</dependency>
<dependency>
    <groupId>cn.afterturn</groupId>
    <artifactId>easypoi-web</artifactId>
    <version>4.4.0</version>
</dependency>
<dependency>
    <groupId>cn.afterturn</groupId>
    <artifactId>easypoi-annotation</artifactId>
    <version>4.4.0</version>
</dependency>

2、数据表结构

2.1用户表

2.2 评分表

2.3 sql

select 
tu.id as userId,//用户id(被评分人id)
tu.real_name as realName, //用户姓名(被评分人)
GROUP_CONCAT(ts.scorer_id  SEPARATOR ',') as scorerId,//该用户对应的所有评分人id,用逗号隔开
GROUP_CONCAT(ts.score SEPARATOR ',') as scoreStr,//该用户的所有评分分数,用逗号隔开
ROUND(avg(ts.score),3) as avgScore//该用户评分平均数
from t_user tu left join t_score ts 
on tu.id  = ts.user_id 
where ts.`year` = '2024' and ts.`month` = '5'
GROUP by userId ,realName
order by  avgScore;

3、代码

1、查询表头所有用户,即可知道表头总列数

2、对应上面sql,查询用户评分数据

3、被评分人分数按照评分人userDOS顺序设置

4、评分人是固定的,但是所有评分人不一定都给(用户)被评分人评分,如果评分人还未评分,分数则为0

5、scoreList 中的数据即是按照表头评分人评的分数有序排列(如果评分人还未评分,分数则为0)

6、excel  title

7、excel data

8、规则设置高度

9、表头设置样式

3.1 controller

/**
     * Excel导出
     */
    @GetMapping("/excel")
    public Result excelDownload( HttpServletResponse response, HttpServletRequest request,
            @RequestParam(name = "year",required = false) String year,
            @RequestParam(name = "month",required = false) String month) throws Exception{
        scoreService.excelDownload(response,request,year,month);
        return ResultGenerator.genOkResult();
    }

3.2实现类

@Override
    public void excelDownload(HttpServletResponse response, HttpServletRequest request,String year, String month) throws IOException {
        LocalDate currentDate = LocalDate.now();
        String currentYear = String.valueOf(currentDate.getYear());
        String currentMonth = String.valueOf(currentDate.getMonthValue());
        year = StrUtil.isNotEmpty(year) ? year : currentYear;
        month = StrUtil.isNotEmpty(month) ? month : currentMonth;
        //1、查询表头所有用户,即可知道表头总列数
        QueryWrapper<UserDO> queryWrapper =  new QueryWrapper<UserDO>();
        queryWrapper.isNotNull("real_name");
        final List<UserDO> userDOS = userMapper.selectList(queryWrapper);

        //2、对应上面sql,查询用户评分数据
        final List<UserIdAndScoreDTO> userIdAndScoreDTOS = userMapper.selectUserScores(year, month);

        
        //3、被评分人分数按照评分人userDOS顺序设置
        for(UserIdAndScoreDTO userIdAndScoreDTO : userIdAndScoreDTOS){
            List<Double> scoreList = new ArrayList<>();
            final String[] split = userIdAndScoreDTO.getScorerId().split(",");
            final String[] split1 = userIdAndScoreDTO.getScoreStr().split(",");
            for(UserDO userDO : userDOS){
                //判断某个字符串在数组中如果存在,找到对应下标,如果不存在则为-1
                int index = findStringIndex(split, userDO.getId());
                //4、评分人是固定的,但是所有评分人不一定都给(用户)被评分人评分,如果评分人还未评分,分数则为0
                String a = (index!= -1) ? split1[index] : "0";
                scoreList.add(Double.valueOf(a));
            }
            //5、scoreList 中的数据即是按照表头评分人评的分数有序排列(如果评分人还未评分,分数则为0)
            userIdAndScoreDTO.setScoreList(scoreList);
        }

        //6、excel  title
        final List<DynamicTablePo> tablePoList = getTalePoList(userDOS);
        //7、excel data
        final List<Map<String, Object>> excelScoreVOS = dataList(userIdAndScoreDTOS, userDOS);


        List<ExcelExportEntity> beanList = new ArrayList<ExcelExportEntity>(tablePoList.size());
        for (DynamicTablePo tablePo : tablePoList){
            ExcelExportEntity entity = new ExcelExportEntity();
            entity.setName(tablePo.getFiledShowName());
            entity.setKey(tablePo.getFiledCode());
            entity.setOrderNum(tablePo.getOrderNum());
            beanList.add(entity);
        }
            String excelName = "营销部"+ month +"月份各专责互评的得分表";
            String secondTitle = "规则:从日常工作协同等工作进行考评,从1-5分为9个分值进行打分," +
                "如:1-1.5-2-2.5-3-3.5-4-4.5-5,每个人总分除以9作为最终得分。" +
                "注意:分值出现一样作为废票,该人员打分全部人员均按照委分统计。";
            ExportParams exportParams = new ExportParams(excelName,secondTitle, "sheet1");
            //8、规则设置高度
            exportParams.setSecondTitleHeight((short) 10);
            //9、表头设置样式
            exportParams.setStyle(ExcelExportTitleStyle.class);
            Workbook workbook = ExcelExportUtil.exportExcel(exportParams, beanList , excelScoreVOS);
            response.setHeader("content-Type","application/vnd.ms-excel");
            response.setHeader("Content-Disposition", "attachment;filename="+ URLEncoder.encode(excelName + "导出表", "UTF-8") + ".xls");
            response.setCharacterEncoding("UTF-8");
            workbook.write(response.getOutputStream());
            workbook.close();
    }

    /**
     * 组装数据
     * @return
     */
    private List<Map<String,Object>> dataList(List<UserIdAndScoreDTO> userIdAndScoreDTOS,List<UserDO> userDOS){
        List<Map<String,Object>> exportList = new ArrayList<>();
        int j = 1;
        for(UserIdAndScoreDTO userIdAndScoreDTO : userIdAndScoreDTOS){
            Map<String,Object> map = new HashMap<>();
            map.put("num",j);
            map.put("realName",userIdAndScoreDTO.getRealName());
            map.put("avgScore",userIdAndScoreDTO.getAvgScore());
            final List<Double> scoreList = userIdAndScoreDTO.getScoreList();
           int i =0;
            for (UserDO userDO : userDOS) {
                map.put(userDO.getId(),scoreList.get(i));
                i++;
            }
            exportList.add(map);
            j++;
        }
        return exportList;
    }

    /**
     * 设置动态表头
     * @return
     */
    private List<DynamicTablePo> getTalePoList(List<UserDO> userDOS) {
        int i = 3;
        List<DynamicTablePo> resultList = new ArrayList<>();
        DynamicTablePo tablePo = new DynamicTablePo();
        tablePo.setFiledShowName("序号");
        tablePo.setFiledCode("num");
        tablePo.setOrderNum(1);
        tablePo.setDataType(0);
        DynamicTablePo tablePo1 = new DynamicTablePo();
        tablePo1.setFiledShowName("姓名");
        tablePo1.setFiledCode("realName");
        tablePo1.setOrderNum(2);
        tablePo1.setDataType(0);
        resultList.add(tablePo);
        resultList.add(tablePo1);
        for (UserDO userDO : userDOS) {
            DynamicTablePo tablePo2 = new DynamicTablePo();
            tablePo2.setFiledShowName(userDO.getRealName());
            tablePo2.setFiledCode(userDO.getId());
            tablePo2.setOrderNum(i);
            tablePo2.setDataType(0);
            resultList.add(tablePo2);
            i++;
        }
        DynamicTablePo tablePo3 = new DynamicTablePo();
        tablePo3.setFiledShowName("平均分");
        tablePo3.setFiledCode("avgScore");
        tablePo3.setOrderNum(i);
        tablePo3.setDataType(0);
        resultList.add(tablePo3);
        return resultList;
    }


    /**
     * 判断某个字符串在数组中如果存在,找到对应下标,如果不存在则为-1
     * @param array
     * @param target
     * @return
     */
    public static int findStringIndex(String[] array, String target) {
        for (int i = 0; i < array.length; i++) {
            if (array[i].equals(target)) {
                return i;
            }
        }
        return -1;
    }

3.3 实体  filedCode(表头key值和查询出来的数据的实体/map相对应,否则无法填充数据)

package com.langzhifangling.wx.scoringapplet.model.VO;

import lombok.Data;

import java.io.Serializable;

@Data
public class DynamicTablePo implements Serializable {
 
    private static final long serialVersionUID = 8991244829305414889L;
 
    //表头名字
    private String filedShowName;
 
    //表头key值和查询出来的数据的实体相对应
    private String filedCode;
 
    //表头顺序
    private Integer orderNum;
 
    //字段数据类型
    private Integer dataType;
}

3.4 表头样式 

package com.langzhifangling.wx.scoringapplet.config;

import cn.afterturn.easypoi.excel.export.styler.AbstractExcelExportStyler;
import cn.afterturn.easypoi.excel.export.styler.IExcelExportStyler;
import org.apache.poi.ss.usermodel.*;

/**
 * 导出自定义title的工具类
 *
 * @author changjiang.liu
 * @date 2022/5/23 16:44
 */
public class ExcelExportTitleStyle extends AbstractExcelExportStyler
        implements IExcelExportStyler {
    public ExcelExportTitleStyle(Workbook workbook) {
        super.createStyles(workbook);
    }

    @Override
    public CellStyle getTitleStyle(short color) {
        CellStyle titleStyle = workbook.createCellStyle();
        // 自定义字体
        Font font = workbook.createFont();
        font.setColor(IndexedColors.WHITE1.getIndex());
        font.setBold(true);
        font.setFontName("宋体");
        titleStyle.setFont(font);

		// 自定义背景色
        titleStyle.setFillForegroundColor(IndexedColors.PALE_BLUE.getIndex());
        titleStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);

        titleStyle.setBorderBottom(BorderStyle.THIN);
        titleStyle.setBorderTop(BorderStyle.THIN);
        titleStyle.setBorderLeft(BorderStyle.THIN);
        titleStyle.setBorderRight(BorderStyle.THIN);

        titleStyle.setAlignment(HorizontalAlignment.CENTER);
        titleStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        titleStyle.setWrapText(true);
        return titleStyle;
    }

    @Override
    public CellStyle stringSeptailStyle(Workbook workbook, boolean isWarp) {
        CellStyle style = workbook.createCellStyle();
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setDataFormat(STRING_FORMAT);
        if (isWarp) {
            style.setWrapText(true);
        }
        return style;
    }

    @Override
    public CellStyle getHeaderStyle(short color) {
        CellStyle titleStyle = workbook.createCellStyle();
        Font font = workbook.createFont();
        font.setFontHeightInPoints((short) 12);
        titleStyle.setFont(font);
        titleStyle.setAlignment(HorizontalAlignment.CENTER);
        titleStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        return titleStyle;
    }

    @Override
    public CellStyle stringNoneStyle(Workbook workbook, boolean isWarp) {
        CellStyle style = workbook.createCellStyle();
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setDataFormat(STRING_FORMAT);
        if (isWarp) {
            style.setWrapText(true);
        }
        return style;
    }

}

4、结果

注:

数据可以封装一个实体,由于被评分人的所有评分是一个集合,没搞出来;

故我是采用List<map>封装数据进行导出; 

所有是非集合,可以采用封装实体进行导出更简单点;

参考:

easypoi导出数据的两种方式(动态表头导出和静态表头导出)_easypoi 导出列的顺序-CSDN博客

补充:使用excel模板进行导出  #是横向获取集合数据   $是纵向获取集合数据  

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

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

相关文章

Nginx+GateWay

目录 Nginx nginx如何配置负载均衡 负载均衡有哪些策略 1、轮询&#xff08;默认&#xff09; 2、指定权重 3、ip_hash&#xff08;客户端ip绑定&#xff09; 4、least_conn&#xff08;最少连接&#xff09; 5、fair 6、url_hash Nginx为什么效率高 gateway 使用gat…

Lobe Chat–在线AI对话聊天机器人,一键部署,免费开源

Lobe Chat 现代化设计的开源 ChatGPT/LLMs 聊天应用与开发框架 支持语音合成、多模态、可扩展的&#xff08;function call&#xff09;插件系统 一键免费拥有你自己的 ChatGPT/Gemini/Claude/Ollama 应用 项目演示 支持多种模型接口 支持语音输入输出 支持云端同步 丰富多彩非…

1013: 哈希表(开放定址法处理冲突)

解法&#xff1a; 线性探测是一种解决哈希冲突的方法&#xff0c;当发生哈希冲突时&#xff0c;它会依次往后查找空的槽位&#xff0c;直到找到一个空的槽位或者达到数组的末尾。 下面是处理哈希冲突的线性探测的步骤&#xff1a; 创建一个哈希表&#xff0c;里面包含一定数量的…

Ps 滤镜:视频

Ps菜单&#xff1a;滤镜/视频 Filter/Video “视频”滤镜子菜单中包含了“NTSC 颜色”和“逐行”两个滤镜。 这两个滤镜都是针对视频和电视播放的特定需求设计的。 “逐行”滤镜主要解决交错视频的视觉问题&#xff0c;而“NTSC 颜色”滤镜则确保色彩在电视播放时的兼容性和准确…

一文带你了解OSPF 七种LSA类型,很全!

大家好&#xff0c;今天我们 带大家了解一下OSPF的七种LSA类型。 在OSPF&#xff08;开放式最短路径优先&#xff09;协议中&#xff0c;LSA&#xff08;链路状态通告&#xff09;是一种至关重要的数据格式&#xff0c;专门用于描述路由信息。它包含了路由器或网络的各种状态信…

编写一个C#程序,实现音乐文件的播放功能

一、作业要求 要求1&#xff1a; 1. 程序应能够读取MP3文件&#xff0c;并播放其中的音频。 2. 程序应能够处理可能出现的异常&#xff0c;如文件不存在、文件读取错误等。 3. 程序应具有良好的用户界面&#xff0c;方便用户进行操作。 4. 程序应具有良好的兼容性&#xf…

VK6932 SOP32数码屏驱动IC抗干扰数显芯片高稳定LED驱动 原厂FAE支持

产品型号&#xff1a;VK6932 产品品牌&#xff1a;永嘉微电/VINKA 封装形式&#xff1a;SOP32 工程服务&#xff0c;技术支持&#xff01; 概述 VK6932是一种数码管或点阵LED驱动控制专用芯片&#xff0c;内部集成有3线串行接口、数据锁存器、LED 驱动等电路。SEG脚接LED阳…

【Python】selenium爬虫常见用法和配置,以及常见错误和解决方法

欢迎来到《小5讲堂》 这是《Python》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 前言无执行文件代码报错信息错误路径手动下载自动下载 选项配置Ch…

js之遍历方法

先创建一个数组&#xff0c;然后使用for.in进行遍历&#xff0c;如下图所示sub代表下标并且遍历几次&#xff0c;arr代表数组 <script>let arr [1, 2, 3, 4, 5, 6];for (let sub in arr) {console.log(arr);}</script> 第二种方法则是for循环遍历&#xff0c;根据…

Transformer 解析 超级详细版

推荐学习视频 汉语自然语言处理-从零解读碾压循环神经网络的transformer模型(一)- 注意力机制-位置编码-attention is all you need_哔哩哔哩_bilibili 目录 首先下transformer和LSTM的最大区别是什么&#xff1f; 1.positional \ encoding, 即位置嵌入(或位置编码); 2 自注…

windows连接CentOS数据库或Tomcat报错,IP通的,端口正常监听

错误信息 数据库错误&#xff1a; ERROR 2003 (HY000): Cant connect to MySQL server on x.x.x.x (10060) Tomcat访问错误&#xff1a; 响应时间过长 ERR_CONNECTION_TIMED_OUT 基础排查工作 【以下以3306端口为例&#xff0c;对于8080端口来说操作是一样的&#xff0c;只需…

NM2-WRDUW施耐德电动机保护器EOCR-NM2

EOCR智能电动机保护器原产地为韩国&#xff0c;隶属于施耐德(韩国)电气有限公司工厂。此公司早起源于韩国三和SAMWHA株式会社&#xff0c;是早研发电子式电动机保护器厂家&#xff0c;产品涵盖过电流继电器EOCR-SS,EOCR-SE2,EOCR-AR&#xff0c;欠电流继电器EUCR&#xff0c;数…

3分钟快速了解VR全景编辑器

说到VR全景&#xff0c;想必大多数人都见过那种可以360旋转拖动观看的图片。虽然这种技术已经不算新鲜&#xff0c;如果你以为这就是VR全景的全部&#xff0c;那就大错特错了&#xff01; 上面看到的这种形式&#xff0c;只能算VR全景的第一层形态。现在的VR全景已经发展成为了…

LabVIEW自动机械变速器(AMT)开发

LabVIEW自动机械变速器&#xff08;AMT&#xff09;开发 在现代汽车工业中&#xff0c;提升车辆的自动化水平和驾驶体验是一个不断追求的目标。随着技术的发展&#xff0c;自动机械变速器&#xff08;AutomatedMechanical Transmission, AMT&#xff09;凭借其较高的能效和较低…

四、VGA项目:联合精简帧+双fifo+sobel算法 实现VGA显示

前言&#xff1a;该项目实际上是在很多基础的小练习上合成起来的&#xff0c;例如涉及到uart&#xff08;rs232&#xff09;的数据传输、双fifo流水线操作、VGA图像显示&#xff0c;本次内容在此基础上又增添了sobel算法&#xff0c;能实现图像的边沿监测并VGA显示。 文章目录…

你写的每条SQL都是全表扫描吗

你写的每条SQL都是全表扫描吗&#xff1f;如果是&#xff0c;那MySQL可太感谢你了&#xff0c;每一次SQL执行都是在给MySQL上压力、上对抗。MySQL有苦难言&#xff1a;你不知道索引吗&#xff1f;你写的SQL索引都失效了不知道吗&#xff1f;慢查询不懂啊&#xff1f;建那么多索…

Xinstall助力App地推监测,实现精准效果评估

在移动互联网时代&#xff0c;App的推广已经成为企业营销的重要手段。然而&#xff0c;如何有效地监测App地推效果&#xff0c;一直是广告主和开发者面临的难题。幸运的是&#xff0c;Xinstall作为国内专业的App全渠道统计服务商&#xff0c;为广告主和开发者提供了一站式的解决…

【C++阅览室】C++之Vector(容器)

目录 vector的介绍 vector的使用 vector的定义 vector iterator 的使用 vector 空间增长问题 vector 增删查改 vector 迭代器失效问题。&#xff08;重点&#xff09; vector的介绍 1、 vector 是表示可变大小数组的序列容器&#xff0c;可以使用连…

java.lang.NoSuchMethodException: com.ruoyi.web.controller.test.bean.HeadTeacher

软件开发过程中使用Java反射机制时遇到了下面的问题 com.ruoyi.web.controller.test.bean.HeadTeacher4b9af9a9 com.ruoyi.web.controller.test.bean.HeadTeacher4b9af9a9java.lang.NoSuchMethodException: com.ruoyi.web.controller.test.bean.HeadTeacher.<init>(java…

英飞凌TC3xx 启动逻辑梳理(1)

目录 1.启动时序总览 2.Boot Firmware干了什么&#xff1f; 2.1 BMHD梳理 2.2 HWCFG 2.3 ABM 2.4 BMHD 无效时处理方案 2.5 HSM启动如何影响SSW启动 3.小结 在调TC3xx的板子时&#xff0c;最害怕的就是刷UCB&#xff1b;稍不注意板子就上锁&#xff0c;调试器也连不上了…
最新文章