He estado ocupado con la hora frontal por un tiempo. He leído los documentos desde cero y he pisado muchas dificultades. Lo he pasado recientemente. He considerado hacer algún resumen para poder revisarlo en el futuro cuando lo desarrollara. También daré una referencia a los estudiantes que trabajan en proyectos relacionados.
De hecho, después de hacerlo una vez, encontrará que no es difícil. La idea general es: los mensajes de usuario y los impulsos de eventos requeridos por los desarrolladores iniciarán una solicitud a través del servidor WeChat y la reenviarán a la dirección de URL del servidor que está configurado en la plataforma pública. El servidor WeChat traerá cuatro parámetros: firma, marca de tiempo, Nonce y Echostr. Nuestro servidor empalmará el token configurado por la plataforma pública y la marca de tiempo cargada. Nonce se encriptará en SHA1 y coincidirá con la firma. Devuelva el ture para indicar que el acceso es exitoso.
1. Configuración de la plataforma pública
2. controlador
@Controlador@requestmapping ("/weChat") publicClass weChatController {@Value ("$ {dnbx_token}") privado cadena dnbx_token; private estático final de logger = loggerFactory.getLogger (wechatcontroller.classs);@recursos de recursos @return * @throws ioexception */ @requestmapping (value = "/conection", método = {requestMethod.get, requestMethod.post}) @ResponseBodyPublicVoid ConnectWeixIn (httpservletRequest Solicitud, httpServletResponse Response) lanza ioexception {// Establezca la encodificación de la solicitud y respuesta a UTF-8 (Evitar el código de cuidado de garlada (evitar el código de garlada) request.setcharacterEncoding ("UTF-8"); // El servidor WeChat utiliza la codificación UTF-8 cuando los mensajes de publicación, y la misma codificación debe usarse al recibir; de lo contrario, el código de confusión chino será un código confuso; respuesta.setcharacterEncoding ("UTF-8"); // Al responder a los mensajes (responder al usuario), el método de codificación también se establece en UTF-8, el principio es el mismo que el anterior; boolean isget = request.getMethod (). tOlowerCase (). Equals ("get"); PrintWriter out = respuesta.getwriter (); try {if (isget) {String firature = requit.getParameter ("firma"); // wechat cifrado firma string timestamp = request.getParameter ("timestamp"); // timestamp string nonce = requit.getParameter ("nonce"); // number string echostr = request.getParameter ("echostr"); // cadena aleatoria // verifique la solicitud verificando la firma. Si la verificación es exitosa, devuelva el ecostr tal como está, lo que indica que el acceso es exitoso. De lo contrario, el acceso falla si (SignUTIl.CheckSignature (DNBX_Token, Signature, TimeStamp, Nonce)) {logger.info ("Conecte el servidor Weixin es exitoso"); Response.getWriter (). Write (ECHOSTR); } else {logger.error ("¡No se pudo verificar la firma!"); }}else{String respMessage = "Exception message! ";try {respMessage = wechatService.weixinPost(request);out.write(respMessage);LOGGER.info("The request completed successfully");LOGGER.info("to weixin server "+respMessage);} catch (Exception e) {LOGGER.error("Failed to convert the message from weixin! "); }}} catch (Exception e) {logger.error ("conectar el servidor weixin es error");} finalmente {out.close ();}}}3. Firma de verificación de verificación de firma
Desde el controlador anterior, podemos ver que encapsulé un significador de clase de herramientas, llamado firma de verificación y pasé en cuatro valores, dnbx_token, firma, marca de tiempo, nonce. Este proceso es muy importante. De hecho, podemos entenderlo como un proceso de cifrado y descifrado del valor transmitido por WeChat. Para garantizar la seguridad, todas las interfaces en muchos proyectos grandes tendrán tal proceso de verificación. DNBX_TOKen Hemos configurado una cadena de token en la plataforma pública WeChat, ¡mantenga la idea confidencial! Los otros tres son parámetros enviados por el servidor WeChat para enviar una solicitud GET. Realizamos una capa de cifrado SHA1:
public class SignUtil { /** * Verification signature * @param token WeChat server token, configured in the env.properties file and configured in the developer center must be consistent* @param signature The WeChat server sends the sha1 encrypted certificate signature* @param timestamp timestamp* @param nonce Random number* @return */ public static boolean checkSignature(String Token, String Signature, String TimeStamp, String Nonce) {String [] arr = new String [] {Token, Timestamp, Nonce}; // ordenar orden de diccionario de token, marca de tiempo y nonce; // empalme las tres cadenas de parámetros en una cadena para la cadena de cifrado Sha1 tmpStr = sha1.encode (arr [0] + arr [1] + arr [2]); // La cadena cifrada SHA1 se puede comparar con la firma, identificando que la solicitud proviene de WeChat Devuelve TMPSTR! = NULL? tmpstr.equals (firma.touppercase ()): falso; }}SHA1:
/** * WeChat Public Platform (JAVA) SDK * * SHA1 Algorithm * @author helijun 2016/06/15 19:49*/ public final class SHA1 { private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'c', 'd', 'e', 'f'}; /*** toma los bytes crudos del resumen y los formatea correctamente. * * @param bytes los bytes sin procesar del resumen. * @return los bytes formateados. */ cadena estática privada getFormattedText (byte [] bytes) {int len = bytes.length; StringBuilder buf = new StringBuilder (len * 2); // Convierta el texto cifrado en una forma de cadena hexadecimal para (int j = 0; j <len; j ++) {buf.append (hex_digits [(bytes [j] >> 4) y 0x0f]); buf.append (hex_digits [bytes [j] & 0x0f]); } return buf.ToString (); } public static string code (String str) {if (str == null) {return null; } try {MessageDigest MessageGest = MessageDigest.getInstance ("Sha1"); MessageDigest.Update (str.getBytes ()); return getFormattedText (MessageDigest.digest ()); } catch (Exception e) {Throw New RuntimeException (e); }}} Cuando lo envíe y lo guarde en la plataforma pública y vea el mensaje verde "éxito de acceso", felicidades por completar el acceso de WeChat. Este proceso requiere un poco más de cuidado y presta atención al caso en el algoritmo de cifrado. Si el acceso no tiene éxito, la mayoría de los casos son problemas con el algoritmo de cifrado, verifíquelo más.
4. Implementar el servicio de respuesta de mensaje automático
/*** Solicitudes de proceso de WeChat** @param request* @return*/public string weixInPost (httpservletRequest request) {string respmessage = null; try {// xml request de mapa de revisión <cadena> requestmap = messageUtil.xmltomap (request); // sender (abre_id) string fromusername = = = = = = = requestMap.get ("fromUsername"); // public Cuenta String tousername = requestmap.get ("tousername"); // Tipo de mensaje String msgType = requestMap.get ("msgtype"); // contenido de contenido de contenido = requestmap.get ("content"); logger.info ("fromuserName:" + fromusername + ", tousername: tousernam ", Msgtype es:" + msgtype); // mensaje de texto if (msgtype.equals (messageUtil.req_message_type_text)) {// La lógica correspondiente se ejecuta de acuerdo con las palabras clave. Solo hay uno que no puedes imaginar. No hay tal cosa como no puede hacer si (content.equals ("xxx")) {} // respuesta automática textMessage text = new TextMessage (); text.setContent ("El texto es" + contenido); text.setTouserName (fromUsername); textFromUsername (touseName); text.setCreateTime (new date (new date ().) ""); Text.SetMsgType (msgtype); respessage = messageUtil.TextMessageToxMl (text);}/*else if (msgtype.equals (messageUtil.req_message_type_event)) {// event string eventtype = requestmap.get ("Event"); // type de evento si if if if if if if if if if if if if if if ifting (eventtype.equals (messageUtil.event_type_subscribe)) {// suscríbete a respcontent = "¡Bienvenido para seguir la cuenta oficial xxx!" String EventKey = requestmap.get ("eventKey"); // valor de tecla de evento, correspondiente al valor de clave especificado al crear el menú personalizado logger.info ("EventKey es:" +eventKey); return xxx;}} // activar weChat prueba de reconocimiento 2015-3-30else if ((equalsequals ("voice") {string recovmessage = requestmap.get ("reconocimiento"); // respcontent = "resultado de análisis del habla:"+RecvMessage; if (recvMessage! = null) {respcontent = tulingapiprocess.gettulingResult (recvMessage);} else {respcontent = "Lo que dijiste es demasiado vago, ¿puedes decirlo nuevamente?";} return Messageresponse.getTextMessage (de UserName, TousName, RespContent); } // función de fotografía más if (msgtype.equals ("pic_sysphoto")) {} else {return Messageresponse.gettextMessage (fromUsername, tousername, "return vacía"); }*// Event Push Else if (msgtype.equals (messageUtil.req_message_type_event)) {String eventType = requestmap.get ("event"); // tipo de evento // suscripción if (eventtype.equals (messageUtil.event_type_subscribe)) {textMessage text = newnEn TextMessage (); text.setContent ("Bienvenido a seguir, xxx"); text.setTouserName (fromUSername); text.setFromUsername (tousername); text.setCreateTime (new Date (). GetTime () + ""); TextmSgType (MessageUtil.Resp_Message_Type_Text); MessageUtil.TextMessageToxMl (texto);} // TODO después de la suscripción, el usuario no puede recibir el mensaje enviado por la cuenta oficial, por lo que no es necesario responder al mensaje más if (eventType.equals (messageUtil.event_type_unsubscribe)))) {// nocrita} // menú personalizado (EventType.equals (MessageUtil.event_type_click)) {String EventKey = requestmap.get ("EventKey"); // Valor clave de eventos, correspondiente al valor de clave especificado al crear el menú personalizado if (eventKey.equals ("customer_telephone")) {TextMessage Text = nuevo nuevo TextMessage (); text.setContent ("0755-86671980"); text.setTouserName (fromUsername); text.setFromUsername (tousername); text.setCreateTime (nueva fecha (). Gettime () + ""); text.setmsgType (messageutil.Resp_message_typex); MessageUtil.TextMessageToxMl (Text);}}}}} Catch (Exception e) {logger.error ("Error ...")} return RespMessage;}El código se publica como se indicó anteriormente. La mayoría de ellos tienen comentarios. Si lee la semántica básica una vez, no necesita explicarlos.
Breve idea: cuando un usuario envía un mensaje a la cuenta oficial, el servidor WeChat solicitará el mensaje del usuario a través de la publicación a la interfaz correspondiente del servidor que configuramos en formato XML. Lo que tenemos que hacer es realizar el procesamiento lógico correspondiente basado en el tipo de mensaje, etc., y devolver el resultado de retorno final al servidor WeChat a través del formato XML, y luego transmitirlo al usuario.
Hay un lugar que necesita atención especial:
El nombre rojo del nombre y el nombre de tousername son exactamente lo contrario, que también es una de las trampas. Recuerdo que lo había ajustado durante mucho tiempo, pero no fue un problema, pero no estaba funcionando. ¡Finalmente, recibí el mensaje después de cambiar estos dos! De hecho, es correcto pensarlo. Cuando regrese al servidor WeChat, su rol cambiará, por lo que el remitente y el receptor son definitivamente lo contrario.
5. Messageutil
MessageUtil de clase pública {/ *** Tipo de mensaje de retorno: Text*/ public static final String resp_message_type_text = "text"; / *** Tipo de mensaje de retorno: música*/ public static final String resp_message_type_music = "Music"; / *** Tipo de mensaje de retorno: Texto gráfico*/ public static final String resp_message_type_news = "News"; / *** Tipo de mensaje de solicitud: Text*/ public static final String req_message_type_text = "text"; / *** Tipo de mensaje de solicitud: imagen*/ public static final String req_message_type_image = "imagen"; / *** Tipo de mensaje de solicitud: enlace*/ public static final String req_message_type_link = "enlace"; / *** Tipo de mensaje de solicitud: ubicación geográfica*/ public static final String req_message_type_location = "ubicación"; / *** Tipo de mensaje de solicitud: audio*/ public static final String req_message_type_voice = "Voice"; / ** * Tipo de mensaje de solicitud: Push */ public static final String req_message_type_event = "evento"; / ** * Tipo de evento: suscríbete (suscríbete) */ public static final string event_type_subscribe = "suscríbete"; / ** * Tipo de evento: Unsubscribe (Unsubscribe) */ public static final String event_type_unsubscribe = "Unsubscribe"; / ** * Tipo de evento: haga clic (Menú personalizado haga clic en evento) */ public static final String event_type_click = "haga clic"; }Aquí, para mejorar la legibilidad y la escalabilidad del programa, he hecho algunas encapsulación, definí varias constantes y encapsulé algunos parámetros que pasaron de WeChat a Java Bean objetos persistentes. El código central es el anterior. Concéntrese en la conversión entre XML y MAP
De hecho, este problema se atribuye a WeChat utilizando la comunicación XML, y generalmente usamos JSON, por lo que podemos sentirnos un poco incómodos en un corto período de tiempo.
1. PAQUETO DE INSTRODUCE
<
2.xml para mapear el objeto de colección
/*** xml Convertir a map* @param request* @return* @throws ioexception*/ @supressWarnings ("no verchado") público estático map <string, string> xmltomap (httpservletRequest request) lanza ioexception {map <string, string> map = new Hashmap <String String> (); Saxreader Reader = New SaxeTer (new Saxe; null; try {ins = request.getInputStream ();} catch (ioException e1) {e1.printStackTrace ();} document doc = null; try {doc = Reader.read (ins); elemento root = doc.getRootElement (); list> list = root.elements (); para (elemento e: list) {map.put (getgetName (),),). e.gettext ());} return map;} capt (documentException e1) {e1.printstackTrace ();} finalmente {ins.close ();} return null;}3. Convertir el objeto de mensaje de texto a XML
/ ** * Convertir el objeto de mensaje de texto a xml * * @param textMessage Mensaje de texto Objeto * @return xml */ public static string textMessageToxml (textMessage textMessage) {xstream xstream = new xStream (); xStream.alias ("xml", textMessage.getClasss ();Lo anterior es la introducción del editor a Java para implementar el acceso a WeChat de SpringMVC e implementar una función de respuesta automática simple. Espero que sea útil para todos. Si tiene alguna pregunta, déjame un mensaje y el editor responderá a todos a tiempo. ¡Muchas gracias por su apoyo al sitio web de Wulin.com!