<menu id="ycqsw"></menu><nav id="ycqsw"><code id="ycqsw"></code></nav>
<dd id="ycqsw"><menu id="ycqsw"></menu></dd>
  • <nav id="ycqsw"></nav>
    <menu id="ycqsw"><strong id="ycqsw"></strong></menu>
    <xmp id="ycqsw"><nav id="ycqsw"></nav>
  • 怎么制作自定義二維碼,分享免費創意二維碼生成器


    本人最近在做一個saas模式的產品開發,公眾號只有一個,但服務的客戶有多種,在各客戶下又有各自的用戶。現在有這么一個需求,當用戶掃描客戶提供的公眾號二維碼時,會出現對應的客戶歡迎語,并且顯示客戶的LOGO界面。前提是每個客戶的LOGO是不同的。是不是有點繞?講明白點,就如你一個公眾號,要被多個商家使用,每個商家都有自己的用戶群,那用戶在掃碼關注公眾號,進入公眾號需要顯示每個商家自己的獨特LOGO。

    正常的關注公眾號二維碼圖片是可以去公眾號開發者后臺下載。但這是統一的二維碼,無法區分商家。這個時候,我們就需要自己去生成公眾號的關注二維碼。這個二維碼跟網上自動生成的功能不一樣。畢竟你掃碼后,還得跟第三方的騰訊連接。

    一、JAVA編輯生成二維碼接口

    參數微信公眾平臺接口https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1443433542

    我們生成一個永久帶字符串的二維碼,我們只需要傳一個商家的ID,就能識別用戶關注時,是掃了哪一個二維碼,從而顯示對應的商家LOGO

    Controller層

    @ApiOperation(value = "創建公眾號二維碼")
    @ResponseBody
    public Result createQRCode(
    @ApiParam(name = "type", value = "類型(1:臨時二維碼;2:永久參數為數字的二維碼;3:永久參數為字符串的二維碼)") @RequestParam() Integer type,
    @ApiParam(name = "validTime", value = "臨時二維碼的有效時間(秒,最高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));
    }

    業務邏輯層

    //獲取公眾號二維碼
    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的值再去調用另外一個接口,下載二維碼圖片
    File file1 = new File(filePath+"sys/QRCode/");//自己要把圖片下載的路徑
    if(!file1.exists()){//判斷文件路徑是否存在,不存在就創建
    file1.mkdirs();
    }
    downloadPicture(GET_TICKET_QRCODE_URL+ URLEncoder.encode(ticket),filePath+fileName);//下載圖片
    }
    }
    return ResultUtil.success(fileName);
    }
    /**
    * 獲取默認公眾號訪問令牌
    */
    public String getGzhAccessTokenDefaultCfg() {
    if (StringUtils.isEmpty(defaultGzhAppId) || StringUtils.isEmpty(defaultGzhSecret)) {
    initialize();//讀取配置文件里公眾號的值(appId和appSecret),這兩個值在公眾號里有,公眾號的接口大多需要這兩個參數去獲取Token
    }
    return getGzhAccessToken(defaultGzhAppId,defaultGzhSecret);
    }
    // 獲取企業號access_token
    private final static String company_access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=CORPID&secret=CORPSECRET";
    // 獲取開放平臺的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";
    /**
    * 獲取微信公眾號訪問令牌
    * @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)) {//如果緩存沒有Token,或過期了,將重新去獲取一次
    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);// (存到緩存中,避免經常去拿token,將近兩小時)
    } catch (Exception e) {
    log.error("獲取微信公眾號token失敗,或token保存至緩存失敗 ####accessToken" + accessToken);
    }
    }
    }
    return accessToken;
    }

    POST和GET請求工具類,在獲取圖片時,需要使用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;
    /**
    * 工具類
    */
    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);// 創建連接
    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()); // 設置發送數據的格式
    }
    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();// 獲取長度
    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);
    // 打開和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);
    // 建立實際的連接
    connection.connect();
    // 定義 BufferedReader輸入流來讀取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;
    }
    }

    接口寫完后,你可以單元測試調用一下,生成的二維碼就可以掃一下,是不是會跳到你對應的公眾號界面。自定義二維碼已經生成了,但現在跟普通的二維碼沒區別,因為沒有觸發事件。接下來,編寫一個能讓公眾號調用你的方法的接口。讓公眾號告訴你,有人關注或取消關注。

    二、事件觸發接口

    controller層

    //微信推送事件 url
    @RequestMapping("/openwx/getticket")
    public void getTicketMessage(HttpServletRequest request, HttpServletResponse response)
    throws Exception {
    wechatPushService.getTicketMessage(request,response);

    事件觸發邏輯層,看下面代碼時,先看官方的文檔,這樣更能理解返回參數: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.收到微信服務器消息");
    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);//不存在的話,放緩存里,記得加一個失效時間,避免一直存在,占用資源
    String Event = wxdata.get("Event");
    System.out.println("Event"+Event);
    if(Event.equals("subscribe") || Event.equals("SCAN")){//掃碼帶參數的二維碼進入的
    String EventKey = wxdata.get("EventKey");//獲取參數
    String FromUserName = wxdata.get("FromUserName");//OpenID
    if(EventKey.indexOf("_") != -1){//初次關注
    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 這里一定要注意,否則會出錯
    textMessage.setCreateTime(new Date().getTime());
    textMessage.setMsgType("text");
    textMessage.setContent("歡迎您關注"+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);//用戶關注時,發一個歡迎語給用戶
    out.close();
    }
    }
    return null;
    }

    三、觸發接口寫完后,需要去公眾號后臺去設置你的接口服務器,讓公眾號知道你的接口地址。

    如何生成關注公眾號自定義二維碼及監聽掃碼事件
    如何生成關注公眾號自定義二維碼及監聽掃碼事件

    修改配置,服務器地址為你部署的地址,必須對方能連上,而且需要80端口(如果80端口被占用,可以使用Nginx做轉發),在配置的時候,公眾號會嘗試調用,調用不到你的接口,會直接提醒你。

    配置完后,點擊啟動。這個時候你再去關注你剛才生成的參數二維碼,就會有反映了。記得在事件觸發接口中,增加你的業務。用戶關注或取消關注時,你要做什么。

    另外,在啟動配置后,你會發現,你的公眾號自定義菜單不見了,這個時候不要慌。接下往下看。

    如何生成關注公眾號自定義二維碼及監聽掃碼事件
    如何生成關注公眾號自定義二維碼及監聽掃碼事件

    啟動菜單

    如何生成關注公眾號自定義二維碼及監聽掃碼事件

    這個時候公眾號上的小菜單就有了。但公眾號后臺自定義菜單還是看不到?那怎么修改菜單呢?

    很簡單,先把前面開啟的服務器配置給停止了,然后再改你的菜單,修改完菜單后,你再開始服務器。到此就完成了生成及事件監聽的過程

    版權聲明:本文內容由互聯網用戶自發貢獻,該文觀點僅代表作者本人。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如發現本站有涉嫌抄襲侵權/違法違規的內容, 請發送郵件至 舉報,一經查實,本站將立刻刪除。

    發表評論

    登錄后才能評論
    国产精品区一区二区免费