2009-08-15 13 views
21

Tôi mới vào thế giới của J (2) EE và phát triển ứng dụng web nhưng tôi đang nhanh chóng điều hướng theo cách của mình và học hỏi rất nhiều. Mỗi ngày là một hành trình khám phá mới tuyệt vời cho tôi.Lưu dữ liệu vào phiên trong JSF

Tôi hiện đang làm việc trên một dự án mà tôi đang sử dụng Visual JSF Woodstock trên Glassfish v2. Tôi cũng khá mới với JSF.

Có những lúc tôi cần lưu một số đối tượng (ví dụ MyObject chẳng hạn) giữa các yêu cầu. Và từ những gì tôi đã đọc và hiểu cho đến nay, tôi cần phải sử dụng các phiên để lưu các đối tượng này giữa các yêu cầu khác nhau. Càng xa càng tốt.

Chính xác cách thực hiện điều này là nơi mà mối quan tâm của tôi nằm. Tôi biết rằng trong JSP bạn có thể sử dụng session.setAttribute("myObj", myObject) để lưu đối tượng ở phía máy khách bằng cách sử dụng cookie hoặc ghi đè url hoặc biến biểu mẫu ẩn.

Mặt khác, trong JSF, tôi sử dụng hạt tạp phiên, ví dụ SessionBean1 ví dụ và lưu đối tượng dưới dạng thuộc tính SessionBean1 (ví dụ: SessionBean1.setSomeOjb(myObj)). Đây có phải là cách đi đúng đắn với điều này không?

Tôi đoán rằng thực hiện theo cách này sẽ dẫn đến việc sử dụng bộ nhớ tăng lên ở cuối máy chủ vì mỗi yêu cầu sẽ tạo một phiên bản mới của phiên có phạm vi bean, SessionBean1 cộng với bộ nhớ được sử dụng bởi các cá thể myObject đã lưu trong SessionBean1.

Tôi đã đọc rằng bạn có thể sử dụng FacesContext.getExternalContext().getSession/getSessionMap() để lưu biến phiên ở phía máy khách.

Vậy phương pháp nào bạn đề xuất tôi nên sử dụng - bean có phạm vi phiên hoặc sơ đồ phiên để lưu các đối tượng truy cập giữa các yêu cầu cho một phiên?

Cảm ơn.

+1

"mỗi yêu cầu sẽ tạo ra một phiên bản mới của đậu phạm vi phiên" Đây là HOÀN THÀNH HOÀN THÀNH –

Trả lời

21

Nói chung, Java EE Web Apps có xu hướng không mong đợi để lưu dữ liệu phiên phía máy khách. Bạn có quyền lo ngại về bloat phiên ở phía máy chủ, một vấn đề phổ biến được thấy là có các dấu chân phiên lớn có thể gây ra các vấn đề về hiệu suất và tài nguyên đáng kể và có thể đặc biệt trong môi trường nhóm.

Tôi muốn biết nơi bạn nhìn thấy

Tôi đã đọc mà bạn có thể sử dụng FacesContext.getExternalContext(). GetSession/getSessionMap() mà sẽ tiết kiệm biến phiên tại phía khách hàng.

Tôi tin rằng (chính xác cho tôi vào thời điểm này) rằng đây chỉ đơn giản là cho phép truy cập đến đối tượng HttpSession, trên đó thì bạn có thể sử dụng cùng một

session.setAttribute("myObj", myObject) 

này không tự nó gửi các đối tượng trở lại khách hàng, nó được giữ trong máy chủ và được khóa bởi một số định danh phiên, thường được chuyển trong cookie. Bây giờ có hai kỹ thuật khác: bạn có thể chọn để đưa dữ liệu vào một cookie sản xuất của riêng bạn - các API servlet mà bạn có thể truy cập từ JSF hoặc JSP sẽ cho phép bạn thực hiện điều đó hoặc bạn có thể sử dụng các trường ẩn các biểu mẫu của bạn và do đó chuyển dữ liệu phiên aorund.

Nhưng hãy cân nhắc điều này. Quy tắc chung trên Máy chủ ứng dụng tôi sử dụng là HttpSession thứ tự của 1k-4k có xu hướng không phải là vấn đề. Lớn hơn thế (và tôi đã thấy các phiên được đo bằng megabyte) làm căng thẳng cơ sở hạ tầng.Nếu bạn lo ngại về các phiên có kích thước đó, bạn có thể gửi dữ liệu megabyte trong cookie hoặc trường ẩn trở lại trình duyệt theo mọi yêu cầu không? Ngay cả 1k-2k có lẽ là một chút lớn.

Vì vậy, khuyến nghị:

  1. Giữ nó đơn giản. Sử dụng API phiên hoặc biểu hiện JSF của nó.

  2. Giữ lượng dữ liệu trong phiên dưới sự kiểm soát.

gia tăng để đáp ứng với câu hỏi về phân nhóm:

Thông thường, trong một môi trường clustered chúng tôi có phiên mối quan hệ, do đó yêu cầu được gửi lại cho các cluster member cùng. Tuy nhiên chúng tôi vẫn cần phải xem xét trường hợp (có lẽ nếu một thành viên cụm không thành công) khi yêu cầu đi đến một máy chủ khác nhau. Một số nhà cung cấp Máy chủ ứng dụng cung cấp bản sao phiên, thông qua liên lạc trực tiếp giữa máy chủ hoặc bằng cách duy trì phiên tới cơ sở dữ liệu - rõ ràng là có chi phí ở đây, vì vậy đôi khi, đối với phiên có giá trị thấp, chúng tôi chỉ chấp nhận mất phiên trong sự kiện của sự thất bại.

Có một lập luận rằng nếu dữ liệu phiên có giá trị cao thì nó sẽ được ứng dụng lưu giữ, nó thực sự là dữ liệu nghiệp vụ và cần được xử lý như vậy. Càng ngày, các cơ sở dữ liệu NOSQL như Cloudant hoặc MongoDb được sử dụng cho việc này. Trong trường hợp này, chúng ta có thể nghĩ về phiên HTTP như một bộ nhớ đệm, trong kiến ​​thức rằng dữ liệu phiên có thể được truy xuất trong trường hợp có lỗi.

Vì vậy, tôi cho rằng Giỏ hàng có thể có giá trị đáng kể đối với doanh nghiệp; nó đại diện cho khách hàng tích lũy chu đáo về những thứ họ muốn tiêu tiền. Vì vậy, nó nên được duy trì, thay vì sau đó chỉ giữ trong phiên. Khi chúng tôi quyết định vẫn tồn tại, chúng tôi thấy rằng nó dẫn đến các tình huống thú vị khác như trải nghiệm tổng hợp trên nhiều thiết bị khách. Khách hàng bắt đầu mua sắm tại nhà trên máy tính để bàn nhưng hoàn tất việc mua hàng trực tuyến.

Vì vậy, nguyên tắc khác:

3). Không sử dụng quá nhiều phiên HTTP chỉ vì nó ở đó. Xem xét giá trị kinh doanh của dữ liệu và liệu nó có nên được duy trì hay không.

+0

Bạn nói đúng. Tôi đã hiểu nhầm rằng toàn bộ các đối tượng phiên đang được lưu trong bản đồ phiên và bản đồ phiên sau đó sẽ được gửi cho khách hàng nơi nó được lưu trữ dưới dạng cookie hoặc trường ẩn. Thay vào đó, nó là id phiên đang được gửi đến máy khách. Nếu tôi hiểu chính xác, id phiên này có thể được sử dụng để truy xuất cá thể của HttpSession đang lưu trữ tất cả các thuộc tính cho phiên web cụ thể đó, đúng không? Cảm ơn bạn đã chỉ ra sự hiểu lầm của tôi. – SibzTer

+0

Xin chào, tôi biết rằng có một thời gian dài mà bạn trả lời câu hỏi nhưng bạn đã nói điều gì đó thú vị về môi trường nhóm. Làm cách nào để giữ phiên trong loại kiến ​​trúc này nếu phiên được lưu trong máy chủ trả lời yêu cầu? – kavain

+1

@Kavain: Các máy chủ Java-EE tốt cung cấp tùy chọn để tối ưu hóa sao chép phiên trong các cụm để chuyển đổi dự phòng. Chúng cho phép các máy chủ được cấu hình theo nhóm, vì vậy không phải tất cả các máy chủ đều nhận được tất cả thông tin phiên. Chỉ những người trong cùng một nhóm. Tốt hơn cho hiệu suất trong bản thân bản thân và sử dụng bộ nhớ. Vì vậy, ví dụ: có 1.000.000 người dùng có kích thước phiên 100k trên 100 máy chủ sẽ không có nghĩa là mỗi máy chủ sẽ yêu cầu 100GB bộ nhớ. Distrubuted trong nhóm 3, sẽ yêu cầu mỗi máy chủ chỉ có 3 GB. Và kích thước phiên là 100k là lớn ... – Kukeltje

2

Vậy bạn sẽ đề xuất phương pháp nào - bean có phạm vi phiên hoặc sơ đồ phiên để lưu các đối tượng truy cập giữa các yêu cầu cho một phiên?

Hai thứ này lưu trữ dữ liệu ở cùng một vị trí.

<managed-bean> 
    <managed-bean-class>foo.Bar</managed-bean-class> 
    <managed-bean-name>bar</managed-bean-name> 
    <managed-bean-scope>session</managed-bean-scope> 
</managed-bean> 

Khi được tham chiếu trong biểu thức, bạn có thể tra cứu "thanh" theo chương trình qua external context.

FYI: trong JSF2, tờ khai có thể được loại bỏ và thay thế bằng chú thích:

@ManagedBean(name="bar") @SessionScoped 
public class Bar { 
... 
+0

Phải thừa nhận là khoảng 3 năm kể từ khi tôi chạm vào JSF. Quay lại sau đó tôi sẽ chỉ sử dụng một phiên quản lý phạm vi đậu, khá nhiều như bạn hiển thị. Tôi không xem xét bất kỳ xen kẽ nào vào thời điểm đó. Tôi đoán một vấn đề có thể là làm thế nào để đảm bảo rằng chúng tôi giữ gọn gàng này, không muốn dần dần hút nhiều hạt đậu được quản lý theo phiên. Điều này có thể là xuống tên đậu được chọn cẩn thận. – djna

14

Tôi đang làm việc trên một dự án của trường đại học với các đồng nghiệp của tôi, là một trang web như GoogleImage Labeler. Vâng, vì vậy chúng tôi có một UserController, với các phương thức đăng nhập, đăng xuất, v.v ...và chúng tôi phạm vi phiên như sau:

@ManagedBean(name = "userController") 
@SessionScoped 

Ok, đây là những gì thuật sĩ của NetBeans tạo ra cho bạn.

cách chúng tôi tạo ra và quản lý phiên là:

Tại phương pháp đăng ký (trong đó chúng tôi sử dụng các thuộc tính của hình thức trong XHTML ...), chúng tôi tồn tại người dùng trong DB và sau đó chúng tôi thêm các giá trị trong phiên:

FacesContext context = FacesContext.getCurrentInstance(); 
context.getExternalContext().getSessionMap().put("user", current); 

Nơi "hiện tại" là Người dùng (Người dùng đã đăng nhập). Chúng tôi có cùng phương thức đăng nhập .

Tại phương pháp logout ta có:

FacesContext.getCurrentInstance().getExternalContext().invalidateSession(); 

Tôi hy vọng điều này sẽ giúp bạn.

+2

Đây là vụng về. Chỉ cần gán 'current' làm thuộc tính của' UserController' (vì nó đã * trong phạm vi phiên!) Và đặt nó thành 'null' khi đăng xuất (hoặc tốt hơn, làm' ExternalContext # invalidateSession() '. Xem thêm http: //stackoverflow.com/questions/3841361/jsf-http-session-login/3842060#3842060 – BalusC

+0

Tôi đã chỉnh sửa bài đăng để thay thế mã của mình bằng mã @BalusC đã nói. Tôi đã thay đổi 'FacesContext context = FacesContext.getCurrentInstance (); context.getExternalContext(). GetSessionMap(). Remove ("user"); 'cho' FacesContext.getCurrentInstance(). GetExternalContext(). InvalidateSession(); ' –