编辑代码

package org.linxidev.utils;

import com.alibaba.fastjson2.JSONObject;
import lombok.Data;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.mail.Address;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: 林夕
 * @Date: 2025/6/16
 * @Description: 发送通知工具类
 */
public class NoticeUtils {

    /**
     * 邮件配置信息
     */
    @Data
    private static class EmailConfig {
        private String host;
        private String port;
        private String username;
        private String password;
        private String auth;
        private String protocol;
        private String debug;
        private String sslEnable;
    }

    /**
     * 钉钉配置信息
     */
    @Data
    private static class DingTalkConfig {
        private String host;
        private String secret;
    }

    /**
     * 配置信息
     */
    private static EmailConfig emailConfig;
    private static DingTalkConfig dingTalkConfig;

    /**
     * 发送邮件接口
     * @param title
     * @param content
     * @param toUsers
     * @return
     */
    public static String sendEmail(String title, String content, List<String> toUsers) {
        checkEmailConfig();
        // 设置邮件服务器信息
        Properties props = new Properties();
        props.setProperty("mail.smtp.host", emailConfig.host);
        props.setProperty("mail.smtp.port", emailConfig.port);
        props.setProperty("mail.smtp.auth", emailConfig.auth);
        props.put("mail.smtp.ssl.enable", emailConfig.sslEnable);
        props.put("mail.smtp.debug", emailConfig.debug);
        props.put("mail.transport.protocol",emailConfig.protocol);
        Session session = Session.getInstance(props);
        Message message = new MimeMessage(session);
        try {
            message.setFrom(new InternetAddress(emailConfig.username, "告警通知平台", "UTF-8"));
            Address[] addresses = toUsers.stream().map(email -> {try { return new InternetAddress(email); } catch (AddressException e) {}return null;}).filter(java.util.Objects::nonNull).toArray(Address[]::new);
            message.setRecipients(Message.RecipientType.TO, addresses);
            message.setSubject(title);
            String body = "<!DOCTYPE html><html xmlns:th=\"http://www.thymeleaf.org\"><head><meta charset=\"utf-8\"><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\"><meta name=\"description\" content=\"email code\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><style>/* 默认样式 */table.main-table { width: 50%; height: 100%; margin: 0px auto; text-align: left; position: relative; border-radius: 5px; font-size: 14px; font-family: '微软雅黑', '黑体', Arial, sans-serif; line-height: 1.5; box-shadow: rgb(153, 153, 153) 0px 0px 5px; border-collapse: collapse; background-color: #fff;}/* 媒体查询,适用于手机端 */@media only screen and (max-width: 600px) { table.main-table { width: 100% !important; /* 使用!important提高优先级 */ }}</style></head><body><div style=\"background-color:#fff; padding: 0px;\"><table class=\"main-table\" cellpadding=\"0\" align=\"center\"><tbody><tr><th valign=\"middle\" style=\"height: 25px; line-height: 25px; padding: 15px 35px; border-bottom: 1px solid RGB(148,0,211); background-color: #3A71E6; border-top-left-radius: 5px; border-top-right-radius: 5px;\"><font face=\"微软雅黑\" size=\"5\" style=\"color: rgb(255, 255, 255); \">"+title+"</font></th></tr><tr><td style=\"word-break:break-all\"><div style=\"padding:25px 35px 40px; background-color:#fff;opacity:0.8;\"><h2 style=\"margin: 5px 0px; \"><font color=\"#333333\" style=\"line-height: 20px; \"><font style=\"line-height: 22px; \" size=\"4\">尊敬的用户:</font></font></h2><p>"+content+"</p><br><div style=\"width:100%;margin:0 auto;\"><div style=\"padding:10px 10px 0;border-top:1px solid #ccc;color:#747474;margin-bottom:20px;line-height:1.3em;font-size:12px;\"><p>林夕科技团队</p><p>联系我们:linxi@linxi.tk</p><p>此为系统邮件,请勿回复<br>Please do not reply to this system email</p></div></div></div></td></tr></tbody></table></div></body></html>";
            message.setContent(body,"text/html;charset=UTF-8");
            Transport transport = session.getTransport();
            transport.connect(emailConfig.username, emailConfig.password);
            transport.sendMessage(message, message.getAllRecipients());
            transport.close();
            return "邮件通知: 成功!";
        } catch (Exception e) {
            return "邮件通知: 异常 "+e.getMessage();
        }
    }

    /**
     * 钉钉发送接口
     * @param title
     * @param content
     * @param toUsers
     */
    public static String sendDingTalk(String title, String content, List<String> toUsers,boolean isAtAll) {
        checkDingTalkConfig();
        JSONObject json = new JSONObject();
        json.put("msgtype", "text");
        json.put("text", new JSONObject().fluentPut("content", title + ":\n" +content));
        json.put("at", new JSONObject().fluentPut("atMobiles", toUsers).fluentPut("isAtAll", isAtAll));
        //  获取时间戳
        long timestamp = System.currentTimeMillis();
        try {
            String sign = dingSign(timestamp,dingTalkConfig.secret);
            Map<String, String> headers = new HashMap<>();
            headers.put("Content-Type", "application/json");
            String response = HttpsUtils.urlSend(dingTalkConfig.host + "&timestamp=" + timestamp + "&sign=" + sign, "POST", false, json.toString(),headers);
            JSONObject object = JSONObject.parseObject(response);
            if (object.getInteger("errcode") == 0){
                return "钉钉通知: 成功 " + object.getString("errmsg");
            }
            return "钉钉通知: 失败" + object.getString("errmsg");
        } catch (Exception e) {
            return "钉钉通知: 异常 " + e.getMessage();
        }
    }

    /**
     * DingTalk 签名计算
     * @param timestamp 时间戳
     * @param secret 密钥
     */
    public static String dingSign(long timestamp, String secret) throws Exception {
        String stringToSign = timestamp + "\n" + secret;
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
        byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));
        String base64Sign = Base64.getEncoder().encodeToString(signData);
        return URLEncoder.encode(base64Sign, StandardCharsets.UTF_8);
    }

    /**
     * 检查邮件配置是否初始化
     */
    private static void checkEmailConfig() {
        if (emailConfig.host == null || emailConfig.host.isEmpty()) {
            throw new IllegalStateException("邮件配置未初始化");
        }
    }

    /**
     * 检查钉钉配置是否初始化
     */
    private static void checkDingTalkConfig() {
        if (dingTalkConfig.host == null || dingTalkConfig.host.isEmpty()) {
            throw new IllegalStateException("钉钉配置未初始化");
        }
    }

    public static void main(String[] args) {
        // 解析配置为JSON对象
        String email = "{\"host\":\"smtp.qq.com\",\"port\":\"465\",\"username\":\"xxx@qq.com\",\"password\":\"xxxx\",\"protocol\":\"smtp\",\"auth\":\"true\",\"debug\":\"false\",\"sslEnable\":\"true\"}";
        String ding = "{\"host\": \"https://oapi.dingtalk.com/robot/send?access_token=\",\"secret\" : \"secret\"}";
        emailConfig = JSONObject.parseObject(email,EmailConfig.class);
        dingTalkConfig = JSONObject.parseObject(ding,DingTalkConfig.class);
        // 测试邮件
        List<String> toEmails = List.of("linxi@linxi.tk");
        System.out.println(sendEmail("测试邮件", "测试", toEmails));
        // 测试钉钉
        List<String> toDings = List.of("123456789");
        System.out.println(sendDingTalk("测试钉钉", "测试", toDings,false));
    }
}