一、场景概述

企业微信作为企业级协同办公平台,其消息通知能力可无缝集成到内部系统中。本文将通过Java代码示例,详细讲解如何快速对接企业微信API,实现自动化消息推送功能,适用于告警通知、审批提醒等业务场景。


二、前置条件准备

  1. 企业微信管理后台配置
  • 登录企业微信管理后台
  • 进入「应用管理」→ 创建/选择自建应用
  • 记录关键参数:
  • AgentId(应用ID)
  • Secret(应用密钥)
  • CorpId(企业ID,位于「我的企业」页面)
  • 如下图:
  • Java集成企业微信API实现高效消息推送实战指南_Java

  • 这里创建了一个用来消息提醒的应用,拿到id和密钥即可。
  • Java集成企业微信API实现高效消息推送实战指南_企业微信_02

  1. 核心代码实现(发送文本消息)

    1、配置企业id,应用id和密钥

    2、编写配置类用来读取
@Configuration
public class WeChatConfig {

    @Value("${wechat.corpId}")
    private String corpId;

    @Value("${wechat.secret}")
    private String secret;

    @Value("${wechat.tokenUrl}")
    private String tokenUrl;

    @Value("${wechat.agentId}")
    private String agentId;

    // 获取 AccessToken 的 URL
    public String getAccessTokenUrl() {
        return tokenUrl + "?corpid=" + corpId + "&corpsecret=" + secret;
    }

    /**
     * 其他配置,如 AgentId 等
     */
    public String getAgentId() {
        return agentId;
    }
}

3、编写获取企微签名相关代码
  注意:这里签名缓存自行设置,不需要每次就去调用企微api,签名失效时间2小时,可自行设置缓存过期时间,我这里利用的redis

@Service
public class WeChatService {
    private static final Logger logger = LoggerFactory.getLogger(WeChatService.class);

    @Autowired
    private WeChatConfig weChatConfig;

    /**
     * Redis 缓存 access_token 的 key
     */
    private static final String QW_ACCESS_TOKEN_CACHE_KEY = "shxd:dekt:qw:access:token";

    public String getAccessToken() {
        Object redisResult = NHRedisUtils.getRedisResult(QW_ACCESS_TOKEN_CACHE_KEY);
        if (redisResult == null) {
            String newToken = refreshAccessToken();
            if (newToken == null) {
                throw new RuntimeException("无法获取企业微信 AccessToken");
            }
            return newToken;
        }
        return String.valueOf(redisResult);
    }

    private String refreshAccessToken() {
        try {
            String url = weChatConfig.getAccessTokenUrl();
            RestTemplate restTemplate = new RestTemplate();
            String response = restTemplate.getForObject(url, String.class);
            JSONObject jsonObject = new JSONObject(response);
            logger.error("获取企业微信 token 成功:{}", jsonObject);

            String accessToken = jsonObject.getString("access_token");
            if (accessToken == null || accessToken.isEmpty()) {
                logger.error("获取企业微信 AccessToken 失败,返回为空");
                return null;
            }
            // 加入 Redis,缓存 110 分钟(提前 10 分钟刷新)
            NHRedisUtils.addRedis(QW_ACCESS_TOKEN_CACHE_KEY, 110, accessToken);
            return accessToken;
        } catch (Exception e) {
            logger.error("获取企业微信 AccessToken 失败", e);
            return null;
        }
    }
}

4、发送消息
 

@Service
public class WeChatMessageService {
    private static final Logger logger = LoggerFactory.getLogger(WeChatMessageService.class);

    @Autowired
    private WeChatService weChatService;
    @Autowired
    private WeChatConfig weChatConfig;

    private static final String SEND_MESSAGE_URL = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=";

    public boolean sendTextMessage(String userId, String content) {
        // 获取 AccessToken
        String accessToken = weChatService.getAccessToken();
        String url = SEND_MESSAGE_URL + accessToken;

        // 构造请求体
        JSONObject message = new JSONObject();
        message.put("touser", userId);
        message.put("msgtype", "text");
        message.put("agentid", weChatConfig.getAgentId());
        JSONObject text = new JSONObject();
        text.put("content", content);
        message.put("text", text);

        try {
            RestTemplate restTemplate = new RestTemplate();
            // 移除默认的StringHttpMessageConverter(这里防止中文乱码)
            restTemplate.getMessageConverters().removeIf(converter ->
                    converter instanceof StringHttpMessageConverter);
            // 添加支持UTF-8的StringHttpMessageConverter
            StringHttpMessageConverter converter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
            converter.setWriteAcceptCharset(false); // 重要!关闭默认字符集
            restTemplate.getMessageConverters().add(0, converter);

            // 设置请求头,确保 Content-Type 是 UTF-8
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            headers.setAcceptCharset(Collections.singletonList(StandardCharsets.UTF_8));
            HttpEntity<String> request = new HttpEntity<>(message.toJSONString(), headers);
            String response = restTemplate.postForObject(url, request, String.class);
            logger.error("发送企业微信消息返回数据:{}", response);
            // 解析返回结果
            JSONObject jsonResponse = JSONObject.parseObject(response);
            int errcode = jsonResponse.getIntValue("errcode");
            if (errcode == 0) {
                return true;
            } else {
                logger.error("发送企业微信消息失败,错误码:{},错误信息:{}", errcode, jsonResponse.getString("errmsg"));
                return false;
            }
        } catch (Exception e) {
            logger.error("发送企业微信消息请求失败", e);
            return false;
        }
    }
}

5、编写controller进行测试

第一个参数为企微用户名,第二个为发送内容。

Java集成企业微信API实现高效消息推送实战指南_企业微信_03


结果如下:

Java集成企业微信API实现高效消息推送实战指南_消息推送_04

  1. 发送图文消息
    只需改变消息体即可,如下
// 构造请求体
        JSONObject message = new JSONObject();
        message.put("touser", userId);
        message.put("msgtype", "news");
        message.put("agentid", weChatConfig.getAgentId());
        // 创建 articles 数组
        JSONArray articles = new JSONArray();
        JSONObject article = new JSONObject();
        article.put("title", "标题");         // 图文标题(必填)
        article.put("description", "我是描述"); // 图文描述
        article.put("url", "https://xf.xdsisu.edu.cn/ydxg");             // 点击后跳转链接
        article.put("picurl", "https://img0.baidu.com/it/u=1077282731,2234353719&fm=253&fmt=auto&app=120&f=JPEG?w=800&h=800");       // 图文封面的图片链接(可选)

        articles.add(article);

        JSONObject news = new JSONObject();
        news.put("articles", articles);
        message.put("news", news);
        message.put("safe", 0);

效果如下:

Java集成企业微信API实现高效消息推送实战指南_Java_05


注意:一定要在应用里面配置可信域名,不然会出现{"errcode":60020,"errmsg":"not allow to access from your ip  ip不被允许访问的错误信息

Java集成企业微信API实现高效消息推送实战指南_API集成_06

  1. 扩展
    如果是本地图片,没有地址的话,可以调用企微的上传图片接口,会返回给你一个url,这个url在企微内部永久有效。上传图片文档地址
    代码如下:
public String uploadImage(byte[] bytes, String accessToken) {
        if (bytes == null || bytes.length == 0) {
            return null;
        }
        try {
            // 构建请求
            String uploadUrl = "https://qyapi.weixin.qq.com/cgi-bin/media/uploadimg?access_token="+accessToken;
            HttpEntity<MultiValueMap<String, Object>> requestEntity = buildRequestEntity(bytes);
            logger.error("开始上传图片,数据大小:{} bytes", bytes.length);
            // 发送请求
            ResponseEntity<String> response = restTemplate.postForEntity(uploadUrl, requestEntity, String.class);
            // 响应处理
            // 解析JSON响应
            String responseBody = response.getBody();
            if (StringUtils.isBlank(responseBody)) {
                logger.error("图片上传返回空响应");
                return null;
            }
            com.alibaba.fastjson.JSONObject json = com.alibaba.fastjson.JSON.parseObject(responseBody);
            int errcode = json.getIntValue("errcode");
            if (errcode != 0) {
                String errmsg = json.getString("errmsg");
                logger.error("图片上传失败,错误码:{},错误信息:{}", errcode, errmsg);
                return null;
            }
            String url = json.getString("url");
            if (StringUtils.isBlank(url)) {
                logger.error("图片上传成功但未返回url");
                return null;
            }
            logger.error("图片上传成功,url:{}", url);
            return url;
        } catch (RestClientException e) {
            logger.error("图片上传请求失败,accessToken:{}", accessToken, e);
        } catch (JSONException e) {
            logger.error("响应数据解析失败", e);
        }
        return null;
    }