Подтвердить что ты не робот

Пользовательский конвертер в JSF 2 с аргументами

Я пытаюсь реализовать настраиваемый конвертер truncate, который обрезает строку с заданным индексом и добавляет символ продолжения. Преобразователь работает нормально, только когда я жестко программирую параметры, так как они не передаются на бэкэнд. Что я делаю неправильно?

Параметры - это свойства класса преобразователя:

@FacesConverter(value = TruncateConverter.CONVERTER_ID)
public class TruncateConverter implements Converter, StateHolder
{
    public static final String CONVERTER_ID = "bla.blablabla.Truncate";

    private int truncateIndex;
    private String contSymbol;

Вот как я использую конвертер (или пытаюсь):

<h:outputText id="news-text-left" value="#{newsListBean.newsList_teaser.text}">
    <f:converter converterId="bla.blablabla.Truncate" truncateIndex="150" contSymbol="..." />
</h:outputText>

Я довольно много искал в googled и не смог найти ни одного примера конвертера JSF2 с параметрами... Спасибо, ребята, за вашу помощь, очень цените это!

4b9b3361

Ответ 1

Вы можете посмотреть источники JSF2.0. Например, источники DateTimeConverter... JSF доступны здесь в svn reposotory: https://svn.java.net/svn/mojarra~svn/trunk

Создание IMO такого конвертера непросто. Также потребовалось создать конверторный тег для регистрации конвертера.

Другой способ передачи некоторых данных в конвертер - это attibutes. Таким образом, вы можете написать

<h:outputText ...>
  <f:converter converterId="bla.blablabla.Truncate" />
  <f:attribute name="truncateIndex" value="150"/>
</h:outputText>

Чем вызов component.getAttributes().get("truncateIndex"); в коде конвертера.

Ответ 3

На основе @Maks: можно комбинировать конвертер и атрибут в одном теге:

<facelet-taglib version="2.2"
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facelettaglibrary_2_2.xsd">
    <namespace>http://mycompany.com/some-identifier</namespace>
    <tag>
        <tag-name>truncate</tag-name>
        <converter>
            <converter-id>bla.blablabla.Truncate</converter-id>
        </converter>
        <attribute>
            <name>truncateIndex</name>
        </attribute>
    </tag>
</facelet-taglib>

Затем вы можете использовать конвертер следующим образом:

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
    xmlns:my="http://mycompany.com/some-identifier">

  <my:truncate truncateIndex="150" />

</ui:composition>

Вам также не нужно захватывать параметр из атрибутов компонента. A bean -property с тем же именем будет автоматически заполнено:

@FacesConverter("bla.blablabla.Truncate")
public class Truncate implements Converter {

    private String truncateIndex;

    // getters + setters

    ...

}

Ответ 4

Вот как я это сделал (в отдельном файле jar и с использованием директорий по умолчанию maven):

1) Создайте класс преобразователя (внутри src/main/java)

2) Создайте класс .taglib.xml(внутри src/main/resources/META-INF)

3) Создайте файл faces-config.xml(внутри src/main/resources/META-INF)

Пример:

Шаг 1)

package com.ocabit.jsf.converter;



import java.io.Serializable;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.NumberFormat;

import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.faces.convert.FacesConverter;

import org.springframework.stereotype.Service;

import com.ocabit.utils.currency.CurrencyUtils;


/**
 * Converter para valores BigDecimal.
 * 
 * @author Carlos Eduardo Pauluk
 * 
 */
@FacesConverter("bigDecimalConverter")
@Service("bigDecimalConverter")
public class BigDecimalConverter implements Converter, Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    public static final String CONVERTER_ID = "com.ocabit.jsf.converter.BigDecimalConverter";

    /**
     * Em caso de null, força a saída para 0.0;
     */
    private boolean nullToZero = false;

    /**
     * Em caso de zero, força a saída para null;.
     */
    private boolean zeroToNull = false;

    /**
     * Só retorna números positivos.
     */
    private boolean onlyAbs = false;

    /**
     * Só retorna números negativos.
     */
    private boolean onlyNeg = false;

    /**
     * Quantidade de casas decimais.
     */
    private int decimals = 2;

    @Override
    public Object getAsObject(final FacesContext context, final UIComponent component, final String value) {
        try {
            BigDecimal bd = new BigDecimal(value);
            bd = bd.setScale(getDecimals(), RoundingMode.HALF_DOWN);

            if (bd.equals(BigDecimal.ZERO) && isZeroToNull()) {
                return null;
            }

            if (isOnlyAbs()) {
                bd = bd.abs();
            }
            if (isOnlyNeg()) {
                bd = bd.abs();
                bd = bd.negate();
            }

            return bd;
        } catch (final Exception e) {
            BigDecimal bd = null;
            if (isNullToZero()) {
                bd = CurrencyUtils.getBigDecimalCurrency("0.0");
                bd = bd.setScale(getDecimals(), RoundingMode.HALF_DOWN);
            }
            return bd;
        }
    }

    @Override
    public String getAsString(final FacesContext context, final UIComponent component, final Object value) {
        if (!(value instanceof BigDecimal)) {
            throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erro ao converter o valor decimal.", ""));
        }

        final NumberFormat nf = NumberFormat.getInstance();
        // sempre terá 2 casas decimais
        nf.setMinimumFractionDigits(2);
        nf.setMaximumFractionDigits(2);
        return nf.format(((BigDecimal) value).doubleValue());
    }

    public boolean isNullToZero() {
        return nullToZero;
    }

    public void setNullToZero(boolean nullToZero) {
        this.nullToZero = nullToZero;
    }

    public boolean isZeroToNull() {
        return zeroToNull;
    }

    public void setZeroToNull(boolean zeroToNull) {
        this.zeroToNull = zeroToNull;
    }

    public boolean isOnlyAbs() {
        return onlyAbs;
    }

    public void setOnlyAbs(boolean onlyAbs) {
        this.onlyAbs = onlyAbs;
    }

    public boolean isOnlyNeg() {
        return onlyNeg;
    }

    public void setOnlyNeg(boolean onlyNeg) {
        this.onlyNeg = onlyNeg;
    }

    public int getDecimals() {
        return decimals;
    }

    public void setDecimals(int decimals) {
        this.decimals = decimals;
    }

}

Шаг 2)

<!DOCTYPE facelet-taglib PUBLIC
    "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
    "facelet-taglib_1_0.dtd">
<facelet-taglib version="2.2"
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facelettaglibrary_2_2.xsd">
    <namespace>http://ocabit.com.br/facelets</namespace>


    <tag>
        <tag-name>convertBigDecimal</tag-name>      
        <converter>
            <converter-id>com.ocabit.jsf.converter.BigDecimalConverter</converter-id>           
        </converter>    
    </tag>


</facelet-taglib>

Шаг 3)

<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
        http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd"
    version="2.2">

    <converter>
        <description></description>
        <converter-id>com.ocabit.jsf.converter.BigDecimalConverter</converter-id>
        <converter-class>com.ocabit.jsf.converter.BigDecimalConverter</converter-class>
        <property>
            <property-name>nullToZero</property-name>
            <property-class>boolean</property-class>
            <description>Ao invés de retornar 'null', retorna '0.0'</description>
        </property>
        <property>
            <property-name>zeroToNull</property-name>
            <property-class>boolean</property-class>
            <description>Ao invés de retornar '0.0', retorna 'null'</description>
        </property>
        <property>
            <property-name>onlyAbs</property-name>
            <property-class>boolean</property-class>
            <description>Somente retorna números positivos</description>
        </property>
        <property>
            <property-name>onlyNeg</property-name>
            <property-class>boolean</property-class>
            <description>Somente retorna números negativos</description>
        </property>
        <property>
            <property-name>decimals</property-name>
            <property-class>int</property-class>
            <description>Quantidade de casas decimais</description>
        </property>
    </converter>


</faces-config>

Вуаля.