Eu estava ocupado há um tempo atrás. Comecei a desenvolver a conta oficial do WeChat e ler os documentos do zero. Eu pisei em muitas armadilhas. Eu já passei por isso. Recentemente, pensei em fazer algum resumo para que eu possa revisá -lo quando o desenvolver no futuro. Também darei uma referência aos alunos que estão trabalhando em projetos relacionados.
1. Ideias
Acesso do WeChat: As mensagens do usuário e os empurrões exigidos pelos desenvolvedores iniciarão uma solicitação através do servidor WeChat e encaminharão para o endereço do URL do servidor que você configurou na plataforma pública. O servidor WeChat trará os quatro parâmetros de assinatura, registro de data e hora, nonce e ecos. Nosso próprio servidor emaranha ao token configurado pela plataforma pública, bem como o registro de data e hora, e o nonce é criptografado no SHA1 e corresponde à assinatura. Retorne a termo para indicar que o acesso é bem -sucedido.
Resposta da mensagem: Quando um usuário envia uma mensagem para a conta oficial, o servidor WeChat solicitará a mensagem do usuário para a interface correspondente do servidor que configuramos no formato XML por meio da postagem. O que precisamos fazer é executar o processamento lógico correspondente com base no tipo de mensagem, etc., e retornar o resultado final de retorno ao servidor WeChat através do formato XML, e a parte WeChat o transmitirá ao usuário.
1. Configuração da plataforma pública
2. Controlador
@Controlador @requestmapping ("/wechat") publicClass wechatcontroller {@value ("$ {dnbx_token}") private string dnbx_token; Logger final estático privado Logger = LoggerFactory.getLogger (wechatcontroller.class); @Resource WeChatService Wechatservice; /** * WeChat access* @param wc * @return * @throws IOException */ @RequestMapping(value="/connect",method = {RequestMethod.GET, RequestMethod.POST}) @ResponseBody publicvoid connectWeixin(HttpServletRequest request, HttpServletResponse response) throws IOException{ // Set the encoding of the request and resposta ao UTF-8 (Prevent Chinese Glebled) request.Setcharacterencoding ("UTF-8"); // O servidor WeChat usa a codificação do UTF-8 quando as mensagens postais e a mesma codificação deve ser usada ao receber, caso contrário, os chineses foram divulgados; Response.Setcharacterencoding ("UTF-8"); // Ao responder às mensagens (respondendo ao usuário), o método de codificação também está definido como UTF-8, o princípio é o mesmo que acima; boolean isget = request.getMethod (). tolowerCase (). igual ("get"); PrintWriter out = Response.getWriter (); try {if (isGet) {string assinatura = request.getParameter ("assinatura"); // weChat criptografia assinatura string timestamp = request.getParameter ("timestamp"); // timestamp string nonce = request. assinatura. Se a verificação for bem -sucedida, o Return EchoStr como está, indicando que o acesso é bem -sucedido. Caso contrário, o acesso falha se (signutil.checkSignature (dnbx_token, assinatura, registro de data e hora, nonce)) {logger.info ("Connect the weixin servidor é bem -sucedido."); resposta.getWriter (). Write (ECHOSTR); } else {Logger.error ("Falha ao verificar a assinatura!"); }} else {string respMessage = "Mensagem de exceção!"; tente {respmessage = wechatService.weixinpost (request); out.write (respmessage); Logger.info ("a solicitação concluída com êxito"); Logger.info ("para weixin server"+respmessage); } catch (Exceção e) {Logger.error ("Falha ao converter a mensagem de Weixin!"); }}} catch (Exceção e) {Logger.error ("Connect the Weixin Server é erro."); } finalmente {out.close (); }}}3. Assinatura de verificação de assinatura
A partir do controlador acima, podemos ver que eu encapsulei uma classe de ferramentas Signutil, denominada design de verificação e passei em quatro valores, dnbx_token, assinatura, registro de data e hora. Este processo é muito importante. De fato, podemos entendê -lo como um processo de criptografia e descriptografia do valor transmitido pelo WeChat. Para garantir a segurança, todas as interfaces em muitos grandes projetos terão esse processo de verificação. DNBX_TOKen Configuramos uma string de token na plataforma pública do WeChat, mantenha a ideia confidencial! Os outros três são parâmetros enviados pelo servidor WeChat para enviar uma solicitação GET. Realizamos uma camada de criptografia SHA1:
classe pública SignUtil { / *** Assinatura de verificação* Token do servidor WeChat @param, configurado no arquivo Env.Properties e configurado no centro do desenvolvedor deve ser consistente* @param assinatura O servidor weChat envia o sha1 recriado de certificado* @param @PoTamMOTAMPOTAMPATAMP* @Part INPARTAMENTO REMOTENCO REMOTEN @PoTATIM @ParTaMeCT Randimated Nourset Numberature* @param TimunMUNGamMonTamp* @Panda @Panda @Panda @Panda NonCoMenc Random Numberature* @param timestampampulp* @paramen @PartEn Random Numberd Token, String Signature, String Timestamp, String nonce) {String [] arr = new String [] {token, Timestamp, Nonce}; // Classifica a ordem do dicionário de token, registro de data e hora e nonce; // cedem as três cadeias de parâmetros em uma string para string de criptografia sha1 tmpstr = sha1.encode (arr [0] + arr [1] + arr [2]); // O string criptografado SHA1 pode ser comparado com a assinatura, identificando que a solicitação vem do WeChat Return tmpstr! = NULL? tmpstr.equals (assinatura.touppercase ()): false; }} SHA1:
/** * Plataforma pública WeChat (Java) SDK * * SHA1 Algoritmo * @Author Helijun 2016/06/15 19:49 */public Final Class SHA1 {private Static Final [] hex_digits = {'0', '1', '2', '' 3 ',' 4 '' '' '' '' '', 'B', 'c', 'd', 'e', 'f'}; /*** pega os bytes crus do digerido e os formam corretos. * * @param bytes Os bytes crus do digerir. * @return os bytes formatados. */ string estática privada getFormattedText (byte [] bytes) {int len = bytes.length; StringBuilder BUF = new StringBuilder (Len * 2); // converte o CipherText em uma forma de sequência hexadecimal para (int j = 0; j <len; j ++) {buf.append (hex_digits [(bytes [j] >> 4) & 0x0f]); buf.append (hex_digits [bytes [j] & 0x0f]); } retornar buf.toString (); } public static string cody (string str) {if (str == null) {return null; } tente {Messagedigest Messagedigest = MessAgedigest.getInstance ("sha1"); Messagedigest.Update (str.getBytes ()); return getFormattedText (Messagedigest.Digest ()); } catch (Exceção e) {lança nova RunTimeException (e); }}}Quando você envia e salva -o na plataforma pública e vê o prompt verde "Access Success", parabéns por concluir o acesso do WeChat. Esse processo requer um pouco mais de cuidado e preste atenção ao caso no algoritmo de criptografia. Se o acesso não for bem -sucedido, a maioria dos casos são problemas com o algoritmo de criptografia, verifique mais.
4. Implementar serviço de resposta de mensagem automática
/ ** * Solicitações de processo do weChat * * @param request * @return */ public string weixInpost (httpServletRequest request) {string respmessage = null; tente {// xml solicitar o mapa de análise <string, string> requestmap = messageUtil.xmlTomaP (request); // Conta do remetente (open_id) string deUserName = requestmap.get ("DOUSUERNAME"); // string pública de conta toumerername = requestmap.get ("touserrame"); // Tipo de mensagem String msgtype = requestmap.get ("msgtype"); // Mensagem Content String Content = requestMap.get ("Content"); Logger.info ("Fromusername é:" + FromUserName + ", TouserName é:" + tousername + ", msgtype é:" + msgtype); // Mensagem de texto if (msgtype.equals (messageutil.req_message_type_text)) {// Aqui você executa a lógica correspondente de acordo com as palavras -chave, existe apenas uma que você não consegue pensar e não é que você não pode fazer ("xxx")) {} // automatiza; text.setContent ("O texto é" + conteúdo); text.setTouserName (FromUrName); text.setFromUserName (TouserName); text.setCreateTime (new Date (). getTime () + ""); text.setmsgtype (msgtype); respmessage = messageUtil.TextMessageToxml (texto); }/*else if (msgtype.equals (messageutil.req_message_type_event)) {// evento push string eventtype = requestmap.get ("event"); // tipo de evento if (eventtype.equals (messageutil.event_typent); return messagerponse.getTextMessage (FromUserName, TouserName, Respontent); } else if (eventtype.equals (messageutil.event_type_click)) {// menu personalizado Clique em Event String EventKey = requestmap.get ("eventKey"); // o valor da chave do evento, correspondente ao valor da chave especificado ao criar o menu personalizado Logger.info ("EventKey Is:" +Key); retornar xxx; }} // Ligue o teste de reconhecimento de som do WeChat 2015-3-30 else if (msgtype.equals ("voz")) {string recvmessage = requestmap.get ("reconhecimento"); // respcontent = "Recebido resultado da análise da fala:"+Recvmessage; if (recvmessage! = null) {respcontent = tulingapiprocess.gettulingResult (recvmessage); } else {respcontent = "O que você disse é muito vago, você pode dizer isso de novo?"; } return messagerponse.getTextMessage (FromUserName, TouserName, Respontent); } // Função fotográfica else if (msgtype.equals ("pic_sysphoto")) {} else {return messagerponse.getTextMessage (FromUserName, tousername, "retornar ao vazio"); }*/ // Evento Empurre else if (msgtype.equals (messageutil.req_message_type_event)) {string eventtype = requestmap.get ("event"); // typet // assinar if (eventtype.equals (messageTil.Event_tyMeess (textTess; text.setContent ("Bem -vindo a seguir, xxx"); text.setTouserName (FromUrName); text.setFromUserName (TouserName); text.setCreateTime (new Date (). getTime () + ""); text.setmsgtype (messageutil.resp_message_type_text); respmessage = messageUtil.TextMessageToxml (texto); } // TODO Após cancelar a inscrição, o usuário não pode receber a mensagem enviada pela conta oficial; portanto, não há necessidade de responder à mensagem mais se (eventtype.equals (messageutil.event_type_unsubscribe)) {// unsubScribe} // menu personalizado clique em Event if (eventtype.equals (util.evcredor} // Menu CLIQUE DE CLIQUE requestmap.get ("EventKey"); // O valor da chave do evento corresponde ao valor da chave especificado ao criar um menu personalizado se (eventKey.equals ("Customer_telephone")) {textMessage text = new textMessage (); text.setContent ("0755-86671980"); text.setTouserName (FromUrName); text.setFromUserName (TouserName); text.setCreateTime (new Date (). getTime () + ""); text.setmsgtype (messageutil.resp_message_type_text); respmessage = messageUtil.TextMessageToxml (texto); }}}} Catch (Exceção e) {Logger.error ("Error ...")} Retornar respmessage; }O código é publicado como acima. A maioria deles tem comentários. Se você ler a semântica básica uma vez, não precisará explicá -las.
Há um lugar que precisa de atenção especial:
O nome vermelho e o nome de Tousername são exatamente o oposto, o que também é uma das armadilhas. Lembro que o ajustei há muito tempo, mas não foi um problema, mas não estava funcionando. Finalmente, recebi a mensagem depois de alterar esses dois! Na verdade, é correto pensar sobre isso. Quando você retornar ao servidor WeChat, sua função mudará, para que o remetente e o receptor sejam definitivamente o oposto.
5.MessageUtil
public class MessageUtil { / *** Retornar Tipo de mensagem: Texto* / public static final String resp_message_type_text = "text"; / *** Return Message Type: Music*/ public static final string resp_message_type_music = "music"; / *** Retornar Tipo de mensagem: Texto gráfico*/ public static final string resp_message_type_news = "News"; / *** Tipo de mensagem de solicitação: texto*/ public static final string req_message_type_text = "text"; / *** Tipo de mensagem de solicitação: imagem*/ public static final string req_message_type_image = "image"; / *** Tipo de mensagem de solicitação: link*/ public static final string req_message_type_link = "link"; / *** Tipo de mensagem de solicitação: localização geográfica*/ public static string final req_message_type_location = "location"; / *** Tipo de mensagem de solicitação: áudio*/ public static string final req_message_type_voice = "voz"; / ** * Tipo de mensagem de solicitação: push */ public static final string req_message_type_event = "event"; / ** * Tipo de evento: Inscreva -se (assinando) */ public static final string event_type_subscribe = "assinando"; / * * / ** * Tipo de evento: clique (menu personalizado, clique em Evento) */ public static final string event_type_click = "clique"; }Aqui, para melhorar o programa e a escalabilidade, fiz alguns encapsulamento, defini várias constantes e encapsulou alguns parâmetros passados do WeChat para os objetos persistentes do Java Bean. O código principal é como acima. Concentre -se na conversão entre XML e mapa
De fato, esse problema é atribuído ao WeChat usando a comunicação XML e geralmente usamos o JSON, para que possamos nos sentir um pouco desconfortáveis em um curto período de tempo.
1. Introduzir o pacote JAR
<!-Parse xml-> <pendency> <puperiD> dom4j </groupiD> <TROTIFACTID> DOM4J </ARTIFACTID> <Versão> 1.6.1 </versão </dependency> <pendence> <pream> com.thoughtworks.xstream </groupid> <stifactId> xstream </artiftId.
2.xml para mapear objeto de coleta
/** * xml to map * @param request * @return * @throws IOException */ @SuppressWarnings("unchecked") public static Map<String, String> xmlToMap(HttpServletRequest request) throws IOException{ Map<String, String> map = new HashMap<String, String>(); SAXReader Reader = new SaxReader (); InputStream ins = null; tente {ins = request.getInputStream (); } catch (ioexception e1) {e1.printStackTrace (); } Documento doc = null; tente {doc = reader.read (ins); Elemento root = doc.getrootelement (); List <lement> list = root.elements (); para (elemento e: list) {map.put (e.getName (), e.getText ()); } mapa de retorno; } catch (documentException e1) {e1.printStackTrace (); } finalmente {ins.close (); } retornar nulo; } 3. Converta o objeto de mensagem de texto em xml
/ ** * Converta o objeto de mensagem de texto para xml * * @param textMessage Text Mensagem Objeto * @return xml */ public static string textMessageToxml (textMessage textMessage) {xstream xStream = new XStream (); xstream.alias ("xml", textMessage.getClass ()); retornar xstream.toxml (textMessage); } Até agora, o trabalho foi concluído. Neste momento, você pode tentar enviar "teste" na conta oficial. Você receberá uma resposta do WeChat "O texto é teste". Este também é o processo de resposta fabricado no código acima. Obviamente, você também pode usar sua imaginação para fazer tudo o que deseja, como responder a 1, verifique o clima, 2 verificando as violações, etc ...
O exposto acima é todo o conteúdo deste artigo. Espero que seja útil para o aprendizado de todos e espero que todos apoiem mais o wulin.com.