word模板字段的填充和导出

1.目的:项目中遇到一个word导出的功能,需要在固定的模板里把一些字段替换掉,然后返回给前端,然后就实现
2.准备文件
a.将word文档需要填充的字段用占位字段替换${key},和map的key对应
在这里插入图片描述
b.将word打开然后另存为xml文件,直接修改文件的后缀xml改为ftl,这样就生成想要的模板文件啦。
c.我是放入项目文件下的
在这里插入图片描述
3.代码实现

package com.example.demo.service.impl;

import com.example.demo.service.WordService;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.Version;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.HashMap;
import java.util.Map;

@Service
public class WordServiceImpl implements WordService {
    @Override
    public String changWord(String id, HttpServletResponse httpServletResponse) {
        //用于区别不同请求的
        if (id == null) {
            id=String.valueOf(System.currentTimeMillis());
        }
        Map<String,Object> dataMap = new HashMap<String, Object>();
        try {
            //模板的参数,其中map各个字段必须要存在key,value可以为空
            dataMap.put("date","2020-06-07");
            dataMap.put("money","200");
            dataMap.put("author","taotao");
            dataMap.put("tie","测试文件");
            Configuration configuration = new Configuration(new Version("2.3.0"));
            configuration.setDefaultEncoding("utf-8");
            dataMap.put("data", "test");
            configuration.setDirectoryForTemplateLoading(new File("./config"));
            //输出文档路径及名称
            File outFile = new File("./config/test"+id+".doc");
            //以utf-8的编码读取ftl文件,模板的位置
            Template template = configuration.getTemplate("test.ftl", "utf-8");
            Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"), 10240);
            template.process(dataMap, out);
            out.close();
            try {
                FileInputStream fileInputStream = new FileInputStream(outFile);
                httpServletResponse.setCharacterEncoding("UTF-8");

                httpServletResponse.setHeader("Content-Disposition","attachment;filename=test"+id+".doc");
                ServletOutputStream outputStream = httpServletResponse.getOutputStream();
                byte[] data= new byte[1024];
                //浏览器直接下载
                int len;
                while ((len=fileInputStream.read(data))>0){
                    outputStream.write(data,0,len);
                }
                outputStream.close();
                fileInputStream.close();
                //字符流返回给前端
                StringBuffer stringBuffer = new StringBuffer();
                for (int i = 0; i <data.length ; i++) {
                    stringBuffer.append((char)data[i]);
                }
                //base64加密返回给前段
                String s = new Base64().encodeAsString(data);
                //用于文件删除
                outFile.delete();
                    //字节流返回
           //     return new String(stringBuffer);
            } catch (Exception e) {
                e.printStackTrace();
            }

        } catch (Exception e) {
            e.printStackTrace();
        }


        return null;
    }
}

4.测试
a.在浏览器中输出
localhost:8090/word/test?id=32312就可以看到下载的文件了。
b.对于postman来说张这样

在这里插入图片描述

然后点击download就行。
c.对于字符流返回的是一个string串然后你可以
在这里插入图片描述
点击download,他会默认存一个txt把它另存为doc,然后效果是一模一样的。

总结:word输出比较简单主要是生成模板,然后是要输出直接下载的还是base加密的还是字符串就看自己了,在实际操作中word页数比较多,然后输出base64的字段较多,此时vue解密时,ie竟然不能获取全字符串,而chorm是可以的,这个前端问题还没解决,所以我目前用的是字符串而非base64的方式。

方案二:
直接通过poi进行字段的替换,为啥这样做呢,因为在实际的使用中竟然还有人在使用低版本的wps,你敢信???帮政府做的word居然乱码,但是在我们这试都好好的,就开始排查问题呀。
大概用了一整天查这个问题,首先复现问题,问他们要了一份他们的版本(版本号:8.1.0.3000),然后我们的是(9.1.0.5024),只能把本地的wps卸载了然后再装他们版本的wps。我敲真的乱码,打开张这样和返回结果一样的,
在这里插入图片描述

为啥呢,再看下wps的升级,搜索xml,我去竟然在9.1.0.4940的版本新增了对xml框架的支持,我敲就是这之前的都不行啊。ps:word都可以就是低版本的wps妖路啊。
哎,看来xml作为模板的路是不行的了,没法只能另起炉灶了。
2.用啥方法捏?
最终只能用比较笨的方法了,poi来操作doc对象然后对字符串进行替换。
1.创建模板doc文件
在这里插入图片描述

2.引入依赖

		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-scratchpad</artifactId>
			<version>3.9</version>
		</dependency>

3.代码实现

 public String getWordByDoc(String id, HttpServletResponse httpServletResponse) {
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("aa", "123");
        dataMap.put("bb", "还不错");
        dataMap.put("cc", 1);
        dataMap.put("date", "2020-07-27");
        try {
            //模板文件
            FileInputStream fileInputStream = new FileInputStream("./config/1.doc");
            HWPFDocument hwpfDocument = new HWPFDocument(fileInputStream);
            Range range = hwpfDocument.getRange();
            for (Map.Entry<String, Object> entry : dataMap.entrySet()
            ) {
                range.replaceText("${" + entry.getKey() + "}", entry.getValue().toString());
            }
            //生成的文件
            File file = new File("./config/newDoc.doc");
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            hwpfDocument.write(byteArrayOutputStream);
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            fileOutputStream.write(byteArrayOutputStream.toByteArray());
            fileInputStream.close();
            fileOutputStream.close();
            byte[] bytes = FileUtils.readFileToByteArray(file);
            return new String(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

4.测试
允许代码生成了doc
在这里插入图片描述
ok,大功告成。
在这里插入图片描述

两种方案的对比
1.flt方法比较智能,生成的是xml;doc能支持低版本的wps,但是用的是遍历不太行。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值