消息类型枚举
/**
* 微信消息类型枚举
* 开发文档: https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_standard_messages.html
*
* @Author [email protected]
* @Date 2023/3/24 15:59
*/
@Getter
@AllArgsConstructor
public enum WechatMessageTypeEnum {
TEXT("text", "文本消息"),
IMAGE("image", "图片消息"),
VOICE("voice", "语音消息"),
VIDEO("video", "视频消息"),
MUSIC("music", "音乐消息"),
SHORT_VIDEO("shortvideo", "小视频消息"),
LOCATION("location", "地理位置消息"),
LINK("link", "链接消息"),
EVENT("event", "链接消息");
/**
* 消息类型
*/
private final String type;
/**
* 消息名称
*/
private final String name;
/**
* 获取所有的消息类型集合
*
* @param
* @return List
*/
public static List<String> getMessageTypeList() {
return Arrays.asList(
TEXT.getType(),
IMAGE.getType(),
VOICE.getType(),
VIDEO.getType(),
MUSIC.getType(),
SHORT_VIDEO.getType(),
LOCATION.getType(),
LINK.getType(),
EVENT.getType()
);
}
}
private static Map<String, Class> MESSAGE_HANDLER_MAP = new HashMap<>();
@PostConstruct
public void initMessageHander() {
MESSAGE_HANDLER_MAP.put(WechatMessageTypeEnum.TEXT.getType(), TextMessage.class);
MESSAGE_HANDLER_MAP.put(WechatMessageTypeEnum.IMAGE.getType(), ImageMessage.class);
}
/**
* 微信请求的基础消息处理统一入口-方式一
*
* @param request 微信请求消息
* @return String
*/
public String messageHandle(WechatMessageRequest request) {
log.info("======>[WechatMessageHandler::messageHandle] 接收到微信请求消息: {}", request);
// 检查消息类型
List<String> msgTypeList = WechatMessageTypeEnum.getMessageTypeList();
if (!msgTypeList.contains(request.getMsgType())) {
log.warn("======>[WechatMessageHandler::messageHandle] 无法处理的事件消息: {}", request);
return WechatReturnContentEnum.SUCCESS.getContent();
}
Assert.isTrue(msgTypeList.contains(request.getMsgType()), "无法处理的消息类型:" + request.getMsgType());
try {
// 获取Method
Class aClass = MESSAGE_HANDLER_MAP.get(request.getMsgType());
Method method = this.getClass().getDeclaredMethod("allTypeMessageHandle", aClass);
method.setAccessible(true);
// 拷贝
ConverterRegistry converterRegistry = ConverterRegistry.getInstance();
Object convert = converterRegistry.convert(aClass, request);
// 反射
Object result = method.invoke(this, convert);
return Convert.toStr(result, WechatReturnContentEnum.SUCCESS.getContent());
} catch (Exception e) {
log.error("消息处理失败, 失败原因:{}", e.getMessage());
}
return WechatReturnContentEnum.SUCCESS.getContent();
}
/**
* 处理微信请求的图片消息
*
* @param imageMessage 微信请求的图片消息
* @return String
*/
private String allTypeMessageHandle(ImageMessage imageMessage) {
// TODO: 业务逻辑
return WechatReturnContentEnum.SUCCESS.getContent();
}
/**
* 处理微信请求的文本消息
*
* @param textMessage 微信请求的文本消息
* @return String
*/
private String allTypeMessageHandle(TextMessage textMessage) {
// TODO: 业务逻辑
return WechatReturnContentEnum.SUCCESS.getContent();
}
private static Map<String, MessageRoute> MESSAGE_HANDLER_ROUTE_MAP = new HashMap<>();
@PostConstruct
public void initMessageHanderRounte() {
MESSAGE_HANDLER_ROUTE_MAP.put(WechatMessageTypeEnum.TEXT.getType(), new MessageRoute<TextMessage>(this::textHandle, new TextMessage()));
MESSAGE_HANDLER_ROUTE_MAP.put(WechatMessageTypeEnum.IMAGE.getType(), new MessageRoute<ImageMessage>(this::imageHandle, new ImageMessage()));
}
/**
* 微信请求的基础消息处理统一入口-方式二
*
* @param request
* @return String
*/
public String messageRounteHandle(WechatMessageRequest request) {
log.info("======>[WechatMessageHandler::messageHandle] 接收到微信请求消息: {}", request);
// 检查消息类型
List<String> msgTypeList = WechatMessageTypeEnum.getMessageTypeList();
if (!msgTypeList.contains(request.getMsgType())) {
log.warn("======>[WechatMessageHandler::messageHandle] 无法处理的事件消息: {}", request);
return "success";
}
// 获取消息路由
MessageRoute messageRoute = MESSAGE_HANDLER_ROUTE_MAP.get(request.getMsgType());
// 拷贝
BeanUtils.copyProperties(request, messageRoute.getObj());
// 调用
Object result = messageRoute.getFunction().apply(messageRoute.getObj());
// 结果处理
return Convert.toStr(result, WechatReturnContentEnum.SUCCESS.getContent());
}
/**
* 图片消息处理
*
* @param imageMessage 请求的图片消息
* @return String
*/
private String imageHandle(ImageMessage imageMessage) {
// TODO: 业务逻辑
return WechatReturnContentEnum.SUCCESS.getContent();
}
/**
* 文本消息处理
*
* @param textMessage 请求的文本消息
* @return String
*/
private String textHandle(TextMessage textMessage) {
// TODO: 业务逻辑
return WechatReturnContentEnum.SUCCESS.getContent();
}
以上代码,违背了面向对象编程的开闭原则以及单一原则。
/**
* 策略模式接口
*
* @Author [email protected]
* @Date 2023/3/27 17:10
*/
public interface WechatMessageStrategy<T> {
/**
* 获取消息类型
*
* @return String
*/
String getMessageType();
/**
* 获取调用方法参数对象
*
* @param request 微信请求参数
* @return T
*/
T getParam(WechatMessageRequest request);
/**
* 封装的公用算法(具体的处理消息方法)
*
* @param message
* @return String
*/
String handleMessage(T message);
}
/**
* 微信推送文本消息处理策略
*
* @Author [email protected]
* @Date 2023/3/27 17:14
*/
@Slf4j
@Component
public class WechatTextMessageStrategy implements WechatMessageStrategy<TextMessage> {
/**
* 获取消息类型
*
* @return String
*/
@Override
public String getMessageType() {
return WechatMessageTypeEnum.TEXT.getType();
}
/**
* 获取调用方法参数对象
*
* @param request 微信请求参数
* @return TextMessage
*/
@Override
public TextMessage getParam(WechatMessageRequest request) {
TextMessage textMessage = new TextMessage();
BeanUtils.copyProperties(request, textMessage);
return textMessage;
}
/**
* 处理微信请求的文本消息
*
* @param message 微信请求的文本消息
* @return String
*/
@Override
public String handleMessage(TextMessage message) {
log.info("处理[{}], 消息内容:{}", WechatMessageTypeEnum.TEXT.getName(), message);
return WechatReturnContentEnum.SUCCESS.getContent();
}
}
/**
* 微信推送图片消息处理策略
*
* @Author [email protected]
* @Date 2023/3/27 17:14
*/
@Slf4j
@Component
public class WechatImageMessageStrategy implements WechatMessageStrategy<ImageMessage> {
/**
* 获取消息类型
*
* @return String
*/
@Override
public String getMessageType() {
return WechatMessageTypeEnum.IMAGE.getType();
}
/**
* 获取调用方法参数对象
*
* @param request 微信请求参数
* @return ImageMessage
*/
@Override
public ImageMessage getParam(WechatMessageRequest request) {
ImageMessage imageMessage = new ImageMessage();
BeanUtils.copyProperties(request, imageMessage);
return imageMessage;
}
/**
* 处理微信请求的图片消息
*
* @param message 微信请求的图片消息
* @return String
*/
@Override
public String handleMessage(ImageMessage message) {
log.info("处理[{}], 消息内容:{}", WechatMessageTypeEnum.IMAGE.getName(), message);
return WechatReturnContentEnum.SUCCESS.getContent();
}
}
借助spring的生命周期,使用ApplicationContextAware接口,把对用的策略,初始化到map里面。然后对外提供resolveMessage方法即可。
/**
* 使用策略模式处理微信请求消息
*
* @Author [email protected]
* @Date 2023/3/27 17:09
*/
@Slf4j
@Component
public class WechatMessageAware implements ApplicationContextAware {
/**
* 消息类型策略
*/
private Map<String, WechatMessageStrategy> msgTypeMap = new ConcurrentHashMap<>();
/**
* 解析消息
*
* @param request 微信消息请求参数
* @return String
*/
public String resolveMessage(WechatMessageRequest request) {
// 获取微信消息策略
WechatMessageStrategy wechatMessageTypeStrategy = msgTypeMap.get(request.getMsgType());
// 判断是否存在该策略
if (wechatMessageTypeStrategy == null) {
log.error("消息策略不存在, 消息类型:{}, 请求参数:{}", request.getMsgType(), request);
return WechatReturnContentEnum.SUCCESS.getContent();
}
// 返回数据
return wechatMessageTypeStrategy.handleMessage(wechatMessageTypeStrategy.getParam(request));
}
/**
* 把不同策略放到map
*
* @param applicationContext 应用上下文对象
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
// 获取接口下所有实现类
Map<String, WechatMessageStrategy> beansOfTypeMap = applicationContext.getBeansOfType(WechatMessageStrategy.class);
// 将所有的实现类添加到msgTypeMap中
this.msgTypeMap = beansOfTypeMap.values()
.stream()
.collect(Collectors.toMap(e -> e.getMessageType(), e -> e));
}
}