2014-04-30 3 views
3

여기에 우리는 PrimeFaces를 사용하고 Tomcat 7에서 실행되는 JSF 애플리케이션이 있으며 모든 관리 Bean은 ViewScoped이며 매우 복잡한 구조를 가지고 있습니다. 최근 우리는 다음 요구 사항을 구현하도록 요청 받았습니다. 사용자간에 공유 할 수있는 URL을 생성합니다. 링크를 클릭하면보기가 링크가 생성되었을 때 이전에 저장된 것과 동일한 상태로 복원됩니다.JSF 저장/복원 뷰 상태

일반적으로 내 생각은 위상 리스너를 구현하고 그에 따라 viewRoot 객체에서 saveState/restoreState를 호출하는 것입니다. URL이 생성 될 때까지는 phaseListener가 saveState를 호출하여 UIViewRoot 상태를 가져온 다음 개체를 serialize하고 데이터베이스 테이블에 유지합니다. 링크가 액세스되면 개체가 데이터베이스에서 검색되고 deserialized되고 restoreState를 호출하여 UIViewRoot에 복원 될 때 반대가 발생합니다.

상태 복원을 시도 할 때 UIViewRoot에서 restoreState를 호출 한 후 관리 Bean 속성이 null이므로 실제 결과가 예상 한 것과 다릅니다.

렌더 단계가 완료된 후 saveState가 호출되고 모든 값이 올바르게 설정 되었기 때문에 직렬화 가능 객체가 좋아 보인다. restoreState는 "restore view"단계에서 호출되고 있으며, restoreState가 호출 된 시간에 대한 많은 조합을 시도해 왔지만 아무 것도 작동하지 않는 것으로 보입니다.

테스트 목적으로 PhaseListener에 메소드를 구현했습니다. 여기에 코드 조각의 그들을 호출하는 논리는 생략 : 그래서,

private void saveState(FacesContext context) { 
    UIViewRoot viewRoot = context.getViewRoot();  
    Object savedState = viewRoot.saveState(context); 
    if(savedState instanceof Serializable) { 
     Serializable s = ((Serializable) savedState); 

     try { 
      this.serialize(s); 
     } catch (IOException e) { 
      logger.error("Error saving state.", e); 
     } 
    } 
} 

private void restoreState(FacesContext context) { 
    UIViewRoot viewRoot = new UIViewRoot(); 
    FileInputStream fis; 

    try { 
     fis = new FileInputStream("/view.ser"); 
     Serializable savedState = this.deserialize(fis); 

     viewRoot.restoreState(context, savedState); 

    } catch (ClassNotFoundException | IOException e) { 
     logger.error("Error restoring state.", e); 
    } 
} 

나는 JSF 전문가가 아니에요 내가 사용하는 노력하고있어 접근 방식은 전혀 의미가 경우에 따라서 잘 모르겠어요 JSF gurus :이 요구 사항을 어떻게 든 구현할 수 있습니까? 그렇다면이를 구현하는 올바른 방법은 무엇입니까? 나는 포럼을 연구했고 내가 재사용 할 수있는 비슷한 것을 찾을 수 없다.

도움이 될 것입니다. 미리 감사드립니다.

UPDATE는 :

이것은 우리가 저장하고 뷰 상태를 복원하는 관리 방법이다.

뷰 상태가 저장되고 있으며 웹 빈에서 직렬화 :

이 상태를 복원하기 위해
private void saveViewState(FacesContext context) throws IOException { 
    UIViewRoot viewRoot = context.getViewRoot(); 
    Object savedState = viewRoot.saveState(context); 
    ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
    ObjectOutputStream oos = new ObjectOutputStream(baos); 
    oos.writeObject(savedState); 
} 

, 위상 리스너가 얼굴이보기 단계 복원 뷰 상태 개체를 역 직렬화 전에 요청 차단 및 UIViewRootrestoreState를 호출

private void restoreState(FacesContext context) { 

    // details omitted 
    ByteArrayInputStream bais = new ByteArrayInputStream(data); 
    ObjectInputStream ois = new ObjectInputStream(bais); 

    Serializable viewState = (Serializable) ois.readObject(); 

    UIViewRoot viewRoot = new UIViewRoot(); 
    viewRoot.restoreState(context, viewState); 
    viewRoot.setRenderKitId(RenderKitFactory.HTML_BASIC_RENDER_KIT); 
    viewRoot.setViewId(savedView.getViewId()); 
    context.setViewRoot(viewRoot); 
    context.renderResponse(); 
} 

답변

3

권장되는 방법은 JSF 사양에 따라 저장하면 StateManager 구성 요소를 통해입니다 상태로. 이것은 JSF 런타임이 자체 상태 저장 조작에서 사용하는 것과 동일한 구성 요소입니다. UIViewRoot#saveState이 유사한 결과를 제공 할 수 있지만 StateManager 및 그 편리한 방법은 사양에서 요구하는 보증을 제공합니다.

  • 응용 프로그램과 관련된 StateManager에 대한 참조를 얻 뷰 상태

    1. 을 저장하려면 :

      FacesContext ctx = FacesContext.getCurrentInstance(); 
      StateManager stateManager = ctx.getApplication().getStateManager(); 
      
    2. 사용 중

      을 수행합니다. Object viewState = stateManager.saveView(ctx);

      b. getViewState 편리한 방법은

      String viewState stateManager.getViewState(ctx); 
      
  • 뷰의 상태

    UIViewRoot restoredView = stateManager.writeState(ctx,viewState); 
    
+0

감사를 복원합니다. StateManager 접근법을 사용하는 것은 실제로 좋은 것처럼 보이지만 저장/복원이 올바른 라이프 사이클 단계에서 수행되지 않기 때문에 여전히 뷰 상태를 복원하는 데 문제가 있습니다. 뷰 단계를 복원하기 전에 writeState를 시도하고 있습니다.이 경우 renderKitId가 null이므로 결과적으로 NPE가 발생합니다. ResponseWriter가 null이므로 writeViewStateField (FacesContext facesContext, ResponseWriter, responseWriter, Object savedState)가 호출 될 때 복원 단계 이후에 writeState를 호출하면 NPE가 발생합니다. – TheRodSouza

+0

@TheRodSouza, 그렇다면 라이프 사이클에서 writeState 메서드를 호출하는 위치를 파악 했습니까? 나는 똑같은 문제를 안고 붙어있다. 감사합니다 –

+2

@Lev Stefanovich 지연에 대해 유감스럽게 생각합니다. 구현한지 오래되었습니다. 실제로 요구 사항은보기의 현재보기 상태를 저장하여 다른 사용자와 페이지의 링크를 공유하는 것입니다. 액션은 context.getViewRoot()와 viewRoot.saveState (context)를 통해 뷰 루트를 얻는 웹 빈의 메소드에 의해 수행된다. 그런 다음 저장된 상태 객체가 반환되고 직렬화되며 지속됩니다. 복원 절차는 RESTORE_VIEW 단계에서 수행됩니다. 희망이 도움이됩니다. – TheRodSouza