1、实现效果图

 2、设计思路

如上图所示,可以将页面分为3大部分,如下:

  1. 【CSDN睡竹】为大标题部分,设计为一个独立的表格,该表格不能设置表头,且表格内容部分只生成一行数据,数据内容为显示的“CSDN睡竹
  2. 【截止日期、板块内容】为表头备注栏部分,同上,设计为一个独立的表格,该表格不能设置表头,且表格内容部分只生成一行数据,数据内容为显示的“截止日期:2022/07/05 
    版块内容:用户信息
    ”,一行内换行操作是通过"\n"实现的。
  3. 【表格】是第三部分,这是一个拥有表头的完整表格。不使用easyExcel的填充方式,直接通过代码实现。

话不多说,直接上代码:

3、实现代码(基于springboot v2.7.1)

3.1、以下是controller层代码:

只是简单的写了一个下载接口,调用service

package com.shuizhu.controller;

import com.shuizhu.service.ExcelServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @睡竹
 */
@Controller
public class ExcelController {

    @Autowired
    private ExcelServiceImpl service;

    @PostMapping("/export")
    public void downExcel(HttpServletRequest reuqest, HttpServletResponse response){
         service.downExcel(reuqest,response);
    }

}

3.2、service代码【关键部分】

package com.shuizhu.service;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.merge.OnceAbsoluteMergeStrategy;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.WriteTable;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.row.SimpleRowHeightStyleStrategy;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.shuizhu.domain.UsersDTO;
import com.shuizhu.util.CustomSheetWriteHandler;
import org.apache.commons.collections4.map.HashedMap;
import org.apache.poi.ss.usermodel.*;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * 睡竹
 */
@Service
public class ExcelServiceImpl {
    /**
     * Excel下载
     */
    public void downExcel(HttpServletRequest reuqest, HttpServletResponse response){
        ServletOutputStream out = null;
        ExcelWriter build = null;
        try {
            /**(1)、创建Excel核心对象 */
            out = response.getOutputStream();
            build = EasyExcel.write(out).build();
            // 创建sheet                   0表示:文件中第1个sheet页 || CustomSheetWriteHandler是去除网格线
            WriteSheet sheet = EasyExcel.writerSheet(0, "测试的sheet名称").registerWriteHandler(
                    new CustomSheetWriteHandler()).build();

            /**(2)、创建Excel页面的数据 【手动创建,工作中,这一部分是动态获取的】*/
            //1、表头数据【最上面的标题】 --topicData
            List<List<Object>> topicData = new ArrayList<>();
            ArrayList<Object> list1 = new ArrayList<>();
            list1.add("CSDN睡竹");
            topicData.add(list1);
            //2、表头备注栏【截止日期、板块内容】--secondData
            // 硬代码生成时间和版块内容【工作中,这里是动态生成的】
            String tableTime = "2022/07/05";
            String sectionContent = "用户信息";
            List<List<Object>> secondData = new ArrayList<>();
            List<Object> list2 = new ArrayList<>();
            list2.add("截止日期:" + tableTime + " \n版块内容:" + sectionContent);
            secondData.add(list2);
            //3、生成数据表格的标题栏内容【这里的元素个数必须与表格保持一致】
            List<List<String>> head = new ArrayList<>();
            List<String> head1 = new ArrayList<>();
            head1.add("用户编号");
            List<String> head2 = new ArrayList<>();
            head1.add("用户编号");
            List<String> head3 = new ArrayList<>();
            head1.add("用户编号");
            head2.add("用户名称");
            head3.add("用户年龄");
            head.add(head1);
            head.add(head2);
            head.add(head3);
            //4、获取数据表格中的数据
            List<List<Object>> data = getData();
            //5、获取数据表格的总列数,下面需要用到
            int size = data.get(0).size();

            /**(3)、设置3个表格的样式 */
            //1、设置表头样式【最上面的标题】
            /**
             * 1.1、 合并单元格 【四个参数】
             * 参数1:合并开始的第一行     【0:表示第一行】
             * 参数2:和平结束的最后一行   【0:表示第一行,0-0=0,表示没有合并行】
             * 参数3:合并开始的第一列     【0:表示第一列】
             * 参数4:合并开始的最后一列   【size-1:表示合并的列数与数据表格的列数一致】
             */
            OnceAbsoluteMergeStrategy mergeStrategy = new OnceAbsoluteMergeStrategy(0, 0, 0, size - 1);
            //1.2、设置内容居中
            WriteCellStyle contentStyle = new WriteCellStyle();
            //垂直居中
            contentStyle.setVerticalAlignment(VerticalAlignment.CENTER);
            //水平居中
            contentStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
            WriteFont writeFont = new WriteFont();
            //加粗
            writeFont.setBold(true);
            //字体大小为16
            writeFont.setFontHeightInPoints((short) 16);
            contentStyle.setWriteFont(writeFont);
            // 单元格策略 参数1为头样式【不需要头部,设置为null】,参数2位表格内容样式
            HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(null, contentStyle);

            //2、设置表头备注栏样式【截止日期、板块内容】
            /**
             * 2.1、合并单元格
             * 两个1表示合并在第二行,且没有合并行
             * 从第一列开始,合并至数据表格的总列数(长度)
             */
            OnceAbsoluteMergeStrategy mergeStrategy2 = new OnceAbsoluteMergeStrategy(1, 1, 0, size - 1);
            //2。1、单元格样式
            WriteCellStyle contentStyle2 = new WriteCellStyle();
            // 设置内容自动换行
            contentStyle2.setWrapped(true);
            // 字体样式
            WriteFont writeFont2 = new WriteFont();
            writeFont2.setFontHeightInPoints((short) 10);
            contentStyle2.setWriteFont(writeFont2);
            HorizontalCellStyleStrategy horizontalCellStyleStrategy2 = new HorizontalCellStyleStrategy(null, contentStyle2);

            //3、设置数据表格的样式
            //  ---------- 头部样式 ----------
            WriteCellStyle headStyle = new WriteCellStyle();
            // 字体样式
            WriteFont headFont = new WriteFont();
            headFont.setFontHeightInPoints((short) 11);
            headStyle.setWriteFont(headFont);
            // 背景颜色
            headStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
            headStyle.setFillForegroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE.index);

            //  ---------- 内容样式 ----------
            WriteCellStyle bodyStyle = new WriteCellStyle();
            // 字体样式
            WriteFont bodyFont = new WriteFont();
            bodyFont.setFontHeightInPoints((short) 10);
            bodyStyle.setWriteFont(bodyFont);
            // 设置边框
            // bodyStyle.setBorderTop(BorderStyle.DOUBLE);
            bodyStyle.setBorderLeft(BorderStyle.THIN);
            bodyStyle.setBorderRight(BorderStyle.THIN);
            bodyStyle.setBorderBottom(BorderStyle.THIN);
            // 创建策略
            HorizontalCellStyleStrategy dataTableStrategy = new HorizontalCellStyleStrategy(headStyle, bodyStyle);

            /**
             * (4)、统一设置行高
             */
            // 设置表头行高【最上面的标题】  参数1:表头行高为0【不需要表头】    参数2:内容行高为28
            SimpleRowHeightStyleStrategy rowHeightStrategy1 = new SimpleRowHeightStyleStrategy((short) 0, (short) 28);
            // 设置表头备注栏行高【截止日期、板块内容】
            SimpleRowHeightStyleStrategy rowHeightStrategy2 = new SimpleRowHeightStyleStrategy((short) 0, (short) 25);
            // 设置数据表格的行高   null表示使用原来的行高
            SimpleRowHeightStyleStrategy rowHeightStrategy3 = new SimpleRowHeightStyleStrategy( null, (short) 18);

            /**(5)、生成页面中的3个表格
             *  0 , 1 , 2 是表格的排序(从上往下)
             *  上面设置的样式,合并。。。都需要在这里关联对应的表格
             */
            // 生成表格1 ----页面中最上方的大标题
            WriteTable topicTable = EasyExcel.writerTable(0).registerWriteHandler(rowHeightStrategy1).registerWriteHandler(mergeStrategy).registerWriteHandler(horizontalCellStyleStrategy).needHead(false).build();
            // 生成表格2 ----表头备注栏【截止日期、板块内容】
            WriteTable secondTable = EasyExcel.writerTable(1).registerWriteHandler(rowHeightStrategy2).registerWriteHandler(mergeStrategy2).registerWriteHandler(horizontalCellStyleStrategy2).needHead(false).build();
            // 生成表格3 ----user表格
            WriteTable dataTable = EasyExcel.writerTable(2).registerWriteHandler(rowHeightStrategy3).registerWriteHandler(dataTableStrategy).head(head).needHead(true).build();
            /**(6)、把数据填充至各个表格 */
            build.write(topicData, sheet, topicTable);
            build.write(secondData, sheet, secondTable);
            build.write(data, sheet, dataTable);
            /**(7) 生成文件 */
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
            response.setHeader("Content-disposition", "attachment;filename=" + "测试Excel" + ".xlsx");
        } catch (Exception e) {
            e.printStackTrace();
            /**
             * 前后端处理下载失败异常
             * 该部分必须与【流关闭操作】处于同一 【try-catch-finally】中,否则无法返回错误信息给前端
             */
            response.reset();
            response.setHeader("content-type", "text/html;charset=utf-8");
            try (OutputStreamWriter writer = new OutputStreamWriter(out, StandardCharsets.UTF_8)) {
                // 组装JSON
                Map<String, Object> map = new HashedMap<>();
                map.put("retCode", "9999");
                map.put("retMsg", "Excel下载失败:" + e.getMessage());
                String json = new ObjectMapper().writeValueAsString(map);
                if (!ObjectUtils.isEmpty(writer) && !ObjectUtils.isEmpty(json)) {
                    //返回错误信息给前端
                    writer.write(json);
                    writer.flush();
                }
            } catch (Exception e2) {
                throw new ClassCastException("response.getOutputStream()语句异常");
            }

        }finally {
            //关闭所有的流

            build.finish();

            if (!ObjectUtils.isEmpty(out)) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    /**
     * 模拟数据库查询,获取user数据
     */
    public List<UsersDTO> getUsers(){
        List<UsersDTO> users = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            UsersDTO usersDTO = new UsersDTO();
            usersDTO.setUserId("1000" + i);
            usersDTO.setUserName("第" + i + "个用户");
            usersDTO.setUserAge(18 + i + "");
            users.add(usersDTO);
        }
        return users;
    }

    /**
     * 不是填充Excel,而是直接往Excel中写
     * 需要从users数据集中,获取到value的部分,不需要key
     */
    public List<List<Object>> getData(){
        List<UsersDTO> users = getUsers();
        List<List<Object>> data = new ArrayList<>();
        for (UsersDTO user : users) {
            //把user转为map
            String s = JSONObject.toJSONString(user);
            Map jsonMap = JSONObject.parseObject(s, LinkedHashMap.class, Feature.OrderedField);
            //获取map中的value,组装成list
            Collection values = jsonMap.values();
            List<Object> list = new ArrayList<>(values);
            data.add(list);
        }
        return data;
    }

}

3.3、去网格的工具类代码

package com.shuizhu.util;

import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import org.apache.poi.ss.usermodel.Sheet;

/**
 * 自定义sheet样式
 *
 * @author 睡竹
 */
public class CustomSheetWriteHandler implements SheetWriteHandler {

    @Override
    public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
        Sheet sheet = writeSheetHolder.getSheet();
        // 去除网格线
        sheet.setDisplayGridlines(false);
    }

}

3.4、pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.1</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.shuizhu</groupId>
    <artifactId>shuizhu-easyexcel</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>shuizhu-easyexcel</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.80</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.0.5</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

4、完整效果

gitee源码地址:easyExcel生成个性化表格https://download.csdn.net/download/weixin_42675423/85926315

更多easyExcel的样式设计,可以参考我的

easyExcel专栏https://blog.csdn.net/weixin_42675423/category_11774988.html

GitHub 加速计划 / js / json
41.72 K
6.61 K
下载
适用于现代 C++ 的 JSON。
最近提交(Master分支:21 天前 )
960b763e 3 个月前
8c391e04 6 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐