En muchas ocasiones necesitamos realizar consultas mediante expresiones regulares que se unen con otras condiciones de búsqueda en la que se necesita utilizar paginación y ordenación.
Vídeo de muestra Búsquedas con expresiones regulares en MongoDB mediante Jmoordbcore
En JmoordbCore es posible utilizar la anotación @SearchByLike, para generar consultas utilizando expresiones regulares combinadas. Por ejemplo:
@SearchLikeBy(caseSensitive = CaseSensitive.NO, typeOrder = TypeOrder.ASC, likeByType = LikeByType.ANYWHERE)
public List<Tarjeta> searchLikeByTarjeta(String tarjeta, Search search);
En este ejemplo utilizaremos un Microservicio que utiliza https://microprofile.io/ con una base de datos MongoDB, que se comunica mediante Jmoordbcore.
Se cuenta con documentos que almacenan información sobre tarjetas con atributos similares a estos
Las interfaces de usuario se desarrollan utilizando Jakarta Faces con Primefaces, como se muestra en la siguiente figura:
Pasos:
- Cree un proyecto Jakarta EE con Payara Starter https://start.payara.fish/
- Agregue la dependencia de jmoordbcore
<version.jmoordbcore>1.0.0.b-7</version.jmoordbcore>
<dependency>
<groupId>com.github.avbravo</groupId>
<artifactId>jmoordb-core</artifactId>
<version>${version.jmoordbcore}</version>
</dependency>
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
- Agrega propiedades de conexión a la base de datos en el archivo microprofile-config.properties
mongodb.uri=mongodb://localhost:27017
#-- Database de configuración
mongodb.jmoordb= configurationjmoordbdb
#-- Database History
mongodb.databasehistory=historydb
#-- Database
mongodb.database=accreditation
mongodb.database1=sft
mongodb.database2=practicadb
- Defina la entidad Tarjeta que representa un documento de la colección
@Entity
public class Tarjeta {
@Id(autogeneratedActive = AutogeneratedActive.ON)
private Long idtarjeta;
@Column
private String tarjeta;
@Column
private String descripcion;
@ViewReferenced(from = "user", localField = "iduser")
List<UserView> userView;
@Column
private Date fechainicial;
@Column
private Date fechafinal;
@Referenced(from = "icono", localField = "idicono", commentary = "Esta asociado a la prioridad")
private Icono icono;
@Referenced(from = "tipotarjeta", localField = "idtipotarjeta", commentary = "Ayuda para la implementación de Deep Learning")
private Tipotarjeta tipotarjeta;
@Column
private Long idsprint;
@Column
private Long idproyecto;
@Column
private Boolean backlog;
@Column(commentary = "alta,baja,media")
private String prioridad;
@Column
private String estimacion;
@Column(commentary = "pendiente,progreso,finalizado")
private String columna;
@Column
private Boolean active;
@Embedded
List<Tarea> tarea;
@Embedded
List<Comentario> comentario;
@Embedded
List<Etiqueta> etiqueta;
@Embedded
List<Archivo> archivo;
@Embedded
List<Impedimento> impedimento;
@Column(commentary = "true cuando la crea un colaborador que no pertenece al proyecto y es un proyecto publico")
private Boolean foreaneo;
@Embedded
List<ActionHistory> actionHistory;
public Tarjeta() {
}
...
}
- Defina el repositorio TarjetaRepository.java, con métodos para contar los documentos y realizar búsquedas combinando expresiones regulares con otros filtros.
@Repository(database = "{mongodb.database1}", entity = Tarjeta.class)
public interface TarjetaRepository extends CrudRepository<Tarjeta, Long> {
@SearchCountLikeBy(caseSensitive = CaseSensitive.NO, likeByType = LikeByType.ANYWHERE)
public Long searchCountLikeByTarjeta(String tarjeta, Search search);
@SearchCountLikeBy(caseSensitive = CaseSensitive.NO, likeByType = LikeByType.ANYWHERE)
public Long searchCountLikeByDescripcion(String descripcion, Search search);
@SearchLikeBy(caseSensitive = CaseSensitive.NO, typeOrder = TypeOrder.ASC, likeByType = LikeByType.ANYWHERE)
public List<Tarjeta> searchLikeByTarjeta(String tarjeta, Search search);
@SearchLikeBy(caseSensitive = CaseSensitive.NO, typeOrder = TypeOrder.ASC, likeByType = LikeByType.ANYWHERE)
public List<Tarjeta> searchLikeByDescripcion(String descripcion, Search search);
}
- Cree una clase controladora llamada TarjetaController.java
@Path("tarjeta")
@Tag(name = "Información del tarjeta", description = "End-point para entidad Tarjeta")
@RolesAllowed({"admin"})
public class TarjetaController {
@GET
@Path("searchcountlikebytarjeta")
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Long searchCountLikeByTarjeta(@QueryParam("tarjeta") String tarjeta, @QueryParam("filter") String filter, @QueryParam("sort") String sort, @QueryParam("page") Integer page, @QueryParam("size") Integer size) {
Long result = 0L;
try {
Search search = DocumentUtil.convertForLookup(filter, sort, page, size);
result= tarjetaRepository.searchCountLikeByTarjeta(tarjeta, search);
} catch (Exception e) {
MessagesUtil.error(MessagesUtil.nameOfClassAndMethod() + "error: " + e.getLocalizedMessage());
}
return result;
}
@GET
@Path("searchcountlikebydescripcion")
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Long searchCountLikeByDescripcion(@QueryParam("descripcion") String descripcion, @QueryParam("filter") String filter, @QueryParam("sort") String sort, @QueryParam("page") Integer page, @QueryParam("size") Integer size) {
Long result = 0L;
try {
Search search = DocumentUtil.convertForLookup(filter, sort, page, size);
result= tarjetaRepository.searchCountLikeByDescripcion(descripcion, search);
} catch (Exception e) {
MessagesUtil.error(MessagesUtil.nameOfClassAndMethod() + "error: " + e.getLocalizedMessage());
}
return result;
}
@GET
@Path("likebytarjetasearch")
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public List<Tarjeta> searchLikeByTarjeta(@QueryParam("tarjeta") String tarjeta, @QueryParam("filter") String filter, @QueryParam("sort") String sort, @QueryParam("page") Integer page, @QueryParam("size") Integer size) {
List<Tarjeta> suggestions = new ArrayList<>();
try {
Search search = DocumentUtil.convertForLookup(filter, sort, page, size);
suggestions = tarjetaRepository.searchLikeByTarjeta(tarjeta, search);
} catch (Exception e) {
MessagesUtil.error(MessagesUtil.nameOfClassAndMethod() + "error: " + e.getLocalizedMessage());
}
return suggestions;
}
@GET
@Path("likebydescripcionsearch")
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public List<Tarjeta> searchLikeByDescripcion(@QueryParam("descripcion") String descripcion, @QueryParam("filter") String filter, @QueryParam("sort") String sort, @QueryParam("page") Integer page, @QueryParam("size") Integer size) {
List<Tarjeta> suggestions = new ArrayList<>();
try {
Search search = DocumentUtil.convertForLookup(filter, sort, page, size);
suggestions = tarjetaRepository.searchLikeByDescripcion(descripcion, search);
} catch (Exception e) {
MessagesUtil.error(MessagesUtil.nameOfClassAndMethod() + "error: " + e.getLocalizedMessage());
}
return suggestions;
}
}
Creando el Cliente
Pasos:
Cree un proyecto nuevo con Cree un proyecto Jakarta EE con Payara Starter https://start.payara.fish/
Agregue al archivo microprofile-config.properties restclient
com.sft.restclient.TarjetaRestClient/mp-rest/url=http://localhost:9002/accreditation/api/
Cree la entidad tarjeta que definió en el microservicio.
Cree las interfaces para el endpoint tarjeta
@RegisterRestClient()
@Path("/tarjeta")
public interface TarjetaRestClient {
@GET
@Path("likebytarjetasearch")
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
List<Tarjeta> searchLikeByTarjeta(@QueryParam("tarjeta") String tarjeta, @QueryParam("filter") String filter, @QueryParam("sort") String sort, @QueryParam("page") Integer page, @QueryParam("size") Integer size);
@GET
@Path("likebydescripcionsearch")
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
List<Tarjeta> searchLikeByDescripcion(@QueryParam("descripcion") String descripcion, @QueryParam("filter") String filter, @QueryParam("sort") String sort, @QueryParam("page") Integer page, @QueryParam("size") Integer size);
@GET
@Path("searchcountlikebytarjeta")
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Long searchCountLikeByTarjeta(@QueryParam("tarjeta") String tarjeta, @QueryParam("filter") String filter, @QueryParam("sort") String sort, @QueryParam("page") Integer page, @QueryParam("size") Integer size);
@GET
@Path("searchcountlikebydescripcion")
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Long searchCountLikeByDescripcion(@QueryParam("descripcion") String descripcion, @QueryParam("filter") String filter, @QueryParam("sort") String sort, @QueryParam("page") Integer page, @QueryParam("size") Integer size);
- Cree la interface TarjetaServices
public interface TarjetaServices {
public List<Tarjeta> searchLikeByTarjeta(String tarjeta, Bson filter, Document sort, Integer page, Integer size);
public Long searchCountLikeByTarjeta(String tarjeta, Bson filter, Document sort, Integer page, Integer size);
public List<Tarjeta> searchLikeByDescripcion(String descripcion, Bson filter, Document sort, Integer page, Integer size);
public Long searchCountLikeByDescripcion(String descripcion, Bson filter, Document sort, Integer page, Integer size);
}
- Cree la implementación
@ApplicationScoped
public class TarjetaServicesImpl implements TarjetaServices {
@Inject
TarjetaRestClient tarjetaRestClient;
@Override
public List<Tarjeta> searchLikeByTarjeta(String tarjeta, Bson filter, Document sort, Integer page, Integer size) {
List<Tarjeta> tarjetaList = new ArrayList<>();
try {
tarjetaList = tarjetaRestClient.searchLikeByTarjeta(tarjeta,
EncodeUtil.encodeBson(filter),
EncodeUtil.encodeBson(sort),
page, size);
} catch (Exception e) {
FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
}
return tarjetaList;
}
@Override
public Long searchCountLikeByTarjeta(String tarjeta, Bson filter, Document sort, Integer page, Integer size) {
Long result = 0L;
try {
result = tarjetaRestClient.searchCountLikeByTarjeta(tarjeta,
EncodeUtil.encodeBson(filter),
EncodeUtil.encodeBson(sort),
page, size);
} catch (Exception e) {
FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
}
return result;
}
@Override
public List<Tarjeta> searchLikeByDescripcion(String descripcion, Bson filter, Document sort, Integer page, Integer size) {
List<Tarjeta> tarjetaList = new ArrayList<>();
try {
tarjetaList = tarjetaRestClient.searchLikeByDescripcion(descripcion,
EncodeUtil.encodeBson(filter),
EncodeUtil.encodeBson(sort),
page, size);
} catch (Exception e) {
FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
}
return tarjetaList;
}
@Override
public Long searchCountLikeByDescripcion(String descripcion, Bson filter, Document sort, Integer page, Integer size) {
Long result = 0L;
try {
result = tarjetaRestClient.searchCountLikeByDescripcion(descripcion,
EncodeUtil.encodeBson(filter),
EncodeUtil.encodeBson(sort),
page, size);
} catch (Exception e) {
FacesUtil.errorMessage(FacesUtil.nameOfClassAndMethod() + " " + e.getLocalizedMessage());
}
return result;
}
}
- Diseñe la interface de usuario con Jakarta Server Faces y Primefaces para realizar búsquedas, quedando de la siguiente manera:
Entre los elementos usados se encuentran:
inputText
selectOneMenu
dataTable
Se usara un datable, con columnas y componentes que no se muestran completamente en la siguiente sección:
<p:dataTable var="item" value="#{buscadorTarjetasFaces.tarjetaLazyDataModel}"
binding="#{buscadorTarjetasFaces.dataTable}"
id="dataTable"
widgetVar="widgetVardataTable"
lazy="true"
paginator="true"
rows="#{buscadorTarjetasFaces.rowPageSmall.get()}" paginatorTemplate="{RowsPerPageDropdown} {FirstPageLink} {PreviousPageLink} {CurrentPageReport} {NextPageLink} {LastPageLink}"
paginatorPosition="both"
reflow="true"
rowKey="#{item.idtarjeta}"
selection="#{buscadorTarjetasFaces.tarjetaSelected}"
rowSelectMode="add">
<p:column class="column2">
<p:rowToggler/>
</p:column>
<p:column class="column8" headerText="#{msg['field.idtarjeta']}">
<p:outputLabel value="#{item.idtarjeta}"/>
</p:column>
...
- Cree la clase BuscadorTarjetasFaces
@Named
@ViewScoped
@Data
public class BuscadorTarjetasFaces implements Serializable, JmoordbCoreXHTMLUtil, IPaginator, SprintFacesServices {
@Inject
TarjetaServices tarjetaServices;
En el método init() se realizara la administración de la paginación insertando el siguiente codigo
this.tarjetaLazyDataModel = new LazyDataModel<Tarjeta>() {
@Override
public List<Tarjeta> load(int offset, int pageSize, Map<String, SortMeta> sortBy, Map<String, FilterMeta> filterBy) {
if (textDescripcionToSearch == null || textDescripcionToSearch.equals("")) {
totalRecords = tarjetaServices.searchCountLikeByTarjeta(textToSearch, paginator.getFilter(), paginator.getSort(), paginator.getPage(), rowPageSmall.get()).intValue();
} else {
if ((textToSearch == null || textToSearch.equals("")) && (textDescripcionToSearch != null || !textDescripcionToSearch.equals(""))) {
totalRecords = tarjetaServices.searchCountLikeByDescripcion(textDescripcionToSearch, paginator.getFilter(), paginator.getSort(), paginator.getPage(), rowPageSmall.get()).intValue();
} else {
totalRecords = tarjetaServices.searchCountLikeByTarjeta(textToSearch, paginator.getFilter(), paginator.getSort(), paginator.getPage(), rowPageSmall.get()).intValue();
}
}
List<Paginator> list = new ArrayList<>();
if (!isRowPageSmall) {
/**
* Utiliza rowPage
*/
list = processLazyDataModel(paginator, paginatorOld, offset, rowPage.get(), totalRecords, sortBy);
} else {
/**
* Utiliza rowPageWithOverlayPanel para el OverlayPanel
*/
list = processLazyDataModel(paginator, paginatorOld, offset, rowPageSmall.get(), totalRecords, sortBy);
}
//
paginator = list.get(0);
paginatorOld = list.get(1);
Pagination pagination = new Pagination();
if (!isRowPageSmall) {
paginator.setNumberOfPage(numberOfPages(totalRecords, rowPage.get()));
pagination = new Pagination(paginator.getPage(), rowPage.get());
} else {
paginator.setNumberOfPage(numberOfPages(totalRecords, rowPageSmall.get()));
pagination = new Pagination(paginator.getPage(), rowPageSmall.get());
}
List<Tarjeta> result = new ArrayList<>();
if (textDescripcionToSearch == null || textDescripcionToSearch.equals("")) {
result = tarjetaServices.searchLikeByTarjeta(textToSearch, paginator.getFilter(), paginator.getSort(), paginator.getPage(), rowPageSmall.get());
} else {
if ((textToSearch == null || textToSearch.equals("")) && (textDescripcionToSearch != null || !textDescripcionToSearch.equals(""))) {
result = tarjetaServices.searchLikeByDescripcion(textDescripcionToSearch, paginator.getFilter(), paginator.getSort(), paginator.getPage(), rowPageSmall.get());
} else {
result = tarjetaServices.searchLikeByTarjeta(textToSearch, paginator.getFilter(), paginator.getSort(), paginator.getPage(), rowPageSmall.get());
}
}
tarjetaLazyDataModel.setRowCount(totalRecords);
PrimeFaces.current().executeScript("setDataTableWithPageStart()");
PrimeFaces.current().executeScript("widgetVardataTable.getPaginator().setPage(0);");
tarjetaList = result;
return result;
}
@Override
public int count(Map<String, FilterMeta> map) {
return totalRecords;
}
@Override
public String getRowKey(Tarjeta object) {
if (object == null || object.getIdtarjeta() == null) {
return "";
}
return object.getIdtarjeta().toString();
}
@Override
public Tarjeta getRowData(String rowKey) {
for (Tarjeta t : tarjetaList) {
if (t != null) {
if (t.getIdtarjeta().equals(rowKey)) {
return t;
}
}
}
return null;
}
};
En la siguiente sección se muestra los comportamientos de los eventos.