Créer un SlackBot avec AWS lambda et API Gateway en Java

introduction

Lors de la création d'un robot slack, je pense que j'utiliserai Python ou Node.js dans la plupart des cas, mais cette fois j'oserai aller avec Java. Je n'ai pas trouvé d'article sur la création d'un robot slack sans serveur via AWS avec Java en japonais ou en anglais, je vais donc écrire la procédure de mise en œuvre ici. Je suis un amateur de Java, il vaut donc mieux faire ça! Je vous serais reconnaissant de bien vouloir souligner certains points. Le code entier est sur github https://github.com/kamata1729/sampleSlackBotWithJava

Créer un bot slack

Créer une application pour créer un bot

Tout d'abord, créons un Slack Bot! https://api.slack.com/apps À partir de là, appuyez sur Créer une nouvelle application pour créer une nouvelle application. image.png

Et ajoutez un utilisateur bot à l'application créée image.png

Créer un point de terminaison pour recevoir les événements Slack

À partir de là, nous allons créer un point de terminaison pour recevoir les événements de Slack sur AWS. Plus précisément, API Gateway reçoit l'événement et le transmet à la fonction lambda.

Créer un rôle IAM

Ouvrez IAM à partir de la console AWS et créez un nouveau rôle. image.png

Puisqu'il sera utilisé dans lambda, sélectionnez "lambda" et procédez d'abord. image.png

Cette fois, je veux pouvoir sortir le journal dans CloudWatch Log, donc sélectionnez ʻAWS LambdaBasicExecutionRoleavec l'autorisation d'écriture image.png

Je ne vais pas l'utiliser cette fois pour créer la prochaine balise, vous pouvez donc l'ignorer. Sur l'écran de confirmation suivant, donnez un nom de rôle et vous avez terminé! Cette fois, je l'ai nommé «sampleBotRole». image.png

Créer une fonction lambda

Accédez maintenant à la console lambda et choisissez de créer une fonction. Sélectionnez «Créer à partir de zéro», cette fois sélectionnez «sampleBot» pour le nom de la fonction et «java 8» pour le runtime. De plus, pour le rôle, j'ai sélectionné le sampleBotRole créé plus tôt. image.png

Créer une passerelle API

Tout d'abord, sélectionnez «Créer une API» sur la page API Gateway de la console aws et créez-la avec le nom de l'API («sampleBotAPI» cette fois). image.png Depuis l'écran créé, sélectionnez ʻAction-> Create Method pour ajouter la méthode POST. ![image.png](https://qiita-image-store.s3.amazonaws.com/0/262908/12a7ec34-251a-41eb-e776-0d000634d735.png) Appuyez sur la coche pour créer une méthode POST, définissez-la pour qu'elle corresponde à la fonction lambda créée précédemment sur l'écran de configuration et enregistrez-la. ![image.png](https://qiita-image-store.s3.amazonaws.com/0/262908/3f5da402-3d95-0c7a-7461-91b6cc428eb4.png) Sur l'écran suivant, sélectionnez ʻAction-> Deploy API et entrez le nom de l'étape à déployer. À ce stade, l'URL pour appeler le point de terminaison sera affichée en haut de l'écran, alors notez-la. Ceci termine la création du point final! image.png

À propos de l'authentification de l'API Slack Event

Avant d'implémenter la fonction lambda, parlons de l'authentification de l'API d'événement slack. Avec l'API d'événement slack, vous devez d'abord renvoyer une chaîne spécifique pour voir si le programme est destiné à l'API d'événement.

Pour l'authentification, le json suivant est d'abord envoyé.

{
    "token": "Jhj5dZrVaK7ZwHHjRyZWjbDl",
    "challenge": "3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P",
    "type": "url_verification"
}

En revanche, si le contenu de «challenge» peut être renvoyé dans les 3 secondes, l'authentification est terminée. Il existe trois formats de renvoi. Pour plus de détails, veuillez consulter https://api.slack.com/events/url_verification.

HTTP 200 OK
Content-type: text/plain
3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P
HTTP 200 OK
Content-type: application/x-www-form-urlencoded
challenge=3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P
HTTP 200 OK
Content-type: application/json
{"challenge":"3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P"}

À propos des entrées / sorties d'AWS lambda

Lors de la définition des E / S AWS lambda en Java, vous devez implémenter une implémentation de gestionnaire, ce qui peut être effectué de trois manières. Je vais l'écrire brièvement ici, mais voir ci-dessous pour plus de détails https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/java-programming-model-handler-types.html https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/java-handler-using-predefined-interfaces.html

1. Chargez directement la méthode du gestionnaire

Il utilise les types implémentés par défaut sans définir de types d'entrée / sortie spéciaux. Mettre en œuvre comme suit


outputType handler-name(inputType input, Context context) {
   ...
}

Il semble que ʻinputType, ʻoutputType de ceci prennent en charge le type de chaîne, le type entier, le type booléen, le type de carte et le type de liste par défaut. (Voir ci-dessous pour plus de détails https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/java-programming-model-req-resp.html)

Par exemple, l'implémentation suivante est possible

package example;

import com.amazonaws.services.lambda.runtime.Context; 

public class Hello {
    public String myHandler(String name, Context context) {
        return String.format("Hello %s.", name);
    }
}

2. Utilisez le type POJO

Si vous souhaitez spécifier votre propre type pour ʻinputType et ʻoutputType, vous pouvez également définir et utiliser le type qui correspond au format d'entrée / sortie.

Cela peut être mis en œuvre comme suit:

package example;

import com.amazonaws.services.lambda.runtime.Context; 

public class HelloPojo {

    // Define two classes/POJOs for use with Lambda function.
    public static class RequestClass {
      ...
    }

    public static class ResponseClass {
      ...
    }

    public static ResponseClass myHandler(RequestClass request, Context context) {
        String greetingString = String.format("Hello %s, %s.", request.getFirstName(), request.getLastName());
        return new ResponseClass(greetingString);
    }
}

3. Utilisez RequestStreamHandler

Il existe également un moyen d'activer n'importe quelle entrée et sortie en utilisant ʻInputStream et ʻOutputStream. Vous pouvez répondre en écrivant une chaîne d'octets dans ʻOutputStream`. Un exemple est un programme qui met en majuscule une chaîne donnée et la renvoie.

package example;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
import com.amazonaws.services.lambda.runtime.Context; 

public class Hello implements RequestStreamHandler {
    // if input is "test", then return "TEST"
    public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context)
            throws IOException {
        int letter;
        while((letter = inputStream.read()) != -1)
        {
            outputStream.write(Character.toUpperCase(letter));
        }
    }
}

Cette fois, il est difficile de recevoir des jsons imbriqués de type POJO, je vais donc utiliser RequestStreamHandler.

Rendre la fonction lambda compatible avec l'authentification slack

Sur la base de ce qui précède, nous coderons la fonction lambda, mais contrairement à python, etc., dans le cas de Java, le code ne peut pas être édité en ligne. Par conséquent, cette fois, je vais créer un projet java avec maven local et le télécharger dans un zip en utilisant gradle.

Créer un projet

Commencez par créer un projet avec maven. (Maven est utilisé uniquement pour créer un projet, donc peu importe si vous le créez d'une autre manière.)

$ mvn archetype:generate

On vous demandera peut-être beaucoup de choses en chemin, mais à l'exception de groupId et ʻartifactId, vous pouvez entrer. Cette fois, groupId est jp.com.hoge, et ʻartifactId est SampleBot. Une fois exécuté, un dossier avec le nom du projet sera créé et src / main / java / jp / com / hoge / App.java sera généré.

Modification de App.java

Modifiez App.java comme suit. Même si vous ne parvenez pas à obtenir le contenu de challenge, si vous ne renvoyez pas de chaîne de caractères, cela sera considéré comme un timeout et l'événement sera renvoyé après 1 minute et 5 minutes, donc pour le moment" OK Je répondrai par ".

src/main/java/jp/com/hoge/App.java


package jp.com.hoge;

import java.io.*;
import java.net.URLEncoder;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.lang.StringBuilder;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONArray;

import com.amazonaws.services.lambda.runtime.*;

public class App implements RequestStreamHandler
{
    @Override
    public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
        //Réponse par défaut Si vous ne répondez rien, le même événement sera envoyé plusieurs fois
        String response = "HTTP 200 OK\nContent-type: text/plain\nOK";
        try{
            BufferedReader rd = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8"))); 
            String jsonText = readAll(rd);
            System.out.println(jsonText); //System.La sortie de out est écrite dans CloudWatch Logs
            JSONObject json = new JSONObject(jsonText);
            if (json.has("type")) {
                String eventType = json.get("type").toString();
                if (eventType.equals("url_verification")) {
                    //Définir le contenu du défi à la réponse
                    response = "HTTP 200 OK\nContent-type: text/plain\n" + json.get("challenge").toString();
                }
            }
        } catch(IOException e) {
            e.printStackTrace();
        } finally {
            //Ecrire le contenu de la réponse dans outputStream
            outputStream.write(response.getBytes());
            outputStream.flush();
            outputStream.close();
        }
        return;
    }

    /* get String from BufferedReader */
    private static String readAll(Reader rd) throws IOException {
        StringBuilder sb = new StringBuilder();
        int cp;
        while ((cp = rd.read()) != -1) {
            sb.append((char) cp);
        }
        return sb.toString();
    }
}

Modifier build.gradle

De plus, placez build.gradle directement sous le dossier du projet. Si vous avez d'autres bibliothèques que vous souhaitez utiliser, vous pouvez les écrire dans les dépendances ou créer un dossier lib et y placer le fichier .jar.

build.gradle


apply plugin: 'java'

repositories {
    mavenCentral()
}

dependencies {
    compile (
        'com.amazonaws:aws-lambda-java-core:1.1.0',
        'com.amazonaws:aws-lambda-java-events:1.1.0',
        'org.json:json:20180813'
    )
    testCompile 'junit:junit:4.+'
}

task buildZip(type: Zip) {
    from compileJava
    from processResources              
    into('lib') {
        from configurations.compileClasspath
    }           
}

build.dependsOn buildZip

Construire avec Gradle

À ce stade, exécutez ce qui suit directement sous le dossier du projet à générer.

$ gradle build

Si la construction réussit, build / distribution / SampleBot.zip doit être généré.

Tester l'exécution de la fonction lambda

Ouvrez la console AWS lambda et téléchargez le SampleBot.zip que vous venez de créer. Entrez jp.com.hoge.App dans le gestionnaire et n'oubliez pas de l'enregistrer. image.png

Exécuter un événement de test

Testons d'abord la fonction lambda. Sélectionnez "Créer un événement de test" à partir de la flèche vers le bas dans la zone qui dit "Sélectionner un événement de test ..." en haut à droite de l'écran, et créez-le comme indiqué dans la figure ci-dessous.

image.png

Cliquez sur le bouton "Test" en haut à droite de l'écran pour exécuter le test. En cas de succès, le résultat de l'exécution sera affiché et si vous appuyez sur «Détails», il apparaîtra comme indiqué ci-dessous. Vous pouvez voir que la sortie est faite correctement image.png

En regardant CloudWatch, le contenu de la sortie inputStream sous forme de journal est affiché. image.png

Abonnez-vous à l'API Slack Event

À ce stade, vous pouvez enfin vous abonner à l'API Slack Event! Sélectionnez "Abonnements aux événements" sur le côté gauche de la page lorsque vous avez créé le bot image.png Activez l'option Activer les événements et entrez l'URL que vous avez notée lors du déploiement de l'API dans le champ URL de la demande. Une fois la réponse confirmée, elle ressemblera à celle ci-dessous et vous pourrez vous abonner aux événements! image.png

Cette fois, recevons un événement appelé ʻapp_mention`. Il s'agit d'un événement qui réagit lorsqu'un bot est mentionné avec un @. Appuyez sur "Oublier les modifications enregistrées" une fois ajoutées image.png

installation de bot

Ensuite, installez le bot dans l'espace de travail Sélectionnez "OAuth & Permissions" et faites défiler vers le bas jusqu'au menu appelé Scopes. Sélectionnez "Send messages as SampleBot" et "Save Changes". Vous pouvez maintenant envoyer un message sous forme de SampleBot. image.png

Ensuite, installez avec "Install App to Workspace". ʻOAuth Access TokenetBot User OAuth Access Token` sont affichés, alors notez-les également. image.png

Faire un robot de retour de perroquet

À partir de là, je vais créer un exemple de Bot qui répond à une déclaration qui m'est adressée en renvoyant un perroquet. Le code source complet est publié sur github https://github.com/kamata1729/sampleSlackBotWithJava

ʻApp_mention` L'événement est envoyé comme suit.

{
    "token": "ZZZZZZWSxiZZZ2yIvs3peJ",
    "team_id": "T061EG9R6",
    "api_app_id": "A0MDYCDME",
    "event": {
        "type": "app_mention",
        "user": "U061F7AUR",
        "text": "What is the hour of the pearl, <@U0LAN0Z89>?",
        "ts": "1515449522.000016",
        "channel": "C0LAN2Q65",
        "event_ts": "1515449522000016"
    },
    "type": "event_callback",
    "event_id": "Ev0LAN670R",
    "event_time": 1515449522000016,
    "authed_users": [
        "U0LAN0Z89"
    ]
}

D'autre part, sur le même canal, créez un Bot qui publie `` Quelle est l'heure de la perle, <@ U061F7AUR>? '' `Avec la mention changée en nom d'utilisateur de l'autre utilisateur.

Obtenir l'ID utilisateur du bot

Nous devons remplacer l'ID utilisateur dans le texte, donc obtenez l'ID utilisateur du bot. Tout d'abord, obtenez le jeton d'espace waork parmi les éléments suivants. https://api.slack.com/custom-integrations/legacy-tokens Utilisez ce jeton pour accéder à l'url suivante, obtenir l'ID du samplebot et en prendre note. Une chaîne commençant par un U supérieur. https://slack.com/api/users.list?token=取得したtoken

Enregistrement des variables d'environnement

Je l'ai noté en tant que variable d'environnement sur la page AWS lambda,

Enregistrez les trois. Vous pouvez maintenant le récupérer à partir de la méthode System.getenv. image.png

Publier un message à l'aide de l'API chat.postMessage

Vous pouvez publier un message en lançant JSON dans l'API chat.postMessage. Le json à ce moment-là est envoyé de cette manière.

{
    "token": SLACK_APP_AUTH_TOKEN,
    "channel": channel,
    "text": message,
    "username": "sampleBot"
}

À ce moment-là, en tant que propriété de demande " Content-Type ":" application / json; charset = UTF-8 ", "Authorization": "Bearer " + SLACK_BOT_USER_ACCESS_TOKEN Doit être réglé.

Sur la base de ce qui précède, j'ai modifié App.java comme suit.

App.java


package jp.com.hoge;

import java.io.*;
import java.net.URLEncoder;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.URL;
import java.nio.charset.Charset;
import java.lang.StringBuilder;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONArray;

import com.amazonaws.services.lambda.runtime.*;

public class App implements RequestStreamHandler
{
    public static String SLACK_BOT_USER_ACCESS_TOKEN = "";
    public static String SLACK_APP_AUTH_TOKEN = "";
    public static String USER_ID = "";

    @Override
    public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
        //Lecture des variables d'environnement
        App.SLACK_BOT_USER_ACCESS_TOKEN = System.getenv("SLACK_BOT_USER_ACCESS_TOKEN");
        App.SLACK_APP_AUTH_TOKEN = System.getenv("SLACK_APP_AUTH_TOKEN");
        App.USER_ID = System.getenv("USER_ID");

        //Réponse par défaut Si vous ne répondez rien, le même événement sera envoyé plusieurs fois
        String response = "HTTP 200 OK\nContent-type: text/plain\nOK";
        try{
            BufferedReader rd = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8"))); 
            String jsonText = readAll(rd);
            System.out.println(jsonText); //System.La sortie de out est écrite dans CloudWatch Logs
            JSONObject json = new JSONObject(jsonText);

            //Lors du test de l'API d'événement
            if (json.has("type")) {
                String eventType = json.get("type").toString();
                if (eventType.equals("url_verification")) {
                    //Définir le contenu du défi à la réponse
                    response = "HTTP 200 OK\nContent-type: text/plain\n" + json.get("challenge").toString();
                }
            }
            
            // app_Au moment de l'événement de mention
            if (json.has("event")) {
                JSONObject eventObject = json.getJSONObject("event");
                if(eventObject.has("type")) {
                    String eventType = eventObject.get("type").toString();
                    if (eventType.equals("app_mention")){
                        String user = eventObject.get("user").toString();
                        if (user.equals(App.USER_ID)) { return; } //Ignorer si l'instruction est l'utilisateur du bot lui-même
                        String channel = eventObject.get("channel").toString();
                        String text = eventObject.get("text").toString();
                        String responseText = text.replace(App.USER_ID, user);
                        System.out.println(responseText);
                        System.out.println(postMessage(responseText, channel));
                    }
                }
            }       
        } catch(IOException e) {
            e.printStackTrace();
        } finally {
            //Ecrire le contenu de la réponse dans outputStream
            outputStream.write(response.getBytes());
            outputStream.flush();
            outputStream.close();
        }
        return;
    }

    /* get String from BufferedReader */
    private static String readAll(Reader rd) throws IOException {
        StringBuilder sb = new StringBuilder();
        int cp;
        while ((cp = rd.read()) != -1) {
            sb.append((char) cp);
        }
        return sb.toString();
    }

    /* post message to selected channel */
    public static String postMessage(String message, String channel) {
        String strUrl = "https://slack.com/api/chat.postMessage";
        String ret = "";
        URL url;

        HttpURLConnection urlConnection = null;
        try {
            url = new URL(strUrl);
            urlConnection = (HttpURLConnection) url.openConnection();
        } catch(IOException e) {
            e.printStackTrace();
            return "IOException";
        }
        
        urlConnection.setDoOutput(true);
        urlConnection.setConnectTimeout(100000);
        urlConnection.setReadTimeout(100000);
        urlConnection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
        String auth = "Bearer " + App.SLACK_BOT_USER_ACCESS_TOKEN;
        urlConnection.setRequestProperty("Authorization", auth);

        try {
            urlConnection.setRequestMethod("POST");
        } catch(ProtocolException e) {
            e.printStackTrace();
            return "ProtocolException";
        }

        try {
            urlConnection.connect();
        } catch(IOException e) {
            e.printStackTrace();
            return "IOException";
        }

        HashMap<String, Object> jsonMap = new HashMap<>();
        jsonMap.put("token", App.SLACK_APP_AUTH_TOKEN);
        jsonMap.put("channel", channel);
        jsonMap.put("text", message);
        jsonMap.put("username", " sampleBot");

        OutputStream outputStream = null;
        try {
            outputStream = urlConnection.getOutputStream();
        } catch(IOException e) {
            e.printStackTrace();
            return "IOException";
        }

        if (jsonMap.size() > 0) {
            JSONObject responseJsonObject = new JSONObject(jsonMap);
            String jsonText = responseJsonObject.toString();
            PrintStream ps = new PrintStream(outputStream);
            ps.print(jsonText);
            ps.close();
        }

        try {
            if (outputStream != null) {
                outputStream.close();
            }
            int responseCode = urlConnection.getResponseCode();
            BufferedReader rd = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "UTF-8"));
            ret = readAll(rd);
        } catch(IOException e) {
            e.printStackTrace();
            return "IOException";
        
        } finally {
            if (urlConnection != null) {
                urlConnection.disconnect();
            }         
        }
        return ret;
    }
}

Téléchargez-le simplement avec gradle build comme avant et vous avez terminé!

État de fonctionnement

Jusqu'à présent, nous avons quelque chose qui fonctionne réellement. Mais il y a encore des écueils. En effet, le délai d'expiration du délai n'est que de 3 secondes, donc si vous incluez le temps de démarrage de la fonction lambda, il expirera rapidement de manière inattendue!

Succès

Cela fonctionne comme prévu sans délai. samplebot.gif

Exemple d'échec

C'est le résultat de son déplacement après un certain temps. Le délai d'expiration est écoulé, probablement parce que la fonction lambda doit être redémarrée. Puisque ** slack l'a jugé comme une erreur et a renvoyé l'événement plusieurs fois **, la fonction lambda a été appelée plusieurs fois et publiée plusieurs fois. samplebot2.gif

Solution

Cela fait longtemps jusqu'à présent, je vais donc vous expliquer comment résoudre ce problème dans le prochain article. S'il vous plaît voir cela aussi [AWS lambda] Empêcher Slack Bot de répondre plusieurs fois avec des délais d'expiration

Recommended Posts

Créer un SlackBot avec AWS lambda et API Gateway en Java
Implémenter l'autorisation API Gateway Lambda dans Java Lambda
Créer un CSR avec des informations étendues en Java
Je ne peux pas créer une classe Java avec un nom spécifique dans IntelliJ
Créer un programme périodique avec Ruby x AWS Lambda x CloudWatch Events
AWS Lambda (Lambda) Partie 1 avec Java pour démarrer maintenant
Créer une application TODO dans Java 7 Créer un en-tête
Diviser une chaîne avec ". (Dot)" en Java
Gérez d'énormes JSON avec Java Lambda
Avec [AWS] CodeStar, vous pouvez créer un projet Spring (Java) s'exécutant sur Lambda en seulement 3 minutes! !!
J'ai écrit une fonction Lambda en Java et l'ai déployée avec SAM
Je veux ForEach un tableau avec une expression Lambda en Java
Interagir avec l'API de message LINE à l'aide de Lambda (Java)
Lire une chaîne dans un fichier PDF avec Java
Créez un tableau d'affichage simple avec Java + MySQL
[Windows] [IntelliJ] [Java] [Tomcat] Créer un environnement pour Tomcat 9 avec IntelliJ
Créons un processus chronométré avec la minuterie de Java! !!
[Java] Créez quelque chose comme une API de recherche de produits
Essayez de créer un babillard en Java
Comment utiliser le framework Java avec AWS Lambda! ??
[Java] Créer une collection avec un seul élément
Créons un framework Web ultra-simple avec Java
Comment utiliser l'API Java avec des expressions lambda
Créer un serveur API Web avec Spring Boot
Faisons une application de calculatrice avec Java ~ Créez une zone d'affichage dans la fenêtre
Valider le jeton d'ID d'un utilisateur authentifié par AWS Cognito en Java
API Zabbix en Java
Créer JSON en Java
Soumettre une tâche à AWS Batch avec Java (Eclipse)
Comment déployer Java sur AWS Lambda avec Serverless Framework
[Débutant] Créez un jeu compétitif avec des connaissances de base sur Java
J'ai essayé de créer une compétence Clova en Java
Comment créer un URI de données (base64) en Java
Implémentez rapidement singleton avec enum en Java
[Note] Créez un environnement Java à partir de zéro avec docker
Sortie true avec if (a == 1 && a == 2 && a == 3) en Java (identifiant invisible)
Écrivons une fonction Lambda qui intègre Amazon API Gateway à Spring Cloud Function.
Créons une application TODO en Java 11 Gestion des exceptions lors de l'accès à un TODO avec un ID inexistant
Utiliser des couches Lambda avec Java
J'ai essayé de créer un environnement de développement java8 avec Chocolatey
Créer une API XML-RPC avec Wicket
Publiez régulièrement des images de tweets sur Twitter avec AWS Lambda + Java
Agrégation et analyse de journaux (utilisation d'AWS Athena en Java)
Gérez les exceptions avec fraîcheur avec les expressions lambda Java 8 et l'API Stream
API Java Stream en 5 minutes
[Java] Créer un fichier temporaire
Créez un terrain de jeu avec Xcode 12
Créer des fonctions Azure en Java
Créer une méthode pour renvoyer le taux de taxe en Java
Même en Java, je veux afficher true avec un == 1 && a == 2 && a == 3
Créez AWS Lambda avec Quarkus
Générer AWS Signature V4 en Java et demander l'API
Créez un serveur Web simple avec la bibliothèque standard Java com.sun.net.httpserver
Créons une application TODO en Java 4 Implémentation de la fonction de publication