Wechattty Project é uma estrutura de desenvolvimento baseada em JAVA para contas públicas WeChat (incluindo contas de serviço e contas de assinatura) e contas empresariais WeChat. A API bem encapsulada permite que os desenvolvedores se concentrem no desenvolvimento da lógica de negócios e melhorem a eficiência do desenvolvimento.
Maven é usado aqui para introduzir dependências.
<dependency>
<groupId>space.chensheng.wechatty</groupId>
<artifactId>wechatty-mp</artifactId>
<version>2.0.0</version>
</dependency>
MpAppContext
é a entrada de chamada unificada para a API da conta pública, que é inicializada usando WechatMpBootstrap
.
WechatMpBootstrap bootstrap = new WechatMpBootstrap();
bootstrap.addMsgListener(new TextMessageListener());
MpAppContext mpAppContext = bootstrap.build();
Se o projeto for gerenciado usando spring, um FactoryBean
pode ser implementado para inicializar MpAppContext
para referência posterior.
@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;
}
}
Existem dois métodos de configuração, um é配置文件
e o outro é JAVA代码配置
. A prioridade da JAVA代码配置
é maior que a配置文件
.
Crie um novo arquivo de configuração wechat-mp.properties e coloque o arquivo no caminho de classe do projeto. Por exemplo, em um projeto maven, esse arquivo pode ser colocado no diretório src/main/resources
. A configuração geral é a seguinte:
token=thisIsToken
aesKey=thisIsAesKey
appId=thisIsYourAppId
appSecret=thisIsAppSecret
Quando MpAppConetxt
for inicializado, chame o método customizeWechatContext
de WechatMpBootstrap
para configuração.
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");
}
});
Parâmetros obrigatórios | ilustrar |
---|---|
ficha | O token da conta oficial pode ser visualizado no fundo da conta oficial. |
aesKey | A chave usada para criptografia pode ser visualizada no fundo da conta oficial. |
ID do aplicativo | O appId da conta oficial pode ser visualizado no fundo da conta oficial. |
appSecret | O appSecret da conta oficial pode ser visualizado no fundo da conta oficial. |
Parâmetros opcionais | ilustrar |
---|---|
ativarCryptedMode | Se deve ativar o modo de criptografia de retorno de chamada, o padrão é verdadeiro. Se estiver ativado, você precisará baixar o arquivo de política de permissões irrestritas do JCE para cobrir os arquivos relevantes no jdk. Para obter detalhes, consulte exemplos de erros comuns no WeChat. |
autoUpdateAccessToken | Se o access_token deve ser atualizado automaticamente quando ocorre um erro relacionado ao access_token O padrão é falso. O aplicativo pode atualizá-lo por meio de tarefas agendadas, que serão apresentadas em detalhes posteriormente. |
accessTokenStrategyClass | A estratégia de acesso access_token, o padrão é space.chensheng.wechatty.common.http.MemoryAccessTokenStrategy, armazena o access_token na memória, e a aplicação pode implementar sua própria estratégia de acesso, como armazená-lo no banco de dados, que será introduzido em detalhe mais tarde. |
chave de pagamento | Chave de pagamento WeChat |
payCertFile | Caminho do arquivo do certificado de pagamento WeChat |
pagarCertPassword | Senha do certificado de pagamento WeChat |
pagarMchId | ID do comerciante de pagamento WeChat |
pagarClientIp | Ligue para o IP da máquina para pagamento |
poolingHttpProxyEnable | Se deseja solicitar o servidor WeChat por meio de um servidor proxy, o padrão é falso |
poolingHttpProxyHostname | O nome do host do servidor proxy, como www.chensheng.space |
poolingHttpProxyPort | Porta do servidor proxy |
poolingHttpProxyUsername | Nome de usuário do servidor proxy |
poolingHttpProxyPassword | Senha do servidor proxy |
poolingHttpMaxPerRoute | O número máximo de conexões simultâneas por link no pool de conexões http, o padrão é 50 |
poolingHttpMaxTotal | O número máximo de conexões simultâneas no pool de conexões http, padrão 200 |
poolingHttpSocketTimeoutMillis | Número de milissegundos para o tempo limite do soquete, padrão 10.000 |
poolingHttpConnectTimeoutMillis | Número de milissegundos para conectar-se ao tempo limite do servidor WeChat, padrão 10.000 |
poolingHttpConnectionRequestTimeoutMillis | Obtenha o tempo limite da conexão em milissegundos do pool de conexões http, padrão 10000 |
poolingHttpTcpNoDelay | Se deve ativar tpcNoDelay, padrão verdadeiro |
mpAppContext.getAccessTokenFetcher().updateAccessToken()
regularmente, geralmente uma vez a cada 1,5 horas, porque o tempo de expiração do access_token é de 2 horas.accessTokenStrategyClass=your.package.name.YourAccessTokenStrategy
em wechat-mp.properties. A seguir está uma estratégia para acessar o banco de dados 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 ();
}
}
Quando MpAppContext
for inicializado, adicione um ouvinte de mensagens por meio do WechatMpBootstrap
para receber mensagens (o ouvinte de mensagens será apresentado posteriormente):
WechatMpBootstrap bootstrap = new WechatMpBootstrap();
bootstrap.addMsgListener(new TextMessageListener());
bootstrap.addMsgListener(new SubscribeEventListener());
bootstrap.addMsgListener(new UnsubscribeEventListener());
Se você tiver definido um URL de retorno de chamada no plano de fundo da conta oficial do WeChat, o servidor WeChat enviará uma solicitação GET a esse URL para verificação. O desenvolvedor precisa lidar com essa solicitação no aplicativo da web. A seguir está um exemplo de verificação do 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;
}
}
Depois de verificar a solicitação de retorno de chamada, o modo de retorno de chamada é realmente ativado. Se o usuário enviar uma mensagem para a conta oficial, o servidor WeChat enviará uma solicitação POST para o URL de retorno e encaminhará a mensagem para este URL. O desenvolvedor precisa lidar com essa solicitação no aplicativo da web. (e o exemplo de verificação anterior de ativação de retorno de chamada em um controlador):
@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;
}
}
Os desenvolvedores podem ouvir tipos específicos de mensagens herdando space.chensheng.wechatty.common.message.MessageListener
. Aqui está um exemplo de como ouvir mensagens de texto enviadas por usuários:
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;
}
}
Informação | ilustrar |
---|---|
Mensagem de entrada de texto | mensagem de texto |
ImagemInboundMessage | Mensagem gráfica |
LinkInboundMessage | Ir para a mensagem gráfica |
LocalizaçãoInboundMessage | Compartilhe informações de localização |
ShortVideoInboundMessage | Pequena mensagem de vídeo |
Mensagem de entrada de vídeo | mensagem de vídeo |
Mensagem de entrada de voz | mensagem de voz |
ClickEventMessage | Clique na mensagem do menu normal |
VerEventMessage | Clique para ir para a mensagem do menu do link |
LocalizaçãoEventoMessage | Mensagens de eventos de localização |
SubscribeEventMessage | Os usuários acompanham notícias de contas públicas |
Cancelar inscriçãoEventMessage | Lembre-se de parar de seguir mensagens de contas públicas |
ScanEventMessage | O usuário escaneia a mensagem do código QR |
MassSendJobFinishEventMessage | Relatório de conclusão de envio de mensagem em grupo |
Informação | ilustrar |
---|---|
Mensagem de resposta de texto | resposta de texto |
Mensagem de resposta de imagem | Resposta de imagem |
Mensagem de resposta de música | resposta musical |
NotíciasResponderMensagem | Resposta gráfica |
Mensagem de resposta de vídeo | resposta de vídeo |
Mensagem de resposta de voz | Resposta de voz |
As contas oficiais podem enviar mensagens proativamente aos usuários, incluindo mensagens em grupo e mensagens de atendimento ao cliente. Todas as mensagens são enviadas uniformemente usando space.chensheng.wechatty.mp.message.MpMessageSender
.
TextMassMessage message = new TextMassMessage();
message.setIsToAll(true);
message.setContent("群发消息测试");
mpAppContext.getMpMessageSender().send(message, 3);
Tipo de mensagem de grupo | ilustrar |
---|---|
TextMassMessage | Texto em massa |
ImageMassMessage | Envio de grupo de imagens |
MpnewsMassMessage | Envio em grupo de fotos e texto no WeChat |
MpvideoMassMessage | Envio de vídeo em grupo |
Mensagem de voz em massa | Envio de grupo de voz |
WxcardMassMessage | Distribuição em massa de cartões e cupons WeChat |
TextCsMessage message = new TextCsMessage();
message.setToUser("thisIsUserOpenId");
message.setContent("客服消息测试 n 212");
mpAppContext.getMpMessageSender().send(message, 3);
Tipo de mensagem de atendimento ao cliente | ilustrar |
---|---|
TextCsMessage | Atendimento ao cliente por mensagem de texto |
ImagemCsMessage | Foto do atendimento ao cliente |
MpnewsCsMessage | Atendimento gráfico ao cliente no WeChat |
NotíciasCsMensagem | Atendimento gráfico externo |
VideoCsMessage | Atendimento ao cliente por vídeo |
Mensagem VoiceCs | Atendimento ao cliente por voz |
Mensagem WxcardCs | Atendimento ao cliente com cartão e voucher WeChat |
O gerenciamento de materiais envolve principalmente upload, consulta, modificação e exclusão de materiais. Os tipos de materiais incluem imagens, vídeos, vozes e gráficos.
O upload de materiais é concluído operando a classe de upload de material correspondente. A seguir está um exemplo de upload de imagens:
File image = new File("/this/is/image/path.jpg");
ImagePermanentMedia material = new ImagePermanentMedia(mpAppContext, image);
UploadResponse resp = material.upload();
Aula de upload de material | ilustrar |
---|---|
ImagemPermanentMedia | imagem permanente |
ThumbPermanentMedia | Miniatura permanente |
VídeoPermanenteMídia | vídeo permanente |
VoicePermanentMedia | voz permanente |
Notícias Permanentes | Imagens e textos permanentes |
PermanentNewsImg | Imagens em gráficos permanentes |
ImagemTemporáriaMídia | Imagem temporária |
ThumbTemporaryMedia | Miniatura temporária |
VídeoTemporárioMídia | vídeo temporário |
VozTemporáriaMídia | Voz temporária |
A operação de consulta de material é concluída por meio das classes de ferramentas space.chensheng.wechatty.mp.material.MaterialQuery
e space.chensheng.wechatty.mp.material.MaterialFinder
.
mpAppContext.getMaterialQuery().count()
mpAppContext.getMaterialQuery().listNews(int offset, int count)
mpAppContext.getMaterialQuery().listMedia(MediaType mediaType, int offset, int count)
mpAppContext.getMaterialFinder().findNews(String mediaId)
mpAppContext.getMaterialFinder().findPermanentVideo(String mediaId)
mpAppContext.getMaterialFinder().findTemporaryVideo(String mediaId)
mpAppContext.getMaterialFinder().downloadPermanentMedia(String mediaId, String saveDir, String fileName)
mpAppContext.getMaterialFinder().downloadTemporaryMedia(String mediaId, String saveDir, String fileName)
A operação de exclusão de material é concluída por meio da classe de ferramenta space.chensheng.wechatty.mp.material.MaterialDeleter
.
mpAppContext.getMaterialDeleter().delete(String mediaId)
A geração de códigos QR com parâmetros é concluída por meio da classe de ferramenta space.chensheng.wechatty.mp.account.QRCodeCreator
.
mpAppContext.getQRCodeCreator().createTemporary(int expireSeconds, int sceneId)
mpAppContext.getQRCodeCreator().createPermanent(int sceneId)
mpAppContext.getQRCodeCreator().createPermanent(String sceneStr)
A consulta de informações do usuário é implementada por meio de UserInfoQuery
.
mpAppConext.getUserInfoQuery().get(String openId)
mpAppContext.getUserInfoQuery().batchGet(List<String> openIds)
A autorização do usuário é implementada através AuthHelper
.
auth access token
por meio do código do link de autorização: mpAppContext.getAuthHelper().fetchAuthAccessToken(String code)
auth access token
: mpAppContext.getAuthHelper().refreshAuthAccessToken(String refreshAccessToken)
auth access token
: mpAppContext.getAuthHelper().fetchAuthUserInfo(String authAccessToken, String openId)
A seguir está um pseudocódigo para autorização do usuário:
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");
}
A autorização jsapi é implementada por meio de JsapiHelper
.
jsapi ticket
(você pode usar tarefas agendadas para obter tickets regularmente e armazená-los no banco de dados): mpAppContext.getJsapiHelper().fetchTicket()
mpAppContext.getJsapiHelper().generateSignature(String jsapiTicket, String nonceStr, long timestamp, String url)
Ao inicializar MpAppContext
, chame enablePayCert()
do WechatMpBootstrap
para habilitar o pagamento WeChat e configurar parâmetros relevantes. (Veja o módulo de configuração para parâmetros específicos)
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)
mpAppContext.getPayHelper().generateJsapiPayParams(String prepayId, PaySignType signType)
mpAppContext.getPayHelper().refund(RefundRequest request)
mpAppContext.getPayHelper().parseRefundNotify(String notifyContent)