Ya estoy inscrito ¿Todavía no tienes acceso? Nuestros Planes
Ya estoy inscrito ¿Todavía no tienes acceso? Nuestros Planes
1
respuesta

Proyecto Final

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);
        }
    }
}
1 respuesta

¡Hola Diego, espero que estés bien!

Gracias por compartir tu solución. Parece que has hecho un gran trabajo al implementar una aplicación que consulta datos de libros desde la API de Gutendex. Aquí hay algunos puntos que podrían ayudarte a mejorar o ajustar tu proyecto:

  1. Manejo de Errores: Aunque ya estás lanzando una excepción cuando la respuesta de la API no es 200, considera manejar otras posibles excepciones, como problemas de red o errores de JSON, para proporcionar mensajes de error más detallados al usuario.

  2. Optimización de Streams: En la parte donde filtras y ordenas los libros por descargas, podrías considerar el uso de limit antes de peek para mejorar el rendimiento, aunque en este caso específico el impacto puede ser mínimo.

  3. Uso de toList(): En Java 16 y versiones posteriores, puedes usar toList() directamente en lugar de collect(Collectors.toList()). Si estás usando una versión anterior, asegúrate de que tu código sea compatible.

  4. Interfaz de Usuario: Podrías mejorar la experiencia del usuario mostrando un mensaje claro si no se encuentran libros durante la búsqueda.

  5. Comentarios y Documentación: Asegúrate de incluir comentarios en tu código para que otros (o tú mismo en el futuro) puedan entender rápidamente lo que hace cada parte del programa.

  6. Pruebas: Considera escribir pruebas unitarias para las partes clave de tu aplicación, especialmente para el consumo y la conversión de datos de la API.

Espero que encuentres útiles estos consejos y que sigas disfrutando de tu aprendizaje en Java. ¡Bons estudos!