首先,本地开发调试 微信接口
1: 服务器配置
2:代码里必须有一个 checkSign 的get请求。(这个方法是微信自动调用的)
/**
* 响应get请求,微信默认token校验时使用get请求
*/
@GetMapping(value = "checkSign")
protected void checkSign(HttpServletRequest req, HttpServletResponse resp)
{
//接收微信用来校验信息的内置规定参数
String signature = req.getParameter("signature");
String timestamp = req.getParameter("timestamp");
String nonce = req.getParameter("nonce");
String echostr = req.getParameter("echostr");
PrintWriter out = null;
try {
out = resp.getWriter();
//按微信指定的规则进行校验并做出响应
if (CheckSignatureUtil.checkSignature(signature, timestamp, nonce)) {
out.print(echostr);
out.flush();
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if(null != out){
out.close();
}
}
}
3:业务相关 同样的方法名 checkSign,但是为post 请求
/**
* 响应post请求,微信中消息和菜单交互都是采用post请求
*/
@RequestMapping(value = "checkSign", method = RequestMethod.POST)
protected String doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
// PrintWriter out = resp.getWriter();
String message = null;
try {
//把微信返回的xml信息转义成map
Map<String, String> map = XmlUtil.xmlToMap(req);
log.info("微信事件触发==============" + JSON.toJSONString(map));
//消息来源用户标识
String fromUserName = map.get("FromUserName");
//消息目的用户标识
String toUserName = map.get("ToUserName");
//消息类型
String msgType = map.get("MsgType");
//消息内容 用户输入内容
String content = map.get("Content");
String eventType = map.get("Event");
//如果为事件类型
if (MessageUtil.MSGTYPE_EVENT.equals(msgType)) {
// userId-类型-公司名-国家 eg:
String sceneStr = map.get("EventKey");
if (MessageUtil.MESSAGE_SUBSCIBE.equals(eventType)){
if(StringUtils.isNotBlank(sceneStr) && sceneStr.contains("-")){
// 添加扫码记录到datathink 下表中
String[] split = sceneStr.split("-");
String userID = split[0].substring(8);
// 业务逻辑
}
//处理订阅事件 判断普通关注还是解锁关注
message = MessageUtil.subscribeForText(toUserName, fromUserName, sceneStr);
} else if(MessageUtil.MESSAGE_SCAN.equals(eventType)){
// 添加扫码记录到datathink 下表中
if(sceneStr.contains("-")){
String[] split = sceneStr.split("-");
// 业务逻辑
}
//处理扫码事件
message = MessageUtil.scanForText(toUserName, fromUserName, sceneStr);
} else if (MessageUtil.MESSAGE_UNSUBSCIBE.equals(eventType)) {
//处理取消订阅事件
message = MessageUtil.unsubscribe(toUserName, fromUserName);
}
}
log.info("微信事件入参:" + JSON.toJSONString(map) + ", 微信事件返回信息:" + message);
return message;
} catch (DocumentException e) {
log.error("checkSign===============" + e.getMessage());
} finally {
// out.println(message);
/*if (out != null) {
out.close();
}*/
}
return null;
}
工具类:
@Component
public class MessageUtil {
/**
* 消息类型--事件
*/
public static final String MSGTYPE_EVENT = "event";
/**
* 消息事件类型--订阅事件
*/
public static final String MESSAGE_SUBSCIBE = "subscribe";
/**
* 消息事件类型--扫描事件
*/
public static final String MESSAGE_SCAN = "SCAN";
/**
* 消息事件类型--取消订阅事件
*/
public static final String MESSAGE_UNSUBSCIBE = "unsubscribe";
/**
* 消息类型--文本消息
*/
public static final String MESSAGE_TEXT = "text";
@Autowired
public ICompanyCdpClient cdpClient;
public static ICompanyCdpClient companyCdpClient;
@PostConstruct
public void init() {
companyCdpClient = cdpClient;
}
/**
* 组装文本消息
*/
public static String textMsg(String toUserName,String fromUserName,String content){
TextMessage text = new TextMessage();
text.setFromUserName(toUserName);
text.setToUserName(fromUserName);
text.setMsgType(MESSAGE_TEXT);
text.setCreateTime(System.currentTimeMillis());
text.setContent(content);
return XmlUtil.textMsgToxml(text);
}
/**
* 响应订阅事件--回复文本消息
* @param toUserName
* @param fromUserName
* @param sceneStr userId-类型-公司名-国家
* @return
*/
public static String subscribeForText(String toUserName,String fromUserName, String sceneStr){
if (StringUtils.isNotBlank(sceneStr) && sceneStr.contains("#")) {
return textMsg(toUserName, fromUserName, "您已成功关注并绑定XXX账号,后续我们将不定期提醒买家更新及福利活动,有空记得多看看哦!");
} else if (StringUtils.isNotBlank(sceneStr) && sceneStr.contains("-")) {
// 解锁扫码关注
return textMsg(toUserName, fromUserName, "/:rose感谢关注!\n" +
"\n" +
"企业信息挖掘成功后,我们将第一时间通知您。您也可以在关注该企业后,在个人中心-我的关注里查看相关进展");
}
return textMsg(toUserName, fromUserName, "感谢关注!\n" +
"在公众号回复“热门买家”\n" +
"/:rose将为您开通7天的免费试用!");
}
/**
* 响应取消订阅事件
*/
public static String unsubscribe(String toUserName,String fromUserName){
//TODO 可以进行取关后的其他后续业务处理
System.out.println("用户:"+ fromUserName +"取消关注~");
return "";
}
}
public class XmlUtil {
/**
* xml转map
*/
public static Map<String, String> xmlToMap(HttpServletRequest request) throws IOException, DocumentException{
HashMap<String, String> map = new HashMap<String,String>();
SAXReader reader = new SAXReader();
InputStream ins = request.getInputStream();
Document doc = reader.read(ins);
Element root = doc.getRootElement();
@SuppressWarnings("unchecked")
List<Element> list = (List<Element>)root.elements();
for(Element e:list){
map.put(e.getName(), e.getText());
}
ins.close();
return map;
}
/**
* 文本消息对象转xml
*/
public static String textMsgToxml(TextMessage textMessage){
XStream xstream = new XStream();
xstream.alias("xml", textMessage.getClass());
return xstream.toXML(textMessage);
}
}
/**
获取微信二维码: 该方法返回ticket 前端 可拿ticket请求获取二维码
**/
@Override
@PostMapping(value = "/getQrCode")
public BaseResponse getQrCode(@RequestBody UserScanReq userScanReq){
BaseResponse baseResponse = new BaseResponse();
org.springblade.core.tool.utils.ThreadLocalUtil.put("token", userScanReq.getToken());
JResDTO dto = sysUserCenterInfoClient.getUserInfo();
if (dto.getCode() != null && dto.getCode() == 0) {
String accessToken = weChatService.getAccessToken(false);
SysUserCenterInfoVO vo = (SysUserCenterInfoVO) dto.getData();
ThreadLocalUtil.set(newUserKey, vo);
Map<String, Object> map = new HashMap<>();
map.put("expire_seconds", 86400);
map.put("action_name", "QR_STR_SCENE");
Map<String, Object> actionInfo = new HashMap<>();
Map<String, String> sean = new HashMap<>();
String sceneStr;
if (userScanReq.getType() == 0) {
// 个人中心二维码
sceneStr = vo.getUserId();
} else if(userScanReq.getType() == 1){
sceneStr = vo.getUserId() + "#";
}else{
sceneStr = vo.getUserId() + "-" + userScanReq.getType() + "-" + userScanReq.getCompanyName() + "-" + userScanReq.getCountry();
}
sean.put("scene_str", sceneStr);
actionInfo.put("scene", sean);
map.put("action_info", actionInfo);
// 1 获取ticket
String result = HttpUtil.postJson(WxConstants.getQrcodeTicket + accessToken
, JSON.toJSONString(map));
JSONObject jsonObject = JSON.parseObject(result);
log.info("wechat accessToken result : {}", result);
if (jsonObject.containsKey("errcode")) {
//重试 一次
accessToken = weChatService.getAccessToken(true);
// 1 获取ticket
result = HttpUtil.postJson(WxConstants.getQrcodeTicket + accessToken
, JSON.toJSONString(map));
jsonObject = JSON.parseObject(result);
}
String ticket = jsonObject.getString("ticket");
baseResponse.setData(ticket);
success(baseResponse);
return baseResponse;
}
baseResponse.setData("获取用户信息失败");
error("获取用户信息失败", baseResponse);
return baseResponse;
}
获取微信token:
public String getAccessToken(boolean refresh) {
if (refresh || accessToken.isExpire()) {
int count = 0;
while (count < 5) {
String result = HttpUtil.get(String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",
weChatAppId, weChatSecret));
JSONObject resultJson = JSON.parseObject(result);
logger.info("wechat accessToken result : {}", result);
if (resultJson.containsKey("access_token")) {
accessToken.token = resultJson.getString("access_token");
accessToken.expiresIn = resultJson.getLong("expires_in");
accessToken.refreshTime = System.currentTimeMillis();
} else if (resultJson.containsKey("errcode")) {
if (resultJson.getInteger("errcode") == -1) {
//重试
try {
Thread.sleep(count * 100L);
} catch (InterruptedException ignored) {
}
count++;
continue;
}
}
break;
}
}
return accessToken.isExpire() ? null : accessToken.token;
}
@Override
@ApiOperation(value = "获取用户是否关注公众号")
@PostMapping(value = "/getUserIsCollectedWX")
public BaseResponse<Boolean> getUserIsCollectedWX(@RequestBody TokenReq req){
BaseResponse baseResponse = new BaseResponse();
boolean flag = false;
if (StringUtils.isBlank(req.getToken())) {
baseResponse.setData(flag);
success(baseResponse);
return baseResponse;
}
org.springblade.core.tool.utils.ThreadLocalUtil.put("token", req.getToken());
JResDTO dto = sysUserCenterInfoClient.getUserInfo();
if (dto.getCode() != null && dto.getCode() == 0) {
SysUserCenterInfoVO vo = (SysUserCenterInfoVO) dto.getData();
if (StringUtils.isNotBlank(vo.getWxOpenId())) {
try {
WxUserInfoDto wxUserInfo = getWxUserInfoByOpenId(vo.getWxOpenId());
if (StringUtils.isNotBlank(wxUserInfo.getSubscribe()) && StringUtils.equals(wxUserInfo.getSubscribe(), "1")) {
flag = true;
}
log.info("微信获取用户基本信息返回参数:", wxUserInfo.toString());
} catch (Exception e) {
throw CommonException.createException("调用微信获取用户基本信息(UnionID机制)接口异常", e);
}
}
}
baseResponse.setData(flag);
success(baseResponse);
return baseResponse;
}
/**
* 根据用户微信openId获取微信信息
* @param openId
* @return
*/
private WxUserInfoDto getWxUserInfoByOpenId(String openId){
String accessToken = weChatService.getAccessToken(false);
String result = HttpUtil.get(String.format("https://api.weixin.qq.com/cgi-bin/user/info?access_token=%s&openid=%s&lang=zh_CN",
accessToken, openId));
WxUserInfoDto wxUserInfo = JSON.parseObject(result, WxUserInfoDto.class);
return wxUserInfo;
}