FreeMarker 导出word (MicrosoftOffice打开)

做了个简单例子用freemarker导出word,将数据库查询出的信息以word形式导出来,简单来说就两步,建立模板,查出数据写入模板。

第一步:建立模板

建立word(以03版为例) 调好格式,将其中的变量用${参数名}来代替,有需要展现图片的业务的话,则在要展示的图片的位置预先插入一张图片,例如:



 然后将该word另存为xm格式的文件,另存为xml的时候需要注意存为XML格式,而不是WORD XML 格式!!!前者格式是wps的这种模板生成的word只能wps打开,office word打开的话是xml代码,存后者xml格式 则wps和office都能正常打开,如图示: 

 

 

再将该xml文件更改文件格式为ftl,下载firstobject XML Editor,F8格式化该文件浏览样式;

 

第二步:服务器获取数据

 

public void createWord(HttpServletRequest request,List<HouseInspectionItems> houseInspectionItemsList,HouseInspection houseInspection) throws IOException{
  //houseInspectionItemsList为上一个方法传入的数据
  Configuration configuration = new Configuration();
  configuration.setDefaultEncoding("UTF-8");
  Map<String,Object> dataMap=new HashMap<String,Object>();
  //填充数据
  dataMap.put("propertyName", houseInspection.getPtorname());//物业名称
  dataMap.put("houseaddr", houseInspection.getComname()+houseInspection.getAddr());
  dataMap.put("ptorname", houseInspection.getPtorname()); 
     dataMap.put("ptorphone", houseInspection.getPtorphone());
     dataMap.put("houseinfo", houseInspection.getAddr());
     dataMap.put("finishDate", houseInspection.getFinishDate()!=null ?DateUtils.formatDate(houseInspection.getFinishDate(), "yyyy年MM月dd日"):"");//完成日期    
    
     List<HouseInspectionItems> list = new ArrayList<HouseInspectionItems>();
     List<Map<String,Object>> ridList = new ArrayList<Map<String,Object>>();
     int imgId = 1;//标记图片id
     for (int i = 0; i < houseInspectionItemsList.size(); i++) {
      
      HouseInspectionItems hii = houseInspectionItemsList.get(i);
      List<HouseProblem> hpList = houseProblemService.findHPListByInsIdAndItemsId(hii.getId(),houseInspection.getId());//根据验房id和检查项目id查找对应问题列表
         hii.setItemsName(hii.getItemsName());//检查项目名
         hii.setHouseProblemList(hpList); //问题列表
         for(int j = 0;j<hpList.size();j++){
          HouseProblem hp = hpList.get(j);
          if(StringUtils.isNotBlank(hp.getHouseProblemImg())){//有图片需要转码
           List<Map<String,Object>> hPImgWordList = new ArrayList<Map<String,Object>>();
           List<String> strList = Arrays.asList(hp.getHouseProblemImg().split(","));
           for(String imgStr:strList){
            Map<String,Object> mm = new HashMap<String, Object>();
            mm.put("imgurl",getImageString(imgStr));
            mm.put("imgId", imgId);
            imgId++;
            hPImgWordList.add(mm);
           }
           
           hp.sethPImgWordList(hPImgWordList);
          }
          hp.setProblemDescription("问题"+(j+1)+":"+hp.getProblemDescription());//问题描述
          hp.setStatusName(DictUtils.getDictLabel(hp.getHandleStatus(), "houseProblem_handle_status", "0"));
         }
         list.add(hii);
  }
    
    
     dataMap.put("hilist", list);    
  
  configuration.setDirectoryForTemplateLoading(new File(request.getSession().getServletContext().getRealPath("/template")));//获取保存的ftl格式文件路径
        Template t=null; 
        try { 
            t = configuration.getTemplate("wordModel.ftl"); //获取ftl模板
        } catch (IOException e) { 
            e.printStackTrace(); 
        }

        
        String fileName = "报告"+houseInspection.getHouid()+DateUtils.formatDate(new Date(), "yyyyMMddHHmmss")+".doc";
        XWPFDocument doc = new XWPFDocument();//poi word下载
        response.reset();
        response.setContentType("application/octet-stream; charset=utf-8");
        response.setHeader("Content-Disposition", "attachment; filename="+Encodes.urlEncode(fileName));
        Writer out = null;
        OutputStream  outstream= null;
        try {
         out = response.getWriter();
            t.process(dataMap, out);
            outstream = response.getOutputStream();
            doc.write(outstream);
        } catch (TemplateException e) { 
            e.printStackTrace(); 
        } catch (IOException e) { 
            e.printStackTrace(); 
        }
        finally{
         try{
          if(out!=null){
           out.close();
          }
          if(outstream!=null){
           outstream.close();
          }
         }catch (IOException e) { 
                e.printStackTrace(); 
            }
        }
              
 }

简要介绍以上的代码:模板里的${hii.itemsName}为检查项目名,是列表形式,检查项目名下面是问题列表,然后每个问题下面又是该问题下的图片列表。

然后从服务器以url形式获取图片并压缩并base64编码

 

 

/**
  * 获取图片并压缩编码
  */
 public  String getImageString(String fileName) throws IOException {
  
        BASE64Encoder encoder = new BASE64Encoder();
//        System.out.println("fileName====="+fileName);

//        File file = new File(fileName);
//        FileInputStream fis = new FileInputStream(file); 
//        byte[] imgData = new byte[fis.available()]; 
//        fis.read(imgData); 
//        fis.close(); 
//        return encoder.encode(imgData);
        
        URL url = new URL(fileName); 
        InputStream inStream = null ;
        ByteArrayOutputStream outSteam = new ByteArrayOutputStream();   
        byte[] buffer = new byte[1024];
        try {
         inStream = url.openStream();
         int len = -1;   
            while ((len = inStream.read(buffer)) != -1) {   
                     outSteam.write(buffer, 0, len); 
            }
         
  } catch (IOException e) {
   e.printStackTrace();
  }
  finally{
         try{
          if(outSteam!=null){
           outSteam.close();
          }   
                if(inStream!=null){
                 inStream.close();
                }
         }catch (IOException e) { 
                e.printStackTrace(); 
            }
        }
  byte[] data = outSteam.toByteArray();
        //图片压缩
  ByteArrayInputStream is = new ByteArrayInputStream(data);
  ImageWriter imgWrier; 
  ImageWriteParam imgWriteParams;
  BufferedImage src = null;
  ByteArrayOutputStream out = null;
   
  // 指定写图片的方式为 jpg 
  imgWrier = ImageIO.getImageWritersByFormatName("jpg").next(); 
  imgWriteParams = new javax.imageio.plugins.jpeg.JPEGImageWriteParam(null); 
  // 要使用压缩,必须指定压缩方式为MODE_EXPLICIT 
  imgWriteParams.setCompressionMode(imgWriteParams.MODE_EXPLICIT); 
  // 这里指定压缩的程度,参数qality是取值0~1范围内, 
  imgWriteParams.setCompressionQuality(0.1f); 
                    
  imgWriteParams.setProgressiveMode(imgWriteParams.MODE_DISABLED); 
//  ColorModel colorModel = ColorModel.getRGBdefault(); 
  // 指定压缩时使用的色彩模式 
//  imgWriteParams.setDestinationType(new javax.imageio.ImageTypeSpecifier(colorModel, colorModel.createCompatibleSampleModel(16, 16))); 
   
  try 
  { 
      src = ImageIO.read(is); 
      out = new ByteArrayOutputStream(data.length); 
   
      imgWrier.reset(); 
      // 必须先指定 out值,才能调用write方法, ImageOutputStream可以通过任何 OutputStream构造 
      imgWrier.setOutput(ImageIO.createImageOutputStream(out)); 
      // 调用write方法,就可以向输入流写图片 
      imgWrier.write(null, new IIOImage(src, null, null), imgWriteParams); 
       
      out.flush(); 
      out.close(); 
      is.close(); 
      data = out.toByteArray(); 
  }catch(Exception e){ 
      e.printStackTrace(); 
  } 
  finally{
         try{
          if(out!=null){
           out.close();
          }   
                if(is!=null){
                 is.close();
                }
         }catch (IOException e) { 
                e.printStackTrace(); 
            }
        }
  
//        return encoder.encode(outSteam.toByteArray());
  return encoder.encode(data);
   }

 

 

第三步:修改模板文件

1、循环list

<w:p>
<w:pPr>
<w:jc w:val="both"/>
<w:rPr>
<w:rFonts w:hint="eastAsia"/>
<w:b w:val="0"/>
<w:bCs w:val="0"/>
<w:sz w:val="21"/>
<w:szCs w:val="21"/>
<w:lang w:val="en-US" w:eastAsia="zh-CN"/>
</w:rPr>
</w:pPr>
<w:r>
<w:rPr>
<w:rFonts w:hint="eastAsia"/>
<w:b w:val="0"/>
<w:bCs w:val="0"/>
<w:sz w:val="21"/>
<w:szCs w:val="21"/>
<w:lang w:val="en-US" w:eastAsia="zh-CN"/>
</w:rPr>
<w:t>报告问题:</w:t>
</w:r>
</w:p>
<#list hilist  as hii>
<w:p>
<w:pPr>
<w:ind w:firstLine="420" w:firstLineChars="0"/>
<w:jc w:val="both"/>
<w:rPr>
<w:rFonts w:hint="eastAsia"/>
<w:b/>
<w:bCs/>
<w:sz w:val="21"/>
<w:szCs w:val="21"/>
<w:lang w:val="en-US" w:eastAsia="zh-CN"/>
</w:rPr>
</w:pPr>
<w:r>
<w:rPr>
<w:rFonts w:hint="eastAsia"/>
<w:b/>
<w:bCs/>
<w:sz w:val="21"/>
<w:szCs w:val="21"/>
<w:lang w:val="en-US" w:eastAsia="zh-CN"/>
</w:rPr>
<w:t>${hii.itemsName}</w:t>
</w:r>
</w:p>
<#list hii.houseProblemList  as hp>
<w:p>
<w:pPr>
<w:ind w:left="420" w:leftChars="0" w:firstLine="420" w:firstLineChars="0"/>
<w:rPr>
<w:rFonts w:hint="eastAsia"/>
<w:b/>
<w:bCs/>
<w:lang w:val="en-US" w:eastAsia="zh-CN"/>
</w:rPr>
</w:pPr>
<w:r>
<w:rPr>
<w:rFonts w:hint="eastAsia"/>
</w:rPr>
<w:t>${hp.problemDescription}</w:t>
</w:r>
<w:r>
<w:rPr>
<w:rFonts w:hint="eastAsia"/>
<w:lang w:val="en-US" w:eastAsia="zh-CN"/>
</w:rPr>
<w:tab/>
<w:t></w:t>
</w:r>
<w:r>
<w:rPr>
<w:rFonts w:hint="eastAsia"/>
<w:lang w:val="en-US" w:eastAsia="zh-CN"/>
</w:rPr>
<w:tab/>
<w:t></w:t>
</w:r>
<w:r>
<w:rPr>
<w:rFonts w:hint="eastAsia"/>
<w:lang w:val="en-US" w:eastAsia="zh-CN"/>
</w:rPr>
<w:tab/>
<w:t></w:t>
</w:r>
<w:r>
<w:rPr>
<w:rFonts w:hint="eastAsia"/>
<w:lang w:val="en-US" w:eastAsia="zh-CN"/>
</w:rPr>
<w:tab/>
</w:r>
<w:r>
<w:rPr>
<w:rFonts w:hint="eastAsia"/>
<w:b/>
<w:bCs/>
<w:lang w:val="en-US" w:eastAsia="zh-CN"/>
</w:rPr>
<w:t>当前状态:${hp.handleStatus}</w:t>
</w:r>
</w:p>
<w:p>
<w:pPr>
<w:ind w:left="420" w:leftChars="0" w:firstLine="420" w:firstLineChars="0"/>
<w:rPr>
<w:rFonts w:hint="eastAsia"/>
<w:b/>
<w:bCs/>
<w:lang w:val="en-US" w:eastAsia="zh-CN"/>
</w:rPr>
</w:pPr>
<#list hp.hPImgWordList  as hpi>
<w:r>
<w:rPr>
<w:rFonts w:hint="fareast"/>
<w:b/>
<w:b-cs/>
<w:lang w:val="EN-US" w:fareast="ZH-CN"/>
</w:rPr>
<w:pict>
<w:binData w:name="wordml://${hpi.imgId}.jpg">
${hpi.imgurl}
</w:binData>
<v:shape id="图片 ${hpi.imgId}" o:spid="_x0000_s1026" o:spt="75" alt="20160810141549" type="#_x0000_t75" style="height:100pt;width:100pt;" filled="f" o:preferrelative="t" stroked="f" coordsize="21600,21600">
<v:path/>
<v:fill on="f" focussize="0,0"/>
<v:stroke on="f" joinstyle="miter"/>
<v:imagedata src="wordml://${hpi.imgId}.jpg" o:title="20160810141549"/>
<o:lock v:ext="edit" aspectratio="t"/>
<w10:wrap type="none"/>
<w10:anchorlock/>
</v:shape>
</w:pict>
</w:r>
</#list>
</w:p>
</#list>
</#list>

<w:p>
<w:pPr>
<w:rPr>
<w:rFonts w:hint="eastAsia"/>
<w:b/>
<w:bCs/>
<w:lang w:val="en-US" w:eastAsia="zh-CN"/>
</w:rPr>
</w:pPr>
</w:p>

 

其中主要代码为:

<#list hilist  as hii>//循环检查项目列表
<w:t>${hii.itemsName}</w:t>

<#list hii.houseProblemList  as hp> //循环该检查项目下的问题list

<w:t>${hp.problemDescription}</w:t>
<w:t>当前状态:${hp.handleStatus}</w:t>
<#list hp.hPImgWordList  as hpi> //循环该问题下的图片list
<w:binData w:name="wordml://${hpi.imgId}.jpg">
${hpi.imgurl}
</w:binData>
<v:shape id="图片 ${hpi.imgId}" o:spid="_x0000_s1026" o:spt="75" alt="20160810141549" type="#_x0000_t75" style="height:100pt;width:100pt;" filled="f" o:preferrelative="t" stroked="f" coordsize="21600,21600">
<v:path/>
<v:fill on="f" focussize="0,0"/>
<v:stroke on="f" joinstyle="miter"/>
<v:imagedata src="wordml://${hpi.imgId}.jpg" o:title="20160810141549"/>

</#list>
</#list>
</#list>

在引入图片的后面有设置代码格式

<v:shape id="_x0000_i1026" o:spt="75" alt="20160810141549" type="#_x0000_t75" style="height:100pt;width:100pt;" filled="f" o:preferrelative="t" stroked="f" coordsize="21600,21600"
o:gfxdata="">

其中的style可以设置图片的大小 ,<w:p></w:p>这应该是换行标志,所以<#list>一般放在<w:p>之前(个人推测)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值