나는 얼마 전에 바빴다. WeChat 공식 계정을 개발하고 문서를 처음부터 읽었습니다. 나는 많은 함정을 밟았다. 나는 그것을 겪었다. 나는 최근에 나중에 개발할 때 검토 할 수 있도록 요약을 고려했습니다. 또한 관련 프로젝트 작업을하는 학생들에게도 참조 할 것입니다.
1. 아이디어
WECHAT 액세스 : 개발자가 요구하는 사용자 메시지 및 이벤트 푸시는 WeChat 서버를 통해 요청을 시작하고 공개 플랫폼에서 구성한 서버 URL 주소로 전달됩니다. WeChat 서버는 시그니처, 타임 스탬프, Nonce 및 Echostr의 네 가지 매개 변수를 가져옵니다. 당사의 서버는 공개 플랫폼으로 구성된 토큰과 업로드 된 타임 스탬프로 구성되며 NONCE는 SHA1에서 암호화되어 서명과 일치합니다. 액세스가 성공했음을 나타 내기 위해 ture를 반환하십시오.
메시지 답장 : 사용자가 공식 계정으로 메시지를 보내면 WeChat 서버는 게시물을 통해 XML 형식으로 구성한 서버의 해당 인터페이스에 사용자 메시지를 요청합니다. 우리가해야 할 일은 메시지 유형 등을 기반으로 해당 논리적 처리를 수행하고 최종 반환 결과를 XML 형식을 통해 WeChat 서버에 반환하는 것입니다. WeChat 당사자는이를 사용자에게 전달합니다.
1. 공개 플랫폼 구성
2. 콘트롤러
@controller @requestMapping ( "/wechat") publicclass wechatcontroller {@Value ( "$ {dnbx_token}") private String dnbx_token; 개인 정적 최종 로거 로거 = 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 (httpervletRequest 요청, httppletRonsponse 응답 및 exmethement and the the the the the the the the the the the the the the the the the reathmence UTF-8에 대한 응답 (중국어 방지) 요청 .SetchAracterEncoding ( "UTF-8"); // WeChat 서버는 게시물 메시지 시점에서 UTF-8 인코딩을 사용하며 수신 할 때 동일한 인코딩을 사용해야합니다. 응답 .SetchAracterEncoding ( "UTF-8"); // 메시지에 응답 할 때 (사용자에게 응답) 인코딩 메소드도 UTF-8로 설정되며 원리는 위와 동일합니다. boolean isget = request.getMethod (). tolowercase (). equals ( "get"); printwriter out = response.getwriter (); try {if (isget) {string signature = request.getParameter ( "signature"); // wechat 암호화 서명 string timestamp = request.getParameter ( "timestamp"); // timestamp string nonce = request.getParameter ( "nonce"); // random number string echostr = requestparameter (// cheport "); 서명. 확인이 성공하면 Echostr을 그대로 반환하여 액세스가 성공했음을 나타냅니다. 그렇지 않으면 (signutil.checksignature (dnbx_token, signature, timestamp, nonce)) {logger.info ( "weixin 서버 연결이 성공적입니다") if에 액세스가 실패합니다. response.getWriter (). 쓰기 (echostr); } else {logger.error ( "서명을 확인하지 못했습니다!"); }} else {string respmessage = "예외 메시지!"; try {respmessage = wechatservice.weixinpost (요청); out.write (respmessage); logger.info ( "요청이 성공적으로 완료되었습니다"); logger.info ( "to weixin server"+respmessage); } catch (예외 e) {logger.error ( "Weixin에서 메시지를 변환하지 못했습니다!"); }}} catch (예외 e) {logger.error ( "Weixin 서버 연결은 오류입니다."); } 마침내 {out.close (); }}}3. 서명 확인 검사 신계
위의 컨트롤러에서, 우리는 도구 클래스 서명을 캡슐화하고, 검사 지정이라고 불리며, dnbx_token, signature, timestamp, nonce의 네 가지 값으로 전달되는 것을 알 수 있습니다. 이 과정은 매우 중요합니다. 실제로, 우리는 그것을 WeChat이 전송 한 값의 암호화 및 암호 해독 공정으로 이해할 수 있습니다. 보안을 보장하기 위해 많은 대형 프로젝트의 모든 인터페이스에는 이러한 검증 프로세스가 있습니다. DNBX_TOKEN 우리는 WeChat 공개 플랫폼에서 토큰 문자열을 구성했습니다. 아이디어를 기밀로 유지하십시오! 다른 세 가지는 get 요청을 보내기 위해 WeChat 서버에서 보낸 매개 변수입니다. SHA1 암호화 층을 수행합니다.
공개 클래스 서명 { / *** verification signature* @param token wechat 서버 토큰, Env.Properties 파일에서 구성되고 개발자 센터에서 구성된 구성이 일관성이 있어야합니다* @param 서명 WeChat 서버는 SHA1 암호화 인증서 서명* @param timestamp* @Param random Number* / proval boolean boolean boolean boolean boolean boolean boolean boolans random nonge를 보냅니다. 토큰, 문자열 서명, 문자열 타임 스탬프, 문자열 nonce) {string [] arr = new String [] {Token, timestamp, nonce}; // 토큰, 타임 스탬프 및 Nonce의 사전 순서 정렬; // 세 매개 변수 문자열을 SHA1 암호화 문자열로 스 플라이싱합니다. 문자열 tmpstr = sha1.encode (arr [0] + arr [1] + arr [2]); // 암호화 된 문자열 SHA1은 서명과 비교할 수 있으며, 요청이 weChat return tmpstr! = null에서 나온 것을 식별합니다. tmpstr.equals (signature.touppercase ()) : false; }} Sha1 :
/** * WeChat Public Platform (Java) SDK * * SHA1 알고리즘 * @Author Helijun 2016/06/15 19:49 */public final class sha1 {private static final char [] hex_digits = { '0', '1', '2', '3', '4', '5', '', '8', ',', ',', ',', ',', ',', ',' ' 'b', 'c', 'd', 'e', 'f'}; /***는 다이제스트에서 원시 바이트를 가져 와서 정확하게 형식화합니다. * * @param은 다이제스트에서 원시 바이트를 바이트합니다. * @형식의 바이트를 return. */ 개인 정적 문자열 getFormattedText (byte [] bytes) {int len = bytes.length; StringBuilder buf = New StringBuilder (len * 2); // ciphertext를 (int j = 0; j <len; j ++)에 대한 16 진수 문자열 양식으로 변환합니다 (buf.append [(bytes [j] >> 4) & 0x0f]); buf.append (hex_digits [bytes [j] & 0x0f]); } return buf.toString (); } public static string encode (string str) {if (str == null) {return null; } try {MessageDigest MessageDigest = MessageDigest.getInstance ( "SHA1"); MessageDigest.update (str.getBytes ()); let } catch (예외 e) {throw new runtimeexception (e); }}}공개 플랫폼에 제출하고 저장하고 녹색 프롬프트 "액세스 성공"을 보면 WeChat 액세스 완료를 축하합니다. 이 프로세스는 조금 더주의를 기울여야하며 암호화 알고리즘의 사례에주의를 기울입니다. 액세스가 성공하지 못한 경우 대부분의 경우 암호화 알고리즘에 문제가있는 경우 더 확인하십시오.
4. 자동 메시지 응답 서비스를 구현하십시오
/ ** * WeChat의 프로세스 요청 * * @param request * @return */ public String weixinpost (httpservletrequest request) {String respmessage = null; try {// xml 요청 구문 분석지도 <string, string> requestmap = messageUtil.xmltomap (request); // sender ac // 공개 계정 문자열 touserName = requestMap.get ( "touserName"); // 메시지 유형 문자열 msgtype = requestMap.get ( "msgtype"); // 메시지 내용 문자열 content = requestMap.get ( "content"); logger.info ( "Fromusername Is :" + Fromusername + ", Tousername은 다음과 같습니다." + tousername + ", msgtype는 다음과 같습니다." + msgtype); // 문자 메시지 if (msgtype.equals (messagutil.req_message_type_text)) {// 키워드에 따라 해당 논리를 실행하고 생각할 수없는 것만이 있으며 (content.equals ( "xxx"))와 같은 일이 없습니다. text.setContent ( "텍스트는" + 내용); text.settousername (fromusername); text.setfromusername (tousername); text.setCreateTime (new date (). gettime () + ""); text.setmsgtype (msgtype); respmessage = messageutil.textmessagetoxml (텍스트); }/*else if (msgtype.equals (messagutil.req_message_type_event)) {// 이벤트 푸시 문자열 eventType = requestMap.get ( "event"); // event type if (eventType.equals (messageUtil.event_type_subscribe)) MessagerPonse.getTextMessage를 반환합니다 (FromuserName, TouserName, RespContent); } else if (eventType.equals (messageUtil.event_Type_click)) {// 사용자 정의 메뉴 클릭 이벤트 문자열 eventKey = requestMap.get ( "eventKey"); // 이벤트 키 값, 지정된 키 값에 해당합니다. XXX를 반환합니다. }} // WECHAT 사운드 인식 테스트 2015-3-30 else if (msgtype.equals ( "Voice")) {String recVmessage = requestMap.get ( "enlock"); // respcontent = "음성 분석 결과 :"+recvmessage; if (recvmessage! = null) {respcontent = tulingapiprocess.getTulingResult (recvmessage); } else {respcontent = "당신이 말한 것은 너무 모호합니다. 다시 말할 수 있습니까?"; } return messagerPonse.getTextMessage (fromUserName, tousername, respcontent); } // 사진 함수 else if (msgtype.equals ( "pic_sysphoto")) {} else {return MessagerEsponse.getTextMessage (fromUsername, tousername, "return to empty"); }*/ // event push if (msgtype.equals (messagutil.req_message_type_event)) {string eventtype = requestMap.get ( "event"); // event type // if (eventType.equals (messagutil.event_type_subscribe))) {new TextMessage (new TextMessage ()); text.setContent ( "xxx를 오신 것을 환영합니다"); text.settousername (fromusername); text.setfromusername (tousername); text.setCreateTime (new date (). gettime () + ""); text.setmsgtype (messageutil.resp_message_type_text); respmessage = messageutil.textmessagetoxml (텍스트); } // 구독 후 TODO, 사용자는 공식 계정에서 보낸 메시지를받을 수 없으므로 다른 If (eventType.equals (emperatil.event_type_unsubscribe)) {// UnsubScribe} // 사용자 정의 메뉴 if (eventType.equals_type_click))에 메시지에 응답 할 필요가 없습니다. requestMap.get ( "EventKey"); // event 키 값은 사용자 정의 메뉴를 만들 때 지정된 키 값에 해당합니다. text.setContent ( "0755-86671980"); text.settousername (fromusername); text.setfromusername (tousername); text.setCreateTime (new date (). gettime () + ""); text.setmsgtype (messageutil.resp_message_type_text); respmessage = messageutil.textmessagetoxml (텍스트); }}}} catch (예외 e) {logger.error ( "error ...")} return respmessage; }코드는 위와 같이 게시됩니다. 그들 대부분은 의견이 있습니다. 기본 의미를 한 번 읽으면 설명 할 필요가 없습니다.
특별한주의가 필요한 곳이 있습니다.
붉은 색의 붉은 색과 tousername은 정확히 반대이며, 이는 또한 함정 중 하나입니다. 나는 오랫동안 그것을 조정했음을 기억하지만 문제는 아니었지만 작동하지 않았습니다. 마침내이 두 가지를 변경 한 후 메시지를 받았습니다! 사실, 그것에 대해 생각하는 것이 옳습니다. WeChat 서버로 돌아 오면 역할이 변경되므로 발신자와 수신자는 반대입니다.
5. MessageUtil
공개 클래스 MessageUtil { / *** 반환 메시지 유형 : 텍스트* / public static final String resp_message_type_text = "text"; / *** 반환 메시지 유형 : 음악*/ public static final String resp_message_type_music = "music"; / *** 반환 메시지 유형 : 그래픽 텍스트*/ 공개 정적 최종 문자열 resp_message_type_news = "News"; / *** 요청 메시지 유형 : 텍스트*/ public static final String req_message_type_text = "text"; / *** 요청 메시지 유형 : image*/ public static final String req_message_type_image = "image"; / *** 요청 메시지 유형 : 링크*/ public static final String req_message_type_link = "link"; / *** 요청 메시지 유형 : 지리적 위치*/ public static final String req_message_type_location = "location"; / *** 요청 메시지 유형 : 오디오*/ 공개 정적 최종 문자열 req_message_type_voice = "음성"; / ** * 요청 메시지 유형 : 푸시 */ public static final String req_message_type_event = "event"; / ** * 이벤트 유형 : 구독 (구독) */ public static final String event_type_subscribe = "구독"; / ** * 이벤트 유형 : Unbscribe (구독 취소) */ public static final String event_type_unsubscribe = "구독"; / ** * 이벤트 유형 : 클릭 (사용자 정의 메뉴 클릭 이벤트) */ public static final String event_type_click = "클릭"; }여기서 프로그램 가독성과 확장 성을 더 좋게 만들기 위해 일부 캡슐화를 만들고 여러 상수를 정의했으며 WeChat에서 Java Bean 영구 물체로 전달 된 일부 매개 변수를 캡슐화했습니다. 핵심 코드는 위와 같습니다. XML과 MAP의 변환에 중점을 둡니다
실제로,이 문제는 XML 통신을 사용하는 WeChat에 기인하며, 우리는 일반적으로 JSON을 사용하므로 짧은 시간 내에 약간 불편할 수 있습니다.
1. 항아리 패키지를 소개하십시오
<!-구문 분석 XML-> <pectionency> <groupId> dom4j </groupid> <artifactid> dom4j </artifactid> <버전> 1.6.1 </version> </dependency> <prectionency> <groupId> com.thoughtsworks.xstream </groupid> <artifactid> xstream </artifactid> 1.9 </version> 1.9 </version> 1.9 <
2.XML, 맵핑 객체를 맵핑합니다
/ ** * xml to map * @param request * @return * @throws ioexception */ @suppresswarnings ( "선택 취소") public static map <string, string> xmltomap (httpservletrequest 요청)은 ioexception {map <string, string> map = new hashmap <string> (); SaxReader Reader = New SaxReader (); 입력 스트림 ins = null; try {ins = request.getInputStream (); } catch (ioexception e1) {e1.printstacktrace (); } 문서 doc = null; try {doc = reader.read (ins); 요소 root = doc.getRootElement (); List <ELTECT> list = root.Elements (); for (요소 e : list) {map.put (e.getName (), e.getText ()); } 리턴 맵; } catch (DocumentException e1) {e1.printstacktrace (); } 마침내 {ins.close (); } return null; } 3. 문자 메시지 객체를 XML로 변환합니다
/ ** * 문자 메시지 객체를 XML로 변환 * * @Param TextMessage 문자 메시지 객체 * @return xml */ public static string textMessagetOxml (TextMessage TextMessage) {xstream xstream = new xstream (); xstream.alias ( "xml", textMessage.getClass ()); xstream.toxml을 반환합니다 (TextMessage); } 지금까지 작업이 완료되었습니다. 현재 공식 계정에서 "테스트"를 보낼 수 있습니다. 당신은 "텍스트는 테스트입니다"라고 wechat 답장을 받게됩니다. 이것은 또한 위 코드에서 이루어진 응답 프로세스입니다. 물론, 당신은 또한 당신의 상상력을 사용하여 날씨 확인, 2 위반 점검 등으로 답장하는 등 당신이하고 싶은 모든 일을 할 수 있습니다 ....
위는이 기사의 모든 내용입니다. 모든 사람의 학습에 도움이되기를 바랍니다. 모든 사람이 wulin.com을 더 지원하기를 바랍니다.