여기에 우리는 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);
}
, 위상 리스너가 얼굴이보기 단계 복원 뷰 상태 개체를 역 직렬화 전에 요청 차단 및 UIViewRoot
에 restoreState
를 호출
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();
}
감사를 복원합니다. StateManager 접근법을 사용하는 것은 실제로 좋은 것처럼 보이지만 저장/복원이 올바른 라이프 사이클 단계에서 수행되지 않기 때문에 여전히 뷰 상태를 복원하는 데 문제가 있습니다. 뷰 단계를 복원하기 전에 writeState를 시도하고 있습니다.이 경우 renderKitId가 null이므로 결과적으로 NPE가 발생합니다. ResponseWriter가 null이므로 writeViewStateField (FacesContext facesContext, ResponseWriter, responseWriter, Object savedState)가 호출 될 때 복원 단계 이후에 writeState를 호출하면 NPE가 발생합니다. – TheRodSouza
@TheRodSouza, 그렇다면 라이프 사이클에서 writeState 메서드를 호출하는 위치를 파악 했습니까? 나는 똑같은 문제를 안고 붙어있다. 감사합니다 –
@Lev Stefanovich 지연에 대해 유감스럽게 생각합니다. 구현한지 오래되었습니다. 실제로 요구 사항은보기의 현재보기 상태를 저장하여 다른 사용자와 페이지의 링크를 공유하는 것입니다. 액션은 context.getViewRoot()와 viewRoot.saveState (context)를 통해 뷰 루트를 얻는 웹 빈의 메소드에 의해 수행된다. 그런 다음 저장된 상태 객체가 반환되고 직렬화되며 지속됩니다. 복원 절차는 RESTORE_VIEW 단계에서 수행됩니다. 희망이 도움이됩니다. – TheRodSouza