Github開源項目:微信公衆號開發框架wechatty介紹

Wechattty Project是一個基於JAVA的微信公衆號(包括服務號和訂閱號)和微信企業號的開發框架,封裝良好的API讓開發者可以專注於業務邏輯的開發,提高開發效率。

簡單使用教程

引入依賴

這裏使用maven來引入依賴。

<dependency>
  <groupId>space.chensheng.wechatty</groupId>
  <artifactId>wechatty-mp</artifactId>
  <version>2.0.0</version>
</dependency>

初始化

MpAppContext是公衆號API的統一調用入口,使用WechatMpBootstrap對其進行初始化。

WechatMpBootstrap bootstrap = new WechatMpBootstrap();
bootstrap.addMsgListener(new TextMessageListener());
MpAppContext mpAppContext = bootstrap.build();

如果項目使用spring來管理,可實現一個FactoryBean來初始化MpAppContext,以便後續引用。

@Component
public class MpAppContextFactoryBean implements FactoryBean<MpAppContext> {

    @Override
    public MpAppContext getObject() throws Exception {
        WechatMpBootstrap bootstrap = new WechatMpBootstrap();
        bootstrap.addMsgListener(new TextMessageListener());
        return bootstrap.build();
    }

    @Override
    public Class<?> getObjectType() {
        return MpAppContext.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

配置

配置方式有兩種,一種是配置文件,另一種是 JAVA代碼配置。其中JAVA代碼配置的優先級高於配置文件

配置文件

新建配置文件wechat-mp.properties, 將該文件放在項目類路徑下。比如maven項目,可將該文件放在src/main/resources目錄下。一般的配置如下:

token=thisIsToken
aesKey=thisIsAesKey
appId=thisIsYourAppId
appSecret=thisIsAppSecret
JAVA代碼配置

MpAppConetxt初始化時,調用WechatMpBootstrapcustomizeWechatContext方法來進行配置。

WechatMpBootstrap bootstrap = new WechatMpBootstrap();
bootstrap.customizeWechatContext(new MpWechatContextCustomizer() {
    @Override
    public void customize(MpWechatContext wechatContext) {
    wechatContext.setToken("thisIsToken");
    wechatContext.setAesKey("thisIsAeskey");
    wechatContext.setAppId("thisIsAppId");
    wechatContext.setAppSecret("thisIsAppSecret");
    }
});
配置參數說明
必填參數 說明
token 公衆號的token,可在公衆號後臺查看.
aesKey 加密用的key, 可在公衆號後臺查看.
appId 公衆號appId,可在公衆號後臺查看。
appSecret 公衆號的appSecret,可在公衆號後臺查看。
可選參數 說明
enableCryptedMode 是否開啓回調加密模式,默認true。如果開啓則要下載JCE無限制權限策略文件,覆蓋jdk中的相關文件,具體可查看微信常見錯誤舉例
autoUpdateAccessToken 出現access_token相關錯誤時是否自動更新access_token,默認false,應用可自己通過定時任務來更新,後面將詳細介紹。
accessTokenStrategyClass access_token存取策略,默認是space.chensheng.wechatty.common.http.MemoryAccessTokenStrategy,將access_token存在內存中,應用可實現自己的存取策略,比如存在數據庫中,後面將詳細介紹。
payKey 微信支付key
payCertFile 微信支付證書文件路徑
payCertPassword 微信支付證書密碼
payMchId 微信支付商戶id
payClientIp 調用支付的機器ip
poolingHttpProxyEnable 是否通過代理服務器給微信服務器必請求,默認false
poolingHttpProxyHostname 代理服務器的hostname,比如www.chensheng.space
poolingHttpProxyPort 代理服務器端口
poolingHttpProxyUsername 代理服務器用戶名
poolingHttpProxyPassword 代理服務器密碼
poolingHttpMaxPerRoute http連接池每條鏈路最大併發連接數,默認爲50
poolingHttpMaxTotal http連接池最大併發連接數,默認200
poolingHttpSocketTimeoutMillis socket超時毫秒數,默認10000
poolingHttpConnectTimeoutMillis 連接到微信服務器超時毫秒數,默認10000
poolingHttpConnectionRequestTimeoutMillis 從htttp連接池獲取連接超時毫秒數,默認10000
poolingHttpTcpNoDelay 是否開啓tpcNoDelay,默認true
access_token更新問題
  • 自動更新:如果開啓了自動更新,則在因爲access_token錯誤而導致請求微信接口失敗的情況下,框架會自動更新access_token。
  • 定時更新:在應用中使用定時任務(比如quartz)來定時執行mpAppContext.getAccessTokenFetcher().updateAccessToken(),一般每1.5小時執行一次,因爲access_token的過期時間爲2小時。
  • 自動更新和定時更新可共存,如果多個線程併發執行更新access_token,只有一個線程會去請求微信服務器來更新access_token,其他線程會立即返回,不執行任何操作。
access_token存取策略問題
  • Web應用單機部署:如果您的應用是單機部署,則可直接使用默認的策略,將access_token存儲在內存中。
  • Web應用集羣部署:如果您的應用是集羣部署,則要實現自己的access_token存取策略,將access_token存放在集羣共享的媒介(比如數據庫)來達到access_token中控管理的目的。實現完自己的策略類後,要在wechat-mp.properties中添加配置accessTokenStrategyClass=your.package.name.YourAccessTokenStrategy。以下是一個accesss_token數據庫存取的策略:
import space.chensheng.wechatty.common.http.AccessTokenStrategy;

//因爲這個策略類的實例化不是通過Spring來管理的,所以在這個類中不能使用Autowired來注入bean,
//要通過ApplicationContext#getBean方法來獲取。
public class DatabaseAccessTokenStrategy implements AccessTokenStrategy{
    
    //將access_token存到數據庫中去
    @Override
    public void doSave(String accessToken) {
        TokenService tokenService = ApplicationContextUtil
        .getApplicationContext().getBean(TokenService.class);
    tokenService.doSave(accessToken);
    }
    
    //從數據庫中取出access_token
    @Override
    public String doQuery() {
        TokenService tokenService = ApplicationContextUtil
        .getApplicationContext().getBean(TokenService.class);
    return tokenService.doQuery();
    }
}

接收消息

MpAppContext初始化時,通過WechatMpBootstrap添加消息監聽器來接收消息(關於message listener會在後面介紹):

WechatMpBootstrap bootstrap = new WechatMpBootstrap();
bootstrap.addMsgListener(new TextMessageListener());
bootstrap.addMsgListener(new SubscribeEventListener());
bootstrap.addMsgListener(new UnsubscribeEventListener());
驗證微信服務器的開啓回調請求

如果你已經在微信公衆號後臺設置了回調URL,微信服務器會向這個URL發送一個GET請求來驗證,開發者需要在Web應用中處理這個請求。以下是一個SpringMVC的驗證例子:

@RestController
@RequestMapping(value = "/wechat-mp")
public class CallbackController extends BaseController{

    @Autowired
    private MpAppContext mpAppContext;
    
    //驗證請求,並回復字符串
    @RequestMapping(value = "/callback", method = RequestMethod.GET)
    public String verify(String msg_signature, String timestamp, String nonce, String echostr) {
        String reply = mpAppContext.getCallbackModeVerifier().verify(msg_signature, timestamp, nonce, echostr);
    return reply;
    }
    
}
消息回調請求處理

驗證完開啓回調請求後,回調模式就真正開啓了。如果用戶發了個消息給公衆號,微信服務器會向回調URL發送一個POST請求,將消息轉發到這個URL上,開發者需要在Web應用中處理這個請求,以下是一個SpringMVC的例子(和前面驗證開啓回調的例子在一個controller中):

@RestController
@RequestMapping(value = "/wechat-mp")
public class CallbackController extends BaseController{

    @Autowired
    private MpAppContext mpAppContext;
    
    //接收回調消息,並回復相應xml消息
    @RequestMapping(value = "/callback", method = RequestMethod.POST)
    public String verify(String msg_signature, String timestamp, String nonce) {
        //postBody是請求體內容,String格式,開發者可以通過HttpServletRequest來解析
        String replyXml = mpAppContext.getMpMessageDispatcher().dispatch(msg_signature(), timestamp, nonce, postBody);
    return replyXml;
    }
}
回調消息的監聽

開發者可以通過繼承space.chensheng.wechatty.common.message.MessageListener來監聽特定類型的消息。以下是一個監聽用戶發送的文本消息的例子:

public class TextMessageListener extends MessageListener<TextInboundMessage> {

    @Override
    protected ReplyMessage onMessage(TextInboundMessage message) {
        String content = message.getContent();
    
    //根據消息內容來回複用戶
    if ("1".equals(content)) {
        TextReplyMessage replyMsg = new TextReplyMessage();
        replyMsg.setContent("this is reply message content");
        replyMsg.setFromUserName(message.getToUserName());
        replyMsg.setToUserName(message.getFromUserName());
        replyMsg.setCreateTime(System.currentTimeMillis());
        return replyMsg;
    }
    
    //返回null表示不回覆用戶
    return null;
    }
}
可監聽的消息類型
消息 說明
TextInboundMessage 文本消息
ImageInboundMessage 圖片消息
LinkInboundMessage 跳轉圖文消息
LocationInboundMessage 共享位置消息
ShortVideoInboundMessage 小視頻消息
VideoInboundMessage 視頻消息
VoiceInboundMessage 語音消息
ClickEventMessage 點擊普通菜單消息
ViewEventMessage 點擊跳轉鏈接菜單消息
LocationEventMessage 位置事件消息
SubscribeEventMessage 用戶關注公衆號消息
UnsubscribeEventMessage 用記取消關注公衆號消息
ScanEventMessage 用戶掃描二維碼消息
MassSendJobFinishEventMessage 羣發消息發送完成報告
可回覆的消息類型
消息 說明
TextReplyMessage 文本回復
ImageReplyMessage 圖片回覆
MusicReplyMessage 音樂回覆
NewsReplyMessage 圖文回覆
VideoReplyMessage 視頻回覆
VoiceReplyMessage 語音回覆

發送消息

公衆號可以主動發送消息給用戶,包括羣發消息和客服消息兩大類型消息。所有消息統一使用space.chensheng.wechatty.mp.message.MpMessageSender來發送。

羣發消息
TextMassMessage message = new TextMassMessage();
message.setIsToAll(true);
message.setContent("羣發消息測試");
mpAppContext.getMpMessageSender().send(message, 3);
羣發消息類型 說明
TextMassMessage 文本羣發
ImageMassMessage 圖片羣發
MpnewsMassMessage 微信內圖文羣發
MpvideoMassMessage 視頻羣發
VoiceMassMessage 語音羣發
WxcardMassMessage 微信卡券羣發
客服消息
TextCsMessage message = new TextCsMessage();
message.setToUser("thisIsUserOpenId");
message.setContent("客服消息測試 \n 212");
mpAppContext.getMpMessageSender().send(message, 3);
客服消息類型 說明
TextCsMessage 文本客服
ImageCsMessage 圖片客服
MpnewsCsMessage 微信內圖文客服
NewsCsMessage 外部圖文客服
VideoCsMessage 視頻客服
VoiceCsMessage 語音客服
WxcardCsMessage 微信卡券客服

素材管理

素材管理主要是進行素材的上傳、查詢、修改、刪除,素材類型包括圖片、視頻、語音、圖文。

上傳素材

上傳素材通過操作對應的素材上傳類來完成,下面是一個上傳圖片的例子:

File image = new File("/this/is/image/path.jpg");
ImagePermanentMedia material = new ImagePermanentMedia(mpAppContext, image);
UploadResponse resp = material.upload();
素材上傳類 說明
ImagePermanentMedia 永久圖片
ThumbPermanentMedia 永久縮略圖
VideoPermanentMedia 永久視頻
VoicePermanentMedia 永久語音
PermanentNews 永久圖文
PermanentNewsImg 永久圖文中的圖片
ImageTemporaryMedia 臨時圖片
ThumbTemporaryMedia 臨時縮略圖
VideoTemporaryMedia 臨時視頻
VoiceTemporaryMedia 臨時語音
查詢素材

查詢素材操作通過工具類space.chensheng.wechatty.mp.material.MaterialQueryspace.chensheng.wechatty.mp.material.MaterialFinder完成。

  • 查詢素材的數量信息:mpAppContext.getMaterialQuery().count()
  • 查詢圖文素材:mpAppContext.getMaterialQuery().listNews(int offset, int count)
  • 查詢其他素材:mpAppContext.getMaterialQuery().listMedia(MediaType mediaType, int offset, int count)
  • 根據mediaId查找圖文:mpAppContext.getMaterialFinder().findNews(String mediaId)
  • 根據mediaId查找永久視頻:mpAppContext.getMaterialFinder().findPermanentVideo(String mediaId)
  • 根據mediaId查找臨時視頻:mpAppContext.getMaterialFinder().findTemporaryVideo(String mediaId)
  • 根據mediaId下載永久素材:mpAppContext.getMaterialFinder().downloadPermanentMedia(String mediaId, String saveDir, String fileName)
  • 根據mediaId下載臨時素材:mpAppContext.getMaterialFinder().downloadTemporaryMedia(String mediaId, String saveDir, String fileName)
刪除素材

刪除素材操作通過工具類space.chensheng.wechatty.mp.material.MaterialDeleter完成。

  • 根據mediaId刪除素材:mpAppContext.getMaterialDeleter().delete(String mediaId)

帳號管理

生成帶參數二維碼

生成帶參數二維碼通過工具類space.chensheng.wechatty.mp.account.QRCodeCreator完成。

  • 生成帶參數臨時二維碼:mpAppContext.getQRCodeCreator().createTemporary(int expireSeconds, int sceneId)
  • 生成帶整型參數永久二維碼:mpAppContext.getQRCodeCreator().createPermanent(int sceneId)
  • 生成帶字符串參數永久二維碼:mpAppContext.getQRCodeCreator().createPermanent(String sceneStr)
查詢用戶信息

查詢用戶信息通過UserInfoQuery實現。

  • 查詢單個用戶信息: mpAppConext.getUserInfoQuery().get(String openId)
  • 批量查詢用戶信息:mpAppContext.getUserInfoQuery().batchGet(List<String> openIds)

微信授權

用戶授權

用戶授權通過AuthHelper實現。

  • 通過授權鏈接的code獲取auth access token: mpAppContext.getAuthHelper().fetchAuthAccessToken(String code)
  • 刷新auth access token: mpAppContext.getAuthHelper().refreshAuthAccessToken(String refreshAccessToken)
  • 通過auth access token獲取用戶信息: mpAppContext.getAuthHelper().fetchAuthUserInfo(String authAccessToken, String openId)

以下是一段用戶授權的僞代碼:

public WxAuthLoginDto authAndLogin(String code) {
    AuthAccessTokenResponse authResp = mpAppContext.getAuthHelper().fetchAuthAccessToken(code);
    if (authResp == null || !authResp.isOk()) {
        //授權失敗,執行相應業務邏輯
        return new WxAuthLoginDto("fail");
    }
        
    String openId = authResp.getOpenId();
    AuthUserInfoResponse wxUserInfo = mpAppContext.getAuthHelper().fetchAuthUserInfo(authResp.getAccessToken(), authResp.getOpenId())
    //根據微信用戶信息在數據庫裏查找系統對應的用戶,或新建一個用戶
    
    //進行登錄相關業務邏輯處理
    return new WxAuthLoginDto("success");
}
jsapi授權

jsapi授權通過JsapiHelper實現。

  • 獲取jsapi ticket(可使用定時任務來定時獲取ticket並存於數據庫中): mpAppContext.getJsapiHelper().fetchTicket()
  • 生成jsapi簽名信息: mpAppContext.getJsapiHelper().generateSignature(String jsapiTicket, String nonceStr, long timestamp, String url)

微信支付

初始化MpAppContext時,調用WechatMpBootstrapenablePayCert()方法來啓用微信支付,並配置相關參數。(具體參數查看配置模塊)

WechatMpBootstrap bootstrap = new WechatMpBootstrap();
bootstrap.enablePayCert();
  • 發送普通紅包: mpAppContext.getPayHelper().sendRedPack(RedPackRequest request)
  • 發送羣紅包: mpAppContext.getPayHelper().sendGroupRedPack(GroupRedPackRequest request)
  • 轉賬: mpAppContext.getPayHelper().transfers(TransfersRequest request)
  • 生成預付款訂單: mpAppContext.getPayHelper().unifiedOrder(UnifiedOrderRequest request)
  • 解析支付回調: mpAppContext.getPayHelper().parsePayNotify(String notifyContent)
  • 校驗支付回調: mpAppContext.getPayHelper().validatePayNotify(PayNotifyResponse response)
  • 支付訂單查詢: mpAppContext.getPayHelper().orderQuery(OrderQueryRequest request)
  • 關閉支付訂單: mpAppContext.getPayHelper().closeOrder(CloseOrderRequest request)
  • 生成短鏈接: mpAppContext.getPayHelper().shortUrl(String longUrl)
  • 生成js支付參數: mpAppContext.getPayHelper().generateJsapiPayParams(String prepayId, PaySignType signType)
  • 發起退款: mpAppContext.getPayHelper().refund(RefundRequest request)
  • 解析退款回調: mpAppContext.getPayHelper().parseRefundNotify(String notifyContent)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章