รับ JSF ที่มีการจัดการ bean ตามชื่อในคลาสที่เกี่ยวข้องกับ Servlet


101

ฉันกำลังพยายามเขียน servlet ที่กำหนดเอง (สำหรับ AJAX / JSON) ซึ่งฉันต้องการอ้างอิง@ManagedBeansตามชื่อ ฉันหวังว่าจะทำแผนที่:

http://host/app/myBean/myProperty

ถึง:

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

เป็นไปได้ไหมที่จะโหลด bean โดยใช้ชื่อจาก servlet ปกติ มี servlet JSF หรือตัวช่วยที่ฉันสามารถใช้ได้หรือไม่

ดูเหมือนว่าฉันจะเสียฤดูใบไม้ผลิซึ่งทั้งหมดนี้ชัดเจนเกินไป


ฉันไม่แน่ใจว่าคุณสามารถใช้คำอธิบายประกอบใหม่เหล่านี้นอก JSF / EL ได้หรือไม่ แต่ฉันจะเริ่มด้วยการดูข้อมูลจำเพาะ JSR 299: jcp.org/en/jsr/detail?id=299
McDowell

คนอื่น ๆ ที่มีปัญหาเกี่ยวกับปัญหาที่คล้ายกันสามารถตรวจสอบbpcatalog.dev.java.net/ajax/jsf-ajax (เกี่ยวข้องกับ AJAX และขอการแมป / การจัดการไม่ได้รับถั่วตามชื่อ)
Konrad Garus

คำตอบ:


263

ในสิ่งประดิษฐ์ตามเซิร์ฟเล็ตเช่น@WebServlet, @WebFilterและ@WebListenerคุณสามารถคว้า "วานิลลาธรรมดา" JSF @ManagedBean @RequestScopedโดย:

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

และ@ManagedBean @SessionScopedโดย:

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

และ@ManagedBean @ApplicationScopedโดย:

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

โปรดทราบว่าสิ่งนี้จำเป็นต้องมีที่ JSF สร้างขึ้นโดยอัตโนมัติล่วงหน้าอยู่แล้ว อื่น ๆ nullเหล่านี้จะกลับมา setAttribute("beanName", bean)จากนั้นคุณจะต้องสร้างด้วยตนเองถั่วและการใช้งาน


หากคุณสามารถใช้ CDI @Namedแทนเนื่องจาก JSF 2.3 เลิกใช้งาน@ManagedBeanแล้วจะง่ายยิ่งขึ้นโดยเฉพาะอย่างยิ่งเนื่องจากคุณไม่จำเป็นต้องสร้างถั่วด้วยตนเองอีกต่อไป:

@Inject
private Bean bean;

โปรดทราบว่าจะใช้ไม่ได้เมื่อคุณใช้@Named @ViewScopedเนื่องจาก bean สามารถระบุได้ด้วยสถานะมุมมอง JSF เท่านั้นและจะใช้ได้เฉพาะเมื่อFacesServletมีการเรียกใช้ ดังนั้นในการกรองซึ่งไปก่อนนั้นการเข้าถึง@Injectเอ็ดมักจะโยน@ViewScopedContextNotActiveException


เมื่อคุณอยู่ข้างใน@ManagedBeanเท่านั้นจึงจะสามารถใช้@ManagedProperty:

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

โปรดทราบว่าสิ่งนี้ใช้ไม่ได้ภายใน@Namedหรือ@WebServletหรือสิ่งประดิษฐ์อื่น ๆ มันใช้งานได้จริงภายใน@ManagedBeanเท่านั้น


หากคุณไม่ได้อยู่ใน a @ManagedBeanแต่FacesContextพร้อมใช้งาน (เช่นFacesContext#getCurrentInstance()ไม่ส่งคืนnull) คุณยังสามารถใช้Application#evaluateExpressionGet():

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

โดยสามารถสรุปได้ดังนี้

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

และสามารถใช้งานได้ดังนี้:

Bean bean = findBean("bean");

ดูสิ่งนี้ด้วย:


9
คำแนะนำที่สองของคุณเกี่ยวกับการฉีดถั่วนั้นง่ายมากอย่างน่าอัศจรรย์ที่ฉันมองข้ามไปโดยสิ้นเชิง เช่นเคยคำตอบของคุณตรงประเด็น ขอบคุณมากสำหรับการทำงานของคุณที่ SO
ม.ค. 30

2
ในระหว่างนี้ (พูดถึง JSF 2.2) ดูเหมือนว่าวิธีการประเมิน ExpressionGet จะขยายด้วยพารามิเตอร์ที่สามที่อนุญาตให้ระบุคลาสที่คาดหวังดังนั้นการแคสต์จะไม่จำเป็นอีกต่อไป PostBean bean = context.getApplication().evaluateExpressionGet(context, "#{beanName}", PostBean.class);
Marc Juchli

1
@ มาร์ค: อยู่มาตั้งแต่แรก เป็นเพียงสิ่งที่เหลือจากความผิดพลาดในการลอกเลียนแบบฉันเดา คำตอบได้รับการแก้ไขแล้ว ขอบคุณที่แจ้ง.
BalusC

FacesContextจะพร้อมใช้งานแม้ว่าstaticวิธีการยูทิลิตี้findBean()จะถูกกำหนดไว้ในคลาส Java ธรรมดา มันมีอยู่ในคลาส Java ธรรมดาที่ไม่ได้รับการจัดการโดย JSF ได้อย่างไร?
จิ๋ว

1
@Tiny: จะถูกเรียกโดยสิ่งประดิษฐ์ JSF ภายในเธรดเดียวกัน
BalusC

11

ฉันใช้วิธีต่อไปนี้:

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);
}

สิ่งนี้ทำให้ฉันได้รับวัตถุที่ส่งคืนในลักษณะที่พิมพ์


3
สิ่งนี้ครอบคลุมอยู่แล้วโดยคำตอบที่ยอมรับในปัจจุบันและแม้กระทั่งในวิธีที่สะดวกกว่า ( Classอาร์กิวเมนต์ไม่จำเป็นในโครงสร้างนี้)
BalusC

3

คุณได้ลองใช้แนวทางในลิงค์นี้หรือไม่? ฉันไม่แน่ใจว่าcreateValueBinding()ยังมีอยู่หรือไม่ แต่รหัสแบบนี้ควรเข้าถึงได้จาก Servlet แบบเก่าธรรมดา สิ่งนี้จำเป็นต้องมีถั่วอยู่แล้ว

http://www.coderanch.com/t/211706/JSF/java/access-managed-bean-JSF- จาก

 FacesContext context = FacesContext.getCurrentInstance();  
 Application app = context.getApplication();
 // May be deprecated
 ValueBinding binding = app.createValueBinding("#{" + expr + "}"); 
 Object value = binding.getValue(context);

สิ่งนี้อาจใช้ไม่ได้ใน servlet ปกติ FacesContext คือสิ่งประดิษฐ์เธรดโลคัลตามคำขอที่ตั้งค่าโดยวงจรชีวิต JSF (โดยปกติคือ FacesServlet)
McDowell

7
ValueBinding เลิกใช้งานตั้งแต่ JSF 1.2 เมื่อ 4 ปีที่แล้ว
BalusC

@BalusC: มันแสดงให้เห็นว่าฉันเป็นคนล่าสุดแค่ไหน ในแง่มุมการใช้เครื่องมือค้นหาในการค้นคว้าเทคนิคนั้นกลับกลายเป็นการต่อต้านข้อมูลเก่า ๆ ทั้งหมดที่มีอยู่ในนั้น @McDowell: นั่นสมเหตุสมผลจริงๆ ฉันจะทดสอบเพื่อดูว่าเกิดอะไรขึ้น
James P.

3

คุณสามารถรับถั่วที่จัดการได้โดยส่งชื่อ:

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;
}

ฉันพยายามทำสิ่งนี้จาก servlet แต่มันไม่ได้ผล
Fernando Pie

0

ฉันมีข้อกำหนดเดียวกัน

ฉันใช้วิธีด้านล่างเพื่อรับมัน

ฉันมีเซสชั่นสโคปถั่ว

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

ฉันใช้โค้ดด้านล่างนี้ในวิธี servlet doPost () ของฉัน

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

มันช่วยแก้ปัญหาของฉันได้


คุณใช้ servlet แบบไหน? mate
Fernando Pie

1
มันคือ HttpServlet
Anil

-1

ฉันใช้สิ่งนี้:

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;
}

แล้วโทร:

MyManageBean bean = getBean(MyManageBean.class);

วิธีนี้ทำให้คุณสามารถ refactor โค้ดของคุณและติดตามการใช้งานได้โดยไม่มีปัญหา

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.