java xml模版导出word

生成word思路

WPS或者office编辑好word的样式,然后另存为word xml文档,将xml翻译为FreeMarker模板,最后用java来解析FreeMarker模板并输出Docx

配置变量

把需要注入的信息换成变量名称,比如几年几月用${d1}表示,全部替换后的格式如下图所示

word另存为xml文档

替换完成后另存为word xml格式的文档,如下图

将xml文件格式化
选定表格的动态生成范围,添加 list 标签,记得保存
动态表头

动态表格

把改好的XML文件存放到项目的resources文件夹下,(我这里模板比较多,就自己建了一个word文件夹)

导入依赖

<!-- 导出word -->
<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.30</version>
</dependency>

编写代码

control类

/**
     * 基于模板生成 Word 文档
     *
     * @param response response
     */
    @RequestMapping( value = "/wordExport", method = RequestMethod.POST )
    @ResponseBody
    @ApiOperation( value = "生成通知单", notes = "生成通知单", code = 200, produces = "application/json" )
    public void wordExport(@RequestBody List<JSONObject> jsonObjects,HttpServletResponse response) {
        wordService.wordExport(jsonObjects,response);
    }
WordService
 void wordExport(List<JSONObject> jsonObjects, HttpServletResponse response);
WordServiceImpl
package com.cnpc.epai.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.cnpc.epai.common.util.SpringManager;
import com.cnpc.epai.dto.WordInfo;
import com.cnpc.epai.service.WordService;
import com.cnpc.epai.utils.ObjectUtils;
import com.cnpc.epai.utils.WordUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.*;

@Service
public class WordServiceImpl implements WordService {

    @Resource
    private WordUtil wordUtil;


    @Override
    public void wordExport(List<JSONObject> jsonObjects, HttpServletResponse response) {
        List<WordInfo> userList = new ArrayList<>();
        int i = 0;
        Map<String, Object> templateParam = new HashMap<>(7);
        if (ObjectUtils.isNotEmpty(jsonObjects)) {
            templateParam.put("orgName", StringUtils.isBlank(jsonObjects.get(0).getString("orgName")) ? "" : jsonObjects.get(0).getString("orgName"));
            for (JSONObject jsonObject : jsonObjects) {
                userList.add(new WordInfo(++i,
                        StringUtils.isBlank(jsonObject.getString("orgName")) ? "" : jsonObject.getString("orgName"),
                        StringUtils.isBlank(jsonObject.getString("wellCommonName")) ? "" : jsonObject.getString("wellCommonName"),
                        "4",
                        "5",
                        "6",
                        "7",
                        "8",
                        "9",
                        StringUtils.isBlank(jsonObject.getString("reasonsInefficiency")) ? "" : jsonObject.getString("reasonsInefficiency"),
                        StringUtils.isBlank(jsonObject.getString("measureContent")) ? "" : jsonObject.getString("measureContent"),
                        StringUtils.isBlank(jsonObject.getString("measureObjective")) ? "" : jsonObject.getString("measureObjective"),
                        StringUtils.isBlank(jsonObject.getString("remark")) ? "" : jsonObject.getString("remark")));
            }
        }
        Calendar calendar = Calendar.getInstance();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
        String year = sdf.format(new Date());
        templateParam.put("date", LocalDate.now());
        templateParam.put("total", userList.size());
        templateParam.put("userList", userList);
        templateParam.put("year", year);
        templateParam.put("month", calendar.get(Calendar.MONTH));
        templateParam.put("userName", SpringManager.getCurrentUser().getDisplayName());
        wordUtil.generate(response, "/word", "通知单.xml", templateParam, "通知单Word");
    }
}

导出word工具类

package com.cnpc.epai.utils;

import freemarker.cache.ClassTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;

/**
 * Word 工具类
 *
 * @author sunyujie
 * 2024/9/20 11:48
 */
@Slf4j
@Component
public class WordUtil {

    /**
     * 基于模板生成 Word 文档
     *
     * @param response         response
     * @param basePackagePath  resources 目录下模板所在包路径
     * @param templateFileName 模板文件名
     * @param templateParam    模板参数
     * @param fileName         文件名
     */
    public void generate(HttpServletResponse response, String basePackagePath, String templateFileName, Object templateParam, String fileName) {
        try {
            // 设置 HTTP 响应的内容类型为 Microsoft Word 文档
            response.setContentType("application/msword");
            // 设置响应字符编码为 UTF-8
            response.setCharacterEncoding("utf-8");
            // 使用 URLEncoder 对文件名进行编码,以防止中文文件名在不同浏览器和操作系统下出现乱码问题
            String filename = URLEncoder.encode(fileName + "_" + System.currentTimeMillis(), "utf-8");
            // 设置响应头,指定文档将以附件的形式下载,并定义文件名
            response.setHeader("Content-disposition", "attachment;filename=" + filename + ".doc");
            // 创建 Freemarker 的 Configuration 对象,设置默认的不兼容改进选项
            Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
            configuration.setDefaultEncoding("utf-8");
            // 设置模板加载器,加载模板文件
            configuration.setTemplateLoader(new ClassTemplateLoader(getClass(), basePackagePath));
            Template t = configuration.getTemplate(templateFileName, "utf-8");
            // 创建 Writer 对象,用于将生成的文档写到输出流中,缓存区大小设为 10KB
            Writer out = new BufferedWriter(new OutputStreamWriter(response.getOutputStream(), StandardCharsets.UTF_8), 10240);
            // 将模型数据与模板结合生成 Word 文档,写入到 Writer 对象中
            t.process(templateParam, out);
            out.close();
        } catch (Exception e) {
            log.info("基于模板{}生成Word文档异常,异常原因:{}", templateFileName, e.getMessage(), e);
            throw new RuntimeException("生成Word文档异常,异常原因:" + e.getMessage());
        }
    }

    /**
     * 基于模板生成 Word 文档到指定文件夹
     *
     * @param outputDir        输出文件夹
     * @param basePackagePath  resources 目录下模板所在包路径
     * @param templateFileName 模板文件名
     * @param templateParam    模板参数
     * @param fileName         文件名
     */
    public void generate(String outputDir, String basePackagePath, String templateFileName, Object templateParam, String fileName) {
        try {
            // 创建 Freemarker 的 Configuration 对象,设置默认的不兼容改进选项
            Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
            configuration.setDefaultEncoding("utf-8");
            // 设置模板加载器,加载模板文件
            configuration.setTemplateLoader(new ClassTemplateLoader(getClass(), basePackagePath));
            Template t = configuration.getTemplate(templateFileName, "utf-8");
            // 构建输出文件的完整路径
            File outputFile = new File(outputDir, fileName + "_" + System.currentTimeMillis() + ".doc");
            // 创建 Writer 对象,用于将生成的文档写到输出流中,缓存区大小设为 10KB
            Writer out = new BufferedWriter(new OutputStreamWriter(Files.newOutputStream(outputFile.toPath()), StandardCharsets.UTF_8), 10240);
            // 将模型数据与模板结合生成 Word 文档,写入到 Writer 对象中
            t.process(templateParam, out);
            out.close();
        } catch (Exception e) {
            log.info("基于模板{}生成Word文档异常,异常原因:{}", templateFileName, e.getMessage(), e);
            throw new RuntimeException("生成Word文档异常,异常原因:" + e.getMessage());
        }
    }

}

在使用Java导出Word的过程中,有时会遇到用Office打开时报错“Word在试图打开文件时报错”的问题。这个错误通常是由于导出XML模板存在一些问题导致的。 首先,我们要确保生成的XML模板是符合Word的格式要求的。WordXML格式有一定的约束,如果XML模板的结构或内容不符合Word的要求,那么就会导致打开文件出错。因此,我们需要仔细检查生成的XML模板,确保其结构和内容是正确的。 其次,我们需要确保使用的Office版本与生成的XML模板兼容。不同版本的Office对XML格式的支持可能存在差异,如果生成的XML模板使用了某个Office版本不支持的特性,那么打开文件时也会出错。因此,我们需要根据使用的Office版本,选择合适的XML模板生成方式和内容。 此外,还有一些其他可能导致该错误的原因,例如操作系统的权限限制、文件路径不正确等。我们需要检查并排除这些可能的问题,确保操作系统和文件的相关设置是正确的。 综上所述,报错“Word在试图打开文件时报错”通常是由XML模板格式不符合要求或与Office版本不兼容导致的。我们需要仔细检查XML模板的结构和内容,确保其符合Word的格式要求,并选择与使用的Office版本兼容的XML模板生成方式和内容。另外,还需要检查其他可能导致该错误的问题,确保操作系统和文件的相关设置是正确的。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值