springboot项目,h5页面通过微信公众号获取微信用户信息
最近本人有一个项目需求,微信公众号里点击一个菜单进入一个商城购物系统。
对于在微信公众号还是小白的我来说难度有点大,但是做完后发现也就这样,用多了就熟悉了。下面记录一下自己开发过程中遇到的一些问题以及解决方案。有好多也是自己在网上找的资料,自己慢慢整合起来的。所以你可能会看到好多差不多的代码。
准备工作:
首先搭建springboot+shiro权限管理框架,在此基础上开发微信H5页面以及商城的后台管理系统。使用MySQL数据库。开发工具idea。
在github上找了一个springboot+shiro后台管理项目。本人觉得简洁,实用,附上链接
https://blog.csdn.net/zwzw1219/article/details/81813201
项目框架好了,然后H5页面在网上找了一个简单的商城模板。该H5模板也是自己在CSDN上面花积分下载下来的。该模板还是有些小问题的,需要自己去修改。
模板链接: https://pan.baidu.com/s/1k-bjTtbW9lDB66bP1ESWmA 提取码: bvrr 复制这段内容后打开百度网盘手机App,操作更方便哦
HBuilderX工具链接: https://pan.baidu.com/s/1F6XYM1Z4u2NMaa7QHqCPKQ 提取码: wime 复制这段内容后打开百度网盘手机App,操作更方便哦
项目框架有了,前端页面也有了,接下来准备微信公众号(自己申请一个微信测试公众号,然后在里面给自己开发者权限,这样才能再微信web开发者工具本地调试)
附上操作流程:
1.自己准备一个带域名的服务器资源。因为微信公众号需要域名。
我自己没有去弄域名了,而且麻烦不方便本地开发,所以在网上找了一个内网穿刺工具,每天有8个小时的免费使用时间。如果当中不能使用域名后,关掉重启,重新敲命令,获取域名。同时微信公众平台接口测试账号里面也要修改域名。
附上链接: https://pan.baidu.com/s/1i1zZwC1IJe3NQXlEmIUc1w 提取码: php6 复制这段内容后打开百度网盘手机App,操作更方便哦
2.进入微信公众平台接口测试帐号申请
https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login
直接点击登录,手机微信端确认
登录后,拿到APPID和appsecret 去微信公众平台调试工具获取token
http://mp.weixin.qq.com/debug/cgi-bin/apiinfo
接着到微信公众平台测试号管理,也就刚刚的第一个微信链接
这个接口配置信息 URL为项目微信用户授权页面(域名+项目文件)
token为上面的token。(我的一直配置失败,但是后面发现没有影响到本地开发)
点击修改,可以修改域名
此域名为 内网穿刺工具生成的域名 敲命令 ngrok http 本地项目端口号
扫码,添加微信测试公众号。
然后 体验接口权限表–网页服务–网页帐号–网页授权获取用户基本信息–修改
此域名和之前的那个一样。
准备了这么多后,开始代码了
微信授权接口js,该js我放在了访问进来的首页.html
$(document).ready(function() {center.enterWxAuthor();
})
// 自己的那个微信appid
var WX_APPID = "wx8eXXXXXXX68aa";
// 此路径需和微信接口配置一样
var pageUrl = pathUrl + "pages/shop/shop_index.html";
var center = {init: function(){// 渲染首页console.log("渲染首页");},enterWxAuthor: function(){debuggervar wxUserInfo = localStorage.getItem("wxUserInfo");if (!wxUserInfo) {var code = getUrlParam('code');if (code) {getWxUserInfo(code);center.init();}else{//没有微信用户信息,没有授权-->> 需要授权,跳转授权页面var authorizeUrl ='https://open.weixin.qq.com/connect/oauth2/authorize?appid='+ WX_APPID+'&redirect_uri='+ pageUrl+'&response_type=code&scope=snsapi_userinfo#wechat_redirect';window.location.href =authorizeUrl;}}else{center.init();}}
}function getWxUserInfo(par){var code = getUrlParam("code");if (par) code = par;var authorizationUrl = pathUrl + "shopApi/authorization";$.get(authorizationUrl,{code:code},function (data) {//保证写入的wxUserInfo是正确的if(data.status == 200){localStorage.setItem("wechatUserid",data.data.id);localStorage.setItem('wxUserInfo',JSON.stringify(data.data));//写缓存--微信用户信息}},"json");}
common.js 自己取舍相关代码
//form序列化为json
$.fn.serializeObject = function()
{var o = {};var a = this.serializeArray();$.each(a, function() {if (o[this.name] !== undefined) {if (!o[this.name].push) {o[this.name] = [o[this.name]];}o[this.name].push(this.value || '');} else {o[this.name] = this.value || '';}});return o;
};//获取url后的参数值
function getUrlParam(key) {var href = window.location.href;var url = href.split("?");if(url.length <= 1){return "";}var params = url[1].split("&");for(var i=0; i<params.length; i++){var param = params[i].split("=");if(key == param[0]){return param[1];}}
}// Get Root Dir
getRootDir = function (js) {var path = "";var strFullPath = window.document.location.href;var strPath = window.document.location.pathname;var pos = strFullPath.indexOf(strPath);var prePath = strFullPath.substring(0, pos);var postPath = strPath.substring(0, strPath.substr(1).indexOf('/') + 1);var path = prePath + postPath + "/";return path;
}getRootDirURL = function (js) {var path = "";var strFullPath = window.document.location.href;var strPath = window.document.location.pathname;var pos = strFullPath.indexOf(strPath);var prePath = strFullPath.substring(0, pos);var path = prePath + "/";return path;
}// 项目根目录
var projectPath = getRootDir("common.js");
var pathUrl = getRootDirURL("common.js");
var imagePath = getRootDir("common.js");
// 手机号
var mobileReg = /^1[3|4|5|7|8]\d{9}$/;
// 邮箱
var emailReg = /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/;
// 邮编
var zipcodeReg = /[1-9]\d{5}(?!\d)/;
// 正整数
var regPositive = /^[1-9]\d*$/;
//整数
var regInteger = /^[0-9]*$/;
// IP地址
var ipReg = /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/;
// 身份证号码为15位或者18位,15位时全为数字,18位前17位为数字,最后一位是校验位,可能为数字或字符X
var iDReg = /^([0-9]{17}[0-9X]{1})|([0-9]{15})$/;
// 英文
var englishReg = /[a-zA-Z]/;
// 中文
var cnReg = /[\u4e00-\u9fa5]/;
// 正数金额
var regAmount = /(^[1-9](\d+)?(\.\d{1,2})?$)|(^0$)|(^\d\.\d{1,2}$)/ ;(function ($) {$.extend({// 替换全部replaceAll: function (str, str1, str2) {return str.replace(new RegExp(str1, "gm"), str2);},// 为空检查checkNull: function (obj) {return !$.trim(obj);},// 手机号检查checkMobile: function (obj) {return !(mobileReg.test(obj));},// 邮箱检查checkEmail: function (obj) {return !(emailReg.test(obj));},// 邮编检查checkZipcode: function (obj) {return !(zipcodeReg.test(obj));},// 正整数检查checkPositive: function (obj) {return !(regPositive.test(obj));},// IP地址检查checkIp: function (obj) {return !(ipReg.test(obj));},// 身份证检查checkID: function (obj) {return !(iDReg.test(obj));},// 英文检查checkEn: function (obj) {return !(englishReg.test(obj));},// 中文检查checkEn: function (obj) {return !(cnReg.test(obj));},// 正整数金额checkAmount: function (obj) {return !(regAmount.test(obj));}});
})(jQuery);// 日期比较yyyy-MM-dd
function dateCompare(startDate, endDate) {if (startDate == '' || endDate == '') {return;}var arr = startDate.split("-");var starttime = new Date(arr[0], arr[1], arr[2]);var starttimes = starttime.getTime();var arrs = endDate.split("-");var lktime = new Date(arrs[0], arrs[1], arrs[2]);var lktimes = lktime.getTime();if (starttimes >= lktimes) {return true;} else {return false;}
}function checkNull(val) {if (val == null || $.trim(val).length == 0) {return true;}return false;
}//手机号检查
function checkMobile(obj) {return !(mobileReg.test(obj));
}// 邮箱检查
function checkEmail(obj) {return !(emailReg.test(obj));
}// 邮编检查
var zipReg = /^[1-9][0-9]{5}$/;function checkZipcode(obj) {return !(zipReg.test(obj));
}// 正整数检查
function checkPositive(obj) {return !(regPositive.test(obj));
}// 整数检查
function checkInteger(obj) {return !(regInteger.test(obj));
}// IP地址检查
function checkIp(obj) {return !(ipReg.test(obj));
}// 身份证检查
function checkID(obj) {return !(iDReg.test(obj));
}// 英文检查
function checkEn(obj) {return !(englishReg.test(obj));
}// 中文检查
function checkCh(obj) {return !(cnReg.test(obj));
}// 正整数金额
function checkAmount(obj) {return !(regAmount.test(obj));
}// 小数检查
var pointReg = /^\d+\.\d+$/;function checkPoint(obj) {return !(pointReg.test(obj));
}//验证年月日(yyyy-mm-dd)格式
function isDate(dateString) {var r = dateString.match(/^(\d{1,4})(-|\/)(\d{1,2})\2(\d{1,2})$/);if (r == null) {return false;}var d = new Date(r[1], r[3] - 1, r[4]);var num = (d.getFullYear() == r[1] && (d.getMonth() + 1) == r[3] && d.getDate() == r[4]);return (num != 0);
}
ShopApiController
/*** @Author zhangfeng* @Description //TODO 首页 获取微信用户信息* @Date 2019/5/23 14:00* @Param [code, request, response]* @return com.otfresh.utils.ServerResponse**/@GetMapping("/authorization")@ResponseBodypublic ServerResponse authorizationWeixin( @RequestParam String code,HttpServletRequest request,HttpServletResponse response) throws IOException {request.setCharacterEncoding("UTF-8");response.setCharacterEncoding("UTF-8");try {return iWechatUserService.getOauthAccessToken(code);} catch (Exception e) {logger.error("RestFul of authorization is error.",e);}return ServerResponse.createByError();}
ServerResponse.java 为返回工具类,需要的朋友可以自己保存
package com.otfresh.utils;import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;import java.util.Date;;/*** * { data: status/code: msg:* * }* * 统一返回值* * @author Administrator* @param*///将该标记放在属性上,如果该属性为NULL则不参与序列化
//如果放在类上边,那对这个类的全部属性起作用
//Include.Include.ALWAYS 默认
//Include.NON_DEFAULT 属性为默认值不序列化
//Include.NON_EMPTY 属性为 空(“”) 或者为 NULL 都不序列化
//Include.NON_NULL 属性为NULL 不序列化
@JsonInclude(Include.NON_NULL)
public class ServerResponse {private int status;private String msg;private String field;private Object data;// 私有构造函数private ServerResponse(int status) {this.status = status;}// 私有构造函数private ServerResponse(int status, Object data) {this.status = status;this.data = data;}// 私有构造函数private ServerResponse(int status, String msg, Object data) {this.status = status;this.msg = msg;this.data = data;}// 私有构造函数private ServerResponse(int status, String msg) {this.status = status;this.msg = msg;}// 验证私有构造函数private ServerResponse(int status, String field, String msg, Object data) {this.status = status;this.field = field;this.msg = msg;this.data = data;}// 使之不在json序列化结果当中@JsonIgnorepublic boolean isSuccess() {return this.status == ResponseCode.SUCCESS.getCode();}@JsonFormat(pattern = "yyyy/MM/dd HH:mm:ss")public Date getDate() {return new Date();}public int getStatus() {return status;}public Object getData() {return data;}public String getMsg() {return msg;}public String getField() {return field;}// 正确返回public static ServerResponse createBySuccess() {return new ServerResponse(ResponseCode.SUCCESS.getCode());}public static ServerResponse createBySuccessMessage(String msg) {return new ServerResponse(ResponseCode.SUCCESS.getCode(), msg);}public static ServerResponse createBySuccess(Object data) {return new ServerResponse(ResponseCode.SUCCESS.getCode(), data);}public static ServerResponse createBySuccess(String msg, Object data) {return new ServerResponse(ResponseCode.SUCCESS.getCode(), msg, data);}public static ServerResponse createBySuccess(ResponseCode responseCode) {return new ServerResponse(responseCode.getCode(), responseCode.getDesc());}public static ServerResponse createBySuccess(ResponseCode responseCode, Object data) {return new ServerResponse(responseCode.getCode(), responseCode.getDesc(), data);}// error返回public static ServerResponse createByError() {return new ServerResponse(500, ResponseCode.ERROR.getDesc());}public static ServerResponse createByErrorMessage(String errorMessage) {return new ServerResponse(ResponseCode.ERROR.getCode(), errorMessage);}public static ServerResponse createByErrorCodeMessage(int errorCode, String errorMessage) {return new ServerResponse(errorCode, errorMessage);}public static ServerResponse createByErrorCodeMessage(ResponseCode responseCode) {return new ServerResponse(responseCode.getCode(), responseCode.getDesc());}public static ServerResponse createByErrorValidator(int code,String field,String message) {return new ServerResponse(code, field,message,null);}public static ServerResponse createByErrorValidator(int code,String field,String message,Object data) {return new ServerResponse(code, field,message,data);}}
ResponseCode.java
package com.otfresh.utils;/*** Created by geely enum类*/
public enum ResponseCode {SUCCESS(200, "SUCCESS"), ERROR(400, "ERROR"), NEED_LOGIN(100, "NEED_LOGIN"), ERROR_LOGIN(401, "你输入的账号和密码有误!!"),ERROR_CODE_LOGIN(402, "你输入的验证有误!!"), SESSION_FAIIL(101, "SESSION IS CLOSED"), ILLEGAL_ARGUMENT(202, "ILLEGAL_ARGUMENT");private final int code;private final String desc;ResponseCode(int code, String desc) {this.code = code;this.desc = desc;}public int getCode() {return code;}public String getDesc() {return desc;}}
IWechatUserService.java
/*** 根据code 获取授权的token 仅限授权时使用,与全局的access_token不同* @param code* @return String 用户信息* @throws IOException* @throws ClientProtocolException*/ServerResponse getOauthAccessToken(String code) throws Exception;
WechatUserServiceImpl.java
package com.otfresh.service.impl;import com.alibaba.fastjson.JSONObject;
import com.otfresh.dao.WechatUserDao;
import com.otfresh.model.dto.WechatUserDTO;
import com.otfresh.model.po.AccessTokenDO;
import com.otfresh.model.vo.WechatUserVO;
import com.otfresh.service.IAccessTokenService;
import com.otfresh.service.IWechatUserService;
import com.otfresh.utils.ServerResponse;
import com.otfresh.utils.StringUtil;
import com.otfresh.utils.constants.StatusEnum;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.TrustStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.*;/*** 微信用户模块 Service 实现层* @author zhangfeng* @create 2019年05月22日 09:56:34**/
@Service
public class WechatUserServiceImpl implements IWechatUserService {protected final Logger logger = LoggerFactory.getLogger(this.getClass());@Value("${app.WX_APPID}")private String WX_APPID;@Value("${app.WX_APPSECRET}")private String WX_APPSECRET;@Value("${app.WX_OAUTH_ACCESS_TOKEN_URL}")private String WX_OAUTH_ACCESS_TOKEN_URL ;@Value("${app.WX_OAUTH_REFRESH_TOKEN_URL}")private String WX_OAUTH_REFRESH_TOKEN_URL ;@Value("${app.WX_USERINFO_URL}")private String WX_USERINFO_URL ;@Autowiredprivate WechatUserDao wechatUserDao;@Autowiredprivate IAccessTokenService accessTokenService;/*** @Author zhangfeng* @Description //TODO 更新微信用户信息* @Date 2019/5/23 9:27* @Param [wechatUserDTO]* @return WechatUserDTO**/@Transactional(rollbackFor = Exception.class)public WechatUserDTO saveOrUpdateWechatUseer(String user){JSONObject userJson = JSONObject.parseObject(user);String openid = userJson.getString("openid");String nickname = userJson.getString("nickname");String sex = userJson.getString("sex");String headimgurl = userJson.getString("headimgurl");WechatUserDTO wechatUserDTO = new WechatUserDTO();wechatUserDTO.setOpenid(openid);wechatUserDTO.setWechatName(nickname);wechatUserDTO.setHeadImg(headimgurl);if(userJson.containsKey("unionid")){String unionid = userJson.getString("unionid");wechatUserDTO.setWechatNo(unionid);}// 查询是否存在该用户WechatUserVO wechatUserByOpenId = wechatUserDao.getWechatUserByOpenId(wechatUserDTO);if(StringUtil.isNotBlank(wechatUserByOpenId)){wechatUserDTO.setId(wechatUserByOpenId.getId());wechatUserDTO.setUpdateTime(new Date());wechatUserDTO.setLastLoginTime(new Date());// 更新信息wechatUserDao.updateWechatUser(wechatUserDTO);}else{wechatUserDTO.setStatus(StatusEnum.NEW.getKey().toString());wechatUserDTO.setSex(sex);// 新增信息wechatUserDao.saveWechatUser(wechatUserDTO);}return wechatUserDTO;}/*** 根据code 获取授权的token 仅限授权时使用,与全局的access_token不同* @param code* @return* @throws IOException* @throws ClientProtocolException*/@Override@Transactional(rollbackFor = Exception.class)public ServerResponse getOauthAccessToken(String code) throws Exception {// 从数据库表查询token信息AccessTokenDO accessToken = accessTokenService.getAccessTokenById(1);String rs_access_token = null;String rs_openid = null;//通过code换取网页授权access_tokenString url = WX_OAUTH_ACCESS_TOKEN_URL + "?appid="+WX_APPID+"&secret="+WX_APPSECRET+"&code="+code+"&grant_type=authorization_code";// 如果token为null 或者 超过过期时间if(accessToken == null || accessToken.getCreateTime().getTime() + Long.parseLong(accessToken.getExpiresIn()) *1000 < System.currentTimeMillis()){synchronized (this) {//已过期,需要刷新String rh = restTemplate().getForObject(url, String.class);JSONObject json = JSONObject.parseObject(rh);if(json.containsKey("errcode")){return ServerResponse.createByErrorCodeMessage(Integer.parseInt(json.get("errcode").toString()),json.get("errmsg").toString());}// 如果token为null 则不刷新tokenif(accessToken == null ){String access_token = json.getString("access_token");String expires_in = json.getString("expires_in");rs_openid = json.getString("openid");rs_access_token = access_token;accessToken = new AccessTokenDO();accessToken.setId(1);accessToken.setAccessToken(access_token);accessToken.setExpiresIn(expires_in);accessTokenService.saveAccessToken(accessToken);}else{String refresh_token = json.getString("refresh_token");// 刷新access_tokenString refresh_url = WX_OAUTH_REFRESH_TOKEN_URL+"?appid="+WX_APPID+"&grant_type=refresh_token&refresh_token="+refresh_token;String r_rh = restTemplate().getForObject(refresh_url, String.class);JSONObject r_json = JSONObject.parseObject(r_rh);if(r_json.containsKey("errcode")){return ServerResponse.createByErrorCodeMessage(Integer.parseInt(r_json.get("errcode").toString()),r_json.get("errmsg").toString());}String r_access_token = r_json.getString("access_token");String r_expires_in = r_json.getString("expires_in");rs_openid = r_json.getString("openid");rs_access_token = r_access_token;accessToken = new AccessTokenDO();accessToken.setId(1);accessToken.setAccessToken(r_access_token);accessToken.setExpiresIn(r_expires_in);accessTokenService.updateAccessToken(accessToken);}}}else{//还没有过期String rh = restTemplate().getForObject(url, String.class);JSONObject json = JSONObject.parseObject(rh);if(json.containsKey("errcode")){return ServerResponse.createByErrorCodeMessage(Integer.parseInt(json.get("errcode").toString()),json.get("errmsg").toString());}rs_access_token = json.getString("access_token");rs_openid = json.getString("openid");}return getOauthUserInfo(rs_access_token,rs_openid);}/*** 根据授权token获取用户信息* @param access_token* @param openid* @return*/@Transactional(rollbackFor = Exception.class)public ServerResponse getOauthUserInfo(String access_token,String openid) {String url = WX_USERINFO_URL +"?access_token="+ access_token +"&openid="+ openid +"&lang=zh_CN";try {String user = restTemplate().getForObject(url, String.class);user = new String(user.getBytes("ISO-8859-1"), "UTF-8");JSONObject userJson = JSONObject.parseObject(user);if(userJson.containsKey("errcode")){return ServerResponse.createByErrorCodeMessage(Integer.parseInt(userJson.get("errcode").toString()),userJson.get("errmsg").toString());}//保存用户信息WechatUserDTO wechatUserDTO = this.saveOrUpdateWechatUseer(user);return ServerResponse.createBySuccess(wechatUserDTO);} catch (Exception e) {logger.error("RestFul of authorization is error.",e);}return ServerResponse.createByError();}// 使用spring的RestTemplate 进行https请求 ,不懂的可以在网上搜索RestTemplate public static RestTemplate restTemplate() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(csf).build();HttpComponentsClientHttpRequestFactory requestFactory =new HttpComponentsClientHttpRequestFactory();requestFactory.setHttpClient(httpClient);RestTemplate restTemplate = new RestTemplate(requestFactory);return restTemplate;}
}
IAccessTokenService 为保存accessToken 而设计的。本人用的spring 的 ehcache缓存技术+数据表保存accessToken ,当然此处也可以使用redis。网上也有这种方案,本文不再记录。附上本人参考的链接https://blog.csdn.net/jiepan9178/article/details/81449004
注解形式获取参数,注意发布到测试环境或者真实环境微信APPID和appsecret需要根据自己的实际情况填写
application.properties
# 微信appId 和appsecret
app.WX_APPID=wxc524XXXXXXXXX0b8
app.WX_APPSECRET=901XXXXXXXXXXXXXXXXe2e00
#通过code换取网页授权access_token Url
app.WX_OAUTH_ACCESS_TOKEN_URL=https://api.weixin.qq.com/sns/oauth2/access_token
#刷新access_token url
app.WX_OAUTH_REFRESH_TOKEN_URL=https://api.weixin.qq.com/sns/oauth2/refresh_token
#获取微信用户 url
app.WX_USERINFO_URL = https://api.weixin.qq.com/sns/userinfo
其中的实体相关类和service类,dao层,mapper,SQL就不贴代码了无非就是CRUD,主要核心代码是getOauthAccessToken这个方法。
好了,代码都准备了好了,那开始来测试了
测试工具为 微信web开发者工具,账号就是之前设置开发者权限的微信账号登录。选择公众号网页调试。地址栏输入 之前在微信公众平台测试号 里面设置的回调域名 + 项目的访问页面。然后就可以调试了。
以上自己测的没有问题,但是难保在诸位博友的项目中会出现各种问题,遇到问题不要急,一步一步慢慢解决。本人在编写这部分代码时,因为不懂,出现过各种问题,比如微信开发者工具无法正常访问本地网页,无法获取微信用户信息等等。最后都一步一步慢慢解决了。该代码块目前只在本地开发过,还没有发布到测试环境使用,估计还会有坑!!!!!!
好了,本地开发获取微信用户信息的相关代码就到这里了,本人小白一个,代码有不正确的地方还请各位博友指出。