Dapatkan kacang yang dikelola JSF dengan nama di kelas terkait Servlet

101

Saya mencoba menulis servlet khusus (untuk AJAX / JSON) di mana saya ingin merujuk @ManagedBeansnama saya . Saya berharap untuk memetakan:

http://host/app/myBean/myProperty

untuk:

@ManagedBean(name="myBean")
public class MyBean {
    public String getMyProperty();
}

Apakah mungkin untuk memuat kacang dengan nama dari servlet biasa? Apakah ada servlet atau pembantu JSF yang bisa saya gunakan untuk itu?

Saya tampaknya dimanjakan oleh Spring di mana semua ini terlalu jelas.

Konrad Garus
sumber
Saya tidak yakin apakah Anda dapat menggunakan anotasi baru ini di luar JSF / EL, tetapi saya akan mulai dengan melihat spesifikasi JSR 299: jcp.org/en/jsr/detail?id=299
McDowell
Orang lain yang memiliki masalah dengan masalah serupa juga dapat memeriksa bpcatalog.dev.java.net/ajax/jsf-ajax (terkait dengan AJAX dan meminta pemetaan / penanganan, tidak mendapatkan biji berdasarkan nama)
Konrad Garus

Jawaban:

263

Dalam artefak berbasis servlet, seperti @WebServlet, @WebFilterdan @WebListener, Anda dapat mengambil JSF "vanilla biasa" @ManagedBean @RequestScopeddengan:

Bean bean = (Bean) request.getAttribute("beanName");

dan @ManagedBean @SessionScopedoleh:

Bean bean = (Bean) request.getSession().getAttribute("beanName");

dan @ManagedBean @ApplicationScopedoleh:

Bean bean = (Bean) getServletContext().getAttribute("beanName");

Perhatikan bahwa ini mensyaratkan bahwa kacang sudah dibuat secara otomatis oleh JSF sebelumnya. Jika tidak, ini akan kembali null. Anda kemudian perlu membuat kacang dan menggunakannya secara manual setAttribute("beanName", bean).


Jika Anda dapat menggunakan CDI dan @Namedbukan karena JSF 2.3 sudah tidak digunakan lagi @ManagedBean, ini akan lebih mudah, terutama karena Anda tidak perlu lagi membuat kacang secara manual:

@Inject
private Bean bean;

Perhatikan bahwa ini tidak akan berfungsi saat Anda menggunakan @Named @ViewScopedkarena kacang hanya dapat diidentifikasi oleh status tampilan JSF dan itu hanya tersedia ketika FacesServlettelah dipanggil. Jadi dalam filter yang berjalan sebelumnya, mengakses @Injected @ViewScopedakan selalu membuang ContextNotActiveException.


Hanya ketika Anda berada di dalam @ManagedBean, maka Anda dapat menggunakan @ManagedProperty:

@ManagedProperty("#{bean}")
private Bean bean;

Perhatikan bahwa ini tidak berfungsi di dalam @Namedatau @WebServletatau artefak lainnya. Ini benar-benar @ManagedBeanhanya berfungsi di dalam .


Jika Anda tidak berada di dalam a @ManagedBean, tetapi FacesContextsudah tersedia (yaitu FacesContext#getCurrentInstance()tidak kembali null), Anda juga dapat menggunakan Application#evaluateExpressionGet():

FacesContext context = FacesContext.getCurrentInstance();
Bean bean = context.getApplication().evaluateExpressionGet(context, "#{beanName}", Bean.class);

yang dapat diselenggarakan sebagai berikut:

@SuppressWarnings("unchecked")
public static <T> T findBean(String beanName) {
    FacesContext context = FacesContext.getCurrentInstance();
    return (T) context.getApplication().evaluateExpressionGet(context, "#{" + beanName + "}", Object.class);
}

dan dapat digunakan sebagai berikut:

Bean bean = findBean("bean");

Lihat juga:

BalusC
sumber
9
Saran kedua Anda tentang hanya menyuntikkan kacang itu sangat sederhana sehingga saya benar-benar mengabaikannya. Seperti biasa, tanggapan Anda sangat tepat sasaran. Terima kasih banyak atas pekerjaan Anda di SO.
jnt30
2
Sementara itu (berbicara tentang JSF 2.2) sepertinya metode evaluExpressionGet telah diperpanjang dengan parameter ketiga yang memungkinkan untuk menentukan kelas yang diharapkan sehingga transmisi tidak diperlukan lagi. PostBean bean = context.getApplication().evaluateExpressionGet(context, "#{beanName}", PostBean.class);
Marc Juchli
1
@Marc: Telah masuk dari awal. Kurasa hanya sisa-sisa dari kesalahan pasta copypaste. Jawaban telah diperbaiki. Terima kasih telah memberi tahu.
BalusC
FacesContexttersedia meskipun staticmetode utilitas findBean()ditentukan di dalam kelas Java biasa. Bagaimana ini tersedia di sana dalam kelas Java biasa yang tidak dikelola oleh JSF?
Tiny
1
@Tiny: ini pada gilirannya dipanggil oleh artefak JSF dalam utas yang sama.
BalusC
11

Saya menggunakan metode berikut:

public static <T> T getBean(final String beanName, final Class<T> clazz) {
    ELContext elContext = FacesContext.getCurrentInstance().getELContext();
    return (T) FacesContext.getCurrentInstance().getApplication().getELResolver().getValue(elContext, null, beanName);
}

Ini memungkinkan saya untuk mendapatkan objek yang dikembalikan dengan cara yang diketik.

John Yeary
sumber
3
Ini sudah tercakup dalam jawaban yang diterima saat ini dan bahkan dengan cara yang lebih nyaman ( Classargumen tidak diperlukan dalam konstruksi ini).
BalusC
3

Sudahkah Anda mencoba pendekatan seperti di tautan ini? Saya tidak yakin apakah createValueBinding()masih tersedia tetapi kode seperti ini harus dapat diakses dari Servlet lama biasa. Ini membutuhkan kacang untuk sudah ada.

http://www.coderanch.com/t/211706/JSF/java/access-managed-bean-JSF-from

 FacesContext context = FacesContext.getCurrentInstance();  
 Application app = context.getApplication();
 // May be deprecated
 ValueBinding binding = app.createValueBinding("#{" + expr + "}"); 
 Object value = binding.getValue(context);
James P.
sumber
Ini mungkin tidak akan berfungsi di servlet biasa. FacesContext adalah artefak lokal thread per permintaan yang disiapkan oleh siklus proses JSF (biasanya FacesServlet).
McDowell
7
ValueBinding tidak digunakan lagi sejak JSF 1.2 lebih dari 4 tahun yang lalu.
BalusC
@BalusC: Ini menunjukkan betapa up to date saya lol. Di sisi lain, menggunakan mesin pencari untuk teknik penelitian ternyata kontraproduktif dengan semua informasi lama di luar sana. @ McDowell: Itu sebenarnya masuk akal. Saya akan melakukan tes hanya untuk melihat apa yang terjadi.
James P.
3

Anda bisa mendapatkan kacang yang dikelola dengan memasukkan nama:

public static Object getBean(String beanName){
    Object bean = null;
    FacesContext fc = FacesContext.getCurrentInstance();
    if(fc!=null){
         ELContext elContext = fc.getELContext();
         bean = elContext.getELResolver().getValue(elContext, null, beanName);
    }

    return bean;
}
Soujanya
sumber
Saya mencoba melakukan ini dari servlet tetapi tidak berhasil.
Fernando Pie
0

Saya memiliki persyaratan yang sama.

Saya telah menggunakan cara di bawah ini untuk mendapatkannya.

Saya memiliki sesi kacang cakupan.

@ManagedBean(name="mb")
@SessionScopedpublic 
class ManagedBean {
     --------
}

Saya telah menggunakan kode di bawah ini dalam metode servlet doPost () saya.

ManagedBean mb = (ManagedBean) request.getSession().getAttribute("mb");

itu memecahkan masalah saya.

Anil
sumber
Jenis servlet apa yang Anda gunakan? pasangan
Fernando Pie
1
Ini adalah HttpServlet.
Anil
-1

Saya menggunakan ini:

public static <T> T getBean(Class<T> clazz) {
    try {
        String beanName = getBeanName(clazz);
        FacesContext facesContext = FacesContext.getCurrentInstance();
        return facesContext.getApplication().evaluateExpressionGet(facesContext, "#{" + beanName + "}", clazz);
    //return facesContext.getApplication().getELResolver().getValue(facesContext.getELContext(), null, nomeBean);
    } catch (Exception ex) {
        return null;
    }
}

public static <T> String getBeanName(Class<T> clazz) {
    ManagedBean managedBean = clazz.getAnnotation(ManagedBean.class);
    String beanName = managedBean.name();

    if (StringHelper.isNullOrEmpty(beanName)) {
        beanName = clazz.getSimpleName();
        beanName = Character.toLowerCase(beanName.charAt(0)) + beanName.substring(1);
    }

    return beanName;
}

Dan kemudian hubungi:

MyManageBean bean = getBean(MyManageBean.class);

Dengan cara ini Anda dapat memfaktor ulang kode Anda dan melacak penggunaan tanpa masalah.

ChRoNoN
sumber