java freemarker转PDF和Word

   最近项目要求做一个freemarker转PDF和Word的功能,因为以前没用过,遇到了很多坑所以在这里记录一下,方便自己以后用到,不说了直接上代码:

1.先说PDF的

(1)先做一个模板(用HTML页面把你需要的模板文件画出来,记得用行内样式,所有标签必须闭合,画完之后复制一份改名为.ftl格式的文件)

正常的HTML文件就不贴了(画完之后里面什么都不用更改,再ftl文件里记得加上下面这两个,不然生成不了)

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<meta name="generator" content="Aspose.Words for .NET 15.1.0.0" />
   

 body {
   font-family: SimSun;
   backgrou nd: none;
   margin-left: 25px;
   margin-right: auto;
}

然后把需要替换值得地方用freemarker标签去替换;这是集合替换值得方法(key是别名)

        <#list tYxyUserMeal as key>
            <td>
                <div>${key.mealName}</div>
            </td>
        </#list> 

下面是对象替换方法(直接对象点属性就好);

      <li>版本日期:${dataTime.date}</li>

还有一种if判断的方法(我是判断值等于一或者二显示这一行    )

  <#if (tyxyKeywordConf.encryption) == "1" || (tyxyKeywordConf.encryption) == "2">
  </#if>

(2)Freemarker转化(tmppdfPath 是在你的电脑上找一个位置放置生成的HTML文件,这个直接可以使用只需要改模板名称就好)

    这个再不同的操作模式下路径//的转换方法

package com.ums.dmp.base.common;

import java.io.File;
import javax.servlet.http.HttpServletRequest;


public class GetWebProjectRealPathTool {
	 /** 
     * 获取项目在服务其中的真实路径的工具类 
     * 这是在web项目中,获取项目实际路径的最佳方式,在windows和linux系统下均可正常使用 
     */  
      
    //获取项目的根路径  
    public static String classPath = GetWebProjectRealPathTool.class.getClassLoader().getResource("/").getPath();  
    //对项目的根路径进行解析,拿到项目路径  
      
    public static String getRootPath() {  
        String rootPath = "";  
        //windows下  
        if("\\".equals(File.separator)){  
            System.out.println("windows");  
        rootPath = classPath.substring(1,classPath.indexOf("/WEB-INF/classes"));  
        rootPath = rootPath.replace("/", "\\");  
        }  
        //linux下  
        if("/".equals(File.separator)){  
            System.out.println("linux");  
        rootPath = classPath.substring(0,classPath.indexOf("/WEB-INF/classes"));  
        rootPath = rootPath.replace("\\", "/");  
        }  
        return rootPath;  
        }  
    
    
    public static String getBasePath(HttpServletRequest request){
    	String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()+request.getContextPath()+"/";
		return basePath;
    }
}

这个是转换方法

package com.ums.dmp.base.service.impl;

import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfGState;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import com.lowagie.text.pdf.BaseFont;
import com.ums.dmp.base.common.GetWebProjectRealPathTool;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

/**
 * html to pdf
 * 
 * @author yl
 * 
 */
public class H2p {
   private Logger logger = LoggerFactory.getLogger(getClass());
   private static H2p instance = new H2p();

   private H2p() {
   }

   public static H2p getInstance() {
      return instance;
   }

   
   private String tmppdfPath = GetWebProjectRealPathTool.getRootPath()
         + "/report/";

   /**
    * 接口文档 html to pdf
    * 
    * @param archiveInfoMap
    * @return
    * @throws Exception
    */
   public File preExportPdfForSh(Map<String, Object> archiveInfoMap)
         throws Exception {
      // UUID uuid = UUID.randomUUID();
      String outputFile = tmppdfPath + "接口文档"+ dateFormat()+".pdf"; // 生成的PDF名
      // a.创建一个合适的Configration对象
      Configuration configuration = new Configuration();
      // configuration.setDirectoryForTemplateLoading(new
      // File(basePath));//方式一:使用绝对路径设置模版路径
      configuration.setDirectoryForTemplateLoading(new File(tmppdfPath+File.separatorChar+"ftl"));
//    configuration.setClassForTemplateLoading(tmppdfPath, "ftl");// 方式二:使用所在类的相对路径设置模版路径
      configuration.setObjectWrapper(new DefaultObjectWrapper());
      configuration.setDefaultEncoding("UTF-8"); // 这个一定要设置,不然在生成的页面中 会乱码
      // b.获取或创建一个模版
      Template template = configuration.getTemplate("interfaceDoc.ftl");
      String outPutFileName = tmppdfPath + "interfaceDoc.html"; // 生成的html名
      File outFile = new File(outPutFileName); // 生成文件的路径
      Writer writer = null;
      writer = new BufferedWriter(new OutputStreamWriter(
            new FileOutputStream(outFile), "UTF-8"));
      // c.使用template将数据注入模版页面生成要转pdf的html页面
      template.process(archiveInfoMap, writer);
      writer.flush();
      // STEP2:使用itext将html页面转成PDF文件
      OutputStream os = new FileOutputStream(outputFile);
      String url = new File(outPutFileName).toURI().toURL().toString();
      // 生成ITextRenderer实例
      ITextRenderer renderer = new ITextRenderer();
      // 关联html页面
      renderer.setDocument(url);
      ITextFontResolver fontResolver = renderer.getFontResolver();
      //字体
      fontResolver.addFont("" + tmppdfPath + "Fonts/simsun.ttc",
            BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
      renderer.layout();
      renderer.createPDF(os);
      writer.close();
      os.close();
      File emptyPDfFile = new File(tmppdfPath + "接口文档" + dateFormat()+".pdf");
      if (!emptyPDfFile.exists()) {
         emptyPDfFile.createNewFile();
      }
//    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(emptyPDfFile));
//        // 将pdf文件先加水印然后输出
//        setWatermark(bos,outputFile);
//        bos.close(); 
        
      return emptyPDfFile;
   }

   
   /**
     * pdf 添加水印
     * @param bos 输出文件(空文件PDF)
     * @param input (输入文件 freemark 生成的pdf文件)
     * @throws DocumentException
     * @throws IOException
     * @throws com.lowagie.text.DocumentException
     */
    public void setWatermark(BufferedOutputStream bos, String input) throws DocumentException,  
            IOException,DocumentException {  
          
        PdfReader reader = new PdfReader(input);  
        PdfStamper stamper = new PdfStamper(reader, bos);  
        int total = reader.getNumberOfPages() + 1;  
        PdfContentByte content;  
        PdfGState gs = new PdfGState();  
        for (int i = 1; i < total; i++) {  
            content = stamper.getOverContent(i);// 在内容上方加水印  
            //content = stamper.getUnderContent(i);//在内容下方加水印  
            gs.setFillOpacity(0.2f);  
            content.setGState(gs);  
            String imageAbsolutPath = GetWebProjectRealPathTool.getRootPath() + "/images/yxlogo1.jpg";
            Image image = Image.getInstance(imageAbsolutPath);  
            image.setAbsolutePosition(-50, 50); // set the first background image of the absolute   
            content.addImage(image);  
        }  
        stamper.close();  
    } 

    /**+
     * 日期方法
     * @return
     */
     public  String dateFormat(){
      return new SimpleDateFormat("yyyyMMdd").format(new Date());
    }
   
}

(3)把所有数据以Map的形式封装好(日期封装只需要建一个日期的实体类DataTime)。

        我把这个PDF需要的所有数据放到一个Map里面一起返回的

package com.ums.dmp.base.service.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import sun.misc.BASE64Encoder;

import com.ums.dmp.base.common.GetWebProjectRealPathTool;
import com.ums.dmp.base.entity.DataTime;
import com.ums.dmp.base.entity.LabelInformationTable;
import com.ums.dmp.base.entity.TYxyKeywordConf;
import com.ums.dmp.base.entity.TYxyMeal;
import com.ums.dmp.base.entity.TYxyUserMeal;
import com.ums.dmp.base.entity.TagInformationTable;
import com.ums.dmp.base.entity.TyxySeviceMessage;
import com.ums.dmp.base.entity.TyxySeviceMessageFenZhi;
import com.ums.dmp.base.manager.LabelInformationTableManager;
import com.ums.dmp.base.manager.TYxyMealManager;
import com.ums.dmp.base.manager.TYxyUserMealManager;
import com.ums.dmp.base.manager.TagInformationTableManager;
import com.ums.dmp.base.manager.TyxyKeywordConfManager;
import com.ums.dmp.base.manager.TyxySeviceMessageFenZhiManager;
import com.ums.dmp.base.manager.TyxySeviceMessagerManager;
import com.ums.dmp.base.service.TYxyUserMealService;


@Service
public class TYxyUserMealServiceImpl implements TYxyUserMealService {

	@Autowired
	private TYxyUserMealManager tYxyUserMealManager;

	@Autowired
	private TyxyKeywordConfManager tyxyKeywordConfManager;

	@Autowired
	private TYxyMealManager tYxyMealManager;

	@Autowired
	private LabelInformationTableManager LabelInformationTableManager;

	@Autowired
	private TagInformationTableManager TagInformationTableManager;
	
	@Autowired
	private TyxySeviceMessageFenZhiManager tyxySeviceMessageFenZhiManager;
	@Autowired
	private TyxySeviceMessagerManager tyxySeviceMessagerManager;
	
		
	public Map<String, Object> getReportData(String userId, String mealId) {
		/**
		 * 根据用户号和套餐号查询套餐名称
		 */
		Map<String, Object> dbMap = new HashMap<>();
		List<TYxyUserMeal> tYxyUserMeal = tYxyUserMealManager.getMealNameByMealId(userId, mealId);
		dbMap.put("tYxyUserMeal", tYxyUserMeal);
		dbMap.put("mealId", mealId);
		/**
		 * 日期封装
		 */
		Date date = new Date();
	        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
	        String dayFormat=sdf.format(date);
	        DataTime dataTime = new DataTime();
	        dataTime.setDate(dayFormat);
	        dbMap.put("dataTime", dataTime);
		
		/**
		 * 根据用户号查询
		 */
		TYxyKeywordConf tyxyKeywordConf = tyxyKeywordConfManager.queryByUserId(userId, mealId);
		dbMap.put("tyxyKeywordConf", tyxyKeywordConf);

		/**
		 * 到套餐表中根据服务编号(meal_id)读取index_id字段信息
		 */

		List<String> indexIds = tYxyMealManager.selectmealId(mealId);
		
		/**
		 * 根据套餐表中index_id对应的flag字段信息: 0-到标签信息表(tag_information_table)读取标签名称
		 * 1-到指标信息表(label_information_table)读取指标名称
		 */
		List<Object> objs = new ArrayList<>();
		for (String indexId : indexIds) {
			TYxyMeal tYxyMealflag = tYxyMealManager.queryindexId(indexId,mealId);
			if (tYxyMealflag.getFlag().equals("0")) {
				// 到标签信息表(tag_information_table)读取标签名称
				LabelInformationTable table = LabelInformationTableManager.queryByIndexNames(indexId);
				objs.add(table);
			} else if (tYxyMealflag.getFlag().equals("1")) {
				// 到指标信息表(label_information_table)读取指标名称
				TagInformationTable table = TagInformationTableManager.selectIndexNames(indexId);
				objs.add(table);
			}

		}
		dbMap.put("objs", objs);
		 /**
		    * 根据comb查询请求报文和响应报文
		    * @param comb
		    * @return
		    */
		TyxySeviceMessageFenZhi tyxySeviceMessager=tyxySeviceMessageFenZhiManager.selectbaowen(mealId);
		
		dbMap.put("tyxySeviceMessager", tyxySeviceMessager);
		
		return dbMap;
	}	
	

(4)因为转PDF是不能自动换行的所以我写了一个方法直接调用就好(这个工具类直接使用就好)

package  com.ums.dmp.base.common;
import java.awt.FontMetrics; 
import javax.swing.JLabel; 
import java.io.UnsupportedEncodingException;

/**
 * 按字节截取字符串util
 * @author yl
 *
 */
public class NewlinetoolUtil {
	/**
	 * jkb编码按字节截取字符串拼接<br/>方法
	 * @param str
	 * @param bytes
	 * @param charSetName
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	public static String subStringOnlyByGBK(String str, int bytes){ 
		String result = "";    // 每次循环截取的字符串的内容
		String parameter="";   // 最后返回的结果字符串
		int i = 0;             // 已经截取字符串的长度累计和
		int j = 0;             // 已经截取字符串的字节长度累计和
		int y = 0;             // 每次循环截取字符串的的长度
		int t = 0;             // 已经截取过的字符串的长度和
		byte[] a;              // 减掉截取过的剩下的字符串的字节数组
		if(str != null){
		        try {  
		        	int length = str.getBytes("GBK").length;// 获取整个字符串的字节长度
		            while(true){ 
		            	a = str.substring(i, str.length()).getBytes("GBK");
		            	if(bytes<length-j){
		            		 result = new String(a, 0, bytes);
		            		 t = result.length(); 
		            		 y= y+t;
		            		if(str.charAt(y-1) != result.charAt(t-1)){
		            			//如果截取最后一个字,产生乱码情况,则替换为后一个字。
		            			result = result.replace(result.charAt(t-1), str.charAt(y-1));
		            			j +=1;
		            		}
		            		parameter+=result+"<br/>";
		            		j += bytes;
		            		i += result.length();
		            	}else{
		            		break;
		            	}
		              }  
		           
		        } catch (UnsupportedEncodingException e) {  
		            e.printStackTrace();  
		        }  
		        // 加上截取之后后面剩余字符串
		        parameter+=str.substring(i,str.length()); 
		    	
    	}
		        return parameter;  
	   } 
	
	
	 
		/**
		 * 按字节截取字符串拼接<br/>通用方法
		 * @param str
		 * @param bytes
		 * @param charSetName
		 * @returnsubStringByBytes
		 */
		 public static String subStringByPX(String str, int bytes,String encode){ 
				String result = "";    // 每次循环截取的字符串的内容
				String parameter="";   // 最后返回的结果字符串
				int i = 0;             // 截取掉的字符串的总长度
				int j = 0;             // 截取掉的字符串的字节长总度
				String ss= "";         // 减掉截取过的剩下的字符串
				if(str != null){
				        try {  
				        	int length = str.getBytes(encode).length;// 获取整个字符串的字节长度
				            while(true){ 
				            	ss = str.substring(i, str.length());
				            	if(bytes<length-j){
				            		//循环每次截取的结果
				       		      	result = idgui(ss,bytes,encode);
				            		parameter+=result+"<br/>";
				            		//截取掉的字符串字节数
				            		j += result.getBytes(encode).length;
				            		//截取掉的字符串长度
				            		i += result.length();
				            	}else{
				            		break;
				            	}
				              }  
				           
				        } catch (UnsupportedEncodingException e) {  
				            e.printStackTrace();  
				        }  
				        // 加上截取之后后面剩余字符串
				        parameter+=str.substring(i,str.length()); 
				    	
		    	}
				        return parameter;  
			   } 
	
	 
		 public static String idgui(String str,int bytes,String encode){
			    int changdu;
				try {
					changdu = str.getBytes(encode).length;
					if(changdu > bytes){
						str = str.substring(0, str.length() - 1);
						str = idgui(str,bytes,encode);
					}
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}
			    return str;
			  }
		 
		 /**
		  * 按像素截取字符串加</br>
		  * @param str
		  * @return
		  */
		 public static String subStringByBytes(String str){ 
			 char[] charArray = str.substring(0, str.length()).toCharArray();
				String result = "";    // 每次循环截取的字符串的内容
				String parameter="";   // 最后返回的结果字符串
				String sheng ="";     // 每次循环剩下的字符串
				String p = "";
				int j = 0;
				JLabel label3 = new JLabel(str); 
				FontMetrics metrics3 = label3.getFontMetrics(label3.getFont()); 
				int textW3 = metrics3.stringWidth(label3.getText()); //字符串的宽
				if(str != null && textW3 > 600){
						for(int i = 0; i<=charArray.length-1; i++){
							result+=charArray[i];
							JLabel label = new JLabel(result); 
							FontMetrics metrics = label.getFontMetrics(label.getFont()); 
							int textW = metrics.stringWidth(label.getText()); //字符串的宽
							if(textW <= 600 && textW >= 587){
								parameter+=result+"<br/>";
								p+=result;
								result = "";
								j = p.length();
								sheng = str.substring(j, str.length());
								JLabel label2 = new JLabel(sheng); 
								FontMetrics metrics2 = label2.getFontMetrics(label2.getFont()); 
								int textW2 = metrics2.stringWidth(label2.getText()); //字符串的宽
								if(textW2 <= 600){
									parameter+=sheng;
									break;
								}
							}
						}
						return parameter;  
		    	}
		    		return str;
		 } 		 		 
}

(5).使用的方法在实体类的get()方法调用就好

	public String getRespMessage() {
		if (this.respMessage != null
				&& this.respMessage.indexOf("<br/>") == -1) {
			this.respMessage = NewlinetoolUtil.subStringByPX(this.respMessage, 90, "UTF-8");
		}
		return respMessage;
	}

4.最后是下载的调用方法(Falg是我有两个 我是判断要下载word还是PDF)

package com.ums.dmp.base.controller;


import com.ums.dmp.base.service.TYxyUserMealService;
import com.ums.dmp.base.service.impl.H2p;
import com.ums.dmp.base.service.impl.MDoc;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.URLEncoder;
import java.util.Map;



/**
 * 获取接口文档控制器
 * 
 * @author yl
 * 
 */
@RestController
@RequestMapping("/downloadFile")
public class KeywordConfXZController {

		
	private Logger logger = LoggerFactory.getLogger(getClass());
	@Autowired
	private TYxyUserMealService tYxyUserMealService;

	/**
	 * 生成文档
	 * 
	 * @param
	 * @param req
	 * @return
	 * @throws IOException
	 */
	@RequestMapping("/download.do")
	public ResponseEntity<byte[]> download(String userId,String mealId,String flag,HttpServletRequest req)
			throws IOException {
		Map<String, Object> baseInfoMap = null;				
	
	    File file = null;
			try {
				if ("1".equals(flag)) {
					logger.info("开始进行PDF文件的参数获取");
					baseInfoMap = tYxyUserMealService.getReportData(userId, mealId);
					logger.info("开始进行PDF文件的参数获取成功");
					file = H2p.getInstance().preExportPdfForSh(baseInfoMap);
				} else if ("0".equals(flag)) {
					baseInfoMap = tYxyUserMealService.createWord(userId, mealId);
					file=MDoc.getInstance().createDoc(baseInfoMap);
				}
			} catch (Exception e) {
				// return 提示生成文档失败
				logger.error("生成文档失败");
			}
			InputStream in;
	        ResponseEntity<byte[]> response=null ;
	        try {
	            in = new FileInputStream(file);
	            byte[] b=new byte[in.available()];
	            in.read(b);
	            HttpHeaders headers = new HttpHeaders();
				String fileName = "";
				String userAgent = req.getHeader("user-agent").toLowerCase();
				if (userAgent.contains("msie") || userAgent.contains("like gecko")) {
					// win10 ie edge 浏览器 和其他系统的ie
					fileName = URLEncoder.encode(file.getName(), "UTF-8");
				} else {
					fileName = new String(file.getName().getBytes("UTF-8"), "iso-8859-1");
				}
	            
	            headers.add("Content-Disposition", "attachment;filename="+fileName);
				headers.setContentType(MediaType.APPLICATION_PDF);
	            
	            HttpStatus statusCode=HttpStatus.OK;
	            response = new ResponseEntity<byte[]>(b, headers, statusCode);  
	            in.close();
	        } catch (FileNotFoundException e) {
	            // TODO Auto-generated catch block
	            e.printStackTrace();
	        } catch (IOException e) {
	            // TODO Auto-generated catch block
	            e.printStackTrace();
	        }
	        return response;	
	   }
   }

5.word的方法和PDF得差不多(只是模板的制作方法不一样,word的模板制作切记用office低版本的做,不然会出错,下篇说具体的制作方法)


  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值