UReport2教學(xué)視頻
http://pan.baidu.com/s/1boWTxF5,密碼:98hj
UReport商業(yè)版BaskReport已推出,采出全新算法,全新設(shè)計(jì)器,實(shí)現(xiàn)百萬(wàn)條數(shù)據(jù)秒級(jí)加載, 價(jià)格低至1000/年,詳見(jiàn):https://www.basksoft.com
在第二小節(jié)中,我們介紹如何搭建一個(gè)包含UReport2的項(xiàng)目,在運(yùn)行項(xiàng)目后,我們發(fā)現(xiàn)在項(xiàng)目的WEB-INF目錄有會(huì)自動(dòng)生成了一個(gè)名為“ureportfiles”目錄,這個(gè)目錄是UReport2提供的默認(rèn)的報(bào)表文件存儲(chǔ)目錄,也就是說(shuō)默認(rèn)情況下,UReport將在項(xiàng)目的WEB-INF/ureportfiles目錄下存儲(chǔ)設(shè)計(jì)好的報(bào)表文件。
默認(rèn)報(bào)表存儲(chǔ)目錄
如果您的項(xiàng)目在Eclipse的開(kāi)發(fā)環(huán)境運(yùn)行時(shí),采用的是jetty(比如run-jetty-run插件),那么就可以在項(xiàng)目的WEB-INF目錄下發(fā)現(xiàn)一個(gè)名為“ureportfiles”目錄。
但如果你采用tomcat運(yùn)行項(xiàng)目,那么在WEB-INF目錄下就沒(méi)有一個(gè)名為“ureportfiles”目錄,原因是在Eclipse中運(yùn)行tomcat,tomcat需要?jiǎng)?chuàng)建一個(gè)臨時(shí)的工作目錄(該目錄一般位于workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\下),所以采用tomcat運(yùn)行項(xiàng)目,則需要到這個(gè)臨時(shí)的工作目錄下找到對(duì)應(yīng)的項(xiàng)目,再到這個(gè)項(xiàng)目的WEB-INF目錄下找到對(duì)應(yīng)的“ureportfiles”目錄。
運(yùn)行我們搭建好的項(xiàng)目,打開(kāi)報(bào)表設(shè)計(jì)器,點(diǎn)擊工具欄上的保存按鈕(),選擇“保存”,可以看到如下圖所示的彈出窗口:
\
在這個(gè)窗口,我們只要輸入報(bào)表名稱,同時(shí)再選擇報(bào)表的存儲(chǔ)目的地就,可以保存當(dāng)前報(bào)表文件??梢钥吹剑琔Report2默認(rèn)給我們提供的存儲(chǔ)目的地是“服務(wù)器文件系統(tǒng) ”,實(shí)際上就是我們項(xiàng)目中WEB-INF目錄下的“ureportfiles”目錄,這個(gè)目錄是系統(tǒng)默認(rèn)自動(dòng)生成的,如果需要我們可以添加一個(gè)屬性來(lái)更改這個(gè)目錄位置。
在我們項(xiàng)目的WEB-INF目錄下創(chuàng)建一個(gè)名為config.properties,打開(kāi)位于WEB-INF下名為context.xml的spring配置文件,在其中添加如下Bean以加載這個(gè)config.properties文件(如果我們的項(xiàng)目中已有自己的Properties文件,那么直接在這個(gè)Properties文件中配置即可)。
<bean id="propertyConfigurer" parent="ureport.props">
<property name="location">
<value>/WEB-INF/config.properties</value>
</property>
</bean>
說(shuō)明
上面的Bean配置,實(shí)際上就是一個(gè)標(biāo)準(zhǔn)的org.springframework.beans.factory.config.PropertyPlaceholderConfigurer類(lèi)配置,我們知道通過(guò)配置PropertyPlaceholderConfigurer,可以實(shí)現(xiàn)加載Spring外部properties的作用,所以如果您的項(xiàng)目中已配置了PropertyPlaceholderConfigurer類(lèi),那么直接在這個(gè)類(lèi)對(duì)應(yīng)的properties文件中添加對(duì)應(yīng)的UReport2屬性即可,而不需要額外配置config.properties文件。
打開(kāi)config.properties文件,在其中添加名為“ureport.fileStoreDir”的屬性,該屬性的值用于定義UReport2中提供的默認(rèn)基于文件系統(tǒng)的報(bào)表存儲(chǔ)目錄,比如定義該屬性為下面樣式:
屬性值定義示例
ureport.fileStoreDir=D:/ureportfiles
表示在D盤(pán)根下名為ureportfiles的目錄中存儲(chǔ)報(bào)表文件,需要注意的是,這里指定特定目錄時(shí),一定要保存這個(gè)目錄已存在,否則將不會(huì)被采用,比如上面的D盤(pán)下名為ureportfiles的目錄,就需要我們預(yù)先創(chuàng)建好。
UReport2默認(rèn)提供的名為“服務(wù)器文件系統(tǒng)”的報(bào)表存儲(chǔ)機(jī)制,實(shí)際上是實(shí)現(xiàn)了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 {
/**
* 根據(jù)報(bào)表名加載報(bào)表文件
* @param file 報(bào)表名稱
* @return 返回的InputStream
*/
InputStream loadReport(String file);
/**
* 根據(jù)報(bào)表名,刪除指定的報(bào)表文件
* @param file 報(bào)表名稱
*/
void deleteReport(String file);
/**
* 獲取所有的報(bào)表文件
* @return 返回報(bào)表文件列表
*/
List<ReportFile> getReportFiles();
/**
* 保存報(bào)表文件
* @param file 報(bào)表名稱
* @param content 報(bào)表的XML內(nèi)容
*/
void saveReport(String file,String content);
/**
* @return 返回存儲(chǔ)器名稱
*/
String getName();
/**
* @return 返回是否禁用
*/
boolean disabled();
/**
* @return 返回報(bào)表文件名前綴
*/
String getPrefix();
}
實(shí)現(xiàn)了ReportProvider接口后,只需要將實(shí)現(xiàn)類(lèi)配置到Spring中,讓其成為一個(gè)標(biāo)準(zhǔn)的Spring Bean,這樣UReport2就會(huì)檢測(cè)到它而將其加載。下面是UReport2默認(rèn)提供的名為“服務(wù)器文件系統(tǒng)”的報(bào)表存儲(chǔ)器源碼:
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 "服務(wù)器文件系統(tǒng)";
}
@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;
}
}
禁用系統(tǒng)提供的默認(rèn)報(bào)表存儲(chǔ)器
如果我們定義了自己的報(bào)表存儲(chǔ)器,同時(shí)又不想再使用系統(tǒng)默認(rèn)提供的”服務(wù)器文件系統(tǒng)“的報(bào)表存儲(chǔ)器,那么我們只需要在之前介紹的config.properties文件中添加一個(gè)名為ureport.disableFileProvider屬性,將其值設(shè)置成true即可。
通過(guò)上面的介紹,可以看到,通過(guò)實(shí)現(xiàn)ReportProvider接口,我們可以很容易的開(kāi)發(fā)出其它類(lèi)型的報(bào)表存儲(chǔ)器,比如開(kāi)發(fā)一個(gè)新的報(bào)表存儲(chǔ)器將報(bào)表文件存儲(chǔ)到數(shù)據(jù)庫(kù)、FTP等。
打開(kāi)UReport2的報(bào)表設(shè)計(jì)器,可以看到UReport2提供了三種類(lèi)型的報(bào)表數(shù)據(jù)源,如下圖所示:
三種類(lèi)型的數(shù)據(jù)源分別是直接連接數(shù)據(jù)庫(kù),Spring Bean以及通過(guò)實(shí)現(xiàn)com.bstek.ureport.definition.datasource.BuildinDatasource接口提供的內(nèi)置數(shù)據(jù)源。
直接連接數(shù)據(jù)庫(kù)比較簡(jiǎn)單,就是在項(xiàng)目的classpath中添加好相應(yīng)數(shù)據(jù)庫(kù)的驅(qū)動(dòng)Jar包后,在彈出的窗口中配置數(shù)據(jù)源連接信息即可,如下圖所示:
Spring Bean類(lèi)型的數(shù)據(jù)源可以選擇Spring上下文中定義好的一個(gè)Bean來(lái)作為數(shù)據(jù)源,點(diǎn)擊圖標(biāo),在彈出的窗口中輸入數(shù)據(jù)源名稱及要采用的Bean的ID,如下圖所示:
保存后,就可以在這個(gè)數(shù)據(jù)源下添加具體的數(shù)據(jù)集,添加方法就是在這個(gè)數(shù)據(jù)源下右鍵,在彈出的菜單中選擇添加數(shù)據(jù)集,在彈出的窗口中定義數(shù)據(jù)集名稱、對(duì)應(yīng)的方法名以及返回對(duì)象類(lèi)型,如下圖所示:
在Spring bean數(shù)據(jù)集配置中,方法名我們可以點(diǎn)擊右側(cè)的“選擇方法”按鈕來(lái)選擇當(dāng)前Bean對(duì)應(yīng)的類(lèi)中定義的方法,但這里對(duì)方法的要求是:方法必須要有三個(gè)參數(shù),依次是String,String,Map,比如我們上面定義的testBean里就包含兩個(gè)合法的方法,如下所示:
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;
}
}
所以對(duì)于一個(gè)合法的Bean數(shù)據(jù)集方法要有三個(gè)參數(shù),分別是String,String,Map,依次對(duì)應(yīng)數(shù)據(jù)源名稱、數(shù)據(jù)集名稱以及外部傳入的參數(shù)Map,Bean的方法只有是這種結(jié)構(gòu)才可以選擇。對(duì)于數(shù)據(jù)集方法的返回值,目前來(lái)說(shuō)可以支持兩種類(lèi)型,一種是我們TestBean中返回的Map<String,Object>類(lèi)型的List集合;另一種就是返回一個(gè)POJO類(lèi)型的List集合,比如像下面的方法:
public List<User> loadData(String dsName,String datasetName,Map<String,Object> parameters){
return null;
}
在上面的示例方法中,返回的就是User對(duì)象集合,這里的User對(duì)象,就是一個(gè)普通的POJO對(duì)象。
這種類(lèi)型的數(shù)據(jù)源,要示我們實(shí)現(xiàn)BuildinDatasource接口,同時(shí)將BuildinDatasource接口實(shí)現(xiàn)類(lèi)配置到Spring即可,BuildinDatasource接口源碼如下:
package com.bstek.ureport.definition.datasource;
import java.sql.Connection;
/**
* @author Jacky.gao
* @since 2017年2月9日
*/
public interface BuildinDatasource {
/**
* @return 返回?cái)?shù)據(jù)源名稱
*/
String name();
/**
* @return 返回當(dāng)前采用數(shù)據(jù)源的一個(gè)連接
*/
Connection getConnection();
}
BuildinDatasource接口實(shí)現(xiàn)類(lèi)配置到Spring中后,UReport2會(huì)自動(dòng)檢測(cè)到,這樣在報(bào)表設(shè)計(jì)器中,點(diǎn)擊數(shù)據(jù)源頁(yè)簽中的按鈕,在彈出的窗口中就可以選擇定義好的內(nèi)置數(shù)據(jù)源,如下圖所示:
對(duì)于UReport2提供的三種類(lèi)型的數(shù)據(jù)源,各有其特點(diǎn)及適用場(chǎng)景,對(duì)于使用者來(lái)說(shuō),要根據(jù)它們的特點(diǎn)靈活選擇。
更多建議: