2011-11-09 30 views
12

Vấn đề là gì: Điều gì sẽ xảy ra khi nhấp vào nút quay lại trình duyệt -> mở ra một trang có quản lý khung nhìn đã bị hủy -> gửi yêu cầu từ một lệnhButton từ đó trang có lựa chọn bản ghi-lưới?browser back + viewscope beans

Điều tôi mong đợi: Chế độ xem-khung nhìn liên quan được tạo lại, nhận các lựa chọn bản ghi trên lưới và xử lý chúng như thể nút quay lại trình duyệt không bao giờ liên quan.

Điều tôi trải nghiệm: Chế độ xem-khung nhìn liên quan không được tạo lại, không nhận được lựa chọn bản ghi lưới. Phải nhập lại URL hoặc F5 sau khi nhấp vào nút trình duyệt để nó hoạt động bình thường trở lại. đậu

Vì vậy, đây là kịch bản thành công, tất cả đậu được viewscoped:

  1. GET page1.xhtml -> page1Bean tạo ra, truy vấn dữ liệu, vv trong @PostConstruct
  2. kiểm tra/chọn một vài hồ sơ từ một nút dữ liệu, nhấp vào nút xử lý
  3. page1Phương pháp xử lý của Bean lưu trữ các bản ghi đã chọn trong đối tượng flash và chuyển hướng đến trang2.xhtml
  4. page1Bean destroyed, page2Bean created and in preRenderView phương thức nghe, tìm nạp các bản ghi đã chọn từ đối tượng flash và xử lý chúng
  5. nhấp vào lệnh "chuyển đến trang chính" để chuyển hướng đến page1.xhtml và page2Bean bị hủy, page1Bean được tạo lại
  6. vòng từ số 2 - 5 là vẫn doable

Bây giờ, đây là errornous kịch bản liên quan đến trình duyệt lại nút (chất liệu khác nhau xảy ra bắt đầu từ # 6):

  1. GET page1.xhtml -> page1Bean tạo, truy vấn dat một, vv trong @PostConstruct
  2. kiểm tra/chọn một vài hồ sơ từ một DataTable, click vào nút quá trình
  3. phương pháp quá trình page1Bean của cửa hàng các hồ sơ được chọn trong các đối tượng flash, và chuyển hướng đến page2.xhtml
  4. page1Bean bị phá hủy, page2Bean tạo ra, và trong phương pháp nghe preRenderView, lấy về các hồ sơ được lựa chọn từ các đối tượng flash, và đối phó với chúng
  5. nhấp vào trình duyệt lại nút page2Bean không bị tiêu diệt, page1Bean không được tạo ra
  6. kiểm tra/chọn một vài hồ sơ từ một datatable, bấm vào nút quá trình
  7. phương thức page1Bean thực thi (lạ, vì page1Bean lẽ ra đã bị hủy), nhưng không thể thấy các lựa chọn bản ghi được thực hiện và chuyển hướng đến page2.xhtml
  8. page1Bean không bị phá hủy (không có đầu ra khai thác gỗ), page2Bean không được tạo ra (vì nó không bị phá hủy), thực hiện người nghe preRenderView như thường lệ, nhưng lần này, không có lựa chọn các bản ghi trong đối tượng flash

Có thể có trải nghiệm bình thường (như thể không có nút quay lại trình duyệt) với các hạt cảnh quan bằng nút quay lại trình duyệt không?

Đây là sự phụ thuộc của tôi:

<dependency> 
    <groupId>org.glassfish</groupId> 
    <artifactId>javax.faces</artifactId> 
    <version>2.1.3</version> 
    <scope>compile</scope> 
</dependency> 

Hãy chia sẻ ý tưởng của bạn!

Trả lời

15

Trình duyệt dường như đã phục vụ trang từ bộ nhớ cache thay vì gửi yêu cầu HTTP GET đầy đủ tới máy chủ, trong khi bạn đã đặt phương thức lưu trạng thái JSF thành server (mặc định).

Có 2 cách để giải quyết vấn đề này:

  1. Cho trình duyệt để không cache các trang JSF động. Bạn có thể thực hiện việc này với sự trợ giúp của filter.

    @Override 
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 
        HttpServletRequest req = (HttpServletRequest) request; 
        HttpServletResponse res = (HttpServletResponse) response; 
    
        if (!req.getRequestURI().startsWith(req.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER)) { // Skip JSF resources (CSS/JS/Images/etc) 
         res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1. 
         res.setHeader("Pragma", "no-cache"); // HTTP 1.0. 
         res.setDateHeader("Expires", 0); // Proxies. 
        } 
    
        chain.doFilter(request, response); 
    } 
    

    Ánh xạ bộ lọc trên FacesServlet hoặc cùng một mẫu URL.

  2. Đặt phương thức lưu trạng thái JSF thành ứng dụng khách, để toàn bộ trạng thái xem được lưu trữ trong trường ẩn của biểu mẫu thay vì trong phiên ở phía máy chủ.

    <context-param> 
        <param-name>javax.faces.STATE_SAVING_METHOD</param-name> 
        <param-value>client</param-value> 
    </context-param> 
    

Bộ lọc cách là một lợi thế.

+0

cảm ơn vì ví dụ nguồn :) tôi đã thử thay đổi phương thức tiết kiệm trạng thái cho ứng dụng khách, tôi hơi bối rối, tôi phải thay đổi nhiều hạt đậu và tên miền thành serializable. vì vậy, đã thử bộ lọc và làm việc tuyệt vời! mặc dù với một chút lo lắng với bài viết này ở đây: http://turbomanage.wordpress.com/2006/08/08/disable-browser-caching-in-jsf/ mà nói rằng nó không được bảo đảm. Nhưng theo kinh nghiệm của tôi ở đây, nó hoạt động rất tốt. – bertie

+0

Làm điều này trong một 'PhaseListener' là vụng về. Như để đảm bảo, tốt, ông đã có một điểm, nhưng tất cả các trình duyệt hiện đại (IE, FF, GC, AS, O, vv) tôn trọng các quy tắc bộ nhớ đệm HTTP đúng cách. Nó sẽ chỉ có thể thất bại khi khách hàng sử dụng một số trình duyệt không rõ ràng. – BalusC

+0

Nhưng có một điều mặc dù, khi nhấp vào nút quay lại trình duyệt, các hộp kiểm bên trong p: datatable được chọn vẫn được chọn, nhưng khi được gửi, chúng thực sự không được chọn. Điều này xảy ra trong google chrome 15, nhưng không xảy ra với firefox 5.0.1. Tôi nghĩ rằng đó là tình huống tương tự như thế này: http://stackoverflow.com/questions/6100741/how-to-prevent-browsers-from-remembering-checkbox-state. Tôi muốn thử sử dụng các tên mẫu ngẫu nhiên như đã nêu trong giải pháp , nhưng im không chắc chắn làm thế nào để làm mới một hình thức bên trong một hình thức trong một trang với nhiều hình thức nếu tôi không biết tên của các hình thức bên ngoài. – bertie

0

Những bất lợi khi vô hiệu hóa bộ nhớ cache của trang là người dùng sẽ thấy trang lỗi trình duyệt nếu anh sử dụng trình duyệt quay lại để điều hướng đến trang trước. Vì vậy, một giải pháp là xác định nếu trang web hiện ra từ máy chủ hoặc từ bộ nhớ cache của trình duyệt sử dụng javascript:

Đầu tiên tạo một bean ủng hộ đơn giản mà phục vụ một id duy nhất (trong trường hợp thời gian hệ thống hiện tại của tôi):

@Named("browserCacheController") 
@RequestScoped 
public class BrowserCacheController implements Serializable { 
private static final long serialVersionUID = 1L; 
/** 
* Returns a unique increasing id for each request 
* @return 
*/ 
public long getCacheID() { 
    return System.currentTimeMillis(); 
} 
} 

Vì vậy, bây giờ bạn có thể kiểm tra xem trang có được phục vụ từ máy chủ hoặc trình duyệt hay không và chuyển hướng người dùng nếu trang hiện tại đến từ bộ nhớ cache của trình duyệt. Xem mã javascript sau đặt vào một trang JSF mà không nên được lưu trữ bởi trình duyệt:

<script type="text/javascript"> 
    // check for latestCacheID 
    if (!isValidCacheID(#{browserCacheController.cacheID})) { 
     //redirect to some page 
     document.location="#{facesContext.externalContext.requestContextPath}/index.jsf"; 
    } 

    // test cacheID if it comes from the server.... 
    function isValidCacheID(currentCacheID) { 
     if (!('localStorage' in window && window['localStorage'] !== null)) 
      return true; // old browsers not supported 
     var latestCacheID=localStorage.getItem("org.imixs.latestCacheID"); 
     if (latestCacheID!=null && currentCacheID<=latestCacheID) { 
      return false; // this was a cached browser page! 
     } 
     // set new id 
     localStorage.setItem("org.imixs.latestCacheID", currentCacheID); 
     return true; 
    } 
</script> 

Các kịch bản cũng có thể được đặt vào facelet để làm cho mã JSF sạch hơn.

+1

Bạn không nên sử dụng POST để điều hướng. – BalusC

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