seaswalker / posts

0 stars 0 forks source link

钉钉报警接入代码 #48

Open seaswalker opened 3 years ago

seaswalker commented 3 years ago
@Service
@Slf4j
public class DingTalkUtil {

    @Value("${dingTalk.robot.url}")
    private String robotUrl;
    @Value("${dingTalk.robot.me}")
    private String me;
    // 钉钉密钥
    @Value("${dingTalk.robot.secret}")
    private String secret;
    @Value("${dingTalk.enabled}")
    private Boolean enabled;

    private OkHttpClient okHttpClient;

    private static final ObjectMapper objectMapper = new ObjectMapper();
    private static final MediaType jsonMediaType = MediaType.parse("application/json");

    @PostConstruct
    public void init() {
        ExecutorService executorService = new ThreadPoolExecutor(
                1,
                5,
                1,
                TimeUnit.MINUTES,
                new ArrayBlockingQueue<>(100),
                ThreadFactoryBuilder.create().setNamePrefix("dingTalk-").build(),
                new ThreadPoolExecutor.CallerRunsPolicy()
        );
        Dispatcher dispatcher = new Dispatcher(executorService);
        dispatcher.setMaxRequests(5);
        dispatcher.setMaxRequestsPerHost(5);
        okHttpClient = new OkHttpClient.Builder()
                .readTimeout(Duration.ofSeconds(1))
                .connectTimeout(Duration.ofSeconds(1))
                .callTimeout(Duration.ofSeconds(1))
                .writeTimeout(Duration.ofSeconds(1))
                .dispatcher(dispatcher)
                .build();
    }

    /**
     * 异步发送钉钉机器人文本消息.
     */
    public void sendTextMessage(String content) {
        doSendTextMessage(content, textMessage -> {
        });
    }

    /**
     * 异步发送文本消息并@自己.
     */
    public void sendTextMessageWithAtMe(String content) {
        doSendTextMessage(content, textMessage -> textMessage.getAt().getAtMobiles().add(me));
    }

    /**
     * 异步发送文本消息并@所有人.
     */
    public void sendTextMessageWithAtAll(String content) {
        doSendTextMessage(content, textMessage -> textMessage.getAt().setAtAll(true));
    }

    private void doSendTextMessage(String content, Consumer<TextMessage> messageConfigurator) {
        if (!enabled) {
            return;
        }

        if (StringUtils.isBlank(content)) {
            throw new IllegalArgumentException("文本消息内容不能为空");
        }

        TextMessage textMessage = new TextMessage();
        textMessage.setText(new TextMessage.Content(content));
        messageConfigurator.accept(textMessage);
        long timestamp = System.currentTimeMillis();
        String sign = sign(timestamp);

        try {
            Request request = new Request.Builder()
                    .url((robotUrl + "&timestamp=" + timestamp + "&sign=" + sign))
                    .post(RequestBody.create(objectMapper.writeValueAsString(textMessage), jsonMediaType))
                    .build();
            Call call = okHttpClient.newCall(request);
            call.enqueue(new Callback() {
                @Override
                public void onFailure(@NotNull Call call, @NotNull IOException e) {
                    log.error("发送钉钉消息失败, 请求: {}.", call, e);
                }

                @Override
                public void onResponse(@NotNull Call call, @NotNull Response response) {
                    ResponseBody responseBody = response.body();
                    log.debug("钉钉发送成功, call: {}, resp: {}.", call.request().body(), responseBody);
                    if (responseBody != null) responseBody.close();
                }
            });
        } catch (JsonProcessingException e) {
            throw ExceptionUtil.wrapRuntime(e);
        }
    }

    private String sign(long timestamp) {
        final String seed = (timestamp + "\n" + secret);
        try {
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
            byte[] result = mac.doFinal(seed.getBytes(StandardCharsets.UTF_8));
            return URLEncoder.encode(Base64.getEncoder().encodeToString(result), StandardCharsets.UTF_8.displayName());
        } catch (NoSuchAlgorithmException | InvalidKeyException | UnsupportedEncodingException e) {
            throw ExceptionUtil.wrapRuntime(e);
        }
    }

    @Getter
    private static class TextMessage {

        private final String msgtype = "text";
        @Setter
        private Content text;
        private final At at = new At();

        @Data
        @AllArgsConstructor
        private static class Content {
            private String content;
        }

        private static class At {
            @Setter
            private boolean isAtAll = false;
            @Getter
            private final List<String> atMobiles = new LinkedList<>();
            // 不能删除,否则会导致生成的json字段名是atAll, 导致@所有人不生效
            public boolean getIsAtAll() {
                return isAtAll;
            }
        }
    }
}