java微信公众号自动回复文字加图片
前提:第一次发布文章,如有写的不好的地方请指正或代码上可以优化的地方也请各路大神多多指教。顺带想吐槽下微信开发文档真的太恶心了,第一次接触下来让人头晕眼花,通过查阅各种资料后理清了思路,在此写上总结。
开发流程
- 服务器(url)接口配置
- 发送文字(根据微信公众号文档“接收事件推送”事件接口编写代码)
- 生成二维码(账号管理下的“生成带参数的二维码”事件接口编写代码)
- 根据UI的图组合微信头像、微信名字、公众号二维码并调用素材管理下的“新增临时素材”接口上传图片
- 发送图片(调用消息管理下的客服消息下的客服接口-发消息(图片)接口)
- 进行裂变(调用“扫描带参数二维码事件”)(此步骤还未开发完,需根据业务需求变动)
详细流程,附上代码:
第一步服务器(url)接口配置
服务器(url)接口配置,此步骤就是微信授权接口的过程,如果域名都不改变,微信只会校验一次。此请求微信文档中说明了是get请求。
/**
* 微信消息接收和token验证
* @param request
* @param response
*/
@RequestMapping(value = "/weChatToken", method = RequestMethod.GET)
public void weChatToken(HttpServletRequest request, HttpServletResponse response){
boolean isGet = request.getMethod().toLowerCase().equals("get");
if (isGet) {
// 微信加密签名
String signature = request.getParameter("signature");
// 时间戳
String timestamp = request.getParameter("timestamp");
// 随机数
String nonce = request.getParameter("nonce");
// 随机字符串
String echostr = request.getParameter("echostr");
// 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败
if (signature != null && WeChatUtil.checkSignature(signature, timestamp, nonce)) {
try {
PrintWriter print = response.getWriter();
print.write(echostr);
print.flush();
} catch (IOException e) {
log.error("微信消息接收和token验证异常",e);
}
}
}
}
第二步发送文字
我这边的需求是发送的文字中要带上微信名称,所以还需要调用微信的获取accessToken接口跟获取用户信息接口。获取用户信息接口中需要openId,在用户点击关注微信公众号时,微信会自动发送过来。微信为什么会知道咱们的接口呢,因为咱们已经在第一步授权了接口,微信会以默认post请求的方式调用相同的路由,所以我们还得写一个post请求的接口。注:finally中是发送图片的动作。调用事件中运用了抽象工厂的设计模式,此处还有待优化。
2.1 接口详解
/**
* 微信公众号 -->
* 消息管理 -->
* 接收普通消息、接收事件推送、被动回复用户消息
*
* @param request
* @return
*/
@ResponseBody
@RequestMapping(value = "/weChatToken", method = RequestMethod.POST)
public String responseEvent(HttpServletRequest request){
WeChatMsgService weChatMsgService = null;
Map<String, String> requestMessageMap = null;
try {
// 获取到请求参数
requestMessageMap = XMLUtil.xmlToMap(request);
log.info("获取到参数为:{}",requestMessageMap);
// 判断请求参数中 MsgType的值或判断Event值
String returnMessage = "";
if (WeChatUtil.REQ_MESSAGE_TYPE_EVENT.equals(requestMessageMap.get("MsgType"))) {
// 如果后期有取消订阅事件,此处方法可以去除if
if (WeChatUtil.EVENT_TYPE_SUBSCRIBE.equals(requestMessageMap.get("Event"))) {
weChatMsgService = getType(requestMessageMap.get("Event"));
returnMessage = weChatMsgService.getReturnMessage(requestMessageMap);
}
}
return returnMessage;
} catch (Exception e) {
log.error("微信公众号自动回复异常",e);
}finally {
if (WeChatUtil.EVENT_TYPE_SUBSCRIBE.equals(requestMessageMap.get("Event"))) {
weChatMsgService = weChatCustomerServiceImgMessageServiceImpl;
weChatMsgService.getReturnMessage(requestMessageMap);
}
}
return "";
}
2.1.2 使用设计模式调用不同的业务逻辑(default有待修改)
此处注入了业务层
@Autowired
private WeChatMsgService weChatTextMessageServiceImpl;
/**
* 根据类型选择所需的业务处理逻辑
* @param type
*/
private WeChatMsgService getType(String type){
switch (type) {
case WeChatUtil.EVENT_TYPE_SUBSCRIBE:
return weChatTextMessageServiceImpl;
default:
return null;
}
}
2.1.3 调用业务层组合返回的信息(微信文档要求返回的信息为xml的形式)
@Service
@Slf4j
public class WeChatTextMessageServiceImpl implements WeChatMsgService {
@Autowired
private WeiXinService weiXinService;
@Override
public String getReturnMessage(Map<String,String> requestMessageMap) {
// 获取access_token
WeiXinAccessTokenDto accessToken = weiXinService.getAccessToken();
//获取用户信息
WeiXinUserInfoDto userInfo = null;
if (accessToken.getAccess_token() != null) {
userInfo = weiXinService.getUnionID(accessToken.getAccess_token(), requestMessageMap.get("FromUserName"));
}
TextMessageResponseVo textMessageResponseVo = new TextMessageResponseVo();
textMessageResponseVo.setFromUserName(requestMessageMap.get("ToUserName"));
textMessageResponseVo.setToUserName(requestMessageMap.get("FromUserName"));
textMessageResponseVo.setMsgType("text");
textMessageResponseVo.setCreateTime(System.currentTimeMillis());
textMessageResponseVo.setContent("欢迎" + userInfo.getNickname() + "11111");
String result = WeChatUtil.messageToXml(textMessageResponseVo);
return result;
}
}
2.2 调用微信获取accessToken 的接口(业务层涉及到其他逻辑,所以就不全部粘出来了)
@Override
public WeiXinAccessTokenDto getAccessToken() {
Map<String,String> reqParams = new HashMap<>();
reqParams.put("appid",