JasperReports là một trong những bộ thư viện mã nguồn mở của Java
được sử dụng phổ biến trong việc tạo ra các file báo cáo với nhiều định
dạng khác nhau (.pdf, .csv, .html,..). Bài viết này sẽ giới thiệu qua về
JasperReports và cách tạo ra một báo cáo đơn giản.
Trong các ứng dụng, đặc biệt là các ứng dụng làm nhiệm vụ quản lý,
thống kê thì việc yêu cầu ứng dụng có thể sinh ra báo cáo dưới các định
dạng để có thể in ra là điều khó có thể tránh khỏi. Chút nữa chúng ta sẽ
có một ví dụ nho nhỏ về cách tạo ra một report đơn giản liên quan đến
việc thống kê các sinh viên có điểm trên trung bình và dưới trung bình
trong một lớp học. Nhưng trước tiên chúng ta hãy nói về iReport, một
công cụ hữu ích trong việc tạo ra các bản mẫu thiết kế của các báo cáo.
Để phục vụ cho ví dụ minh họa, đầu tiên ta tạo một database gồm hai bảng
STUDENT và
CLASS như sau
CREATE DATABASE jasper_report_demo; USE jasper_report_demo; CREATE TABLE CLASS(
CLASS_ID NVARCHAR(4), CLASS_NAME NVARCHAR(30), PRIMARY KEY (CLASS_ID) );
CREATE TABLE STUDENT( STUDENT_ID INT AUTO_INCREMENT, STUDENT_NAME NVARCHAR(20), MARK DECIMAL,
CLASS_ID NVARCHAR(4), PRIMARY KEY (STUDENT_ID) );
Để tạo ra một báo cáo bằng JasperReports, trước hết chúng ta phải
tạo ra một bản mẫu cho báo cáo đó. Sau khi có bản mẫu thì việc tạo ra
một báo cáo cụ thể thực chất chỉ ra việc truyền giá trị cho các tham số
bên trong bản mẫu. Bản mẫu thiết kế sẽ là một file có đuôi .jrxml với
nội dung được thể hiện dưới dạng XML. Vì chỉ là XML nên chúng ta hoàn
toàn có thể chỉ dùng notepad mà tạo ra bản mẫu, tuy nhiên việc này rất
công phu và tốn thời gian. Nếu không phải là trường hợp nào đó thật đặc
biệt thì chúng ta hãy sử dụng công cụ iReport để tiết kiệm công sức và
thời gian. iReport cung cấp cho chúng ta một giao diện thiết kế trực
diện, thay vì phải viết XML, ta chỉ việc kéo thả và tinh chỉnh các thành
phần vào trong bản mẫu. Sau đó công cụ sẽ tự sinh ra file .jrxml cho ta
có thể sử dụng trong ứng dụng.
Ta có thể tải iReport tại
đây.
Trong mục iReport Designer, ta hãy chọn bản cài tương ứng với hệ điều
hành mà ta đang dùng rồi tiến hành download về và cài đặt.
Sau khi cài đặt iReport thành công, ta bắt tay vào công việc xây dựng bản mẫu cho báo cáo. Trong iReport ta chọn
File –>
New,
một loạt các bản mẫu hiện ra như hình dưới đây. Ta chọn một
trong số chúng để làm bản mẫu cho báo cáo của mình.

Chọn
Blank A4 –>
Launch Report Wizard, đặt tên và vị trí để lưu file .jrxml. Trong ví dụ, ta đặt tên file thiết kế là
StudentMark.jrxml, chọn
Next sau đó ta sẽ được yêu cầu để chỉ ra kết nối đến database để lấy dữ liệu cho báo cáo.

Trong trường hợp chưa có một kết nối nào, ta có thể tạo ra một kết nối mới bằng việc click vào
New sau đó chọn loại datasource tương ứng. Ở đây, ta kết nối đến mysql database server nên ta chọn vào mục
Database JDBC connection

Click
Next, sau đó đặt tên cho kết nối này là
JasperReportDemo, sau đó chỉ ra các thông số kết nối như là
JDBC Driver,
JDBC URL,
Username và
Password.

Click
Save, sau đó ta được yêu cầu để nhập vào Master
Query cho report. Lưu ý là khi sinh ra báo cáo, nội dung của báo
cáo sẽ bị lặp lại với số lần bằng số lượng bản ghi sinh ra
bởi câu truy vấn master query. Vì vậy, hãy cân nhắc trong việc
sử dụng master query với việc đảm bảo rằng số lượng bản ghi
sinh ra bởi câu truy vấn là 1. Ở trong trường hợp này ta chọn
câu master query là
SELECT 1

Tiếp theo chọn
Next đến khi xuất hiện và chọn
Finish. Bản mẫu thiết kế sẽ được tạo và chúng ta tiến hành bắt tay vào thiết kế chi tiết cho bản mẫu này

Để ý thấy bản mẫu thiết kế là một trang A4, được chia ra làm nhiều phần như là
Title,
Page Header,
Column Header,
Detail 1,
Column Footer,
Page Footer và
Summary. Trong đó các phần nội dung của
Page Header,
Column Header,
Column Footer,
Page Footer
sẽ bi lặp lại ở các trang của báo cáo. Trong quá trình thiết
kế, ta hãy loại bỏ những phần không sử dụng đến bằng cách
click chuột phải vào phần đó và chọn
Delete Band. Trong ví dụ ta chỉ sử dụng đến phần
Title và phần
Detail 1, nên bản mẫu của chúng ta sẽ có layout như sau:

Bây giờ là đến giai đoạn thiết kế chi tiết các thành phần
chi tiết trong báo cáo. Các thành phần gồm có các nhãn, bảng
biểu … tất cả các thành phần này nằm trong khung
Palette (nếu không thấy khung này ta vào menu
Window –>
Palette) như hình dưới đây:

Ngoài ra, các thành phần bên trong báo cáo còn có thể là
các tham số được truyền vào trong quá trình chạy chương trình,
hay cũng có thể là một trường nào đó trong kết quả trả về
từ một câu truy vấn trên data source. Trong ví dụ này, ta tạo 2
tham biến là
classId và
className bằng cách bên trong khung
Report Inspector, click chuột phải vào mục
Parameters –>
Add Parameter như hình dưới đây:

Tiếp theo ta kéo các thành phần vào trong phần Title của báo
cáo, các thành phần tên báo cáo, các nhãn là các static text,
một tham số sẽ hiển thị trên bản thiết kế với dạng
$P{param name}. Sau bước này, báo cáo sẽ giống như hình dưới đây

Trong phần nội dung của báo cáo, ta sẽ hiển thị danh sách
các học sinh có điểm trên trung bình và danh sách các học sinh
có điểm dưới trung bình. Mỗi một danh sách như thế sẽ được
lấy ra từ một data set. Trước hết ta sẽ tạo một data set cho
việc truy vấn danh sách các sinh viên có điểm trên trung bình
bằng cách click chuột vào
StudentMark trong khung
Report Inspector sau đó chọn
Add Dataset như hình dưới đây

Đặt tên cho data set là
DataSetStudentAboveAverage, và chọn
Create new dataset from a connection or datasource như hình dưới đây:

Click
Next, sau đó trong panel mới hiện ra, ở mục
Connections/ Data Sources ta chọn vào Data source mà ta đã tạo lúc đầu là
JasperReportDemo. Trong mục
Query ta viết câu truy vấn để lấy ra các sinh viên có điểm lớn hơn 5 như dưới đây

Click
Next, trong mục tiếp theo ta sẽ lựa chọn các
trường sẽ dùng trong dataset, ở đây ta dùng tất cả các trường
nên ta chọn
>> để cho các trường sẽ sang khung bên tay phải như hình dưới đây:

Click
Next và sau đó chọn
Finish, dataset sẽ được tạo ra và hiển thị ở trong mục
Report Inspector.
Nếu để ý chúng ta có thể thấy câu truy vấn trong dataset vừa
tạo đang là hard code, chúng ta mong muốn dữ liệu trong dataset
sẽ là danh sách sinh viên của một lớp mà có class id được
truyền vào từ chương trình. Vậy chúng ta tạo một tham số mới
trong dataset vừa tạo là
dsClassId như sau:

Sau khi tạo một tham số, việc tiếp theo là phải sửa câu query
trong dataset để nó ăn theo tham số này. Click chuột phải và
dataset sau đó chọn
Edit Query, sau đó sửa điều kiện câu query thành
CLASS_ID = $P{dsClassId} như dưới đây

Click
OK, bây giờ ta sẽ thiết kế một bảng để có thể hiển thị dữ liệu từ dataset này lên báo cáo. Trong khung
Palette, ta chọn Table và sau đó kéo vào phần
Detail 1 của báo cáo. Khung
Table Wizard sẽ hiện ra, ta chọn dataset cho bảng này chính là
DataSetStudentAboveAverage vừa được tạo ở trên như hình dưới đây:

Click
Next, bước tiếp theo ta chọn các field trong dataset để hiển thị lên table, click
Next ở bước này chọn vào mục
Use the same connection used to fill the master report. Click
Next, và ở bước cuối ta có một số tùy chọn cho cách hiển thị của table như hình dưới đây:

Click
Finish, sau đó trong phần thiết kế cho table sẽ hiện ra trong tab
Table 1.
Ở phần này ta có thể tùy chỉnh table như là tên của các cột,
độ rộng của các cột, padding, … như hình dưới đây:

Bây giờ sang bên tab
Main report, việc tiếp theo ta phải làm là map tham số
dsClassId của dataset với tham số
classId của master datasource mà ta đã tạo ở trên. Click chuột phải vào table mà ta vừa tạo, chọn
Edit table datasource. Chọn tab
Parameters chọn
Add, trong mục
Dataset parameter name chọn
dsClassId, trong mục
Value expression ta nhập
$P{classId} như hình dưới đây:

Nhấp
OK, ta có thể thấy sự ánh xạ giữa các tham số
từ dataset với các tham số của master datasource được hiển thị
trong tab
Parameters như hình dưới đây. Làm tương tự nếu như dataset của chúng ta còn có các tham số khác nữa

Làm tương tự các bước ở trên, tạo một dataset mới có tên là
DataSetStudentBelowAverage, một table mới để hiển thị danh sách các sinh viên có điểm dưới trung bình. Thêm một số các nhãn vào phần
Detail 1 của báo cáo, cuối cùng báo cáo của chúng ta sẽ giống như dưới đây

Chú ý là các thành phần ở phía dưới trong nội dung của phần
Detail 1 sẽ được đặt lại giá trị của thuộc tính
Position Type là
Float thay cho giá trị mặc định của chúng là
Fix to Relative Top
như hình dưới đây. Điều này đảm bảo rằng việc hiển thị các
thành phần ở phía dưới sẽ chỉ được bắt đầu khi các thành
phần ở phía trên đã hiện ra hoàn toàn nội dung của nó.

Bây giờ chúng ta sẽ viết java code để sinh ra một file báo
cáo dưới dạng PDF. Dùng Eclipse IDE sau đó tạo ra một Project có
cấu trúc giống như hình dưới đây:

Thư mục
lib lưu tất cả các thư viện cần dùng trong việc tạo report. File
StudentMark.jrxml mà chúng ta tạo ở trên sẽ được đặt ở trong một source folder có tên là reports.
Nội dung của file
Test.java sẽ giống như dưới đây:
Test.java
package testjasperreport;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.Map;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
public class Test {
public static void main(String [] args){
String targetFolder = "D:/StudentMarks/";
Connection con = null;
try{
String query = "SELECT * FROM CLASS";
con = getConnection();
PreparedStatement stm = con.prepareStatement(query);
ResultSet rs = stm.executeQuery();
while(rs.next()){ String classId = rs.getString("CLASS_ID");
String className = rs.getString("CLASS_NAME");
exportStudentMarkToPdf(classId, className, targetFolder);
}
rs.close();
stm.close();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(con != null && !con.isClosed())
{
con.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
public static void exportStudentMarkToPdf(String classId, String className, String targetFolder){
Connection con = null;
try {
String source = "reports/StudentMark.jrxml";
JasperReport jr = JasperCompileManager.compileReport(source);
Map<String, Object> params = new HashMap<String, Object>();
params.put("classId", classId); params.put("className", className);
con = getConnection(); JasperPrint jp = JasperFillManager.fillReport(jr, params, con);
OutputStream os = new FileOutputStream(targetFolder+"STUDENT_MARK_"+classId+".pdf");
JasperExportManager.exportReportToPdfStream(jp, os); os.flush(); os.close();
} catch (Exception e) {
e.printStackTrace();
}finally{
try{
if(con != null && !con.isClosed()){
con.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
public static Connection getConnection(){
Connection conn = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost/jasper_report_demo","root", "test12345");
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
}
Trong đoạn code trên, ta sẽ truy vấn vào database để lấy ra
danh sách các lớp và sau đó sẽ sinh ra báo cáo cho từng lớp
một. Ta chú ý nội dung của hàm
exportStudentMarkToPdf()
để có thể nhận biết các bước để sinh ra một báo cáo. Cần
phải nhắc lại là việc tạo báo cáo đơn giản là việc ta truyền
giá trị vào các tham số bên trong báo cáo. Ở ví dụ này hai
tham số ta cần dùng đến đó là
classId và
className sẽ được đặt vào trong một
Map
với key là tên của tham số, value là giá trị của tham số tương
ứng. Sau đó map này được truyền vào trong API của JasperReports.
Nếu như chúng ta truyền thiếu hoặc sai tên một tham số nào đó
trong bản mẫu thì một exception sẽ xảy ra trong quá trình tạo
báo cáo. Trong chương trình trên ta chỉ ra thư mục
D:/StudentMarks/
là thư mục sẽ chứa các file báo cáo được xuất ra. Các file
này có định dạng là PDF, mỗi file sẽ là thông tin báo cáo cho
một lớp học.
Bây giờ chúng ta chèn một số dữ liệu vào hai bảng
STUDENT và
CLASS trong database để test chương trình trên như sau:
INSERT INTO `jasper_report_demo`.`class` (`CLASS_ID`, `CLASS_NAME`) VALUES ('C001','Class Of Computer Science');
INSERT INTO `jasper_report_demo`.`class` (`CLASS_ID`, `CLASS_NAME`) VALUES ('C002','Class Of Software Engineering');
INSERT INTO `jasper_report_demo`.`student` (`STUDENT_NAME`, `MARK`, `CLASS_ID`) VALUES ('Nguyen Van A', 8, 'C001');
INSERT INTO `jasper_report_demo`.`student` (`STUDENT_NAME`, `MARK`, `CLASS_ID`) VALUES ('Nguyen Van B', 7, 'C001');
INSERT INTO `jasper_report_demo`.`student` (`STUDENT_NAME`, `MARK`, `CLASS_ID`) VALUES ('Nguyen Van C', 6, 'C001');
INSERT INTO `jasper_report_demo`.`student` (`STUDENT_NAME`, `MARK`, `CLASS_ID`) VALUES ('Nguyen Van D', 4, 'C001');
INSERT INTO `jasper_report_demo`.`student` (`STUDENT_NAME`, `MARK`, `CLASS_ID`) VALUES ('Nguyen Van E', 3, 'C001');
INSERT INTO `jasper_report_demo`.`student` (`STUDENT_NAME`, `MARK`, `CLASS_ID`) VALUES ('Nguyen Van F', 10, 'C002');
INSERT INTO `jasper_report_demo`.`student` (`STUDENT_NAME`, `MARK`, `CLASS_ID`) VALUES ('Nguyen Van G', 3, 'C002');
Sau đó tiến hành chạy file Test.java. Vào trong thư mục
D:/StudentMarks/ ta sẽ thấy hai file báo cáo tương ứng với hai lớp học có mã là
C001 và
C002 như hình dưới đây:

Mở từng file để kiểm tra dữ liệu và xem báo cáo được xuất ra. Nội dung hai file báo cáo lần lượt như dưới đây:
STUDENT_MARK_C001.pdf
STUDENT_MARK_C001.pdf
Chú ý: có một số tùy chỉnh trong quá trình thiết kế báo cáo như sau
1. Mặc định, khi không có dữ liệu ở các câu truy vấn thì
báo cáo sẽ hiện ra là một trang giấy trắng, ta có thể chỉnh
sửa thuộc tính “
When No Data” của báo cáo để đổi giá trị của nó từ “
No Pages” sang “
All Sections, No Detail“. Khi đó các phần của báo cáo sẽ được hiển thị ra đầy đủ ngay cả khi bản thân báo cáo không có dữ liệu.
2. Tương tự trong trường hợp của Table, bình thường khi bảng
không có dữ liệu thì các tiêu đề của bảng cũng không hiện ra.
Ta sửa thuộc tính “
When no data type” từ giá trị mặc định là “
Blank” sang “
All sections, no detail” để đảm bảo khi không có dữ liệu thì bảng vẫn hiển thị đầy đủ tiêu đền gồm các tên cột của nó.
3. Khi dữ liệu quá dài so với kích thước của một ô trong
bảng, theo mặc định, phần dữ liệu thừa sẽ bị cắt đi. Để đảm
bảo dữ liệu được hiển thị nguyên vẹn ta chọn vào thuộc tính “
Stretch With Overflow” như hình dưới đây. Khi đó phần dữ liệu tràn sẽ được đẩy xuống dòng dưới.

Như vậy bài viết này đã chỉ ra các bước để tạo ra một báo
cáo đơn giản với Jasper Report. Vì trong phạm vị bài viết không
thể nói hết, nên chỉ lấy ví dụ về việc xuất ra file báo cáo
dưới định dạng PDF. JasperReports còn cung cấp rất nhiều API
khác để xuất ra các file báo cáo dưới các định dạng khác
nữa. Với những gì bài viết cung cấp, hi vọng bạn đọc sẽ có
được những gì là cơ bản nhất để có thể tự tìm hiểu sâu hơn
về JasperReports.
Good luck!
Nguồn: http://codersontrang.wordpress.com/2013/06/16/tao-bao-cao-voi-jasperreports/