Apa perbedaan antara action
dan actionListener
, dan kapan saya harus menggunakan action
versus actionListener
?
Apa perbedaan antara action
dan actionListener
, dan kapan saya harus menggunakan action
versus actionListener
?
Jawaban:
Gunakan actionListener
jika Anda ingin memiliki pengait sebelum tindakan bisnis nyata dijalankan, misalnya untuk mencatatnya, dan / atau untuk mengatur properti tambahan (oleh <f:setPropertyActionListener>
), dan / atau untuk memiliki akses ke komponen yang meminta tindakan (yang tersedia oleh ActionEvent
argumen). Jadi, murni untuk menyiapkan tujuan sebelum aksi bisnis nyata dipanggil.
The actionListener
metode memiliki secara default tanda tangan berikut:
import javax.faces.event.ActionEvent;
// ...
public void actionListener(ActionEvent event) {
// ...
}
Dan itu seharusnya dinyatakan sebagai berikut, tanpa metode kurung:
<h:commandXxx ... actionListener="#{bean.actionListener}" />
Perhatikan bahwa Anda tidak dapat melewati argumen tambahan oleh EL 2.2. Namun Anda dapat mengesampingkan ActionEvent
argumen secara keseluruhan dengan meneruskan dan menentukan argumen khusus. Contoh-contoh berikut ini valid:
<h:commandXxx ... actionListener="#{bean.methodWithoutArguments()}" />
<h:commandXxx ... actionListener="#{bean.methodWithOneArgument(arg1)}" />
<h:commandXxx ... actionListener="#{bean.methodWithTwoArguments(arg1, arg2)}" />
public void methodWithoutArguments() {}
public void methodWithOneArgument(Object arg1) {}
public void methodWithTwoArguments(Object arg1, Object arg2) {}
Perhatikan pentingnya tanda kurung dalam ekspresi metode tanpa argumen. Jika mereka tidak ada, JSF masih akan mengharapkan metode dengan ActionEvent
argumen.
Jika Anda menggunakan EL 2.2+, maka Anda dapat mendeklarasikan beberapa metode pendengar tindakan melalui <f:actionListener binding>
.
<h:commandXxx ... actionListener="#{bean.actionListener1}">
<f:actionListener binding="#{bean.actionListener2()}" />
<f:actionListener binding="#{bean.actionListener3()}" />
</h:commandXxx>
public void actionListener1(ActionEvent event) {}
public void actionListener2() {}
public void actionListener3() {}
Perhatikan pentingnya tanda kurung dalam binding
atribut. Jika mereka tidak ada, EL akan membingungkan melemparkan javax.el.PropertyNotFoundException: Property 'actionListener1' not found on type com.example.Bean
, karena binding
atribut secara default diartikan sebagai ekspresi nilai, bukan sebagai ekspresi metode. Menambahkan tanda kurung gaya EL 2.2+ secara transparan mengubah ekspresi nilai menjadi ekspresi metode. Lihat juga ao. Mengapa saya bisa mengikat <f: actionListener> ke metode arbitrer jika tidak didukung oleh JSF?
Gunakan action
jika Anda ingin menjalankan aksi bisnis dan jika perlu menangani navigasi. The action
Metode dapat (dengan demikian, tidak harus) mengembalikan String
yang akan digunakan sebagai kasus navigasi hasil (tampilan target). Nilai pengembalian null
atau void
akan membiarkannya kembali ke halaman yang sama dan menjaga lingkup tampilan saat ini tetap hidup. Nilai kembali dari string kosong atau ID tampilan yang sama juga akan kembali ke halaman yang sama, tetapi membuat ulang ruang lingkup tampilan dan dengan demikian menghancurkan setiap scoped bean yang saat ini aktif dilihat dan, jika ada, membuatnya kembali.
The action
Metode dapat berupa valid MethodExpression
, juga orang-orang yang menggunakan EL 2.2 argumen seperti di bawah ini:
<h:commandXxx value="submit" action="#{bean.edit(item)}" />
Dengan metode ini:
public void edit(Item item) {
// ...
}
Perhatikan bahwa ketika metode tindakan Anda hanya mengembalikan string, maka Anda juga bisa menentukan string tersebut di action
atribut. Jadi, ini benar-benar canggung:
<h:commandLink value="Go to next page" action="#{bean.goToNextpage}" />
Dengan metode tidak masuk akal ini mengembalikan string yang dikodekan:
public String goToNextpage() {
return "nextpage";
}
Sebagai gantinya, cukup masukkan string hardcoded secara langsung di atribut:
<h:commandLink value="Go to next page" action="nextpage" />
Harap perhatikan bahwa ini pada gilirannya menunjukkan desain yang buruk: menavigasi dengan POST. Ini bukan pengguna atau SEO friendly. Ini semua dijelaskan di Kapan saya harus menggunakan h: outputLink bukan h: commandLink? dan seharusnya diselesaikan sebagai
<h:link value="Go to next page" outcome="nextpage" />
Lihat juga Bagaimana cara menavigasi di JSF? Cara membuat URL mencerminkan halaman saat ini (dan bukan yang sebelumnya) .
Karena JSF 2.x ada cara ketiga, the <f:ajax listener>
.
<h:commandXxx ...>
<f:ajax listener="#{bean.ajaxListener}" />
</h:commandXxx>
The ajaxListener
metode memiliki secara default tanda tangan berikut:
import javax.faces.event.AjaxBehaviorEvent;
// ...
public void ajaxListener(AjaxBehaviorEvent event) {
// ...
}
Di Mojarra, AjaxBehaviorEvent
argumennya opsional, di bawah ini berfungsi dengan baik.
public void ajaxListener() {
// ...
}
Tapi di MyFaces, itu akan melempar MethodNotFoundException
. Di bawah ini berfungsi di kedua implementasi JSF ketika Anda ingin menghilangkan argumen.
<h:commandXxx ...>
<f:ajax execute="@form" listener="#{bean.ajaxListener()}" render="@form" />
</h:commandXxx>
Pendengar Ajax tidak benar-benar berguna pada komponen perintah. Mereka lebih berguna pada input dan pilih komponen <h:inputXxx>
/ <h:selectXxx>
. Dalam komponen perintah, tetap berpegang pada action
dan / atau actionListener
untuk kejelasan dan kode pendokumentasian diri yang lebih baik. Selain itu, seperti actionListener
, yang f:ajax listener
tidak mendukung mengembalikan hasil navigasi.
<h:commandXxx ... action="#{bean.action}">
<f:ajax execute="@form" render="@form" />
</h:commandXxx>
Untuk penjelasan execute
dan render
atribut, pergilah ke Memahami proses / pembaruan PrimeFaces dan JSF f: ajax execute / render atribut .
Itu actionListener
s selalu dipanggil sebelum itu action
dalam urutan yang sama seperti yang dinyatakan dalam tampilan dan melekat pada komponen. Itu f:ajax listener
selalu dipanggil sebelum pendengar tindakan. Jadi, contoh berikut:
<h:commandButton value="submit" actionListener="#{bean.actionListener}" action="#{bean.action}">
<f:actionListener type="com.example.ActionListenerType" />
<f:actionListener binding="#{bean.actionListenerBinding()}" />
<f:setPropertyActionListener target="#{bean.property}" value="some" />
<f:ajax listener="#{bean.ajaxListener}" />
</h:commandButton>
Akan memohon metode dalam urutan berikut:
Bean#ajaxListener()
Bean#actionListener()
ActionListenerType#processAction()
Bean#actionListenerBinding()
Bean#setProperty()
Bean#action()
Itu actionListener
mendukung pengecualian khusus: AbortProcessingException
. Jika pengecualian ini dilemparkan dari suatu actionListener
metode, maka JSF akan melewatkan pendengar tindakan yang tersisa dan metode tindakan dan melanjutkan untuk memberikan tanggapan secara langsung. Anda tidak akan melihat halaman kesalahan / pengecualian, namun JSF akan mencatatnya. Ini juga secara implisit akan dilakukan setiap kali ada pengecualian lain yang dilemparkan dari actionListener
. Jadi, jika Anda bermaksud untuk memblokir halaman dengan halaman kesalahan sebagai akibat dari pengecualian bisnis, maka Anda pasti harus melakukan pekerjaan dalam action
metode tersebut.
Jika satu-satunya alasan untuk menggunakan actionListener
adalah untuk memilikivoid
metode untuk kembali ke halaman yang sama, maka itu adalah metode yang buruk. action
Metode - metode ini juga dapat kembali dengan sempurna void
, sebaliknya apa yang Anda yakini oleh beberapa IDE melalui validasi EL. Perhatikan bahwa contoh showcase PrimeFaces dikotori dengan jenis ini actionListener
di semua tempat. Ini memang salah. Jangan gunakan ini sebagai alasan untuk melakukannya sendiri.
Namun dalam permintaan ajax, penangan pengecualian khusus diperlukan. Ini terlepas dari apakah Anda menggunakan listener
atribut <f:ajax>
atau tidak. Untuk penjelasan dan contoh, buka penanganan Pengecualian dalam permintaan ajax JSF .
actionListener
, tetapi itu masih tidak menjadikannya alasan yang baik untuk penyalahgunaan actionListener
untuk tindakan bisnis .
action
sesuai dengan itu. actionListener
adalah untuk hal-hal sekunder. Hanya ingin mengklarifikasi bahwa pengecualian dari actionListener
s dapat diperbanyak jika diperlukan;)
actionListener
atribut dan itu harus public
juga. The processAction
Nama hanya wajib ketika Anda menggunakan <f:actionListener type>
, hanya karena jenis harus mengimplementasikan ActionListener
antarmuka yang memiliki tepat bahwa nama metode processAction
definied.
<f:ajax>
, Anda dalam kasus komponen perintah lebih suka menggunakan action
atribut untuk tindakan bisnis. Misalnya <h:commandButton action="#{bean.businessAction}"><f:ajax/></h:commandButton>
.
Seperti yang ditunjukkan BalusC, actionListener
secara default menelan pengecualian, tetapi di JSF 2.0 ada sedikit lebih dari ini. Yaitu, itu tidak hanya menelan dan mencatat, tetapi sebenarnya menerbitkan pengecualian.
Ini terjadi melalui panggilan seperti ini:
context.getApplication().publishEvent(context, ExceptionQueuedEvent.class,
new ExceptionQueuedEventContext(context, exception, source, phaseId)
);
Pendengar default untuk acara ini adalah ExceptionHandler
yang diatur untuk Mojarracom.sun.faces.context.ExceptionHandlerImpl
. Implementasi ini pada dasarnya akan memikirkan kembali pengecualian apa pun, kecuali jika menyangkut AbortProcessingException, yang dicatat. ActionListeners membungkus pengecualian yang dilemparkan oleh kode klien sedemikian AbortProcessingException yang menjelaskan mengapa ini selalu dicatat.
Namun ini ExceptionHandler
bisa diganti di wajah-config.xml dengan implementasi khusus:
<exception-handlerfactory>
com.foo.myExceptionHandler
</exception-handlerfactory>
Alih-alih mendengarkan secara global, satu kacang juga dapat mendengarkan acara ini. Berikut ini adalah bukti konsep ini:
@ManagedBean
@RequestScoped
public class MyBean {
public void actionMethod(ActionEvent event) {
FacesContext.getCurrentInstance().getApplication().subscribeToEvent(ExceptionQueuedEvent.class, new SystemEventListener() {
@Override
public void processEvent(SystemEvent event) throws AbortProcessingException {
ExceptionQueuedEventContext content = (ExceptionQueuedEventContext)event.getSource();
throw new RuntimeException(content.getException());
}
@Override
public boolean isListenerForSource(Object source) {
return true;
}
});
throw new RuntimeException("test");
}
}
(perhatikan, ini bukan bagaimana seharusnya kode pendengar, ini hanya untuk tujuan demonstrasi!)
Memanggil ini dari Facelet seperti ini:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:body>
<h:form>
<h:commandButton value="test" actionListener="#{myBean.actionMethod}"/>
</h:form>
</h:body>
</html>
Akan menghasilkan halaman kesalahan yang ditampilkan.
ActionListener dipecat terlebih dahulu, dengan opsi untuk mengubah respons, sebelum Aksi dipanggil dan menentukan lokasi halaman berikutnya.
Jika Anda memiliki beberapa tombol pada halaman yang sama yang harus pergi ke tempat yang sama tetapi melakukan hal-hal yang sedikit berbeda, Anda dapat menggunakan Aksi yang sama untuk setiap tombol, tetapi menggunakan ActionListener yang berbeda untuk menangani fungsionalitas yang sedikit berbeda.
Berikut ini tautan yang menggambarkan hubungan:
TL; DR :
The ActionListener
s (bisa ada beberapa) mengeksekusi dalam urutan mereka terdaftar SEBELUMaction
Jawaban panjang :
Suatu bisnis action
biasanya meminta layanan EJB dan jika perlu juga menetapkan hasil akhir dan / atau menavigasi ke tampilan yang berbeda jika itu bukan apa yang Anda lakukan actionListener
adalah lebih tepat yaitu ketika ketika pengguna berinteraksi dengan komponen, seperti h:commandButton
atau h:link
mereka dapat ditangani dengan meneruskan nama metode kacang terkelola dalam actionListener
atribut Komponen UI atau untuk mengimplementasikan ActionListener
antarmuka dan meneruskan nama kelas implementasi ke actionListener
atribut Komponen UI.