利用freemarker转pdf和


java freemarker转PDF和Word
置顶 2018年04月27日 17:55:34 qq_35925291 阅读数:295 标签: freemake制作PDF和word java 生成PDF和Word
最近项目要求做一个freemarker转PDF和Word的功能,因为以前没用过,遇到了很多坑所以在这里记录一下,方便自己以后用到,不说了直接上代码:

1.先说PDF的

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

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

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;

扫描二维码关注公众号,回复: 3946928 查看本文章

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编码按字节截取字符串拼接
方法
* @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+"
";
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低版本的做,不然会出错,下篇说具体的制作方法)

猜你喜欢

转载自blog.csdn.net/jianghuchuanke/article/details/83269146