diff --git a/austin-common/src/main/java/com/java3y/austin/common/constant/CommonConstant.java b/austin-common/src/main/java/com/java3y/austin/common/constant/CommonConstant.java index cd142df..1502b41 100644 --- a/austin-common/src/main/java/com/java3y/austin/common/constant/CommonConstant.java +++ b/austin-common/src/main/java/com/java3y/austin/common/constant/CommonConstant.java @@ -47,6 +47,14 @@ public class CommonConstant { */ public static final String CHARSET_NAME = "UTF-8"; + /** + * HTTP请求内容格式 + */ + public static final String CONTENT_TYPE_JSON = "application/json; charset=utf-8"; + public static final String CONTENT_TYPE_TEXT = "text/html;charset=utf-8"; + public static final String CONTENT_TYPE_XML = "application/xml; charset=UTF-8"; + public static final String CONTENT_TYPE_FORM_URL_ENCODE = "application/x-www-form-urlencoded;charset=utf-8;"; + /** * HTTP 请求方法 */ diff --git a/austin-common/src/main/java/com/java3y/austin/common/constant/OfficialAccountParamConstant.java b/austin-common/src/main/java/com/java3y/austin/common/constant/OfficialAccountParamConstant.java new file mode 100644 index 0000000..cd646bb --- /dev/null +++ b/austin-common/src/main/java/com/java3y/austin/common/constant/OfficialAccountParamConstant.java @@ -0,0 +1,17 @@ +package com.java3y.austin.common.constant; + + +/** + * @author 3y + * 微信服务号的参数常量 + */ +public class OfficialAccountParamConstant { + public static final String SIGNATURE = "signature"; + public static final String ECHO_STR = "echostr"; + public static final String NONCE = "nonce"; + public static final String TIMESTAMP = "timestamp"; + public static final String ENCRYPT_TYPE = "encrypt_type"; + public static final String RAW = "raw"; + public static final String AES = "aes"; + public static final String MSG_SIGNATURE = "msg_signature"; +} diff --git a/austin-common/src/main/java/com/java3y/austin/common/dto/account/WeChatOfficialAccount.java b/austin-common/src/main/java/com/java3y/austin/common/dto/account/WeChatOfficialAccount.java index 59ab5a6..91c1b22 100644 --- a/austin-common/src/main/java/com/java3y/austin/common/dto/account/WeChatOfficialAccount.java +++ b/austin-common/src/main/java/com/java3y/austin/common/dto/account/WeChatOfficialAccount.java @@ -24,5 +24,6 @@ public class WeChatOfficialAccount { */ private String appId; private String secret; + private String token; } diff --git a/austin-handler/src/main/java/com/java3y/austin/handler/script/impl/YunPianSmsScript.java b/austin-handler/src/main/java/com/java3y/austin/handler/script/impl/YunPianSmsScript.java index 991096f..e19a4ed 100644 --- a/austin-handler/src/main/java/com/java3y/austin/handler/script/impl/YunPianSmsScript.java +++ b/austin-handler/src/main/java/com/java3y/austin/handler/script/impl/YunPianSmsScript.java @@ -42,8 +42,8 @@ public class YunPianSmsScript implements SmsScript { Map params = assembleParam(smsParam, account); String result = HttpRequest.post(account.getUrl()) - .header(Header.CONTENT_TYPE.getValue(), "application/x-www-form-urlencoded;charset=utf-8;") - .header(Header.ACCEPT.getValue(), "application/json;charset=utf-8;") + .header(Header.CONTENT_TYPE.getValue(), CommonConstant.CONTENT_TYPE_FORM_URL_ENCODE) + .header(Header.ACCEPT.getValue(), CommonConstant.CONTENT_TYPE_JSON) .form(params) .timeout(2000) .execute().body(); diff --git a/austin-support/src/main/java/com/java3y/austin/support/utils/WxServiceUtils.java b/austin-support/src/main/java/com/java3y/austin/support/utils/WxServiceUtils.java index 6a653b9..609625b 100644 --- a/austin-support/src/main/java/com/java3y/austin/support/utils/WxServiceUtils.java +++ b/austin-support/src/main/java/com/java3y/austin/support/utils/WxServiceUtils.java @@ -22,9 +22,9 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; -import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; /** * 微信服务号/微信小程序 工具类 @@ -36,11 +36,11 @@ import java.util.Map; @Data public class WxServiceUtils { - private Map officialAccountServiceMap = new HashMap<>(); - private Map miniProgramServiceMap = new HashMap<>(); + private Map officialAccountServiceMap = new ConcurrentHashMap<>(); + private Map miniProgramServiceMap = new ConcurrentHashMap<>(); - private Map officialAccountHashMap = new HashMap<>(); - private Map miniProgramHashMap = new HashMap<>(); + private Map officialAccountHashMap = new ConcurrentHashMap<>(); + private Map miniProgramHashMap = new ConcurrentHashMap<>(); @Autowired private ChannelAccountDao channelAccountDao; @@ -50,6 +50,9 @@ public class WxServiceUtils { initOfficialAccount(); initMiniProgram(); } + public void fresh() { + init(); + } private void initMiniProgram() { @@ -80,6 +83,7 @@ public class WxServiceUtils { WxMpDefaultConfigImpl config = new WxMpDefaultConfigImpl(); config.setAppId(officialAccount.getAppId()); config.setSecret(officialAccount.getSecret()); + config.setToken(officialAccount.getToken()); wxMpService.setWxMpConfigStorage(config); return wxMpService; } diff --git a/austin-web/src/main/java/com/java3y/austin/web/controller/OfficialAccountController.java b/austin-web/src/main/java/com/java3y/austin/web/controller/OfficialAccountController.java index 9d68b55..0bc09a7 100644 --- a/austin-web/src/main/java/com/java3y/austin/web/controller/OfficialAccountController.java +++ b/austin-web/src/main/java/com/java3y/austin/web/controller/OfficialAccountController.java @@ -1,10 +1,13 @@ package com.java3y.austin.web.controller; -import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; import com.google.common.base.Throwables; +import com.java3y.austin.common.constant.CommonConstant; +import com.java3y.austin.common.constant.OfficialAccountParamConstant; +import com.java3y.austin.common.dto.account.WeChatOfficialAccount; import com.java3y.austin.common.enums.RespStatusEnum; import com.java3y.austin.common.vo.BasicResultVO; import com.java3y.austin.support.utils.WxServiceUtils; @@ -13,18 +16,23 @@ import com.java3y.austin.web.vo.amis.CommonAmisVo; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.mp.api.WxMpMessageRouter; 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.mp.bean.result.WxMpQrCodeTicket; import me.chanjar.weixin.mp.bean.template.WxMpTemplate; +import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl; 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.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import java.util.ArrayList; import java.util.List; -import java.util.Map; /** * 微信服务号 @@ -32,14 +40,18 @@ import java.util.Map; * @author 3y */ @Slf4j -@RestController @RequestMapping("/officialAccount") +@RestController @Api("微信服务号") public class OfficialAccountController { @Autowired private WxServiceUtils wxServiceUtils; + String appId = "wx2xxxxxb325"; + String secret = "203xxx6db46fa99"; + String token = "austin123"; + /** * @param id 账号Id * @return @@ -94,43 +106,77 @@ public class OfficialAccountController { * * @return */ - @GetMapping("/receipt") + @RequestMapping(value = "/receipt", produces = {CommonConstant.CONTENT_TYPE_XML}) @ApiOperation("/接收微信的事件消息") - public String receiptMessage(String signature, String timestamp, String nonce, String echostr) { - log.info("get weixin signature:{},:{},nonce:{},echostr:{}", signature, timestamp, nonce, echostr); - if (StrUtil.isNotBlank(echostr)) { - return echostr; + public String receiptMessage(HttpServletRequest request, HttpServletResponse response) { + try { + WxMpService wxMpService = wxServiceUtils.initOfficialAccountService(WeChatOfficialAccount.builder().appId(appId).secret(secret).token(token).build()); + WxMpMessageRouter wxMpMessageRouter = new WxMpMessageRouter(wxMpService); + + WxMpDefaultConfigImpl config = new WxMpDefaultConfigImpl(); + config.setAppId(appId); + config.setSecret(secret); + config.setToken(token); + + String echoStr = request.getParameter(OfficialAccountParamConstant.ECHO_STR); + String signature = request.getParameter(OfficialAccountParamConstant.SIGNATURE); + String nonce = request.getParameter(OfficialAccountParamConstant.NONCE); + String timestamp = request.getParameter(OfficialAccountParamConstant.TIMESTAMP); + + // echoStr!=null,说明只是微信调试的请求 + if (StrUtil.isNotBlank(echoStr)) { + return echoStr; + } + + if (!wxMpService.checkSignature(timestamp, nonce, signature)) { + return RespStatusEnum.CLIENT_BAD_PARAMETERS.getMsg(); + } + + String encryptType = StrUtil.isBlank(request.getParameter(OfficialAccountParamConstant.ENCRYPT_TYPE)) ? OfficialAccountParamConstant.RAW : request.getParameter(OfficialAccountParamConstant.ENCRYPT_TYPE); + + if (OfficialAccountParamConstant.RAW.equals(encryptType)) { + WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(request.getInputStream()); + log.info("raw inMessage:{}", JSON.toJSONString(inMessage)); + WxMpXmlOutMessage outMessage = wxMpMessageRouter.route(inMessage); + response.getWriter().write(outMessage.toXml()); + } else if (OfficialAccountParamConstant.AES.equals(encryptType)) { + String msgSignature = request.getParameter(OfficialAccountParamConstant.MSG_SIGNATURE); + WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(request.getInputStream(), config, timestamp, nonce, msgSignature); + log.info("aes inMessage:{}", JSON.toJSONString(inMessage)); + WxMpXmlOutMessage outMessage = wxMpMessageRouter.route(inMessage); + response.getWriter().write(outMessage.toEncryptedXml(config)); + } + return RespStatusEnum.SUCCESS.getMsg(); + } catch (Exception e) { + log.error("OfficialAccountController#receiptMessage fail:{}", Throwables.getStackTraceAsString(e)); + return RespStatusEnum.SERVICE_ERROR.getMsg(); } - return null; + } /** * 临时给微信服务号登录使用(生成二维码),正常消息推送平台不会有此接口 * - * @param accountId 消息推送平台体系内的Id * @return */ - @GetMapping("/qrCode") + @PostMapping("/qrCode") @ApiOperation("/生成 服务号 二维码") - public BasicResultVO getQrCode(Long accountId) { - if (accountId == null) { - return BasicResultVO.fail(RespStatusEnum.CLIENT_BAD_PARAMETERS); - } + public BasicResultVO getQrCode() { try { - // 生成随机值,获取服务号二维码 且 用于校验登录 - String id = IdUtil.getSnowflake().nextIdStr(); - WxMpService wxMpService = wxServiceUtils.getOfficialAccountServiceMap().get(accountId); - WxMpQrCodeTicket ticket = wxMpService.getQrcodeService().qrCodeCreateTmpTicket(id, 2592000); + String id = IdUtil.getSnowflake().nextIdStr(); + // 获取服务号二维码 + WxMpService wxMpService = wxServiceUtils.initOfficialAccountService(WeChatOfficialAccount.builder().appId(appId).secret(secret).build()); + WxMpQrCodeTicket ticket = wxMpService.getQrcodeService().qrCodeCreateTmpTicket(id, 2592000); String url = wxMpService.getQrcodeService().qrCodePictureUrl(ticket.getTicket()); - Map result = MapUtil.of(new String[][]{{"url", url}, {"id", id}}); - return BasicResultVO.success(result); + + // 存入Redis做校验 + return BasicResultVO.success(Convert4Amis.getWxMpQrCode(url)); } catch (Exception e) { log.error("OfficialAccountController#getQrCode fail:{}", Throwables.getStackTraceAsString(e)); return BasicResultVO.fail(RespStatusEnum.SERVICE_ERROR); } } - } diff --git a/austin-web/src/main/java/com/java3y/austin/web/service/impl/ChannelAccountServiceImpl.java b/austin-web/src/main/java/com/java3y/austin/web/service/impl/ChannelAccountServiceImpl.java index 70c9b85..5338b36 100644 --- a/austin-web/src/main/java/com/java3y/austin/web/service/impl/ChannelAccountServiceImpl.java +++ b/austin-web/src/main/java/com/java3y/austin/web/service/impl/ChannelAccountServiceImpl.java @@ -1,10 +1,10 @@ package com.java3y.austin.web.service.impl; import cn.hutool.core.date.DateUtil; -import com.java3y.austin.common.constant.AustinConstant; import com.java3y.austin.common.constant.CommonConstant; import com.java3y.austin.support.dao.ChannelAccountDao; import com.java3y.austin.support.domain.ChannelAccount; +import com.java3y.austin.support.utils.WxServiceUtils; import com.java3y.austin.web.service.ChannelAccountService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -19,6 +19,8 @@ public class ChannelAccountServiceImpl implements ChannelAccountService { @Autowired private ChannelAccountDao channelAccountDao; + @Autowired + private WxServiceUtils wxServiceUtils; @Override public ChannelAccount save(ChannelAccount channelAccount) { if (channelAccount.getId() == null) { @@ -26,7 +28,9 @@ public class ChannelAccountServiceImpl implements ChannelAccountService { channelAccount.setIsDeleted(CommonConstant.FALSE); } channelAccount.setUpdated(Math.toIntExact(DateUtil.currentSeconds())); - return channelAccountDao.save(channelAccount); + ChannelAccount result = channelAccountDao.save(channelAccount); + wxServiceUtils.fresh(); + return result; } @Override diff --git a/austin-web/src/main/java/com/java3y/austin/web/utils/Convert4Amis.java b/austin-web/src/main/java/com/java3y/austin/web/utils/Convert4Amis.java index bd4b338..d793499 100644 --- a/austin-web/src/main/java/com/java3y/austin/web/utils/Convert4Amis.java +++ b/austin-web/src/main/java/com/java3y/austin/web/utils/Convert4Amis.java @@ -305,4 +305,14 @@ public class Convert4Amis { return officialAccountParam; } + + /** + * 【这个方法不用看】,纯粹为了适配amis前端 + * + * 得到微信服务号的【带参数】二维码返回给前端 + * @return + */ + public static CommonAmisVo getWxMpQrCode(String url) { + return CommonAmisVo.builder().type("image").imageMode("original").width("450px").height("450px").title("扫描关注服务号-登录").src(url).build(); + } } diff --git a/austin-web/src/main/java/com/java3y/austin/web/vo/amis/CommonAmisVo.java b/austin-web/src/main/java/com/java3y/austin/web/vo/amis/CommonAmisVo.java index b54b08c..7e3c414 100644 --- a/austin-web/src/main/java/com/java3y/austin/web/vo/amis/CommonAmisVo.java +++ b/austin-web/src/main/java/com/java3y/austin/web/vo/amis/CommonAmisVo.java @@ -38,6 +38,17 @@ public class CommonAmisVo { private boolean needConfirm; + private String width; + + private String height; + + private String src; + + + private String title; + + private String imageMode; + /** * columns */ diff --git a/docker-compose.yml b/docker-compose.yml index 90e28af..34aa17d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -23,6 +23,10 @@ services: - 16379:6379 restart: always container_name: austin-redis + volumes: + - ./docker/redis.conf:/usr/local/etc/redis/redis.conf:rw + command: + /bin/bash -c "redis-server /usr/local/etc/redis/redis.conf" networks: - app austin: