首页 > 编程语言 >java-EasyExcel模板导出

java-EasyExcel模板导出

时间:2023-11-24 10:45:38浏览次数:39  
标签:map java imageData researchDetailVo EasyExcel put new MultipartFile 模板

前言: 

需求:根据自定义模板导出Excel,包含图片、表格,采用EasyExcel

 

提示:EasyExcel请使用 3.0 以上版本,

对图片操作最重要的类就是 WriteCellData<Void> 如果你的easyexcel没有这个类,说明你的版本太低,请升级到3.0以上

<dependency>
     <groupId>com.alibaba</groupId>
     <artifactId>easyexcel</artifactId>
     <version>3.2.1</version>
 </dependency>

 

实际代码:

Controller

@ApiOperation("excel导出详情")
@PostMapping("excelExport")
public void excelExport(HttpServletResponse response,
                        @ApiParam("id {\"id\":\"xxx\"}") @RequestBody Map<String, String> data) {
    ExcelUitl.templateExport(response, researcherInformationService
                             .getDetail(data.get("id")));
}

ServiceImpl

public static String templateExport(HttpServletResponse response,ResearchDetailVo researchDetailVo) {
        InputStream is = null;
        try {
            // 取出模板
            is = ResourceUtil.getStream("classpath:templates/survey.xlsx");
            Map<String, Object> map = new HashMap<>(10);
            map.put("goOutDate", researchDetailVo.getGoOutDate());
            map.put("userName", researchDetailVo.getUserName());
            map.put("visitPlace", researchDetailVo.getVisitPlace());
            map.put("marketTrends", researchDetailVo.getMarketTrends());
            map.put("marketEnvironment", researchDetailVo.getMarketEnvironment());
            map.put("partnerTrends", researchDetailVo.getPartnerTrends());
            map.put("companyStatus", researchDetailVo.getCompanyStatus());
            map.put("marketCompetition", researchDetailVo.getMarketCompetition());
            map.put("feedback", researchDetailVo.getFeedback());

            // 文件名称
            String fileName = researchDetailVo.getUserName() + researchDetailVo.getGoOutDate()
                    + "调研反馈信息表";
   
            if (!ObjectUtils.isEmpty(researchDetailVo.getUrl())) {
                //图片url转换为MultipartFile对象
                // getUrl 是 List<String>
                MultipartFile[] files = downloadImages(researchDetailVo.getUrl());
                for (int i = 0; i < files.length; i++) {
                    MultipartFile file = files[i];
                    // 图像设置处理
                    WriteCellData<Void> voidWriteCellData = imageCells(file.getBytes());
                    map.put("img" + (i + 1), voidWriteCellData);
                }
            }

            ExcelWriter excelWriter = EasyExcel.write(getOutputStream(fileName, response)).withTemplate(is).excelType(ExcelTypeEnum.XLSX).build();
            WriteSheet writeSheet = EasyExcel.writerSheet().build();
            excelWriter.fill(map, writeSheet);
            excelWriter.finish();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


public static WriteCellData<Void> imageCells(byte[] bytes) throws IOException {

        WriteCellData<Void> writeCellData = new WriteCellData<>();

        // 可以放入多个图片
        List<ImageData> imageDataList = new ArrayList<>();
        writeCellData.setImageDataList(imageDataList);

        ImageData imageData = new ImageData();
        imageDataList.add(imageData);
        // 设置图片
        imageData.setImage(bytes);
        // 图片类型
        //imageData.setImageType(ImageData.ImageType.PICTURE_TYPE_PNG);

        // 上 右 下 左 需要留空,这个类似于 css 的 margin;
        // 这里实测 不能设置太大 超过单元格原始大小后 打开会提示修复。暂时未找到很好的解法。
        imageData.setTop(10);
        imageData.setRight(10);
        imageData.setBottom(10);
        imageData.setLeft(10);

        // * 设置图片的位置。Relative表示相对于当前的单元格index。first是左上点,last是对角线的右下点,这样确定一个图片的位置和大小。
        // 目前填充模板的图片变量是images,index:row=CELL_COUNT,column=0。所有图片都基于此位置来设置相对位置
        // 第1张图片相对位置
        imageData.setRelativeFirstRowIndex(0);
        imageData.setRelativeFirstColumnIndex(0);
        imageData.setRelativeLastRowIndex(0);
        imageData.setRelativeLastColumnIndex(0);

        return writeCellData;
    }

///为什么用线程池去实现 原因:当时项目文件储存用的是minio,由于服务器宽带非常低,导致几百K的图片都需要很久,多图片需要加载资源很久
public static MultipartFile[] downloadImages(List<String> imageUrls) {
        // 创建一个固定大小的线程池
        int poolSize = 5;
        ThreadPoolExecutor executor = new ThreadPoolExecutor(poolSize, poolSize,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>());
        MultipartFile[] files = new MultipartFile[imageUrls.size()];

        for (int i = 0; i < imageUrls.size(); i++) {
            final int index = i;
            executor.submit(() -> {
                try {
                    files[index] = convert(imageUrls.get(index));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
        }

        executor.shutdown(); // 关闭线程池

        // 等待所有任务执行完成
        while (!executor.isTerminated()) {
            // 等待
        }

        return files;
    }

    /**
     * 图片地址转换为MultipartFile文件
     *
     * @param imageUrl
     * @return
     * @throws IOException
     */
    public static MultipartFile convert(String imageUrl) throws IOException {
        // 将在线图片地址转换为URL对象
        URL url = new URL(imageUrl);
        // 打开URL连接 转换为HttpURLConnection对象
        URLConnection connection = url.openConnection();
        HttpURLConnection httpURLConnection = (HttpURLConnection) connection;
        // 获取输入流 并读取输入流中的数据,并保存到字节数组中
        InputStream inputStream = httpURLConnection.getInputStream();
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int bytesRead;
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            byteArrayOutputStream.write(buffer, 0, bytesRead);
        }
        byte[] bytes = byteArrayOutputStream.toByteArray();
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        return new MockMultipartFile("file", "filename.jpg", "image/jpeg", byteArrayInputStream);
    }

 

xlsx模板位置

xlsx模板内容

导出内容展示

 

标签:map,java,imageData,researchDetailVo,EasyExcel,put,new,MultipartFile,模板
From: https://www.cnblogs.com/Kikai/p/17853121.html

相关文章

  • java 实现断点续传的上传功能
    下面是一个简单的实现Java断点续传上传功能的代码示例,其中使用了HttpURLConnection和RandomAccessFile类:publicclassResumableUploader{privatestaticfinalintBUFFER_SIZE=4096;privatestaticfinalStringFILE_PATH="yourFilePath";privatestaticfi......
  • 基于html5+javascript技术开发的房贷利率计算器,买房的码农们戳进来
    房贷计算器是一款专为购房者设计的实用工具应用,其主要功能是帮助用户详细计算房贷的还款金额、利息以及还款计划等。通过这款软件,用户可以更加便捷地了解到自己的还款情况和计划,从而更好地规划自己的财务。下面将对房贷计算器进行详细的介绍。体验地址房贷计算器体验地址关键代码<t......
  • Java中如何比较两个日期的大小
    日期比较1.自定义时间与当前时间比较代码展示 运行结果 2.两个自定义时间比较代码展示 运行结果 ......
  • java实现大文件的分片上传与下载(springboot+vue3)
    1.1项目背景对于超大文件上传我们可能遇到以下问题•大文件直接上传,占用过多内存,可能导致内存溢出甚至系统崩溃•受网络环境影响,可能导致传输中断,只能重新传输•传输时间长,用户无法知道传输进度,用户体验不佳1.2项目目标对于上述问题,我们需要对文件做分片传输。分片传输就是......
  • java中ArrayList和LinkedList的区别
    Java中ArrayList和LinkedList都是List集合的实现类,它们都可以用来存储一组有序的元素,但是它们的内部实现方式不同,在使用时也有不同的适用场景。ArrayList是一个基于动态数组的实现,它可以容纳任何类型的对象,并且允许对元素进行随机访问。当添加或者删除元素时,ArrayList需要移动内......
  • Java开发者的Python快速进修指南:面向对象基础
    当我深入学习了面向对象编程之后,我首先感受到的是代码编写的自由度大幅提升。不同于Java中严格的结构和约束,Python在面向对象的实现中展现出更加灵活和自由的特性。它使用了一些独特的关键字,如self和cls,这些不仅增强了代码的可读性,还提供了对类和实例的明确引用。正如Java,Python也......
  • Java设计模式之单例模式
    单例模式(SingletonPattern)是一种常用的设计模式,它用于限制一个类只能创建一个实例,并提供一个全局访问点。在Java中,实现单例模式的关键点包括:私有的构造函数:为了防止其他类创建该类的实例,我们需要将构造函数设为私有。静态的实例变量:我们需要一个静态的变量来存储该类的唯一......
  • java-策略模式
    使用原因:  需求:同一套系统,使用不同的资源,例如A使用阿里的OSS,B使用腾讯的OSS,使用配置的方式实现动态选择哪个资源策略模式示例  做个例子:比如去服装店买衣服,普通会员不打折,黄金会员打9折,铂金会员打8折,钻石会员打7折,这样不同的客户价格计算方式不同,这个时候就可以使用策略模......
  • Java算法练习—递归/回溯
    递归是一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。因此递归过程,最重要的就是查看能不能将原本的问题分解为更小的子问题,这是使用递归的关键。如果是线型递归,子问题直接回到父问题......
  • JavaScript知识点
    类类(class)是在JS中编写构造函数的新方法。它是使用构造函数的语法糖,在底层中使用仍然是原型和基于原型的继承。模板字符串模板字符串是在JS中创建字符串的一种新方法。我们可以通过使用反引号使模板字符串化。对象解构对象析构是从对象或数组中获取或提取值的—种新的、更简洁的......