나는 한동안 프론트 엔드 시간으로 바빴다. 나는 문서를 처음부터 읽었고 많은 함정을 밟았습니다. 나는 최근에 그것을 겪었다. 나는 그것을 개발할 때 앞으로 그것을 검토 할 수 있도록 약간의 요약을 고려했습니다. 또한 관련 프로젝트 작업을하는 학생들에게도 참조 할 것입니다.
사실, 한 번 수행 한 후에는 어렵지 않다는 것을 알게 될 것입니다. 일반적인 아이디어는 다음과 같습니다. 개발자가 요구하는 사용자 메시지 및 이벤트 푸시는 WeChat 서버를 통해 요청을 시작하여 공개 플랫폼에서 구성한 서버 URL 주소로 전달합니다. WeChat 서버는 서명, 타임 스탬프, Nonce 및 Echostr의 네 가지 매개 변수를 가져옵니다. 당사의 서버는 공개 플랫폼과 타임 스탬프 업로드로 구성된 토큰을 스플 라이스합니다. Nonce는 SHA1에서 암호화되어 서명과 일치합니다. 액세스가 성공했음을 나타 내기 위해 ture를 반환하십시오.
1. 공개 플랫폼 구성
2. 콘트롤러
@controller@requestMapping ( "/wechat") publicclass wechatcontroller {@Value ( "$ {dnbx_token}") private String dnbx_token; private static final logger = loggeractory.getLogger (wechatcontroller.class); @percewechatservice wechatservice; @return * @Throws ioException */ @requestMapping (value = "/connect", method = {requestMethod.get, requestMethod.post}) @responseboblicVoid ConnectWeixin (httpservletRequest 요청, httpservletResponse 응답) IoException을 던지려고합니다. request.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 ( "seventature"); // wechat 암호화 서명 string timestamp = request.getParameter ( "timestamp"); // timestamp string nonce = request.getParameter ( "nonce"); // random number echost = request.getParameter ( "echostr"); // random string // 서명을 확인하여 요청을 확인하십시오. 확인이 성공하면 Echostr을 그대로 반환하여 액세스가 성공했음을 나타냅니다. 그렇지 않으면 (signutil.checksignature (dnbx_token, signature, timestamp, nonce)) {logger.info ( "weixin 서버 연결이 성공적입니다") if에 액세스가 실패합니다. response.getWriter (). 쓰기 (echostr); } else {logger.error ( "서명을 확인하지 못했습니다!"); }} else {string respmessage = "Exception Message!"; try {respmessage = wechatservice.weixinpost (request); out.write (respmessage); logger.info ( "요청은 성공적으로 완료된 요청"); logger.info ( "weixin 서버로"+respmessage (예외) {e) { "전환 ("메시지로 전환) { " 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', '7', ',', ',', ',', ',', ',', '9' '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 request parsing map <string, string> requestmap = messageutil.xmltomap (request); // sender ac requestMap.get ( "fromUserName"); // public 계정 문자열 touserName = requestMap.get ( "touserName"); // 메시지 유형 문자열 msgtype = requestMap.get ( "msgType"); // 메시지 content content = requestMap.get ( "content"); logger.info ( "fromUsername is :" + fromusername + " ", msgtype는" + msgtype); // 문자 메시지 if (msgtype.equals (messgtype.equals (messagutil.req_message_type_text)) {// 해당 논리가 키워드에 따라 실행됩니다. 상상할 수없는 사람은 하나뿐입니다. if (content.equals ( "xxx")) {} // 자동 답장 textmessage text = new TextMessage (); text.setContent ( "텍스트는" + content); text.setTounsername (fromusername); text.setfromusername (tousername); textrateMeTime (new Date (). ""); text.setmsgtype (msgtype); respmessage = messageutil.textmessagetoxml (text);}/*else if (msgtype.equals (messgtype.req_message_type_event)) {// event push eventtype = requestmap.get ( "이벤트"); (eventType.equals (messageutil.event_type_subscribe)) {// respcontent를 구독합니다 = "xxx 공식 계정을 따라 오신 것을 환영합니다!" eventKey = requestMap.get ( "eventKey"); // 이벤트 키 값, 사용자 정의 메뉴 로거를 만들 때 지정된 키 값에 해당하는 이벤트 키 값 ( "eventKey는" +eventKey); return xxx;}} // weChat 사운드 인식 테스트를 켜십시오 (msgtype.Aftionals) {string recvmessage = " requestMap.get ( "인식"); // respContent = "음성 분석 결과 :"+recvmessage; if (recvmessage! = null) {respcontent = tulingapiprocess.getTulingResult (recvmessage);} else {respcontent = "당신이 말한 것은 너무 모호합니다. 다시 말할 수 있습니까?" } // 사진 함수 else if (msgtype.equals ( "pic_sysphoto")) {} else {return MessagerEsponse.getTextMessage (fromUsername, tousername, "return empty"); }*// event push if (msgtype.equals (messageutil.req_message_type_event)) {String eventType = requestMap.get ( "event"); // event type // if (eventType.equals (messageUtil.event_type_subscribe)) {new TextMessage (new TextMessage (well textcege); 다음, xxx "); text.setTouserName (fromUserName); text.setfromusername (tousername); text.setCreateTime (new date (). gettime () +" "); text.setmsgtype (messageutil.resp_message_type_text); respmessageTmsml (textmestms); 비문화, 사용자는 공식 계정에서 보낸 메시지를받을 수 없으므로 다른 메시지에 회신 할 필요가 없습니다. if (eventType.equals (ementUtil.event_Type_UnsubScribe)) {// unsubScribe} // 사용자 정의 메뉴 클릭 이벤트 else (eventType.equals (messingUtil.event_type_click))) {string eventkey = (recondkey = reguesky =); if (eventkey.equals ( "customer_telephone"))) {textMessage text = new TextMessage (); text.setContent ( "0755-86671980"); Text.SetTouserName (fromUserName (wromusername); text.SetCromUserName (toustCreatEname); 날짜 (). gettime () + ""); text.setmsgtype (messageutil.resp_message_type_text); respmessage = messageUtil.textMessagetOxml (text);}}}} catch (예외 e) {logger.error ( "error ...")}}}}}}.코드는 위와 같이 게시됩니다. 그들 대부분은 의견이 있습니다. 기본 의미를 한 번 읽으면 설명 할 필요가 없습니다.
간단한 아이디어 : 사용자가 공식 계정으로 메시지를 보낼 때 WeChat 서버는 XML 형식으로 구성한 서버의 해당 인터페이스에 게시물을 통해 사용자 메시지를 요청합니다. 우리가해야 할 일은 메시지 유형 등을 기준으로 해당 논리적 처리를 수행하고 최종 리턴 결과를 XML 형식을 통해 WeChat 서버에 반환 한 다음 사용자에게 전달하는 것입니다.
특별한주의가 필요한 곳이 있습니다.
붉은 색의 붉은 색과 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. 항아리 패키지를 소개하십시오
<!-Parse XML-> <pectionency> <groupId> dom4j </groupid> <artifactid> dom4j </artifactid> <버전> 1.6.1 </version> </dependency> <prectionency> <groupid> com.thoughtsworks.xstream </groupid> <artifactid> xStream </arepifactid> 1.9 </version> 1.9 </version> 1.9
2.XML, 맵핑 객체를 맵핑합니다
/*** xml map으로 변환* @param request* @return* @throws ioexception*/ @suppresswarnings ( "선택 취소") public static map <string, string, string> xmltomap (httpservletrequest 요청) Ioexception {map <string, string> map = new Hashmap <string> (); Saxreader Reader = incaxreder (); null; thry {ins = request.getInputStream ();} catch (ioexception e1) {e1.printstacktrace ();} doc = null; try {doc = reader.read (ins); element root = doc.getRootElement (); list <elect> list = root.lements (); e.getText ());} return map;} 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 ();위의 것은 SpringMVC WeChat 액세스를 구현하고 간단한 자동 응답 기능을 구현하기 위해 Java에 대한 편집자의 소개입니다. 모든 사람에게 도움이되기를 바랍니다. 궁금한 점이 있으면 메시지를 남겨 주시면 편집자가 제 시간에 모든 사람에게 답장을 드리겠습니다. Wulin.com 웹 사이트를 지원해 주셔서 대단히 감사합니다!