java 通过velocity导出word

项目需要通过程序生成word文档,就是业务方提供了一份模板,里面的有一份表格或者合同,程序主要就是把数据填到word中,并提供用户下载。首先想到的是iText和POI。iText操作pdf还不错,但是对word貌似就很吃力了。POI对excel读取和操作还行,对word的写入太复杂。上网搜了下java导出word,发现可以通过FreeMarker来完成还能保持word中复杂的样式。我们的工程中已经使用了velocity,将freemarker换成velocity很轻松。这样的话导出简单方便,还支持复杂的样式。下次业务方要换模板的时候简单替换下就行了。

具体过程

1.将运营给的word文档,需要数据的地方用$变量符替换

测试用,这里就简单的设置了邮箱。

2.保存之后将word文档另存为xml格式。

3.将这个xml文件另存为.vm文件就是我们的模板了。

写个测试

public void execute(TurbineRunData rundata, Context context) throws IOException {

        VelocityContext veContext = new VelocityContext();

        veContext.put("email", "17173as");

        // 渲染html

        InputStreamReader reader = new InputStreamReader(this.getClass().getResourceAsStream("/green.vm"),"UTF-8");

        String html = ExportUtil.buildHtmlByVelocity(veContext, reader);

        String fileName="绿色通道.docx";

        ServletOutputStream sos = null;

        try {

            HttpServletResponse response = rundata.getResponse();

            response.setContentType("application/msword;");

            response.setHeader("Content-Disposition", "attachment; filename=" + new String(fileName.getBytes(), "ISO-8859-1"));

            sos = response.getOutputStream();

            sos.print(html);

        } catch (Exception e) {

            log.warn("[导出除标的物异常]" + fileName, e);

        } finally {

            if (sos != null) {

                try {

                    sos.close();

                } catch (IOException e) {

                    log.error("[close异常]", e);

                }

            }

        }

    }

结果能导出,但是文件压根打不开,提示文件错误

将导出的doc文件用文本编辑器打开,初看挺正常的,之前的通过word导出的xml改为doc结尾后缀都能用word 再打开,这份重新导出的怎么就不行呢。用文本比较工具比较了下2份文件发现程序导出的文件存在一部分中文是?,应该就是这个引起的。但是为啥会部分是乱码,部分又是正常的中文。于是上网查了一通资料。中间换过好几种方法,一度想放弃xml,使用mth文件(html格式),但是悲剧的是word导出的mth打开就有乱码。于是又想到把xml文件转换成GBK编码,这样对中文总算友好吧。结果还不行,xml文件里居然有韩文之类的(不要问我为啥,我也不知道),GBK也行不通。那就查吧,看看是那一步导出乱码的,写了个main函数

public static void main(String[] args) throws IOException {

        VelocityContext veContext = new VelocityContext();

        veContext.put("email", "开");

        // 渲染html

        InputStreamReader reader = new InputStreamReader(ExportSettledGreenChannel.class.getResourceAsStream("/green.vm"),

        "UTF-8");

        int b;

        while ((b = reader.read()) != -1)

        {

            System.out.print((char)b);

        }

    }

这个时候发现打印出来也是部分字是乱码,这时候尝试将green.vm用比较简单的中文替换原来的xml。发现能正常的打印出来,于是再换成word导出的xml内容,打印出来也是ok的,我还特意将打印出来的大段xml复制出来,改成doc后缀也能正常打开。这个就有点诡异了,当时觉得是我写的vm模板有问题,导致编码出错。现在ok了就重新打包测试一下。maven打包起tomcat,点击导出,发现还是跟之前一样的结果,还是打不开。这个就非常郁闷了,这时尝试将刚才的main函数再跑一下,发现居然也出乱码。看来是有八成跟打包有关系,因为我把vm放在resources目录下,这样可以通过class path加载。但是pom文件里配置的编码是GBK,而vm模板的编码是UTF-8,难道是maven编译的时候导致乱码。但是我不能改vm的编码也不能改pom里设置的编码。于是把vm文件放到WEB-INF下面,这样mavn打包不会对他产生影响。再来测试一下

public void execute(TurbineRunData rundata, Context context) throws IOException {

        VelocityContext veContext = new VelocityContext();

        veContext.put("email", "17173as");

        InputStream greenInput=  rundata.getRequestContext().getServletContext().getResourceAsStream("/WEB-INF/green.vm");

        InputStreamReader reader = new InputStreamReader(greenInput,"UTF-8");

        String html = ExportUtil.buildHtmlByVelocity(veContext, reader);

        String fileName="绿色通道.doc";

        ServletOutputStream sos = null;

        try {

            HttpServletResponse response = rundata.getResponse();

            response.setContentType("application/msword;charset=UTF-8");

            response.setHeader("Content-Disposition", "attachment; filename=" + new String(fileName.getBytes(), "ISO-8859-1"));

            sos = response.getOutputStream();

            sos.print(html);

        } catch (Exception e) {

            log.warn("[导出除标的物异常]" + fileName, e);

        } finally {

            if (sos != null) {

                try {

                    sos.close();

                } catch (IOException e) {

                    log.error("[close异常]", e);

                }

            }

        }

    }

最后文件能正常的打开,而且email替换成了变量

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值