LINE Messaging API　メッセージ送信方法

Spring Boot と Java を使用して、LINE Messaging API の Webhook でメッセージを送信するサンプルソース。このサンプルでは SDK を使用しません。

まず、必要な依存関係を `pom.xml` に追加します：

```xml
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
    </dependency>
</dependencies>
```

次に、Webhook を処理するコントローラーを作成します：

```java
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Collections;

@RestController
public class LineWebhookController {

    @Value("${line.bot.channel-secret}")
    private String channelSecret;

    @Value("${line.bot.channel-token}")
    private String channelToken;

    private static final String LINE_API_URL = "https://api.line.me/v2/bot/message/reply";

    @PostMapping("/webhook")
    public ResponseEntity<String> handleWebhook(@RequestBody String payload,
                                                @RequestHeader("X-Line-Signature") String signature) {
        if (verifySignature(payload, signature)) {
            try {
                ObjectMapper objectMapper = new ObjectMapper();
                JsonNode jsonNode = objectMapper.readTree(payload);
                String replyToken = jsonNode.path("events").get(0).path("replyToken").asText();
                String messageText = jsonNode.path("events").get(0).path("message").path("text").asText();

                sendReplyMessage(replyToken, "You said: " + messageText);
                return ResponseEntity.ok("OK");
            } catch (Exception e) {
                e.printStackTrace();
                return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error processing webhook");
            }
        } else {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid signature");
        }
    }

    private boolean verifySignature(String payload, String signature) {
        try {
            Mac mac = Mac.getInstance("HmacSHA256");
            SecretKeySpec secretKeySpec = new SecretKeySpec(channelSecret.getBytes(), "HmacSHA256");
            mac.init(secretKeySpec);
            byte[] hash = mac.doFinal(payload.getBytes(StandardCharsets.UTF_8));
            String encodedHash = Base64.getEncoder().encodeToString(hash);
            return encodedHash.equals(signature);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    private void sendReplyMessage(String replyToken, String message) {
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        headers.set("Content-Type", "application/json");
        headers.set("Authorization", "Bearer " + channelToken);

        String body = String.format(
            "{\"replyToken\":\"%s\",\"messages\":[{\"type\":\"text\",\"text\":\"%s\"}]}",
            replyToken, message);

        HttpEntity<String> request = new HttpEntity<>(body, headers);
        restTemplate.postForObject(LINE_API_URL, request, String.class);
    }
}
```

最後に、`application.properties` ファイルに LINE チャンネルのシークレットとトークンを設定します：

```
line.bot.channel-secret=YOUR_CHANNEL_SECRET
line.bot.channel-token=YOUR_CHANNEL_TOKEN
```

このサンプルコードでは、以下の機能を実装しています：

1. Webhook エンドポイント (`/webhook`) を作成し、POST リクエストを処理します。
2. 受信したペイロードの署名を検証します。
3. 受信したメッセージを解析し、送信者のメッセージを抽出します。
4. LINE Messaging API を使用して、オウム返しのメッセージを送信します。

このコードを実行するには、LINE Developers コンソールで Webhook URL を設定し、チャンネルシークレットとチャンネルトークンを `application.properties` ファイルに設定する必要があります[1][2][7]。

Citations:
[1] https://f-code.co.jp/blog/line/line_messaging_api/
[2] https://developers.line.biz/ja/docs/messaging-api/nodejs-sample/
[3] https://kikutaro777.hatenablog.com/entry/2017/01/16/230122
[4] https://qiita.com/blue_islands/items/582db1f8354aadea4f70
[5] https://qiita.com/Esfahan/items/25d74247778c87454634
[6] https://www.grandream.jp/blog/line-webhook-with-chat
[7] https://zenn.dev/otkshol/articles/52d2649c6fa4dc
[8] https://lineapiusecase.com/ja/api/webhook.html
[9] https://blog.socialplus.jp/knowledge/line-webhook/
[10] https://techblog.a-tm.co.jp/entry/2022/11/28/104359
[11] https://www.divx.co.jp/media/techblog-231220-02
[12] https://kotovuki.co.jp/archives/18481
[13] https://www.higutthiengineer.com/2024/02/11/lineapimessaging-apiphp-sdk/
[14] https://zenn.dev/mochan_tk/articles/9f142bb1051c55
[15] https://developers.line.biz/ja/docs/messaging-api/sending-messages/
[16] https://udemy.benesse.co.jp/development/app/line-bot-making.html
[17] https://github.com/ryo-tsurusaki/line-bot-api