SyntaxHighlighter

2012-11-26

如何iReport中簡單的設定List成為Datasource

大多數人使用iReport生成都會使用SQL來抓取資料庫檔案,但是iReport畢竟只是個設計表單用的程式,資料還是要靠Java餵給他。

一般的使用法,就像我以前做的
1. 在iReport中寫死SQL查詢句(SELECT xxx FROM yyy WHERE zzz),然後靠JDBC自動抓取db的內容來設定field,然後把那些Field丟進表單中

2. WHERE句所需要的最底限的資料靠HashMap丟進jasper中,讓jasper在跑的時候自動抓取資料庫內容

HashMap parameters = new HashMap();
parameters.put("FIELD1", something);
JasperFillManager.fillReportToFile(JASPER檔案路徑, parameters, 某某資料庫的Connection);

但是上面的程序對DB不是很友善。
一般來說,我們再輸出之前都會想確定一下內容寫了什麼,所以會把資料先從資料庫叫出來一次。加上關聯式資料庫方式,一般來說都會JOIN一大堆內容。可是老實說,JOIN對資料庫非常的花時間(至少在MYSQL上是這樣的)

既然已經把db的內容叫出來了,那何必再叫一次呢?


程式流程會變成下面這樣
1. Java向DB查詢資料
2. DB將資料傳給Java程式
3. Java程式將所需要的資料填進jasper生成jrprint文件

一般來說,jrprint出來之後要轉成pdf或是其他的資料型式就不成問題了


但是你會說:用Parameter也可以把資料傳進去阿
是阿,沒錯,但是那樣的話parameter會變成一長串,程式沒有美感也沒有程度可言
而且如果你是從SQL轉過來的,光是改原來的report裡面的欄位就改到手酸
$F{FIELDS}要改成$P{FIELDS}

那我們怎麼弄呢?很簡單,把Connection改成Datasource,然後把原來Java裡面的內容靠Datasource丟進去。

詳細就照著作比較快。我們用個班級的個人成績表作範例。個人成績表需要有個人姓名,學號,以及個人的各科成績。其中姓名與學號是每張單都不同的,而成績是靠學號來分辨,另外記在其他資料庫裡的。
1. 建立Datasource用的Javabean。在這個例子裡,我叫他Student
public class Student {
    private String name;
    private String serialNo;
    private List scores;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSerialNo() {
        return serialNo;
    }

    public void setSerialNo(String serialNo) {
        this.serialNo = serialNo;
    }

    public List getScores() {
        return scores;
    }

    public void setScores(List scores) {
        this.scores = scores;
    }

}



我們還需要另外一個JavaBean來紀錄各科成績,姑且叫他Score
public class Score {
    private Integer point;
    private String name;

    public Integer getPoint() {
        return point;
    }

    public void setPoint(Integer point) {
        this.point = point;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    
}


讓我們做個假資料來放上面的東西
public class ContentFactory {
    static public List create(){
        List fakelist = new ArrayList<>();
        
        Student fakeStudent1 = new Student();
        fakeStudent1.setName("孫甲");
        fakeStudent1.setSerialNo("A001");
        
        List fakeScoreList1 = new ArrayList<>();
        Score fakeScore1 = new Score();
        fakeScore1.setName("國語");
        fakeScore1.setPoint(76);
        Score fakeScore2 = new Score();
        fakeScore2.setName("數學");
        fakeScore2.setPoint(100);
        
        fakeStudent1.setScores(fakeScoreList1);
        
        fakelist.add(fakeStudent1);
        
        return fakelist;
    }
}



重頭戲來了,把資料填給jasper吧
JasperFillManager.fillReportToFile("reports/epsSinglePageOutput.jasper", parameters, new JRBeanCollectionDataSource(ContentFactory.create()));



放給Jasper的資料,自然不是那麼容易拿到。接下來就告訴你怎麼設定Jasper去接這些資料。

新建一個JasperReport,資料源留白(Empty datasource)。因為資料源已經從Java程式設定好了。

你會說:Fields裡面都沒有東西,那我要從哪裡叫資料阿?
沒錯,接下來,我們就是要設定Fields。手動設定所有你需要的Field,他們的class也必須符合Java裡面的形式
在我的範例裡面,你需要三個Field:name(java.lang.String),serialNo(java.lang.String),
scores(java.util.List)。他們分別對應了Student的三個變數name, serialNo, scores。



接下來,我們要設定一個副查詢(Sub-Dataset),而這個副查詢是原本主查詢中的資料List。
我們一如往常的在頁面上添加一個表格(Table)。iReport跳出來跟你說:喔,你家沒有副查詢喔,要不要自己加一個阿。


我們不理他,繼續加個空白表格(Just create an empty table)並選擇我們需要的欄位數。在這個例子中,我們需要兩欄。完成後,你會看到表格自動被展開並準備好排版。但是我們暫時還不想理他。

在看一次Inspector,你會看到剛剛自動生成的Dataset(Table Dataset 1), 名字非常難看,但是我們可以不理他(當然,你可以自己把他改成更好看一點)。
檢查Table Dataset裡面的Fields,當然,他還是沒有任何內容。
手動增加我們需要的兩個Field以對應Score的兩個Field:
name(java.lang.String), point(java.lang.Integer)

接下來的一個非常重要:右擊table叫出功能表,點擊Edit table Datasource

一般來說,Datasource會被設定到剛剛的Table Dataset 1上,就像下圖一樣

要注意:Connection / Datasource Expression是Use datasource expression。

接下來,另一個重頭戲來了。編輯datasource的方程式,讓他變成自動擷取主查詢裡面的變數List


new net.sf.jasperreports.engine.JREmptyDataSource(1)
改成
new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{scores})

大功告成。接下來你就可以自由的編輯你的排版,看看剛剛設定的值有沒有問題囉
剛剛設定的各Field也會自動的排進你的jasper囉

2012-11-20

get the last insert id in MySQL

In fact, there is the default function names LAST_INSERT_ID().
So, Just use it!
SELECT LAST_INSERT_ID()

2012-11-14

Netbeans 出力文字化け on MacOSX

civicさんの文章を拝見してもらいまして、
長い間に悩んでいました問題が解決しました。

ネットで他の文章を拝見すると、
大体の場合、netbeansの設定ファイルnetbeans.conf(場所/Applications/NetBeans/NetBeans 7.2.app/Contents/Resources/NetBeans/etc/netbeans.conf)に、

netbeans_default_options-J-Dfile.encoding=UTF-8 を追加。

だけと書いてある。

しかし!それだけではない!

最後に

export JAVA_TOOL_OPTION='-Dfile_encoding=UTF-8'

と追加しましょう。とすると、出力に文字化けの問題が解決。おめでたい、おめでたい。

2012-11-08

About the Table name Case Sensitivity in MySQL

It confused me for a while.
With the MySQL server which is installed in Windows, the tables' name and schemas' name are all case insensitive.

It means, if you try to make a table name as tblSomething,
it will be named as tblsomething.

As the official answer,
the MySQL server in Mac and Windows save TABLEs case insensitive because the filesystem is case insensitive.

so, don't waste your time to rename the TABLEs try to make the name case sensitive.
it won't work

人気の投稿