微信微服务
1. 背景
2. 业务逻辑
3. 设计方案
1. 背景
现有业务和微信openId关联,目前,消费者测存在多个公众号时需要修改为:业务和unionid关联。
此设计包含如下设计内容
2.业务逻辑
微信微服务逻辑设计
用户:浏览器,手机客户端
消费者服务:业务系统
微信微服务:所有和微信api的接口,比如监听事件:关注事件,取消关注事件,扫码事件,验证网页授权码是否有效
3.设计方案
本次微信微服务是基于weixin-java-tools3.2.0插件进行改造,贴出关键代码供大家进行学习,如需要整个项目,关注“IT技术论坛”公众号,并在微信公众中“关于我们”中加我为好友,我私发给你。
微信服务器回调代码
@RequestMapping("/wxOfficial/entrance/{appId}")
public class WxOfficialController extends GenericController{
@Autowired
private Environment environment;
@Autowired
private WeixinService wxService;
@ResponseBody
@GetMapping(produces = "text/plain;charset=utf-8")
public String authGet(@RequestParam(name = "signature", required = false) String signature,
@RequestParam(name = "timestamp", required = false) String timestamp,
@RequestParam(name = "nonce", required = false) String nonce,
@RequestParam(name = "echostr", required = false) String echostr,
@PathVariable String appId) {
this.logger.info("\n接收到来自微信服务器的认证消息:[{}, {}, {}, {}]", signature, timestamp, nonce, echostr);
if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) {
throw new IllegalArgumentException("请求参数非法,请核实!");
}
final WxMpInMemoryConfigStorage wxConfig = WeixinServiceFactory.getWxConfig(appId,environment);
wxService.setWxMpConfigStorage(wxConfig);
if (wxService.checkSignature(timestamp, nonce, signature)) {
return echostr;
}
return "非法请求";
}
@ResponseBody
@PostMapping(produces = "application/xml; charset=UTF-8")
public String post(@RequestBody String requestBody, @RequestParam("signature") String signature,
@RequestParam(name = "encrypt_type", required = false) String encType,
@RequestParam(name = "msg_signature", required = false) String msgSignature,
@RequestParam("timestamp") String timestamp, @RequestParam("nonce") String nonce,
@PathVariable String appId) {
this.logger.info(
"\n接收微信请求:[signature=[{}], encType=[{}], msgSignature=[{}],"
+ " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
signature, encType, msgSignature, timestamp, nonce, requestBody);
final WxMpInMemoryConfigStorage wxConfig = WeixinServiceFactory.getWxConfig(appId,environment);
wxService.setWxMpConfigStorage(wxConfig);
if (!wxService.checkSignature(timestamp, nonce, signature)) {
throw new IllegalArgumentException("非法请求,可能属于伪造的请求!");
}
String out = null;
if (encType == null) {
// 明文传输的消息
WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(requestBody);
WxMpXmlOutMessage outMessage = wxService.route(inMessage);
if (outMessage == null) {
return "";
}
out = outMessage.toXml();
} else if ("aes".equals(encType)) {
// aes加密的消息
WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(requestBody,
wxService.getWxMpConfigStorage(), timestamp, nonce, msgSignature);
this.logger.debug("\n消息解密后内容为:\n{} ", inMessage.toString());
WxMpXmlOutMessage outMessage = wxService.route(inMessage);
if (outMessage == null) {
return "";
}
out = outMessage.toEncryptedXml(wxService.getWxMpConfigStorage());
}
this.logger.debug("\n组装回复信息:{}", out);
return out;
}
}
关注事件监听代码:
@Component
public class SubscribeHandler extends AbstractHandler {
@Autowired
private RabbitProducer rabbitProducer;
@Autowired
private MqMessageLogRepository mqMessageLogRepository;
@Autowired
private RabbitConfig rabbitConfig;
@Autowired
private Environment environment;
@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map context, WxMpService wxMpService,
WxSessionManager sessionManager) throws WxErrorException {
this.logger.info("关注用户 OPENID: " + wxMessage.getFromUser());
this.logger.info("关注公众号 AppId:"+wxMpService.getWxMpConfigStorage().getAppId());
JSONObject jsonObject = new JSONObject();
jsonObject.put("error", 0);
String openId = wxMessage.getFromUser();
this.logger.info("新关注用户 OPENID: " + openId);
JSONObject contentObject = (JSONObject) JSONObject.toJSON(wxMessage);
String appId = wxMpService.getWxMpConfigStorage().getAppId();
WxMpUser userWxInfo = wxMpService.getUserService().userInfo(openId, null);
this.logger.info("新关注用户详细信息: " + userWxInfo);
contentObject.put("openId",openId);
contentObject.put("unionId",userWxInfo.getUnionId());
contentObject.put("headImgUrl",userWxInfo.getHeadImgUrl());
contentObject.put("userName",userWxInfo.getNickname());
contentObject.put("nickname",userWxInfo.getNickname());
contentObject.put("country",userWxInfo.getCountry());
contentObject.put("province",userWxInfo.getProvince());
contentObject.put("city",userWxInfo.getCity());
contentObject.put("sex",userWxInfo.getSex());
contentObject.put("language",userWxInfo.getLanguage());
contentObject.put("remark",userWxInfo.getRemark());
contentObject.put("subscribeTime",userWxInfo.getSubscribeTime());
contentObject.put("subscribe",userWxInfo.getSubscribe());
SimpleDateFormat nowTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
contentObject.put("nowTime",nowTime.format(System.currentTimeMillis()));
String eventKey = wxMessage.getEventKey();
if (StringUtils.isNotBlank(eventKey)) {
eventKey = eventKey.replace("qrscene_", "");
contentObject.put("devCode",eventKey);
}
contentObject.put("type","subscribe");
//获取微信appId
contentObject.put("appId",appId);
//userType 1:导购 2:消费者
String userType = environment.getProperty("spring."+appId+".userType");
if("1".equals(userType)){
contentObject.put("appType","org");
}else if("2".equals(userType)){
contentObject.put("appType","customer");
}
String content = JSONObject.toJSONString(contentObject);
this.logger.info("经消息队列传递的用户信息: " + content);
rabbitProducer.sendMsg(content, rabbitConfig.EXCHANGE,rabbitConfig.ROUTINGKEY_SUBSCRIBE);
//记录mq日志
MqMessageLog mqMessageLog = JSONObject.toJavaObject(contentObject,MqMessageLog.class);
mqMessageLogRepository.insert(mqMessageLog);
return null;
}
}
该项目是基于spring cloud构建的微服务,微信公众号配置信息是存放在配置服务中,格式如下
spring:
xxxxx1: #该值为第一个微信公众号appId
#YCC端测试
appId: xxxxx1
appSecret:
token:
aesKey:
xxxxx2: #该值为第二个微信公众号appId
appId:xxxxx2
appSecret:
token:
aesKey: