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

2012-10-31

run java programs with self-boudle JRE

1. at first, make sure you have the JRE which can run the program.
for example, It's c:\java\jre.

2. copy the JRE to the program directory.
so, it may look like below:
SOMEPROGRAM\ (root)
SOMEPROGRAM\jre (the JRE directory)
SOMEPROGRAM\app (maybe put JARs here)
SOMEPROGRAM\app\lib (maybe some third-party JARs here)

3. make a batch file in root directory, maybe named it FOO.bat
.\jre\bin\java -jar "app\FOO.jar" -cp app\lib

4. run the FOO.bat.
It's done.

to run the batch(.bat) file without showing the (command line tool) window in Windows

1.At first, we have a batch file, FOO.BAT for example.

2.Make a vbScript file, BOO.vbs for example
contents with the script below:

Set ws = CreateObject("Wscript.Shell") 
ws.run "cmd /C FOO.bat",vbhide 

3. Put the BOO.vbs with FOO.bat, or say, put the files into the same directory.

4. done.

2012-10-25

net.sf.jasperreports.engine.JRException: Error loading byte data

OK, if you find this from Google or somewhere, you got the same problem as I did.

With an official answer, you lost the JDT jar in your classpath.
So, the solvation is easy: include the jdt jar into your classpath.

That's all.

Compile and Print reports in JasperReports 4

When I working my report with JasperReports 4.7(the latest version at the moment), I'm forced to face the truth: the documents on the net were too old to make the reports. They uses the JasperReports 3.x when it's in 2002~2005. I can't find the JasperManager class in the library in JasperReports 4.7.

You may see some examples which were written for JasperReport 3.x as below:
// First, load JasperDesign from XML and compile it into JasperReport
JasperDesign jasperDesign = JasperManager.loadXmlDesign("BasicReport.xml");
JasperReport jasperReport = JasperManager.compileReport(jasperDesign);
// Second, create a map of parameters to pass to the report.
Map parameters = new HashMap();
parameters.put("ReportTitle", "Basic JasperReport");
parameters.put("MaxSalary", new Double(25000.00));
// Third, get a database connection
Connection conn = Database.getConnection(); 
// Fourth, create JasperPrint using fillReport() method
JasperPrint jasperPrint = JasperManager.fillReport(jasperReport, parameters, conn);
// You can use JasperPrint to create PDF
JasperManager.printReportToPdfFile(jasperPrint, "BasicReport.pdf");
// Or to view report in the JasperViewer
JasperViewer.viewReport(jasperPrint);


In JasperReport 4.x, it will look like below:
// First, load JasperDesign from XML and compile it into JasperReport
JasperDesign jasperDesign = JRXmlLoader.load("BasicReport.xml");
JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign);
// Second, create a map of parameters to pass to the report.
Map parameters = new HashMap();
parameters.put("ReportTitle", "Basic JasperReport");
parameters.put("MaxSalary", new Double(25000.00));
// Third, get a database connection
Connection conn = Database.getConnection(); 
// Fourth, create JasperPrint using fillReport() method
JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, conn);
// You can use JasperPrint to create PDF
JasperExportManager.exportReportToPdfFile(jasperPrint, "BasicReport.pdf");
// Or to view report in the JasperViewer
JasperViewer.viewReport(jasperPrint);


As you can see, there is some change between version 3.x to 4.x. In JasperReport 4.x, there are LOTS of class which sees to access to the same in-memory data. The classes becomes more easy to do things you want. Just try it.

2012-10-17

JavaFX standalone application with external jar

To compile/build a JavaFX standalone application with external jar CORRECTLY.

with the code below, I get runtime exception as the others.

     <target name="-post-jfx-deploy">
        <fx:deploy width="${javafx.run.width}" height="${javafx.run.height}" 
                  nativeBundles="all"
                  outdir="${basedir}/${dist.dir}" outfile="${application.title}">
          <fx:application name="${application.title}" 
                          mainClass="${javafx.main.class}"/>
          <fx:resources>
              <fx:fileset dir="${basedir}/${dist.dir}" includes="*.jar"/>
              <fx:fileset dir="${basedir}/${dist.dir}/lib" includes="*.jar"/>
          </fx:resources>
          <fx:info title="${application.title}" 
                   vendor="${application.vendor}"/>
        </fx:deploy>
     </target>

but I fix it finally.
with the code below, the external jars go to the right location.
     <target name="-post-jfx-deploy">
        <fx:deploy width="${javafx.run.width}" height="${javafx.run.height}" 
                  nativeBundles="all"
                  outdir="${basedir}/${dist.dir}" outfile="${application.title}">
          <fx:application name="${application.title}" 
                          mainClass="${javafx.main.class}"/>
          <fx:resources>
              <fx:fileset dir="${basedir}/${dist.dir}" includes="*.jar"/>
              <fx:fileset dir="${basedir}/${dist.dir}" includes="lib/*.jar"/>
          </fx:resources>
          <fx:info title="${application.title}" 
                   vendor="${application.vendor}"/>
        </fx:deploy>
     </target>

All the thing I done is just set the external jar's dir and includes in to the correct way.
from
<fx:fileset dir="${basedir}/${dist.dir}/lib" includes="*.jar"/>
to
<fx:fileset dir="${basedir}/${dist.dir}" includes="lib/*.jar"/>

2012-10-09

JavaFX 2 MDI プログラム

基本的に、MDIは現時点でJavaFX自体ではできない。

けれど、swingと組み合わせると、何とかできる。

keyword: swing, JDesktopFrame, JInternalFrame, JApplet

具体的にいうと、swingアプリの中に、JFrameの中身をすべてJApplet経由でJavaFXを呼び出す。

swingの奥が深いなぁ

2012-09-19

GlassFish 文字化け

keyword: Java, Java EE, GlassFish, 文字化け

たまたまに遭遇した問題ですが。
Java EEでプログラムをデプロイすると、
プログラム自体は文字化けしないけど
レスポンスされると、内容が文字化けする。

何度もテストして、
結局内容はサーバーのsetResposeのところに問題があるようで。

glassfish-web.xmlの中にglassfish-web-appタグの中に
parameter-encodingを追加することにしたら解決。


<glassfish -web-app="-web-app" error-url="">  …  <parameter-encoding default-charset="UTF-8" /> </glassfish>
さて、引き続きプログラムを組むか…

2012-08-17

Doxygen

ソースコード分析用ソフト
大学の時に一度世話になりましたが、最近になってまた必要になってましたね…

一応リンクを張っておきます。使用方法は後ほど補完します。

http://www.stack.nl/~dimitri/doxygen/

GoogleCode-Prettify

SyntaxHighlighter

人気の投稿