У меня есть объект данных с именем DeliveryPeriod
, который является контейнером для начальной и конечной даты (сохраняется как String
как dd.MM.yyy, приходит из базы данных) и идентификатором другого объекта с именем PlanningPeriod
. Этот период доставки должен отображаться в его собственном пользовательском компоненте в формате JSF, например
<myc:deliveryPeriodComponent value="#{backendBean.deliveryPeriod}" />
Я реализую класс DeliveryPeriodComponent
, который расширяет UIInput
и DeliveryPeriodComponentRenderer
, который extendes javax.faces.renderer
. Рендеринг работает хорошо, я вижу два элемента календаря и SelectOneMenu, чтобы выбрать период планирования. Но рендеринг данных это еще не все, мне тоже нужно изменить данные. И тут возникает проблема, я понятия не имею, чтобы передать данные внутри моего компонента в бэкэнд-компонент. Метод decode()
не знает новых значений, а другие методы никогда не вызываются. Я не знал хитрости, как связать страницу JSF с бином, из учебника (http://jsfatwork.irian.at, я купил книгу) у меня были такие методы, как getValue()
и getConverter()
.
Вот код из компонента:
public class DeliveryPeriodComponent extends UIInput {
public static final String COMPONENT_TYPE = "de.hacon.tps.integrator.web.component.deliveryperiod.DeliveryPeriodComponent";
enum PropertyKeys {
begin, end, planningPeriod
}
public DeliveryPeriodComponent() {
setRendererType("de.hacon.tps.integrator.web.component.deliveryperiod.DeliveryPeriodComponent");
}
public String getBegin() {
return (String) getStateHelper().eval(PropertyKeys.begin, "01.01.2012");
}
public void setBegin(String begin) {
getStateHelper().put(PropertyKeys.begin, begin);
}
public String getEnd() {
return (String) getStateHelper().eval(PropertyKeys.end, "31.12.2012");
}
public void setEnd(String end) {
getStateHelper().put(PropertyKeys.end, end);
}
public int getPlanningPeriod() {
return (Integer) getStateHelper().eval(PropertyKeys.planningPeriod, 0);
}
public void setPlanningPeriod(int planningPeriod) {
getStateHelper().put(PropertyKeys.planningPeriod, planningPeriod);
}}
А вот и рендер:
открытый класс DeliveryPeriodComponentRenderer расширяет Renderer {
SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy");
@Override
public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
DeliveryPeriodComponent comp = (DeliveryPeriodComponent) component;
String clientId = comp.getId();
try {
encodeInput(context, comp, clientId);
} catch (ParseException e) {
e.printStackTrace();
}
}
private void encodeInput(FacesContext context, DeliveryPeriodComponent comp, String clientId) throws ParseException {
comp.getChildren().clear();
DeliveryPeriod value = (DeliveryPeriod) comp.getAttributes().get("value");
List<PlanningPeriodSubset> pp = (List<PlanningPeriodSubset>) comp.getAttributes().get("periods");
HtmlPanelGrid pGrid = new HtmlPanelGrid();
pGrid.setColumns(4);
Calendar cBegin = new Calendar();
cBegin.setShowOn("button");
cBegin.setValue(sdf.parse(value.getStartDate()));
cBegin.setPattern("dd.MM.yyyy");
pGrid.getChildren().add(cBegin);
Calendar cEnd = new Calendar();
cEnd.setShowOn("button");
cEnd.setValue(sdf.parse(value.getEndDate()));
cEnd.setPattern("dd.MM.yyyy");
pGrid.getChildren().add(cEnd);
HtmlSelectOneMenu sPlanningPeriod = new HtmlSelectOneMenu();
Collection<UISelectItem> items = new ArrayList<UISelectItem>();
for (PlanningPeriodSubset op : pp) {
UISelectItem item = new UISelectItem();
item.setItemLabel(op.getName());
item.setItemValue(op.getId());
items.add(item);
}
sPlanningPeriod.getChildren().addAll(items);
sPlanningPeriod.setValue(value.getPlanningPeriodId());
pGrid.getChildren().add(sPlanningPeriod);
HtmlPanelGrid buttonPanel = new HtmlPanelGrid();
buttonPanel.setColumns(2);
Button bDelete = new Button();
bDelete.setValue(" - ");
buttonPanel.getChildren().add(bDelete);
Button bInfo = new Button();
bInfo.setValue(" i ");
buttonPanel.getChildren().add(bInfo);
pGrid.getChildren().add(buttonPanel);
comp.getChildren().add(pGrid);
}
@Override
public void decode(FacesContext context, UIComponent component) {
DeliveryPeriodComponent deliveryComponent = (DeliveryPeriodComponent) component;
DeliveryPeriod deliveryPeriod = new DeliveryPeriod();
deliveryPeriod.setStartDate(deliveryComponent.getBegin());
deliveryPeriod.setEndDate(deliveryComponent.getEnd());
deliveryPeriod.setPlanningPeriodId(deliveryComponent.getPlanningPeriod());
// Map<String, String> params = context.getExternalContext().getRequestParameterMap();
// String clientId = component.getClientId();
// String value = params.get(clientId);
// ((UIInput) component).setSubmittedValue(value);
}
@Override
public Object getConvertedValue(FacesContext context, UIComponent component, Object submittedValue)
throws ConverterException {
Converter converter = getConverter(context, (DeliveryPeriodComponent) component);
if (converter != null) {
return converter.getAsObject(context, component, (String) submittedValue);
} else {
return submittedValue;
}
}
private Object getValue(FacesContext context, DeliveryPeriodComponent comp) {
Object submittedValue = comp.getSubmittedValue();
if (submittedValue != null) {
return submittedValue;
}
Object begin = comp.getBegin();
Object end = comp.getEnd();
Object planningPeriod = comp.getPlanningPeriod();
DeliveryPeriod period = new DeliveryPeriod();
period.setStartDate((String) begin);
period.setEndDate((String) end);
period.setPlanningPeriodId((Integer) planningPeriod);
Converter converter = this.getConverter(context, comp);
if (converter != null) {
return converter.getAsString(context, comp, period);
} else if (period != null) {
return period.toString();
} else {
return "";
}
}
private Converter getConverter(FacesContext context, DeliveryPeriodComponent comp) {
Converter conv = ((UIInput) comp).getConverter();
if (conv != null) {
ValueExpression exp = comp.getValueExpression("value");
if (exp == null) {
return null;
} else {
Class valueType = exp.getType(context.getELContext());
if (valueType == null) {
return null;
} else {
return context.getApplication().createConverter(valueType);
}
}
}
return null;
}}
Может быть, это тривиальная проблема, я не профессионал в JSF и все еще учусь. И очень сложно писать свои собственные компоненты, когда вы почти не понимаете основ :-( Все еще изучаете новые вещи каждый день. Спасибо за вашу помощь!
(Я нашел много пользовательских компонентов с примерами, такими как поля ввода custum, эти компоненты хорошо работают и передают свои данные. К сожалению, я ничего не нашел в пользовательских компонентах, которые содержат более одного поля ввода или сделали что-то отличное от существующих элементов JSF )