java实现word文档的导出功能

声明:文章参考 【java 导出word文档 - CSDN App】http://t.csdnimg.cn/WcaP7

1.准备模板

对于表格的域需要带个自定义的前缀,如下

2.导入maven依赖

<dependency>
			<groupId>org.jxls</groupId>
			<artifactId>jxls</artifactId>
			<version>2.6.0</version>
			<exclusions>
				<exclusion>
					<groupId>ch.qos.logback</groupId>
					<artifactId>logback-core</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.jxls</groupId>
			<artifactId>jxls-poi</artifactId>
			<version>1.2.0</version>
		</dependency>
		<dependency>
			<groupId>fr.opensagres.xdocreport</groupId>
			<artifactId>fr.opensagres.xdocreport.core</artifactId>
			<version>2.0.2</version>
		</dependency>
		<dependency>
			<groupId>fr.opensagres.xdocreport</groupId>
			<artifactId>fr.opensagres.xdocreport.document</artifactId>
			<version>2.0.2</version>
		</dependency>
		<dependency>
			<groupId>fr.opensagres.xdocreport</groupId>
			<artifactId>fr.opensagres.xdocreport.template</artifactId>
			<version>2.0.2</version>
		</dependency>
		<dependency>
			<groupId>fr.opensagres.xdocreport</groupId>
			<artifactId>fr.opensagres.xdocreport.document.docx</artifactId>
			<version>2.0.2</version>
		</dependency>
		<dependency>
			<groupId>fr.opensagres.xdocreport</groupId>
			<artifactId>fr.opensagres.xdocreport.template.freemarker</artifactId>
			<version>2.0.2</version>
		</dependency>


		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi</artifactId>
			<version>3.16</version>
		</dependency>


		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml</artifactId>
			<version>3.14</version>
		</dependency>
        <dependency>
			<groupId>commons-io</groupId>
			<artifactId>commons-io</artifactId>
			<version>2.5</version>
		</dependency>

3.导入工具类 

package io.renren.modules.recycle.api.utils;

import fr.opensagres.xdocreport.core.XDocReportException;
import fr.opensagres.xdocreport.document.IXDocReport;
import fr.opensagres.xdocreport.document.registry.XDocReportRegistry;
import fr.opensagres.xdocreport.template.IContext;
import fr.opensagres.xdocreport.template.TemplateEngineKind;

import java.io.FileInputStream;
import java.io.InputStream;

public class WordUtil {

    /**
     * 获取 Word 模板的两个操作对象 IXDocReport 和 IContext
     * @param path 模板绝对地址
     * @return 模板数据对象
     */
    public static ExportData createExportData(String path) {
        try {
            IXDocReport report = createReport(path);
            IContext context = report.createContext();
            return new ExportData(report, context);
        } catch (XDocReportException ex) {
            throw new RuntimeException(ex.getMessage());
        }
    }

    /**
     * 加载模板的方法,主要是指定模板的路径和选择渲染数据的模板
     * @param url 模板相对于类路径的地址
     * @return word 文档操作类
     */
    private static IXDocReport createReport(String url) {
        try (
                InputStream in = new  FileInputStream(url);
        ) {
            IXDocReport ix = XDocReportRegistry.getRegistry().loadReport(in, TemplateEngineKind.Freemarker);
            return ix;
        } catch (Exception ex) {
            throw new RuntimeException(ex.getMessage());
        }
    }

}
package io.renren.modules.recycle.api.utils;

import fr.opensagres.xdocreport.document.IXDocReport;
import fr.opensagres.xdocreport.document.images.ByteArrayImageProvider;
import fr.opensagres.xdocreport.document.images.IImageProvider;
import fr.opensagres.xdocreport.template.IContext;
import fr.opensagres.xdocreport.template.formatter.FieldsMetadata;
import org.springframework.core.io.ClassPathResource;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class ExportData {

    private IXDocReport report;
    private IContext context;

    /**
     * 构造方法
     * @param report
     * @param context
     */
    public ExportData(IXDocReport report, IContext context) {
        this.report = report;
        this.context = context;
    }

    /**
     * 设置普通数据,包括基础数据类型,数组,试题对象
     * 使用时,直接 ${key.k} 或者 [#list d as key]
     * @param key   健
     * @param value 值
     */
    public void setData(String key, Object value) {
        context.put(key, value);
    }

    /**
     * 设置表格数据,用来循环生成表格的 List 数据
     * 使用时,直接 ${key.k}
     * @param key   健
     * @param maps List 集合
     */
    public void setTable(String key, List<SoMap> maps) {
        FieldsMetadata metadata = report.getFieldsMetadata();
        metadata = metadata == null ? new FieldsMetadata() : metadata;
        SoMap map = maps.get(0);
        for (String kk : map.keySet()) {
            metadata.addFieldAsList(key + "." + kk);
        }
        report.setFieldsMetadata(metadata);
        context.put(key, maps);
    }

    /**
     * 设置图片数据
     * 使用时 直接在书签出 key
     * @param key 健
     * @param url 图片地址
     */
    public void setImg(String key, String url) {
        FieldsMetadata metadata = report.getFieldsMetadata();
        metadata = metadata == null ? new FieldsMetadata() : metadata;
        metadata.addFieldAsImage(key);
        report.setFieldsMetadata(metadata);
        try (
                InputStream in = new ClassPathResource(url).getInputStream();
        ) {
            IImageProvider img = new ByteArrayImageProvider(in);
            context.put(key, img);
        } catch (IOException ex) {
            throw new RuntimeException(ex.getMessage());
        }
    }

    /**
     * 获取文件流数据
     * @return 文件流数组
     */
    public byte[] getByteArr() {
        try (
                ByteArrayOutputStream out = new ByteArrayOutputStream();
        ) {
            report.process(context, out);
            return out.toByteArray();
        } catch (Exception ex) {
            ex.printStackTrace();
            throw new RuntimeException(ex.getMessage());
        }
    }
}
package io.renren.modules.recycle.api.utils;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.HashMap;

/**
 * @Author: linbo
 * @Date: 2022/1/4 11:38
 * @Version 1.0
 */
public class SoMap extends HashMap<String, Object> {


    public SoMap() { }

    /**
     * 构造方法,将任意实体类转化为 Map
     * @param obj
     */
    public SoMap(Object obj) {
        Class clazz = obj.getClass();
        Field[] fields = clazz.getDeclaredFields();
        try {
            for (Field field : fields) {
                field.setAccessible(true);
                this.put(field.getName(), field.get(obj));
            }
        } catch (IllegalAccessException ex) {
            throw new RuntimeException(ex.getMessage());
        }
    }

    /**
     * 将 Map 转化为 任意实体类
     * @param clazz 反射获取类字节码对象
     * @return
     */
    public <T> T toEntity(Class<T> clazz) {
        Field[] fields = clazz.getDeclaredFields();
        try {
            Constructor constructor = clazz.getDeclaredConstructor();
            T t = (T) constructor.newInstance();
            for (Field field : fields) {
                field.setAccessible(true);
                field.set(t, this.get(field));
            }
            return t;
        } catch (Exception ex) {
            throw new RuntimeException(ex.getMessage());
        }
    }

    /**
     * 从集合中获取一个字段的方法,如果字段不存在返回空
     * @param key  字段的唯一标识
     * @param <T>  字段的类型,运行时自动识别,使用时无需声明和强转
     * @return     对应字段的值
     */
    public <T> T get(String key) {
        return (T) super.get(key);
    }

}

4.导入表格内变量实体类

package io.renren.modules.recycle.api.dto;


import lombok.Data;

import java.io.Serializable;

/**
 * @Author: 表格变量实体类
 * @Date: 2023/11/9 13:47
 */
@Data
public class ReportVo  implements Serializable {
    private static final long serialVersionUID = 1L;

    private String profession;
    private String topic;

}

5.数据库实体类

package io.renren.modules.recycle.api.entity;

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

@Data
@TableName("report")
public class ReportEntity {
    private Integer id;
    private Integer userId;
    // 专业
    private String profession;
    // 题目
    private String topic;
    // 中文摘要
    private String abstractCn;
    // 英文摘要
    private String abstractEn;
    //中文关键词
    private String keywordCn;
    //英文关键词
    private String keywordEn;

}

6.service层

package io.renren.modules.recycle.api.service;

public interface ReportService {

    public byte[] getSQLWordByte(Integer id);
}

serviceImpl

package io.renren.modules.recycle.api.service.impl;

import io.renren.modules.recycle.api.dao.ReportDao;
import io.renren.modules.recycle.api.dto.ReportVo;
import io.renren.modules.recycle.api.entity.ReportEntity;
import io.renren.modules.recycle.api.service.ReportService;
import io.renren.modules.recycle.api.utils.ExportData;
import io.renren.modules.recycle.api.utils.SoMap;

import io.renren.modules.recycle.api.utils.WordUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;

@Service
public class ReportServiceImpl implements ReportService {
    /**
     * 模型路径
     */
    @Value("${report.model-path-day}")
    private String MODEL_PATH_DAY;

    @Resource
    private ReportDao reportDao;


    @Override
    public byte[] getSQLWordByte(Integer id) {

        //模拟从数据库 根据id 查数据然后插入
        final ReportEntity reportEntity = reportDao.selectById(id);
        if (reportEntity==null){
            return null;
        }

        //准备数据
        ExportData evaluation = WordUtil.createExportData(MODEL_PATH_DAY);
        //填充数据
        evaluation.setData("profession",reportEntity.getProfession());
        evaluation.setData("topic",reportEntity.getTopic());
        evaluation.setData("abstract",reportEntity.getAbstractCn());
        evaluation.setData("abstractEn",reportEntity.getAbstractEn());
        evaluation.setData("keyword",reportEntity.getKeywordCn());
        evaluation.setData("keywordEn",reportEntity.getKeywordEn());
        //填充表格里的专业和题目
        final ReportVo reportVo = new ReportVo();
        reportVo.setProfession(reportEntity.getProfession());
        reportVo.setTopic(reportEntity.getTopic());
        final ArrayList<SoMap> videoList = new ArrayList<SoMap>();
        videoList.add(new SoMap(reportVo));
        //创建word模板时自定义的表格前缀
        evaluation.setTable("video",videoList);
        //获取新生成的文件流
        byte[] data = evaluation.getByteArr();
        return data;
    }

}

7.controller层

package io.renren.modules.recycle.api.controller;

import io.renren.modules.recycle.api.service.ReportService;
import io.renren.modules.recycle.api.utils.ResUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.UUID;

@RestController
@RequestMapping("/app/recycle/report")
@Slf4j
public class ReportController {


    @Resource
    private ReportService reportService;

    @GetMapping("/sql/export")
    public Object exportSQL(HttpServletRequest request) {

        //根据文章id从数据库查询,然后导出word
        //这里测试用,所以写死id为1,实际应该是接口传入 id
        byte[] data = reportService.getSQLWordByte(1);

        return ResUtil.getStreamData(request,data,UUID.randomUUID().toString(),"docx");
    }
}

8.yml配置,把word模板放置在指定文件夹里,并配置yml

report:
  model-path-day: "D://ceshi.docx"  # word模板地址

9.打开浏览器访问自己的接口地址

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值