目录
- 一、生成微信登录二维码
- 1、准备工作
- 2、后端开发service_user
- 3、前端显示登录二维码
- 4、二维码出现不了进行调试
- 二、开发微信扫描回调
- 1、准备工作
- 2、后台开发
- 3、前台开发
- 三、分析代码
- 四、bug
一、生成微信登录二维码
1、准备工作
1、注册
2、邮箱激活
3、完善开发者资料
4、开发者资质认证
准备营业执照,1-2个工作日审批、300元
5、创建网站应用
提交审核,7个工作日审批
6、熟悉微信登录流程
参考文档:https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505&token=e547653f995d8f402704d5cb2945177dc8aa4e7e&lang=zh_CN
获取access_token时序图
介绍一个详细的
2、后端开发service_user
说明:微信登录二维码我们是以弹出层的形式打开,不是以页面形式,所以做法是不一样的,参考如下链接,上面有相关弹出层的方式
https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html
如图:
因此我们的操作步骤为:
第一步我们通过接口把对应参数返回页面;
第二步在头部页面启动打开微信登录二维码;
第三步处理登录回调接口;
第四步回调返回页面通知微信登录层回调成功
第五步如果是第一次扫描登录,则绑定手机号码,登录成功
接下来我们根据步骤,一步一步实现
1、添加配置
application.properties添加相关配置信息
# 微信开放平台 appid
wx.open.app_id=你的appid
# 微信开放平台 appsecret
wx.open.app_secret=你的appsecret
# 微信开放平台 重定向url
wx.open.redirect_url=http://你的服务器名称/api/ucenter/wx/callback
2、创建常量类
创建util包,创建ConstantPropertiesUtil.java常量类
@Component
@Data
public class WeixinProperties {
@Value("${wx.open.app_id}")
private String appId;
@Value("${wx.open.app_secret}")
private String appSecret;
@Value("${wx.open.redirect_url}")
private String redirectUrl;
}
3、创建controller
service_user微服务中创建api包
api包中创建WeixinController,返回微信参数
@Controller
@RequestMapping("/user/ucenter/wx")
public class WeixinController {
@Autowired
private WeixinProperties weixinProperties;
@RequestMapping("/param")
@ResponseBody
public R getWeixinLoginParam() throws UnsupportedEncodingException {
String redirectUri = URLEncoder.encode(weixinProperties.getRedirectUrl(), "UTF-8");
HashMap<String, Object> map = new HashMap<>();
map.put("appid",weixinProperties.getAppId());
map.put("scope","snsapi_login");
map.put("redirect_uri",redirectUri);
map.put("state",System.currentTimeMillis()+"");
return R.ok().data(map);
}
}
授权url参数说明
3、前端显示登录二维码
1、封装api请求
创建api/yygh/wx.js
import request from '@/utils/request'
const api_name = `/user/ucenter/wx`
export default {
getLoginParam() {
return request({
url: `${api_name}/param`,
method: `get`
})
}
}
2、修改组件
修改layouts/myheader.vue文件,添加微信二维码登录逻辑
// 1、引入api
import weixinApi from '@/api/wx'
//2、引入微信js
mounted() {
......
//初始化微信js
const script = document.createElement('script')
script.type = 'text/javascript'
script.src = 'https://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js'
document.body.appendChild(script)
},
......
weixinLogin() {
this.dialogAtrr.showLoginType = 'weixin'
weixinApi.getLoginParam().then(response => {
var obj = new WxLogin({
self_redirect:true,
id: 'weixinLogin', // 需要显示的容器id
appid: response.data.appid, // 公众号appid wx*******
scope: response.data.scope, // 网页默认即可
redirect_uri: response.data.redirect_uri, // 授权成功后回调的url
state: response.data.state, // 可设置为简单的随机数加session用来校验
style: 'black', // 提供"black"、"white"可选。二维码的样式
href: '' // 外部css文件url,需要https
})
})
},
//说明:微信登录方法已绑定weixinLogin(),查看页面
new WxLogin中的容器id是这个
解释这几行代码是什么意思
//初始化微信js
const script = document.createElement(‘script’)
script.type = ‘text/javascript’
script.src = ‘https://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js’
document.body.appendChild(script)
相当于这行代码
< script type=“test/javascript” src=“https://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js”>< /script>
4、二维码出现不了进行调试
报404错误,路径都对了的,由此可以想到可能是网关的问题
添加即可
二、开发微信扫描回调
1、准备工作
1、全局配置的跳转路径
# 微信开放平台 重定向url
wx.open.redirect_url=http://localhost:8160/user/ucenter/wx/callback
2、修改当前项目启动端口号为8160
一定要和微信重定向url的端口号一致
3、测试回调是否可用
在WxApiController中添加方法
@GetMapping("callback")
public String callback(String code, String state, HttpSession session) {
//得到授权临时票据code
System.out.println("code = " + code);
System.out.println("state = " + state);
return "";
}
2、后台开发
1、添加依赖
<!--httpclient-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<!--gson-->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
2、创建httpclient工具类
放入util包
package com.donglin.yygh.user.utils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.config.RequestConfig.Builder;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.security.GeneralSecurityException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* 依赖的jar包有:commons-lang-2.6.jar、httpclient-4.3.2.jar、httpcore-4.3.1.jar、commons-io-2.4.jar
* @author zhaoyb
*
*/
public class HttpClientUtils {
public static final int connTimeout=10000;
public static final int readTimeout=10000;
public static final String charset="UTF-8";
private static HttpClient client = null;
static {
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(128);
cm.setDefaultMaxPerRoute(128);
client = HttpClients.custom().setConnectionManager(cm).build();
}
public static String postParameters(String url, String parameterStr) throws ConnectTimeoutException, SocketTimeoutException, Exception{
return post(url,parameterStr,"application/x-www-form-urlencoded",charset,connTimeout,readTimeout);
}
public static String postParameters(String url, String parameterStr,String charset, Integer connTimeout, Integer readTimeout) throws ConnectTimeoutException, SocketTimeoutException, Exception{
return post(url,parameterStr,"application/x-www-form-urlencoded",charset,connTimeout,readTimeout);
}
public static String postParameters(String url, Map<String, String> params) throws ConnectTimeoutException,
SocketTimeoutException, Exception {
return postForm(url, params, null, connTimeout, readTimeout);
}
public static String postParameters(String url, Map<String, String> params, Integer connTimeout,Integer readTimeout) throws ConnectTimeoutException,
SocketTimeoutException, Exception {
return postForm(url, params, null, connTimeout, readTimeout);
}
public static String get(String url) throws Exception {
return get(url, charset, null, null);
}
public static String get(String url, String charset) throws Exception {
return get(url, charset, connTimeout, readTimeout);
}
/**
* 发送一个 Post 请求, 使用指定的字符集编码.
*
* @param url
* @param body RequestBody
* @param mimeType 例如 application/xml "application/x-www-form-urlencoded" a=1&b=2&c=3
* @param charset 编码
* @param connTimeout 建立链接超时时间,毫秒.
* @param readTimeout 响应超时时间,毫秒.
* @return ResponseBody, 使用指定的字符集编码.
* @throws ConnectTimeoutException 建立链接超时异常
* @throws SocketTimeoutException 响应超时
* @throws Exception
*/
public static String post(String url, String body, String mimeType,String charset, Integer connTimeout, Integer readTimeout)
throws ConnectTimeoutException, SocketTimeoutException, Exception {
HttpClient client = null;
HttpPost post = new HttpPost(url);
String result = "";
try {
if (StringUtils.isNotBlank(body)) {
HttpEntity entity = new StringEntity(body, ContentType.create(mimeType, charset));
post.setEntity(entity);
}
// 设置参数
Builder customReqConf = RequestConfig.custom();
if (connTimeout != null) {
customReqConf.setConnectTimeout(connTimeout);
}
if (readTimeout != null) {
customReqConf.setSocketTimeout(readTimeout);
}
post.setConfig(customReqConf.build());
HttpResponse res;
if (url.startsWith("https")) {
// 执行 Https 请求.
client = createSSLInsecureClient();
res = client.execute(post);
} else {
// 执行 Http 请求.
client = HttpClientUtils.client;
res = client.execute(post);
}
result = IOUtils.toString(res.getEntity().getContent(), charset);
} finally {
post.releaseConnection();
if (url.startsWith("https") && client != null&& client instanceof CloseableHttpClient) {
((CloseableHttpClient) client).close();
}
}
return result;
}
/**
* 提交form表单
*
* @param url
* @param params
* @param connTimeout
* @param readTimeout
* @return
* @throws ConnectTimeoutException
* @throws SocketTimeoutException
* @throws Exception
*/
public static String postForm(String url, Map<String, String> params, Map<String, String> headers, Integer connTimeout,Integer readTimeout) throws ConnectTimeoutException,
SocketTimeoutException, Exception {
HttpClient client = null;
HttpPost post = new HttpPost(url);
try {
if (params != null && !params.isEmpty()) {
List<NameValuePair> formParams = new ArrayList<NameValuePair>();
Set<Entry<String, String>> entrySet = params.entrySet();
for (Entry<String, String> entry : entrySet) {
formParams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formParams, Consts.UTF_8);
post.setEntity(entity);
}
if (headers != null && !headers.isEmpty()) {
for (Entry<String, String> entry : headers.entrySet()) {
post.addHeader(entry.getKey(), entry.getValue());
}
}
// 设置参数
Builder customReqConf = RequestConfig.custom();
if (connTimeout != null) {
customReqConf.setConnectTimeout(connTimeout);
}
if (readTimeout != null) {
customReqConf.setSocketTimeout(readTimeout);
}
post.setConfig(customReqConf.build());
HttpResponse res = null;
if (url.startsWith("https")) {
// 执行 Https 请求.
client = createSSLInsecureClient();
res = client.execute(post);
} else {
// 执行 Http 请求.
client = HttpClientUtils.client;
res = client.execute(post);
}
return IOUtils.toString(res.getEntity().getContent(), "UTF-8");
} finally {
post.releaseConnection();
if (url.startsWith("https") && client != null
&& client instanceof CloseableHttpClient) {
((CloseableHttpClient) client).close();
}
}
}
/**
* 发送一个 GET 请求
*
* @param url
* @param charset
* @param connTimeout 建立链接超时时间,毫秒.
* @param readTimeout 响应超时时间,毫秒.
* @return
* @throws ConnectTimeoutException 建立链接超时
* @throws SocketTimeoutException 响应超时
* @throws Exception
*/
public static String get(String url, String charset, Integer connTimeout,Integer readTimeout)
throws ConnectTimeoutException,SocketTimeoutException, Exception {
HttpClient client = null;
HttpGet get = new HttpGet(url);
String result = "";
try {
// 设置参数
Builder customReqConf = RequestConfig.custom();
if (connTimeout != null) {
customReqConf.setConnectTimeout(connTimeout);
}
if (readTimeout != null) {
customReqConf.setSocketTimeout(readTimeout);
}
get.setConfig(customReqConf.build());
HttpResponse res = null;
if (url.startsWith("https")) {
// 执行 Https 请求.
client = createSSLInsecureClient();
res = client.execute(get);
} else {
// 执行 Http 请求.
client = HttpClientUtils.client;
res = client.execute(get);
}
result = IOUtils.toString(res.getEntity().getContent(), charset);
} finally {
get.releaseConnection();
if (url.startsWith("https") && client != null && client instanceof CloseableHttpClient) {
((CloseableHttpClient) client).close();
}
}
return result;
}
/**
* 从 response 里获取 charset
*
* @param ressponse
* @return
*/
@SuppressWarnings("unused")
private static String getCharsetFromResponse(HttpResponse ressponse) {
// Content-Type:text/html; charset=GBK
if (ressponse.getEntity() != null && ressponse.getEntity().getContentType() != null && ressponse.getEntity().getContentType().getValue() != null) {
String contentType = ressponse.getEntity().getContentType().getValue();
if (contentType.contains("charset=")) {
return contentType.substring(contentType.indexOf("charset=") + 8);
}
}
return null;
}
/**
* 创建 SSL连接
* @return
* @throws GeneralSecurityException
*/
private static CloseableHttpClient createSSLInsecureClient() throws GeneralSecurityException {
try {
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
public boolean isTrusted(X509Certificate[] chain,String authType) throws CertificateException {
return true;
}
}).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, new X509HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
@Override
public void verify(String host, SSLSocket ssl)
throws IOException {
}
@Override
public void verify(String host, X509Certificate cert)
throws SSLException {
}
@Override
public void verify(String host, String[] cns,
String[] subjectAlts) throws SSLException {
}
});
return HttpClients.custom().setSSLSocketFactory(sslsf).build();
} catch (GeneralSecurityException e) {
throw e;
}
}
public static void main(String[] args) {
try {
String str= post("https://localhost:443/ssl/test.shtml","name=12&page=34","application/x-www-form-urlencoded", "UTF-8", 10000, 10000);
//String str= get("https://localhost:443/ssl/test.shtml?name=12&page=34","GBK");
/*Map<String,String> map = new HashMap<String,String>();
map.put("name", "111");
map.put("page", "222");
String str= postForm("https://localhost:443/ssl/test.shtml",map,null, 10000, 10000);*/
System.out.println(str);
} catch (ConnectTimeoutException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SocketTimeoutException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
3、创建回调controller方法
在WxApiController.java中添加如下方法
@GetMapping("/callback")
public String callback(String code, String state) throws Exception {
//第一步 获取临时票据 code
System.out.println("code:"+code);
//第二步 拿着code和微信id和秘钥,请求微信固定地址 ,得到两个值
//使用code和appid以及appscrect换取access_token
// %s 占位符
StringBuffer baseAccessTokenUrl = new StringBuffer()
.append("https://api.weixin.qq.com/sns/oauth2/access_token")
.append("?appid=%s")
.append("&secret=%s")
.append("&code=%s")
.append("&grant_type=authorization_code");
String accessTokenUrl = String.format(baseAccessTokenUrl.toString(),
weixinProperties.getAppId(),
weixinProperties.getAppSecret(),
code);
//使用httpclient请求这个地址
String accesstokenInfo = HttpClientUtils.get(accessTokenUrl);
//System.out.println("accesstokenInfo:"+accesstokenInfo);
//从返回字符串获取两个值 openid 和 access_token
JSONObject jsonObject = JSONObject.parseObject(accesstokenInfo);
String access_token = jsonObject.getString("access_token");
String openid = jsonObject.getString("openid");
//System.out.println(access_token+" "+openid);
//-----到这里可以调试能不能打印access_token和openid---------
//判断数据库是否存在微信的扫描人信息
//根据openid判断
UserInfo userInfo = userInfoService.selectWxInfoOpenId(openid);
if (userInfo == null){
//第三步 拿着openid 和 access_token请求微信地址,得到扫描人信息
String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +
"?access_token=%s" +
"&openid=%s";
String userInfoUrl = String.format(baseUserInfoUrl, access_token, openid);
String resultInfo = HttpClientUtils.get(userInfoUrl);
System.out.println("resultInfo:"+resultInfo);
JSONObject resultUserInfoJson = JSONObject.parseObject(resultInfo);
//解析用户信息
//用户昵称
String nickname = resultUserInfoJson.getString("nickname");
//用户头像
String headimgurl = resultUserInfoJson.getString("headimgurl");
//获取扫描人信息添加数据库
userInfo = new UserInfo();
userInfo.setNickName(nickname);
userInfo.setOpenid(openid);
userInfo.setStatus(1);
userInfoService.save(userInfo);
}
//返回name和token字符串
Map<String,String> map = new HashMap<>();
String name = userInfo.getName();
if(StringUtils.isEmpty(name)) {
name = userInfo.getNickName();
}
if(StringUtils.isEmpty(name)) {
name = userInfo.getPhone();
}
map.put("name", name);
//使用jwt生成token字符串
String token = JwtHelper.createToken(userInfo.getId(), name);
map.put("token", token);
//判断userInfo是否有手机号,如果手机号为空,返回openid
//如果手机号不为空,返回openid值是空字符串
//前端判断:如果openid不为空,绑定手机号,如果openid为空,不需要绑定手机号
if(StringUtils.isEmpty(userInfo.getPhone())){
map.put("openid", userInfo.getOpenid());
}else {
map.put("openid", "");
}
return "redirect:http://localhost:3000/weixin/callback?token="+map.get("token")+ "&openid="+map.get("openid")+"&name="+URLEncoder.encode(map.get("name"),"utf-8");
}
4、创建UserInfoService方法
根据openid查询用户信息
//定义方法
UserInfo selectWxInfoOpenId(String openid);
//实现方法
@Override
public UserInfo selectWxInfoOpenId(String openid) {
return baseMapper.selectOne(new QueryWrapper<UserInfo>().eq("openid",openid));
}
到这里可以把前端页面先写上(直接看前台开发)
同一个手机号登录,(微信登录+强行绑定手机号登录)会出现两条sql,我们需要两条sql合并成一条,这里需要修改之前写的手机登录模块改一下逻辑(判断手机验证时,openid为不为空)
5、创建UserInfoServiceImpl的登录方法
绑定手机号操作
//登录接口
@Override
public Map<String, Object> login(LoginVo loginVo) {
//1.首先获取用户输入的手机号和验证码信息
String phone = loginVo.getPhone();
String code = loginVo.getCode();
//2.对接收的手机号和验证码做一个非空判断
if (StringUtils.isEmpty(phone) || StringUtils.isEmpty(code)){
throw new YyghException(20001,"数据为空");
}
//TODO 对验证码做进一步确认
//校验校验验证码
String mobleCode = redisTemplate.opsForValue().get(phone);
if(!code.equals(mobleCode)) {
throw new YyghException(20001,"验证码失败");
}
String openid = loginVo.getOpenid();
Map<String, Object> map = new HashMap<>();
if(StringUtils.isEmpty(openid)) {
//4.是否手机首次登陆,如果首次登陆,就先网表中注册一下当前用户信息
QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
wrapper.eq("phone",phone);
UserInfo userInfo = baseMapper.selectOne(wrapper);
if (null == userInfo){
userInfo = new UserInfo();
userInfo.setPhone(phone);
userInfo.setCreateTime(new Date());
userInfo.setStatus(1);
baseMapper.insert(userInfo);
}
//5.验证用户的status
if (userInfo.getStatus() == 0){
throw new YyghException(20001,"用户已经禁用");
}
map.get(userInfo);
}else {
//1 创建userInfo对象,用于存在最终所有数据
UserInfo userInfoFinal = new UserInfo();
//2 根据手机查询数据
// 如果查询手机号对应数据,封装到userInfoFinal
UserInfo userInfoPhone =
baseMapper.selectOne(new QueryWrapper<UserInfo>().eq("phone", phone));
if(userInfoPhone != null) {
// 如果查询手机号对应数据,封装到userInfoFinal
BeanUtils.copyProperties(userInfoPhone,userInfoFinal);
//把手机号数据删除
baseMapper.delete(new QueryWrapper<UserInfo>().eq("phone", phone));
}
//3 根据openid查询微信信息
QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
wrapper.eq("openid",openid);
UserInfo userInfoWX = baseMapper.selectOne(wrapper);
//4 把微信信息封装userInfoFinal
userInfoFinal.setOpenid(userInfoWX.getOpenid());
userInfoFinal.setNickName(userInfoWX.getNickName());
userInfoFinal.setId(userInfoWX.getId());
//数据库表没有相同绑定手机号,设置值
if(userInfoPhone == null) {
userInfoFinal.setPhone(phone);
userInfoFinal.setStatus(userInfoWX.getStatus());
}
//修改手机号
baseMapper.updateById(userInfoFinal);
//5 判断用户是否锁定
if(userInfoFinal.getStatus() == 0) {
throw new YyghException(20001,"用户被锁定");
}
//6 登录后,返回登录数据
map = get(userInfoFinal);
}
return map;
}
private Map<String,Object> get(UserInfo userInfo) {
//返回页面显示名称
Map<String, Object> map = new HashMap<>();
String name = userInfo.getName();
if(StringUtils.isEmpty(name)) {
name = userInfo.getNickName();
}
if(StringUtils.isEmpty(name)) {
name = userInfo.getPhone();
}
map.put("name", name);
//根据userid和name生成token字符串
String token = JwtHelper.createToken(userInfo.getId(), name);
map.put("token", token);
return map;
}
3、前台开发
1.回调返回页面
说明:我们只期望返回一个空页面,然后跟登录层通信就可以了,其实就是一个过渡页面,所以我们要给这个过渡页面定义一个空模板
(1)添加空模板组件:/layouts/empty.vue
<template>
<div>
<nuxt/>
</div>
</template>
(2)创建回调返回页面 /pages/weixin/callback.vue
<template>
<!-- header -->
<div>
</div>
<!-- footer -->
</template>
<script>
export default {
layout: "empty",
data() {
return {
}
},
mounted() {
//params获取/:id的参数
let token = this.$route.query.token //query获取?后的参数https://e/md?Id=91975
let name = this.$route.query.name
let openid = this.$route.query.openid
// 调用父vue方法
window.parent['loginCallback'](name, token, openid)
}
}
</script>
(3)在myheader.vue添加方法
mounted() {
// 注册全局登录事件对象
window.loginEvent = new Vue();
// 监听登录事件
loginEvent.$on('loginDialogEvent', function () {
document.getElementById("loginDialog").click();
})
// 触发事件,显示登录层:loginEvent.$emit('loginDialogEvent')
//初始化微信js
const script = document.createElement('script')
script.type = 'text/javascript'
script.src = 'https://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js'
document.body.appendChild(script)
// 微信登录回调处理
let self = this;
window["loginCallback"] = (name,token, openid) => {
self.loginCallback(name, token, openid);
}
},
loginCallback(name, token, openid) {
// 打开手机登录层,绑定手机号,改逻辑与手机登录一致
//openid不为空,强制绑定手机号,后端写的逻辑
if(openid != null) {
this.userInfo.openid = openid
this.showLogin()
} else {
this.setCookies(name, token)
}
},
2.预约挂号页面调整
修改/pages/hospital/_hoscode.vue组件
(1)引入cookie
import cookie from 'js-cookie'
(2)修改方法
schedule(depcode) {
// 登录判断
let token = cookie.get('token')
if (!token) {
loginEvent.$emit('loginDialogEvent')
return
}
window.location.href = '/hospital/schedule?hoscode=' + this.hospital.hoscode + "&depcode="+ depcode
}
意思就是当你选择门诊的时候必须是登录账号,如果没有就要弹框
思考loginEvent为啥调用就能弹出登录框,因为在myheader.vue里面设定了loginEvent
// 注册全局登录事件对象
window.loginEvent = new Vue();
// 监听登录事件
loginEvent.$on('loginDialogEvent', function () {
document.getElementById("loginDialog").click();
})
// 触发事件,显示登录层:loginEvent.$emit('loginDialogEvent')
三、分析代码
WeixinController层中callback方法
使用code和appid以及appscrect换取access_token
拿着openid和access_token请求微信地址,得到扫描人信息
四、bug
后端传的空字符串,在前端变成null