Ejemplo de creación de un bot de Whatsapp en Java

La guía completa
Repositorio de origen de bot
Publicado: 5 de noviembre de 2020

Le mostraremos cómo escribir un simple bot de WhatsApp en Java usando nuestra API de WhatsApp.

En este ejemplo, el bot responderá a los comandos recibidos en forma de mensajes regulares en WhatsApp y responderá a ellos. ¡No olvide descargar el bot terminado de nuestro repositorio y usarlo en su trabajo!

¿Cuál es la funcionalidad de este bot?

  1. Al enviar el comando "chatid", el bot debe enviar un mensaje con el ID de chat actual;
  2. Al enviar el comando "file [format]", el bot debe enviar los archivos preparados (pdf, jpg, doc, mp3);
  3. Al enviar el comando "ogg", el bot debe enviar un archivo con la extensión "ogg" (mensaje de voz);
  4. Al enviar el comando "geo", el bot debe enviar geo-coordenadas (ubicación);
  5. Al enviar el comando "group", el bot debe crear un grupo consigo mismo y con el usuario;
  6. Cuando envías cualquier mensaje no relacionado con un comando, el bot responde con un mensaje de bienvenida que describe todos los comandos (como una especie de menú);

Preparación

Primero, enlazaremos inmediatamente WhatsApp a nuestro script, luego, cuando escribamos el código, comprobaremos cómo funciona. Para hacer esto, vaya a su cuenta personal y obtenga un código QR allí. Luego, abra WhatsApp en su teléfono, vaya a Configuración Primero, enlazaremos inmediatamente WhatsApp a nuestro script, luego, cuando escribamos el código, verificaremos cómo funciona. Para hacer esto, vaya a su cuenta personal y obtenga un código QR allí. Luego abra WhatsApp en su teléfono, vaya a Configuración -> WhatsApp Web -> Escanee el código QR.

¡Atención!
Para que el bot funcione, el teléfono debe estar siempre conectado a Internet y no debe usarse para WhatsApp Web.

Para que nuestro bot responda a los comandos, es necesario que el bot pueda aceptar y procesar los datos recibidos. Para hacer esto, debe crear su propio servidor - Webhook e ingresar la dirección en su cuenta personal.

Un poco sobre la función de Webhook

El Webhook resuelve el problema de los retrasos en la respuesta a los mensajes recibidos. Sin él, nuestro bot tendría que preguntar constantemente al servidor sobre los datos recibidos, realizar solicitudes regulares y fijas a los servidores. Por lo tanto, tener algo de latencia en la respuesta, y esto también, contribuiría a la carga en el servidor.

Pero, si especificamos la dirección del servidor Webhook, esa necesidad ya no será relevante. Los propios servidores enviarán notificaciones de cambios recibidos tan pronto como aparezcan. Y la tarea del servidor webhook es aceptarlos y procesarlos correctamente, implementando la lógica del bot. Puede especificar un dominio y una dirección ip.

Put webhook in your personal cabinet Configurar webhook en su perfil personal

Crear su propio servidor en Java utilizando el framework Spring Boot

Para simplificar la creación de nuestra plantilla de arranque de aplicación Spring Boot, usaremos spring initializr: Configure los ajustes necesarios, seleccione la versión de Java deseada y haga clic en Generate

A continuación, debe descargar el proyecto generado y abrirlo en su IDE. Usaré Intellij IDEA. Crearemos una carpeta "controller", en la que almacenaremos nuestro controlador para procesar los datos de entrada en nuestro servidor y las clases necesarias para que el bot funcione.

Сhat-api envía datos JSON que necesitamos analizar y procesar.

Para saber qué es exactamente lo que nos llega en json, usaremos la página de prueba en la cuenta personal e iremos a la pestaña "Webhook Simulator".

JSON body - datos que llegarán a nuestro servidor (su estructura). Para trabajar cómodamente con él en Java, deserialicemos en un objeto y tratemos los datos como si fueran propiedades del objeto.

Para nuestra comodidad, usaremos el servicio para generar automáticamente Json to Java class. Copie el JSON body. Haga clic en Preview y copie las clases Java generadas automáticamente en nuestro proyecto. Para hacer esto, cree un archivo jsonserializables.java y pegue el código en el archivo.

Después de que se crea nuestra clase que describe el cuerpo JSON, procedemos con la implementación del propio controlador, que procesará los datos de entrada. Para hacer esto, cree un nuevo archivo MessageController y describa la clase MessageController en él.

@RestController
@RequestMapping("webhook")
    public class MessageController {
        @PostMapping
        public String AnswerWebhook(@RequestBody RequestWebhook hook) throws IOException {
            return  "ok";
        }

La anotación @RequestMapping("webhook") es responsable de la dirección en la que se procesará nuestro controlador. Por ejemplo: "localhost:8080/webhook"

La anotación @PostMapping significa que la función AnswerWebhook procesará las POST requests.

Al mismo tiempo, el parámetro RequestWebhook en los parámetros de la función es nuestra clase JSON deserializada, cuya deserialización es asumida por Spring Boot e inmediatamente obtenemos un objeto listo para su uso y podemos trabajar con él dentro de la propia función. En él, describiremos la lógica del bot.

La implementación de la lógica del controlador

@RestController
    @RequestMapping("webhook")
    public class MessageController {
        @PostMapping
        public String AnswerWebhook(@RequestBody RequestWebhook hook) throws IOException {
            for (var message : hook.getMessages()) {
                if (message.getFromMe())
                    continue;
                String option = message.getBody().split(" ")[0].toLowerCase();
                switch (option)
                {
                    case "chatid":
                        ApiWA.sendChatId(message.getChatId());
                        break;
                    case "file":
                        var texts = message.getBody().split(" ");
                        if (texts.length > 1)
                            ApiWA.sendFile(message.getChatId(), texts[1]);
                        break;
                    case "ogg":
                        ApiWA.sendOgg(message.getChatId());
                        break;
                    case "geo":
                        ApiWA.sendGeo(message.getChatId());
                        break;
                    case "group":
                        ApiWA.createGroup(message.getAuthor());
                        break;
                    default:
                        ApiWA.sendDefault(message.getChatId());
                        break;
                }
            }
            return  "ok";
        }

En un ciclo, revisamos todos los mensajes recibidos y los procesamos en switch. Es necesario comprobar el inicio del ciclo para que el bot no se obsesione consigo mismo. Si el mensaje proviene de sí mismo, lo omitimos y no lo procesamos.

A continuación, escribiremos el comando recibido en la variable de option. Para hacer esto, dividimos el cuerpo del mensaje usando el método split y ponemos el comando en minúsculas para que el bot responda a los comandos independientemente del caso. En switch, dependiendo del comando que venga, llamamos al método necesario de la clase ApiWA, de cuya implementación hablaremos ahora.

Clase ApiWA

Esta clase implementará métodos estáticos para llamar a la API. Dentro de la clase, describiremos las variables que almacenarán nuestro token para que podamos usar la API con éxito, pasando estos datos. Se pueden encontrar en su cuenta personal.

public class ApiWA {
        private static String APIURL = "https://eu115.chat-api.com/instance123456/";
        private static String TOKEN = "1hi0xw1fzaen1234";
    }

A continuación, necesitamos implementar un método que envíe una solicitud POST.

 public static CompletableFuture<Void> postJSON(URI uri,
                                            Map<String,String> map)
            throws IOException
    {
        ObjectMapper objectMapper = new ObjectMapper();
        String requestBody = objectMapper
                .writerWithDefaultPrettyPrinter()
                .writeValueAsString(map);

        HttpRequest request = HttpRequest.newBuilder(uri)
                .header("Content-Type", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(requestBody))
                .build();

        return HttpClient.newHttpClient()
                .sendAsync(request, HttpResponse.BodyHandlers.ofString())
                .thenApply(HttpResponse::statusCode)
                .thenAccept(System.out::println);
    }

Este método recibe en parámetros una referencia de URI para la cual se debe realizar una solicitud POST, así como un diccionario, que se serializa en una cadena JSON y se pasa al servidor.

Para implementar cada método, examinamos la documentación detallada y repetimos las solicitudes.

Este es el método para enviar chatid:

    public static void sendChatId(String chat_id) throws IOException {
        URI uri = URI.create(APIURL + "sendMessage?token=" + TOKEN);
        Map<String, String> map = new HashMap<String, String>();
        map.put("body", "Your ID: " + chat_id);
        map.put("phone", chat_id);
        ApiWA.postJSON(uri, map);
    }

Hemos formado un enlace para el que necesita realizar una solicitud y un diccionario con parámetros. Después de eso, accedemos al método para enviar una solicitud POST, que implementamos anteriormente.

En el siguiente capítulo describimos la implementación de enviar un archivo a través del chatbot de Whatsapp, y el resto de la funcionalidad, como enviar geolocalización, crear un grupo y otros comandos, se puede ver en el código fuente de nuestro bot.

Otros comandos
Otros métodos se implementan de manera similar. El código fuente puede ser descargado y visualizado en Github.

Hablaremos por separado sobre cómo aplicar el método de envío del archivo

 public static void sendFile(String chat_id, String file_format) throws IOException {
        Map<String, String> formats= new HashMap<String, String>();
        formats.put("doc", Base64Help.getDOC());
        formats.put("jpeg", Base64Help.getJPEG());
        formats.put("pdf", Base64Help.getPDFtring());
        formats.put("mp3", Base64Help.getMP3String());

        if (formats.containsKey(file_format))
        {
            Map<String, String> map = new HashMap<String, String>();
            map.put("phone", chat_id);
            map.put("body", formats.get(file_format));
            map.put("filename", "ThisIsFile");
            map.put("caption", "ThisIsCaption");
            URI uri = URI.create(APIURL + "sendFile?token=" + TOKEN);
            ApiWA.postJSON(uri, map);
        }
        else
        {
            Map<String, String> map = new HashMap<String, String>();
            map.put("phone", chat_id);
            map.put("body", "File not found");
            URI uri = URI.create(APIURL + "sendMessage?token=" + TOKEN);
            ApiWA.postJSON(uri, map);
        }
    }

Este método almacena un diccionario en el que las claves son el formato de archivo y los valores son una cadena en el formato Base64. La cadena Base64 se utiliza para transferencias de archivos. Para generar una cadena, puede utilizar el servicio en nuestro sitio web. Si el archivo con el formato deseado no está en el diccionario, enviamos un mensaje indicando que no se encontró el archivo.

Describimos la clase Base64Help y los métodos para obtener una cadena con un archivo en el formato requerido. La cadena en sí se almacena en archivos txt en el servidor y el código se acaba de leer del archivo. Esto es necesario porque Java no le permite almacenar estas cadenas largas directamente en su código. Puede generar una cadena Base64 automáticamente o utilizando servicios.

public class Base64Help {
        static public String getPDFString() throws IOException {
            return new String(Files.readAllBytes(Paths.get("src/main/resources/pdf.txt")));
        }

        static  public String getMP3String() throws IOException {
            return new String(Files.readAllBytes(Paths.get("src/main/resources/mp3.txt")));
        }

        static public String getJPEG() throws IOException {
            return new String(Files.readAllBytes(Paths.get("src/main/resources/jpeg.txt")));
        }

        static public String getDOC() throws IOException {
            return new String(Files.readAllBytes(Paths.get("src/main/resources/doc.txt")));
        }

    }

Por lo tanto, describimos el trabajo de un simple bot de Whatsapp y publicamos el código fuente con funcionalidad lista para usar en Github.

El código completo y la guía estarán disponibles en el enlace de github: https://github.com/chatapi/whatsapp-java-bot-en

tutorial de bot de chat java para whatsapp

Solo necesita reemplazar su token de cuenta personal y el número de instancia en el código.

Tutorial de chatbot de Java para Whatsapp

Ahora necesita cargar nuestro servidor junto con el bot para alojar y especificar su dominio como webhook. Por cada mensaje recibido, el servidor recibirá y procesará los datos. Si tiene alguna pregunta, ¡siempre puede comunicarse con nuestro soporte técnico!