데이터베이스에서 h : selectOneMenu 옵션을 채우는 방법은 무엇입니까?
DB에서 모든 애플리케이션을 작성 <h:selectOneMenu>
합니다. 제출 코딩 할 수 없습니다. 어떤 사람이 어떻게하는지 보여줄 수 있습니까?
List<User>
DB에서 얻는 방법을 알고 있습니다. 내가 알아야 할 것은 목록을 <h:selectOneMenu>
.
<h:selectOneMenu value="#{bean.name}">
...?
</h:selectOneMenu>
질문 기록을 기반으로 JSF 2.x를 사용하고 있습니다. 그래서 여기에 JSF 2.x 대상 답변이 있습니다. JSF 1.x에서는 추악한 인스턴스 에서 항목 값 / 레이블을 래핑해야 합니다. 더 이상 JSF 2.x에서는 더 이상 필요하지 않습니다.SelectItem
기본 예
귀하의 질문에 직접 답한 비용 의 (사후) 구성 중에 DB에서 보존 하는 속성에 대한 포인트를 사용 합니다. 다음은 실제로 .<f:selectItems>
value
List<T>
T
String
<h:selectOneMenu value="#{bean.name}">
<f:selectItems value="#{bean.names}" />
</h:selectOneMenu>
와
@ManagedBean
@RequestScoped
public class Bean {
private String name;
private List<String> names;
@EJB
private NameService nameService;
@PostConstruct
public void init() {
names = nameService.list();
}
// ... (getters, setters, etc)
}
그렇게 간단합니다. 실제로 T
의 toString()
는 드롭 다운 항목 레이블과 값을 모두 나타내는 데 사용됩니다 . 복잡한 List<String>
객체 목록 을 사용하는 대신 List<SomeEntity>
클래스의 메소드 toString()
를 재정의하지 않은 경우 com.example.SomeEntity@hashcode
항목 값으로 볼 수 있습니다. 제대로 해결하는 방법은 다음 섹션을 참조하십시오.
또한 <f:selectItems>
값에 대한 Bean 이 반드시 값에 대한 Bean과 동일한 Bean 일 필요는 없습니다 <h:selectOneMenu>
. 이 때 값이 실제로 응용 프로그램을 시작하는 동안 번만로드하면되는 응용 프로그램 전체 상수 일 유용합니다. 그런 다음 응용 프로그램 범위 빈의 속성으로 만들 수 있습니다.
<h:selectOneMenu value="#{bean.name}">
<f:selectItems value="#{data.names}" />
</h:selectOneMenu>
사용 가능한 항목으로 복잡한 개체
때마다 T
같은 복잡한 복잡한 (자바 빈즈), User
가지고있는 String
재산은 name
, 당신이 사용할 수있는 var
당신 차례가에서 사용할 수있는 반복 변수의 보류 속성 itemValue
및 / 또는 itemLabel
생략하면 (attribtues을 itemLabel
한 라벨 후은 값과 동일하게 됩니다).
예 1 :
<h:selectOneMenu value="#{bean.userName}">
<f:selectItems value="#{bean.users}" var="user" itemValue="#{user.name}" />
</h:selectOneMenu>
와
private String userName;
private List<User> users;
@EJB
private UserService userService;
@PostConstruct
public void init() {
users = userService.list();
}
// ... (getters, setters, etc)
또는 항목 값으로 설정하려는 Long
속성이 id
있는 경우 :
예 2 :
<h:selectOneMenu value="#{bean.userId}">
<f:selectItems value="#{bean.users}" var="user" itemValue="#{user.id}" itemLabel="#{user.name}" />
</h:selectOneMenu>
와
private Long userId;
private List<User> users;
// ... (the same as in previous bean example)
선택한 항목으로 복잡한 개체
당신이로 설정하고자 할 때마다 T
뿐만 아니라 콩의 재산과을 T
나타냅니다. User
, 당신은 사용자 정의를 구울 필요가 있는 사이의 변환 및합니다 (할 수있는 고유 한 소유의 표현 속성). (가) 수행 할 복잡한 객체 자체, 선택 구성 요소의로 설정이 필요가 정확히 유형을 표시해야합니다 .Converter
User
id
itemValue
value
<h:selectOneMenu value="#{bean.user}" converter="#{userConverter}">
<f:selectItems value="#{bean.users}" var="user" itemValue="#{user}" itemLabel="#{user.name}" />
</h:selectOneMenu>
와
private User user;
private List<User> users;
// ... (the same as in previous bean example)
과
@ManagedBean
@RequestScoped
public class UserConverter implements Converter {
@EJB
private UserService userService;
@Override
public Object getAsObject(FacesContext context, UIComponent component, String submittedValue) {
if (submittedValue == null || submittedValue.isEmpty()) {
return null;
}
try {
return userService.find(Long.valueOf(submittedValue));
} catch (NumberFormatException e) {
throw new ConverterException(new FacesMessage(String.format("%s is not a valid User ID", submittedValue)), e);
}
}
@Override
public String getAsString(FacesContext context, UIComponent component, Object modelValue) {
if (modelValue == null) {
return "";
}
if (modelValue instanceof User) {
return String.valueOf(((User) modelValue).getId());
} else {
throw new ConverterException(new FacesMessage(String.format("%s is not a valid User", modelValue)), e);
}
}
}
(참고가있는 것이 Converter
를 사용 가능하게하기 위해 비트 해키 @EJB
JSF의 제출은 일반적으로 사람은 그것을 사용하여 주석 것 @FacesConverter(forClass=User.class)
, 하지만 불행히도 사용 @EJB
가능합니다 )
복잡한 object-클래스 확인는 것을 확인하는 것을 잊지 마세요 equals()
과 hashCode()
제대로 구현 , 그렇지 않으면 JSF는 동안 미리 선택된 항목 (들)을 표시하지 렌더링, 당신의 얼굴들 그리고을 제출하는을 구석으로입니다 검증 오류 : 값이 유효하지 않습니다 .
public class User {
private Long id;
@Override
public boolean equals(Object other) {
return (other != null && getClass() == other.getClass() && id != null)
? id.equals(((User) other).id)
: (other == this);
}
@Override
public int hashCode() {
return (id != null)
? (getClass().hashCode() + id.hashCode())
: super.hashCode();
}
}
일반 변환기가있는 복잡한 개체
이 답변으로 이동하십시오 : Java Generics를 사용하여 다수의 변환기를 구현하십시오 .
사용자 지정 변환기가없는 복잡한 개체
JSF 유틸리티 라이브러리 OmniFaces 는 <h:selectOneMenu>
사용자 정의 변환기를 만들 필요없이 복잡한 개체를 사용할 수있는 특별한 변환기를 제공합니다 . 는 에서 쉽게 사용할 수있는 항목을 기반으로 변환을 수행합니다 .SelectItemsConverter
<f:selectItem(s)>
<h:selectOneMenu value="#{bean.user}" converter="omnifaces.SelectItemsConverter">
<f:selectItems value="#{bean.users}" var="user" itemValue="#{user}" itemLabel="#{user.name}" />
</h:selectOneMenu>
또한,
페이지보기
<h:selectOneMenu id="selectOneCB" value="#{page.selectedName}">
<f:selectItems value="#{page.names}"/>
</h:selectOneMenu>
백킹 빈
List<SelectItem> names = new ArrayList<SelectItem>();
//-- Populate list from database
names.add(new SelectItem(valueObject,"label"));
//-- setter/getter accessor methods for list
선택한 특정 레코드를 표시 목록에있는 값 중 하나 택합니다.
선택한 항목으로 복잡한 개체를위한 롤-자신의 일반 변환기
Balusc는이 주제에 대한 매우 유용한 개요 답변을 제공합니다. 그러나 그가 제시하지 않은 대안이 하나 있습니다. 선택한 항목으로 복잡한 개체를 처리하는 Roll-your-own 일반 변환기입니다. 모든 경우에 처리 비용이 매우 복잡하지만 간단한 경우에는 매우 간단합니다.
아래 코드에는 현재 변환기의 예가 포함되어 있습니다. 개체 를 포함 하는 구성 요소의 자식을 살펴볼 때 OmniFaces SelectItemsConverter 와 동일한 방식으로 작동 UISelectItem(s)
합니다. 차이점은 엔터티 개체의 단순 컬렉션이나 단순화에 대한 바인딩 만 처리한다는 것입니다. 항목 그룹, 컬렉션 SelectItem
, 배열 및 기타 많은 것을 처리하지 않습니다 .
가 바인딩하는 컴포넌트 엔티티는 IdObject
인터페이스 를 구현해야 우리합니다 . (이는 사용하는 것과 같은 다른 방법으로 사용할 수 있습니다 toString
.)
는 엔티티 equals
동일한 ID 가진 두 엔티티를가 동일하게 비교되는 방식으로 구현해야 우리합니다 .
하나를 사용하기 위해 수행하는 유일한 작업은 수행해야하는 구성 요소에서 변환기로 지정하고 수행해야 할 속성 목록에 바인딩하는 것입니다.
<h:selectOneMenu value="#{bean.user}" converter="selectListConverter">
<f:selectItem itemValue="unselected" itemLabel="Select user..."/>
<f:selectItem itemValue="empty" itemLabel="No user"/>
<f:selectItems value="#{bean.users}" var="user" itemValue="#{user}" itemLabel="#{user.name}" />
</h:selectOneMenu>
변환기 :
/**
* A converter for select components (those that have select items as children).
*
* It convertes the selected value string into one of its element entities, thus allowing
* binding to complex objects.
*
* It only handles simple uses of select components, in which the value is a simple list of
* entities. No ItemGroups, arrays or other kinds of values.
*
* Items it binds to can be strings or implementations of the {@link IdObject} interface.
*/
@FacesConverter("selectListConverter")
public class SelectListConverter implements Converter {
public static interface IdObject {
public String getDisplayId();
}
@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (value == null || value.isEmpty()) {
return null;
}
return component.getChildren().stream()
.flatMap(child -> getEntriesOfItem(child))
.filter(o -> value.equals(o instanceof IdObject ? ((IdObject) o).getDisplayId() : o))
.findAny().orElse(null);
}
/**
* Gets the values stored in a {@link UISelectItem} or a {@link UISelectItems}.
* For other components returns an empty stream.
*/
private Stream<?> getEntriesOfItem(UIComponent child) {
if (child instanceof UISelectItem) {
UISelectItem item = (UISelectItem) child;
if (!item.isNoSelectionOption()) {
return Stream.of(item.getValue());
}
} else if (child instanceof UISelectItems) {
Object value = ((UISelectItems) child).getValue();
if (value instanceof Collection) {
return ((Collection<?>) value).stream();
} else {
throw new IllegalStateException("Unsupported value of UISelectItems: " + value);
}
}
return Stream.empty();
}
@Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value == null) return null;
if (value instanceof String) return (String) value;
if (value instanceof IdObject) return ((IdObject) value).getDisplayId();
throw new IllegalArgumentException("Unexpected value type");
}
}
나는 다음과 같이하고있다.
모델은 ViewScoped입니다.
변환기 :
@Named @ViewScoped public class ViewScopedFacesConverter implements Converter, Serializable { private static final long serialVersionUID = 1L; private Map<String, Object> converterMap; @PostConstruct void postConstruct(){ converterMap = new HashMap<>(); } @Override public String getAsString(FacesContext context, UIComponent component, Object object) { String selectItemValue = String.valueOf( object.hashCode() ); converterMap.put( selectItemValue, object ); return selectItemValue; } @Override public Object getAsObject(FacesContext context, UIComponent component, String selectItemValue){ return converterMap.get(selectItemValue); } }
다음으로 구성 요소에 바인딩합니다.
<f:converter binding="#{viewScopedFacesConverter}" />
hashCode 대신 ID를 사용하면 충돌이 저장됩니다. 동일한 ID를 가진 다른 경우 (클래스)에 대해 한 페이지에 목록이 거의없는 경우
게으르다 고 부르지 만 변환기 코딩은 불필요한 작업이 많은 것 같습니다. 저는 Primefaces를 사용하고 있으며 이전에 일반 바닐라 JSF2 목록 상자 또는 드롭 다운 메뉴를 사용하지 않았으며 위젯이 복잡한 개체를 처리 할 수 있다고 가정했습니다 (게으른 상태). 즉 선택한 개체를있는 그대로 해당 getter / setter에 전달합니다. 다른 많은 위젯이 있습니다. 변환기 없이는이 위젯 유형에 대해이 기능이 존재하지 않는다는 사실을 알게되어 실망했습니다. 실제로 String 대신 복잡한 객체에 setter를 제공하면 조용히 실패하고 (단순하게 setter를 호출하지 않고 예외도, JS 오류도 없음) BalusC의 우수한 문제 해결 도구를 사용 하는 데 많은 시간을 보냈습니다.그 제안이 적용되지 않았기 때문에 원인을 찾을 수 없습니다. 내 결론 : 목록 상자 / 메뉴 위젯은 다른 JSF2 위젯이하지 않는 조정이 필요합니다. 이것은 오해의 소지가 있고 저와 같은 정보가없는 개발자를 토끼 구멍으로 이끌 기 쉽습니다.
결국 나는 변환기 코딩에 저항했고 시행 착오를 통해 위젯 값을 복잡한 객체로 설정하면 다음과 같은 사실을 발견했습니다.
<p:selectOneListbox id="adminEvents" value="#{testBean.selectedEvent}">
... 사용자가 항목을 선택하면 위젯은 해당 객체에 대한 String setter를 호출 할 수 있습니다 (예 setSelectedThing(String thingString) {...}
:). 전달 된 문자열은 Thing 객체를 나타내는 JSON 문자열입니다. 어떤 개체가 선택되었는지 확인하기 위해 구문 분석 할 수 있습니다. 이것은 해킹처럼 느껴지지만 변환기보다는 해킹이 적습니다.
참고 URL : https://stackoverflow.com/questions/6848970/how-to-populate-options-of-hselectonemenu-from-database
'ProgramingTip' 카테고리의 다른 글
일치를 기반으로 열 선택 -dplyr :: select (0) | 2020.11.03 |
---|---|
mockito 구입 및 인수 값 가져 오기 (0) | 2020.11.03 |
Coffeescript의 조건부 연산자 (0) | 2020.11.03 |
몇 초 후 MessageBoxClose (0) | 2020.11.03 |
ProGuard : 참조 된 클래스 com.google.android.gms.R을 사용할 수 없습니다. (0) | 2020.11.03 |