DEV Community

aristides villarreal
aristides villarreal

Posted on • Edited on

Optimizando Converter con Primefaces selectOneMenu y Autocomplete

Para optimizar los converter cuando utilizamos componentes como podemos recurrir a crear un services que contenga la lista de objetos a utilizar y hacemos la conversión buscando en esa lista en lugar de realizar una consulta al microservicios que devuelve el resultado, esto mejora el desempeño de la aplicación y reduce la cantidad de peticiones al microservicio.

Image description

Converter

El Converter lo usaremos para selectOneMenu y Autocomplete de Primefaces. Por lo tanto recibirá una lista de objetos delimitados por la cantidad máxima que se especifique en la variable de configuración en el archivo microprofile-config.properties denominada: #-- converter

converter.max.number.of.elements =25
Enter fullscreen mode Exit fullscreen mode

Como valor predeterminado serán 25 elementos. Para evitar cargar listas muy grandes.
Cuando se realiza una selección en un selectOneMenu o Autocomplete de un elemento que excede los 25 se buscara en el microservicio, en caso contrario se buscara en la lista almacenada en la memoria.

Image description

Crear el Services

@ViewScoped
@Named
public class TipoTarjetaConverterServices implements Serializable {

    @Inject
    TipotarjetaServices tipotarjetaServices;

    List<Tipotarjeta> tipotarjetas = new ArrayList<>();

    public List<Tipotarjeta> getTipotarjetas() {
        return tipotarjetas;
    }

    public void setTipotarjetas(List<Tipotarjeta> tipotarjetas) {
        this.tipotarjetas = tipotarjetas;
    }

    // <editor-fold defaultstate="collapsed" desc="Optional<Tipotarjeta> get(Long id)">
    public Optional<Tipotarjeta> get(Long id) {
        Optional<Tipotarjeta> result;

        try {

            result = tipotarjetas.stream().filter(x -> x.getIdtipotarjeta().equals(id)).findFirst();
            if (!result.isPresent()) {
                Tipotarjeta tipotarjeta = tipotarjetaServices.findByIdtipotarjeta(id);
                if (tipotarjeta != null) {
tipotarjetas.add(tipotarjeta);
                    return Optional.of(tipotarjeta);
                }
                result = Optional.empty();
            }
            return result;
        } catch (Exception e) {

            FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
        }
        return Optional.empty();

    }
// </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="void add(List<Tipotarjeta> tipotarjetas)">

    public void add(List<Tipotarjeta> tipotarjetas) {
        try {
            destroyed();
            this.tipotarjetas = tipotarjetas;

        } catch (Exception e) {

            FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
        }

    }
// </editor-fold>

// <editor-fold defaultstate="collapsed" desc="void destroyed()">
    public void destroyed() {
        try {
            this.tipotarjetas = new ArrayList<>();
        } catch (Exception e) {

            FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
        }

    }
// </editor-fold>

}

Enter fullscreen mode Exit fullscreen mode

Crear el Converter

@Named
@FacesConverter(forClass = Tipotarjeta.class, managed = true)
public class TipotarjetaConverter implements Converter<Tipotarjeta> {

    @Inject
    TipoTarjetaConverterServices tipoTarjetaConverterServices;

    // <editor-fold defaultstate="collapsed" desc="String getAsString(FacesContext fc, UIComponent uic, Tipotarjeta t)">
    @Override
    public String getAsString(FacesContext fc, UIComponent uic, Tipotarjeta t) {
        try {
            if (t == null) {
                return "";
           }
            if (t.getIdtipotarjeta() != null) {
                return t.getIdtipotarjeta().toString();
            }
        } catch (Exception e) {
            new FacesMessage("Error en converter  " + e.getLocalizedMessage());
        }
        return "";
    }
    // </editor-fold>
// <editor-fold defaultstate="collapsed" desc="Tipotarjeta getAsObject(FacesContext fc, UIComponent uic, String submittedValue)">

    @Override
    public Tipotarjeta getAsObject(FacesContext fc, UIComponent uic, String submittedValue) {
        Tipotarjeta result = new Tipotarjeta();
        if (submittedValue == null || submittedValue.isEmpty()) {
            return null;
        }

        try {
            Integer id = Integer.parseInt(submittedValue);
            Long idTipotarjeta = id.longValue();
            Optional<Tipotarjeta> optional = tipoTarjetaConverterServices.get(idTipotarjeta);
            if (optional.isPresent()) {
                result = optional.get();
            }
            return result;
        } catch (Exception e) {

            System.out.println("====================");
            System.out.println(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
            ConsoleUtil.test("\t " + FacesUtil.nameOfClassAndMethod() + " submittedValue " + submittedValue);
            System.out.println("====================");
            throw new ConverterException(new FacesMessage(submittedValue + " is not a valid selecction from Converter"), e);
        }
    }
// </editor-fold>
}


Enter fullscreen mode Exit fullscreen mode

SelectOneMenu

Para el selectOneMenu se pasa la lista completa al services.

En la clase Faces

Necesita agregar en su clase

    // # Converter
     @Inject
    private Config config;

     @Inject
    @ConfigProperty(name = "converter.max.number.of.elements")
    private Provider<Integer> converterMaxNumberOfElements;

Enter fullscreen mode Exit fullscreen mode
@Inject
TipoTarjetaConverterServices tipoTarjetaConverterServices;
/**
 * invoca al método para cargar la lista en el ConverterServices
 */
    @PostConstruct
    public void init() {
        try {
 loadTipotarjetaByProyecto(proyectoSelected);

 } catch (Exception e) {
            FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
        }

}

/**
Carga la lista de tipotarjeta en el ConverterServices
*/
private void loadTipotarjetaByProyecto(Proyecto proyecto) {
        try {
          tipoTarjetaConverterServices.add(tipotarjetaServices.loadTipotarjetaByProyecto(proyecto))
            );

        } catch (Exception e) {
            FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
        }
    }
/**

/**
 * Limpia la lista
 */
@PreDestroy
public void preDestroy() {
  tipoTarjetaConverterServices.destroyed();
}

Enter fullscreen mode Exit fullscreen mode

En las paginas xhtml


 <p:selectOneMenu  value="#{tableroFaces.tarjetaSelected.tipotarjeta}" 
var="item">

<f:selectItems value="#{tipoTarjetaConverterServices.tipotarjetas}" 
 var="item" 
 itemLabel="#{item.tipotarjeta}"                                                    itemValue="#{item}"

 />
<p:column>
<i class="#{item.tipotarjeta}" /> #{item.tipotarjeta} 
</p:column>


</p:selectOneMenu>

Enter fullscreen mode Exit fullscreen mode

Image description

Autocomplete

Pasamos el máximo de registros permitidos que se configuraron en el archivo microprofile-config.properties. Mediante el método:

calcularConverterMaxNumberOfElements(result.size(),converterMaxNumberOfElements.get())
Enter fullscreen mode Exit fullscreen mode
  // <editor-fold defaultstate="collapsed" desc="List<Tipotarjeta> completeTipotarjeta(String query)">
    public List<Tipotarjeta> completeTipotarjeta(String query) {

        List<Tipotarjeta> result = new ArrayList<>();
        try {
            query = query.trim();
            result = tipotarjetaServices.likeByTipotarjeta(query);

            tipoTarjetaConverterServices.add(result.subList(0,                     
                    calcularConverterMaxNumberOfElements(result.size(),converterMaxNumberOfElements.get()))
            );
        } catch (Exception e) {

            FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
        }

        return result;
    }


Enter fullscreen mode Exit fullscreen mode

En la pagina xhtml


 <p:autoComplete id="tipotarjeta" 
  multiple="false"
  value="#{tipoTarjetaFaces.tipotarjetaSelectedAutocomplete}"

  completeMethod="#{tipoTarjetaFaces.completeTipotarjeta}"

  var="tipotarjeta"
  itemLabel="#{tipotarjeta.tipotarjeta}" 

  itemValue="#{tipotarjeta}"

   forceSelection="true"

  title="#{msg['autocomplete.minimo3caracteres']}"

  dropdown="true"

  minQueryLength="3"

  scrollHeight="250"

  converter="#{tipotarjetaConverter}"
>

<p:column>
    <h:outputText style="vertical-align: middle; margin-left: .5rem" value="#{tipotarjeta.tipotarjeta} - #{tipotarjeta.grupoTipoTarjeta.grupoTipoTarjeta}"/>
</p:column>

<p:ajax event="itemSelect"  
  listener="#{tipoTarjetaFaces.autocompleteSelectedEvent}"  
  update=":form:growl, tipotarjeta, dataTable" />  

<p:ajax event="itemUnselect" 
  process="@this" 
  listener="#{tipoTarjetaFaces.autocompleteUnselectListener}" 

 update=":form:growl, tipotarjeta, dataTable"
 />
 </p:autoComplete>


Enter fullscreen mode Exit fullscreen mode

AWS Q Developer image

Your AI Code Assistant

Ask anything about your entire project, code and get answers and even architecture diagrams. Built to handle large projects, Amazon Q Developer works alongside you from idea to production code.

Start free in your IDE

Top comments (0)

Billboard image

Create up to 10 Postgres Databases on Neon's free plan.

If you're starting a new project, Neon has got your databases covered. No credit cards. No trials. No getting in your way.

Try Neon for Free →

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay