前言:
最近在研究一个功能,在系统中绑定用户微信号,绑定好用户账号后,用户就可以直接扫码进入系统。讲到这里先来看一个下面这个完整的项目例子。
例子:
在系统当中的业务逻辑是这样的。
- 第一步,用户点击绑定微信,生成一个二维码。
- 第二步,用户扫完二维码后出现关注公众号的页面。
- 第三步,用户关注该公众号出现微信扫码的界面
- 第四步,用户扫完这个微信后,弹出获取微信用户信息的框。用户同意以后即可绑定成功,下次就可用微信扫码登录系统。
- 第五步,绑定成功。
业务介绍:
上面是一个完整的项目例子,但是我这边博客我会将这个功能拆分开。
上面这个例子可以这么来做。
第一种情况 ,
用户有系统的账号和密码 ,在个人设置中有一个绑定微信账号功能。
1)
第一步,用户用手机扫描这个公众号的二维码,要用户关注公众号,
2)
如果需要强制用户关注公众号的话,我们可以配置微信开发者设置,做接收微信事件功能,这样用户是否关注了该公众号一目了然,并且在这个接收微信事件功能接口里面,我们可以获取到关注的当前用户的openID , 根据openid 可以获取微信用户信息,在这之前我写过一个获取微信用户列表的功能,当后台获取到扫码的openId 以后 ,我就从数据库中获取当前用户信息,将当前用户信息保存到redis中,通过接口将这个redis中的数据返回给前端,如果数据库中没有当前用户信息,我就将数据保到数据库中。这样前端就能判断用户能否进入下一步操作。
3)
扫描完公众号的二维码以后,我们可以生成一个带参数的二维码,指引用户授权,获取当前用户的信息 一般情况下可以返回微信用户昵称等等,这个时候我们是在系统内部扫码的。我们可以将昵称和openId 跟当前用户关联起来,这样在登录界面的时候,用户可以凭借 微信扫码登录到系统中。
在这里有一点需要注意的是,刚开始我是将用户信息保存到session中的,在接收事件方法中我能够获取到保存到Session中的值,但是我新写一个接口的时候,发现session中的值为Null ,后面才知道这是俩个不同的客户端,用户关注公众号是手机端,而我在浏览器上访问这个用户信息的时候,是浏览器端,俩个sessionId 都不一样,自然数据就获取不到。
第二种情况,
用户没有系统的账号和密码,那么是在登录界面有一个微信扫码的功能。
当用户扫描这个二维码以后,我们就需要根据当前用户的openId 查询一下用户信息,提示他是否需要绑定已有账号 ,或者重新注册一个新账号,已新账号身份登录,并且将用户信息和微信用户信息绑定起来。
1.这篇文章先给大家演示一下如何生成一个公众号的二维码。
开发步骤:
步骤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:
扫描上图中的公众号二维码 关注公众号。
到此,本篇文章就写完啦 ,如果觉得小编写的不错的话,不妨给小编一个赞吧,如果有什么问题的话,欢迎评论区留言。一起加油。