杰瑞科技汇

Java微信公众平台开发源码哪里找?

核心原理:微信服务器与我们的服务器如何通信?

微信公众平台开发的核心是 服务器配置消息交互

Java微信公众平台开发源码哪里找?-图1
(图片来源网络,侵删)
  1. 服务器配置

    • 你需要一台公网可访问的服务器(可以是云服务器如阿里云、腾讯云,也可以是内网穿透工具如 ngrok)。
    • 在微信公众平台后台(mp.weixin.qq.com)的“开发” -> “基本配置”中,配置你的服务器信息。
    • URL:你的服务器上接收微信消息的接口地址,http://yourdomain.com/wechat
    • Token:你自定义的字符串,用于验证请求是否来自微信服务器。
    • EncodingAESKey:用于消息加解密的密钥(可选,安全起见建议开启)。
  2. 消息交互流程

    • 验证阶段(首次配置):微信服务器会向你的 URL 发送一个 GET 请求,携带 signature, timestamp, nonce, echostr 四个参数,你的服务器需要根据 Tokentimestampnonce 进行加密(SHA1),并与 signature 对比,如果一致,说明请求合法,需要将 echostr 原样返回。
    • 消息接收阶段:验证通过后,当用户在公众号里发送消息、点击菜单、关注/取关等事件发生时,微信服务器会向你的 URL 发送一个 POST 请求,请求体中包含 XML 格式的消息数据。
    • 消息回复阶段:你的服务器解析 XML 消息,根据业务逻辑生成要回复的 XML 格式消息,通过 HTTP 响应返回给微信服务器,微信服务器再将此消息推送给用户。

项目结构与技术选型

一个典型的 Java 微信公众号项目结构如下:

wechat-demo/
├── pom.xml                              <!-- Maven 依赖管理文件 -->
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/
│   │   │       └── example/
│   │   │           ├── config/
│   │   │           │   └── WeChatConfig.java     <!-- 微信配置信息(Token, AppID等) -->
│   │   │           ├── controller/
│   │   │           │   └── WeChatController.java  <!-- 核心控制器,处理所有微信请求 -->
│   │   │           ├── service/
│   │   │           │   └── WeChatService.java     <!-- 业务逻辑处理层 -->
│   │   │           └── utils/
│   │   │               ├── SHA1Util.java          <!-- SHA1 加密工具类 -->
│   │   │               └── XmlUtils.java          <!-- XML 解析工具类 -->
│   │   └── resources/
│   │       └── application.properties             <!-- 配置文件,存放敏感信息 -->
└── README.md

技术选型

Java微信公众平台开发源码哪里找?-图2
(图片来源网络,侵删)
  • 框架:Spring Boot (简化开发,快速构建项目)
  • Web 容器:Spring Boot 内嵌 Tomcat
  • XML 解析:Dom4J 或 JDK 自带的 javax.xml
  • 加密:JDK 自带的 java.security.MessageDigest

核心代码实现

pom.xml 依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" ...>
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.0</version> <!-- 使用较新的稳定版本 -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>wechat-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <!-- Spring Boot Web 依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- Dom4J 用于 XML 解析 -->
        <dependency>
            <groupId>org.dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>2.1.3</version>
        </dependency>
        <!-- Lombok (可选,简化代码) -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

application.properties 配置文件

# 服务器端口
server.port=8080
# 微信公众号配置
wechat.token=your_wechat_token
wechat.appid=your_app_id
wechat.secret=your_app_secret
wechat.encodingaeskey=your_encoding_aes_key

WeChatConfig.java 配置类

package com.example.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "wechat")
public class WeChatConfig {
    private String token;
    private String appid;
    private String secret;
    private String encodingaeskey;
    // Getters and Setters
    public String getToken() { return token; }
    public void setToken(String token) { this.token = token; }
    public String getAppid() { return appid; }
    public void setAppid(String appid) { this.appid = appid; }
    public String getSecret() { return secret; }
    public void setSecret(String secret) { this.secret = secret; }
    public String getEncodingaeskey() { return encodingaeskey; }
    public void setEncodingaeskey(String encodingaeskey) { this.encodingaeskey = encodingaeskey; }
}

SHA1Util.java 加密工具类

package com.example.utils;
import java.security.MessageDigest;
import java.util.Arrays;
public class SHA1Util {
    public static String getSHA1(String token, String timestamp, String nonce, String echostr) {
        String[] arr = new String[]{token, timestamp, nonce, echostr};
        Arrays.sort(arr);
        StringBuilder sb = new StringBuilder();
        for (String s : arr) {
            sb.append(s);
        }
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            byte[] digest = md.digest(sb.toString().getBytes("UTF-8"));
            StringBuilder hexStr = new StringBuilder();
            for (byte b : digest) {
                String shaHex = Integer.toHexString(b & 0xFF);
                if (shaHex.length() < 2) {
                    hexStr.append(0);
                }
                hexStr.append(shaHex);
            }
            return hexStr.toString();
        } catch (Exception e) {
            throw new RuntimeException("SHA1加密失败", e);
        }
    }
}

WeChatController.java 核心控制器

这是整个项目的核心,负责处理所有来自微信的请求。

package com.example.controller;
import com.example.config.WeChatConfig;
import com.example.utils.SHA1Util;
import com.example.utils.XmlUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/wechat")
public class WeChatController {
    @Autowired
    private WeChatConfig weChatConfig;
    /**
     * 处理微信服务器的验证请求(GET)
     */
    @GetMapping
    public String validate(@RequestParam("signature") String signature,
                          @RequestParam("timestamp") String timestamp,
                          @RequestParam("nonce") String nonce,
                          @RequestParam("echostr") String echostr) {
        // 1. 将token, timestamp, nonce三个参数进行字典序排序
        // 2. 将三个参数字符串拼接成一个字符串进行SHA1加密
        // 3. 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
        String mySignature = SHA1Util.getSHA1(weChatConfig.getToken(), timestamp, nonce, "");
        if (mySignature.equals(signature)) {
            return echostr; // 验证成功,返回echostr
        }
        return "Invalid Request";
    }
    /**
     * 处理用户发送的消息和事件(POST)
     */
    @PostMapping
    public String handlePost(@RequestBody String requestBody) {
        try {
            // 1. 解析XML消息
            Document document = XmlUtils.readXml(requestBody);
            Element root = document.getRootElement();
            String msgType = root.element("MsgType").getStringValue();
            String fromUserName = root.element("FromUserName").getStringValue();
            String toUserName = root.element("ToUserName").getStringValue();
            // 2. 根据消息类型处理
            String replyContent = "";
            if ("text".equals(msgType)) {
                // 文本消息
                String content = root.element("Content").getStringValue();
                replyContent = "你发送的是文本消息: " + content;
            } else if ("event".equals(msgType)) {
                // 事件消息
                String event = root.element("Event").getStringValue();
                if ("subscribe".equals(event)) {
                    // 关注事件
                    replyContent = "感谢关注!";
                } else if ("unsubscribe".equals(event)) {
                    // 取消关注事件
                    replyContent = ""; // 通常不回复
                }
            }
            // 其他消息类型(图片、语音等)可以在这里扩展
            // 3. 构造回复消息
            return buildReplyXml(toUserName, fromUserName, replyContent);
        } catch (DocumentException e) {
            e.printStackTrace();
            return "Error parsing XML";
        }
    }
    /**
     * 构造回复消息的XML
     */
    private String buildReplyXml(String toUserName, String fromUserName, String content) {
        return "<xml>" +
                "<ToUserName><![CDATA[" + toUserName + "]]></ToUserName>" +
                "<FromUserName><![CDATA[" + fromUserName + "]]></FromUserName>" +
                "<CreateTime>" + System.currentTimeMillis() / 1000 + "</CreateTime>" +
                "<MsgType><![CDATA[text]]></MsgType>" +
                "<Content><![CDATA[" + content + "]]></Content>" +
                "</xml>";
    }
}

XmlUtils.java XML 解析工具类

package com.example.utils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4.io.SAXReader;
import java.io.StringReader;
public class XmlUtils {
    public static Document readXml(String xmlStr) throws DocumentException {
        SAXReader reader = new SAXReader();
        return reader.read(new StringReader(xmlStr));
    }
    // 如果需要将Map转为XML,可以添加此方法
    public static String mapToXml(Map<String, String> map, String rootName) {
        StringBuilder sb = new StringBuilder();
        sb.append("<").append(rootName).append(">");
        for (Map.Entry<String, String> entry : map.entrySet()) {
            sb.append("<").append(entry.getKey()).append(">")
              .append("<![CDATA[").append(entry.getValue()).append("]]>")
              .append("</").append(entry.getKey()).append(">");
        }
        sb.append("</").append(rootName).append(">");
        return sb.toString();
    }
}

如何运行和部署

  1. 本地运行

    • 将上述代码文件放入对应目录。
    • 确保 application.properties 中的 wechat.token 与你在微信后台设置的 Token 一致。
    • 运行 WeChatDemoApplication.java(Spring Boot 启动类)。
    • 你的服务将在 http://localhost:8080/wechat 启动。
  2. 内网穿透(用于本地测试)

    • 由于微信服务器无法访问你的 localhost,你需要使用内网穿透工具,如 ngrok
    • 下载并安装 ngrok
    • 在终端运行命令:ngrok http 8080
    • ngrok 会为你提供一个公网 URL,http://a1b2c3d4.ngrok.io
    • 将这个 URL(加上 /wechat 路径)填写到微信公众平台后台的 URL 字段中,Token 填写你的。
  3. 部署到云服务器

    Java微信公众平台开发源码哪里找?-图3
    (图片来源网络,侵删)
    • 购买一台云服务器(如阿里云ECS、腾讯云CVM)。
    • 安装 Java 运行环境 和 Maven。
    • 将你的 Spring Boot 项目打包成 JAR 文件:mvn clean package
    • 将生成的 wechat-demo-0.0.1-SNAPSHOT.jar 文件上传到云服务器。
    • 在服务器上运行 JAR:java -jar wechat-demo-0.0.1-SNAPSHOT.jar
    • 配置服务器的防火墙(安全组),开放 8080 端口。
    • 将云服务器的公网 IP 和端口(如 http://your_server_ip:8080/wechat)填写到微信后台。

进阶功能

  • 接收和回复图片、图文等多媒体消息:解析对应类型的 XML,并构造相应类型的回复 XML。
  • 自定义菜单创建:通过调用微信提供的 POST 接口(需要 access_token)来创建菜单。access_token 需要通过你的 AppIDSecret 调用微信接口获取。
  • 模板消息:用于发送重要的服务通知,如订单确认、物流更新等。
  • 网页授权获取用户信息:当用户在公众号内点击链接时,可以通过 OAuth2.0 授权获取用户的 openid 和基本信息。
  • 安全与加密:如果开启了消息加解密,你需要实现 AES-256-CBC 的加解密逻辑来处理所有收发消息。

这份指南和源码为您提供了一个坚实的基础,您可以根据这个框架,逐步添加更复杂的业务逻辑,构建功能完善的微信公众号应用。

分享:
扫描分享到社交APP
上一篇
下一篇