¿Cómo creamos un menú para interactuar con la API de Cat Happy?
Este contenido explora cómo crear un menú interactivo en Java para gestionar imágenes de gatos desde la API de Cat Happy. Este proceso es esencial para quienes desean desarrollar aplicaciones interactivas basadas en datos externos, aplicando conceptos de programación orientada a objetos y buenas prácticas en el manejo de excepciones.
¿Cómo estructuramos el menú?
Primero, necesitas definir las opciones del menú que ofrecerás a los usuarios. Es importante que las opciones sean claras y accionables para guiar correctamente la experiencia del usuario.
Define un String llamado menu que contenga las opciones de elección para el usuario. Puedes utilizar el carácter \n para listar cada opción en una nueva línea.
Crea un arreglo de String llamado botones donde almacenarás estas opciones para su posterior uso en la interfaz gráfica.
String menu ="Opciones:\n"+"1. Ver otra imagen\n"+"2. Marcar el gato como favorito\n"+"3. Volver al menú";String[] botones ={"Ver otra imagen","Favorito","Volver"};
¿Cómo presentamos las opciones al usuario?
Para presentar estas opciones al usuario, usaremos un cuadro de diálogo que permite seleccionar entre ellas:
Usa JOptionPane.showInputDialog para desplegar un cuadro de diálogo que muestre las opciones del menú y espere una respuesta del usuario.
El cuadro de diálogo debe mostrar la imagen del gato y las opciones de interacción.
int opcion =JOptionPane.showOptionDialog(null, menu,"ID de la imagen: "+ gato.getId(),JOptionPane.INFORMATION_MESSAGE,null, botones, botones[0]);
¿Cómo gestionamos las selecciones del usuario?
Con cada opción seleccionada, debes tener un flujo definido para manejar la interacción del usuario. Utiliza estructuras de control como switch para definir acciones específicas según la opción elegida.
La opción 0 podría generar una nueva llamada a la API para revisar otra imagen.
La opción 1 llama un método favoritoGato que marca al gato actual como favorito.
La opción 2 podría redirigir al usuario al menú principal o cerrar la aplicación.
switch(opcion){case0:verOtraImagen();break;case1:favoritoGato(gato);break;// Otros casos pueden incluir un default para manejar selecciones no deseadasdefault:System.out.println("Opción no válida.");break;}
¿Qué errores comunes podemos encontrar y cómo solucionarlos?
En la programación, el manejo de errores es crucial para asegurar una experiencia fluida y sin interrupciones. Uno de los errores comunes es la conversión incorrecta de tipos de datos, especialmente cuando se manejan IDs o identificadores únicos.
Comprueba que el tipo de datos coincida con la definición en el modelo. Si en la base de datos o en la API el ID está como String, debe reflejarse igual en el modelo Java.
Revisa y prueba la aplicación después de realizar cualquier cambio. Utiliza herramientas de pruebas como Postman para validar la correcta recepción y envío de datos.
// Ajuste en el modelo cuando el ID es un StringpublicclassGato{privateString id;// Cambiado de int a String// getters y setters correspondientes}
Mantente atento a cómo el usuario interactúa con la interfaz y optimiza el flujo según la experiencia que desees proporcionar. Con cada clase y ejecución, se robustecen las aplicaciones, acercándote más a una implementación completa y funcional. ¡Continúa explorando, construyendo, y perfeccionando tus habilidades en programación!
Si llegaron al final de este video y no les muestra la imagen del gato y encima les sale un error como este: "Can’t get input stream from URL! "
Relájense, el error es básicamente por temas de seguridad ya que la imagen está en https y el sitio del api de gatitos no permite la descarga.
El código:
image = ImageIO.read(url);
ImageIcon fondoG = new ImageIcon(image);
Si funciona en http o https que no impida la descarga de la imagen (lo probé), una simple declaración de ulr no es suficiente para descargar la imagen protegida.
Esto me funcionó:
HttpURLConnection httpcon = (HttpURLConnection)url.openConnection();
httpcon.addRequestProperty("User-Agent", "");
BufferedImage bufferedImage = ImageIO.read(httpcon.getInputStream());
ImageIcon fondoG = new ImageIcon(bufferedImage);
Creditos a un usuario de la siguiente clase.
Saludos!
Muchas gracias, me sirvió para solucionar ese error.
Consulta, sabes que es lo que hace esta linea con esos parámetros?
httpcon.addRequestProperty(“User-Agent”, “”);
muchas gracias por el aporte, me funcionó a la perfección
Este es el codigo entero con la solucion del error Input Stream
`public static void verGatitos() throws IOException{
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://api.thecatapi.com/v1/images/search")
.method("GET", null)
.build();
Response response = client.newCall(request).execute();
Muchísimas gracias Cesar, tenía este fallo como casi todo el mundo, me leí todos los comentarios pero el tuyo fue el único que estaba claro y conciso, mil gracias por tus aportes!
Muchas gracias por el aporte Cesar 👏🏻
Creo que la API de gatitos esta experimentando problemas, asi que utilice una API de perritos les dejo el link:
https://dog.ceo/dog-api/
Justamente!!! Me sucedió lo mismo y encontré esta también, pero gasté tiempo buscando una. Estaría bueno compartirlo en la clase anterior. Saludos
¡Me ayudaste resto! Como el código que me proporcionó Postman es muy diferente al que obtuvo el instructor, pensé que directamente no serviría.
Profesor, el error de Can’t get input stream from URL! logre solucionarlo gracias al código que compartieron mas abajo que va debajo de la instancia del URL y antes del ImageIcon
ahora podre seguir con el tutorial, pero, si no es mucho pedir, alguien podría explicar ese pedacito de código? o el por que algunos les funciona sin ese código y a otros no? Gracias, seguiré investigando si tengo la respuesta la compartiré.
Tengo exactamente la misma pregunta, lei un poco de la documentacion de las clases que mencionas, y lo que entiendo es esto.
Esta Linea crea una instancia URLConnection que contiene los datos del URL, en este caso la imagen incluida. Lo que aun no me quedo claro es esto:
http.addRequestProperty("User-Agent","");
Segun la documentacion añade propiedades segun la Key que se use, lo que no entiendo es que hace User-Agent.
Investigue mas y lo que encontre es que :
http.addRequestProperty("User-Agent","");
Contiene los datos con los que nos identification ante la API por medio de HTTP, basicamente estamos pidiendole permiso al servidor.
Estudiantes, actualicé el proyecto en mi repositorio aplicando mejores prácticas
Al ejecutar el programa me trae un IIOException: Can't get input stream from URL
javax.imageio.IIOException: Can't get input stream from URL!
at javax.imageio.ImageIO.read(ImageIO.java:1401)
at com.donnatto.gatos.CatService.verGatos(CatService.java:40)
at com.donnatto.gatos.Start.main(Start.java:28)
Caused by: java.io.IOException: Server returned HTTP response code: 403 for URL: https://cdn2.thecatapi.com/images/MTU1Nzc3MQ.jpg
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1900)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1498)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:268)
at java.net.URL.openStream(URL.java:1057)
at javax.imageio.ImageIO.read(ImageIO.java:1399)
... 2 more
```
Hola, este error 403 (forbidden) ocurre por que thecatapi.com considera que no tienes acceso a esa imagen.
Esto puede ser por que te falte la APIkey al momento de traer las fotos.
O por que la foto dejó de estar disponible.
Prueba con otra API (con otro email) y nos confirmas si te deja traer las fotos de los gatos
Quien quiere ver gatos? lo de hoy son los memes, les dejo un proyecto en github que busca memes en reddit y devuelve un JSON con la información, este es el link de la API https://meme-api.herokuapp.com/gimme
Este es mi codigo:
MemeService
publicclassMemesService{publicstaticvoidverMemes() throws IOException{ArrayList<String> options =newArrayList<>(); options.add(" 1. ver otro meme"); options.add(" 2. abrir meme en chrome"); options.add(" 3. favoritos"); options.add(" 4. volver al menu"); int op =-1;do{Meme meme =getMemeFromAPI();Object input =JOptionPane.showInputDialog(null,"Opciones: ", meme.getTitle()+" subreddit: "+meme.getSubreddit(),JOptionPane.INFORMATION_MESSAGE,getImageFromURL(meme.getUrl()), options.toArray(), options.get(0)); op = options.indexOf(input);//abre el meme en el navegador chromeif(op ==1)Runtime.getRuntime().exec(newString[]{"cmd","/c","start chrome "+meme.getPostLink()});}while(op !=3);}privatestaticIcongetImageFromURL(String url) throws IOException,MalformedURLException{returnnewImageIcon(ImageIO.read(newURL(url)).getScaledInstance(800,800,BufferedImage.SCALE_SMOOTH));}privatestaticMemegetMemeFromAPI(){Unirest.setTimeouts(0,0);Meme meme =newMeme();try{HttpResponse<String> response =Unirest.get("https://meme-api.herokuapp.com/gimme").asString(); meme =newGson().fromJson(response.getBody(),Meme.class);}catch(UnirestException e){ e.printStackTrace();}return meme;}}
En caso de que no te abra la documentación en thecatapi debes usar una vpn (en mi caso usé proton vpn), y debes configurar como máximo java 17 (yo como tenía java 21 no me cargaba okhttp en el pom.xml).
Aqui está mi gatito:
No esperen que todo les salga perfecto a la primera, tambien hay que leer los comentarios de los compañeros he ir probando el código por nuestra cuenta y haciendo Debug para entender y identificar los errores en la líneas especificas. antes de implementar el menú hice pruebas, y con el apoyo de los comentarios fui corrigiendo los errores que se tenia. así me quedo la clase GatosService:
<publicclassGatosService{publicstaticvoidverGatos() throws IOException{// Traemos los datos de la Api dados por postmanOkHttpClient client =newOkHttpClient();// MediaType mediaType = MediaType.parse("text/plain");// RequestBody body = RequestBody.create(mediaType, "");Request request =newRequest.Builder().url("https://api.thecatapi.com/v1/images/search").get().build();Response response = client.newCall(request).execute();String elJson = response.body().string();// devemos cortar los primeros corchetes de iteracion del archivo elJson = elJson.substring(1, elJson.length());// corte el primer corteche elJson = elJson.substring(0, elJson.length()-1);// corto el ultimo corchete// creo el objeto de la GsonGson gson =newGson();// Apartir del gson, creo el objeto gatoGatos gatos = gson.fromJson(elJson,Gatos.class);// Redimencinar Imagen Image image =null;try{URL url =newURL(gatos.getUrl());//Creo una conexión HTTP con el servidor que aloja la imagen del perroHttpURLConnection http =(HttpURLConnection) url.openConnection();// Agrega una propiedad de solicitud al objeto http http.addRequestProperty("User-Agent","");BufferedImage bufferedImage =ImageIO.read(http.getInputStream());ImageIcon fondoGato =newImageIcon(bufferedImage);if(fondoGato.getIconWidth()>800|| fondoGato.getIconHeight()>500){// redimencionarImage fondo = fondoGato.getImage();Image modificada = fondo.getScaledInstance(800,500, java.awt.Image.SCALE_SMOOTH); fondoGato =newImageIcon(modificada);}String id_gato = gatos.getId();String opcion =(String)JOptionPane.showInputDialog(null,null, id_gato,JOptionPane.INFORMATION_MESSAGE, fondoGato,null,null);}catch(IOException e){System.out.println(e);}}}>
Después de luchar porque tenia un error, era cuestión de solo leer la documentación y vi el porque rápido. Logre este producto final.
Como ?
Salioooooo
Compañeros conseguí la explicación del código que compartieron para los que les causaba el error de la URL.
Hola, para los que les das error al ejecutar deberían copiar exactamente la misma dirección que usa Santiago. A mi solo con esa me funcionó.
Aquí se las dejo: https://api.thecatapi.com/v1/images/search
Cuidado con la versión del okio que utilizan, yo había descargado 2.2.2 y me estaba dando error, cambié a 1.6.0 para que funcionara
Listo, muy bien para algo introductorio, vamos mejorando
Tiene un error grave de llamado recursivo en el método verGato
Super :)
Esta linea me marca un error:
Gatos cats = json.fromJson(eljson, Gatos.class);
:-(
Exception in thread "main" com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept
Caused by: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 138 path $
cualquier ayuda es bienvenida !:-
Es posible que en ese momento la respuesta del Json de la API estuviese dando error.
Lo que puedes hacer es un print de eljson para ver cómo viene la data