最近在进行公司的微信公众号和小程序的开发,由于都是由本人独立研发,所以框架和接口都要自己去搭去写,因此想把相关接口做完之后做一些记录,如今闲来无事就总结下相关接口,本篇内容为:微信公众号研发的服务器配置
要进行服务器配置的话首先登入微信公众平台,总步骤如下:
至此,微信公众平台上的配置就完成了,接下来是java端的接口写法。
开发者提交信息后,微信服务器将发送GET请求到填写的服务器地址URL上,GET请求携带参数如下表所示:
参数 | 描述 |
---|---|
signature | 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。 |
timestamp | 时间戳 |
nonce | 随机数 |
echostr | 随机字符串 |
开发者通过检验signature对请求进行校验(下面有校验方式)。若确认此次GET请求来自微信服务器,请原样返回echostr参数内容,则接入生效,成为开发者成功,否则接入失败。加密/校验流程如下:
1)将token、timestamp、nonce三个参数进行字典序排序
2)将三个参数字符串拼接成一个字符串进行sha1加密
3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
官方文档链接:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319
官方文档里还给了个PHP的代码示例,不过我做的框架是java的SSM,开始有点懵,后来在网上借鉴相关在ssm里配置相关借口资料研究之后终于走通,所以现在直接贴出java的相关代码
Controller层
package com.wechat.controller;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.wechat.service.WxService;
@RestController
@RequestMapping("/wxportal")
public class WxController {
@Autowired
private WxService wxService;
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private static org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger("logfile");
@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) {
this.logger.info("\n接收到来自微信服务器的认证消息:[{}, {}, {}, {}]", signature, timestamp, nonce, echostr);
if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) {
throw new IllegalArgumentException("请求参数非法,请核实!");
}
if (this.getWxService().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) {
this.logger.info(
"\n接收微信请求:[signature=[{}], encType=[{}], msgSignature=[{}],"
+ " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
signature, encType, msgSignature, timestamp, nonce, requestBody);
if (!this.wxService.checkSignature(timestamp, nonce, signature)) {
throw new IllegalArgumentException("非法请求,可能属于伪造的请求!");
}
String out = null;
if (encType == null) {//unsubscribe event fromUser=oQmj3t35STb8TZHs7keHSYrYlPos msgType=event
//event=subscribe
// 明文传输的消息
WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(requestBody);
WxMpXmlOutMessage outMessage = this.getWxService().route(inMessage);
if (outMessage == null) {
return "";
}
out = outMessage.toXml();
} else if ("aes".equals(encType)) {
// aes加密的消息
WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(requestBody,
this.getWxService().getWxMpConfigStorage(), timestamp, nonce, msgSignature);
this.logger.debug("\n消息解密后内容为:\n{} ", inMessage.toString());
WxMpXmlOutMessage outMessage = this.getWxService().route(inMessage);
if (outMessage == null) {
return "";
}
out = outMessage.toEncryptedXml(this.getWxService().getWxMpConfigStorage());
}
this.logger.debug("\n组装回复信息:{}", out);
return out;
}
protected WxService getWxService() {
return this.wxService;
}
}
Service层
package com.wechat.service;
import static me.chanjar.weixin.common.api.WxConsts.EventType.LOCATION;
import static me.chanjar.weixin.common.api.WxConsts.EventType.SCAN;
import static me.chanjar.weixin.common.api.WxConsts.EventType.SUBSCRIBE;
import static me.chanjar.weixin.common.api.WxConsts.EventType.UNSUBSCRIBE;
import static me.chanjar.weixin.common.api.WxConsts.MenuButtonType.CLICK;
import static me.chanjar.weixin.common.api.WxConsts.MenuButtonType.VIEW;
import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType.EVENT;
import static me.chanjar.weixin.mp.constant.WxMpEventConstants.POI_CHECK_NOTIFY;
import static me.chanjar.weixin.mp.constant.WxMpEventConstants.CustomerService.KF_CLOSE_SESSION;
import static me.chanjar.weixin.mp.constant.WxMpEventConstants.CustomerService.KF_CREATE_SESSION;
import static me.chanjar.weixin.mp.constant.WxMpEventConstants.CustomerService.KF_SWITCH_SESSION;
import javax.annotation.PostConstruct;
import me.chanjar.weixin.common.api.WxConsts.XmlMsgType;
import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage;
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.bean.kefu.result.WxMpKfOnlineList;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.wechat.config.WxMpConfig;
import com.wechat.handler.KfSessionHandler;
import com.wechat.handler.LocationHandler;
import com.wechat.handler.LogHandler;
import com.wechat.handler.MenuHandler;
import com.wechat.handler.MsgHandler;
import com.wechat.handler.NullHandler;
import com.wechat.handler.StoreCheckNotifyHandler;
import com.wechat.handler.SubscribeHandler;
import com.wechat.handler.UnsubscribeHandler;
@Service
public class WxService extends WxMpServiceImpl {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
protected LogHandler logHandler;
@Autowired
protected NullHandler nullHandler;
@Autowired
protected KfSessionHandler kfSessionHandler;
@Autowired
protected StoreCheckNotifyHandler storeCheckNotifyHandler;
@Autowired
private WxMpConfig wxConfig;
@Autowired
private LocationHandler locationHandler;
@Autowired
private MenuHandler menuHandler;
@Autowired
private MsgHandler msgHandler;
@Autowired
private UnsubscribeHandler unsubscribeHandler;
@Autowired
private SubscribeHandler subscribeHandler;
private WxMpMessageRouter router;
@PostConstruct
public void init() {
final WxMpInMemoryConfigStorage config = new WxMpInMemoryConfigStorage();
// 设置微信公众号的appid
config.setAppId(this.wxConfig.getAppid());
// 设置微信公众号的app corpSecret
config.setSecret(this.wxConfig.getAppSecret());
// 设置微信公众号的token
config.setToken(this.wxConfig.getToken());
// 设置消息加解密密钥
config.setAesKey(this.wxConfig.getAesKey());
super.setWxMpConfigStorage(config);
this.refreshRouter();
}
private void refreshRouter() {
final WxMpMessageRouter newRouter = new WxMpMessageRouter(this);
// 记录所有事件的日志
newRouter.rule().handler(this.logHandler).next();
// 接收客服会话管理事件
newRouter.rule().async(false).msgType(EVENT).event(KF_CREATE_SESSION)
.handler(this.kfSessionHandler).end();
newRouter.rule().async(false).msgType(EVENT).event(KF_CLOSE_SESSION)
.handler(this.kfSessionHandler).end();
newRouter.rule().async(false).msgType(EVENT).event(KF_SWITCH_SESSION)
.handler(this.kfSessionHandler).end();
// 门店审核事件
newRouter.rule().async(false).msgType(EVENT).event(POI_CHECK_NOTIFY)
.handler(this.storeCheckNotifyHandler).end();
// 自定义菜单事件
newRouter.rule().async(false).msgType(EVENT).event(CLICK).handler(this.menuHandler).end();
// 点击菜单连接事件
newRouter.rule().async(false).msgType(EVENT).event(VIEW).handler(this.nullHandler).end();
// 关注事件
newRouter.rule().async(false).msgType(EVENT).event(SUBSCRIBE).handler(this.subscribeHandler).end();
// 取消关注事件
newRouter.rule().async(false).msgType(EVENT).event(UNSUBSCRIBE).handler(this.unsubscribeHandler).end();
// 上报地理位置事件
newRouter.rule().async(false).msgType(EVENT).event(LOCATION).handler(this.locationHandler).end();
// 接收地理位置消息
newRouter.rule().async(false).msgType(XmlMsgType.LOCATION).handler(this.locationHandler).end();
// 扫码事件
newRouter.rule().async(false).msgType(EVENT).event(SCAN).handler(this.nullHandler).end();
// 默认
newRouter.rule().async(false).handler(this.msgHandler).end();
this.router = newRouter;
}
public WxMpXmlOutMessage route(WxMpXmlMessage message) {
try {
return this.router.route(message);
} catch (Exception e) {
this.logger.error(e.getMessage(), e);
}
return null;
}
public boolean hasKefuOnline() {
try {
WxMpKfOnlineList kfOnlineList = this.getKefuService().kfOnlineList();
return kfOnlineList != null && kfOnlineList.getKfOnlineList().size() > 0;
} catch (Exception e) {
this.logger.error("获取客服在线状态异常: " + e.getMessage(), e);
}
return false;
}
}
配置文件 wx.properties
wx_appid=wx3cd70cbxxxxxxx
wx_appsecret=8e939b9e582f4fdfxxxxxxx
wx_token=123487xxx
wx_aeskey=2Ud4dSEEM6ykj0Cgs5Q5xxxx
wx_url=http://top.xxxxxx.cc
wx_key=cafdae5e6xxxxxxxxa8c6cd143e
file_Path=E\:\\apache-tomcat-7.0.77\\apiclient_cert.p12
[参考链接]:[https://github.com/binarywang/weixin-java-mp-demo-springboot]