網(wǎng)上有很多關(guān)于微信群pos機信息登記二維碼,如何生成關(guān)注公眾號自定義二維碼及監聽(tīng)掃碼事件的知識,也有很多人為大家解答關(guān)于微信群pos機信息登記二維碼的問(wèn)題,今天pos機之家(m.xjcwpx.cn)為大家整理了關(guān)于這方面的知識,讓我們一起來(lái)看下吧!
本文目錄一覽:
微信群pos機信息登記二維碼
本人最近在做一個(gè)saas模式的產(chǎn)品開(kāi)發(fā),公眾號只有一個(gè),但服務(wù)的客戶(hù)有多種,在各客戶(hù)下又有各自的用戶(hù)?,F在有這么一個(gè)需求,當用戶(hù)掃描客戶(hù)提供的公眾號二維碼時(shí),會(huì )出現對應的客戶(hù)歡迎語(yǔ),并且顯示客戶(hù)的LOGO界面。前提是每個(gè)客戶(hù)的LOGO是不同的。是不是有點(diǎn)繞?講明白點(diǎn),就如你一個(gè)公眾號,要被多個(gè)商家使用,每個(gè)商家都有自己的用戶(hù)群,那用戶(hù)在掃碼關(guān)注公眾號,進(jìn)入公眾號需要顯示每個(gè)商家自己的獨特LOGO。
正常的關(guān)注公眾號二維碼圖片是可以去公眾號開(kāi)發(fā)者后臺下載。但這是統一的二維碼,無(wú)法區分商家。這個(gè)時(shí)候,我們就需要自己去生成公眾號的關(guān)注二維碼。這個(gè)二維碼跟網(wǎng)上自動(dòng)生成的功能不一樣。畢竟你掃碼后,還得跟第三方的騰訊連接。
一、JAVA編輯生成二維碼接口
參數微信公眾平臺接口https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1443433542
我們生成一個(gè)永久帶字符串的二維碼,我們只需要傳一個(gè)商家的ID,就能識別用戶(hù)關(guān)注時(shí),是掃了哪一個(gè)二維碼,從而顯示對應的商家LOGO
Controller層
@ApiOperation(value = "創(chuàng )建公眾號二維碼")@ResponseBodypublic Result createQRCode( @ApiParam(name = "type", value = "類(lèi)型(1:臨時(shí)二維碼;2:永久參數為數字的二維碼;3:永久參數為字符串的二維碼)") @RequestParam() Integer type, @ApiParam(name = "validTime", value = "臨時(shí)二維碼的有效時(shí)間(秒,最高2592000秒(30天))") @RequestParam(required = false) Integer validTime, @ApiParam(name = "IntParameter", value = "數字參數") @RequestParam(required = false) Integer IntParameter, @ApiParam(name = "strParameter", value = "字符串參數") @RequestParam(required = false) String strParameter, HttpServletRequest request){ return wechatPushService.createQRCode(type,validTime,IntParameter,strParameter, this.getUserId(request));}
業(yè)務(wù)邏輯層
//獲取公眾號二維碼private final static String GET_PERPETUAL_QRCODE_URL = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=ACCESS_TOKEN";//獲取TICKET對應的二維碼圖private final static String GET_TICKET_QRCODE_URL = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=";public Result createQRCode(Integer type, Integer validTime, Integer IntParameter, String strParameter,String userId) { String accessToken = weChatPushService.getGzhAccessTokenDefaultCfg();//獲取公眾號Token String requestUrl = GET_PERPETUAL_QRCODE_URL.replace("ACCESS_TOKEN", accessToken);//替換URL的參數 jsonObject json = new JSONObject(); JSONObject actionInfoJson = new JSONObject(); JSONObject sceneJson = new JSONObject(); String fileName = "/sys/QRCode/"+strParameter+".jpg";//圖片的下載路徑 if(type == 3){//生成永久帶字符串參數的二維碼 json.put("action_name","QR_LIMIT_STR_SCENE");//固定值 sceneJson.put("scene_str",strParameter);//strParameter是商家ID的參數,也是要跟二維碼一同生成的參數 actionInfoJson.put("scene",sceneJson); json.put("action_info",actionInfoJson);//{"action_name": "QR_LIMIT_STR_SCENE", "action_info": {"scene": {"scene_str": "test"}}} 調用公眾號接口的參數格式,json值 Map<String, Object> map = RequestUtils.json(requestUrl, json);//POST方法調用第三方公眾號接口 String ticket = map.containsKey("ticket")?map.get("ticket").toString():"";//從返回參數中獲取二維碼ticket值 if(org.apache.commons.lang.StringUtils.isNotEmpty(ticket)){//使用ticket的值再去調用另外一個(gè)接口,下載二維碼圖片 File file1 = new File(filePath+"sys/QRCode/");//自己要把圖片下載的路徑 if(!file1.exists()){//判斷文件路徑是否存在,不存在就創(chuàng )建 file1.mkdirs(); } downloadPicture(GET_TICKET_QRCODE_URL+ URLEncoder.encode(ticket),filePath+fileName);//下載圖片 } } return ResultUtil.success(fileName);}
/** * 獲取默認公眾號訪(fǎng)問(wèn)令牌 */public String getGzhAccessTokenDefaultCfg() { if (StringUtils.isEmpty(defaultGzhAppId) || StringUtils.isEmpty(defaultGzhSecret)) { initialize();//讀取配置文件里公眾號的值(appId和appSecret),這兩個(gè)值在公眾號里有,公眾號的接口大多需要這兩個(gè)參數去獲取Token } return getGzhAccessToken(defaultGzhAppId,defaultGzhSecret);}
// 獲取企業(yè)號access_tokenprivate final static String company_access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=CORPID&secret=CORPSECRET";// 獲取開(kāi)放平臺的access_token、openid等認證信息private final static String GET_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";/** * 獲取微信公眾號訪(fǎng)問(wèn)令牌 * @param appId appId * @param appSecret appSecret */public String getGzhAccessToken(String appId, String appSecret) { String accessToken = ""; try { accessToken = redisService.getDataService("WX_AccessToken").getData().toString();//從Redis緩存中獲取Token, } catch (Exception e) { log.error("從緩存微信公眾號token失敗"); } if (StringUtils.isEmpty(accessToken)) {//如果緩存沒(méi)有Token,或過(guò)期了,將重新去獲取一次 String requestUrl = company_access_token_url.replace("CORPID", appId).replace("CORPSECRET", appSecret);//替換參數 Map<String, Object> map = RequestUtils.json(requestUrl, null);//POST接口調用第三方接口 // 如果請求成功 if (null != map) { System.out.print("###############################" + map.toString()); try { accessToken = (String) map.get("access_token"); redisService.strAdd("WX_AccessToken", accessToken, 700);// (存到緩存中,避免經(jīng)常去拿token,將近兩小時(shí)) } catch (Exception e) { log.error("獲取微信公眾號token失敗,或token保存至緩存失敗 ####accessToken" + accessToken); } } } return accessToken;}
POST和GET請求工具類(lèi),在獲取圖片時(shí),需要使用GET
import org.springframework.http.MediaType;import java.io.*;import java.net.HttpURLConnection;import java.net.URL;import java.net.URLConnection;import java.util.Map;/** * 工具類(lèi) */public class RequestUtils { @SuppressWarnings("unchecked") public static Map<String, Object> json(String url, Map<String, Object> params){ String content = null; if(params != null){ content = JsonUtils.convert(params); } String result = post(url, content, MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON); if(result != null){ return JsonUtils.convert(result, Map.class); } return null; } public static void main(String[] args) { String post = post("http://www.baidu.com", "", MediaType.APPLICATION_JSON); System.out.println(post); } public static String post(String strURL, String content) { return post(strURL, content, null); } public static String post(String strURL, String content, MediaType mediaType) { return post(strURL, content, mediaType, mediaType); } public static String post(String strURL, String content, MediaType sendMediaType, MediaType receiveMediaType) { try { URL url = new URL(strURL);// 創(chuàng )建連接 HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setDoOutput(content != null); connection.setDoInput(true); connection.setUseCaches(false); connection.setInstanceFollowRedirects(true); connection.setRequestMethod("POST"); // 設置請求方式 if(sendMediaType != null) { connection.setRequestProperty("Accept", receiveMediaType.toString()); // 設置接收數據的格式 } if(sendMediaType != null) { connection.setRequestProperty("Content-Type", sendMediaType.toString()); // 設置發(fā)送數據的格式 } connection.connect(); if(content != null) { OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream(), "UTF-8"); // utf-8編碼 out.write(content); out.flush(); out.close(); } int code = connection.getResponseCode(); System.out.println(code); InputStream is = connection.getInputStream(); if (is == null) { is = connection.getErrorStream(); } // 讀取響應 int length = (int) connection.getContentLength();// 獲取長(cháng)度 if (length != -1) { byte[] data = new byte[length]; byte[] temp = new byte[1024]; int readLen = 0; int destPos = 0; while ((readLen = is.read(temp)) > 0) { System.arraycopy(temp, 0, data, destPos, readLen); destPos += readLen; } String result = new String(data, "UTF-8"); // utf-8編碼 return result; } } catch (IOException e) { e.printStackTrace(); } return null; // 自定義錯誤信息 } public static String get(String url) { BufferedReader in = null; try { URL realUrl = new URL(url); // 打開(kāi)和URL之間的連接 URLConnection connection = realUrl.openConnection(); // 設置通用的請求屬性 connection.setRequestProperty("accept", "*/*"); connection.setRequestProperty("connection", "Keep-Alive"); connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); connection.setConnectTimeout(5000); connection.setReadTimeout(5000); // 建立實(shí)際的連接 connection.connect(); // 定義 BufferedReader輸入流來(lái)讀取URL的響應 in = new BufferedReader(new InputStreamReader(connection.getInputStream())); StringBuffer sb = new StringBuffer(); String line; while ((line = in.readLine()) != null) { sb.append(line); } return sb.toString(); } catch (Exception e) { e.printStackTrace(); }finally { try { if (in != null) { in.close(); } } catch (Exception e2) { e2.printStackTrace(); } } return null; }}
接口寫(xiě)完后,你可以單元測試調用一下,生成的二維碼就可以?huà)咭幌?,是不是?huì )跳到你對應的公眾號界面。自定義二維碼已經(jīng)生成了,但現在跟普通的二維碼沒(méi)區別,因為沒(méi)有觸發(fā)事件。接下來(lái),編寫(xiě)一個(gè)能讓公眾號調用你的方法的接口。讓公眾號告訴你,有人關(guān)注或取消關(guān)注。
二、事件觸發(fā)接口
controller層
//微信推送事件 url@RequestMapping("/openwx/getticket")public void getTicketMessage(HttpServletRequest request, HttpServletResponse response) throws Exception { wechatPushService.getTicketMessage(request,response);}
事件觸發(fā)邏輯層,看下面代碼時(shí),先看官方的文檔,這樣更能理解返回參數:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140543
public String getTicketMessage(HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("1.收到微信服務(wù)器消息"); Map<String, String> wxdata=parseXml(request); if(null != wxdata){ String key = wxdata.get("FromUserName")+ "__" + wxdata.get("ToUserName")+ "__" + wxdata.get("MsgId") + "__" + wxdata.get("CreateTime"); Result keyRedisResult = redisService.getDataService(key); System.out.println(keyRedisResult.getStatus()); if(keyRedisResult.getStatus() == 200){//防止公眾重復推送消息,所以第一次把消息送緩存中,如果存在了就不處理 return null; } redisService.strAdd(key,"1",3600);//不存在的話(huà),放緩存里,記得加一個(gè)失效時(shí)間,避免一直存在,占用資源 String Event = wxdata.get("Event"); System.out.println("Event"+Event); if(Event.equals("subscribe") || Event.equals("SCAN")){//掃碼帶參數的二維碼進(jìn)入的 String EventKey = wxdata.get("EventKey");//獲取參數 String FromUserName = wxdata.get("FromUserName");//OpenID if(EventKey.indexOf("_") != -1){//初次關(guān)注 EventKey = EventKey.substring(EventKey.indexOf("_")+1); } System.out.println("EventKey:"+EventKey); Map map = (Map)result.getData(); TextMessage textMessage=new TextMessage(); textMessage.setToUserName(wxdata.get("FromUserName")); //這里的ToUserName 是剛才接收xml中的FromUserName textMessage.setFromUserName(wxdata.get("ToUserName")); //這里的FromUserName 是剛才接收xml中的ToUserName 這里一定要注意,否則會(huì )出錯 textMessage.setCreateTime(new Date().getTime()); textMessage.setMsgType("text"); textMessage.setContent("歡迎您關(guān)注"+map.get("departmentTopName")+"電子送達"); MessageUtil messageUtil = MessageUtil.getInstance(); String xml=messageUtil.textMessageToXml(textMessage); System.out.println("xml:"+xml); response.setCharacterEncoding("UTF-8"); PrintWriter out = response.getWriter(); out.print(xml);//用戶(hù)關(guān)注時(shí),發(fā)一個(gè)歡迎語(yǔ)給用戶(hù) out.close(); } } return null; }
三、觸發(fā)接口寫(xiě)完后,需要去公眾號后臺去設置你的接口服務(wù)器,讓公眾號知道你的接口地址。
修改配置,服務(wù)器地址為你部署的地址,必須對方能連上,而且需要80端口(如果80端口被占用,可以使用Nginx做轉發(fā)),在配置的時(shí)候,公眾號會(huì )嘗試調用,調用不到你的接口,會(huì )直接提醒你。
配置完后,點(diǎn)擊啟動(dòng)。這個(gè)時(shí)候你再去關(guān)注你剛才生成的參數二維碼,就會(huì )有反映了。記得在事件觸發(fā)接口中,增加你的業(yè)務(wù)。用戶(hù)關(guān)注或取消關(guān)注時(shí),你要做什么。
另外,在啟動(dòng)配置后,你會(huì )發(fā)現,你的公眾號自定義菜單不見(jiàn)了,這個(gè)時(shí)候不要慌。接下往下看。
啟動(dòng)菜單
這個(gè)時(shí)候公眾號上的小菜單就有了。但公眾號后臺自定義菜單還是看不到?那怎么修改菜單呢?
很簡(jiǎn)單,先把前面開(kāi)啟的服務(wù)器配置給停止了,然后再改你的菜單,修改完菜單后,你再開(kāi)始服務(wù)器。到此就完成了生成及事件監聽(tīng)的過(guò)程
以上就是關(guān)于微信群pos機信息登記二維碼,如何生成關(guān)注公眾號自定義二維碼及監聽(tīng)掃碼事件的知識,后面我們會(huì )繼續為大家整理關(guān)于微信群pos機信息登記二維碼的知識,希望能夠幫助到大家!
