JSF에서 '바인딩'속성은 어떻게 작동합니까? 언제 어떻게 사용해야합니까?


78

JSF 에는 value속성과 binding속성을 구분하는 많은 자료가 있습니다 .

두 가지 접근 방식이 서로 어떻게 다른지에 관심이 있습니다. 주어진:

public class User {
    private String name;
    private UICommand link;

    // Getters and setters omitted.
}
<h:form>
    <h:commandLink binding="#{user.link}" value="#{user.name}" />
</h:form>

value속성이 지정 될 때 일어나는 일은 매우 간단 합니다. getter가 실행되어 Bean 의 name속성 값 을 반환합니다 User. 값은 HTML 출력으로 인쇄됩니다.

하지만 어떻게 binding작동 하는지 이해할 수 없었습니다 . 생성 된 HTML은 어떻게 bean 의 link속성 과 바인딩을 유지 User합니까?

다음은 수동 미화 및 주석 처리 후 생성 된 출력의 관련 부분입니다 (ID j_id_jsp_1847466274_1가 자동 생성되었으며 두 개의 숨겨진 입력 위젯이 있음에 유의하십시오 ). Sun의 JSF RI 버전 1.2를 사용하고 있습니다.

<form action="/TestJSF/main.jsf" enctype="application/x-www-form-urlencoded"
    id="j_id_jsp_1847466274_1" method="post"  name="j_id_jsp_1847466274_1">
    <input name="j_id_jsp_1847466274_1" type="hidden" value="j_id_jsp_1847466274_1">
    <a href="#" onclick="...">Name</a>
    <input autocomplete="off" id="javax.faces.ViewState" name="javax.faces.ViewState"
        type="hidden" value="-908991273579182886:-7278326187282654551">
</form>

여기에 어디에 binding저장되어 있습니까?

답변:


132

어떻게 작동합니까?

JSF보기 (Facelets / JSP 파일)가 빌드 / 복원되면 JSF 컴포넌트 트리가 생성됩니다. 그 순간 뷰 빌드 시간 , 모든 binding속성이 평가됩니다 ( JSTL과 같은 속성 및 태그 핸들러와 함께id ). 구성 요소 트리에 추가하기 전에 JSF 구성 요소를 만들어야하는 경우 JSF는 binding속성이 미리 생성 된 구성 요소 (예 : non- null)를 반환 하는지 확인한 다음 사용합니다. 미리 생성되지 않은 경우 JSF는 구성 요소를 "일반적인 방법"으로 binding자동 생성하고 자동 생성 된 구성 요소 인스턴스를 인수로 사용하여 속성 뒤에 setter를 호출합니다 .

실제로 구성 요소 트리의 구성 요소 인스턴스 참조를 범위 변수에 바인딩합니다. 이 정보는 구성 요소 자체의 생성 된 HTML 표현에 표시되지 않습니다. 이 정보는 어쨌든 생성 된 HTML 출력과 관련이 없습니다. 양식이 제출되고보기가 복원되면 JSF 구성 요소 트리가 처음부터 다시 작성되고 모든 binding속성이 위 단락에서 설명한대로 다시 평가됩니다. 컴포넌트 트리가 재생성 된 후 JSF는 JSF보기 상태를 컴포넌트 트리로 복원합니다.

구성 요소 인스턴스는 요청 범위입니다!

알고 이해해야 할 중요한 것은 구체적인 구성 요소 인스턴스가 효과적으로 요청 범위가 지정된다는 것입니다. 모든 요청에 ​​대해 새로 생성되며 해당 속성은 복원보기 단계 동안 JSF보기 상태의 값으로 채워집니다. 따라서 구성 요소를 지원 빈의 속성에 바인딩하는 경우 지원 빈은 절대적으로 요청 범위보다 더 넓은 범위에 있지 않아야 합니다. JSF 2.0 사양 3.1.5 장을 참조하십시오 .

3.1.5 구성 요소 바인딩

...

컴포넌트 바인딩은 종종 Managed Bean 생성 기능을 통해 동적으로 인스턴스화되는 JavaBeans와 함께 사용됩니다 (섹션 5.8.1“VariableResolver 및 기본 VariableResolver”참조). 응용 프로그램 개발자는 "요청"범위에서 구성 요소 바인딩식이 가리키는 관리 빈을 배치하는 것이 좋습니다. 이는 UIComponent 인스턴스가 단일 스레드 내부에서 실행되는 것에 의존하기 때문에 세션 또는 응용 프로그램 범위에 배치하려면 스레드 안전성이 필요하기 때문입니다. 구성 요소 바인딩을 "세션"범위에 배치 할 때 메모리 관리에 잠재적으로 부정적인 영향을 미칠 수도 있습니다.

그렇지 않으면 구성 요소 인스턴스가 여러 요청간에 공유 되어 뷰에 선언 된 유효성 검사기, 변환기 및 리스너가 이전 요청의 기존 구성 요소 인스턴스에 다시 연결되기 때문에 " 중복 구성 요소 ID "오류 및 "이상한"동작이 발생할 수 있습니다. 증상은 명확합니다. 구성 요소가 바인드 된 것과 동일한 범위 내에서 각 요청에 대해 한 번 더 여러 번 실행됩니다.

그리고 과부하 상태에서 (즉, 여러 다른 HTTP 요청 (스레드)이 동시에 매우 동일한 구성 요소 인스턴스에 액세스하고 조작하는 경우) 조만간 UIComponent.popComponentFromEL 또는 Java 스레드 에서 스레드가 멈춤 과 함께 애플리케이션 충돌에 직면 할 수 있습니다. Richfaces UIDataAdaptorBase 및 내부 HashMap 을 사용하거나 JSF가 뷰 상태 (예 : 스택 추적 표시 또는 메서드 등)를 저장하거나 복원하는 동안 JSF 구현 소스 코드에서 "이상한" IndexOutOfBoundsException또는 ConcurrentModificationException직접 오는 100 % CPU 사용률 .saveState()restoreState()

binding빈 속성에 사용 하는 것은 나쁜 습관입니다.

어쨌든 binding이 방법을 사용 하면 요청 범위 빈에서도 전체 구성 요소 인스턴스를 빈 속성에 바인딩하는 것은 JSF 2.xa에서 매우 드문 사용 사례이며 일반적으로 모범 사례가 아닙니다. 디자인 냄새를 나타냅니다. 당신은 일반적으로보기 측에서 구성 요소를 선언하고 바인드 자신의 런타임과 같은 속성 value, 그리고 아마도 다른 사람들이 좋아하는 styleClass, disabled, rendered일반 콩 속성 등. 그런 다음 전체 구성 요소를 잡고 속성과 관련된 setter 메서드를 호출하는 대신 원하는 빈 속성을 정확하게 조작합니다.

구성 요소의 요구가 "동적으로 작성"할 때의 경우 정적 모델을 기반으로 더 나은 사용하는 것입니다 JSTL처럼보기 빌드시 태그를 필요한 경우에, 태그 파일 대신에, createComponent(), new SomeComponent(), getChildren().add()어떤이 없습니다. 이전 JSP의 스 니펫을 JSF와 동등한 것으로 리팩터링하는 방법 도 참조하십시오 .

구성 요소의 요구가 "동적으로 렌더링"하는 경우 또는 동적 모델을 기반으로, 다음 그냥 사용 반복자 구성 요소를 ( <ui:repeat>, <h:dataTable>, 등). JSF 구성 요소를 동적으로 추가하는 방법 도 참조하십시오 .

복합 구성 요소는 완전히 다른 이야기입니다. 내부의 구성 요소 <cc:implementation>를 백업 구성 요소 (예 :으로 식별되는 구성 요소) 에 바인딩하는 것은 완전히 합법적 <cc:interface componentType>입니다. f : convertDateTime을 사용하여 시간과 분을 나타내는 두 개의 h : inputText 필드에 대한 ao Split java.util.Date 및 다음 을 사용하여 동적 목록을 구현하는 방법을 참조하십시오. JSF 2.0 복합 구성 요소?

binding로컬 범위 에서만 사용

그러나 때로는 특정 구성 요소 내부에서 다른 구성 요소의 상태에 대해 알고 싶을 때가 있습니다. 작업 / 값 종속 유효성 검사와 관련된 사용 사례에서 더 자주 알 수 있습니다. 이를 위해 binding속성을 사용할 수 있지만 빈 속성과 함께 사용할 수는 없습니다 . 로컬 EL 범위에서 고유 변수 이름을 이와 같이 binding속성에 지정할 수 있으며 binding="#{foo}"구성 요소는에서 UIComponent사용할 수있는 참조로 직접 동일한 뷰의 다른 위치에서 렌더링 응답 중에 있습니다 #{foo}. 다음은 이러한 솔루션이 답변에 사용 된 몇 가지 관련 질문입니다.

또한보십시오:


사용자를 요청 범위 빈으로 설정했습니다. 그리고 getlink 및 setlink 메소드에서 sysout을 시도했습니다. 페이지 방문시 = User.User(), User.getLink(), User.setLink(), User.getValue()링크를 클릭 할 때 =User.User(), User.setLink()...
John

setLink ()가 다시 호출되고 이미 하나가있는 경우 다른 UICommand 객체가 생성되는 이유는 무엇입니까?
John

"[...]를 바인드하면 백킹 빈은 절대적으로 요청 범위보다 더 넓은 범위에 있지 않아야합니다." JSF 2.2에서도 여전히 사실입니까? getChildren (). addAll (...)을 사용하여 페이지에 구성 요소를 프로그래밍 방식으로 포함해야하는 경우 가장 좋은 옵션은 무엇입니까?
RinaldoPJr 2014-06-18

@Rinaldo : JSTL을 사용하여 XML 구문만으로보기를 프로그래밍 방식으로 빌드합니다.
BalusC 2014-06-18

1
@Shirgill : 그렇습니다. UIViewRoot( UIComponent기본적으로 모두 ) 어쨌든 직렬화 불가능합니다.
BalusC 2016

1

각 JSF 구성 요소는 자신을 HTML로 렌더링하고 생성하는 HTML을 완벽하게 제어합니다. JSF에서 사용할 수있는 많은 트릭이 있으며, 이러한 트릭 중 정확히 어떤 트릭을 사용할지는 사용중인 JSF 구현에 따라 다릅니다.

  • 모든 입력 입력에 완전히 고유 한 이름이 있는지 확인하여 양식을 렌더링 한 구성 요소 트리로 다시 제출할 때 각 구성 요소가 값 양식을 읽을 수있는 위치를 쉽게 알 수 있습니다.
  • JSF 구성 요소는 서버에 다시 제출하는 javascript를 생성 할 수 있으며 생성 된 javascript는 구성 요소에 의해 생성 되었기 때문에 각 구성 요소가 바인딩 된 위치도 알고 있습니다.
  • hlink와 같은 경우에는 쿼리 매개 변수 또는 URL 자체의 일부 또는 matrx 매개 변수로 url에 바인딩 정보를 포함 할 수 있습니다. 예를 들어.

    http:..../somelink?componentId=123jsf가 구성 요소 트리에서 링크 123이 클릭되었음을 확인하도록 허용합니다. 또는 전자 수htp:..../jsf;LinkId=123

이 질문에 답하는 가장 쉬운 방법은 링크가 하나만있는 JSF 페이지를 만든 다음 생성되는 html 출력을 검사하는 것입니다. 이렇게하면 사용중인 JSF 버전을 사용하여 이것이 어떻게 발생하는지 정확히 알 수 있습니다.


난 단지, 서버 측에서 동적으로 구성 요소를 생성하는 것처럼 모든 속성을 설정할 때 바인딩 구성 요소를 사용한 적이 있다는 말을 action하고 value, 다음 JSF 프레임 워크는 자신의 작업을 할 수 있습니다.
Luiggi Mendoza

나는 user응용 프로그램 범위 관리 빈으로 저장 했고 링크를 클릭 할 때마다 두 번째 숫자 만 value="-908991273579182886:-7278326187282654551"변경되고 다른 모든 것은 동일합니다. 이것들이 어떤 마법을하는지 궁금합니다.
John
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.