Commit 7e86b4d6 by liangyuhang

普通消息和事件推送处理

parents
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.liang</groupId>
<artifactId>wechat-message-handle</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>wechat-message-handle</name>
<description>wechat-message-handle</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.12</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.10</version>
</dependency>
<!--hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.8</version>
</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>
package com.liang.wechat;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class WechatMessageHandleApplication {
public static void main(String[] args) {
SpringApplication.run(WechatMessageHandleApplication.class, args);
}
}
package com.liang.wechat.bean;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
import java.io.Serializable;
@Data
public class BaseMessage implements Serializable {
/**
* 开发者微信号
*/
@XStreamAlias("ToUserName")
private String toUserName;
/**
* 发送方openId
*/
@XStreamAlias("FromUserName")
private String fromUserName;
/**
* 消息创建时间
*/
@XStreamAlias("CreateTime")
private long createTime;
/**
* 消息类型
*/
@XStreamAlias("MsgType")
private String msgType;
}
package com.liang.wechat.bean.event;
import com.liang.wechat.bean.BaseMessage;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
@Data
@XStreamAlias("xml")
public class EventMessage extends BaseMessage {
@XStreamAlias("Event")
private String event;
@XStreamAlias("EventKey")
private String eventKey;
}
package com.liang.wechat.bean.message;
import com.liang.wechat.bean.BaseMessage;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* 图片消息
*/
@Data
@XStreamAlias("xml")
public class ImageMessage extends BaseMessage {
/**
* 图片链接
*/
@XStreamAlias("PicUrl")
private String picUrl;
/**
* 图片素材ID
*/
@XStreamAlias("MediaId")
private String mediaId;
/**
* mediaId的包装,回复时用到
*/
@XStreamAlias("Image")
private Image image;
@Data
@AllArgsConstructor
public static class Image {
/**
* 通过素材管理中的接口上传多媒体文件,得到的id
*/
@XStreamAlias("MediaId")
private String mediaId;
}
}
package com.liang.wechat.bean.message;
import com.liang.wechat.bean.BaseMessage;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
/**
* 链接消息
*/
@Data
@XStreamAlias("xml")
public class LinkMessage extends BaseMessage {
/**
* 消息标题
*/
@XStreamAlias("Title")
private String title;
/**
* 消息描述
*/
@XStreamAlias("Description")
private String description;
/**
* 消息链接
*/
@XStreamAlias("Url")
private String url;
}
package com.liang.wechat.bean.message;
import com.liang.wechat.bean.BaseMessage;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
/**
* 地理位置消息
*/
@Data
@XStreamAlias("xml")
public class LocationMessage extends BaseMessage {
/**
* 地理位置维度
*/
@XStreamAlias("Location_X")
private String location_X;
/**
* 地理位置经度
*/
@XStreamAlias("Location_Y")
private String location_Y;
/**
* 地图缩放大小
*/
@XStreamAlias("Scale")
private String scale;
/**
* 地理位置信息
*/
@XStreamAlias("Label")
private String label;
}
package com.liang.wechat.bean.message;
import com.liang.wechat.bean.BaseMessage;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 音乐消息,只有回复
*/
@Data
@XStreamAlias("xml")
public class MusicMessage extends BaseMessage {
@XStreamAlias("Music")
private Music music;
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class Music {
/**
* 音乐标题
*/
@XStreamAlias("Title")
private String title;
/**
* 音乐描述
*/
@XStreamAlias("Description")
private String description;
/**
* 音乐链接
*/
@XStreamAlias("MusicURL")
private String musicURL;
/**
* 高质量音乐链接,WIFI环境优先使用该链接播放音乐
*/
@XStreamAlias("HQMusicUrl")
private String hQMusicUrl;
/**
* 缩略图的媒体id,通过素材管理中的接口上传多媒体文件,得到的id
*/
@XStreamAlias("ThumbMediaId")
private String thumbMediaId;
}
}
package com.liang.wechat.bean.message;
import com.liang.wechat.bean.BaseMessage;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* 图文消息
*/
@Data
@XStreamAlias("xml")
public class NewsMessage extends BaseMessage {
/**
* 图文消息个数;当用户发送文本、图片、语音、视频、图文、地理位置这六种消息时,开发者只能回复1条图文消息;其余场景最多可回复8条图文消息
*/
@XStreamAlias("ArticleCount")
private int articleCount;
/**
* 图文消息信息,注意,如果图文数超过限制,则将只发限制内的条数
*/
@XStreamAlias("Articles")
private List<Article> articles;
@Data
@NoArgsConstructor
@AllArgsConstructor
@XStreamAlias("item")
public static class Article {
/**
* 图文消息标题
*/
@XStreamAlias("Title")
private String title;
/**
* 图文消息描述
*/
@XStreamAlias("Description")
private String description;
/**
* 图片链接,支持JPG、PNG格式,较好的效果为大图360*200,小图200*200
*/
@XStreamAlias("PicUrl")
private String picUrl;
/**
* 点击图文消息跳转链接
*/
@XStreamAlias("Url")
private String url;
}
}
package com.liang.wechat.bean.message;
import com.liang.wechat.bean.BaseMessage;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
/**
* 小视频消息
*/
@Data
@XStreamAlias("xml")
public class ShortVideoMessage extends BaseMessage {
/**
* 视频消息媒体id,可以调用获取临时素材接口拉取数据
*/
@XStreamAlias("MediaId")
private String mediaId;
/**
* 视频消息缩略图的媒体id,可以调用获取临时素材接口拉取数据
*/
@XStreamAlias("ThumbMediaId")
private String thumbMediaId;
}
package com.liang.wechat.bean.message;
import com.liang.wechat.bean.BaseMessage;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
/**
* 文本消息
*/
@Data
@XStreamAlias("xml")
public class TextMessage extends BaseMessage {
@XStreamAlias("Content")
private String content;
}
package com.liang.wechat.bean.message;
import com.liang.wechat.bean.BaseMessage;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 视频消息
*/
@Data
@XStreamAlias("xml")
public class VideoMessage extends BaseMessage {
/**
* 视频消息媒体id,可以调用多媒体文件下载接口拉取数据
*/
@XStreamAlias("MediaId")
private String mediaId;
/**
* 视频消息缩略图的媒体id,可以调用多媒体文件下载接口拉取数据
*/
@XStreamAlias("ThumbMediaId")
private String thumbMediaId;
/**
* 回复时用到
*/
@XStreamAlias("Video")
private Video video;
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class Video {
/**
* 通过素材管理中的接口上传多媒体文件,得到的id
*/
@XStreamAlias("MediaId")
private String mediaId;
/**
* 视频消息的标题
*/
@XStreamAlias("Title")
private String title;
/**
* 视频消息的描述
*/
@XStreamAlias("Description")
private String description;
}
}
package com.liang.wechat.bean.message;
import com.liang.wechat.bean.BaseMessage;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* 语音消息
*/
@Data
@XStreamAlias("xml")
public class VoiceMessage extends BaseMessage {
/**
* 语音消息媒体id,可以调用获取临时素材接口拉取数据
*/
@XStreamAlias("MediaId")
private String mediaId;
/**
* 语音格式,如amr,speex等
*/
@XStreamAlias("Format")
private String format;
/**
* 语音识别结果,UTF8编码(注:由于客户端缓存,开发者开启或者关闭语音识别功能,对新关注者立刻生效,对已关注用户需要24小时生效。开发者可以重新关注此帐号进行测试)
*/
@XStreamAlias("Recognition")
private String recognition;
/**
* 回复时用到
*/
@XStreamAlias("Voice")
private Voice voice;
@Data
@AllArgsConstructor
public static class Voice {
/**
* 通过素材管理中的接口上传多媒体文件,得到的id
*/
@XStreamAlias("MediaId")
private String mediaId;
}
}
package com.liang.wechat.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
@ConfigurationProperties(prefix = "wx")
public class WechatConfig {
private String appId ;
private String secret;
private String token;
private String encodingAESKey;
}
package com.liang.wechat.constant;
public class WechatConstant {
/**
* 获取access_token的URL
*/
public static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={1}&secret={2}";
/**
* 创建二维码URL
*/
public final static String CREATE_QRCODE_URL = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token={1}";
/**
* 展示二维码URL
*/
public static final String SHOW_QRCODE_URL = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket={1}";
/**
* 创建菜单URL
*/
public static final String CREATE_MENU_URL = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";
/**
* 删除菜单URL
*/
public static final String DELETE_MENU_URL = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN";
/**
* 模版服务相关-设置所属行业
*/
public static final String SET_INDUSTRY = "https://api.weixin.qq.com/cgi-bin/template/api_set_industry?access_token=ACCESS_TOKEN";
/**
* 获取所属行业信息
*/
public static final String GET_INDUSTRY = "https://api.weixin.qq.com/cgi-bin/template/get_industry?access_token=ACCESS_TOKEN";
/**
* 获取所有模版信息
*/
public static final String GET_ALL_PRIVATE_TEMPLATE = "https://api.weixin.qq.com/cgi-bin/template/get_all_private_template?access_token=ACCESS_TOKEN";
/**
* 发送模版消息
*/
public static final String TEMPLATE_SEND = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN";
/**
* 获取OAUTH认证的access_token
*/
public static final String OAUTH_GET_AT = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
/**
* 获取用户基本信息
*/
public static final String OAUTH_USER_INFO = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
/**
* 引导链接
*/
public static final String OAUTH2_AUTHORIZE = "";
}
package com.liang.wechat.controller;
import com.liang.wechat.constant.WechatConstant;
import com.liang.wechat.factory.MessageFactory;
import com.liang.wechat.strategy.MessageStrategy;
import com.liang.wechat.utils.WechatUtil;
import com.liang.wechat.utils.XmlUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
import java.util.Objects;
@RestController
@Slf4j
@RequestMapping("/wechat")
public class WechatController {
@Autowired
private WechatUtil wechatUtil;
@Autowired
private MessageFactory messageFactory;
/**
* @param signature 微信加密签名,signature结合了开发者填写的 token 参数和请求中的 timestamp 参数、nonce参数。
* @param timestamp 时间戳
* @param nonce 随机数
* @param echostr 随机字符串
*/
@GetMapping
public String doGet(@RequestParam(value = "signature") String signature,
@RequestParam(value = "timestamp") String timestamp,
@RequestParam(value = "nonce") String nonce,
@RequestParam(value = "echostr") String echostr) {
if (!wechatUtil.checkSignature(signature, timestamp, nonce)) {
return null;
}
return echostr;
}
@PostMapping
public String doPost(@RequestBody String message) throws Exception {
log.info("接收微信的消息:{}", message);
//xml转map
Map<String, String> map = XmlUtil.xmlToMap(message);
String msgType = map.get("MsgType");
log.info("消息类型:{}", msgType);
String eventType = map.get("Event");
log.info("事件类型:{}", eventType);
MessageStrategy messageStrategy = messageFactory.getMessageStrategy(msgType, eventType);
if(Objects.isNull(messageStrategy)){
return null;
}
return messageStrategy.handleMessage(message);
}
}
package com.liang.wechat.enumeration;
public enum EventType {
/**
* 关注
*/
SUBSCRIBE("subscribe"),
/**
* 取消关注
*/
UNSUBSCRIBE("unsubscribe"),
/**
* 用户已关注时的事件推送
*/
SCAN("scan"),
/**
* 上报地理位置事件
*/
LOCATION("location"),
/**
* 自定义菜单事件(点击菜单拉取消息时的事件推送)
*/
CLICK("click"),
/**
* 点击菜单跳转链接时的事件推送
*/
VIEW("view");
private final String type;
EventType(String type) {
this.type = type;
}
public String getType() {
return type;
}
}
package com.liang.wechat.enumeration;
import java.util.Arrays;
public enum MessageType {
/**
* 文本类型
*/
TEXT("text"),
/**
* 图片消息
*/
IMAGE("image"),
/**
* 语音消息
*/
VOICE("voice"),
/**
* 视频消息
*/
VIDEO("video"),
/**
* 小视频消息
*/
SHORTVIDEO("shortvideo"),
/**
* 位置消息
*/
LOCATION("location"),
/**
* 链接消息
*/
LINK("link"),
/**
* 事件消息
*/
EVENT("event"),
/**
* 图文列表
*/
NEWS("news");
private final String type;
MessageType(String type) {
this.type = type;
}
public String getType() {
return type;
}
public static String getType(String type) {
MessageType messageType = Arrays.stream(MessageType.values())
.filter(value -> value.getType().equalsIgnoreCase(type))
.findFirst().orElse(MessageType.TEXT);
return messageType.getType();
}
}
package com.liang.wechat.enumeration;
import lombok.Getter;
@Getter
public enum WxOpenErrorMsgEnum {
/**
* 系统繁忙,此时请开发者稍候再试 system error
*/
CODE_1(-1, "系统繁忙,此时请开发者稍候再试"),
/**
* 请求成功 ok
*/
CODE_0(0, "请求成功"),
/**
* 获取 access_token 时 AppSecret 错误,或者 access_token 无效。请开发者认真比对 AppSecret 的正确性,或查看是否正在为恰当的公众号调用接口 invalid credential, access_token is invalid or not latest
*/
CODE_40001(40001, "获取 access_token 时 AppSecret 错误,或者 access_token 无效。请开发者认真比对 AppSecret 的正确性,或查看是否正在为恰当的公众号调用接口"),
/**
* 不合法的凭证类型 invalid grant_type
*/
CODE_40002(40002, "不合法的凭证类型"),
/**
* 不合法的 OpenID ,请开发者确认 OpenID (该用户)是否已关注公众号,或是否是其他公众号的 OpenID invalid openid
*/
CODE_40003(40003, "不合法的 OpenID ,请开发者确认 OpenID (该用户)是否已关注公众号,或是否是其他公众号的 OpenID"),
/**
* 不合法的媒体文件类型 invalid media type
*/
CODE_40004(40004, "不合法的媒体文件类型"),
/**
* 上传素材文件格式不对 invalid file type
*/
CODE_40005(40005, "上传素材文件格式不对"),
/**
* 上传素材文件大小超出限制 invalid meida size
*/
CODE_40006(40006, "上传素材文件大小超出限制"),
/**
* 不合法的媒体文件 id invalid media_id
*/
CODE_40007(40007, "不合法的媒体文件 id"),
/**
* 不合法的消息类型 invalid message type
*/
CODE_40008(40008, "不合法的消息类型"),
/**
* 图片尺寸太大 invalid image size
*/
CODE_40009(40009, "图片尺寸太大"),
/**
* 不合法的语音文件大小 invalid voice size
*/
CODE_40010(40010, "不合法的语音文件大小"),
/**
* 不合法的视频文件大小 invalid video size
*/
CODE_40011(40011, "不合法的视频文件大小"),
/**
* 不合法的缩略图文件大小 invalid thumb size
*/
CODE_40012(40012, "不合法的缩略图文件大小"),
/**
* 不合法的appid invalid appid
*/
CODE_40013(40013, "不合法的appid"),
/**
* 不合法的 access_token ,请开发者认真比对 access_token 的有效性(如是否过期),或查看是否正在为恰当的公众号调用接口 invalid access_token
*/
CODE_40014(40014, "不合法的 access_token ,请开发者认真比对 access_token 的有效性(如是否过期),或查看是否正在为恰当的公众号调用接口"),
/**
* 不合法的菜单类型 invalid menu type
*/
CODE_40015(40015, "不合法的菜单类型"),
/**
* 不合法的按钮个数 invalid button size
*/
CODE_40016(40016, "不合法的按钮个数"),
/**
* 不合法的按钮类型 invalid button type
*/
CODE_40017(40017, "不合法的按钮类型"),
/**
* 不合法的按钮名字长度 invalid button name size
*/
CODE_40018(40018, "不合法的按钮名字长度"),
/**
* 不合法的按钮 KEY 长度 invalid button key size
*/
CODE_40019(40019, "不合法的按钮 KEY 长度"),
/**
* 不合法的按钮 URL 长度 invalid button url size
*/
CODE_40020(40020, "不合法的按钮 URL 长度"),
/**
* 不合法的菜单版本号 invalid menu version
*/
CODE_40021(40021, "不合法的菜单版本号"),
/**
* 不合法的子菜单级数 invalid sub_menu level
*/
CODE_40022(40022, "不合法的子菜单级数"),
/**
* 不合法的子菜单按钮个数 invalid sub button size
*/
CODE_40023(40023, "不合法的子菜单按钮个数"),
/**
* 不合法的子菜单按钮类型 invalid sub button type
*/
CODE_40024(40024, "不合法的子菜单按钮类型"),
/**
* 不合法的子菜单按钮名字长度 invalid sub button name size
*/
CODE_40025(40025, "不合法的子菜单按钮名字长度"),
/**
* 不合法的子菜单按钮 KEY 长度 invalid sub button key size
*/
CODE_40026(40026, "不合法的子菜单按钮 KEY 长度"),
/**
* 不合法的子菜单按钮 URL 长度 invalid sub button url size
*/
CODE_40027(40027, "不合法的子菜单按钮 URL 长度"),
/**
* 不合法的自定义菜单使用用户 invalid menu api user
*/
CODE_40028(40028, "不合法的自定义菜单使用用户"),
/**
* 无效的 oauth_code invalid code
*/
CODE_40029(40029, "无效的 oauth_code"),
/**
* 不合法的 refresh_token invalid refresh_token
*/
CODE_40030(40030, "不合法的 refresh_token"),
/**
* 不合法的 openid 列表 invalid openid list
*/
CODE_40031(40031, "不合法的 openid 列表"),
/**
* 不合法的 openid 列表长度 invalid openid list size
*/
CODE_40032(40032, "不合法的 openid 列表长度"),
/**
* 不合法的请求字符,不能包含 \\uxxxx 格式的字符 invalid charset. please check your request, if include \\uxxxx will create fail!
*/
CODE_40033(40033, "不合法的请求字符,不能包含 \\uxxxx 格式的字符"),
/**
* 不合法的参数 invalid args size
*/
CODE_40035(40035, "不合法的参数"),
/**
* 不合法的请求格式 invalid packaging type
*/
CODE_40038(40038, "不合法的请求格式"),
/**
* 不合法的 URL 长度 invalid url size
*/
CODE_40039(40039, "不合法的 URL 长度"),
/**
* 无效的url invalid url domain
*/
CODE_40048(40048, "无效的url"),
/**
* 不合法的分组 id invalid timeline type
*/
CODE_40050(40050, "不合法的分组 id"),
/**
* 分组名字不合法 invalid group name
*/
CODE_40051(40051, "分组名字不合法"),
/**
* 删除单篇图文时,指定的 article_idx 不合法 invalid article idx
*/
CODE_40060(40060, "删除单篇图文时,指定的 article_idx 不合法"),
/**
* 分组名字不合法 invalid button media_id size
*/
CODE_40117(40117, "分组名字不合法"),
/**
* media_id 大小不合法 invalid sub button media_id size
*/
CODE_40118(40118, "media_id 大小不合法"),
/**
* button 类型错误 invalid use button type
*/
CODE_40119(40119, "button 类型错误"),
/**
* 子 button 类型错误 invalid use sub button type
*/
CODE_40120(40120, "子 button 类型错误"),
/**
* 不合法的 media_id 类型 invalid media type in view_limited
*/
CODE_40121(40121, "不合法的 media_id 类型"),
/**
* 无效的appsecret invalid appsecret
*/
CODE_40125(40125, "无效的appsecret"),
/**
* 微信号不合法 invalid username
*/
CODE_40132(40132, "微信号不合法"),
/**
* 不支持的图片格式 invalid image format
*/
CODE_40137(40137, "不支持的图片格式"),
/**
* 请勿添加其他公众号的主页链接 please don't contain other home page url
*/
CODE_40155(40155, "请勿添加其他公众号的主页链接"),
/**
* oauth_code已使用 code been used
*/
CODE_40163(40163, "oauth_code已使用"),
/**
* 标题为空
*/
CODE_40227(40227, "标题为空"),
/**
* 缺少 access_token 参数 access_token missing
*/
CODE_41001(41001, "缺少 access_token 参数"),
/**
* 缺少 appid 参数 appid missing
*/
CODE_41002(41002, "缺少 appid 参数"),
/**
* 缺少 refresh_token 参数 refresh_token missing
*/
CODE_41003(41003, "缺少 refresh_token 参数"),
/**
* 缺少 secret 参数 appsecret missing
*/
CODE_41004(41004, "缺少 secret 参数"),
/**
* 缺少多媒体文件数据,传输素材无视频或图片内容 media data missing
*/
CODE_41005(41005, "缺少多媒体文件数据,传输素材无视频或图片内容"),
/**
* 缺少 media_id 参数 media_id missing
*/
CODE_41006(41006, "缺少 media_id 参数"),
/**
* 缺少子菜单数据 sub_menu data missing
*/
CODE_41007(41007, "缺少子菜单数据"),
/**
* 缺少 oauth code missing code
*/
CODE_41008(41008, "缺少 oauth code"),
/**
* 缺少 openid missing openid
*/
CODE_41009(41009, "缺少 openid"),
/**
* access_token 超时,请检查 access_token 的有效期,请参考基础支持 - 获取 access_token 中,对 access_token 的详细机制说明 access_token expired
*/
CODE_42001(42001, "access_token 超时,请检查 access_token 的有效期,请参考基础支持 - 获取 access_token 中,对 access_token 的详细机制说明"),
/**
* refresh_token 超时 refresh_token expired
*/
CODE_42002(42002, "refresh_token 超时"),
/**
* oauth_code 超时 code expired
*/
CODE_42003(42003, "oauth_code 超时"),
/**
* 用户修改微信密码, accesstoken 和 refreshtoken 失效,需要重新授权 access_token and refresh_token exception
*/
CODE_42007(42007, "用户修改微信密码, accesstoken 和 refreshtoken 失效,需要重新授权"),
/**
* 相同 media_id 群发过快,请重试
*/
CODE_42010(42010, "相同 media_id 群发过快,请重试"),
/**
* 需要 GET 请求 require GET method
*/
CODE_43001(43001, "需要 GET 请求"),
/**
* 需要 POST 请求 require POST method
*/
CODE_43002(43002, "需要 POST 请求"),
/**
* 需要 HTTPS 请求 require https
*/
CODE_43003(43003, "需要 HTTPS 请求"),
/**
* 需要接收者关注 require subscribe
*/
CODE_43004(43004, "需要接收者关注"),
/**
* 需要好友关系 require friend relations
*/
CODE_43005(43005, "需要好友关系"),
/**
* 需要将接收者从黑名单中移除 require remove blacklist
*/
CODE_43019(43019, "需要将接收者从黑名单中移除"),
/**
* 多媒体文件为空 empty media data
*/
CODE_44001(44001, "多媒体文件为空"),
/**
* POST 的数据包为空 empty post data
*/
CODE_44002(44002, "POST 的数据包为空"),
/**
* 图文消息内容为空 empty news data
*/
CODE_44003(44003, "图文消息内容为空"),
/**
* 文本消息内容为空 empty content
*/
CODE_44004(44004, "文本消息内容为空"),
/**
* 多媒体文件大小超过限制 media size out of limit
*/
CODE_45001(45001, "多媒体文件大小超过限制"),
/**
* 消息内容超过限制 content size out of limit
*/
CODE_45002(45002, "消息内容超过限制"),
/**
* 标题字段超过限制 title size out of limit
*/
CODE_45003(45003, "标题字段超过限制"),
/**
* 描述字段超过限制 description size out of limit
*/
CODE_45004(45004, "描述字段超过限制"),
/**
* 链接字段超过限制 url size out of limit
*/
CODE_45005(45005, "链接字段超过限制"),
/**
* 图片链接字段超过限制 picurl size out of limit
*/
CODE_45006(45006, "图片链接字段超过限制"),
/**
* 语音播放时间超过限制 playtime out of limit
*/
CODE_45007(45007, "语音播放时间超过限制"),
/**
* 图文消息超过限制 article size out of limit
*/
CODE_45008(45008, "图文消息超过限制"),
/**
* 接口调用超过限制 reach max api daily quota limit
*/
CODE_45009(45009, "接口调用超过限制"),
/**
* 创建菜单个数超过限制 create menu limit
*/
CODE_45010(45010, "创建菜单个数超过限制"),
/**
* API 调用太频繁,请稍候再试 api minute-quota reach limit, must slower, retry next minute
*/
CODE_45011(45011, "API 调用太频繁,请稍候再试"),
/**
* 回复时间超过限制 response out of time limit or subscription is canceled
*/
CODE_45015(45015, "回复时间超过限制"),
/**
* 系统分组,不允许修改 can't modify sys group
*/
CODE_45016(45016, "系统分组,不允许修改"),
/**
* 分组名字过长 can't set group name too long sys group
*/
CODE_45017(45017, "分组名字过长"),
/**
* 分组数量超过上限 too many group now, no need to add new
*/
CODE_45018(45018, "分组数量超过上限"),
/**
* 客服接口下行条数超过上限 out of response count limit
*/
CODE_45047(45047, "客服接口下行条数超过上限"),
/**
* 创建菜单包含未关联的小程序 no permission to use weapp in menu
*/
CODE_45064(45064, "创建菜单包含未关联的小程序"),
/**
* 相同 clientmsgid 已存在群发记录,返回数据中带有已存在的群发任务的 msgid clientmsgid exist
*/
CODE_45065(45065, "相同 clientmsgid 已存在群发记录,返回数据中带有已存在的群发任务的 msgid"),
/**
* 相同 clientmsgid 重试速度过快,请间隔1分钟重试 same clientmsgid retry too fast
*/
CODE_45066(45066, "相同 clientmsgid 重试速度过快,请间隔1分钟重试"),
/**
* clientmsgid 长度超过限制 clientmsgid size out of limit
*/
CODE_45067(45067, "clientmsgid 长度超过限制"),
/**
* 不存在媒体数据,media_id 不存在 media data no exist
*/
CODE_46001(46001, "不存在媒体数据,media_id 不存在"),
/**
* 不存在的菜单版本 menu version no exist
*/
CODE_46002(46002, "不存在的菜单版本"),
/**
* 不存在的菜单数据 menu no exist
*/
CODE_46003(46003, "不存在的菜单数据"),
/**
* 解析 JSON/XML 内容错误 data format error
*/
CODE_47001(47001, "解析 JSON/XML 内容错误"),
/**
* 模板参数不准确,可能为空或者不满足规则,errmsg会提示具体是哪个字段出错 argument invalid!
*/
CODE_47003(47003, "模板参数不准确,可能为空或者不满足规则,errmsg会提示具体是哪个字段出错"),
/**
* api 功能未授权,请确认公众号已获得该接口,可以在公众平台官网 - 开发者中心页中查看接口权限 api unauthorized
*/
CODE_48001(48001, "api 功能未授权,请确认公众号已获得该接口,可以在公众平台官网 - 开发者中心页中查看接口权限"),
/**
* 粉丝拒收消息(粉丝在公众号选项中,关闭了 “ 接收消息 ” ) user block receive message
*/
CODE_48002(48002, "粉丝拒收消息(粉丝在公众号选项中,关闭了 “ 接收消息 ” )"),
/**
* user not agree mass-send protocol
*/
CODE_48003(48003, "user not agree mass-send protocol"),
/**
* api 接口被封禁,请登录 mp.weixin.qq.com 查看详情 api forbidden for irregularities, view detail on mp.weixin.qq.com
*/
CODE_48004(48004, "api 接口被封禁,请登录 mp.weixin.qq.com 查看详情"),
/**
* api 禁止删除被自动回复和自定义菜单引用的素材 forbid to delete material used by auto-reply or menu
*/
CODE_48005(48005, "api 禁止删除被自动回复和自定义菜单引用的素材"),
/**
* api 禁止清零调用次数,因为清零次数达到上限 forbid to clear quota because of reaching the limit
*/
CODE_48006(48006, "api 禁止清零调用次数,因为清零次数达到上限"),
/**
* 没有该类型消息的发送权限 no permission for this msgtype
*/
CODE_48008(48008, "没有该类型消息的发送权限"),
/**
* 该视频非新接口上传,不能用于视频消息群发
*/
CODE_48021(48021, "自动保存的草稿无法预览/发送,请先手动保存草稿"),
/**
* 用户未授权该 api api unauthorized or user unauthorized
*/
CODE_50001(50001, "用户未授权该 api"),
/**
* 用户受限,可能是违规后接口被封禁 user limited
*/
CODE_50002(50002, "用户受限,可能是违规后接口被封禁"),
/**
* 用户未关注公众号 user is unsubscribed
*/
CODE_50005(50005, "用户未关注公众号"),
/**
* 发布功能被封禁
*/
CODE_53500(53500, "发布功能被封禁"),
/**
* 频繁请求发布
*/
CODE_53501(53501, "频繁请求发布"),
/**
* Publish ID 无效
*/
CODE_53502(53502, "Publish ID 无效"),
/**
* Article ID 无效
*/
CODE_53600(53600, "Article ID 无效"),
/**
* 参数错误 (invalid parameter)
*/
CODE_61451(61451, "参数错误 (invalid parameter)"),
/**
* 无效客服账号 (invalid kf_account)
*/
CODE_61452(61452, "无效客服账号 (invalid kf_account)"),
/**
* 客服帐号已存在 (kf_account exsited)
*/
CODE_61453(61453, "客服帐号已存在 (kf_account exsited)"),
/**
* 客服帐号名长度超过限制 ( 仅允许 10 个英文字符,不包括 @ 及 @ 后的公众号的微信号 )(invalid kf_acount length)
*/
CODE_61454(61454, "客服帐号名长度超过限制 ( 仅允许 10 个英文字符,不包括 @ 及 @ 后的公众号的微信号 )(invalid kf_acount length)"),
/**
* 客服帐号名包含非法字符 ( 仅允许英文 + 数字 )(illegal character in kf_account)
*/
CODE_61455(61455, "客服帐号名包含非法字符 ( 仅允许英文 + 数字 )(illegal character in kf_account)"),
/**
* 客服帐号个数超过限制 (10 个客服账号 )(kf_account count exceeded)
*/
CODE_61456(61456, "客服帐号个数超过限制 (10 个客服账号 )(kf_account count exceeded)"),
/**
* 无效头像文件类型 (invalid file type)
*/
CODE_61457(61457, "无效头像文件类型 (invalid file type)"),
/**
* 系统错误 (system error)
*/
CODE_61450(61450, "系统错误 (system error)"),
/**
* 日期格式错误 date format error
*/
CODE_61500(61500, "日期格式错误"),
/**
* 部分参数为空 some arguments is empty
*/
CODE_63001(63001, "部分参数为空"),
/**
* 无效的签名 invalid signature
*/
CODE_63002(63002, "无效的签名"),
/**
* 不存在此 menuid 对应的个性化菜单 this menu is not conditionalmenu
*/
CODE_65301(65301, "不存在此 menuid 对应的个性化菜单"),
/**
* 没有相应的用户 no such user
*/
CODE_65302(65302, "没有相应的用户"),
/**
* 没有默认菜单,不能创建个性化菜单 there is no selfmenu, please create selfmenu first
*/
CODE_65303(65303, "没有默认菜单,不能创建个性化菜单"),
/**
* MatchRule 信息为空 match rule empty
*/
CODE_65304(65304, "MatchRule 信息为空"),
/**
* 个性化菜单数量受限 menu count limit
*/
CODE_65305(65305, "个性化菜单数量受限"),
/**
* 不支持个性化菜单的帐号 conditional menu not support
*/
CODE_65306(65306, "不支持个性化菜单的帐号"),
/**
* 个性化菜单信息为空 conditional menu is empty
*/
CODE_65307(65307, "个性化菜单信息为空"),
/**
* 包含没有响应类型的 button exist empty button act
*/
CODE_65308(65308, "包含没有响应类型的 button"),
/**
* 个性化菜单开关处于关闭状态 conditional menu switch is closed
*/
CODE_65309(65309, "个性化菜单开关处于关闭状态"),
/**
* 填写了省份或城市信息,国家信息不能为空 region info: country is empty
*/
CODE_65310(65310, "填写了省份或城市信息,国家信息不能为空"),
/**
* 填写了城市信息,省份信息不能为空 region info: province is empty
*/
CODE_65311(65311, "填写了城市信息,省份信息不能为空"),
/**
* 不合法的国家信息 invalid country info
*/
CODE_65312(65312, "不合法的国家信息"),
/**
* 不合法的省份信息 invalid province info
*/
CODE_65313(65313, "不合法的省份信息"),
/**
* 不合法的城市信息 invalid city info
*/
CODE_65314(65314, "不合法的城市信息"),
/**
* 该公众号的菜单设置了过多的域名外跳(最多跳转到 3 个域名的链接) domain count reach limit
*/
CODE_65316(65316, "该公众号的菜单设置了过多的域名外跳(最多跳转到 3 个域名的链接)"),
/**
* 不合法的 URL contain invalid url
*/
CODE_65317(65317, "不合法的 URL"),
/**
* 无效的签名 invalid signature
*/
CODE_87009(87009, "无效的签名"),
/**
* POST 数据参数不合法
*/
CODE_9001001(9001001, "POST 数据参数不合法"),
/**
* 远端服务不可用
*/
CODE_9001002(9001002, "远端服务不可用"),
/**
* Ticket 不合法
*/
CODE_9001003(9001003, "Ticket 不合法"),
/**
* 获取摇周边用户信息失败
*/
CODE_9001004(9001004, "获取摇周边用户信息失败"),
/**
* 获取商户信息失败
*/
CODE_9001005(9001005, "获取商户信息失败"),
/**
* 获取 OpenID 失败
*/
CODE_9001006(9001006, "获取 OpenID 失败"),
/**
* 上传文件缺失
*/
CODE_9001007(9001007, "上传文件缺失"),
/**
* 上传素材的文件类型不合法
*/
CODE_9001008(9001008, "上传素材的文件类型不合法"),
/**
* 上传素材的文件尺寸不合法
*/
CODE_9001009(9001009, "上传素材的文件尺寸不合法"),
/**
* 上传失败
*/
CODE_9001010(9001010, "上传失败"),
/**
* 帐号不合法
*/
CODE_9001020(9001020, "帐号不合法"),
/**
* 已有设备激活率低于 50% ,不能新增设备
*/
CODE_9001021(9001021, "已有设备激活率低于 50% ,不能新增设备"),
/**
* 设备申请数不合法,必须为大于 0 的数字
*/
CODE_9001022(9001022, "设备申请数不合法,必须为大于 0 的数字"),
/**
* 已存在审核中的设备 ID 申请
*/
CODE_9001023(9001023, "已存在审核中的设备 ID 申请"),
/**
* 一次查询设备 ID 数量不能超过 50
*/
CODE_9001024(9001024, "一次查询设备 ID 数量不能超过 50"),
/**
* 设备 ID 不合法
*/
CODE_9001025(9001025, "设备 ID 不合法"),
/**
* 页面 ID 不合法
*/
CODE_9001026(9001026, "页面 ID 不合法"),
/**
* 页面参数不合法
*/
CODE_9001027(9001027, "页面参数不合法"),
/**
* 一次删除页面 ID 数量不能超过 10
*/
CODE_9001028(9001028, "一次删除页面 ID 数量不能超过 10"),
/**
* 页面已应用在设备中,请先解除应用关系再删除
*/
CODE_9001029(9001029, "页面已应用在设备中,请先解除应用关系再删除"),
/**
* 一次查询页面 ID 数量不能超过 50
*/
CODE_9001030(9001030, "一次查询页面 ID 数量不能超过 50"),
/**
* 时间区间不合法
*/
CODE_9001031(9001031, "时间区间不合法"),
/**
* 保存设备与页面的绑定关系参数错误
*/
CODE_9001032(9001032, "保存设备与页面的绑定关系参数错误"),
/**
* 门店 ID 不合法
*/
CODE_9001033(9001033, "门店 ID 不合法"),
/**
* 设备备注信息过长
*/
CODE_9001034(9001034, "设备备注信息过长"),
/**
* 设备申请参数不合法
*/
CODE_9001035(9001035, "设备申请参数不合法"),
/**
* 查询起始值 begin 不合法
*/
CODE_9001036(9001036, "查询起始值 begin 不合法");
private final int code;
private final String msg;
WxOpenErrorMsgEnum(int code, String msg) {
this.code = code;
this.msg = msg;
}
}
package com.liang.wechat.factory;
import com.liang.wechat.strategy.MessageStrategy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import java.util.Map;
import java.util.Optional;
@Configuration
@Slf4j
public class MessageFactory {
//Spring会自动将实现类注入到这个Map中,key为bean id,value值则为对应的策略实现类
@Autowired
private Map<String, MessageStrategy> MESSAGE_STRATEGY_MAP;
public MessageStrategy getMessageStrategy(String msgType, String eventType) {
if (msgType.equals("event") && eventType != null) {
msgType = eventType;
}
return Optional.ofNullable(MESSAGE_STRATEGY_MAP.get(msgType)).orElse(null);
}
}
package com.liang.wechat.handler;
import com.liang.wechat.bean.message.ImageMessage;
import com.liang.wechat.strategy.MessageStrategy;
import com.liang.wechat.utils.WechatUtil;
import com.liang.wechat.utils.XmlUtil;
import org.springframework.stereotype.Service;
@Service("image")
public class ImageMessageHandler implements MessageStrategy {
@Override
public String handleMessage(String message) {
ImageMessage imageMessage = XmlUtil.xmlToBean(message, ImageMessage.class);
String mediaId = imageMessage.getMediaId();
return WechatUtil.sendImage(imageMessage,mediaId);
}
}
package com.liang.wechat.handler;
import com.liang.wechat.bean.message.LinkMessage;
import com.liang.wechat.strategy.MessageStrategy;
import com.liang.wechat.utils.WechatUtil;
import com.liang.wechat.utils.XmlUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@Service("link")
public class LinkMessageHandler implements MessageStrategy {
@Override
public String handleMessage(String message) {
LinkMessage linkMessage = XmlUtil.xmlToBean(message, LinkMessage.class);
log.info("发了链接消息");
//return WechatUtil.sendText(linkMessage,"发了链接消息");
return null;
}
}
package com.liang.wechat.handler;
import com.liang.wechat.bean.message.LocationMessage;
import com.liang.wechat.strategy.MessageStrategy;
import com.liang.wechat.utils.WechatUtil;
import com.liang.wechat.utils.XmlUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.text.MessageFormat;
@Slf4j
@Service("location")
public class LocationMessageHandler implements MessageStrategy {
@Override
public String handleMessage(String message) {
log.info("发了地理位置消息");
LocationMessage locationMessage = XmlUtil.xmlToBean(message, LocationMessage.class);
//return WechatUtil.sendText(locationMessage, "发了地理位置消息");
String pattern = "您发送的地理位置消息如下:{0},{1},{2},{3}";
String content = MessageFormat.format(pattern, locationMessage.getLocation_X(), locationMessage.getLocation_Y(), locationMessage.getScale(), locationMessage.getLabel());
return WechatUtil.sendText(locationMessage, content);
}
}
package com.liang.wechat.handler;
import com.liang.wechat.bean.message.ShortVideoMessage;
import com.liang.wechat.strategy.MessageStrategy;
import com.liang.wechat.utils.WechatUtil;
import com.liang.wechat.utils.XmlUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@Service("shortvideo")
public class ShortVideoMessageHandler implements MessageStrategy {
@Override
public String handleMessage(String message) {
log.info("发了小视频消息");
ShortVideoMessage shortVideoMessage = XmlUtil.xmlToBean(message, ShortVideoMessage.class);
//return WechatUtil.sendText(shortVideoMessage, "发了小视频消息");
return null;
}
}
package com.liang.wechat.handler;
import com.liang.wechat.bean.message.TextMessage;
import com.liang.wechat.strategy.MessageStrategy;
import com.liang.wechat.utils.WechatUtil;
import com.liang.wechat.utils.XmlUtil;
import org.springframework.stereotype.Service;
@Service("text")
public class TextMessageHandler implements MessageStrategy {
@Override
public String handleMessage(String message) {
TextMessage textMessage = XmlUtil.xmlToBean(message, TextMessage.class);
//return WechatUtil.sendText(textMessage, "你好");
return WechatUtil.sendText(textMessage);
}
}
package com.liang.wechat.handler;
import com.liang.wechat.bean.message.VideoMessage;
import com.liang.wechat.strategy.MessageStrategy;
import com.liang.wechat.utils.WechatUtil;
import com.liang.wechat.utils.XmlUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@Service("video")
public class VideoMessageHandler implements MessageStrategy {
@Override
public String handleMessage(String message) {
log.info("发了视频消息");
VideoMessage videoMessage = XmlUtil.xmlToBean(message, VideoMessage.class);
//return WechatUtil.sendText(videoMessage, "发了视频消息");
//TODO 格式都对不知道为什么不行
//VideoMessage.Video video = new VideoMessage.Video();
//video.setMediaId(videoMessage.getMediaId());
//video.setTitle("这是视频");
//video.setDescription("这是描述");
//return WechatUtil.sendVideo(videoMessage, video);
return null;
}
}
package com.liang.wechat.handler;
import com.liang.wechat.bean.message.VideoMessage;
import com.liang.wechat.bean.message.VoiceMessage;
import com.liang.wechat.strategy.MessageStrategy;
import com.liang.wechat.utils.WechatUtil;
import com.liang.wechat.utils.XmlUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@Service("voice")
public class VoiceMessageHandler implements MessageStrategy {
@Override
public String handleMessage(String message) {
log.info("发了语音消息");
VoiceMessage voiceMessage = XmlUtil.xmlToBean(message, VoiceMessage.class);
//return WechatUtil.sendText(voiceMessage, "发了语音消息");
String mediaId = voiceMessage.getMediaId();
return WechatUtil.sendVoice(voiceMessage, mediaId);
}
}
package com.liang.wechat.handler.event;
import com.liang.wechat.strategy.MessageStrategy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* 菜单点击事件处理
*/
@Slf4j
@Service("CLICK")
public class MenuClickEventHandler implements MessageStrategy {
@Override
public String handleMessage(String message) {
log.info("点击了");
return null;
}
}
package com.liang.wechat.handler.event;
import com.liang.wechat.strategy.MessageStrategy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* 菜单链接跳转事件处理
*/
@Slf4j
@Service("VIEW")
public class MenuViewEventHandler implements MessageStrategy {
@Override
public String handleMessage(String message) {
log.info("链接跳转了");
return null;
}
}
package com.liang.wechat.handler.event;
import com.liang.wechat.strategy.MessageStrategy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* 扫码事件处理
*/
@Slf4j
@Service("scan")
public class ScanEventHandler implements MessageStrategy {
@Override
public String handleMessage(String message) {
log.info("扫码了");
return null;
}
}
package com.liang.wechat.handler.event;
import com.liang.wechat.bean.event.EventMessage;
import com.liang.wechat.bean.message.LocationMessage;
import com.liang.wechat.bean.message.NewsMessage;
import com.liang.wechat.strategy.MessageStrategy;
import com.liang.wechat.utils.WechatUtil;
import com.liang.wechat.utils.XmlUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.Collections;
/**
* 关注事件处理
*/
@Slf4j
@Service("subscribe")
public class SubscribeEventHandler implements MessageStrategy {
@Override
public String handleMessage(String message) {
EventMessage eventMessage = XmlUtil.xmlToBean(message, EventMessage.class);
//return WechatUtil.sendText(locationMessage, "你好呀,欢迎关注我的公众号");
NewsMessage.Article article = new NewsMessage.Article();
article.setTitle("你好呀");
article.setDescription("欢迎关注我的公众号");
//article.setPicUrl("https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png");
article.setUrl("https://www.baidu.com/");
return WechatUtil.sendNews(eventMessage, Collections.singletonList(article));
}
}
package com.liang.wechat.handler.event;
import com.liang.wechat.bean.event.EventMessage;
import com.liang.wechat.strategy.MessageStrategy;
import com.liang.wechat.utils.XmlUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* 取关事件处理
*/
@Slf4j
@Service("unsubscribe")
public class UnsubscribeEventHandler implements MessageStrategy {
@Override
public String handleMessage(String message) {
EventMessage eventMessage = XmlUtil.xmlToBean(message, EventMessage.class);
String openId = eventMessage.getFromUserName();
log.info("openId:{} 取关了", openId);
return null;
}
}
package com.liang.wechat.service.material;
public interface MaterialService {
}
package com.liang.wechat.service.material;
import org.springframework.stereotype.Service;
@Service
public class MaterialServiceImpl implements MaterialService {
}
package com.liang.wechat.strategy;
/**
* 消息处理策略
*/
public interface MessageStrategy {
String handleMessage(String message);
}
package com.liang.wechat.utils;
import com.liang.wechat.bean.BaseMessage;
import com.liang.wechat.bean.message.*;
import com.liang.wechat.config.WechatConfig;
import com.liang.wechat.enumeration.MessageType;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@Component
public class WechatUtil {
@Autowired
private WechatConfig wechatConfig;
public boolean checkSignature(String signature, String timestamp, String nonce) {
//1.将token、timestamp、nonce三个参数进行字典序排序
String[] arr = new String[]{wechatConfig.getToken(), timestamp, nonce};
Arrays.sort(arr);
//2.将三个参数字符串拼接成一个字符串进行sha1加密
String str = arr[0] + arr[1] + arr[2];
String sha1Hex = DigestUtils.sha1Hex(str);
return signature.equals(sha1Hex);
}
public static String sendText(TextMessage textMessage) {
return sendText(textMessage, textMessage.getContent());
}
public static String sendText(BaseMessage baseMessage, String content) {
TextMessage textMessage = new TextMessage();
textMessage.setCreateTime(System.currentTimeMillis());
textMessage.setFromUserName(baseMessage.getToUserName());
textMessage.setToUserName(baseMessage.getFromUserName());
textMessage.setMsgType(MessageType.TEXT.getType());
textMessage.setContent(content);
return XmlUtil.beanToXml(textMessage);
}
public static String sendImage(BaseMessage baseMessage, String mediaId) {
ImageMessage imageMessage = new ImageMessage();
imageMessage.setCreateTime(System.currentTimeMillis());
imageMessage.setFromUserName(baseMessage.getToUserName());
imageMessage.setToUserName(baseMessage.getFromUserName());
imageMessage.setMsgType(MessageType.IMAGE.getType());
imageMessage.setImage(new ImageMessage.Image(mediaId));
return XmlUtil.beanToXml(imageMessage);
}
public static String sendVoice(BaseMessage baseMessage, String mediaId) {
VoiceMessage voiceMessage = new VoiceMessage();
voiceMessage.setCreateTime(System.currentTimeMillis());
voiceMessage.setFromUserName(baseMessage.getToUserName());
voiceMessage.setToUserName(baseMessage.getFromUserName());
voiceMessage.setMsgType(MessageType.VOICE.getType());
voiceMessage.setVoice(new VoiceMessage.Voice(mediaId != null ? mediaId : ""));
return XmlUtil.beanToXml(voiceMessage);
}
public static String sendMusic(BaseMessage baseMessage, MusicMessage.Music music) {
MusicMessage musicMessage = new MusicMessage();
musicMessage.setCreateTime(System.currentTimeMillis());
musicMessage.setFromUserName(baseMessage.getToUserName());
musicMessage.setToUserName(baseMessage.getFromUserName());
musicMessage.setMsgType(MessageType.VOICE.getType());
musicMessage.setMusic(music);
return XmlUtil.beanToXml(musicMessage);
}
public static String sendVideo(BaseMessage baseMessage, VideoMessage.Video video) {
VideoMessage videoMessage = new VideoMessage();
videoMessage.setCreateTime(System.currentTimeMillis());
videoMessage.setFromUserName(baseMessage.getToUserName());
videoMessage.setToUserName(baseMessage.getFromUserName());
videoMessage.setMsgType(MessageType.VIDEO.getType());
videoMessage.setVideo(video);
String s = XmlUtil.beanToXml(videoMessage);
System.out.println("s = " + s);
return s;
}
public static String sendNews(BaseMessage baseMessage, List<NewsMessage.Article> articles) {
NewsMessage newsMessage = new NewsMessage();
newsMessage.setCreateTime(System.currentTimeMillis());
newsMessage.setFromUserName(baseMessage.getToUserName());
newsMessage.setToUserName(baseMessage.getFromUserName());
newsMessage.setMsgType(MessageType.NEWS.getType());
newsMessage.setArticleCount(articles.size());
newsMessage.setArticles(articles);
return XmlUtil.beanToXml(newsMessage);
}
}
package com.liang.wechat.utils;
import com.liang.wechat.bean.BaseMessage;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import java.io.Writer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class XmlUtil {
public static Map<String, String> xmlToMap(String xmlStr) throws Exception {
Map<String, String> map = new HashMap<>(16);
//将xml格式的字符串转换成Document对象
Document doc = DocumentHelper.parseText(xmlStr);
//获取根节点
Element root = doc.getRootElement();
//获取根节点下的所有元素
List<Element> children = root.elements();
//循环所有子元素
if (children != null && children.size() > 0) {
for (Element o : children) {
map.put(o.getName(), o.getTextTrim());
}
}
return map;
}
public static <T extends BaseMessage> String beanToXml(T t) {
XStream xStream = new XStream();
xStream.processAnnotations(t.getClass());
return xStream.toXML(t);
}
public static <T> T xmlToBean(String xml, Class<T> clazz) {
XStream xstream = newXStreamInstance();
//先忽略未知的元素,防止从xml转换成对象时报错
xstream.ignoreUnknownElements();
xstream.processAnnotations(clazz);
return (T) xstream.fromXML(xml);
}
/**
* 扩展xstream,使其支持CDATA块
*/
private static XStream newXStreamInstance() {
return new XStream(new XppDriver() {
@Override
public HierarchicalStreamWriter createWriter(Writer out) {
return new PrettyPrintWriter(out) {
// 对所有xml节点的转换都增加CDATA标记
boolean cdata = true;
@Override
protected void writeText(QuickWriter writer, String text) {
if (this.cdata) {
writer.write("<![CDATA[");
writer.write(text);
writer.write("]]>");
} else {
writer.write(text);
}
}
};
}
});
}
}
server:
port: 8080
wx:
appId: wxdd95a0d4eb1c29f7
secret: d33cf03467a02d897bed1e1a1b7605f9
token: abc
spring:
redis:
host: 47.98.134.122
database: 2
port: 6379
timeout: 3000
{
"button":[
{
"name":"热门产品",
"sub_button":[
{
"type":"miniprogram",
"name":"知微舆论场",
"url":"https://trends.zhiweidata.com/",
"appid":"wx8f47f701f6a8e768",
"pagepath":"pages/index-v/index-v"
},
{
"type":"miniprogram",
"name":"危机案例库",
"url":"https://crisis.zhiweidata.com/",
"appid":"wx3287f77ae759a173",
"pagepath":"pages/index/index"
},
{
"type":"view",
"name":"知微事见",
"url":"https://ef.zhiweidata.com/"
}]
},
{
"name":"精选内容",
"sub_button":[
{
"type":"view",
"name":"新消费研究",
"url":"https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzU3MDMzMzIxMA==&action=getalbum&album_id=2522641317311709185&scene=173&from_msgid=2247485024&from_itemidx=1&count=3&nolastread=1#wechat_redirect"
},
{
"type":"view",
"name":"危机复盘",
"url":"https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzU3MDMzMzIxMA==&action=getalbum&album_id=2392137959220363267&scene=173&from_msgid=2247484665&from_itemidx=1&count=3&nolastread=1#wechat_redirect"
},
{
"type":"view",
"name":"年度报告",
"url":"https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzU3MDMzMzIxMA==&action=getalbum&album_id=2406680589417496577&scene=173&from_msgid=2247484643&from_itemidx=1&count=3&nolastread=1#wechat_redirect"
}]
},
{
"name":"限时福利",
"sub_button":[
{
"type":"click",
"name":"解锁案例",
"key":"UNLOCK_CASE"
},
{
"type":"click",
"name":"联系客服",
"key":"CONTACT_US"
}]
}]
}
\ No newline at end of file
package com.liang.wechat;
import com.liang.wechat.constant.WechatConstant;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.ResponseEntity;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class AccessTokenTest {
@Autowired
private TestRestTemplate testRestTemplate;
@Value("${wx.appid}")
private String appid;
@Value("${wx.secret}")
private String secret;
@Test
public void testGetAccessToken() {
ResponseEntity<String> forEntity = testRestTemplate.getForEntity(WechatConstant.ACCESS_TOKEN_URL, String.class, appid, secret);
System.out.println(forEntity);
}
}
package com.liang.wechat;
import com.liang.wechat.constant.WechatConstant;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.HashMap;
import java.util.Map;
@SpringBootTest
public class QrCodeTest {
@Test
public void testGetQrCodeUrl(){
}
//private String createTicket(String accessToken) {
// Map<String, String> intMap = new HashMap<>(8);
// intMap.put("scene_str", sceneStr);
// Map<String, Map<String, String>> mapMap = new HashMap<>(8);
// mapMap.put("scene", intMap);
// Map<String, Object> paramsMap = new HashMap<>(8);
// paramsMap.put("expire_seconds", expireSeconds);
// paramsMap.put("action_name", "QR_STR_SCENE");
// paramsMap.put("action_info", mapMap);
// ResponseEntity<JSONObject> entity = restTemplate.postForEntity(WechatConstant.CREATE_QRCODE_URL, paramsMap, JSONObject.class, accessToken);
// return entity.getBody().getString("ticket");
//}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment