Excel 操作 转图片,转pdf等

方式一 spire.xls.free(没找设置分辨率的方法)

macOs开发Java GUI程序提示缺少字体问题解决

Spire.XLS:一款Excel处理神器_spire.xls免费版和收费版的区别-CSDN博客

官方文档

Spire.XLS for Java 中文教程

XML 复制代码
        <dependency>
            <groupId>e-iceblue</groupId>
            <artifactId>spire.xls.free</artifactId>
            <version>5.1.0</version>
        </dependency>


      <repositories>
        <repository>
            <id>e-iceblue</id>
            <name>e-iceblue</name>
            <url>https://repo.e-iceblue.cn/repository/maven-public/</url>
        </repository>
      </repositories>
java 复制代码
/**
     * 功能描述: 处理将Excel文件转换为图片并提供下载的请求。
     * 参数说明:
     *   excelFilePath: 存储在服务器上的Excel文件的绝对路径。
     * 返回值说明: ResponseEntity 包含图片文件流,供浏览器下载。
     * 使用示例:
     *   GET /downloadExcelAsImage?excelFilePath=/path/to/your/excel.xlsx
     */
    @GetMapping( "/downloadImage/{id}")
    public ResponseEntity<InputStreamResource> downloadExcelAsImage(@PathVariable("id") String id) throws IOException {
        // 调用服务层方法将Excel转换为图片
        File imageFile = resultHistoryService.convertFromFilePath(id);
        // 设置HTTP头,用于文件下载
        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + imageFile.getName());
        headers.add(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, must-revalidate");
        headers.add(HttpHeaders.PRAGMA, "no-cache");
        headers.add(HttpHeaders.EXPIRES, "0");
        InputStreamResource resource = new InputStreamResource(new FileInputStream(imageFile));
        return ResponseEntity.ok()
                .headers(headers)
                .contentLength(imageFile.length())
                // 或者根据实际生成的图片类型调整 MediaType.IMAGE_JPEG 等
                .contentType(MediaType.IMAGE_PNG)
                .body(resource);

    }
java 复制代码
public File convertFromFilePath(String id) throws IOException {
        ResultHistoryDO resultHistoryDO = resultHistoryDao.get(id);
        String uploadPath = bootdoConfig.getUploadPath();
        String fileurl = resultHistoryDO.getFileurl();
        String[] split = fileurl.split("/files/");
        String fileName =uploadPath+ split[1] ;
        Workbook workbook = new Workbook();
        // 加载Excel文档
        workbook.loadFromFile(fileName);
        // 获取第一个工作表 (您可以根据需要选择特定的工作表)
        Worksheet sheet = workbook.getWorksheets().get(0);

        // 定义输出图片的文件名和路径 (这里我们将其保存在临时目录)
        // 您可以根据需要更改保存路径和文件名逻辑
        File outputFile = File.createTempFile("excel_image_", ".png");
        // 将工作表保存为图片
        sheet.saveToImage(outputFile.getAbsolutePath());

        return outputFile;

    }

方式二aspose-cells(推荐设置分辨率转出的图片更清晰)

XML 复制代码
<dependency>
            <groupId>com.luhuiguo</groupId>
            <artifactId>aspose-cells</artifactId>
            <version>23.1</version>
        </dependency>
java 复制代码
package com.charsming.common.domain;

/**
 * 功能描述: 用于封装图片数据及其元数据的包装类。
 */
public class ImageDataWrapper {
    // 图片的字节数组
    private byte[] data;
    // 建议的下载文件名
    private String fileName;
    // 图片的MIME类型 (例如 "image/png")
    private String contentType;

    /**
     * 功能描述: ImageDataWrapper的构造函数。
     * 参数: data - 图片的字节数组。
     * 参数: fileName - 建议的下载文件名。
     * 参数: contentType - 图片的MIME类型。
     */
    public ImageDataWrapper(byte[] data, String fileName, String contentType) {
        this.data = data;
        this.fileName = fileName;
        this.contentType = contentType;
    }

    // Getter 方法
    public byte[] getData() {
        return data;
    }

    public String getFileName() {
        return fileName;
    }

    public String getContentType() {
        return contentType;
    }
}
java 复制代码
@GetMapping("/downloadImage/{id}")
    public ResponseEntity<InputStreamResource> downloadExcelAsImage(@PathVariable("id") String id, HttpServletResponse response) throws Exception {
        try {
            // logger.info("请求下载图片,ID: {}", id); // 日志记录
            ImageDataWrapper imageData = resultHistoryService.convertExcelToImageData(id);
            HttpHeaders headers = new HttpHeaders();
            // 设置Content-Disposition,提示浏览器下载并指定文件名
            headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + imageData.getFileName() + "\"");
            // 其他缓存控制相关的头信息 (可选,但推荐)
            headers.add(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, must-revalidate");
            headers.add(HttpHeaders.PRAGMA, "no-cache");
            headers.add(HttpHeaders.EXPIRES, "0");
            InputStreamResource resource = new InputStreamResource(new ByteArrayInputStream(imageData.getData()));
            // logger.info("成功生成图片: {}, 大小: {} bytes", imageData.getFileName(), imageData.getData().length); // 日志记录
            return ResponseEntity.ok()
                    .headers(headers)
                    .contentLength(imageData.getData().length)
                    .contentType(MediaType.parseMediaType(imageData.getContentType()))
                    .body(resource);

        } catch (Exception e) {
            // logger.error("下载图片失败,ID: {}. 错误: {}", id, e.getMessage(), e); // 记录异常堆栈
            // 在发生错误时,返回一个带有错误信息的ResponseEntity
            // 您可以根据需要定制错误响应的格式,例如返回一个JSON对象
            String errorMessage = "下载图片失败: " + e.getMessage();
            InputStreamResource errorResource = new InputStreamResource(
                    new ByteArrayInputStream(errorMessage.getBytes(java.nio.charset.StandardCharsets.UTF_8))
            );
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .contentType(MediaType.TEXT_PLAIN)
                    .body(errorResource);
        }
java 复制代码
@Override
    public ImageDataWrapper convertExcelToImageData(String id) throws Exception {
        ResultHistoryDO resultHistoryDO = resultHistoryDao.get(id);
        if (resultHistoryDO == null || resultHistoryDO.getFileurl() == null) {
            throw new Exception("未找到ID为 " + id + " 的结果历史记录或文件路径为空。");
        }
        String uploadPath = bootdoConfig.getUploadPath();
        String fileurl = resultHistoryDO.getFileurl();
        // 注意:此处的分割逻辑可能需要根据您的实际fileurl格式调整
        String[] split = fileurl.split("/files/");
        if (split.length < 2) {
            throw new Exception("文件路径格式不正确,无法提取文件名: " + fileurl);
        }
        String excelFilePath = uploadPath + split[1];
        Workbook workbook = null;
        // 使用try-with-resources确保baos关闭
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            workbook = new Workbook(excelFilePath);
            Worksheet worksheet = workbook.getWorksheets().get(0);

            // --- 全局修改默认字体 开始 ---
            Style defaultStyle = workbook.getDefaultStyle();
            Font defaultFont = defaultStyle.getFont();
            defaultFont.setName("Times New Roman"); // 设置全局默认字体名称
            defaultFont.setSize(11);   // 设置全局默认字体大小
            // defaultFont.setBold(false); // 根据需要设置其他属性
            workbook.setDefaultStyle(defaultStyle); // 应用修改后的默认样式到整个工作簿

            ImageOrPrintOptions imgOptions = new ImageOrPrintOptions();
            imgOptions.setImageType(ImageType.PNG);
            imgOptions.setHorizontalResolution(800);
            imgOptions.setVerticalResolution(800);
            SheetRender sr = new SheetRender(worksheet, imgOptions);
            if (sr.getPageCount() > 0) {
                // 渲染第一页
                int pageIndexToRender = 0;
                sr.toImage(pageIndexToRender, baos);
                // baos.flush(); // ByteArrayOutputStream的flush是空操作,可以省略
                byte[] imageBytes = baos.toByteArray();
                String originalFileName = new File(excelFilePath).getName();
                String baseName = originalFileName.contains(".") ? originalFileName.substring(0, originalFileName.lastIndexOf('.')) : originalFileName;
                String suggestedFileName = baseName  + (pageIndexToRender + 1) + ".png";
                String contentType = "image/png";
                return new ImageDataWrapper(imageBytes, suggestedFileName, contentType);
            } else {
                throw new Exception("Excel工作表 " + excelFilePath + " 为空或无法渲染成图片。");
            }
        } finally {
            if (workbook != null) {
                // 根据Aspose.Cells文档,Workbook类实现了IDisposable接口,
                // 在.NET中通常用using语句处理。在Java中,如果它有close()或dispose()方法,应在此调用。
                // 查阅文档,Aspose.Cells for Java 通常不需要显式调用 workbook.dispose(),垃圾回收器会处理。
                // 但如果遇到内存问题,可以检查是否有相关API。
            }
        }
    }
javascript 复制代码
async function downloadImage(imageId) {
    // 构建下载文件的 URL
    const downloadUrl = `${prefix}/downloadImage/${imageId}`;
    let loadingIndex; // 用于存储 Layui 加载层的索引
    try {
        loadingIndex = layer.load(1);
        // 使用 fetch API 发送 GET 请求
        const response = await fetch(downloadUrl, {
            method: 'GET', // 后端是 @GetMapping,所以前端也用 GET
            cache: 'no-cache', // 根据你的后端设置,这里也禁用缓存
        });
        // 检查响应是否成功
        if (!response.ok) {
            // 如果服务器返回错误状态 (如 404, 500)
            // 你可以根据 response.status 和 response.statusText 来处理不同类型的错误
            const errorText = await response.text(); // 尝试获取错误信息文本
            throw new Error(`服务器错误: ${response.status} ${response.statusText}. ${errorText}`);
        }
        // 从响应头中获取文件名
        // 后端设置了 Content-Disposition: attachment; filename=...
        const contentDisposition = response.headers.get('content-disposition');
        let filename = `image_${imageId}.png`; // 默认文件名,如果无法从头部获取
        if (contentDisposition) {
            const filenameMatch = contentDisposition.match(/filename\*?=['"]?(?:UTF-\d['"]*)?([^;"\n]*)/i);
            if (filenameMatch && filenameMatch[1]) {
                filename = decodeURIComponent(filenameMatch[1]);
            }
        }
        // 将响应体转换为 Blob 对象
        const blob = await response.blob();
        // 创建一个指向 Blob 的 URL
        const objectUrl = window.URL.createObjectURL(blob);
        // 创建一个临时的 <a> 标签用于触发下载
        const link = document.createElement('a');
        link.href = objectUrl;
        link.setAttribute('download', filename); // 设置下载的文件名
        document.body.appendChild(link);
        // 触发点击
        link.click();
        // 清理:移除 <a> 标签并释放 Object URL
        document.body.removeChild(link);
        window.URL.revokeObjectURL(objectUrl);
        // 如果你使用了 parent.layer.alert,可以在这里提示成功
        if (parent && parent.layer) {
            parent.layer.alert("图片下载成功!");
        }

    } catch (error) {
        console.error('下载图片时发生错误:', error);
        // 如果你使用了 parent.layer.alert,可以在这里提示错误
        if (parent && parent.layer) {
            parent.layer.alert(`连接或下载错误: ${error.message}`);
        }
        throw error; // 重新抛出错误,以便调用者可以进一步处理
    }
    finally {
            layer.close(loadingIndex);
    }
}


// 如果你仍然想在类似 $.ajax 的结构中使用,可以这样包装:
function triggerDownloadWithAjaxLikeStructure(imageId) {
    // 这里不再需要 $('#signupForm').serialize(),因为 ID 是直接传递的
    // 也不再需要 type: "POST",因为下载是 GET
    // async: false 非常不推荐,fetch 默认就是异步的,应该使用 Promise 处理

    downloadImage(imageId)
        .then(() => {
            // 成功回调,提示已经在 downloadImage 函数内部处理
            // 你可以在这里添加额外的成功逻辑
            console.log('图片下载流程成功完成。');
        })
        .catch(error => {
            // 错误回调,提示已经在 downloadImage 函数内部处理
            // 你可以在这里添加额外的错误处理逻辑
            console.error('图片下载流程发生错误。', error);
        });
}
javascript 复制代码
 triggerDownloadWithAjaxLikeStructure(id)
相关推荐
llm2 分钟前
MediaPlayer介绍
java·架构
橙序员小站2 分钟前
仍然嫌GC卡顿?新一代低延迟GC了解一下
java·jvm·性能优化
_oP_i7 分钟前
移除 Excel 文件(.xlsx)的工作表保护
excel
handsomestWei14 分钟前
Cursor Java开发配置
java·ai编程·环境配置·cursor
Y40900123 分钟前
Java基础——实现图书管理系统交互功能
java·开发语言·笔记·交互
LiuYaoheng32 分钟前
【Android】使用 Intent 传递对象的两种序列化方式
android·java·笔记·学习
寒水馨1 小时前
Java 24 新特性解析与代码示例
java·开发语言·新特性·jdk24·java24
奋进的孤狼1 小时前
【Java】在一个前台界面中动态展示多个数据表的字段及数据
java·数据库·oracle
IT利刃出鞘2 小时前
Intellij Idea--解决Cannot download “https://start.spring.io‘: Connect timedout
java·ide·intellij-idea