Wechattty Project es un marco de desarrollo basado en JAVA para cuentas públicas de WeChat (incluidas cuentas de servicio y cuentas de suscripción) y cuentas empresariales de WeChat. La API bien encapsulada permite a los desarrolladores centrarse en el desarrollo de la lógica empresarial y mejorar la eficiencia del desarrollo.
Maven se utiliza aquí para introducir dependencias.
<dependency>
<groupId>space.chensheng.wechatty</groupId>
<artifactId>wechatty-mp</artifactId>
<version>2.0.0</version>
</dependency>
MpAppContext
es la entrada de llamadas unificada de la API de la cuenta pública, que se inicializa usando WechatMpBootstrap
.
WechatMpBootstrap bootstrap = new WechatMpBootstrap();
bootstrap.addMsgListener(new TextMessageListener());
MpAppContext mpAppContext = bootstrap.build();
Si el proyecto se gestiona mediante Spring, se puede implementar un FactoryBean
para inicializar MpAppContext
para referencia 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;
}
}
Hay dos métodos de configuración, uno es配置文件
y el otro es JAVA代码配置
. La prioridad de JAVA代码配置
es mayor que la配置文件
.
Cree un nuevo archivo de configuración wechat-mp.properties y coloque el archivo en la ruta de clase del proyecto. Por ejemplo, en un proyecto maven, este archivo se puede colocar en el directorio src/main/resources
. La configuración general es la siguiente:
token=thisIsToken
aesKey=thisIsAesKey
appId=thisIsYourAppId
appSecret=thisIsAppSecret
Cuando se inicializa MpAppConetxt
, llame al método customizeWechatContext
de WechatMpBootstrap
para la configuración.
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 requeridos | ilustrar |
---|---|
simbólico | El token de la cuenta oficial se puede ver en el fondo de la cuenta oficial. |
aesClave | La clave utilizada para el cifrado se puede ver en el backend de la cuenta oficial. |
ID de aplicación | El ID de aplicación de la cuenta oficial se puede ver en el fondo de la cuenta oficial. |
aplicaciónSecreto | La aplicación Secret de la cuenta oficial se puede ver en el fondo de la cuenta oficial. |
Parámetros opcionales | ilustrar |
---|---|
habilitarCryptedMode | Ya sea para habilitar el modo de cifrado de devolución de llamada, el valor predeterminado es verdadero. Si está activado, debe descargar el archivo de política de permisos sin restricciones de JCE para cubrir los archivos relevantes en el jdk. Para obtener más detalles, consulte ejemplos de errores comunes en WeChat. |
token de acceso de actualización automática | Si se actualiza automáticamente access_token cuando ocurre un error relacionado con access_token. El valor predeterminado es falso. La aplicación puede actualizarlo mediante tareas programadas, que se presentarán en detalle más adelante. |
accesoTokenStrategyClass | La estrategia de acceso access_token, la predeterminada es space.chensheng.wechatty.common.http.MemoryAccessTokenStrategy, almacena el access_token en la memoria y la aplicación puede implementar su propia estrategia de acceso, como almacenarlo en la base de datos, que se introducirá en detalle más adelante. |
clave de pago | Clave de pago de WeChat |
pagarCertFile | Ruta del archivo del certificado de pago de WeChat |
payCertContraseña | Contraseña del certificado de pago de WeChat |
pagoMchId | ID de comerciante de pagos de WeChat |
pagarClienteIp | Llame a la IP de la máquina para realizar el pago. |
agrupaciónHttpProxyEnable | Ya sea para solicitar el servidor WeChat a través de un servidor proxy, el valor predeterminado es falso |
poolingHttpProxyHostname | El nombre de host del servidor proxy, como www.chensheng.space |
agrupaciónHttpProxyPort | Puerto del servidor proxy |
poolingHttpProxyNombre de usuario | Nombre de usuario del servidor proxy |
poolingHttpProxyContraseña | Contraseña del servidor proxy |
agrupaciónHttpMaxPerRoute | El número máximo de conexiones simultáneas por enlace en el grupo de conexiones http, el valor predeterminado es 50 |
agrupaciónHttpMaxTotal | El número máximo de conexiones simultáneas en el grupo de conexiones http, predeterminado 200 |
agrupaciónHttpSocketTimeoutMillis | Número de milisegundos para el tiempo de espera del socket, predeterminado 10000 |
agrupaciónHttpConnectTimeoutMillis | Número de milisegundos para conectarse al tiempo de espera del servidor WeChat, predeterminado 10000 |
poolingHttpConnectionRequestTimeoutMillis | Obtenga el tiempo de espera de conexión en milisegundos del grupo de conexiones http, por defecto 10000 |
agrupaciónHttpTcpNoDelay | Ya sea para habilitar tpcNoDelay, valor predeterminado verdadero |
mpAppContext.getAccessTokenFetcher().updateAccessToken()
con regularidad, generalmente una vez cada 1,5 horas, porque el tiempo de vencimiento de access_token es de 2 horas.accessTokenStrategyClass=your.package.name.YourAccessTokenStrategy
en wechat-mp.properties. La siguiente es una estrategia para acceder a la base de datos 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 ();
}
}
Cuando se inicializa MpAppContext
, agregue un oyente de mensajes a través de WechatMpBootstrap
para recibir mensajes (el oyente de mensajes se presentará más adelante):
WechatMpBootstrap bootstrap = new WechatMpBootstrap();
bootstrap.addMsgListener(new TextMessageListener());
bootstrap.addMsgListener(new SubscribeEventListener());
bootstrap.addMsgListener(new UnsubscribeEventListener());
Si ha configurado una URL de devolución de llamada en el fondo de la cuenta pública de WeChat, el servidor de WeChat enviará una solicitud GET a esta URL para su verificación. El desarrollador debe manejar esta solicitud en la aplicación web. El siguiente es un ejemplo de verificación de 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;
}
}
Después de verificar la solicitud de devolución de llamada, el modo de devolución de llamada está realmente habilitado. Si el usuario envía un mensaje a la cuenta oficial, el servidor WeChat enviará una solicitud POST a la URL de devolución de llamada y reenviará el mensaje a esta URL. El desarrollador debe manejar esta solicitud en la aplicación web. El siguiente es un ejemplo de SpringMVC. (y el ejemplo de verificación anterior de habilitar la devolución de llamada en un 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;
}
}
Los desarrolladores pueden escuchar tipos específicos de mensajes heredando space.chensheng.wechatty.common.message.MessageListener
. A continuación se muestra un ejemplo de escucha de mensajes de texto enviados por usuarios:
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;
}
}
información | ilustrar |
---|---|
Mensaje de texto entrante | mensaje de texto |
ImagenEntranteMensaje | Mensaje con imagen |
EnlaceEntranteMensaje | Saltar al mensaje gráfico |
UbicaciónEntranteMensaje | Compartir información de ubicación |
Vídeo cortoMensaje entrante | Pequeño mensaje de vídeo |
VideoEntranteMensaje | mensaje de vídeo |
VozEntranteMensaje | mensaje de voz |
Haga clic en mensaje de evento | Haga clic en el mensaje del menú normal. |
Ver mensaje de evento | Haga clic para saltar al mensaje del menú del enlace |
UbicaciónEventoMensaje | Mensajes de eventos de ubicación |
SuscribirseEventMensaje | Los usuarios siguen las noticias de cuentas públicas. |
Cancelar suscripciónEventMensaje | Recuerde dejar de seguir los mensajes de cuentas públicas. |
Escanear mensaje de evento | El usuario escanea el mensaje del código QR |
MasaEnviarTrabajoFinalizarEventoMensaje | Informe de finalización de envío de mensajes grupales |
información | ilustrar |
---|---|
Mensaje de respuesta de texto | respuesta de texto |
ImagenRespuestaMensaje | Respuesta de imagen |
MúsicaRespuestaMensaje | respuesta musical |
NoticiasRespuestaMensaje | Respuesta gráfica |
VídeoRespuestaMensaje | respuesta en vídeo |
mensaje de respuesta de voz | respuesta de voz |
Las cuentas oficiales pueden enviar mensajes de forma proactiva a los usuarios, incluidos mensajes grupales y mensajes de servicio al cliente. Todos los mensajes se envían de manera uniforme utilizando space.chensheng.wechatty.mp.message.MpMessageSender
.
TextMassMessage message = new TextMassMessage();
message.setIsToAll(true);
message.setContent("群发消息测试");
mpAppContext.getMpMessageSender().send(message, 3);
Tipo de mensaje grupal | ilustrar |
---|---|
MensajeMasivoTexto | Texto masivo |
ImagenMasaMensaje | Envío de grupo de imágenes |
MpnoticiasMasaMensaje | Envío grupal de imágenes y texto dentro de WeChat |
MpvideoMasaMensaje | Envío de vídeo en grupo |
VozMasaMensaje | Envío de grupos de voz |
WxcardMassMensaje | Distribución masiva de tarjetas y cupones WeChat |
TextCsMessage message = new TextCsMessage();
message.setToUser("thisIsUserOpenId");
message.setContent("客服消息测试 n 212");
mpAppContext.getMpMessageSender().send(message, 3);
Tipo de mensaje de atención al cliente | ilustrar |
---|---|
TextoCsMensaje | Servicio al cliente por mensaje de texto |
ImagenCsMensaje | Imagen de servicio al cliente |
MpnoticiasCsMensaje | Servicio al cliente gráfico dentro de WeChat |
NoticiasCsMensaje | Atención al cliente gráfica externa |
VideoCsMensaje | Vídeo de atención al cliente |
VozCsMensaje | Atención al cliente por voz |
WxcardCsMensaje | Servicio al cliente de tarjetas y cupones WeChat |
La gestión de materiales implica principalmente cargar, consultar, modificar y eliminar materiales. Los tipos de materiales incluyen imágenes, videos, voces y gráficos.
La carga de materiales se completa operando la clase de carga de material correspondiente. El siguiente es un ejemplo de carga de imágenes:
File image = new File("/this/is/image/path.jpg");
ImagePermanentMedia material = new ImagePermanentMedia(mpAppContext, image);
UploadResponse resp = material.upload();
Clase de carga de materiales | ilustrar |
---|---|
ImagenPermanenteMedia | imagen permanente |
PulgarPermanenteMedia | Miniatura permanente |
VídeoPermanenteMedia | vídeo permanente |
VozPermanenteMedia | voz permanente |
PermanenteNoticias | Imágenes y textos permanentes. |
PermanenteNoticiasImg | Imágenes en gráficos permanentes |
ImagenTemporalMedios | imagen temporal |
PulgarTemporalMedia | Miniatura temporal |
VídeoTemporalMedios | vídeo temporal |
VozTemporalMedia | voz temporal |
La operación de consulta de materiales se completa a través de las clases de herramientas space.chensheng.wechatty.mp.material.MaterialQuery
y 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)
La operación de eliminación de material se completa a través de la clase de herramienta space.chensheng.wechatty.mp.material.MaterialDeleter
.
mpAppContext.getMaterialDeleter().delete(String mediaId)
La generación de códigos QR con parámetros se completa a través de la clase de herramienta space.chensheng.wechatty.mp.account.QRCodeCreator
.
mpAppContext.getQRCodeCreator().createTemporary(int expireSeconds, int sceneId)
mpAppContext.getQRCodeCreator().createPermanent(int sceneId)
mpAppContext.getQRCodeCreator().createPermanent(String sceneStr)
La consulta de información del usuario se implementa a través de UserInfoQuery
.
mpAppConext.getUserInfoQuery().get(String openId)
mpAppContext.getUserInfoQuery().batchGet(List<String> openIds)
La autorización del usuario se implementa a través de AuthHelper
.
auth access token
a través del código del enlace de autorización: mpAppContext.getAuthHelper().fetchAuthAccessToken(String code)
auth access token
: mpAppContext.getAuthHelper().refreshAuthAccessToken(String refreshAccessToken)
auth access token
: mpAppContext.getAuthHelper().fetchAuthUserInfo(String authAccessToken, String openId)
El siguiente es un pseudocódigo para la autorización del usuario:
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");
}
La autorización jsapi se implementa a través de JsapiHelper
.
jsapi ticket
(puede usar tareas programadas para obtener tickets regularmente y almacenarlos en la base de datos): mpAppContext.getJsapiHelper().fetchTicket()
mpAppContext.getJsapiHelper().generateSignature(String jsapiTicket, String nonceStr, long timestamp, String url)
Al inicializar MpAppContext
, llame enablePayCert()
de WechatMpBootstrap
para habilitar el pago de WeChat y configurar los parámetros relacionados. (Consulte el módulo de configuración 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)