Comparto mi solución propuesta: Principal
package com.diego.booksearchengine.principal;
import com.diego.booksearchengine.model.DatosLibros;
import com.diego.booksearchengine.model.Libro;
import com.diego.booksearchengine.service.ConsumoAPI;
import com.diego.booksearchengine.service.ConvierteDatos;
import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Comparator;
import java.util.DoubleSummaryStatistics;
import java.util.List;
import java.util.Scanner;
import java.util.stream.Collectors;
public class Principal {
private ConsumoAPI consumoAPI = new ConsumoAPI();
private ConvierteDatos convierteDatos = new ConvierteDatos();
private final String URL_BASE = "http://gutendex.com/books";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd/MM/yyyy");
Scanner scan = new Scanner(System.in);
public void muestraMenu() throws IOException, InterruptedException {
//Obtener datos en json de la API
var json = consumoAPI.obtenerDatos(URL_BASE);
System.out.println(json);
//Convertir los datos json a la clase DatosLibros
var datosLibros = convierteDatos.obtenerDatos(json, DatosLibros.class).DatosLibros();
System.out.println(" ");
for (int i = 0; i < 5; i++) {
System.out.println(datosLibros.get(i));
}
System.out.println("\n TOP 10 LIBRO MÁS DESCARGADOS! " + "Hoy: " + LocalDate.now().format(dtf) +"\n");
List<Libro> librosFiltradosYOrdenados = datosLibros.stream()
.filter((l -> l.totaldescargas() > 1000))
.sorted(Comparator.comparing(Libro::totaldescargas).reversed())
.peek(l -> System.out.println(l.titulo().toUpperCase() + ", " + l.totaldescargas()))
.limit(10)
.toList();
// Obtener las estadísticas de una busqueda por # de descargas
System.out.print("\n Ingresa el nombre del libro que deseas buscar: ");
String busqueda = scan.nextLine();
json = consumoAPI.obtenerDatos(URL_BASE+"?search="+busqueda.replace(" ", "+"));
datosLibros = convierteDatos.obtenerDatos(json, DatosLibros.class).DatosLibros();
System.out.println(datosLibros);
DoubleSummaryStatistics est = datosLibros.stream()
.filter(d -> d.totaldescargas() > 0)
.collect(Collectors.summarizingDouble(Libro::totaldescargas));
System.out.println("\n Estadísticas! " + "Hoy: " + LocalDate.now().format(dtf) +"\n");
System.out.println("Media de descargas: " + est.getAverage());
System.out.println("Número mayor de descargas: " + est.getMax());
System.out.println("Número menor de descargas: " + est.getMin());
System.out.println("Número de registros contados: " + est.getCount());
}
}
Consumo API
package com.diego.booksearchengine.service;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.io.IOException;
public class ConsumoAPI {
private final HttpClient client;
public ConsumoAPI() {
this.client = HttpClient.newBuilder()
.followRedirects(HttpClient.Redirect.ALWAYS)
.build();
}
public String obtenerDatos(String url) throws IOException, InterruptedException {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() != 200) {
throw new RuntimeException("Error API: " + response.statusCode());
}
return response.body();
}
}
Datos Libros
package com.diego.booksearchengine.model;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import java.util.List;
@JsonIgnoreProperties(ignoreUnknown = true)
public record DatosLibros(
@JsonAlias("results") List<Libro> DatosLibros
) {}
Convierte datos json a clase
package com.diego.booksearchengine.service;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class ConvierteDatos implements IConvierteDatos{
private ObjectMapper objectMapper = new ObjectMapper();
@Override
public <T> T obtenerDatos(String json, Class<T> clase) {
ObjectMapper objectMapper = new ObjectMapper();
try {
return objectMapper.readValue(json, clase);
}catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
}