July 2010 Posts

Membuat Aplikasi Reporting sederhana dengan JasperReport dan Java Swing

Beberapa hari terakhir ini, gw ditanyain terus tentang caranya connect java swing ke jasper report. Dan konyolnya, gw juga udah lupa caranya. Maklum, kebanyakan copy-paste jadi begini niy. Ya udh supaya inget dan gag lupa-lupa lagi, gw paste disini aja sourcenya.

Gw coba bikin report gembel sederhana dulu, yg ambil data nama dan alamat dari table “contoh” yang ada di database “test”. Pertama-tama kita bikin dulu table nya didatabase,

CREATE TABLE `contoh` (
  `nama` varchar(30) NOT NULL DEFAULT '',
  `alamat` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`nama`)
)

Abis itu kita bikin file jrxml-nya, nanti file jrxml ini akan dicompile on-the-fly oleh compiler jadi .jasper.

<?xml version="1.0" encoding="UTF-8"?>
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="Iseng" language="groovy" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20">
	<parameter name="nama1" class="java.lang.String"/>
	<queryString>
		<![CDATA[SELECT
     contoh.`nama` AS contoh_nama,
     contoh.`alamat` AS contoh_alamat
FROM
     `contoh` contoh
where contoh.`nama` like $P{nama1}]]>
	</queryString>
	<field name="contoh_nama" class="java.lang.String">
		<fieldDescription><![CDATA[]]></fieldDescription>
	</field>
	<field name="contoh_alamat" class="java.lang.String">
		<fieldDescription><![CDATA[]]></fieldDescription>
	</field>
	<background>
		<band splitType="Stretch"/>
	</background>
	<title>
		<band height="56" splitType="Stretch">
			<staticText>
				<reportElement x="0" y="0" width="555" height="46"/>
				<textElement textAlignment="Center" verticalAlignment="Middle">
					<font size="24"/>
				</textElement>
				<text><![CDATA[Testing Report]]></text>
			</staticText>
		</band>
	</title>
	<pageHeader>
		<band height="13" splitType="Stretch"/>
	</pageHeader>
	<columnHeader>
		<band height="34" splitType="Stretch">
			<staticText>
				<reportElement x="0" y="11" width="100" height="20"/>
				<textElement textAlignment="Center" verticalAlignment="Middle"/>
				<text><![CDATA[Nama]]></text>
			</staticText>
			<staticText>
				<reportElement x="132" y="11" width="100" height="20"/>
				<textElement textAlignment="Center" verticalAlignment="Middle"/>
				<text><![CDATA[Alamat]]></text>
			</staticText>
		</band>
	</columnHeader>
	<detail>
		<band height="27" splitType="Stretch">
			<textField>
				<reportElement x="0" y="0" width="100" height="20"/>
				<textElement textAlignment="Center" verticalAlignment="Middle"/>
				<textFieldExpression class="java.lang.String"><![CDATA[$F{contoh_nama}]]></textFieldExpression>
			</textField>
			<textField>
				<reportElement x="132" y="0" width="100" height="20"/>
				<textElement textAlignment="Center" verticalAlignment="Middle"/>
				<textFieldExpression class="java.lang.String"><![CDATA[$F{contoh_alamat}]]></textFieldExpression>
			</textField>
		</band>
	</detail>
	<columnFooter>
		<band height="45" splitType="Stretch"/>
	</columnFooter>
	<pageFooter>
		<band height="54" splitType="Stretch"/>
	</pageFooter>
	<summary>
		<band height="42" splitType="Stretch"/>
	</summary>
</jasperReport>

Di situ gw bikin satu report yang akan mencari data di table contoh berdasarkan query nama. Perhatikan line 10, itu adalah variabel yang akan gw gunakan untuk menjadi variabel query report.

Setelah jadi reportnya, sekarang gw lanjut bikin tampilannya. Gw pakek java Swing buat bikin UI. Jadi harap maklum klo rada kacrut sederhana.

package com.edw.frame;

import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.HashMap;
import java.util.Map;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.view.JasperViewer;

import org.apache.log4j.Logger;

/**
 *
 * @author edw
 */
public class FrameMain extends JFrame implements ActionListener {

    private Logger logger = Logger.getLogger(FrameMain.class);
    private JTextField txtNama = new JTextField(20);
    private JButton cmdPrint = new JButton("cetak");

    public FrameMain() {
        init();
    }

    private void init() {
        Container conn = getContentPane();
        conn.setLayout(new FlowLayout());
        conn.add(new JLabel("Iseng"));
        conn.add(txtNama);
        conn.add(cmdPrint);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        cmdPrint.addActionListener(this);
        pack();
    }

    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == cmdPrint) {
            try {
                // parameter
                String parameterNama = txtNama.getText();

                //load report location
                FileInputStream fis = new FileInputStream("src\\com\\edw\\rpt\\Iseng.jrxml");
                BufferedInputStream bufferedInputStream = new BufferedInputStream(fis);

                //set parameters
                Map<String, String> map = new HashMap<String, String>();
                map.put("nama1", parameterNama);

                Class.forName("com.mysql.jdbc.Driver");
                Connection connection = DriverManager.getConnection("jdbc:mysql://localhost/test", "root", "xxxx");


                //compile report
                JasperReport jasperReport = (JasperReport) JasperCompileManager.compileReport(bufferedInputStream);
                JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, map, connection);

                //close connection
                connection.close();

                //view report to UI
                JasperViewer.viewReport(jasperPrint, false);

            } catch (Exception ex) {
                logger.error(ex.getMessage(), ex);
            }

        }
    }

    public static void main(String[] args) {
        new FrameMain().setVisible(true);
    }
}

Coba cek di line 64, itu adalah parameter yang akan dikirim ke report, pastikan nama variabelnya sama dengan nama variabel yang ada di jasper report ( file jrxml ). Sedangkan line 67 adalah Koneksi database gw, silahkan di modifikasi sesuai keinginan.

Nanti klo udh dijalanin, jadinya kayak gini
Form UI

terus klo misalkan text field nya diisi dengan “edwin” dan kemudian menekan tombol “cetak”, maka akan muncul form report dengan data “edwin” yang kita cari.
report jasper

berikut adalah struktur project gw serta library (jar) apa aja yg gw pake.
jasper report jar project structure
harap diingat, lokasi jar yg gw pake ada di dalam folder instalasi Jasper Report, silahkan di search aja.

nah ini adalah isi database gw, coba di cek output dari jasper dan isi databasenya, sinkron apa engga.
isi db

Sekian dan terima kasih.

nb. Oh iya, hasil preview dari jasper report juga bisa di save as ke berbagai macam format, tinggal di save aja.
export jasper into another format

Google+

When Edward meet Blade

PWND..!!

When Edward meet Blade

Google+

encrypting ibatis’ sqlmapconfig.xml

after im writing this article, i keep wondering “how can i keep database’s password secure.?”. As you all know, i keep database’s password plain at SqlMapConfig.xml. Therefore, we need to keep our database’s password secure. One of the simplest method is to encrypting SqlMapConfig’s properties.

Im using Swing, jasypt library for basic encryption, and iBatis 2.3.4. Jasypt also need 2 additional jars, commons-lang and commons-codec, you can find them at apache’s website.

first i create a properties file, named db.properties

JDBC.Driver=1rzI2NrjkRaiwdZso6qZaI0THnqKx/wkAROxbfaCL/E=
JDBC.ConnectionURL=7EpsURgD/FFzdzuDTKYtdcT3iGPePc8uklqBweCnbCkw1wjUAKPyEA==
JDBC.Username=ciUNsgpnvS6bEkkB1F/Q8g==
JDBC.Password=c5dvo6UUKK5t633Dt6lvma0WAm5snxb+

after that, i create a singleton class to do all the Encryption-Decryption functions

package com.edw.util;

import org.jasypt.util.text.BasicTextEncryptor;

/**
 * @author edw
 */
public class BasicEncryption {

    private static final BasicEncryption basicEncryption = new BasicEncryption();
    private final String CONSTANT = "busuk";

    private BasicTextEncryptor textEncryptor = new BasicTextEncryptor();

    private BasicEncryption(){        
        textEncryptor.setPassword(CONSTANT);
    }

    public static BasicEncryption getInstance(){
        return basicEncryption;
    }

    public String encrypt(String word){
        return textEncryptor.encrypt(word);
    }

    public String decrypt(String word){
        return textEncryptor.decrypt(word);
    }

}

after that, we modified SqlMapConfig.java to put decrypted properties into SqlMapConfig.xml

package com.edw.config;

import com.edw.util.BasicEncryption;

import com.ibatis.common.resources.Resources;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapClientBuilder;
import java.io.File;
import java.io.FileInputStream;

import java.io.IOException;
import java.io.Reader;
import java.util.Properties;

/**
 *
 * @author edw
 */
public class SqlMapConfig {

    protected static final SqlMapClient sqlMap;

    static {
        try {

            File file = new File("db.properties");
            FileInputStream fileInputStream = new FileInputStream(file);
            Properties properties = new Properties();            
            properties.load(fileInputStream);
            fileInputStream.close();

            // load encryption class
            BasicEncryption basicEncryption = BasicEncryption.getInstance();

            properties.setProperty("JDBC.Driver", basicEncryption.decrypt(properties.getProperty("JDBC.Driver")));
            properties.setProperty("JDBC.ConnectionURL", basicEncryption.decrypt(properties.getProperty("JDBC.ConnectionURL")));
            properties.setProperty("JDBC.Username", basicEncryption.decrypt(properties.getProperty("JDBC.Username")));
            properties.setProperty("JDBC.Password", basicEncryption.decrypt(properties.getProperty("JDBC.Password")));

            Reader reader = Resources.getResourceAsReader("com/edw/sqlmap/sqlmapconfig.xml");
            sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader, properties);
        } catch (IOException e) {
            throw new RuntimeException("Fatal Error, ga dapet sqlmapconfignya.  Cause: " + e, e);
        } catch (Exception e){
            throw new RuntimeException("Fatal Error.  Cause: " + e, e);
        }
    }

    public static SqlMapClient getSqlMap() {
        return sqlMap;
    }
}

and we set the variable at sqlmapconfig.xml to fit decrypted properties values.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMapConfig
PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-config-2.dtd">

<sqlMapConfig>
    <settings
        useStatementNamespaces="true"
        lazyLoadingEnabled="true"
        enhancementEnabled="true"
        maxSessions="20"
        />

    <transactionManager type="JDBC" commitRequired="false">
        <dataSource type="SIMPLE">

            <property name="SetAutoCommitAllowed" value="false"/>
            <property name="DefaultAutoCommit" value="false"/>
            
            <property name="JDBC.Driver" value="${JDBC.Driver}"/>
            <property name="JDBC.ConnectionURL" value="${JDBC.ConnectionURL}"/>
            <property name="JDBC.Username" value="${JDBC.Username}"/>
            <property name="JDBC.Password" value="${JDBC.Password}"/>
   
        </dataSource>
    </transactionManager>


    <!-- dont forget to register your sql map configs -->
    <sqlMap resource="com/edw/sqlmap/contoh.xml"/>


</sqlMapConfig>

this is my project structure
structure
structure2

this is what will happen if we submit the form
success

you can check it in the database
database

Google+

InvalidClassException: com.sun.rowset.providers. RIOptimisticProvider; local class incompatible: stream classdesc serialVersionUID

i ran into this weird exception when im trying to connecting a Swing Application + Crystal Report to a database via EJB. I dont know why, but this error always happen only at reporting module. And what makes it weird that this exception only happen at several terminals only.

java.rmi.RemoteException: null; nested exception is: 
	java.io.InvalidClassException: com.sun.rowset.providers.RIOptimisticProvider; local class incompatible: stream classdesc serialVersionUID = -3143367176751761936, local class serialVersionUID = -8429279896237029122
	at com.rubean.statelesstunnel.client.BusinessInterfaceProxyFactory$Handler.invoke(Unknown Source)
	at $Proxy7.runNamedReportQuery(Unknown Source)
	at com.xxx.GenericQueryDelegate.runnamedReportQuery(ReportQueryDelegate.java:166)
	at com.xxx.report.RptOne.setQuery(RptOne.java:78)
	at com.xxx.report.RptOne$runReport.run(RptOne.java:136)
Caused by: java.io.InvalidClassException: com.sun.rowset.providers.RIOptimisticProvider; local class incompatible: stream classdesc serialVersionUID = -3143367176751761936, local class serialVersionUID = -8429279896237029122
	at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:562)
	at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1583)
	at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1496)
	at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1732)
	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
	at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1947)
	at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1871)
	at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1753)
	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
	at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1947)
	at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1871)
	at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1753)
	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)
	at com.rubean.statelesstunnel.client.http.HttpRequestorCompression.postRequest(HttpRequestorCompression.java:60)
	... 5 more
	

after some research i found out that this exception happen only to terminals using JRE 1.60 update 7 or less.

C:\Users\edw>java -version
java version "1.6.0_07"
Java(TM) SE Runtime Environment (build 1.6.0_07-b06)
Java HotSpot(TM) Client VM (build 10.0-b23, mixed mode, sharing)

this exception gone after i updated every terminal’s JRE into JRE 1.60 update 19

C:\Users\edw>java -version
java version "1.6.0_19"
Java(TM) SE Runtime Environment (build 1.6.0_19-b04)
Java HotSpot(TM) Client VM (build 16.2-b04, mixed mode, sharing)

And now i have to update every terminals that are still using JRE 1.6.0_07. Weird eh, hahahaa…..

Google+