Nhận bean được quản lý JSF theo tên trong bất kỳ lớp nào liên quan đến Servlet


101

Tôi đang cố gắng viết một servlet tùy chỉnh (cho AJAX / JSON) trong đó tôi muốn tham chiếu @ManagedBeanstheo tên của mình. Tôi hy vọng sẽ lập bản đồ:

http://host/app/myBean/myProperty

đến:

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

Có thể tải một bean theo tên từ một servlet thông thường không? Có một servlet JSF hoặc trình trợ giúp mà tôi có thể sử dụng cho nó không?

Tôi dường như được chiều chuộng bởi Spring, trong đó tất cả điều này là quá rõ ràng.


Tôi không chắc liệu bạn có thể sử dụng những chú thích mới này bên ngoài JSF / EL hay không, nhưng tôi sẽ bắt đầu bằng cách xem xét thông số JSR 299: jcp.org/en/jsr/detail?id=299
McDowell

Những người khác gặp vấn đề với vấn đề tương tự cũng có thể kiểm tra bpcatalog.dev.java.net/ajax/jsf-ajax (liên quan đến AJAX và yêu cầu lập bản đồ / xử lý, không nhận được đậu theo tên)
Konrad Garus

Câu trả lời:


263

Trong một tạo tác dựa trên servlet, chẳng hạn như @WebServlet, @WebFilter@WebListener, bạn có thể lấy JSF "vani đơn giản" @ManagedBean @RequestScopedbằng cách:

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

@ManagedBean @SessionScopedbởi:

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

@ManagedBean @ApplicationScopedbởi:

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

Lưu ý rằng điều này yêu cầu trước rằng bean đã được JSF tự động tạo trước đó. Nếu không, chúng sẽ trở lại null. Sau đó, bạn cần phải tạo bean theo cách thủ công và sử dụng setAttribute("beanName", bean).


Nếu bạn có thể sử dụng CDI @Namedthay vì JSF 2.3 không được chấp nhận @ManagedBean, thì điều đó thậm chí còn dễ dàng hơn, đặc biệt là vì bạn không cần phải tạo các bean theo cách thủ công nữa:

@Inject
private Bean bean;

Lưu ý rằng điều này sẽ không hoạt động khi bạn đang sử dụng @Named @ViewScopedvì bean chỉ có thể được xác định bằng trạng thái xem JSF và điều đó chỉ khả dụng khi nó FacesServletđã được gọi. Vì vậy, trong một bộ lọc mà chạy trước đó, truy cập vào một @Injected @ViewScopedsẽ luôn ném ContextNotActiveException.


Chỉ khi bạn ở trong @ManagedBean, bạn mới có thể sử dụng @ManagedProperty:

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

Lưu ý rằng điều này không làm việc bên trong một @Namedhoặc @WebServlethoặc bất kỳ vật khác. Nó thực sự chỉ hoạt động bên trong @ManagedBean.


Nếu bạn không ở trong a @ManagedBean, nhưng FacesContextcó sẵn (tức là FacesContext#getCurrentInstance()không quay lại null), bạn cũng có thể sử dụng Application#evaluateExpressionGet():

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

có thể được thuận tiện như sau:

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

và có thể được sử dụng như sau:

Bean bean = findBean("bean");

Xem thêm:


9
Đề nghị thứ hai của bạn về việc chỉ tiêm hạt đậu đơn giản đến mức tuyệt vời mà tôi đã hoàn toàn bỏ qua. Như mọi khi, câu trả lời của bạn là hoàn hảo. Cảm ơn rất nhiều vì công việc của bạn ở đây trên SO.
30

2
Trong khi đó (nói về JSF 2.2), có vẻ như phương thức evalExpressionGet đã được mở rộng với tham số thứ ba cho phép chỉ định lớp mong đợi nên việc truyền sẽ không cần thiết nữa. PostBean bean = context.getApplication().evaluateExpressionGet(context, "#{beanName}", PostBean.class);
Marc Juchli

1
@Marc: Đã tham gia ngay từ đầu. Tôi đoán chỉ là một phần còn sót lại từ một lỗi copypaste. Câu trả lời đã được sửa chữa. Cảm ơn bạn đã thông báo.
BalusC

FacesContextcó sẵn ngay cả khi staticphương thức tiện ích findBean()được định nghĩa bên trong một lớp Java thuần túy. Làm thế nào nó có sẵn ở đó trong một lớp Java thuần túy không được quản lý bởi JSF?
Tiny

1
@Tiny: nó lần lượt được gọi bởi một tạo tác JSF trong cùng một chuỗi.
BalusC

11

Tôi sử dụng phương pháp sau:

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

Điều này cho phép tôi lấy đối tượng trả về theo cách đã nhập.


3
Điều này đã được bao phủ bởi câu trả lời được chấp nhận hiện tại và thậm chí theo cách thuận tiện hơn ( Classđối số cụ thể là không cần thiết trong cấu trúc này).
BalusC 10/12/12

3

Bạn đã thử cách tiếp cận như trên liên kết này chưa? Tôi không chắc liệu createValueBinding()có còn khả dụng hay không nhưng mã như thế này có thể truy cập được từ một Servlet cũ đơn giản. Điều này yêu cầu bean đã tồn tại.

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

Điều này có thể sẽ không hoạt động trong một servlet thông thường. FacesContext là một đồ tạo tác cục bộ theo luồng theo yêu cầu được thiết lập bởi vòng đời JSF (thường là FacesServlet).
McDowell

7
ValueBinding không được dùng nữa kể từ JSF 1.2 hơn 4 năm trước.
BalusC

@BalusC: Nó hiển thị mức độ cập nhật của tôi lol. Theo một ghi chú bên lề, việc sử dụng công cụ tìm kiếm để nghiên cứu các kỹ thuật hóa ra lại phản tác dụng với tất cả thông tin cũ ngoài kia. @McDowell: Điều đó thực sự có ý nghĩa. Tôi sẽ làm một bài kiểm tra chỉ để xem điều gì sẽ xảy ra.
James P.

3

Bạn có thể lấy bean được quản lý bằng cách chuyển tên:

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

Tôi cố gắng làm điều này từ một servlet nhưng nó không hoạt động.
Fernando Pie

0

Tôi đã có yêu cầu tương tự.

Tôi đã sử dụng cách dưới đây để có được nó.

Tôi đã có phiên đậu phạm vi.

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

Tôi đã sử dụng đoạn mã dưới đây trong phương thức doPost () của servlet.

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

nó đã giải quyết vấn đề của tôi.


Bạn sử dụng loại Servlet nào? bạn đời
Fernando Pie

1
Đó là HttpServlet.
Anil

-1

Tôi sử dụng cái này:

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

Và sau đó gọi:

MyManageBean bean = getBean(MyManageBean.class);

Bằng cách này, bạn có thể cấu trúc lại mã của mình và theo dõi việc sử dụng mà không gặp vấn đề gì.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.