微信公众号完成自动回复,自定义菜单
- 首先要获取到微信公众号的开发者权限,这一步省略,可以自行百度
- 微信公众号对接自己的服务器
首先第一步需要有自己的服务器和固定的ip,
其中,80/443端口需要有其中一个,
80端口对应http服务,
443端口对应https服务。
然后需要在自己的服务器上编写服务端代码,对应微信公众号的token和秘钥,在微信公众号上填写相应地址,调试通过后对接完成。
对接完成后,用户向龚总好发送的消息会被转发至服务端,你可以根据用户发送的消息做对应的处理
具体操作流程如下:
点击基本服务,然后点击修改配置。
填写自己的服务端地址和接口,填写对应的token和秘钥,服务端必须和客户端保持一致,然后点击提交,成功的话页面会有提示,然后返回上一层页面点击启用即可。
需要注意的是,启用后我们之前在公众号上的菜单将会失效,需要我们用api的方式重新提交一次,所以说,有做过菜单的需要注意,下面是创建菜单的步骤
首先我们需要通过接口获取token
/*
获取token
*/
@RequestMapping("/getToken")
public String getToken() {
String appId = "xxxxxxxxx"; // 替换为你的AppID
String appSecret = "xxxxxxxx"; // 替换为你的AppSecret
String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + appSecret;
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet(url);
try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
HttpEntity entity = response.getEntity();
if (entity != null) {
String result = EntityUtils.toString(entity, "UTF-8");
JSONObject jsonObject = new JSONObject(result);
// 提取access_token
String accessToken = jsonObject.getString("access_token");
token = accessToken;
// 输出access_token
System.out.println("Access Token: " + accessToken);
// 在这里你可以解析返回的JSON字符串以获取access_token
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
然后获取之前的菜单的结构json,有菜单的在此之前请不要启用服务器配置
/*
获取自定义菜单
*/
@RequestMapping("/getMenu")
public String getMenu() {
String token = "xxxxxxxxxxxxxxxxxxx"; // 替换为你的AppSecret
String url = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token=" + token;
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet(url);
try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
HttpEntity entity = response.getEntity();
if (entity != null) {
String result = EntityUtils.toString(entity, "UTF-8");
JSONObject jsonObject = new JSONObject(result);
// 提取access_token
// 输出access_token
System.out.println("menu: " + jsonObject);
// 在这里你可以解析返回的JSON字符串以获取access_token
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
通过此程序你可以获取自己的菜单结构,如下所示
{
"is_menu_open": 1,
"selfmenu_info": {
"button": [
{
"type": "click",
"name": "今日歌曲",
"key": "V1001_TODAY_MUSIC"
},
{
"name": "菜单",
"sub_button": {
"list": [
{
"type": "view",
"name": "搜索",
"url": "http://www.soso.com/"
},
{
"type": "view",
"name": "视频",
"url": "http://v.qq.com/"
},
{
"type": "click",
"name": "赞一下我们",
"key": "V1001_GOOD"
}
]
}
}
]
}}
然后你只需将此json通过创建接口重新创建即可,我这里都用的java。需要在启用服务器后进行配置
String url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=" + token;
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(url);
// 设置请求体参数为您提供的 JSON 数据
String jsonBody = “你的菜单结构”
StringEntity requestEntity = new StringEntity(jsonBody, ContentType.APPLICATION_JSON);
httpPost.setEntity(requestEntity);
// 设置请求头 Content-Type 为 application/json
httpPost.setHeader("Content-Type", "application/json");
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
HttpEntity entity = response.getEntity();
if (entity != null) {
String result = EntityUtils.toString(entity, "UTF-8");
JSONObject jsonObject = new JSONObject(result);
// 提取access_token
// 输出access_token
System.out.println("menu: " + jsonObject);
// 在这里您可以解析返回的JSON字符串以获取access_token
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
然后就是自动回复,我们要编写代码接收到用户向公众号发送的消息,然后返回我们想要回复的消息即可:此接口必须是你对接微信服务器所填写的接口,否则无法接收:如下
@RequestMapping("/wx")
public @ResponseBody
String wxGZHGetMsg(HttpServletRequest request) {
System.out.println(request.toString());
try {
// 获取请求体内容
String xmlContent = getRequestBody(request);
// 使用 Jsoup 解析 XML 内容
Document document = Jsoup.parse(xmlContent, "", org.jsoup.parser.Parser.xmlParser());
// 修改 XML 内容
// modifyXmlimg(document);
Elements eventElements = document.select("Event");
if (!eventElements.isEmpty()) {
String s = modifuxmlMenu(document);
return s;
} else {
return modifyXmlContent(document);
}
// 将修改后的 XML 内容转换为字符串
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private String getRequestBody(HttpServletRequest request) throws IOException {// 获取请求体内容
StringBuilder requestBody = new StringBuilder();
try (BufferedReader reader = request.getReader()) {
String line;
while ((line = reader.readLine()) != null) {
requestBody.append(line);
}
}
return requestBody.toString();
}
由于微信发送的信息室xml格式的,所以我们需要进行一定的处理,我这里使用的是jsonp包所带的方法进行处理的,使用jsonp需要在
Pom文件中引入相关的依赖,如下
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.14.3</version>
</dependency>
此外,这里回复处理xml文件的过程需要大家自己根据情况进行编写,可以配合数据库进行相应的逻辑回答,这里给出xml文件的格式,微信文档中也可以查看到
这是接收到的
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>1348831860</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[this is a test]]></Content>
<MsgId>1234567890123456</MsgId>
<MsgDataId>xxxx</MsgDataId>
<Idx>xxxx</Idx></xml>
回复的话也基本相同,
回复文本消息
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>12345678</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[你好]]></Content></xml>
回复图片消息
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>12345678</CreateTime>
<MsgType><![CDATA[image]]></MsgType>
<Image>
<MediaId><![CDATA[media_id]]></MediaId>
</Image></xml>
这里需要注意的是,回复消息的时候需要把ToUserName和FromUserName
的value值进行互换,具体过程大家可以自行根据需求编写。
此外,为了区分不同用户的提问状态,我这里使用了Redis进行保存用户提问数据的操作,并且设置1小时超时 ,在用户提问的时候,把用户的id存入Redis,由此可以分辨出每一位用户的问题,做出相对应的回答。
Redis可从网上自行下载安装,在java中使用可以通过pom文件引入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
然后编写配置类
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
// 使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
// 使用GenericJackson2JsonRedisSerializer来序列化和反序列化redis的value值
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
template.afterPropertiesSet();
return template;
}
}
这里我们通过 bean的方式注入,可以通过@Autowired注入的方式在程序中进行调用,Redis在springboot中的调用方式非常简单,可以使用sava ,find,delete 方式进行存储和删除修改
这里的sava方式我进行了保存时间的设定,timeou是时间参数,
TimeUnit 是时间单位(时/分/秒/毫秒),最小单位为毫秒,超时后会自动删除数据。
public class RedisService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public void save(String key, Object value, long timeout, TimeUnit unit) {
redisTemplate.opsForValue().set(key, value, timeout, unit);
}
public Object find(String key) {
return redisTemplate.opsForValue().get(key);
}
public void delete(String key) {
redisTemplate.delete(key);
}
}