RTFTemplate巧妙的利用了word的“域”和书签实现了报表模板的设计。通过向rtf插入特定类型的域字段,用来标记将会被报表引擎用实际数据或者逻辑替代的部分。

通常单一的值用:Mergefield代替。

循环和条件采用:bookmark替代。

RefTemplate底层采用了两类模板引擎:

第一类:Jakarta Velocity

第二类:freemark

采用的模板不同生成的中间模板文件略有差异(这是必然)。

设计模板的方法:

1.  编辑好报表模板。

2.  如果是单一值得话插入域。

MS Word207 插入域的方法:

插入->文档部件->域à类别选择(邮件合并、或者不选)->域名(F)选择“MergeField”->域属性中域名输入” $Attribute.field” (注:Attribute为填充对象名,field是其属性,注意大小写长度不宜太长)。

插入后手动删除域两边的和(如:),如果不删除的话中文显示会有一定的编码问题。

1.  循环

在循环开始及结束位置分别插入bookmark 命名分别为:START_LOOP_{i},END_LOOP_{i},循环的开始和结束需要相呼应。引擎会自动根据循环内部的内容去变量循序对象。

4.      条件

在条件对应位置插入bookmark命名为IF_{i},ELSE_{i},ENDIF_{i}.

5.      MS Word207 插入书签的方法:

插入->书签

6.  对于表格不需要我们在外层加入循环,rtftemplate会根据模板和数据智能解析。

7.      完成上述的定义操作即可实现抽象类AbstractRTFUseCase类的

protectedvoidputContext(IContext context) 方法(数据填充方法)

通过调用run(模板文件)即可将文件将模板和数据相结合,产生最终结果。

我们可以通过该类的:saveTransformedDocument(true)方法设定是否输出模板转换结果该结果文件用来核对产出物是否正确。(实际上最终生成是调用freemark 或者Jakarta Velocity生成的)。

我们可以通过saveXmlFields(xmlFieldsAvailable, false);来设定是否输出xml文件用来核对相关字段是否解释正确。

8.至此我们就完成了rtf报表输出的相关工作。

该引擎的缺陷:

该引擎每次都会由rtf模板文件生成最终引擎所需要的模板文件。运行效率低下,且存在转换结果不一致的现象。对于相对简单的报表该引擎基本满足,但是循环嵌套较多的模板实测结果不是很理想。

在实际项目中笔者通过了rtftemplate 生成了模板文件的初步rtf模板,在文本编辑器中调整了相关的属性后直接采用了使用freemark加载模板的方式,生成了报表。实际测试运行情况稳定。在该方式中rtftemplate充当了报表设计器的角色。

使用RTFtemplate直接加载freemark模板范例:

定义如下类:

public class RTFGenerator {private Map<String, Object> contextMap;private RTFTemplate rtfTemplate = null;private File transformerConfigFile = null;private ApplicationContext applicationContext;private String rtfTemplateImpl;private boolean saveTransformedDocument = false;private String outDirectory = null;/*** This value allow to group by content when there is PageBreak in order to* group by content.*/private int groupByPerPageBreak = -1;// true if context has circular references and false otherwiseprivate boolean circularReferences = false;public RTFGenerator(String outDirectory,Map<String, Object> contextMap) {this.outDirectory = outDirectory;this.contextMap = contextMap;}/*** Run RTFTemplate for merging rtfSource with the context putted with the* method putContext which be must implement. After execution of this* method, files rtfSource + ".<rtfTemplateImpl>.rtf" (RTF template* implementation (vmRTFtemplate,...) and rtfSource + ".out.rtf" (RTF final* with values of the context) will be generate.* * @param rtfSource*            RTF source model.* @throws Exception*/public final void run(String rtfSource, String rtfTagert) throws Exception {File rtfSourceFile = new File(rtfSource);String rtfTransformedDocumentOutput = rtfSource + "."+ getRtfTemplateImpl() + ".rtf";//String rtfOutput = rtfSource + "." + getRtfTemplateImpl() + ".out.rtf";String rtfOutput = rtfTagert;rtfTransformedDocumentOutput = rtfTagert + "_temp.rtf";if (outDirectory != null) {// Create out DirectoryFile out = new File(outDirectory);out.mkdirs();/*rtfTransformedDocumentOutput = outDirectory + "/"+ rtfSourceFile.getName() + "." + getRtfTemplateImpl()+ ".rtf";rtfOutput = outDirectory + "/" + rtfSourceFile.getName() + "."+ getRtfTemplateImpl() + ".out.rtf";*/}/*** 1. Get RTFtemplate builder*/RTFTemplateBuilder builder = null;if (applicationContext == null)builder = RTFTemplateBuilder.newRTFTemplateBuilder();elsebuilder = RTFTemplateBuilder.newRTFTemplateBuilder(applicationContext);/*** 2. Get RTFtemplate with Implementation*/this.rtfTemplate = builder.newRTFTemplate(rtfTemplateImpl);this.rtfTemplate.setGroupByPerPageBreak(groupByPerPageBreak);this.rtfTemplate.setCircularReferences(circularReferences);/*** 3. Put default format*/putDefaultFormat(rtfTemplate);//        VelocityTemplateEngineImpl templateEngine = new VelocityTemplateEngineImpl();
//        VelocityEngine velocityEngine = new VelocityEngine();
//        velocityEngine.setProperty("input.encoding ", "UTF-8");
//        velocityEngine.setProperty("output.encoding", "GBK");
//        velocityEngine.setProperty ("response.encoding", "GBK-8");
//        templateEngine.setVelocityEngine(velocityEngine);FreemarkerTemplateEngineImpl templateEngine = new FreemarkerTemplateEngineImpl();rtfTemplate.setTemplateEngine(templateEngine);  /*** 4. Create a common inner context - not required but showing how* common context values can be re-used*/IContext ctx = rtfTemplate.getTemplateEngine().newContext();putGlobalContext(ctx);/*** 5. Set the template*/rtfTemplate.setTemplate(rtfSourceFile);/*** 6. Set Global Context*/rtfTemplate.setGlobalContext(ctx);/*** 7. Set Transformer Config*/if (transformerConfigFile != null) {TransformerConfig transformConfig = DigesterTransformerConfig.getTransformerConfig(new FileInputStream(transformerConfigFile));rtfTemplate.setTransformerConfig(transformConfig);}/*** 8. Put Context*/putContext(rtfTemplate.getContext());if (saveTransformedDocument) {RTFDocument transformedDocument = rtfTemplate.transform();transformedDocument.save(new File(rtfTransformedDocumentOutput));}/*** 9. Merge template and context*/rtfTemplate.merge(rtfOutput);}/*** Return String XML Mergefields used in your context and Bookmarks (for* start and end loop)* * @return*/public String getXMLFields() {// XMLRTFXmlFieldsReader reader = new RTFXmlFieldsReader();reader.readContext(rtfTemplate.getContext(), rtfTemplate.getTransformerConfig(), rtfTemplate.isCircularReferences());return reader.getXMLFields();}protected void putDefaultFormat(RTFTemplate template) {}protected void putGlobalContext(IContext context) {}/*** Save XML fields available into file. If force parameter is false, the* file is updated with new context (by keeping just description) otherwise* the file is crushed with new context.* * @param filename* @throws Exception*/public void saveXmlFields(String filename, boolean force) throws Exception {RTFContextFieldsReader reader = new RTFContextFieldsReader();reader.readContext(rtfTemplate.getContext(), rtfTemplate.getTransformerConfig(), rtfTemplate.isCircularReferences());RTFContextUtil.saveXmlFields(filename, reader.getContextFields(), force);}/*** This method must be implement by class wich manage your RTF model. Put* the context of your model (eg : context("date", new Date()); )* * @param context*            IContext*/protected void putContext(IContext context){for (String key : contextMap.keySet()) {context.put(key, contextMap.get(key));}}public void setTransformerConfigFile(String transformerConfig) {setTransformerConfigFile(new File(transformerConfig));}public void setTransformerConfigFile(File transformerConfigFile) {this.transformerConfigFile = transformerConfigFile;}/*** set true if RTF with (velocity, freemarker,... macro) file must be* generated and false otherwise.* * @param saveTransformedDocument*/public void saveTransformedDocument(boolean saveTransformedDocument) {this.saveTransformedDocument = saveTransformedDocument;}public String getRtfTemplateImpl() {if (rtfTemplateImpl == null) {/*** Default RTFTemplate is Velocity*///this.rtfTemplateImpl = RTFTemplateBuilder.DEFAULT_VELOCITY_RTFTEMPLATE;this.rtfTemplateImpl = RTFTemplateBuilder.DEFAULT_FREEMARKER_RTFTEMPLATE;}return rtfTemplateImpl;}public void setRtfTemplateImpl(String rtfTemplateImpl) {this.rtfTemplateImpl = rtfTemplateImpl;}protected int getGroupByPerPageBreak() {return groupByPerPageBreak;}/*** This value allow to group by content when there is PageBreak in order to* group by content.* * @param groupByPerPageBreak*/protected void setGroupByPerPageBreak(int groupByPerPageBreak) {this.groupByPerPageBreak = groupByPerPageBreak;}protected RTFTemplate getRtfTemplate() {return rtfTemplate;}protected void setApplicationContext(ApplicationContext applicationContext) {this.applicationContext = applicationContext;}public boolean isCircularReferences() {return circularReferences;}/*** true if context has circular references and false otherwise* @param circularReferences*/public void setCircularReferences(boolean circularReferences) {this.circularReferences = circularReferences;}}

调用代码:

Map<String, Object> contextMap = new HashMap<String, Object>();UseCaseLog logger = new UseCaseLog();logger.logTitle("Start export report...");// Create out Directory// Generate RTF file by using RTF model table.rtf//String rtfSource = SpringContextHolder.getRootRealPath() +   "/report/template/proi.rtf";String rtfSource = SpringContextHolder.getRootRealPath() +   "/report/template/rtf_temp.rtf";String rtfTarget = SpringContextHolder.getRootRealPath() + "/report/" + saveName +".rtf";String outputPath = SpringContextHolder.getRootRealPath() + "/report/";System.out.println(rtfSource);System.out.println(rtfTarget);System.out.println(outputPath);putContextVal(contextMap,projectId,reportName);RTFGenerator usecase = new RTFGenerator(outputPath, contextMap);/*** Set Velocity as RTFTemplate implementation* */// usecase.setRtfTemplateImpl(RTFTemplateHelper.DEFAULT_VELOCITY_RTFTEMPLATE);// => this line is// not required, because by default velocity is the default RTFTemplate// implementationusecase.saveTransformedDocument(false); // Save RTF file with velocity// macrousecase.run(rtfSource, rtfTarget);logger.logTitle("End export report!");

数据填充:

private void putContextVal(Map<String, Object> context ,String projectId,String reportName) {// TODO Auto-generated method stub// 项目基本信息getProjectBaseInfo(context, projectId,reportName);
}

注意事项:

1.  中文编码问题

a)   中文输出乱码时在填充context时对String内容进行编码

核心方法:

public class GBKEncoded {public static String getEncodedRTFString(String sourceStr)  {try{return java.net.URLEncoder.encode(sourceStr, "GBK").replaceAll("%", "\\\\'").replaceAll("\\+", " ");}catch(Exception ex){return sourceStr;}}/*** @param args*/public static void main(String[] args) {// TODO Auto-generated method stub}}

2.  图片处理

a)   图片需转换为rtf对应格式的字符串转换

核心方法如下:

package net.sourceforge.rtf.format;import java.io.InputStream;
import java.text.FieldPosition;
import java.text.Format;
import java.text.ParsePosition;import net.sourceforge.rtf.context.image.FormatBase;
import net.sourceforge.rtf.context.image.ImageConstants;import org.apache.commons.io.IOUtils;
/*** Description : Format for Input Stream.* @version 1.0.0* @author <a href="mailto:angelo.zerr@gmail.com">Angelo ZERR</a>*/
public class DefaultInputStreamFormat extends Format {public static final long serialVersionUID = 1L;public StringBuffer format(Object arg0, StringBuffer arg1, FieldPosition arg2) {InputStream in = (InputStream) arg0;byte[] imagedata = null;try {imagedata = IOUtils.toByteArray(in);}catch (Exception e) {} finally {IOUtils.closeQuietly(in);}StringBuffer buf = new StringBuffer("");if (imagedata != null) {// Test if image date is imageFormatBase imageformat = FormatBase.determineFormat(imagedata);if (!(imageformat.getType() == ImageConstants.I_NOT_SUPPORTED| imageformat.getRtfTag() == "")) {buf = new StringBuffer(imagedata.length * 3);for (int i = 0; i < imagedata.length; i++) {int iData = imagedata [i];// Make positive byteif (iData < 0) {iData += 256;}if (iData < 16) {// Set leading zero and appendbuf.append('0');}buf.append(Integer.toHexString(iData));}buf.insert(0, "{\\*\\shppict{\\pict\\" + imageformat.getRtfTag() + " ");buf.append("}");buf.append("}");}}return buf;}public Object parseObject(String arg0, ParsePosition arg1) {// TODO Auto-generated method stubreturn null;}}

利用RTFtemplate生成rtf报表相关推荐

  1. 利用POI生成EXCEL报表(通过web页面导出后台数据)

    很多时候需要将数据利用浏览器进行导出,这个时候我们就可以采用Apache的POI进行实现通过web页面实现Excel导出后台数据,并且以.xlsx的形式下载到本地,也就是excel表格形式. 首先先下 ...

  2. SpringCloud之利用FTL生成Word报表并下载

    1.首先,新建一个word文档:里面写需要下载的东西 2.编辑完后,另存为xml格式(不用管xml里面是什么),然后将后缀名xml改为ftl 3.这个ftl就是在Java代码中可生成word的模板文件 ...

  3. 学习利用ReportLab生成PDF报表 -- RML基础(The Basics)

    以下内容均参考RML User Guide文档(部分为译文,还有一份RML for idiots文档更适合入门),文档中的Demo都在 https://www.reportlab.com/docume ...

  4. 利用iText生成pdf报表

    任务书.期中检查.延期申请书 一.    需要用到的支持 包支持:向java工程导入两个包 iText.jar,iTextAsian.jar(汉字支持包) 软件支持:Adobe Acrobat Pro ...

  5. PB利用SaveAs生成PDF报表

    PB9为例: ADIST5.INF驱动文件只支持32位电脑 1.下载安装gs705w32.exe 下载地址:gs705w32.exe 2.添加环境变量 path:C:\gs\gs7.05\bin PS ...

  6. 性能碾压 POI !利用模板语法快速生成 Excel 报表

    本期讲师:刘鹏 GcExcel项目组,核心开发者 Hello,大家好,本期葡萄城技术公开课,将由我来为大家带来<性能碾压 POI !利用模板语法快速生成 Excel 报表>的技术分享. 本 ...

  7. c#中嵌入echarts_利用c#+jquery+echarts生成统计报表(附源代码)

    背景: 因为最近项目要生成报表,经过几轮挑选,最终选择了百度的echarts作为报表基础类库.百度echarts简介请参考虽然echarts功能强大,界面优美, 但是使用起来非常繁琐.本文在参考写的& ...

  8. jasper生成动态报表

    jasper生成动态报表 业务:客户点击链接(get请求),在页面显示报表.根据请求信息动态获取报表. 环境/工具:springboot ,IDEA编译器, TIBCO JasperSoft TIBC ...

  9. 利用owc生成excel并且显示在页面

    主要利用OWC生成Excel,画表头和显示从数据库读出来的数据,然后显示在前台页面上,无需客户端安装office,只需要安装owc.一年以前写的,似乎很烦锁,哪位有高见请指教! 后面利用OWC操作EX ...

  10. 使用SQLPLUS生成HTML报表

    我们可以在SQLPLUS中手工运行AWR,ASH的脚本生成HTML报表,下面来简单讲讲怎么利用SQLPLUS来生成HTML报表 在SQLPLUS中有个命令(具体可以参考官方文档SQLPLUS部分) S ...

最新文章

  1. “由于/bin 不在PATH 环境变量中,故无法找到该命令”
  2. python 时间字符串
  3. Bluetooth LE(低功耗蓝牙) - 第五部分
  4. Android当中layer-list使用来实现多个图层堆叠到一块儿
  5. .NET平台功能最强大,性能最佳的JSON库
  6. 如何对web.config进行加密和解密
  7. android提示程序正在执行,Android中获取正在运行的进程(一)
  8. 三星linux打印机驱动官网下载,三星SL-C515驱动
  9. 基于SpringBoot 2.3的WebService指南(包含案例)
  10. python处理excel表格-60万行的Excel数据,Python轻松处理
  11. python 把当前目录文件夹中的所有图片缩放为640*480
  12. 云存储安全,主要面临哪些问题
  13. 压缩PPT文件的技巧
  14. 解密excel工作表保护
  15. “黑暗潜伏者” -- 手机病毒新型攻击方式
  16. 微信小程序base64转为二维码、条形码图片
  17. 感慨一下中年人的焦虑
  18. Jscex没有xxxAsync().stop()怎么办?
  19. [离散数学]谓词逻辑与推理演算
  20. java程序员具体是做什么的?我来分享一天的工作内容

热门文章

  1. Python 中使用 ImageJ 详细教程
  2. 单纯形法的代码实现与退化算例
  3. 【电源科普】负载调整率
  4. RetinaFace+ArcFace人脸识别测试
  5. matlab中solver函数_matlab solve函数的用法
  6. matlab绘制符号函数的ezplot函数
  7. 战旗助手服务器代码,炉石传说酒馆战旗助手
  8. 画法几何及工程制图考试卷A卷
  9. 毕业论文:vrml设计的虚拟校园
  10. 3dmax java,基于Java 3D与3DS MAX的虚拟校园设计