使用freemarker生成HTML文件

好久没写博客了,不是没东西写而是犯懒不想写,最近实在积累太多不写点担心全丢了,反正前一阵子的东西时找不回来了啦,赶紧趁有时间、有激情、有记忆记点是点吧。好啦,罗里吧嗦到这里,言归正传。

最近弄一项目,要求把人的基本信息和各项事迹弄成一个简历,并且导出为word、html、pdf三种格式。导出为word和html都使用的freemarker,生成pdf使用的flying saucer技术,这些技术都比较娴熟了,网上的资料也比较多,这里根据自己的实际情况记载一下,以及做的过程中遇到的一些问题。

生成word这篇文件已经介绍过了,这里就不赘述了。这里说生成html文件。

生成html文件使用的技术和生成word是一样的,流程和模式也是一样的。

1、创建模板文件:写一个符合条件和样式要求的html页面或者jsp页面,然后将其中的具体内容使用EL进行格式化(具体的可以看生成word的那篇,讲的比较详情)。我这里的基本内容如下(内容比较多,节选):

<%--基本信息 --%>
<tr>
  <td class="resume-tit" >姓&nbsp;名</td>
  <td width="112" >${field2}</td>
  <td class="resume-tit" >性&nbsp;别</td>
  <td width="112" >${field3}</td>
  <%--电子照片 --%>
  <td width="120" align="center" rowspan="5">
  	<img width="120" height="150"  src="${field30}" />
  </td>
</tr>
<%--个人基本事迹 --%>
<#if (table4List?size>0)>
    <tr>
      <td class="resume-tit">获奖情况</td>
      <td colspan="4">
      <ul class="jlitem">
      	<#list table4List as t4>
			<li>${t4.order}、
				<b>成果名称</b>:${t4.field3}<br />
	      		<b>获奖名称及等级</b>:${t4.field4} &nbsp;
	      		<b>本人排名</b>:${t4.field5}</li>
		</#list>
	</ul>
      </td>
    </tr>
</#if>

这里有几个说明点

a、基本信息其实还有很多,个人基本事迹也有4个列表,这里只是截取其中一个比较有代表性的。

b、在freemarker中,可以使用<#if>标签进行判断。因为并不是每个人都有获奖的情况,若是没有那么在简历中获奖情况这块就不应该再显示。

c、获取list的长度,用size属性,结构:table4List?size,而且结合if使用时,一定要用括号将table4List?size括起来(形如:<#if (table4List?size>0)>),不然相当于没有判断

d、循环list,使用<#list>标签,各个属性值的获取参照放进去时候的赋值(第三步赋值有具体说明)

2、修改后缀名:修改第一步中的html/jsp文件的后缀名,改成ftl格式。

3、读取模板文件需要的数据:根据主键序号从数据库中读取基本信息,并放到一个map中进行返回。

基本属性直接使用key-value放到map中,如将姓名为wjl的放到map中,第一步中姓名的代替符是${field2},也就是field2,那么:map.put(”field2“,”wjl”),这样页面中显示的就是wjl了。

有循环的,需要先将基本内容放到map中,然后将map放到list里,再将list放到需要返回的map中,具体操作看代码。

/***
 * 该方法用来组装数据
 * @param id:专家序号
 * @param flag:1-word 2-html 3-pdf,主要是用来区分图片显示的问题
 * */
public List readData(String id,int flag) {
	if(id==null || id.trim().length()<=0){return null;}
	
	/** 用于组装word页面需要的数据 */
    Map<String, Object> dataMap = new HashMap<String, Object>();
    List list = null;
    try{
    	//1、获取基本信息
		StringBuffer sql = new StringBuffer();
		sql.append("select field1,field2,field3,field4,field5,field6,field7,field8,field9,field10,")
			.append("field11,field12,field13,field14,field15,field16,field17,field18,field19,field20,")
			.append("field21,field22,field23,field24,field25,field26,field27,field28,field29,")
			.append("(select filepath from S_ACCESSORIES where id=field13) as field30 ")
			.append("from table1 ")
			.append("where field1="+id);
//    		System.out.println(sql);
		List<Object[]> expertsList = execSQL.selectQuery2(sql.toString());
		String fileContent="";
		Object[] obj = null;
		if(expertsList!=null && expertsList.size()>0){
			obj = expertsList.get(0);//只取一条
			for(int i=0;i<obj.length;i++){
				if(obj[i]!=null){
					fileContent = obj[i].toString();
				}
				dataMap.put("field"+(i+1),fileContent);
				fileContent="";//置空
			}
			
			//出生日期格式调整
			String birthday = dataMap.get("field5").toString();
			if(birthday!=null && birthday.trim().length()>0){
				birthday = com.wjl.util.Time.formatStringDateToYYYYMMDD(birthday);
				dataMap.put("field5",birthday);
			}
			
			//图片路径
			String picture = dataMap.get("field30").toString();
			if(picture!=null && picture.trim().length()>0){//说明有值
				if(flag==3){//说明是导出为pdf,那么需要先生成html,此时文件加载使用绝对路径
					picture = "file:///"+picture;
				}else{//导出为word、html,需要生成base64编码的图片
					String prefix = picture.substring(picture.lastIndexOf(".")+1);
					picture = getImageStr(picture);//将图片变成base64编码
					if(picture!=null && picture.trim().length()>0){
						//说明是html格式,需要为base64编码的展示添加前缀否则显示不出来,word格式的可以直接显示
						if(flag==2)picture = "data:image/"+prefix+";base64,"+picture;
					}else picture="";
				}
			}else picture="";
			dataMap.put("field30",picture);
		}
		
		//获奖情况
		sql.delete(0,sql.length());
		sql.append("select field1,field2,field3,field4,field5 ").append("from table4 ").append("where field2="+id);
		List<Object[]> prizeList = execSQL.selectQuery2(sql.toString());
		List<Map<String, Object>> table4List=new ArrayList<Map<String,Object>>();
		if(prizeList!=null && prizeList.size()>0){
   	         for(int i=0;i<prizeList.size();i++){
   	        	Map<String, Object> map=new HashMap<String, Object>();
            		obj = prizeList.get(i);
	       	        map.put("order", (i+1));//序号(与模板文件中list各个属性一一对应)
	       	        map.put("field3", obj[2]);//成果名称
	       	        map.put("field4", obj[3]);//获奖名称及等级
	       	        map.put("field5", obj[4]);//本人排名
	       	        table4List.add(map);
   	         }
		}
	dataMap.put("table4List",table4List);
	list = new ArrayList();
        list.add(dataMap);
    }catch(Exception e){
    	e.printStackTrace();
    	return null;
    }
	return list;
}
@SuppressWarnings("unchecked")
//执行SQL
public List<Object[]> selectQuery2(final String sql) throws Exception {
	log.debug("执行sql语句: " + sql);
	List<Object[]> result=null;
	try {
			result = (List<Object [] > ) getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session arg0) throws HibernateException,
					SQLException {
				return arg0.createSQLQuery(sql).list();
			}
		});
	} catch (Exception e) {
		System.out.println("ERROR:" + e.getMessage());
		log.info("执行sql:[" + sql + "]失败:" + e.getMessage());
		log.error("执行sql:[" + sql + "]失败:" + e.getMessage(), e);
		throw e;
	}
	if(result!=null && result.size()>0){
		return result;
	}else{
		return null;
	}
}
/**
 * 将字符串类型的日期进行格式化,返回格式化之后字符串类型的日期
 * @param String strDate:字符串格式的日期
 * @return 字符串类型格式化后的日期,如:2016.06.05 
 * **/
public static String formatStringDateToYYYYMMDD(String strDate){
	if (strDate == null) 
        return ""; 
    SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");// 实例化模板对象  
    SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy.MM.dd");// 实例化模板对象  
    Date d = null ;  
    try{  
        d = sdf1.parse(strDate) ; // 将给定的字符串中的日期提取出来  
    }catch(Exception e){ // 如果提供的字符串格式有错误,则进行异常处理  
        e.printStackTrace() ;// 打印异常信息 
        logger.info(e);
    }  
    return sdf2.format(d);//按照规定格式进行格式化
}
/**
 * 该方法用来将指定的文件转换成base64编码
 * @param path:图片路径
 * **/
private String getImageStr(String path){
	//1、校验是否为空
	if(path==null || path.trim().length()<=0){return "";}
	
	//2、校验文件是否为目录或者是否存在
	File picFile = new File(path);
	if(picFile.isDirectory() || (!picFile.exists())) return "";
	
	//3、校验是否为图片
	try {  
	    BufferedImage image =ImageIO.read(picFile);  
	    if (image == null) {  
	    	return "";
	    }  
	} catch(IOException ex) { 
		ex.printStackTrace();
		return "";
	}
	
	//4、转换成base64编码
	String imageStr = "";
	try {
		byte[] data = null;
		InputStream in = new FileInputStream(path);
		data = new byte[in.available()];
		in.read(data);
		BASE64Encoder encoder = new BASE64Encoder();
		imageStr = encoder.encode(data);
	} catch (Exception e) {
		imageStr="";
		e.printStackTrace();
	}
	
	return imageStr;
}

说明点

a、图片显示问题。(详情点这里

b、模板文件中有的EL,返回的map中必须put进去否则会报错。如:模板文件中有个${field100},map中并没有put("field10",field100的内容)那么就会报错,生成的html也会说格式错误。

4、生成文件:使用模板文件生成html文件。

/**
* @Desc:生成word/html文件
* @param dataMap:数据集合
* @param templateFilePath:模板文件所在目录
* @param templateFileName:模板文件名称
* @param docFilePath:生成的word文档的具体目录,包括目录+名称+.doc
* @param boolean:true-创建成功 false:创建失败
*/
public boolean createFile(Map dataMap,String templateFilePath,String templateFileName,String docFilePath){
    try {
    	Configuration configuration = new Configuration();//创建配置实例 
        configuration.setDefaultEncoding("UTF-8");//设置编码
        configuration.setDirectoryForTemplateLoading(new File(templateFilePath));//加载模板文件
        Template template = configuration.getTemplate(templateFileName);//获取模板
        
        //创建文件
        File outFile = new File(docFilePath);
        //如果输出目标文件夹不存在,则创建
        if (!outFile.getParentFile().exists()){
            outFile.getParentFile().mkdirs();
        }
        //该文件已经存在,那么删除,避免更新了数据但是简历没有更新的情况发生
        if(outFile.isFile() && outFile.exists()){
        	outFile.delete();
        }
        //将模板和数据模型合并生成文件 
        Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile),"UTF-8"));
        //生成文件
        template.process(dataMap, out);
        //关闭流
        out.flush();
        out.close();
        return true;//返回文件路径
    } catch (Exception e) {
        e.printStackTrace();
        return false;
    }
}

5、组合:将获取数据和生成文件组合起来,并提供下载。

//将基本信息导出到word或者pdf
public String exportToFile() throws Exception{
	HttpServletRequest request = ServletActionContext.getRequest();
	Object userInfo = request.getSession().getAttribute("userInfo");
	if (userInfo == null)
		throw new Exception("用户信息获取失败:userInfo=null");
	try{
		String id = request.getParameter("id");
		Integer flag= Integer.parseInt(request.getParameter("flag"));//1-导出到word 2-导出为HTML 3-导出为pdf
		if(id!=null){
			//1、获取添加到word/html中的数据
			List dataList = readData(id,flag); 
			
			//2、生成word/html
			String path = "";
			//word文档目录
            String docFilePath = "D"+File.separator+":"+File.separator+"bfp"+File.separator+"temp";
            if(WebAppConfig.app("tempPath")!=null && WebAppConfig.app("tempPath").trim().length()>0){
            	docFilePath = WebAppConfig.app("tempPath");
            }
            String prefix="JM";
            if(WebAppConfig.app("docPrefix")!=null && WebAppConfig.app("docPrefix").trim().length()>0){
            	prefix = WebAppConfig.app("docPrefix");
            }
            boolean result2=false;
			if(dataList!=null && dataList.size()>0){
				Map dataMap = (Map)dataList.get(0);//集合数据
				//word文档名称
				String fileName = docFilePath+File.separator+prefix+System.currentTimeMillis();
				switch(flag){
				case 1:
					path = fileName+".doc";//word文档所在目录
					break;
				case 2://html
				case 3://pdf,生成pdf之前必须生成html
					tempWordName = "experts.ftl";//模板名称
					path = fileName+".html";//word文档所在目录
					break;
				default:break;
				}
			    //生成word或者html文件
	            result2 = createFile(dataMap,templateFilePath,tempWordName,path);//生成word
	            
	            if(flag==3 && result2==true){//生成pdf并且word已经生成
					//7、生成pdf
					//param1:pdf所在目录 param2:word/html所在目录
					result2 = createPDFByHtml(fileName+".pdf",path);
					//result2 = officeToPdf(new File(fileName+".pdf"),new File(path));//使用openoffice生成pdf
					path = fileName+".pdf";
				}
				//8、提供下载
				fileDown(new File(path));
			}
		}
	}catch(Exception e){
		e.printStackTrace();
	}
	return null;
}

/**
 * 进行下载
 * @param file:File对象,需要进行下载的对象
 * */
public void fileDown(File downFile){
	try{
		if (!downFile.exists())
			throw new Exception("没有找到您需要的资源:" + downFile.getName()+"!");
		HttpServletResponse response = ServletActionContext.getResponse();
		FileInputStream in = new FileInputStream(downFile);
//			response.setContentType("application/msword"); 
		response.setHeader("Content-Disposition","attachment;filename="+ new String(downFile.getName().getBytes("GBK"),"ISO-8859-1"));
		//response.reset();//解决:getWriter() has already been called for this response的问题  
        OutputStream outputStream = response.getOutputStream();  
        int i = 0;  
        byte b[] = new byte[1024];  
        while ((i = in.read(b)) != -1) {//读取文件  
            outputStream.write(b, 0, i);//写入到页面提供下载  
        }  
        outputStream.flush();  
        outputStream.close();  
        outputStream=null;  
        response.flushBuffer(); 
    }catch(Exception e){
    	e.printStackTrace();
    }
}

猜你喜欢

转载自1017401036.iteye.com/blog/2353518