欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JAVA實(shí)現(xiàn) springMVC方式的微信接入、實(shí)現(xiàn)消息自動(dòng)回復(fù)實(shí)例

 更新時(shí)間:2016年12月08日 15:59:39   作者:liliangel  
本篇文章主要介紹了JAVA實(shí)現(xiàn) springMVC方式的微信接入、實(shí)現(xiàn)消息自動(dòng)回復(fù),這里整理了詳細(xì)的代碼,有需要的小伙伴可以參考下。

前段時(shí)間小忙了一陣,微信公眾號(hào)的開發(fā),從零開始看文檔,踩了不少坑,也算是熬過(guò)來(lái)了,最近考慮做一些總結(jié),方便以后再開發(fā)的時(shí)候回顧,也給正在做相關(guān)項(xiàng)目的同學(xué)做個(gè)參考。

1.思路

微信接入:用戶消息和開發(fā)者需要的事件推送都會(huì)通過(guò)微信方服務(wù)器發(fā)起一個(gè)請(qǐng)求,轉(zhuǎn)發(fā)到你在公眾平臺(tái)配置的服務(wù)器url地址,微信方將帶上signature,timestamp,nonce,echostr四個(gè)參數(shù),我們自己服務(wù)器通過(guò)拼接公眾平臺(tái)配置的token,以及傳上來(lái)的timestamp,nonce進(jìn)行SHA1加密后匹配signature,返回ture說(shuō)明接入成功。

消息回復(fù):當(dāng)用戶給公眾號(hào)發(fā)送消息時(shí),微信服務(wù)器會(huì)將用戶消息以xml格式通過(guò)POST請(qǐng)求到我們配置好的服務(wù)器對(duì)應(yīng)的接口,而我們要做的事情就是根據(jù)消息類型等做相應(yīng)的邏輯處理,并將最后的返回結(jié)果也通過(guò)xml格式return給微信服務(wù)器,微信方再傳達(dá)給用戶的這樣一個(gè)過(guò)程。 

1.公眾平臺(tái)配置

2.Controller

@Controller
@RequestMapping("/wechat")
publicclass WechatController {
  @Value("${DNBX_TOKEN}")
  private String DNBX_TOKEN;
  
  private static final Logger LOGGER = LoggerFactory.getLogger(WechatController.class);
  
  @Resource
  WechatService wechatService;
  
  /**
   * 微信接入
   * @param wc
   * @return
   * @throws IOException 
   */
  @RequestMapping(value="/connect",method = {RequestMethod.GET, RequestMethod.POST})
  @ResponseBody
  publicvoid connectWeixin(HttpServletRequest request, HttpServletResponse response) throws IOException{
    // 將請(qǐng)求、響應(yīng)的編碼均設(shè)置為UTF-8(防止中文亂碼) 
    request.setCharacterEncoding("UTF-8"); //微信服務(wù)器POST消息時(shí)用的是UTF-8編碼,在接收時(shí)也要用同樣的編碼,否則中文會(huì)亂碼;
    response.setCharacterEncoding("UTF-8"); //在響應(yīng)消息(回復(fù)消息給用戶)時(shí),也將編碼方式設(shè)置為UTF-8,原理同上;boolean isGet = request.getMethod().toLowerCase().equals("get"); 
   
    PrintWriter out = response.getWriter();
     
    try {
      if (isGet) {
        String signature = request.getParameter("signature");// 微信加密簽名 
        String timestamp = request.getParameter("timestamp");// 時(shí)間戳 
        String nonce = request.getParameter("nonce");// 隨機(jī)數(shù) 
        String echostr = request.getParameter("echostr");//隨機(jī)字符串 
        
        // 通過(guò)檢驗(yàn)signature對(duì)請(qǐng)求進(jìn)行校驗(yàn),若校驗(yàn)成功則原樣返回echostr,表示接入成功,否則接入失敗 if (SignUtil.checkSignature(DNBX_TOKEN, signature, timestamp, nonce)) { 
          LOGGER.info("Connect the weixin server is successful.");
          response.getWriter().write(echostr); 
        } else { 
          LOGGER.error("Failed to verify the signature!"); 
        }
      }else{
        String respMessage = "異常消息!";
        
        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("Connect the weixin server is error.");
    }finally{
      out.close();
    }
  }
}

3.簽名驗(yàn)證 checkSignature

從上面的controller我們可以看到,我封裝了一個(gè)工具類SignUtil,調(diào)用了里面的一個(gè)叫checkSignature,傳入了四個(gè)值,DNBX_TOKEN, signature, timestamp, nonce。這個(gè)過(guò)程非常重要,其實(shí)我們可以理解為將微信傳過(guò)來(lái)的值進(jìn)行一個(gè)加解密的過(guò)程,很多大型的項(xiàng)目所有的接口為保證安全性都會(huì)有這樣一個(gè)驗(yàn)證的過(guò)程。DNBX_TOKEN我們?cè)谖⑿殴娖脚_(tái)配置的一個(gè)token字符串,主意保密哦!其他三個(gè)都是微信服務(wù)器發(fā)送get請(qǐng)求傳過(guò)來(lái)的參數(shù),我們進(jìn)行一層sha1加密:

public class SignUtil { 
 
  /** 
   * 驗(yàn)證簽名 
   * 
   * @param token 微信服務(wù)器token,在env.properties文件中配置的和在開發(fā)者中心配置的必須一致 
   * @param signature 微信服務(wù)器傳過(guò)來(lái)sha1加密的證書簽名
   * @param timestamp 時(shí)間戳
   * @param nonce 隨機(jī)數(shù) 
   * @return 
   */ 
  public static boolean checkSignature(String token,String signature, String timestamp, String nonce) { 
    String[] arr = new String[] { token, timestamp, nonce }; 
    // 將token、timestamp、nonce三個(gè)參數(shù)進(jìn)行字典序排序 
    Arrays.sort(arr); 
    
    // 將三個(gè)參數(shù)字符串拼接成一個(gè)字符串進(jìn)行sha1加密 
    String tmpStr = SHA1.encode(arr[0] + arr[1] + arr[2]); 
    
    // 將sha1加密后的字符串可與signature對(duì)比,標(biāo)識(shí)該請(qǐng)求來(lái)源于微信 
    return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false; 
  } 
  
}

SHA1:

/** 
 * 微信公眾平臺(tái)(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', 
              '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; 
 
  /** 
   * Takes the raw bytes from the digest and formats them correct. 
   * 
   * @param bytes the raw bytes from the digest. 
   * @return the formatted bytes. 
   */ 
  private static String getFormattedText(byte[] bytes) { 
    int len = bytes.length; 
    StringBuilder buf = new StringBuilder(len * 2); 
    // 把密文轉(zhuǎn)換成十六進(jìn)制的字符串形式 
    for (int j = 0; j < len; j++) { 
      buf.append(HEX_DIGITS[(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()); 
      return getFormattedText(messageDigest.digest()); 
    } catch (Exception e) { 
      throw new RuntimeException(e); 
    } 
  } 
}

當(dāng)你在公眾平臺(tái)提交保存,并且看到綠色的提示“接入成功”之后,恭喜你已經(jīng)完成微信接入。這個(gè)過(guò)程需要細(xì)心一點(diǎn),注意加密算法里的大小寫,如果接入不成功,大多數(shù)情況都是加密算法的問(wèn)題,多檢查檢查。

4. 實(shí)現(xiàn)消息自動(dòng)回復(fù)service

/**
   * 處理微信發(fā)來(lái)的請(qǐng)求
   * 
   * @param request
   * @return
   */
  public String weixinPost(HttpServletRequest request) {
    String respMessage = null;
    try {

      // xml請(qǐng)求解析
      Map<String, String> requestMap = MessageUtil.xmlToMap(request);

      // 發(fā)送方帳號(hào)(open_id)
      String fromUserName = requestMap.get("FromUserName");
      // 公眾帳號(hào)
      String toUserName = requestMap.get("ToUserName");
      // 消息類型
      String msgType = requestMap.get("MsgType");
      // 消息內(nèi)容
      String content = requestMap.get("Content");
      
      LOGGER.info("FromUserName is:" + fromUserName + ", ToUserName is:" + toUserName + ", MsgType is:" + msgType);

      // 文本消息
      if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) {
        //這里根據(jù)關(guān)鍵字執(zhí)行相應(yīng)的邏輯,只有你想不到的,沒(méi)有做不到的
        if(content.equals("xxx")){
          
        }
        
        //自動(dòng)回復(fù)
        TextMessage text = new TextMessage();
        text.setContent("the text is" + content);
        text.setToUserName(fromUserName);
        text.setFromUserName(toUserName);
        text.setCreateTime(new Date().getTime() + "");
        text.setMsgType(msgType);
        
        respMessage = MessageUtil.textMessageToXml(text);
        
      } /*else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)) {// 事件推送
        String eventType = requestMap.get("Event");// 事件類型
        
        if (eventType.equals(MessageUtil.EVENT_TYPE_SUBSCRIBE)) {// 訂閱
          respContent = "歡迎關(guān)注xxx公眾號(hào)!";
          return MessageResponse.getTextMessage(fromUserName , toUserName , respContent);
        } else if (eventType.equals(MessageUtil.EVENT_TYPE_CLICK)) {// 自定義菜單點(diǎn)擊事件
          String eventKey = requestMap.get("EventKey");// 事件KEY值,與創(chuàng)建自定義菜單時(shí)指定的KEY值對(duì)應(yīng)
          logger.info("eventKey is:" +eventKey);
          return xxx;
        }
      }
      //開啟微信聲音識(shí)別測(cè)試 2015-3-30
      else if(msgType.equals("voice"))
      {
        String recvMessage = requestMap.get("Recognition");
        //respContent = "收到的語(yǔ)音解析結(jié)果:"+recvMessage;
        if(recvMessage!=null){
          respContent = TulingApiProcess.getTulingResult(recvMessage);
        }else{
          respContent = "您說(shuō)的太模糊了,能不能重新說(shuō)下呢?";
        }
        return MessageResponse.getTextMessage(fromUserName , toUserName , respContent); 
      }
      //拍照功能
      else if(msgType.equals("pic_sysphoto"))
      {
        
      }
      else
      {
        return MessageResponse.getTextMessage(fromUserName , toUserName , "返回為空"); 
      }*/
      // 事件推送
      else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)) {
        String eventType = requestMap.get("Event");// 事件類型
        // 訂閱
        if (eventType.equals(MessageUtil.EVENT_TYPE_SUBSCRIBE)) {
          
          TextMessage text = new TextMessage();
          text.setContent("歡迎關(guān)注,xxx");
          text.setToUserName(fromUserName);
          text.setFromUserName(toUserName);
          text.setCreateTime(new Date().getTime() + "");
          text.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_TEXT);
          
          respMessage = MessageUtil.textMessageToXml(text);
        } 
        // TODO 取消訂閱后用戶再收不到公眾號(hào)發(fā)送的消息,因此不需要回復(fù)消息
        else if (eventType.equals(MessageUtil.EVENT_TYPE_UNSUBSCRIBE)) {// 取消訂閱
          
          
        } 
        // 自定義菜單點(diǎn)擊事件
        else if (eventType.equals(MessageUtil.EVENT_TYPE_CLICK)) {
          String eventKey = requestMap.get("EventKey");// 事件KEY值,與創(chuàng)建自定義菜單時(shí)指定的KEY值對(duì)應(yīng)
          if (eventKey.equals("customer_telephone")) {
            TextMessage text = new TextMessage();
            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(text);
          }
        }
      }
    }
    catch (Exception e) {
      Logger.error("error......")
    }
    return respMessage;
  }

先貼代碼如上,大多都有注釋,讀一遍基本語(yǔ)義也懂了不需要多解釋。

 有一個(gè)地方格外需要注意:

上面標(biāo)紅的fromUserName和toUserName剛好相反,這也是坑之一,還記得我當(dāng)時(shí)調(diào)了很久,明明都沒(méi)有問(wèn)題就是不通,最后把這兩個(gè)一換消息就收到了!其實(shí)回過(guò)頭想也對(duì),返回給微信服務(wù)器這時(shí)本身角色就變了,所以發(fā)送和接收方也肯定是相反的。

5.MessageUtil

public class MessageUtil {
  
  /** 
   * 返回消息類型:文本 
   */ 
  public static final String RESP_MESSAGE_TYPE_TEXT = "text"; 
 
  /** 
   * 返回消息類型:音樂(lè) 
   */ 
  public static final String RESP_MESSAGE_TYPE_MUSIC = "music"; 
 
  /** 
   * 返回消息類型:圖文 
   */ 
  public static final String RESP_MESSAGE_TYPE_NEWS = "news"; 
 
  /** 
   * 請(qǐng)求消息類型:文本 
   */ 
  public static final String REQ_MESSAGE_TYPE_TEXT = "text"; 
 
  /** 
   * 請(qǐng)求消息類型:圖片 
   */ 
  public static final String REQ_MESSAGE_TYPE_IMAGE = "image"; 
 
  /** 
   * 請(qǐng)求消息類型:鏈接 
   */ 
  public static final String REQ_MESSAGE_TYPE_LINK = "link"; 
 
  /** 
   * 請(qǐng)求消息類型:地理位置 
   */ 
  public static final String REQ_MESSAGE_TYPE_LOCATION = "location"; 
 
  /** 
   * 請(qǐng)求消息類型:音頻 
   */ 
  public static final String REQ_MESSAGE_TYPE_VOICE = "voice"; 
 
  /** 
   * 請(qǐng)求消息類型:推送 
   */ 
  public static final String REQ_MESSAGE_TYPE_EVENT = "event"; 
 
  /** 
   * 事件類型:subscribe(訂閱) 
   */ 
  public static final String EVENT_TYPE_SUBSCRIBE = "subscribe"; 
 
  /** 
   * 事件類型:unsubscribe(取消訂閱) 
   */ 
  public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe"; 
 
  /** 
   * 事件類型:CLICK(自定義菜單點(diǎn)擊事件) 
   */ 
  public static final String EVENT_TYPE_CLICK = "CLICK"; 
}

這里為了程序可讀性、擴(kuò)展性更好一點(diǎn),我做了一些封裝,定義了幾個(gè)常量,以及將微信傳過(guò)來(lái)的一些參數(shù)封裝成java bean持久化對(duì)象,核心代碼如上。重點(diǎn)講下xml和map之間的轉(zhuǎn)換

其實(shí)這個(gè)問(wèn)題要?dú)w咎于微信是用xml通訊,而我們平時(shí)一般是用json,所以可能短時(shí)間內(nèi)會(huì)有點(diǎn)不適應(yīng)

1.引入jar包

<!-- 解析xml -->
    <dependency>
      <groupId>dom4j</groupId>
      <artifactId>dom4j</artifactId>
      <version>1.6.1</version>
    </dependency>
    
    <dependency>
      <groupId>com.thoughtworks.xstream</groupId>
      <artifactId>xstream</artifactId>
      <version>1.4.9</version>
    </dependency>

2.xml轉(zhuǎn)map集合對(duì)象

/**
   * xml轉(zhuǎn)換為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;
    try {
      ins = request.getInputStream();
    } catch (IOException e1) {
      e1.printStackTrace();
    }
    Document doc = null;
    try {
      doc = reader.read(ins);
      Element root = doc.getRootElement();
      
      List<Element> list = root.elements();
      
      for (Element e : list) {
        map.put(e.getName(), e.getText());
      }
      
      return map;
    } catch (DocumentException e1) {
      e1.printStackTrace();
    }finally{
      ins.close();
    }
    
    return null;
  }

3.文本消息對(duì)象轉(zhuǎn)換成xml

/** 
   * 文本消息對(duì)象轉(zhuǎn)換成xml 
   * 
   * @param textMessage 文本消息對(duì)象 
   * @return xml 
   */ 
  public static String textMessageToXml(TextMessage textMessage){
    XStream xstream = new XStream();
    xstream.alias("xml", textMessage.getClass());
    return xstream.toXML(textMessage);
  }

到此為止已經(jīng)大功告成了,這個(gè)時(shí)候可以在公眾號(hào)里嘗試發(fā)送“測(cè)試”,你會(huì)收到微信回復(fù)的“the text is 測(cè)試”,這也是上面代碼里做的回復(fù)處理,當(dāng)然你也可以發(fā)揮你的想象用他做所有你想做的事了,比如回復(fù)1查天氣,2查違章等等....

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • springboot中thymeleaf模板使用詳解

    springboot中thymeleaf模板使用詳解

    這篇文章將更加全面詳細(xì)的介紹thymeleaf的使用。thymeleaf 是新一代的模板引擎,在spring4.0中推薦使用thymeleaf來(lái)做前端模版引擎。
    2017-05-05
  • 詳解在SpringBoot應(yīng)用中獲取應(yīng)用上下文方法

    詳解在SpringBoot應(yīng)用中獲取應(yīng)用上下文方法

    本篇文章主要介紹了詳解在SpringBoot應(yīng)用中獲取應(yīng)用上下文方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2017-04-04
  • Java的Spring?AOP詳細(xì)講解

    Java的Spring?AOP詳細(xì)講解

    章主要為大家詳細(xì)介紹了Java的Spring?AOP,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-02-02
  • Java生成二維碼可添加logo和文字功能

    Java生成二維碼可添加logo和文字功能

    這篇文章主要介紹了Java生成二維碼可添加logo和文字功能,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2017-02-02
  • Java實(shí)現(xiàn)自定義阻塞隊(duì)列

    Java實(shí)現(xiàn)自定義阻塞隊(duì)列

    這篇文章主要介紹了Java如何實(shí)現(xiàn)自定義阻塞隊(duì)列,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下
    2020-10-10
  • 在java中main函數(shù)如何調(diào)用外部非static方法

    在java中main函數(shù)如何調(diào)用外部非static方法

    這篇文章主要介紹了在java中main函數(shù)如何調(diào)用外部非static方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • Mybatis-plus獲取雪花算法生成的ID并返回生成ID

    Mybatis-plus獲取雪花算法生成的ID并返回生成ID

    本文主要介紹了Mybatis-plus獲取雪花算法生成的ID并返回生成ID,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-09-09
  • Java 編程中十個(gè)處理異常的建議

    Java 編程中十個(gè)處理異常的建議

    這篇文章主要介紹了Java 編程中十個(gè)處理異常的建議,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • springmvc九大組件之HandlerAdapter詳解

    springmvc九大組件之HandlerAdapter詳解

    這篇文章主要介紹了springmvc九大組件之HandlerAdapter詳解,RequestMappingHandlerAdapter支持的handler的類型是HandlerMethod,而HandlerMethod是通過(guò)解析@RequestMapping注解獲得的,需要的朋友可以參考下
    2023-11-11
  • Nacos作為配置中心注冊(cè)監(jiān)聽(tīng)器方法

    Nacos作為配置中心注冊(cè)監(jiān)聽(tīng)器方法

    本文主要討論Nacos作為配置中心時(shí),其中配置內(nèi)容發(fā)生更改時(shí),我們的應(yīng)用程序能夠做的事。一般使用監(jiān)聽(tīng)器來(lái)實(shí)現(xiàn)這步操作,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧
    2023-02-02

最新評(píng)論