Tutorial Membuat Halaman Wizard Menggunakan JSF dan CDI

Proses wizard adalah beberapa halaman yang digabungkan untuk membentuk satu alur proses, misal. Jika kita akan memasukkan data yang sangat banyak, biasanya kita memisahkan data tersebut menjadi beberapa bagian. Contoh saat kita akan memasukkan biodata pegawai, kita akan memasukkan data identitasnya terlebih dahulu, setelah itu memasukkan data akademik, data pengalaman kerja, dan lain-lain. Dari pada kita memasukkan datanya ke dalam satu halaman, lebih baik jika kita membaginya menjadi beberapa halaman.
Dalam proses wizard, artinya data pada halaman pertama harus dapat diakses pada halaman kedua dan halaman selanjutnya. Dalam web, biasanya data tersebut disimpan dalam sebuah HttpSession. Namun jika kita menggunakan HttpSession, maka data akan selalu sama dalam browser yang kita gunakan. Jika kita merubah data wizard di satu tab, maka data pada tab yang lain akan ikut berubah. Hal ini membuat kita tidak dapat menambah data secara sekaligus di beberapa tab.
Dalam kasus ini, kita dapat menggunakan @ConversationScope milik Context & Dependency Injection (CDI) yang tergabung dalam teknologi JEE 6. Untuk menggunakan CDI, kita hanya dapat menggunakannya pada Enterprise Application Server seperti Glassfish dan JBoss. Kita tidak dapat menggunakannya Servlet Container seperti Tomcat dan Jetty.
Untuk membuat sebuah ManageBean menggunakan @ConversationScope kita hanya perlu menambahkan @ConversationScope dalam kelas ManageBean yang kita gunakan, dan setelah itu menambahkan sebuah variabel Conversation menggunakan annotation @Inject.
01package khannedy.learning.faces.controller;
02 
03import java.io.Serializable;
04import javax.enterprise.context.Conversation;
05import javax.inject.Named;
06import javax.enterprise.context.ConversationScoped;
07import javax.inject.Inject;
08 
09@Named(value = "WizardController")
10@ConversationScoped
11public class WizardController implements Serializable {
12 
13    @Inject
14    private Conversation conversation;
15}
Untuk memulai proses wizard, maka kita perlu memanggil metode begin() pada objek Conversation. Dan untuk mengakhiri proses wizard, kita perlu memanggil metode end() pada objek Conversation.
1@PostConstruct
2public void start(){
3    conversation.begin();
4}
5 
6public String finish(){
7    conversation.end();
8    return "finish";
9}
Karena kita akan membuat sebuah wizard, dimana terdapat beberapa tahapan dalam sebuah proses, maka kita perlu menentukan berapa jumlah tahapan yang terjadi pada wizard tersebut. Untuk mengetahui sekarang proses keberapa, kita dapat menambahkan variabel step dalam ManageBean.
1private int step;
2 
3public int getStep() {
4    return step;
5}
Dalam sebuah wizard, harus ada navigasi untuk ke halaman selanjutnya dan kehalaman sebelumnya. Oleh karena itu, kita perlu menambahkan metode next() untuk ke halaman selanjutnya dan prev() untuk kehalaman sebelumnya.
1public String next(){
2    step++;
3    return null;
4}
5 
6public String prev(){
7    step--;
8    return null;
9}
Sebagai contoh, kita tambahkan 4 buah variabel yang harus diisi ketika proses wizard. Setiap variabel diisi dalam satu tahapan, sehingga akan ada 4 tahapan dalam proses wizard ini.
1private String data1;
2private String data2;
3private String data3;
4private String data4;
5 
6// getter and setter
7...
Berikut adalah kode lengkap untuk kelas ManageBean yang telah kita buat :
01package khannedy.learning.faces.controller;
02 
03import java.io.Serializable;
04import javax.annotation.PostConstruct;
05import javax.enterprise.context.Conversation;
06import javax.inject.Named;
07import javax.enterprise.context.ConversationScoped;
08import javax.inject.Inject;
09 
10@Named(value = "WizardController")
11@ConversationScoped
12public class WizardController implements Serializable {
13 
14    @Inject
15    private Conversation conversation;
16    private int step;
17    private String data1;
18    private String data2;
19    private String data3;
20    private String data4;
21 
22    @PostConstruct
23    public void start() {
24        conversation.begin();
25    }
26 
27    public String finish() {
28        conversation.end();
29        return "finish";
30    }
31 
32    public int getStep() {
33        return step;
34    }
35 
36    public String next() {
37        step++;
38        return null;
39    }
40 
41    public String prev() {
42        step--;
43        return null;
44    }
45 
46    public String getData1() {
47        return data1;
48    }
49 
50    public void setData1(String data1) {
51        this.data1 = data1;
52    }
53 
54    public String getData2() {
55        return data2;
56    }
57 
58    public void setData2(String data2) {
59        this.data2 = data2;
60    }
61 
62    public String getData3() {
63        return data3;
64    }
65 
66    public void setData3(String data3) {
67        this.data3 = data3;
68    }
69 
70    public String getData4() {
71        return data4;
72    }
73 
74    public void setData4(String data4) {
75        this.data4 = data4;
76    }
77}
Setelah itu, kita dapat membuat halaman faceletnya hanya dengan menggunakan 1 file xhtml.
01<?xml version='1.0' encoding='UTF-8' ?>
02<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
04      xmlns:h="http://java.sun.com/jsf/html">
05    <h:head>
06        <title>Simple Wizard</title>
07    </h:head>
08    <h:body>
09    </h:body>
10</html>
Setelah itu, kita hanya perlu menambahkan h:form dan h:input yang akan digunakan untuk mengisi data-data pada wizard.
01<?xml version='1.0' encoding='UTF-8' ?>
02<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
04      xmlns:h="http://java.sun.com/jsf/html">
05    <h:head>
06        <title>Simple Wizard</title>
07    </h:head>
08    <h:body>
09        <h:form id="wizard">
10 
11            <h:panelGrid rendered="#{WizardController.step == 0}" columns="3">
12                <h:outputLabel for="data1" value="Data 1 :"></h:outputLabel>
13                <h:inputText id="data1" value="#{WizardController.data1}" required="true"></h:inputText>
14                <h:message for="data1"></h:message>
15                <h:outputText></h:outputText>
16                <h:panelGroup>
17                    <h:commandButton value="Next" action="#{WizardController.next}"></h:commandButton>
18                </h:panelGroup>
19                <h:outputText></h:outputText>
20            </h:panelGrid>
21 
22            <h:panelGrid rendered="#{WizardController.step == 1}" columns="3">
23                <h:outputLabel for="data2" value="Data 2 :"></h:outputLabel>
24                <h:inputText id="data2" value="#{WizardController.data2}" required="true"></h:inputText>
25                <h:message for="data2"></h:message>
26                <h:outputText></h:outputText>
27                <h:panelGroup>
28                    <h:commandButton value="Prev" action="#{WizardController.prev}" immediate="true"></h:commandButton>
29                    <h:commandButton value="Next" action="#{WizardController.next}"></h:commandButton>
30                </h:panelGroup>
31                <h:outputText></h:outputText>
32            </h:panelGrid>
33 
34            <h:panelGrid rendered="#{WizardController.step == 2}" columns="3">
35                <h:outputLabel for="data3" value="Data 3 :"></h:outputLabel>
36                <h:inputText id="data3" value="#{WizardController.data3}" required="true"></h:inputText>
37                <h:message for="data3"></h:message>
38                <h:outputText></h:outputText>
39                <h:panelGroup>
40                    <h:commandButton value="Prev" action="#{WizardController.prev}" immediate="true"></h:commandButton>
41                    <h:commandButton value="Next" action="#{WizardController.next}"></h:commandButton>
42                </h:panelGroup>
43                <h:outputText></h:outputText>
44            </h:panelGrid>
45 
46            <h:panelGrid rendered="#{WizardController.step == 3}" columns="3">
47                <h:outputLabel for="data4" value="Data 4 :"></h:outputLabel>
48                <h:inputText id="data4" value="#{WizardController.data4}" required="true"></h:inputText>
49                <h:message for="data4"></h:message>
50                <h:outputText></h:outputText>
51                <h:panelGroup>
52                    <h:commandButton value="Prev" action="#{WizardController.prev}" immediate="true"></h:commandButton>
53                    <h:commandButton value="Finish" action="#{WizardController.finish}"></h:commandButton>
54                </h:panelGroup>
55                <h:outputText></h:outputText>
56            </h:panelGrid>
57 
58        </h:form>
59    </h:body>
60</html>
Pada kode diatas, kita menggunakan h:panelGrid untuk menampilkan input wizard. Agar h:panelGrid tersebut muncul, maka kita menggunakan atribut rendered=”#{WizardController.step == step}”, artinya jika step-nya 0, maka h:panelGrid yang menampilkan input data 1 yang muncul, dan seterusnya, sampai h:panelGrid untuk input data 4.
Setelah membuat halaman wizard.xhtml, kita dapat membuat sebuah halaman finish.xhtml untuk menampilkan halaman ketika proses wizard selesai.
01<?xml version='1.0' encoding='UTF-8' ?>
02<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
04      xmlns:h="http://java.sun.com/jsf/html">
05    <h:head>
06        <title>Finish Wizard</title>
07    </h:head>
08    <h:body>
09        <h1>Thank's!!!!</h1>
10    </h:body>
11</html>
Hasilnya kita dapat melihatnya pada gambar dibawah ini :
Wizard Step 1
Wizard Step 1
Wizard Step 2
Wizard Step 2
Wizard Finish
Wizard Finish