package com.iformall.controller; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.iformall.common.Result; import com.iformall.common.ResultData; import com.iformall.domain.po.*; import com.iformall.enums.*; import com.iformall.mp.manager.WxMpManager; import com.iformall.mp.utils.MpUtil; import com.iformall.service.*; import com.iformall.service.wechat.WxOpenService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; import me.chanjar.weixin.open.bean.message.WxOpenXmlMessage; import me.chanjar.weixin.open.bean.result.WxOpenAuthorizerInfoResult; import me.chanjar.weixin.open.bean.result.WxOpenPlatformResult; import me.chanjar.weixin.open.bean.result.WxOpenQueryAuthResult; import me.chanjar.weixin.open.bean.result.WxOpenResult; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; import java.text.SimpleDateFormat; import java.util.Date; @Controller @RequestMapping("/wxOpen") @Api(description = "微信第三方开放平台回调相关接口") public class WechatCalllbackController extends BaseController { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired protected WxOpenService openService; @Autowired private WxComponentVerifyTicketService componentVerifyTicketService; @Autowired private WxAuthorizerInfoService authorizerInfoService; @Autowired private WxWeappAuditStatusService weappAuditStatusService; @Autowired private WxAppinfoService appinfoService; @Autowired private MailService mailService; @Autowired private WxMpManager mpManager; @RequestMapping(value = "/notify", method = RequestMethod.POST) @ApiOperation("接收ticket回调") public Object receiveTicket(HttpServletRequest request) throws IOException { logger.info("[" + getIpAddr() + "]接收微信回调 /wxOpen/notify"); InputStream inStream = request.getInputStream(); ByteArrayOutputStream outSteam = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = 0; while ((len = inStream.read(buffer)) != -1) { outSteam.write(buffer, 0, len); } String resultxml = new String(outSteam.toByteArray(), Charset.forName("UTF-8")); logger.info(resultxml); outSteam.close(); inStream.close(); String timestamp = request.getParameter("timestamp"); String nonce = request.getParameter("nonce"); String signature = request.getParameter("signature"); String encType = request.getParameter("encrypt_type"); String msgSignature = request.getParameter("msg_signature"); /* // 测试数据 String timestamp = "1545708083"; String nonce = "1052028699"; String signature = "b5fa8296b46c726cbed35f744944f20f682776a6"; String encType = "aes"; String msgSignature= "54bec4c513f447cb312fd091bea48326f87aedde"; String resultxml = "\n" + " \n" + " \n" + ""; */ logger.info("\n接收微信回调:[signature=[{}], encType=[{}], msgSignature=[{}]," + " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ", signature, encType, msgSignature, timestamp, nonce, resultxml); if (!StringUtils.equalsIgnoreCase("aes", encType) || !openService.getWxOpenComponentService().checkSignature(timestamp, nonce, signature)) { throw new IllegalArgumentException("非法请求,可能属于伪造的请求!"); } // aes加密的消息 WxOpenXmlMessage inMessage = WxOpenXmlMessage.fromEncryptedXml(resultxml, openService.getWxOpenConfigStorage(), timestamp, nonce, msgSignature); this.logger.info("接收微信回调,消息解密后内容为:{} ", inMessage.toString()); if (inMessage.getInfoType().equals(EnumWxAuthorizationInfoType.COMPONENT_VERIFY_TICKET.getMessage())) { // 保存component_verify_ticket componentVerifyTicketService.saveOrUpdate(new WxComponentVerifyTicket() { { setComponentVerifyTicket(inMessage.getComponentVerifyTicket()); setCreateTime(new Date(Long.valueOf(inMessage.getCreateTime() * 1000))); setComponentAppid(inMessage.getAppId()); setDeadline(new Date(Long.valueOf(System.currentTimeMillis() + (60 * 60 * 1000)))); } }); } else if (inMessage.getInfoType().equals(EnumWxAuthorizationInfoType.AUTHORIZED.getMessage()) || inMessage.getInfoType().equals(EnumWxAuthorizationInfoType.UPDATEAUTHORIZED.getMessage()) ) { try { WxOpenQueryAuthResult queryAuthResult = openService.getWxOpenComponentService().getQueryAuth(inMessage.getAuthorizationCode()); logger.info("getQueryAuth", queryAuthResult); WxOpenAuthorizerInfoResult openAuthorizerInfoResult = openService.getWxOpenComponentService().getAuthorizerInfo( queryAuthResult.getAuthorizationInfo().getAuthorizerAppid()); logger.info(openAuthorizerInfoResult.toString()); // save auth info authorizerInfoService.saveOrUpdate(new WxAuthorizerInfo() { { setAuthorizerAppid(openAuthorizerInfoResult.getAuthorizationInfo().getAuthorizerAppid()); setAlias(openAuthorizerInfoResult.getAuthorizerInfo().getAlias()); setHeadImg(openAuthorizerInfoResult.getAuthorizerInfo().getHeadImg()); setQrcodeUrl(openAuthorizerInfoResult.getAuthorizerInfo().getQrcodeUrl()); setAuthorizationStatus(EnumWxAuthorizationStatus.AUTHORIZED.getCode()); setAuthTime(new Date()); } }); } catch (WxErrorException e) { logger.error(e.getMessage()); } } else if (inMessage.getInfoType().equals(EnumWxAuthorizationInfoType.UNAUTHORIZED.getMessage())) { authorizerInfoService.saveOrUpdate(new WxAuthorizerInfo() { { setAuthorizerAppid(inMessage.getAuthorizerAppid()); setAuthorizationStatus(EnumWxAuthorizationStatus.UNAUTHORIZED.getCode()); setAuthTime(new Date()); } }); } try { String out = openService.getWxOpenComponentService().route(inMessage); this.logger.info("组装回复信息:{}", out); } catch (WxErrorException e) { this.logger.error("notify", e); } return "success"; } @RequestMapping(value = "/{appId}/callback") @ApiOperation("消息回调") @ResponseBody public String callback(@PathVariable("appId") String appId, HttpServletRequest request) throws IOException { logger.info("[" + getIpAddr() + "]接收微信APP回调 /{appId}/callback"); String timestamp = request.getParameter("timestamp"); String nonce = request.getParameter("nonce"); String signature = request.getParameter("signature"); String encType = request.getParameter("encrypt_type"); String openid = request.getParameter("openid"); String msgSignature = request.getParameter("msg_signature"); InputStream inStream = request.getInputStream(); ByteArrayOutputStream outSteam = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = 0; while ((len = inStream.read(buffer)) != -1) { outSteam.write(buffer, 0, len); } String resultxml = new String(outSteam.toByteArray(), Charset.forName("UTF-8")); logger.info(resultxml); outSteam.close(); inStream.close(); logger.info("接收微信APP回调:[appId=[{}], openid=[{}], signature=[{}], encType=[{}], msgSignature=[{}]," + " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ", appId, openid, signature, encType, msgSignature, timestamp, nonce, resultxml); // 第三方平台一定接收的是加密的消息 if (!StringUtils.equalsIgnoreCase("aes", encType) || !openService.getWxOpenComponentService().checkSignature(timestamp, nonce, signature)) { throw new IllegalArgumentException("非法请求,可能属于伪造的请求!"); } WxAppinfo appinfo = appinfoService.getByAppId(appId); String out = ""; // aes加密的消息 WxMpXmlMessage inMessage = WxOpenXmlMessage.fromEncryptedMpXml(resultxml, openService.getWxOpenConfigStorage(), timestamp, nonce, msgSignature); logger.info("接收微信APP回调,消息解密后内容为:\n{}", inMessage.toString()); // 全网发布测试用例 /* if (StringUtils.equalsAnyIgnoreCase(appId, "wx570bc396a51b8ff8", "wxd101a85aa106f53e")) { try { if (StringUtils.equals(inMessage.getMsgType(), "text")) { if (StringUtils.equals(inMessage.getContent(), "TESTCOMPONENT_MSG_TYPE_TEXT")) { out = WxOpenXmlMessage.wxMpOutXmlMessageToEncryptedXml( WxMpXmlOutMessage.TEXT().content("TESTCOMPONENT_MSG_TYPE_TEXT_callback") .fromUser(inMessage.getToUser()) .toUser(inMessage.getFromUser()) .build(), openService.getWxOpenConfigStorage() ); } else if (StringUtils.startsWith(inMessage.getContent(), "QUERY_AUTH_CODE:")) { String msg = inMessage.getContent().replace("QUERY_AUTH_CODE:", "") + "_from_api"; WxMpKefuMessage kefuMessage = WxMpKefuMessage.TEXT().content(msg).toUser(inMessage.getFromUser()).build(); openService.getWxOpenComponentService().getWxMpServiceByAppid(appId).getKefuService().sendKefuMessage(kefuMessage); } } else if (StringUtils.equals(inMessage.getMsgType(), "event")) { WxMpKefuMessage kefuMessage = WxMpKefuMessage.TEXT().content(inMessage.getEvent() + "from_callback").toUser(inMessage.getFromUser()).build(); openService.getWxOpenComponentService().getWxMpServiceByAppid(appId).getKefuService().sendKefuMessage(kefuMessage); } } catch (WxErrorException e) { logger.error("callback", e); } } */ if(appinfo.getType().equals(EnumAppType.B.getCode()) || appinfo.getType().equals(EnumAppType.C.getCode())) { // 小程序 /**判断消息类型,调用对应的方法*/ switch (inMessage.getMsgType()) { case "event": { switch (inMessage.getEvent()) { case "weapp_audit_success": { // 审核成功 updateAuditStatus(appId, true, ""); break; } case "weapp_audit_fail": { // 审核失败 updateAuditStatus(appId, false, inMessage.getReason()); break; } default: break; } return "success"; } case "text": WxMpXmlOutMessage outMessage = openService.getWxOpenMessageRouter().route(inMessage, appId); if (outMessage != null) { out = WxOpenXmlMessage.wxMpOutXmlMessageToEncryptedXml(outMessage, openService.getWxOpenConfigStorage()); logger.info(out); } else { out = "success"; } break; default: return "success"; } } else { // 公众号 WxMpService mpService = MpUtil.getMpService(appinfo); try { WxMpXmlOutMessage outMessage = mpManager.getRouter(mpService).route(inMessage); if (outMessage == null) { this.logger.info("2 return: success"); return "success"; } out = outMessage.toEncryptedXml(mpService.getWxMpConfigStorage()); } catch (Exception e) { logger.error("路由消息时出现异常!", e); } } return out; } private void updateAuditStatus(String appId, boolean success, String reason) { WxWeappAuditStatus auditStatus = weappAuditStatusService.getByAppId(appId); if (auditStatus != null) { if (success) { auditStatus.setAuditStatus(EnumWeappAuditStatus.SUCCESS.getCode()); auditStatus.setAuditErrCode(""); } else { auditStatus.setAuditStatus(EnumWeappAuditStatus.FAIL.getCode()); auditStatus.setAuditErrCode(reason); } auditStatus.setAuditTime(new Date()); weappAuditStatusService.updateStatus(auditStatus); } // 发邮件 WxAppinfo appinfo = appinfoService.getByAppId(appId); if (appinfo != null) { SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式 StringBuilder titleSB = new StringBuilder(); if (appinfo.getType().equals(EnumAppType.C.getCode())) { titleSB.append("C端小程序"); } else if (appinfo.getType().equals(EnumAppType.B.getCode())) { titleSB.append("B端小程序"); } else if (appinfo.getType().equals(EnumAppType.MP_S.getCode())) { titleSB.append("公众号-服务号"); } else if (appinfo.getType().equals(EnumAppType.MP_P.getCode())) { titleSB.append("公众号-订阅号"); } titleSB.append(appinfo.getName()); if (success) { titleSB.append("审核通过"); } else { titleSB.append("审核未通过"); } StringBuilder sb = new StringBuilder(); sb.append(df.format(new Date())).append("\n"); if (success) { sb.append("审核通过\n"); } else { sb.append("审核未通过\n").append("原因").append(reason); } String[] receivers = new String[]{"wangmei@iformall.com", "wuguoqiang@iformall.com", "huanghui@iformall.com", "sunmingming@iformall.com"}; //发送邮件 mailService.sendSimpleMail(receivers, titleSB.toString(), sb.toString()); } } @GetMapping(value = "/createOpenPlatform") @ApiOperation("创建微信开放平台") public ResultData createOpenPlatform(@RequestParam(value = "appId") String appId) { Gson gson = new GsonBuilder().create(); try { String responseStr = openService.getWxOpenComponentService().getWxMpServiceByAppid(appId).createOpenPlatform(appId); logger.info(responseStr); WxOpenPlatformResult openPlatformResult = gson.fromJson(responseStr, WxOpenPlatformResult.class); if (openPlatformResult.isSuccess()) { WxAuthorizerInfo authorizerInfo = authorizerInfoService.getByAppId(appId); if (authorizerInfo != null) { authorizerInfo.setId(authorizerInfo.getId()); authorizerInfo.setOpenAppid(openPlatformResult.getOpenAppid()); authorizerInfoService.updateOpenAppid(authorizerInfo); } } return new ResultData(responseStr); } catch (WxErrorException e) { logger.error(e.getMessage()); return new ResultData(Result.ERROR, e.getMessage()); } } @GetMapping(value = "/bindOpenPlatform") @ApiOperation("绑定微信开放平台") public ResultData bindOpenPlatform(@RequestParam(value = "appId") String appId, @RequestParam(value = "openAppId") String openAppId) { Gson gson = new GsonBuilder().create(); try { String responseStr = openService.getWxOpenComponentService().getWxMpServiceByAppid(appId).bindOpenPlatform(appId, openAppId); logger.info(responseStr); WxOpenResult openResult = gson.fromJson(responseStr, WxOpenResult.class); if (openResult.isSuccess()) { return new ResultData(); } return new ResultData(Result.ERROR, responseStr); } catch (WxErrorException e) { logger.error(e.getMessage()); return new ResultData(Result.ERROR, e.getMessage()); } } @GetMapping(value = "/unbindOpenPlatform") @ApiOperation("解绑微信开放平台") public ResultData unbindOpenPlatform(@RequestParam(value = "appId") String appId, @RequestParam(value = "openAppId") String openAppId) { Gson gson = new GsonBuilder().create(); try { String responseStr = openService.getWxOpenComponentService().getWxMpServiceByAppid(appId).unbindOpenPlatform(appId, openAppId); logger.info(responseStr); WxOpenResult openResult = gson.fromJson(responseStr, WxOpenResult.class); if (openResult.isSuccess()) { return new ResultData(); } return new ResultData(Result.ERROR, responseStr); } catch (WxErrorException e) { logger.error(e.getMessage()); return new ResultData(Result.ERROR, e.getMessage()); } } @GetMapping(value = "/getOpenPlatform") @ApiOperation("获取微信开放平台appId") public ResultData getOpenPlatform(@RequestParam(value = "appId") String appId) { Gson gson = new GsonBuilder().create(); try { String responseStr = openService.getWxOpenComponentService().getWxMpServiceByAppid(appId).getBindOpenPlatform(appId); logger.info(responseStr); WxOpenPlatformResult openPlatformResult = gson.fromJson(responseStr, WxOpenPlatformResult.class); if (openPlatformResult.isSuccess()) { return new ResultData(openPlatformResult.getOpenAppid()); } return new ResultData(Result.ERROR, responseStr); } catch (WxErrorException e) { logger.error(e.getMessage()); return new ResultData(Result.ERROR, e.getMessage()); } } @GetMapping(value = "/clearQuota") @ApiOperation("代公众号清零quota,每个公众号每个月有10次清零机会,包括在微信公众平台上的清零以及调用API进行清零") public ResultData clearQuota(@RequestParam(value = "appId") String appId) { try { openService.getWxOpenComponentService().getWxMpServiceByAppid(appId).clearQuota(appId); return new ResultData(); } catch (WxErrorException e) { logger.error(e.getMessage()); return new ResultData(Result.ERROR, e.getMessage()); } } }