2011-01-21 21 views
7

Có cách nào để lấy một phiên từ một POJO không? Hoặc cuối cùng là lấy một hạt từ POJO.Lấy bối cảnh servlet, phiên làm việc và yêu cầu trong một thùng chứa POJO bên ngoài

Để làm rõ:

Về cơ bản tôi đang tạo ra một bean từ một servlet và tôi cần phải truy cập vào các tính chất của đậu mà từ bên ngoài của những trang web chứa (từ một POJO). Tôi không thể chuyển yêu cầu đến pojo; và yêu cầu là cần thiết để truy xuất phiên.

Cụ thể hơn, tôi có một ứng dụng web sử dụng khung công tác Cactus để chạy các kiểm tra JUnit từ giao diện web. Tuy nhiên servlet gọi Á hậu thử nghiệm JUnit được biên dịch trong một cái bình; Tôi đã bổ sung thêm các menu thả xuống để thay đổi các thiết lập mà từ đó kiểm tra JUnit sẽ đọc từ để chuyển đổi giữa các môi trường khác nhau (WLI cluster), do đó servlet runner đã được biên dịch, tôi không thể sửa đổi nó để xử lý các tham số phụ từ nhiều môi trường. Tôi đã thử phương pháp tiếp cận liên tục bằng văn bản cho một tệp .dat fro mà bài kiểm tra JUnit sẽ đọc từ một lớp Reader; tôi cũng đã thử phương pháp tiếp cận bean mà cuối cùng không thể truy cập từ bài kiểm tra JUnit.

+0

Bạn có thể giải thích một chút về vấn đề của mình không? – Sid

+0

Mô tả vấn đề của bạn tốt hơn. Rõ ràng bạn có một ứng dụng web đang thao tác dữ liệu. Có vẻ như bạn cần lưu trữ và sau đó tham chiếu nó bên ngoài ứng dụng web. – DwB

+0

Được rồi, hãy xem các chỉnh sửa ở trên, cảm ơn. – TheWolf

Trả lời

11

Chỉ và chỉ khi POJO của bạn đang chạy trong cùng chủ đề như HttpServletRequest đang chạy trong, sau đó bạn sẽ có thể đạt được điều này với sự giúp đỡ của ThreadLocal<T>.

Tạo lớp sau:

public final class YourContext implements AutoCloseable { 

    private static ThreadLocal<YourContext> instance = new ThreadLocal<>(); 

    private HttpServletRequest request; 
    private HttpServletResponse response; 

    private YourContext(HttpServletRequest request, HttpServletResponse response) { 
     this.request = request; 
     this.response = response; 
    } 

    public static YourContext create(HttpServletRequest request, HttpServletResponse response) { 
     YourContext context = new YourContext(request, response); 
     instance.set(context); 
     return context; 
    } 

    public static YourContext getCurrentInstance() { 
     return instance.get(); 
    } 

    @Override  
    public void close() { 
     instance.remove(); 
    } 

    public HttpServletRequest getRequest() { 
     return request; 
    } 

    public HttpSession getSession() { 
     return request.getSession(); 
    } 

    public ServletContext getServletContext() { 
     return request.getServletContext(); 
    } 

    // ... (add if necessary more methods here which return/delegate the request/response).  
} 

Thực hiện javax.servlet.Filter mà làm như sau trong doFilter() phương pháp và được ánh xạ vào một url-pattern quan tâm, ví dụ /* hoặc trên servlet-name của servlet bộ điều khiển phía trước của bạn.

@Override 
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException { 
    HttpServletRequest request = (HttpServletRequest) req; 
    HttpServletResponse response = (HttpServletResponse) res; 

    try (YourContext context = YourContext.create(request, response)) { 
     chain.doFilter(request, response); 
    } 
} 

Lưu ý tầm quan trọng của tuyên bố cố gắng với tài nguyên. Nó đảm bảo rằng YourContext#close() sẽ được gọi sau khi bộ lọc đã thực hiện công việc của mình và tài nguyên ThreadLocal sẽ bị xóa. Nếu không, luồng vẫn sẽ chứa nó khi được tái chế cho một yêu cầu HTTP khác.

Và đây là cách bạn có thể sử dụng nó trong các POJO:

YourContext context = YourContext.getCurrentInstance(); 
HttpSession session = context.getSession(); 

này tất cả là về cơ bản cũng như thế nào Context đối tượng của khung MVC trung bình hoạt động, như JSF FacesContext và một trong Wicket.

Nói rằng, bạn đã xem CDI chưa? Có lẽ nó dễ dàng hơn để làm cho các tạo tác CDI được quản lý để bạn có thể chỉ @Inject chúng với nhau.

+0

Cảm ơn, điều này thật tuyệt vời. Gói ThreadLocal nào thuộc về gói nào? ThreadLocal gốc JDK không chấp nhận các mẫu. – TheWolf

+0

Ok tôi đã tìm thấy nó trong JDK 6, tôi đang sử dụng WLI 8 vì vậy tôi bị giới hạn ở JDK 1.4, liệu đối tượng không có khuôn mẫu có hoạt động tốt không? – TheWolf

+1

Liên kết 'ThreadLocal ' trong các điểm trả lời của tôi cho javadoc 'java.lang.ThreadLocal'. Tôi không chắc ý bạn là gì với "mẫu", nhưng nếu bạn đang thực sự đề cập đến tham số kiểu chung '' (và sử dụng nhất quán cụm từ "POJO" cũ của bạn vào tài khoản) tôi nghi ngờ rằng bạn aren chưa có trên Java 1.5. Trong trường hợp đó, chỉ cần bỏ qua '' trong ví dụ mã và áp dụng phôi '(Ngữ cảnh)' nếu có. Theo gợi ý javadoc, 'ThreadLocal' đã có sẵn từ 1.2. – BalusC

2

Một Pojo là một đối tượng Java cũ đơn giản. POJOS không liên quan gì đến phiên.

Phiên https có sẵn trên đối tượng yêu cầu.

Check-out

http://download.oracle.com/docs/cd/E17802_01/webservices/webservices/docs/1.6/api/index.html

đặc biệt là giao diện HttpServletRequest này, và phương pháp getSession().

Đối với phần 'bean' của câu hỏi của bạn. Một bean là một lớp java phù hợp với 3 tiêu chuẩn.

  1. Không constructor arg
  2. setters và thu khí để truy cập các lĩnh vực tin
  3. Thực hiện serializable.

POJO là bean nếu nó tuân theo các quy ước đó.

+0

Tôi có nghĩa là truy xuất phiên web được tạo từ phiên web (ví dụ: từ một số loại yêu cầu) từ POJO bên ngoài vùng chứa web. (Phiên không đến từ POJO tất nhiên). – TheWolf

+0

@Vapen 'một POJO bên ngoài vùng chứa web' không có cách nào, bạn cần phải lưu giữ dữ liệu ở một nơi nào đó hoặc bằng cách nào bạn cần truyền dữ liệu –

+0

Tôi đã thử phương pháp tiếp cận bền vững bằng cách ghi các tham số vào tệp .dat và tôi chạy vào điều kiện chủng tộc cho các yêu cầu đồng thời truy cập vào tệp .dat. – TheWolf

2

Giả sử rằng bạn đang đề cập đến lập trình Servlet ....

Không có cách nào trực tiếp để có được từ một POJO đến phiên. Bạn cần lấy Session từ đối tượng HttpServletRequest.

Có 2 giải pháp phổ biến mà tôi đã thấy để giải quyết vấn đề này.

Tùy chọn đầu tiên là tạo đối tượng ngữ cảnh của một số loại có chứa Phiên. Sau đó, ngữ cảnh này được chuyển xuống tầng kinh doanh của bạn để các POJO của bạn có thể nhận được thông tin này nếu họ cần.

Tùy chọn thứ hai là tận dụng lưu trữ ThreadLocal. Thường thì phiên được đặt trên lưu trữ ThreadLocal bởi bộ lọc hoặc bộ chặn. Sau đó, bất kỳ đối tượng trong hệ thống của bạn có thể lấy nó từ chuỗi. Mẫu này hiển thị trong rất nhiều khung công tác web như Spring và Struts.

+0

Tôi cần đối tượng ngữ cảnh để được stateful và duy trì trạng thái của nó trong suốt toàn bộ cuộc sống của phiên và có thể thay đổi, điều này có thể không? – TheWolf

+0

Các giải pháp mà tôi đã cung cấp sẽ chỉ có quyền truy cập trong suốt thời gian yêu cầu. Nó sẽ có thể snag một phiên và lưu trữ một tham chiếu đến nó bên ngoài chu kỳ cuộc sống yêu cầu tiêu chuẩn, nhưng tôi thực sự sẽ không khuyên bạn nên. Tại thời điểm đó, bạn sẽ được nhìn thấy cách container servlet của bạn xử lý các phiên. Không thực sự là nơi bạn muốn. Bạn có thể cải tổ câu hỏi của mình để thể hiện điều bạn muốn làm ở cấp độ cao hơn không? Có lẽ việc tham chiếu đến Phiên không phải là giải pháp tốt nhất. – rfeak

+0

Cảm ơn, gần đây tôi đã chỉnh sửa câu hỏi của tôi, bạn có thể vui lòng kiểm tra các chỉnh sửa mới. Tôi có thể giải thích thêm các yêu cầu nếu cần :) – TheWolf

2

Có, có.

Nếu bạn đang sử dụng một khung công tác web, ví dụ như Wicket, thường có cách để lấy HttpSession hiện tại. Từ đó, bạn có thể lấy Spring ApplicationContext và nếu bạn có nó, bạn có thể lấy Spring Beans từ nó. Điều này làm việc ở bất kỳ vị trí nào, vì chúng tôi chỉ sử dụng các phương thức tiện ích tĩnh.

Ví dụ mã:

import org.apache.wicket.protocol.http.WebApplication; 
import org.springframework.web.context.support.WebApplicationContextUtils; 
import org.springframework.web.context.WebApplicationContext; 

ServletContext sc = WebApplication.getServletContext(); 
WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(sc); 

Object bean = wac.getBean("myBeanId"); 

Lưu ý tuy nhiên đó Lọc mùa xuân và Wicket Lọc phải tại chỗ và xử lý các yêu cầu hiện tại, nếu không thì phương pháp hữu ích sẽ không hoạt động.

Nếu bạn không có nghĩa là Đậu mùa xuân, bạn sẽ phải tự lưu trữ chúng trong phiên HTTP. Nếu bạn không có khung web, bạn có thể muốn làm gì rfeak đang đề xuất và triển khai ThreadLocal của riêng bạn.

+0

"Object bean = wac.getBean (" myBeanId ");" sẽ mang lại đậu từ phiên hiện tại cho rằng nó có phạm vi phiên? – TheWolf

+0

Không, không phải bean phiên, mà là Bean Bean từ ngữ cảnh ứng dụng. – mhaller

+0

-1 để tiêm Spring vào giải pháp, vẫn có thể xây dựng phần mềm mà không có nó. –

Các vấn đề liên quan