报表存储目录配置
在第二小节中,我们介绍如何搭建一个包含UReport2的项目,在运行项目后,我们发现在项目的WEB-INF目录有会自动生成了一个名为“ureportfiles”目录,这个目录是UReport2提供的默认的报表文件存储目录,也就是说默认情况下,UReport将在项目的WEB-INF/ureportfiles目录下存储设计好的报表文件。
运行我们搭建好的项目,打开报表设计器,点击工具栏上的保存按钮(),选择“保存”,可以看到如下图所示的弹出窗口:
在这个窗口,我们只要输入报表名称,同时再选择报表的存储目的地就,可以保存当前报表文件。可以看到,UReport2默认给我们提供的存储目的地是“服务器文件系统 ”,实际上就是我们项目中WEB-INF目录下的“ureportfiles”目录,这个目录是系统默认自动生成的,如果需要我们可以添加一个属性来更改这个目录位置。
在我们项目的WEB-INF目录下创建一个名为config.properties,打开位于WEB-INF下名为context.xml的spring配置文件,在其中添加如下Bean以加载这个config.properties文件(如果我们的项目中已有自己的Properties文件,那么直接在这个Properties文件中配置即可)。
<bean id="propertyConfigurer" parent="ureport.props"> <property name="location"> <value>/WEB-INF/config.properties</value> </property> </bean>
打开config.properties文件,在其中添加名为“ureport.fileStoreDir”的属性,该属性的值用于定义UReport2中提供的默认基于文件系统的报表存储目录,比如定义该属性为下面样式:
表示在D盘根下名为ureportfiles的目录中存储报表文件,需要注意的是,这里指定特定目录时,一定要保存这个目录已存在,否则将不会被采用,比如上面的D盘下名为ureportfiles的目录,就需要我们预先创建好。
自定义报表存储器
UReport2默认提供的名为“服务器文件系统”的报表存储机制,实际上是实现了UReport2提供的com.bstek.ureport.provider.report.ReportProvider接口,该接口源码如下:
package com.bstek.ureport.provider.report; import java.io.InputStream; import java.util.List; /** * @author Jacky.gao * @since 2016年12月4日 */ public interface ReportProvider { /** * 根据报表名加载报表文件 * @param file 报表名称 * @return 返回的InputStream */ InputStream loadReport(String file); /** * 根据报表名,删除指定的报表文件 * @param file 报表名称 */ void deleteReport(String file); /** * 获取所有的报表文件 * @return 返回报表文件列表 */ List<ReportFile> getReportFiles(); /** * 保存报表文件 * @param file 报表名称 * @param content 报表的XML内容 */ void saveReport(String file,String content); /** * @return 返回存储器名称 */ String getName(); /** * @return 返回是否禁用 */ boolean disabled(); /** * @return 返回报表文件名前缀 */ String getPrefix(); }
实现了ReportProvider接口后,只需要将实现类配置到Spring中,让其成为一个标准的Spring Bean,这样UReport2就会检测到它而将其加载。下面是UReport2默认提供的名为“服务器文件系统”的报表存储器源码:
package com.bstek.ureport.provider.report.file; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.Comparator; import java.util.List; import javax.servlet.ServletContext; import org.apache.commons.io.IOUtils; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.web.context.WebApplicationContext; import com.bstek.ureport.exception.ReportException; import com.bstek.ureport.provider.report.ReportFile; import com.bstek.ureport.provider.report.ReportProvider; /** * @author Jacky.gao * @since 2017年2月11日 */ public class FileReportProvider implements ReportProvider,ApplicationContextAware{ private String prefix="file:"; private String fileStoreDir; private boolean disabled; @Override public InputStream loadReport(String file) { if(file.startsWith(prefix)){ file=file.substring(prefix.length(),file.length()); } String fullPath=fileStoreDir+"/"+file; try { return new FileInputStream(fullPath); } catch (FileNotFoundException e) { throw new ReportException(e); } } @Override public void deleteReport(String file) { if(file.startsWith(prefix)){ file=file.substring(prefix.length(),file.length()); } String fullPath=fileStoreDir+"/"+file; File f=new File(fullPath); if(f.exists()){ f.delete(); } } @Override public List<ReportFile> getReportFiles() { File file=new File(fileStoreDir); List<ReportFile> list=new ArrayList<ReportFile>(); for(File f:file.listFiles()){ Calendar calendar=Calendar.getInstance(); calendar.setTimeInMillis(f.lastModified()); list.add(new ReportFile(f.getName(),calendar.getTime())); } Collections.sort(list, new Comparator<ReportFile>(){ @Override public int compare(ReportFile f1, ReportFile f2) { return f2.getUpdateDate().compareTo(f1.getUpdateDate()); } }); return list; } @Override public String getName() { return "服务器文件系统"; } @Override public void saveReport(String file,String content) { if(file.startsWith(prefix)){ file=file.substring(prefix.length(),file.length()); } String fullPath=fileStoreDir+"/"+file; FileOutputStream outStream=null; try{ outStream=new FileOutputStream(new File(fullPath)); IOUtils.write(content, outStream,"utf-8"); }catch(Exception ex){ throw new ReportException(ex); }finally{ if(outStream!=null){ try { outStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } @Override public boolean disabled() { return disabled; } public void setDisabled(boolean disabled) { this.disabled = disabled; } public void setFileStoreDir(String fileStoreDir) { this.fileStoreDir = fileStoreDir; } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { File file=new File(fileStoreDir); if(file.exists()){ return; } if(applicationContext instanceof WebApplicationContext){ WebApplicationContext context=(WebApplicationContext)applicationContext; ServletContext servletContext=context.getServletContext(); String basePath=servletContext.getRealPath("/"); fileStoreDir=basePath+fileStoreDir; file=new File(fileStoreDir); if(!file.exists()){ file.mkdirs(); } } } @Override public String getPrefix() { return prefix; } }
通过上面的介绍,可以看到,通过实现ReportProvider接口,我们可以很容易的开发出其它类型的报表存储器,比如开发一个新的报表存储器将报表文件存储到数据库、FTP等。
配置报表数据源
打开UReport2的报表设计器,可以看到UReport2提供了三种类型的报表数据源,如下图所示:
三种类型的数据源分别是直接连接数据库,Spring Bean以及通过实现com.bstek.ureport.definition.datasource.BuildinDatasource接口提供的内置数据源。
直接连接数据库比较简单,就是在项目的classpath中添加好相应数据库的驱动Jar包后,在弹出的窗口中配置数据源连接信息即可,如下图所示:
Spring Bean类型的数据源可以选择Spring上下文中定义好的一个Bean来作为数据源,点击图标,在弹出的窗口中输入数据源名称及要采用的Bean的ID,如下图所示:
保存后,就可以在这个数据源下添加具体的数据集,添加方法就是在这个数据源下右键,在弹出的菜单中选择添加数据集,在弹出的窗口中定义数据集名称、对应的方法名以及返回对象类型,如下图所示:
在Spring bean数据集配置中,方法名我们可以点击右侧的“选择方法”按钮来选择当前Bean对应的类中定义的方法,但这里对方法的要求是:方法必须要有三个参数,依次是String,String,Map,比如我们上面定义的testBean里就包含两个合法的方法,如下所示:
package com.ureport.test; import java.util.List; import java.util.Map; /** * @author Jacky.gao * @since 2017年2月7日 */ public class TestBean { public List<Map<String,Object>> loadReportData(String dsName,String datasetName,Map<String,Object> parameters){ return null; } public List<Map<String,Object>> buildReport(String dsName,String datasetName,Map<String,Object> parameters){ return null; } }
所以对于一个合法的Bean数据集方法要有三个参数,分别是String,String,Map,依次对应数据源名称、数据集名称以及外部传入的参数Map,Bean的方法只有是这种结构才可以选择。对于数据集方法的返回值,目前来说可以支持两种类型,一种是我们TestBean中返回的Map<String,Object>类型的List集合;另一种就是返回一个POJO类型的List集合,比如像下面的方法:
public List<User> loadData(String dsName,String datasetName,Map<String,Object> parameters){ return null; }
在上面的示例方法中,返回的就是User对象集合,这里的User对象,就是一个普通的POJO对象。
内置数据源
这种类型的数据源,要示我们实现BuildinDatasource接口,同时将BuildinDatasource接口实现类配置到Spring即可,BuildinDatasource接口源码如下:
package com.bstek.ureport.definition.datasource; import java.sql.Connection; /** * @author Jacky.gao * @since 2017年2月9日 */ public interface BuildinDatasource { /** * @return 返回数据源名称 */ String name(); /** * @return 返回当前采用数据源的一个连接 */ Connection getConnection(); }
BuildinDatasource接口实现类配置到Spring中后,UReport2会自动检测到,这样在报表设计器中,点击数据源页签中的按钮,在弹出的窗口中就可以选择定义好的内置数据源,如下图所示:
对于UReport2提供的三种类型的数据源,各有其特点及适用场景,对于使用者来说,要根据它们的特点灵活选择。
Attachments:









