通过freemarker生成一个word,解决生成的word用wps打开有问题的问题,解决出word时中文文件名乱码问题,解决打开出word时打开的word出现问题的问题,出图片,解决动态列表...

    xiaoxiao2023-09-04  247

    

    通过freemarker制作word比较简单

    步骤:制作word模板。制作方式是:将模板word保存成为xml----xmlword模板中添加相应的标记----xmlword文件的后缀名改成ftl文件(要注意的是生成xml格式要是2003格式的xml,也就是说拿到的word模板得是2003格式的,否则用wps打开word将会出现问题)

     

    详细步骤如下:

    模板制作(将要动态显示的数据打上标记,这个标记是freemarker中的EL标记,要注意的是,要控制值为空的情况,下面${(site.wzmc)?default(“”)}标识当网站名称为空的时候显示空值,如果这里如果不做控制,在实际项目中会显示错误!

    另外要注意的是:

    一、不要直接在word中替换掉文字的方式添加标记,这种会有问题。

    二、不要使用Eclipsexml文件进行格式化,这种生成word的时候会提示文档有问题。解决这个的问题是通过firstobjectwordxml进行格式化,对xml进行编辑。(使用firstobject打开带有中文文件名的xml文件的时候,会出现问题,建议使用英文word文档名称),或者使用XMLViewer

    三、firstobject下载地址:http://www.firstobject.com/dn_editor.htm

    其中,要想软件能够格式化xml代码,需要进行设置,设置方式是:打开firstobject----Tools-----Preferences------Format-----Tabs

    点击Indent,结果xml变成了有格式化的,效果图如下:

     

    常见标签:

    行标记:

    <w:p w:rsidR="00790C22"w:rsidRPr="00C07F75" w:rsidRDefault="00790C22"w:rsidP="004018B7">

     

    标识是一个表格的标签

    <w:tbl></w:tb1>

     

    表格行:

    <w:trw:rsidR="00790C22" w:rsidRPr="00C07F75"w:rsidTr="004018B7"></w:tr>

     

    表格中的单元格:

    <w:tc></w:tc>

     

     

    循环输出数据的方式

    <#list problemInfoInterview as problemInfo>

                     <w:tbl>

                        <w:tblPr>

                            <w:tblW w:w="0" w:type="auto"/>

                            <w:tblBorders>

                               <w:top w:val="single" w:sz="4" w:space="0" w:color="auto"/>

                               <w:left w:val="single" w:sz="4" w:space="0" w:color="auto"/>

                               <w:bottom w:val="single" w:sz="4" w:space="0" w:color="auto"/>

                               <w:right w:val="single" w:sz="4" w:space="0" w:color="auto"/>

                               <w:insideH w:val="single" w:sz="4" w:space="0" w:color="auto"/>

                               <w:insideV w:val="single" w:sz="4" w:space="0" w:color="auto"/>

                            </w:tblBorders>

                            <w:tblLook w:val="04A0" w:firstRow="1" w:lastRow="0" w:firstColumn="1" w:lastColumn="0" w:noHBand="0" w:noVBand="1"/>

                        </w:tblPr>

                        <w:tblGrid>

                            <w:gridCol w:w="2235"/>

                            <w:gridCol w:w="6287"/>

                        </w:tblGrid>

                        <w:tr w:rsidR="00790C22" w:rsidRPr="00C07F75" w:rsidTr="004018B7">

                            <w:tc>

                               <w:tcPr>

                                   <w:tcW w:w="2235" w:type="dxa"/>

                                   <w:shd w:val="clear" w:color="auto" w:fill="auto"/>

                                   <w:vAlign w:val="center"/>

                               </w:tcPr>

                               <w:p w:rsidR="00790C22" w:rsidRPr="00C07F75" w:rsidRDefault="00790C22" w:rsidP="004018B7">

                                   <w:pPr>

                                      <w:jc w:val="center"/>

                                      <w:rPr>

                                          <w:rFonts w:ascii="Times New Roman" w:eastAsia="黑体" w:hAnsi="Times New Roman"/>

                                          <w:sz w:val="24"/>

                                          <w:szCs w:val="24"/>

                                      </w:rPr>

                                   </w:pPr>

                                   <w:r>

                                      <w:rPr>

                                          <w:rFonts w:ascii="Times New Roman" w:eastAsia="黑体" w:hAnsi="Times New Roman" w:hint="eastAsia"/>

                                         <w:sz w:val="24"/>

                                          <w:szCs w:val="24"/>

                                      </w:rPr>

                                      <w:t>问题名称</w:t>

                                   </w:r>

                               </w:p>

                            </w:tc>

                            <w:tc>

                               <w:tcPr>

                                   <w:tcW w:w="6287" w:type="dxa"/>

                                   <w:shd w:val="clear" w:color="auto" w:fill="auto"/>

                                   <w:vAlign w:val="center"/>

                               </w:tcPr>

                               <w:p w:rsidR="00790C22" w:rsidRPr="00C07F75" w:rsidRDefault="00790C22" w:rsidP="004018B7">

                                   <w:pPr>

                                      <w:jc w:val="left"/>

                                      <w:rPr>

                                          <w:rFonts w:ascii="Times New Roman" w:eastAsia="宋体" w:hAnsi="Times New Roman"/>

                                          <w:sz w:val="24"/>

                                          <w:szCs w:val="24"/>

                                      </w:rPr>

                                   </w:pPr>

                                                                                    <w:r>

                                      <w:rPr>

                                          <w:rFonts w:ascii="Times New Roman" w:eastAsia="宋体"

                                             w:hAnsi="Times New Roman" w:hint="eastAsia" />

                                          <w:sz w:val="24" />

                                          <w:szCs w:val="24" />

                                      </w:rPr>

                                      <w:t>${(problemInfo.problemName)?default("")}</w:t>

                                   </w:r>

                               </w:p>

                            </w:tc>

                        </w:tr>

                        

     

                        这里面的行删除

     

                     </w:tbl>

                                                <w:p w:rsidR="007F35A8" w:rsidRPr="007F35A8" w:rsidRDefault="007F35A8" w:rsidP="007F35A8" />

                                                </#list>

     

    另外,往文档中插入图片的时候,在做模板的时候要往模板中插入一个图片,然后打开文档,然后替换掉base64转码的图片部分。

     

    将图片资源变成base64加密后的图片的代码

    将图片转成base64串的方式:

    publicstatic String getImageString(String fileName)throws IOException {

         InputStream in =null;

         byte[] data =null;

         try {

            in =new FileInputStream(fileName);

            data =newbyte[in.available()];

            in.read(data);

            in.close();

         }catch (Exception e) {

            e.printStackTrace();

         }finally {

            if (in !=null){

               in.close();

            }

         }

         Base64Encoder encoder =new Base64Encoder();

         return data !=null ? encoder.encode(data) :"";

      }

    下面是出word用的相关的类:

    读取路径用的TemplateUtil工具类

    package com.ucap.netcheck.utils;

     

    import java.io.File;

    import java.io.FileInputStream;

    import java.net.URL;

    import java.util.Properties;

     

    /**

     * @Title: TemplateUtil.java

     * @Package com.ucap.netcheck.utils

     * @Description:

     * @author

     * @date 2015-4-13下午9:07:58

     * @version V1.0

     */

    public class TemplateUtil {

       //模板所在的位置

       public static String reportTemplatePath;

       //模板的名称

       public static String templateFileName;

       

       static {

          URL resource = TemplateUtil.class.getClassLoader().getResource("template.properties");

          System.out.println(resource.getPath());

          

          File file = new File(resource.getPath());

          //生成文件输入流

          FileInputStream in = null;

          try {

              in = new FileInputStream(file);

          } catch (Exception e) {

             e.printStackTrace();

          }

          

          //生成properties对象

          Properties prop = new Properties();

          try {

              prop.load(in);

          } catch (Exception e) {

              e.printStackTrace();

          }

          

          reportTemplatePath = prop.getProperty("reportTemplatePath");

          templateFileName = prop.getProperty("templateFileName");

       }

       

       /*public static void main(String[] args) {

          System.out.println(TemplateUtil.reportTemplatePath);

       }*/

    }

    配置文件路径截图:

    FreeMarkerUtil工具类

    package com.ucap.netcheck.utils;

     

    import java.io.File;

    import java.io.FileInputStream;

    import java.io.FileOutputStream;

    import java.io.IOException;

    import java.io.InputStream;

    import java.io.OutputStreamWriter;

    import java.io.Writer;

    import java.util.HashMap;

    import java.util.Map;

     

    import com.thoughtworks.xstream.core.util.Base64Encoder;

     

    import freemarker.template.Configuration;

    import freemarker.template.Template;

     

    /**

     *@Title: FreeMarkerUtil.java

     *@Package com.ucap.netcheck.utils

     *@Description: FreeMarker工具类

     *@authorZuoquan Tu

     *@date 2015-4-5下午6:02:11

     *@version V1.0

     */

    publicclass FreeMarkerUtil {

      privatestatic Configurationconfiguration =null;

      privatestatic Map<String, Template>allTemplates =null;

      

      static {

         configuration =new Configuration();

         configuration.setDefaultEncoding("utf-8");

         //configuration.setClassForTemplateLoading(FreeMarkerUtil.class,

         //   "../template");

         

         try {

            configuration.setDirectoryForTemplateLoading(

                   new File(TemplateUtil.reportTemplatePath));

         }catch (IOException e1) {

            e1.printStackTrace();

         }

         allTemplates =new HashMap<String, Template>();

         try {

           allTemplates.put("word",configuration.getTemplate(TemplateUtil.templateFileName));

         }catch (Exception e) {

            e.printStackTrace();

            thrownew RuntimeException(e);

         }

      }

      

      public FreeMarkerUtil() {

         

      }

      

      publicstatic File createDoc(Map<?, ?> dataMap,String type){

         String name ="temp" + (int) (Math.random() * 100000) +".doc";

         File f =new File(name);

         Template t =allTemplates.get(type);

         try {

            //这个地方不能使用FileWriter因为需要指定编码类型否则生成的Word

            //文档会因为有无法识别的编码而无法打开

            Writer w =new OutputStreamWriter(new FileOutputStream(f),"utf-8");

            t.process(dataMap, w);

            w.close();

         }catch (Exception ex) {

            ex.printStackTrace();

            thrownew RuntimeException();

         }

         return f;

      }

     

      publicstatic String getImageString(String fileName)throws IOException {

         InputStream in =null;

         byte[] data =null;

         try {

            in =new FileInputStream(fileName);

            data =newbyte[in.available()];

            in.read(data);

            in.close();

         }catch (Exception e) {

            e.printStackTrace();

         }finally {

            if (in !=null){

               in.close();

            }

         }

         Base64Encoder encoder =new Base64Encoder();

         return data !=null ? encoder.encode(data) :"";

      }

    }

    WordController层的代码,并解决出word时中文文件名乱码的问题

    package com.ucap.netcheck.controller;

     

    import java.io.File;

    import java.io.FileInputStream;

    import java.io.FileNotFoundException;

    import java.io.IOException;

    import java.io.InputStream;

    import java.net.URLEncoder;

    import java.util.Map;

     

    import javax.servlet.ServletOutputStream;

    import javax.servlet.http.HttpServletRequest;

    import javax.servlet.http.HttpServletResponse;

     

    import org.apache.commons.lang.StringUtils;

    import org.springframework.beans.factory.annotation.Autowired;

    import org.springframework.stereotype.Controller;

    import org.springframework.ui.Model;

    import org.springframework.web.bind.annotation.RequestMapping;

    import org.springframework.web.bind.annotation.RequestMethod;

     

    import com.ucap.netcheck.entity.Site;

    import com.ucap.netcheck.entity.User;

    import com.ucap.netcheck.service.IReport2WordService;

    import com.ucap.netcheck.service.ISiteService;

    import com.ucap.netcheck.utils.DateUtil;

    import com.ucap.netcheck.utils.FreeMarkerUtil;

     

    /**

     * @Title: Report2WordController.java

     * @Package com.ucap.netcheck.controller

     * @Description:生成word部分的Controller

     * @author Zuoquan Tu

     * @date 2015-4-12上午9:36:43

     * @version V1.0

     */

    @Controller

    @RequestMapping(value = "/reportToWord", method = { RequestMethod.GET,

                      RequestMethod.POST })

    public class Report2WordController {

     

            @Autowired

            private IReport2WordService report2WordService;

            @Autowired

            private ISiteService siteService;

     

            @RequestMapping(value = "/word")

            public String outWord(Model model, HttpServletRequest request,

                               HttpServletResponse response) throws Exception {

                      request.setCharacterEncoding("utf-8");

     

                      //获取innerUUIDtaskId

                      String siteCode = request.getParameter("innerUUID");

                      //获取taskId

                      Integer taskId = Integer.parseInt(request.getParameter("taskId"));

                      //获取用户的userId

                      User user = (User) request.getSession().getAttribute("user");

                      //通过下面的方式获得模板的参数

                      Site site = siteService.findSite(siteCode);

                      String webSiteName = site.getWzmc();

                      Map<String, Object> map = report2WordService.generateWordData(siteCode,

                                        taskId, user.getId());

     

                      //获取innerUUID,taskId

                      // Map<String, Object> map = new HashMap<String, Object>();

     

                      //获取innerUUID,taskId

                      // Map<String, Object> map = new HashMap<String, Object>();

                      // map.put("taskNum", "测试");

                      // map.put("tackRunNum", "测试2……rqwrqw");

                      // String imageStr = new FreeMarkerUtil().getImageString("D:/1.png");

                      // map.put("imgStr", imageStr);

                      //

                      // List<CheckService> newsList = new ArrayList<CheckService>();

                      // for (int i = 0; i < 10; i++) {

                      // CheckService checkService = new CheckService();

                      // checkService.setTaskRunNum(10);

                      // checkService.setTaskNum(1000);

                      // newsList.add(checkService);

                      // }

                      // map.put("newList", newsList);

     

                      this.generateWord(request,response, map, webSiteName);

     

                      return null;

            }

     

            @SuppressWarnings("static-access")

            private void generateWord(HttpServletRequest request,HttpServletResponse response,

                               Map<String, Object> map, String webSiteName)

                               throws FileNotFoundException, IOException {

                      File file = null;

                      InputStream fin = null;

                      ServletOutputStream out = null;

                      try {

                               //调用工具类WordGeneratorcreateDoc方法生成Word文档

                               file = new FreeMarkerUtil().createDoc(map, "word");

                               fin = new FileInputStream(file);

                               response.setCharacterEncoding("utf-8");

                               response.setContentType("application/msword");

                               //设置浏览器以下载的方式处理该文件默认名为下面的文件,按照时间来生成的一个文件名称

                               String longMsDateStr = DateUtil.getStringLongMsDate();

                               String fileName = webSiteName + "_" + longMsDateStr + ".doc";

                               //设置下载用的文件名

                               setFileDownloadHeader(request, response, fileName);

                               //response.addHeader("Content-Disposition", "attachment;filename=" + fileName);

     

                               out = response.getOutputStream();

                               byte[] buffer = new byte[512];

                               int bytesToRead = -1;

     

                               //通过循环将读入的Word文件的内容输出到浏览器中

                               while ((bytesToRead = fin.read(buffer)) != -1) {

                                        out.write(buffer, 0, bytesToRead);

                               }

                      } finally {

                               if (fin != null)

                                        fin.close();

                               if (out != null)

                                        out.close();

                               if (file != null)

                                        file.delete(); //删除临时文件

                      }

            }

     

            /**

             *根据当前用户的浏览器不同,对文件的名字进行不同的编码设置,从而解决不同浏览器下文件名中文乱码问题

             */

            public static void setFileDownloadHeader(HttpServletRequest request,

                               HttpServletResponse response, String fileName) {

                      final String userAgent = request.getHeader("USER-AGENT");

                      try {

                               String finalFileName = null;

                               if (StringUtils.contains(userAgent, "MSIE")) {

                                        // IE浏览器

                                        finalFileName = URLEncoder.encode(fileName, "UTF8");

                               } else if (StringUtils.contains(userAgent, "Mozilla")) {

                                        // google,火狐浏览器

                                        finalFileName = new String(fileName.getBytes(), "ISO8859-1");

                               } else {

                                        //其他浏览器

                                        finalFileName = URLEncoder.encode(fileName, "UTF8");

                               }

                               

                               //这里设置一下让浏览器弹出下载提示框,而不是直接在浏览器中打开

                               response.setHeader("Content-Disposition", "attachment; filename=\""

                                                  + finalFileName + "\"");

                      } catch (Exception e) {

                               e.printStackTrace();

                      }

            }

    }

    ServiceImpl层的实现类

    package com.ucap.netcheck.service.impl;

     

    import java.text.NumberFormat;

    import java.util.ArrayList;

    import java.util.HashMap;

    import java.util.List;

    import java.util.Map;

     

    import org.springframework.beans.factory.annotation.Autowired;

    import org.springframework.stereotype.Service;

     

    import com.ucap.netcheck.combination.beans.TargetTypeParentToChildBean;

    import com.ucap.netcheck.dao.IReport2WordDao;

    import com.ucap.netcheck.entity.CheckService;

    import com.ucap.netcheck.entity.MainPageScanFail;

    import com.ucap.netcheck.entity.MainPageScanResult;

    import com.ucap.netcheck.entity.ProblemInfo;

    import com.ucap.netcheck.entity.Site;

    import com.ucap.netcheck.entity.SiteService;

    import com.ucap.netcheck.service.CheckServiceService;

    import com.ucap.netcheck.service.IReport2WordService;

    import com.ucap.netcheck.service.ISingleRejectResultService;

    import com.ucap.netcheck.service.ISiteService;

    import com.ucap.netcheck.service.SiteServService;

    import com.ucap.netcheck.service.TargetTypeService;

    import com.ucap.netcheck.utils.DateUtil;

     

    /**  

     * @Title: Report2WordServiceImpl.java

     * @Package com.ucap.netcheck.service.impl

     * @Description:

     * @author 

     * @date 2015-4-12上午11:58:09

     * @version V1.0  

     */

    @Service

    public class Report2WordServiceImpl implements IReport2WordService {

     

            @Autowired

       private ISiteService siteService;

            @Autowired

            private CheckServiceService checkServiceService;

            @Autowired

            private IReport2WordDao report2WordDao;

            @Autowired

            private TargetTypeService targetTypeService;

            @Autowired

            private ISingleRejectResultService singleRejectResultService;

            @Autowired

            private SiteServService siteServService;

     

            /**

             * generateWordData(通过这个方法获得生成报告所需的数据)

             *

             * @Title: generateWordData

             * @Description:通过这个方法获得生成报告所需的数据

             * @param @return   返回所需的数据

             * @return Map<String,Object>   返回的数据

             * @throws

             */

            @Override

            public Map<String, Object> generateWordData(

                               String siteCode,Integer taskId,String userId) {

                      Map<String, Object> map = new HashMap<String, Object>();

                      //网站名称,首页网址,报告编号,报告日期

                      Site site = siteService.findSite(siteCode);

                      map.put("site", site);

                      //生成报告编号和报告日期

                      map.put("reportCode", DateUtil.getNowDateStr() + "_" + taskId);

                      map.put("reportDate", DateUtil.getYearMonthAndDay());

                      

                      //检查方法的数据,获得CheckService的值

                      //通过siteCode查找site_service

                      SiteService siteService = siteServService.findSiteService(siteCode);

                      CheckService checkService = report2WordDao.findCheckService(siteService.getServId());

                      map.put("checkService", checkService);

                      //设置开通时间的日期

                      map.put("checkServiceOpenTime", DateUtil.dateToStr(checkService.getOpenTime()));

                      //设置结束时间的日期

                      map.put("checkServiceCloseTime", DateUtil.dateToStr(checkService.getCloseTime()));

                      

                      return map;

            }

    }

    Ftl语法:

    一、判断listchannelUpdateResults是否为空,判断list的大小是否大于某个值,注意加括号

    <#if channelUpdateResults??>

                                                                             <#if (channelUpdateResults?size>=10) >

                                                                                          未更新数量为“单项否决”。

                                                                                  </#if>

    </#if>

    二、list迭代

    <#list queryMainPageScanFailList as mainPageScanFail>

    </#list>

    四、迭代的时候输出序号

    ${( mainPageScanFail _index+1)?default("")}  其中

    五、if语句中取数组的值

    <#if deadUrl[0] == 1>                                                                                                      

                                                                                                 <#else>                                                                                                                                                                         </#if>

    六、<#assign>赋值,并且通过x_has_next来辨别当前项是否是序列的最后一项的布尔值。

    <#assign seq = ["winter", "spring", "summer", "autumn"]>

    <#list seq as x>

    ${x_index+ 1}. ${x}<#ifx_has_next>,</#if>

    </#list>

    七、解决出word中因为特殊字符“&”出现的问题,同时判断字符串为NULL和“”空字符串。如果在链接地址中出现了&字符,在生成的word会报错,解决办法是将这个特殊字符用“&”替换掉,示例加链接的代码如下:

    <#if (channelUpdate.url)??>           <w:hlink w:dest="${(channelUpdate.url)?replace('&','&')}">            <w:r wsp:rsidR="002F59FF" wsp:rsidRPr="002F59FF">             <w:rPr>              <w:rStyle w:val="ab"/>              <w:rFonts w:ascii="仿宋" w:fareast="仿宋" w:h-ansi="仿宋"/>              <wx:font wx:val="仿宋"/>              <w:sz w:val="24"/>              <w:sz-cs w:val="30"/>             </w:rPr>             <w:t>${(channelUpdate.url)?replace('&','&')}</w:t>            </w:r>           </w:hlink>                                                                                                   </#if>

      八、多次替换以及replace多次:

    ${(problemInfo.problemUrl)?replace("&","&")?replace("<","<")?replace(">",">")}

    九:判断一个对象是否为空

    freemarker中显示某对象使用${name}.

     

    但如果name为null,freemarker就会报错。如果需要判断对象是否为空:

    <#if name??>

    ……

    </#if>

     

    当然也可以通过设置默认值${name!''}来避免对象为空的错误。如果name为空,就以默认值(“!”后的字符)显示。

     

    对象user,name为user的属性的情况,user,name都有可能为空,那么可以写成${(user.name)!''},表示user或者name为null,都显示为空。判断为空

    <#if (user.name)??>

    ……

    </#if>

    十:freemarker获取map中的值:

    第一种方式 <#list map?keys as itemkey>         < option value="${itemkey}" >                ${map.get(itemkey)}       </option>  </#list>第二种方式     主意红色字体区分 <#list map.keySet() as itemkey>         < option value="${itemkey}" >          ${map.get(itemkey)}     </option>  </#list>

       相关资源:Java POI 生成Word文档
    最新回复(0)