个人只能申请订阅号
1、首先需要申请一个微信公众号。具体如何申请,请登录微信公众号平台申请即可
2、外网映射工具——ngrok
项目使用spring boot 开发 结合自己项目 引入如下依赖及三个java文件
<!-- 微信开发工具包 -->
<!-- https://github.com/binarywang/weixin-java-mp-demo-springboot -->
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-mp</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.0.7</version>
</dependency>
WeChatProperties.java
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "wechat.config")
public class WeChatProperties {
/**
* 是否使用redis存储access token
*/
private boolean useRedis;
/**
* 设置微信公众号的appid
*/
private String appId;
/**
* 设置微信公众号的app secret
*/
private String appSecret;
/**
* 设置微信公众号的token
*/
private String token;
/**
* 设置微信公众号的EncodingAESKey
*/
private String aesKey;
private String mpVerify;
private String jobTemplateId1;
}
WeChatConfig.java
import lombok.AllArgsConstructor;
import me.chanjar.weixin.common.redis.JedisWxRedisOps;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.config.WxMpConfigStorage;
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
import me.chanjar.weixin.mp.config.impl.WxMpRedisConfigImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
@AllArgsConstructor
@Configuration
@EnableConfigurationProperties(WeChatProperties.class)
public class WeChatConfig {
@Autowired
WeChatProperties weChatProperties;
@Autowired
RedisProperties redisProperties;
@Bean
public WxMpService wxMpService() {
if (StringUtils.isAnyBlank(weChatProperties.getAppId(), weChatProperties.getAppSecret(), weChatProperties.getAesKey(), weChatProperties.getToken())) {
throw new RuntimeException("请检查微信公众平台开发配置文件");
}
/**
* WxMpServiceImpl继承WxMpServiceHttpClientImpl 内部获取了AccessToken
*/
WxMpServiceImpl wxMpService = new WxMpServiceImpl();
WxMpConfigStorage wxMpConfigStorage = wxMpConfigStorage(weChatProperties.isUseRedis());
wxMpService.setWxMpConfigStorage(wxMpConfigStorage);
return wxMpService;
}
public WxMpConfigStorage wxMpConfigStorage(Boolean isUseRedis) {
WxMpDefaultConfigImpl configStorage = new WxMpDefaultConfigImpl();
if (weChatProperties.isUseRedis()) {
String host = redisProperties.getHost();
Integer port = redisProperties.getPort();
if (StringUtils.isAnyBlank(host, port.toString())) {
throw new RuntimeException("请检查配置文件中redis====> host,port 不能为空");
}
JedisPoolConfig poolConfig = new JedisPoolConfig();
JedisPool jedisPool = new JedisPool(poolConfig, host, port);
configStorage = new WxMpRedisConfigImpl(new JedisWxRedisOps(jedisPool), weChatProperties.getAppId());
}
configStorage.setAppId(weChatProperties.getAppId());
configStorage.setSecret(weChatProperties.getAppSecret());
configStorage.setAesKey(weChatProperties.getAesKey());
configStorage.setToken(weChatProperties.getToken());
//String accessToken = AccessTokenUtils.getToken(weChatProperties.getAppId(),weChatProperties.getAppSecret());
//configStorage.setAccessToken(accessToken);
return configStorage;
}
@Bean
public WxMpXmlMessage wxMpXmlMessage() {
return new WxMpXmlMessage();
}
}
WxController.java
package com.frkj.modules.wechat;
import cn.hutool.json.JSONObject;
import com.frkj.common.api.vo.Result;
import com.frkj.common.exception.WechatException;
import com.frkj.common.util.MessageUtils;
import com.frkj.config.WeChatProperties;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.bean.WxJsapiSignature;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.menu.WxMpMenu;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutNewsMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutTextMessage;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping("/wx")
public class WxController {
private static final Logger log = LoggerFactory.getLogger(WxController.class);
@Autowired
WxMpService wxService;
@Autowired
WxMpXmlMessage wxMpXmlMessage;
@Autowired
WeChatProperties weChatProperties;
@RequestMapping(value = "authWx", method = RequestMethod.GET)
public String authGet(HttpServletRequest request, HttpServletResponse response) {
String signature = request.getParameter("signature");
String timestamp = request.getParameter("timestamp");
String nonce = request.getParameter("nonce");
String echostr = request.getParameter("echostr");
log.info("\n接收到来自微信服务器的认证消息:[signature:{}, timestamp:{}, nonce:{}, echostr:{}]", signature,
timestamp, nonce, echostr);
if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) {
throw new IllegalArgumentException("请求参数非法,请核实!");
}
if (wxService.checkSignature(timestamp, nonce, signature)) {
log.info("返回随机字符串表示验证成功,随机字符串:{}", echostr);
return echostr;
}
return "非法请求,验证微信服务器失败";
}
@RequestMapping(value = "authWx", method = RequestMethod.POST)
public String getMessageFromUser(HttpServletRequest request, HttpServletResponse response) throws IOException {
//获取用户发送的消息fromXml方法底层已转化为对象
WxMpXmlMessage message = wxMpXmlMessage.fromXml(request.getInputStream());
if (com.frkj.common.util.StringUtils.isNull(message)) {
throw new RuntimeException("解析用户发送的消息失败");
}
if (!message.getMsgType().equals(WxConsts.XmlMsgType.EVENT)) {//不是事件
//TODO 可以选择将消息保存到本地
}
log.info("用户发送的消息:{}", message);
//回复用户消息
return replyMessage(message);
}
public String replyMessage(WxMpXmlMessage message) {
String out = null;
switch (message.getMsgType()) {
case WxConsts.XmlMsgType.TEXT:
out = dealTextMessage(message);
break;
case WxConsts.XmlMsgType.IMAGE:
break;
case WxConsts.XmlMsgType.VIDEO:
break;
case WxConsts.XmlMsgType.VOICE:
break;
case WxConsts.XmlMsgType.NEWS:
break;
case WxConsts.XmlMsgType.MUSIC:
break;
case WxConsts.XmlMsgType.LOCATION:
break;
case WxConsts.XmlMsgType.LINK:
break;
case WxConsts.XmlMsgType.EVENT:
break;
}
if (StringUtils.isNotEmpty(out)) {
return out;
}
return "欢迎关注";
}
private String dealTextMessage(WxMpXmlMessage message) {
//TODO 组装回复消息
String out = null;
MessageUtils messageUtils = new MessageUtils();
long time = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
//当用户输入关键词如“1”,“2”等,可以组装特定的响应消息返回给用户
try {
if (StringUtils.startsWithAny(message.getContent(), "你好", "1")) {
WxMpXmlOutTextMessage xmlOutTextMessage = messageUtils.replyTextMessage(message.getFromUser(), message.getToUser(), "欢迎关注");
//组装回复用户消息
out = xmlOutTextMessage.toXml();//返回也是xml
return out;
}else if (StringUtils.startsWithAny(message.getContent(), "图文")) {
List<WxMpXmlOutNewsMessage.Item> articles = new ArrayList<>();
WxMpXmlOutNewsMessage.Item item = new WxMpXmlOutNewsMessage.Item();
item.setDescription("微信公众号发送图文消息");
item.setPicUrl("http://mmbiz.qpic.cn/mmbiz_jpg/DhpEVfrp0gtYNA8lA3py0YBhHxByIJIRUE1J2Hhe8vd6V1lh82PvP4hBFzY6R25AlyO96HJpSRYyF4LYZeqWew/0");
item.setTitle("正在开发,敬请期待");
item.setUrl("http://www.baidu.com");
articles.add(item);
WxMpXmlOutMessage newsMessage = messageUtils.replyNewsMessage(message.getFromUser(), message.getToUser(), item, articles);
//组装回复用户消息
out = newsMessage.toXml();//返回也是xml
return out;
}
//不是关键字
WxMpXmlOutTextMessage xmlOutTextMessage = messageUtils.replyTextMessage(message.getFromUser(), message.getToUser(), "http://www.baidu.com");
//组装回复用户消息
out = xmlOutTextMessage.toXml();//返回也是xml
} catch (Exception e) {
e.printStackTrace();
}
return out;
}
public String dealNewMessage(WxMpXmlMessage message) {
String out = null;
MessageUtils messageUtils = new MessageUtils();
try {
} catch (Exception e) {
e.printStackTrace();
}
return out;
}
/**
* 创建自定义按钮
*
* @param json
* @return
* @throws WxErrorException
*/
@PostMapping("/createByJson")
public String menuCreate(@RequestBody String json) throws WxErrorException {
try {
String s = wxService.switchoverTo(weChatProperties.getAppId()).getMenuService().menuCreate(json);
if (StringUtils.isNotEmpty(s)) {
JSONObject jsonObject = new JSONObject(s);
if (jsonObject.get("errcode").equals(String.valueOf(0))) {
return "创建菜单成功";
}
return "创建菜单失败";
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage());
}
return null;
}
/**
* 自定义菜单删除接口
*/
@GetMapping("/delete")
public void menuDelete() throws WxErrorException {
try {
this.wxService.switchoverTo(weChatProperties.getAppId()).getMenuService().menuDelete();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage());
}
}
/**
* 删除个性化菜单接口
*
* @param menuId 个性化菜单的menuid
*/
@GetMapping("/delete/{menuId}")
public void menuDelete(@PathVariable String menuId) throws WxErrorException {
this.wxService.switchoverTo(weChatProperties.getAppId()).getMenuService().menuDelete(menuId);
}
/**
* 自定义菜单查询接口
*/
@GetMapping("/get")
public WxMpMenu menuGet() throws WxErrorException {
try {
WxMpMenu wxMpMenu = this.wxService.switchoverTo(weChatProperties.getAppId()).getMenuService().menuGet();
if (com.frkj.common.util.StringUtils.isNotNull(wxMpMenu)) {
log.info("获取菜单列表成功{}", wxMpMenu);
return wxMpMenu;
}
throw new RuntimeException("没有获取到菜单列表");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
测试平台申请地址:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login 获取appId、appSecret
在配置文件 application-dev.yml 中填写获取appId、appSecret token自定义
wechat:
config:
useRedis: true
#自己测试用的appId及appSecret
appId: xxxxxxxx
appSecret: xxxxxxxxxxx
aesKey: IfDd5twyHOmEzmElMgyNE5mmnh8BRuQ23jXRdajDa7B
token: 123456
mpVerify: 6qn27EliDfT1mSYa
jobTemplateId1: yvv6RNXhtvYRow-w14NhXwc5ZmDDBj23nBETi8zmGNw
打开cmd 窗口运行ngrok.exe http 9999 因为自己项目的端口号是9999
启动成功如下所示
启动自己项目 在测试平台接口配配置上 把ngrok获取的http://20de-182-242-18-59.ngrok.io + wechat(项目根路径)+WxController.java中的authWx认证路径(get请求) 填入url
完成url: http://20de-182-242-18-59.ngrok.io/wechat/wx/authWx
填入自定义token:123456
点击提交按钮 若提示配置成功 则成功介入微信公众测试平台