Java实现动态生成word报告

news2024/12/20 16:18:11

Java实现动态生成word报告

1.准备好docx文件模板

举例:动态生成表格数据,以下是list数组类型的freemarker语法

在这里插入图片描述

将写好的word模板加入到templates目录下
在这里插入图片描述

2.在pom.xml中导入相关依赖

		<dependency>
			<groupId>fr.opensagres.xdocreport</groupId>
			<artifactId>fr.opensagres.xdocreport.document.docx</artifactId>
			<version>2.0.3</version>
		</dependency>
            <dependency>
			<groupId>io.minio</groupId>
			<artifactId>minio</artifactId>
			<version>8.2.1</version>
		</dependency>

3.关于Minio的介绍

Minio 是一个开源的对象存储服务器,可用于存储和访问海量数据。以下是 Minio 的基本用法:

(1)安装 Minio

首先,你需要下载和安装 Minio。你可以从 Minio 的官方网站(https://min.io/)下载适用于你的操作系统的安装包,然后按照 Minio 的安装说明进行操作。

(2)启动 Minio

安装完成后,你可以通过运行以下命令来启动 Minio:

bash复制代码

minio server /path/to/data

其中 /path/to/data 是你用于存储数据的目录或磁盘空间。

(3)访问 Minio

一旦 Minio 启动成功,你就可以使用 Web 浏览器、命令行工具或 SDK 来访问和操作 Minio。

  • Web 浏览器:在浏览器中输入 Minio 的访问地址(默认为 localhost:9000),即可看到 Minio 的管理界面。你可以使用默认的用户名和密码(分别为 miniominio123)登录。
  • 命令行工具:你可以使用 Minio 提供的命令行工具(如 mcbs)来访问和操作 Minio。这些工具提供了丰富的命令行选项和 SDK,方便你进行数据的上传、下载、备份、恢复等操作。
  • SDK:Minio 还提供了多种编程语言的 SDK,如 Java、Python、Go、JavaScript 等。你可以使用这些 SDK 在应用程序中集成 Minio 的功能,以便更方便地管理和操作数据。

总之,使用 Minio 可以通过简单的安装和配置,快速构建一个可靠的对象存储服务,方便你存储和访问海量数据。

4.在application.yml中添加Minio配置

minio:
//host和port自行填写
  endpoint: http://127.0.0.1:9000
  accessKey: minio
  secretKey: minio123
  bucketName: carbon
  expires: 86400

5.导入MinioConfig配置类

@Data
@Configuration
public class MinioConfig {

    @Value("${minio.endpoint}")
    private String endpoint;

    @Value("${minio.bucketName}")
    private String bucketName;

    @Value("${minio.accessKey}")
    private String accessKey;

    @Value("${minio.secretKey}")
    private String secretKey;

    @Value("${minio.expires}")
    private Integer expires = 86400;

}

6.导入UploadFileService类与其实现类UploadFileServiceImpl(直接CV过去)

public interface UploadFileService {

    void createBucket(String bucketName);

    /**
     * 获取全部bucket
     * <p>
     * https://docs.minio.io/cn/java-client-api-reference.html#listBuckets
     */
    List<Bucket> getAllBuckets();

    /**
     * 根据bucketName获取信息
     *
     * @param bucketName bucket名称
     */
    // @SneakyThrows
    Optional<Bucket> getBucket(String bucketName);

    /**
     * 根据bucketName删除信息
     *
     * @param bucketName bucket名称
     */
    void removeBucket(String bucketName);

    /**
     * 根据文件前置查询文件
     *
     * @param bucketName bucket名称
     * @param prefix     前缀
     * @param recursive  是否递归查询
     * @return MinioItem 列表
     */
    List getAllObjectsByPrefix(String bucketName, String prefix, boolean recursive);

    /**
     * 获取文件外链
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @param expires    过期时间 <=7
     * @return url
     */
    String getObjectURL(String bucketName, String objectName, Integer expires);

    /**
     * 获取文件
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @return 二进制流
     */
    InputStream getObject(String bucketName, String objectName);

    /**
     * 上传文件
     *
     * @param bucketName bucket名称
     * @param stream     文件流
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#putObject
     */
    void putObject(String bucketName, String objectName, InputStream stream);

    /**
     * 上传文件
     *
     * @param bucketName  bucket名称
     * @param objectName  文件名称
     * @param stream      文件流
     * @param size        大小
     * @param contextType 类型
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#putObject
     */
    void putObject(String bucketName, String objectName, InputStream stream, long size, String contextType);

    /**
     * 获取文件信息, 如果抛出异常则说明文件不存在
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#statObject
     */
    StatObjectResponse getObjectInfo(String bucketName, String objectName);

    /**
     * 删除文件
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#removeObject
     */
    boolean removeObject(String bucketName, String objectName) throws Exception;
}

@Slf4j
@Service
public class UploadFileServiceImpl implements UploadFileService {

    private MinioClient minioClient;

    @Autowired
    MinioConfig minioConfig;

    @PostConstruct
    public void init() {
        this.minioClient =
                MinioClient.builder()
                        .endpoint(minioConfig.getEndpoint())
                        .credentials(minioConfig.getAccessKey(), minioConfig.getSecretKey())
                        .build();
    }

    @Override
    @SneakyThrows
    public void createBucket(String bucketName) {
        if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        }
    }

    @Override
    @SneakyThrows
    public List<Bucket> getAllBuckets() {
        // 列出所有存储桶
        return minioClient.listBuckets();
    }

    @Override
    @SneakyThrows
    public Optional<Bucket> getBucket(String bucketName) {
        return minioClient.listBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();
    }

    @Override
    @SneakyThrows
    public void removeBucket(String bucketName) {
        // 删除之前先检查bucketName是否存在。
        boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        if (found) {
            // 删除bucketName存储桶,注意,只有存储桶为空时才能删除成功。
            minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
        } else {
            log.info(bucketName + "does not exist");
        }
    }

    @Override
    @SneakyThrows
    public List getAllObjectsByPrefix(String bucketName, String prefix, boolean recursive) {
        List<Item> list = new ArrayList<>();
        Iterable<Result<Item>> objectsIterator = minioClient.listObjects(
                ListObjectsArgs.builder().bucket(bucketName).prefix(prefix)
                        .recursive(recursive).build()
        );
        if (objectsIterator != null) {
            Iterator<Result<Item>> iterator = objectsIterator.iterator();
            if (iterator != null) {
                while (iterator.hasNext()) {
                    Result<Item> result = iterator.next();
                    Item item = result.get();
                    list.add(item);
                }
            }
        }

        return list;
    }

    @Override
    @SneakyThrows
    public String getObjectURL(String bucketName, String objectName, Integer expires) {
        return minioClient.getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                        .method(Method.GET)
                        .bucket(bucketName)
                        .object(objectName)
                        .expiry(expires, TimeUnit.DAYS)
                        .build());
    }

    @Override
    @SneakyThrows
    public InputStream getObject(String bucketName, String objectName) {
        return minioClient.getObject(GetObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .build());
    }

    @Override
    @SneakyThrows
    public void putObject(String bucketName, String objectName, InputStream stream) {
        // 检查存储桶是否已经存在
        if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        }
        minioClient.putObject(
                PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(
                        stream, stream.available(), -1)
                        .build());
    }

    @Override
    @SneakyThrows
    public void putObject(String bucketName, String objectName, InputStream stream, long size, String contextType) {
        minioClient.putObject(
                PutObjectArgs.builder().bucket(bucketName)
                        .object(objectName).stream(stream, size, -1)
                        .contentType(contextType).build());
    }

    @Override
    @SneakyThrows
    public StatObjectResponse getObjectInfo(String bucketName, String objectName) {
        StatObjectResponse statObjectResponse = minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
        return statObjectResponse;
    }

    @Override
    public boolean removeObject(String bucketName, String objectName) throws Exception {
        try {
            minioClient.removeObject(
                    RemoveObjectArgs.builder()
                            .bucket(bucketName)
                            .object(objectName)
                            .build());
        } catch (Exception e) {
            return false;
        }
        return true;
    }
}

7.编写ReportData类

@Slf4j
@Data
@Component
public class ReportData {
//generateReport可加入需要的参数
    public String generateReport() throws IOException, XDocReportException {
        //通过freemarker模板引擎加载文档,并缓存到registry中
        ClassPathResource resource= new ClassPathResource("templates/report.docx");
        InputStream input = resource.getInputStream();
        IXDocReport report = XDocReportRegistry
                .getRegistry()
                .loadReport(input, TemplateEngineKind.Freemarker);

        //匹配填充字段和填充数据,进行填充
        IContext context = report.createContext();
        //获取要放入报告的数据(省略),假设获取到了一个list数组dataList
        

        //context.put(" ", )放入相应的数据,可在word模板中动态调用
        context.put("time", LocalDateTime.now());
        context.put("dataList",dataList);

        ByteArrayOutputStream output = new ByteArrayOutputStream();
        report.process(context, output);
        
        ByteArrayInputStream inputStream = new ByteArrayInputStream(output.toByteArray());
         String objectName = "Document/"+"报告.docx";
        uploadFileService.putObject(minioConfig.getBucketName(),objectName, inputStream);
        return objectName;
    }
}

8.controller层调用

 @RequestMapping(value = "/reportExport", method = RequestMethod.POST)
//UserServiceByReportExport中可填写所需参数
    public void UserServiceByReportExport(HttpServletRequest request, HttpServletResponse response) throws IOException, XDocReportException {
        // TODO 使用预置的word文档导出
        String objectName = reportData.generateReport();
        Optional<InputStream> inputOp = Optional.of(uploadFileService.getObject(minioConfig.getBucketName(), objectName));
        if (!inputOp.isPresent()) {
            throw new NullPointerException("报告生成失败");
        }

        try (InputStream input1 = inputOp.get();
             OutputStream output1 = response.getOutputStream()) {
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            response.addHeader("Content-Disposition",
                    "attachment;filename=" + URLEncoder.encode( "报告.docx", "UTF-8"));
            response.setHeader("Access-Control-Expose-Headers","Content-Disposition");
            IoUtils.copy(input1, output1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

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

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

相关文章

react antd checkbox实现全选,多选

背景 目前好像只有table组件有实现表格数据的全选功能&#xff0c;如果说对于list&#xff0c;card&#xff0c;collapse等其他组件来说&#xff0c;需要自己结合checkbox来手动实现全选功能。 Checkbox.Group有实现全选功能&#xff0c;但是对于需要遍历出来的数据&#xff…

人民大学与加拿大女王大学金融硕士——原来“鱼和熊掌”可以兼得

“鱼和熊掌”不可兼得&#xff0c;我们从小就听到过这句话。随着长大&#xff0c;随着能力增强&#xff0c;两者我们都想要。就像在中国人民大学与加拿大女王大学金融硕士项目读研&#xff0c;我们不只要获得毕业证书&#xff0c;我们还要学到真本领。你的愿望在人大女王金融硕…

Ubuntu18.04离线安装Nginx

因需要安装nginx的服务器无法连接互联网&#xff0c;所以需要离线安装。首先需要下载nginx的安装包&#xff0c;之后进行安装&#xff0c;在安装之前需要保证gcc&#xff0c;g&#xff0c;make等依赖包已经安装。 因为是需要离线安装&#xff0c;所以在之前是用的一台互联网下载…

Java选择题刷题记录1

LinkedList类继承自AbstractSequentialList ArrayList listnew ArrayList(); 这种是默认创建大小为10的数组&#xff0c;每次扩容大小为1.5倍&#xff1b;ArrayList listnew ArrayList(20);这种是指定数组大小的创建&#xff0c;创建时直接分配其大小&#xff0c;扩充0次 Ite…

naive-ui NPopconfirm怎么用vue3的h()渲染

先看效果 然后我先贴代码&#xff0c; 你们看懂的先运行下&#xff0c; 文章后面我教你怎么 添加这种有template&#xff0c;有slot插槽的组件 h(NPopconfirm,{positiveButtonProps: {size: tiny,color: #007293,bordered: true,},negativeButtonProps: {size: tiny,color: #…

解决添加上@RequiresPermissions权限注解后无法访问接口,swagger读取不到的问题

目录 一、先搭建 Swagger 1、添加依赖库 2、创建Swagger配置类 3、配置yml 4、编写测试Web接口 5、测试Web接口 二、解决问题 1、出现的问题 2、解决问题 一、先搭建 Swagger 开发前后端分离架构的项目&#xff0c;往往调试后端Web接口需要用到POSTMAN工具。虽然POSTM…

智安网络|人工智能蔓延,网络安全所面临的威胁和应对之道

随着人工智能&#xff08;Artificial Intelligence&#xff0c;AI&#xff09;技术的快速发展和广泛应用&#xff0c;我们进入了一个智能时代&#xff0c;人工智能已经蔓延到我们生活的方方面面。然而&#xff0c;与其带来的方便和创新相伴随的是网络安全所面临的新威胁。 【威…

记录一下RocketMQ中遇见的 连环大坑!!!差点没把我摔死

目录 环境&#xff1a;Win10 &#xff0c; 不是 linux 首先我遇见的第一个问题是&#xff1a; No route info of this topic 问题原因&#xff1a; PS&#xff1a; 64位系统环境下&#xff0c;如果软件在安装时安装路径默认c:\progarmfiles即为64位&#xff0c;默认c:\pr…

Sharding-JDBC之PreciseShardingAlgorithm(精确分片算法)

目录 一、简介二、maven依赖三、数据库3.1、创建数据库3.2、创建表 四、配置&#xff08;二选一&#xff09;4.1、properties配置4.2、yml配置 五、精确分片算法5.1、精确分库算法5.2、精确分表算法 六、实现6.1、实体层6.2、持久层6.3、服务层6.4、测试类6.4.1、保存订单数据6…

ai画图怎么弄?简单几步教会你如何用ai绘画

艺术创作一直是人类文明发展的重要组成部分&#xff0c;在当今数字化时代&#xff0c;ai技术的不断进步也为我们带来了全新的创作方式。在这其中&#xff0c;ai绘画软件因其独特的创作方式和优秀的绘画效果受到了广泛关注和喜爱。使用ai绘画软件可以让我们轻松地创作出各种风格…

关于数据仓库那点事,一文捋清

借助海量的数据&#xff0c;企业进行了深层次的数字化改革&#xff0c;把数据当成了企业发展的核心&#xff0c;但无效的数据即使规模再大&#xff0c;也对企业没有意义&#xff0c;所以数据质量也就愈发重要。 数据仓库 事实上&#xff0c;很多人在看到数据仓库的第一眼&…

【夜深人静学数据结构与算法 | 第四篇】手撕二叉树遍历

目录 前言&#xff1a; 二叉树遍历方式&#xff1a; 手撕前中后序遍历&#xff08;递归&#xff09;的三大准备 深度优先搜索&#xff1a; 手撕前中后遍历&#xff08;递归&#xff09;&#xff1a; 手撕前中后序遍历&#xff08;迭代&#xff09;&#xff1a; 深度优先…

经典Java面试题收集

1、面向对象的特征有哪些方面&#xff1f; 答&#xff1a;面向对象的特征主要有以下几个方面&#xff1a; 抽象&#xff1a;抽象是将一类对象的共同特征总结出来构造类的过程&#xff0c;包括数据抽象和行为抽象两方面。抽象只关注对象有哪些属性和行为&#xff0c;并不关注这…

EHCI接口概述(三)

EHCI主机接口寄存器在BAR0所示的PCI MEM地址空间中&#xff0c;主要包括两部分&#xff1a; 1&#xff09;能力寄存器组 2&#xff09;操作寄存器组 下面先介绍能力寄存器组 CAPLENGTH寄存器&#xff0c;8位只读寄存器&#xff0c;给出了控制寄存器组的偏移量。 HCIVERSION…

springboot+vue项目之CSGO赛事管理系统(java项目源码+文档)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的CSGO赛事管理系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 &#x1f495;&#x1f495;作者&#xff1a;风…

C语言:求两个数二进制中不同位的个数

题目&#xff1a; 编程实现&#xff1a;两个int&#xff08;32位&#xff09;整数 m 和 n 的二进制表达中&#xff0c;有多少个位(bit)不同&#xff1f; 输入例子 : 1999 2299 输出例子 : 7 思路&#xff1a; 总体思路&#xff1a; 把 m 异或 n 后&#xff0c;有几个相异就有几…

抢占父亲节市场:2023年出海品牌的海外网红营销策略揭秘

随着社交媒体的迅猛发展和全球化的趋势&#xff0c;网红营销已经成为品牌推广的一种重要方式。在父亲节这个特殊的节日里&#xff0c;出海品牌可以通过巧妙利用网红的影响力来推动产品销售和品牌知名度的提升。本文Nox聚星将详细介绍如何通过海外网红营销来提升品牌知名度和销售…

HarmonyOS学习路之开发篇—Java UI框架(动画开发)

动画开发 动画是组件的基础特性之一&#xff0c;精心设计的动画使UI变化更直观&#xff0c;有助于改进应用程序的外观并改善用户体验。Java UI框架提供了帧动画、数值动画和属性动画&#xff0c;并提供了将多个动画同时操作的动画集合。 帧动画 帧动画是利用视觉暂留现象&…

[电离层建模学习笔记]开源程序M_GIM学习记录

[电离层建模学习笔记]开源程序M_GIM学习记录 文章目录 [电离层建模学习笔记]开源程序M_GIM学习记录1. 程序相关信息2. 程序学习记录2.1 采用的数据说明2.2 程序运行前2.3 程序运行结果 3. 其他 1. 程序相关信息 开源程序M_GIM基于Matlab(Zhou et al., 2023)&#xff0c;用于实…