生成微信公衆號的二維碼

 

前言:

       最近在研究一個功能,在系統中綁定用戶微信號,綁定好用戶賬號後,用戶就可以直接掃碼進入系統。講到這裏先來看一個下面這個完整的項目例子。

例子:

在系統當中的業務邏輯是這樣的。

  • 第一步,用戶點擊綁定微信,生成一個二維碼。

   

  •  第二步,用戶掃完二維碼後出現關注公衆號的頁面。

  • 第三步,用戶關注該公衆號出現微信掃碼的界面

  • 第四步,用戶掃完這個微信後,彈出獲取微信用戶信息的框。用戶同意以後即可綁定成功,下次就可用微信掃碼登錄系統。

 

  •  第五步,綁定成功。

業務介紹:

上面是一個完整的項目例子,但是我這邊博客我會將這個功能拆分開。

上面這個例子可以這麼來做。

第一種情況

用戶有系統的賬號和密碼 ,在個人設置中有一個綁定微信賬號功能。

1)

第一步,用戶用手機掃描這個公衆號的二維碼,要用戶關注公衆號,

2)

如果需要強制用戶關注公衆號的話,我們可以配置微信開發者設置,做接收微信事件功能,這樣用戶是否關注了該公衆號一目瞭然,並且在這個接收微信事件功能接口裏面,我們可以獲取到關注的當前用戶的openID , 根據openid 可以獲取微信用戶信息,在這之前我寫過一個獲取微信用戶列表的功能,當後臺獲取到掃碼的openId 以後 ,我就從數據庫中獲取當前用戶信息,將當前用戶信息保存到redis中,通過接口將這個redis中的數據返回給前端,如果數據庫中沒有當前用戶信息,我就將數據保到數據庫中。這樣前端就能判斷用戶能否進入下一步操作。

3)

掃描完公衆號的二維碼以後,我們可以生成一個帶參數的二維碼,指引用戶授權,獲取當前用戶的信息 一般情況下可以返回微信用戶暱稱等等,這個時候我們是在系統內部掃碼的。我們可以將暱稱和openId 跟當前用戶關聯起來,這樣在登錄界面的時候,用戶可以憑藉 微信掃碼登錄到系統中。

在這裏有一點需要注意的是,剛開始我是將用戶信息保存到session中的,在接收事件方法中我能夠獲取到保存到Session中的值,但是我新寫一個接口的時候,發現session中的值爲Null ,後面才知道這是倆個不同的客戶端,用戶關注公衆號是手機端,而我在瀏覽器上訪問這個用戶信息的時候,是瀏覽器端,倆個sessionId 都不一樣,自然數據就獲取不到。

第二種情況,

用戶沒有系統的賬號和密碼,那麼是在登錄界面有一個微信掃碼的功能。
當用戶掃描這個二維碼以後,我們就需要根據當前用戶的openId 查詢一下用戶信息,提示他是否需要綁定已有賬號 ,或者重新註冊一個新賬號,已新賬號身份登錄,並且將用戶信息和微信用戶信息綁定起來。

 

1.這篇文章先給大家演示一下如何生成一個公衆號的二維碼。

2.下篇文章我將給大家介紹一下微信的掃碼功能。 

開發步驟:

步驟1:

首先我們需要生成一個帶參數的二維碼,關於二維碼有2種,一種是臨時二維碼,一種是永久二維碼。

  • 1.臨時二維碼:有過期時間,最長可以設置爲在二維碼生成的30天(即2592000秒)後過期,生成較多數量。臨時二維碼主要用於帳  號綁定等不要求二維碼永久保存的業務場景。
  • 2.永久二維碼:是無過期時間的,但數量較少(目前爲最多10萬個)。永久二維碼主要用於適用於帳號綁定、用戶來源統計等場景。

獲取帶參數的二維碼的過程包括兩步:

  • 1.首先創建二維碼ticket。
  • 2.然後憑藉ticket到指定URL換取二維碼。

官方文檔地址

步驟2:

1. 首先創建二維碼Ticket  以下是請求地址和參數。

2.通過Ticket換取二維碼,以下是請求地址和請求參數內容

WechatController 

   @ApiOperation(value = "1.8 綁定微信賬號")
    @GetMapping(value = "/bindWechatAccount")
    public ResultData bindWechatAccount() {
        return weiService.bindWechatAccount();
    }

WeiService

 @Override
    public ResultData bindWechatAccount() {
        ResultData resultData = new ResultData();
        try {
            //第一步:向微信公衆平臺發送請求,獲取Ticket
            String accessToken = WeiXinParamesUtil.getAccessToken2("weixin");
            String createQrCodeUrl = WeiXinParamesUtil.createQrCodeUrl;
            createQrCodeUrl = createQrCodeUrl.replace("TOKEN", accessToken);
            //傳入參數。
            String postParam = "{\"action_name\": \"QR_LIMIT_SCENE\", \"action_info\": {\"scene\": {\"scene_id\": 123}}}";
            //發送請求 獲取Ticket
            JSONObject jsonObject = SendRequest.sendPost(createQrCodeUrl, postParam);
            System.out.println("111----" + jsonObject);
            String ticket = jsonObject.getString("ticket");
            // url : 二維碼圖片解析後的地址,開發者可根據該地址自行生成需要的二維碼圖片
            String url = jsonObject.getString("url");
            //第二步: 通過Ticket換取二維碼。
            String getWehatCodeUrl = WeiXinParamesUtil.getWeiQrCodeUrl;
            getWehatCodeUrl = getWehatCodeUrl.replace("TICKET", ticket);
            resultData.setResult("true");
            resultData.setMessage("返回微信公衆號二維碼成功");
            //返回生成的二維碼圖片
            System.out.println("111----"+getWehatCodeUrl);
            resultData.setStr(getWehatCodeUrl);
        } catch (Exception e) {
            resultData.setResult("false");
            resultData.setMessage("返回微信公衆號二維碼失敗");
            logger.error("返回微信公衆號二維碼失敗", e);
        }
        return resultData;
    }

 WeiXinParamesUtil

當前這個類屬於微信公衆平臺的參數配置類,其中有很多參數是我當前這篇文章不需要的,可以自行刪除。 

package com.bos.util;

import com.alibaba.fastjson.JSONObject;
import com.bos.common.CommenUtil;
import com.bos.data.model.WeiUserInfoModel;
import com.bos.qiWechat.AesException;
import com.bos.qiWechat.WXBizMsgCrypt;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * 微信公衆平臺的參數
 * @param
 * @return
 */
public class WeiXinParamesUtil {

    private Logger logger = LoggerFactory.getLogger(WeiXinParamesUtil.class);

    /**
     * 獲取微信公衆平臺accessToken
     * @param
     * @return
     */
    public static String getWeiAccessToken ="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";

    public static String getUserInfoList = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
    public static String getUserList = "https://api.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&next_openid=NEXT_OPENID";
    public static String updateUserRemark = "https://api.weixin.qq.com/cgi-bin/user/info/updateremark?access_token=ACCESS_TOKEN";
    public static String open_access_token_url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={appid}&secret={secret}&code={code}&grant_type=authorization_code";
    /**
     * 客戶接口發送消息
     * @param
     * @return
     */
    public static String sendCustomerMsgUrl="https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN";
    /**
     * 上傳臨時文件素材到微信服務器上
     * @param
     * @return
     */
    public static String uploadMaterialToWeiUrl="https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE";

    /**
     * 從微信服務器上下載臨時文件素材
     * @param
     * @return
     */
    public static String downloadMaterialFromWeiUrl="https://api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID";

    /**
     * 獲取access_token的接口地址(GET) 限200(次/天)
     * @param
     * @return
     */
    public static String access_token_url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={corpId}&corpsecret={corpsecret}";



    public static String open_id = "gh_b920df4d06d0";
    /**
     * 微信掃碼之後獲取用戶基本信息的地址
     * @param
     * @return
     */
    public static String getuserinfo_url = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID";
    /**
     * 發送消息給微信公衆平臺的url
     * @param
     * @return
     */
    public static  String sendMessageToWei_url="https://api.weixin.qq.com/cgi-bin/message/send?access_token=ACCESS_TOKEN";


    /**
     * 獲取微信公衆平臺Ticket
     */
    public static String createQrCodeUrl="https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=TOKEN";

    /**
     * 生成推廣的二維碼
     */
    public static String getWeiQrCodeUrl="https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=TICKET";

    /**
     * 生成小程序的二維碼
     */
    public static String CREATE_APPLET_CODE = "https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode?access_token=ACCESS_TOKEN";

    /**
     * 通過code 獲取 access_token
     */
    public static String GET_ACCESSTOKEN = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={appid}&secret={secret}&code={code}&grant_type=authorization_code";
    /**
     * 檢驗AccessToken是否有效
     */
    public static String CHECK_OUT_ACCESSTOKEN = "https://api.weixin.qq.com/sns/auth?access_token={access_token}&openid={open_id}";
    /**
     * 微信開放平臺獲取用戶信息
     */
    public static String GET_SNS_USER_INFO = "https://api.weixin.qq.com/sns/userinfo?access_token={access_token}&openid={open_id}";
    /**
     * 刷新AccessToken
     */
    public static String REFRESH_TOKEN = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid={appid}&grant_type={refresh_token}&refresh_token={refresh_token}";


//------------微信公衆平臺的參數
    /**
     * appId
     * @param
     * @return
     */
    public static String APPID;
    /**
     * secret
     * @param
     * @return
     */
    public static String SECRET;

    //----------------微信開放平臺的參數
    /**
     * openAppid
     * @param
     * @return
     */
    public static String OPENAPPID;
    /**
     * appSecret
     * @param
     * @return
     */
    public static String OPENSECRET;


    /**
     * 回調地址  redirect_uri
     * @param
     * @return
     */
    public static String REDIRECT_URI;
    /**
     * scope
     * @param
     * @return
     */
    public static String SCOPE;
    /**
     * 模板id
     * @param
     * @return
     */
    public static String TEMPLATEID;

    public static String TOKEN="weixinEbo";

    public static String ENCODEING_AES_KEY="MUPgLCxZND6ER0wON5FhdfGLtzzbOI7O5P23B2EWFrM";

    /**
     * 微信加密簽名
     */
    private String msg_signature;
    /**
     * 時間戳
     */
    private String timestamp;
    /**
     * 隨機數
     */
    private String nonce;

    static {
        
            APPID = "替換成你的APPid";
            SECRET = "替換成你的Secret";
            SCOPE = "snsapi_userinfo";
            REDIRECT_URI = "snsapi_userinfo";
            TEMPLATEID = "********";

            OPENAPPID="************";
            OPENSECRET="**************";


        }
    }


    /**
     * 獲取微信公衆平臺的access_token
     * @param type
     * @return
     */
    public static String getAccessToken2(String type) {
        String url = "";
        if ("weixin".equals(type)) {
            url = getWeiAccessToken.replace("APPID", WeiXinParamesUtil.APPID).replace("APPSECRET", WeiXinParamesUtil.SECRET);
        }
        JSONObject departmentJson = SendRequest.sendGet2(url);
        return departmentJson.getString("access_token");
    }

   

}

SendRequest 

 

 // 發送post請求(返回json)
    public static JSONObject sendPost(String url, String param) {
        PrintWriter out = null;
        BufferedReader in = null;
        JSONObject jsonObject = null;
        String result = "";
        try {
            URL realUrl = new URL(url);
            // 打開和URL之間的連接
            URLConnection conn = realUrl.openConnection();
            // 發送POST請求必須設置如下兩行
            conn.setDoOutput(true);
            conn.setDoInput(true);
//            conn.addRequestProperty("Cookie", "stay_login=1 smid=DumpWzWQSaLmKlFY1PgAtURdV_u3W3beoei96zsXkdSABwjVCRrnnNBsnH1wGWI0-VIflgvMaZAfli9H2NGtJg id=EtEWf1XZRLIwk1770NZN047804");//設置獲取的cookie
            // 獲取URLConnection對象對應的輸出流(設置請求編碼爲UTF-8)
            out = new PrintWriter(new OutputStreamWriter(conn.getOutputStream(), "UTF-8"));
            // 發送請求參數
            out.print(param);
            // flush輸出流的緩衝
            out.flush();
            // 獲取請求返回數據(設置返回數據編碼爲UTF-8)
            in = new BufferedReader(
                    new InputStreamReader(conn.getInputStream(), "UTF-8"));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
            jsonObject = JSONObject.parseObject(result);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }

        return jsonObject;
    }
package com.bos.common;

import com.bos.data.model.TShowColumnModel;
import io.swagger.annotations.ApiModelProperty;

import java.util.List;
import java.util.Map;

/**
 * @author tanghh
 */
public class ResultData {
    /**
     * "true" or "false"
     */
    @ApiModelProperty(value = "後臺返回的查詢結果,true=查詢成功,false=查詢失敗")
    private String result;
    /**
     * 消息提示
     */
    @ApiModelProperty(value = "後臺返回的消息,如'保存成功'。用作前端的提示消息")
    private String message;

    /**
     * 消息提示
     */
    @ApiModelProperty(value = "一個字符串")
    private String str;

    /**
     * 存放一個實體
     */
    private Object object;
    /**
     * 主數據集合
     */
    private PageData pageData;
    /**
     *其他數據
     */
    private List<Map> otherData;
    /**
     *整形
     */
    private Integer number;
    /**
     *存放list集合的map
     */
    private Map<String, List> mapList;
    /**
     *
     */
    private Map<Object, Object> map;
    /**
     *存放一個list集合
     */
    private List list;
    /**
     *專用於存放表頭字段的集合
     */
    private List fieldList;
    /**
     *專用於存放視圖集合
     */
    private List viewList;

    /**
     *專用於存放報表集合
     */
    private List reportList;

    /**
     * 專用於存每個頁面的page
     * @param
     * @return
     */
    private String page;
    /**
     * 專用於存不同頁面的module
     * @param
     * @return
     */
    private String module;

    /**
     * 存儲當前數據的上一級數據(第一級)
     * @param
     * @return
     */
    private String level1;
    /**
     * 存儲當前數據的上一級的上一級數據(第二級)
     * @param
     * @return
     */
    private String level2;
    /**
     * 存儲當前數據的上一級的上一級的上一級數據(第三級)
     * @param
     * @return
     */
    private String level3;

    /**
     * map2
     */
    private Map<Object, Object> map2;

    private Map<String,List<TShowColumnModel>> mapCloumnList;

    public List getReportList() {
        return reportList;
    }

    public void setReportList(List reportList) {
        this.reportList = reportList;
    }

    public List getViewList() {
        return viewList;
    }

    public void setViewList(List viewList) {
        this.viewList = viewList;
    }

    public List getList() {
        return list;
    }

    public void setList(List list) {
        this.list = list;
    }

    public Integer getNumber() {
        return number;
    }

    public void setNumber(Integer number) {
        this.number = number;
    }

    public Object getObject() {
        return object;
    }

    public void setObject(Object object) {
        this.object = object;
    }

    public Map<String, List<TShowColumnModel>> getMapCloumnList() {
        return mapCloumnList;
    }

    public void setMapCloumnList(Map<String, List<TShowColumnModel>> mapCloumnList) {
        this.mapCloumnList = mapCloumnList;
    }

    public ResultData() {
        this.message = "查詢成功";
        this.result = "true";
    }

    /**
     * 用於刪除成功
     * @param count
     */
    public ResultData(int count) {
        if(count>0){
            this.message = "刪除成功";
            this.result = "true";
        }else {
            this.message = "刪除失敗";
            this.result = "false";
        }
    }

    public ResultData(Object object) {
        this.object=object;
        this.message = "查詢成功";
        this.result = "true";
    }

    /**
     * 用於添加刪除提示
     * @param type
     * @param flag
     */
    public ResultData(String type,boolean flag) {
        if(flag==false){
            //保存和修改時候的提示
            if(Constant.SAVE.equals(type)){
                this.message = "保存失敗";
            }else{
                this.message = "刪除失敗";
            }
            this.result = "false";
        }else {
            if(Constant.SAVE.equals(type)){
                this.message = "保存成功";
            }else{
                this.message = "刪除成功";
            }
            this.result = "true";
        }
    }

    public ResultData(String result, String message, PageData pageData) {
        this.result = result;
        this.message = message;
        this.pageData = pageData;
    }

    public ResultData(String result, String message, PageData pageData, List<Map> otherData) {
        this.result = result;
        this.message = message;
        this.pageData = pageData;
        this.otherData = otherData;
    }

    public ResultData(String result, String message, PageData pageData, List<Map> otherData, Map<String, List> mapList) {
        this.result = result;
        this.message = message;
        this.pageData = pageData;
        this.otherData = otherData;
        this.mapList = mapList;
    }

    public ResultData(String result, String message) {
        this.result = result;
        this.message = message;
    }

    public String getResult() {
        return result;
    }

    public void setResult(String result) {
        this.result = result;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public PageData getPageData() {
        return pageData;
    }

    public void setPageData(PageData pageData) {
        this.pageData = pageData;
    }

    public List<Map> getOtherData() {
        return otherData;
    }

    public void setOtherData(List<Map> otherData) {
        this.otherData = otherData;
    }

    public Map<String, List> getMapList() {
        return mapList;
    }

    public void setMapList(Map<String, List> mapList) {
        this.mapList = mapList;
    }

    public Map<Object, Object> getMap() {
        return map;
    }

    public void setMap(Map<Object, Object> map) {
        this.map = map;
    }

    public List getFieldList() {
        return fieldList;
    }

    public void setFieldList(List fieldList) {
        this.fieldList = fieldList;
    }

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }

    public String getPage() {
        return page;
    }

    public void setPage(String page) {
        this.page = page;
    }

    public String getModule() {
        return module;
    }

    public void setModule(String module) {
        this.module = module;
    }

    public String getLevel1() {
        return level1;
    }

    public void setLevel1(String level1) {
        this.level1 = level1;
    }

    public String getLevel2() {
        return level2;
    }

    public void setLevel2(String level2) {
        this.level2 = level2;
    }

    public String getLevel3() {
        return level3;
    }

    public void setLevel3(String level3) {
        this.level3 = level3;
    }

    public Map<Object, Object> getMap2() {
        return map2;
    }

    public void setMap2(Map<Object, Object> map2) {
        this.map2 = map2;
    }
}

ResultData

 

步驟3:

訪問這個接口,http://localhost:8088/bindWechatAccount

getWehatCodeUrl 爲一個url ,這個url可以直接在網頁上展示也可以下載下來。我這裏的話先在網頁上訪問一下。

 

將上面這個url 複製到 瀏覽器上,掃描這個二維碼。

 

 

步驟4:

掃描上圖中的公衆號二維碼 關注公衆號。

 

到此,本篇文章就寫完啦 ,如果覺得小編寫的不錯的話,不妨給小編一個贊吧,如果有什麼問題的話,歡迎評論區留言。一起加油。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章