微信openid由用户id和公众号id加密而来,同一用户相对同一公众账号的openid是不变的。
-
微信openid
2019-09-28 14:08:41微信openid由用户id和公众号id加密而来,同一用户相对同一公众账号的openid是不变的。 转载于:https://www.cnblogs.com/superAnny/p/8422461.html转载于:https://www.cnblogs.com/superAnny/p/8422461.html
-
微信 openId
2017-01-17 11:25:00摘要 关于微信开发的话题,例子确实已经有不少,但大部分都是人云亦云,很多小细节...二 : 第三方页面授权,如何减少从微信服务器获取用户openid的次数以及减少获取用户信息的次数,加速第三方页面的加载速速。 ...摘要关于微信开发的话题,例子确实已经有不少,但大部分都是人云亦云,很多小细节或者需要注意的地方却大多没有讲清楚,这令很多刚开始开发的人感觉大很迷茫。而我今天要说的话题,主要着眼于两个方面。
一:如何存储获取用户信息及调用第三方接口所需要的token.
二 : 第三方页面授权,如何减少从微信服务器获取用户openid的次数以及减少获取用户信息的次数,加速第三方页面的加载速速。
(注:演示所使用的是java语言,其他语言可与此类似)
下面我将开始讲述第一个问题。
如何存储获取用户信息及调用第三方接口所需要的token?
从微信的官方文档上,我们知道,获取token的次数为1天2000次,每两小时token失效一次,对于那种一天没有几个人访问的微信公众号而言,他们可能只是简单的每次调用高级接口都会去获取一遍token.众所周知,这种做法极其的耗费时间。从网上其他网友给出的存储方案大概有如下几种:
- 数据库:通过微信接口获取到 Token 之后,将 Token存储到数据库,每次需要时从数据库取出。采用定时任务的方法每隔一个固定的时间去获取一次token.
- NoSQl:这里以 Redis 为例子。通过微信接口获取到 Token 之后,存入 Redis,可以通过设置redis的过期时间,每次需要token时从redis中取出来,若没有,则证明Token 已过期可重新获取(当然也可采用上面的定时任务的方式定期获取)。
- 文件存储:这个比较适合单一公众号的情况。通过微信接口获取到 Token 之后,存入文件,采用定时任务的方法每隔一个固定的时间去获取一次token.
(固定的时间:一般设为1小时为宜,如1小时后因网络原因,请求获取token失败,则原有的token还可以在使用1小时,这种方式将错误降低了一半)大致有这三种方案。当然对于那些将token存储在session或者cookie里面的,这里我只能呵呵一笑了。基于以上三种方式,我个人比较推崇的一个顺序是NoSQl>数据库>文件存储。下面我分别来说说他们的优缺点:采用数据库和文件存储,对于单节点并且用户请求数不是很多的web项目而言,是可以的正常运行的,但是对于分布式多节点的项目,采用这两种方式是行不通的。而我今天要说的第三种通过Redis方法存储,一方面它可以提升获取token的速度,另一方面当分布式项目的多个节点要公用同一个token的时候,我们可以方便的取到。第三方页面授权,如何减少从微信服务器获取用户openid的次数以及减少获取用户信息的次数,加速第三方页面的加载速速?
从诸多的博客中,我们了解到,第三方页面授权获取用户信息,我们要调用两次微信接口。
- 第一次:构造应用授权的url,通过返回的code,换取用户的openid.
- 第二次:通过用户的openid与token获取用户信息。
对于页面比较多的应用,每个页面请求时都需要调用两个方法,于用户而言这是极其耗费时间的。
然而诸多的博客只是告诉我们改如何处理用户信息,诸如将用户信息先拉取下来存储到自己的数据库,然后每次需要时从自己的数据库中通过openid来获取。殊不知这种博客只说了一点,他们没有考虑到的问题是:
- 用户若修改了自己的信息,该如何同步到自己的表里面.
- 用户的信息是获取到了,但是每次用户访问网页,标识用户身份的openid依旧每次都要去调用接口获取。(获取用户信息的次数微信API规定为500000次)
那么接下来我要说的这个就是如何解决上面两个问题,处理过程大致如下:
a.添加拦截器,拦截需要授权页面的controller
拦截器:
package com.fdc.home.dec.wx.filter; import com.alibaba.dubbo.common.utils.StringUtils; import com.fdc.platform.common.yfutil.PropertyReader; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.Arrays; /** * Created by pl on 2017/1/13. */ public class OAuth2Interceptor extends HandlerInterceptorAdapter { public static String indexUrl = PropertyReader.getValue("indexUrl");//从配置文件中读取域名 // private static String[] arrQueController = {"newquestion", "mycenter","testCookie"}; public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Cookie[] cookies = request.getCookies(); String openId=null; //判断cookie中是否存在openid 若存在则直接跳过,不存在则获取一次 if(cookies!=null){ for(Cookie cookie : cookies){ if(cookie.getName().equals("openId")){ openId = cookie.getValue(); } } } if (StringUtils.isEmpty(openId)) { if (handler instanceof HandlerMethod) { HandlerMethod handlerMethod = (HandlerMethod) handler; String methodName = handlerMethod.getMethod().getName(); String uri = request.getRequestURI(); // if (checkList(arrQueController, methodName)) { // System.out.println("执行了"); response.sendRedirect(indexUrl + "/oauth2Api?resultUrl=" + indexUrl + uri); return false; // } } return true; } else { return true; } } public void postHandle( HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } public void afterCompletion( HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } public boolean checkList(String[] arr, String targetValue) { return Arrays.asList(arr).contains(targetValue); } }
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/testCookie"/> <mvc:mapping path="/testCookie1"/> <bean class="com.fdc.home.dec.wx.filter.OAuth2Interceptor"/> </mvc:interceptor> </mvc:interceptors>
b.用户首次访问,调用微信接口获取openid和用户信息。将openid写入服务器端的cookie,将用户的信息写入redis缓存中,以openid作为redis的key。
package com.fdc.home.dec.wx.controller; import com.fdc.home.dec.service.inter.service.DecWxService; import com.fdc.home.dec.wx.service.CheckUserInfo; import com.fdc.home.dec.wx.utils.JSONHelper; import com.fdc.home.dec.wx.utils.WxUtils; import com.fdc.home.dec.wx.vo.token.WeixinOauth2Token; import com.fdc.home.dec.wx.vo.user.WeixinUserInfo; import com.fdc.platform.common.yfutil.PropertyReader; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; /** * Created by pl on 2017/1/13. */ @Controller public class OAuth2Controller { @Autowired private DecWxService decWxService; //判断用户是否登录的公用方法 CheckUserInfo checkUserInfo = new CheckUserInfo(); //从配置文件获取appid public static String appid = PropertyReader.getValue("appid"); //从配置文件获取appsecret public static String appsecret = PropertyReader.getValue("appsecret"); //从配置文件获取主域名 public static String indexUrl = PropertyReader.getValue("indexUrl"); public static String wtoken = PropertyReader.getValue("wholetoken"); /** * 组装授权url * @param request * @param resultUrl * @return */ @RequestMapping(value ="/oauth2Api") public String oauth2API(HttpServletRequest request, @RequestParam String resultUrl) { String redirectUrl = ""; if (resultUrl != null) { String backUrl =indexUrl+"/oauth2MeUrl?oauth2url="+resultUrl; //组装授权url redirectUrl = WxUtils.oAuth2Url(appid, backUrl); } return "redirect:" + redirectUrl; } /** * 获取用户信息 * @param request * @param response * @param code * @param oauth2url * @return * @throws IOException */ @RequestMapping(value = "/oauth2MeUrl") public String oauth2MeUrl(HttpServletRequest request,HttpServletResponse response, @RequestParam String code, @RequestParam String oauth2url) throws IOException { request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8"); HttpSession session = request.getSession(); session.setAttribute("code",code); // 用户同意授权 if (!"authdeny".equals(code)) { // 获取网页授权access_token WeixinOauth2Token weixinOauth2Token = WxUtils.getOauth2AccessToken(appid, appsecret, code); // 网页授权接口访问凭证 String accessToken = weixinOauth2Token.getAccessToken(); // 用户标识 String openId = weixinOauth2Token.getOpenId(); String wholetoken = decWxService.getToken(wtoken); //获取微信用户openid存储在cookie中的信息 Cookie userCookie=new Cookie("openId",openId); userCookie.setMaxAge(-1); userCookie.setPath("/"); response.addCookie(userCookie); WeixinUserInfo weixinUserInfo = WxUtils.getWeixinUserInfo(wholetoken, openId); //将用户信息写入redis decWxService.setToken(openId, JSONHelper.beanToJson(weixinUserInfo)); }else { return "redirect:"+indexUrl+"/error404"; } return "redirect:" + oauth2url; } }
(注:WxUtils中封装各种请求微信服务器的接口,具体可自行百度)
以上两步基本可以解决用户授权的问题。基于此需要说明的是:
- 开发中要设置cookie过期时间,设置为负数,表明当用户关闭浏览器的时候自动清空cookie,但在实际的测试中,微信浏览器并不会立刻清理cookie,你可以自行清理cookie.每次用户访问时直接从cookie中获取openid,若没有,才会调用微信接口获取。在获取openid的同时,更新redis缓存中的用户信息,这样达到及时同步用户信息的效果,也减少了对微信服务器的访问。
- 有部分网页在博客中提到微信浏览器没有cookie和session,基于这类问题,还请自己动手验证吗,微信浏览器是有cookie和session的(请区分服务端session和客户端session),这里之所以没有将openid存储在session中,其主要是考虑到分布式多点项目中session比较难以处理。
- 比较重要的一点是,当用户更换微信登录时,cookie会自动清除,登录成功后,会重新获取新登录的用户的openid。
转载于:https://www.cnblogs.com/yelongsan/p/6292327.html
-
获取微信openid的工具类
2018-05-24 09:49:58获取微信openid必要的工具类,获取微信openid必要的工具类。 -
微信小程序 获取微信OpenId详解及实例代码
2020-09-01 07:48:47主要介绍了微信小程序 获取微信OpenId详解及实例代码的相关资料,需要的朋友可以参考下 -
php获取微信openid方法总结
2020-10-16 06:01:36在本篇文章里小编给大家整理了关于php获取微信openid方法总结,有需要的朋友们参考学习下。 -
获取微信openid工具类
2018-06-09 14:15:19通过该工具,可以获取到微信openid,该方式为静默式获取。 -
获取微信OpenId
2016-10-07 14:34:44获取微信OpenId获取微信OpenId
- 先获取code
- 再通过code获取authtoken,从authtoken中取出openid给前台
- 微信端一定不要忘记设定网页账号中的授权回调页面域名
流程图如下
主要代码
页面js代码
/* 写cookie */ function setCookie(name, value) { var Days = 30; var exp = new Date(); exp.setTime(exp.getTime() + Days * 24 * 60 * 60 * 1000); document.cookie = name + "=" + escape(value) + ";expires=" + exp.toGMTString() + ";path=/"; } /* 读cookie */ function getCookie(name) { var arr = document.cookie.match(new RegExp("(^| )" + name + "=([^;]*)(;|$)")); if (arr != null) { return unescape(arr[2]); } return null; } /* 获取URL参数 */ function getUrlParams(name) { var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i"); var r = window.location.search.substr(1).match(reg); if (r != null) { return unescape(r[2]); } return null; } /* 获取openid */ function getOpenId(url) { var openid = getCookie("usropenid"); if (openid == null) { openid = getUrlParams('openid'); alert("openid="+openid); if (openid == null) { window.location.href = "wxcode?url=" + url; } else { setCookie("usropenid", openid); } } }
WxCodeServlet代码
//访问微信获取code @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String state = req.getParameter("url"); //WxOpenIdServlet的地址 String redirect ="http://"+Configure.SITE+"/wxopenid"; redirect = URLEncoder.encode(redirect, "utf-8"); StringBuffer url = new StringBuffer("https://open.weixin.qq.com/connect/oauth2/authorize?appid=") .append(Configure.APP_ID).append("&redirect_uri=").append(redirect) .append("&response_type=code&scope=snsapi_base&state=").append(state).append("#wechat_redirect"); resp.sendRedirect(url.toString()); }
WxOpenIdServlet代码
//访问微信获取openid @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String code = req.getParameter("code"); String state = req.getParameter("state"); Result ret = new Result(); AuthToken token = WXUtil.getAuthToken(code); if(null != token.getOpenid()){ ret.setCode(0); log.info("====openid=="+token.getOpenid()); Map<String,String> map = new HashMap<String,String>(); map.put("openid", token.getOpenid()); map.put("state", state); ret.setData(map); }else{ ret.setCode(-1); ret.setMsg("登录错误"); } String redUrl = state+"?openid="+token.getOpenid(); resp.sendRedirect(redUrl); }
获取AuthToken(WXUtil.getAuthToken(code))代码
public static AuthToken getAuthToken(String code){ AuthToken vo = null; try { String uri = "https://api.weixin.qq.com/sns/oauth2/access_token?"; StringBuffer url = new StringBuffer(uri); url.append("appid=").append(Configure.APP_ID); url.append("&secret=").append(Configure.APP_SECRET); url.append("&code=").append(code); url.append("&grant_type=").append("authorization_code"); HttpURLConnection conn = HttpClientUtil.CreatePostHttpConnection(url.toString()); InputStream input = null; if (conn.getResponseCode() == 200) { input = conn.getInputStream(); } else { input = conn.getErrorStream(); } vo = JSON.parseObject(new String(HttpClientUtil.readInputStream(input),"utf-8"),AuthToken.class); } catch (Exception e) { log.error("getAuthToken error", e); } return vo; }
HttpClientUtil类
package com.huatek.shebao.util; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.ProtocolException; import java.net.URL; public class HttpClientUtil { // 设置body体 public static void setBodyParameter(String sb, HttpURLConnection conn) throws IOException { DataOutputStream out = new DataOutputStream(conn.getOutputStream()); out.writeBytes(sb); out.flush(); out.close(); } // 添加签名header public static HttpURLConnection CreatePostHttpConnection(String uri) throws MalformedURLException, IOException, ProtocolException { URL url = new URL(uri); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setUseCaches(false); conn.setDoInput(true); conn.setDoOutput(true); conn.setRequestMethod("POST"); conn.setInstanceFollowRedirects(true); conn.setConnectTimeout(30000); conn.setReadTimeout(30000); conn.setRequestProperty("Content-Type","application/json"); conn.setRequestProperty("Accept-Charset", "utf-8"); conn.setRequestProperty("contentType", "utf-8"); return conn; } public static byte[] readInputStream(InputStream inStream) throws Exception { ByteArrayOutputStream outStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = 0; while ((len = inStream.read(buffer)) != -1) { outStream.write(buffer, 0, len); } byte[] data = outStream.toByteArray(); outStream.close(); inStream.close(); return data; } }
封装AuthToken的VO类
package com.huatek.shebao.wxpay; public class AuthToken { private String access_token; private Long expires_in; private String refresh_token; private String openid; private String scope; private String unionid; private Long errcode; private String errmsg; public String getAccess_token() { return access_token; } public void setAccess_token(String access_token) { this.access_token = access_token; } public Long getExpires_in() { return expires_in; } public void setExpires_in(Long expires_in) { this.expires_in = expires_in; } public String getRefresh_token() { return refresh_token; } public void setRefresh_token(String refresh_token) { this.refresh_token = refresh_token; } public String getOpenid() { return openid; } public void setOpenid(String openid) { this.openid = openid; } public String getScope() { return scope; } public void setScope(String scope) { this.scope = scope; } public String getUnionid() { return unionid; } public void setUnionid(String unionid) { this.unionid = unionid; } public Long getErrcode() { return errcode; } public void setErrcode(Long errcode) { this.errcode = errcode; } public String getErrmsg() { return errmsg; } public void setErrmsg(String errmsg) { this.errmsg = errmsg; } }
-
.NET获取微信openid
2016-06-22 12:22:46.net获取微信OpenID随着越来越多的微信公众号开发需求,很多人看微信公众平台的说明文档,都觉得有点是懂非懂的感觉,关键在于,微信开发调试比较困难。
针对这个现象,我来说一下.NET怎么获取用得较多的微信openid(获取头像等功能也类似)。
获取微信OpenID的前提是,你拥有认证过的微信服务号(公众号)或者订阅号,具体服务号、订阅号的功能区别可以看微信接口权限说明文档(详细接口权限说明文档)。
以认证过的微信服务号为例,我们来获取一下微信Openid。
第一步,设置网页回调域名,下面是微信的说明文字
1、在微信公众号请求用户网页授权之前,开发者需要先到公众平台官网中的“开发 - 接口权限 - 网页服务 - 网页帐号 - 网页授权获取用户基本信息”的配置选项中,修改授权回调域名。请注意,这里填写的是域名(是一个字符串),而不是URL,因此请勿加 http:// 等协议头;
2、授权回调域名配置规范为全域名,比如需要网页授权的域名为:www.qq.com,配置以后此域名下面的页面http://www.qq.com/music.html 、
http://www.qq.com/login.html 都可以进行OAuth2.0鉴权。但http://pay.qq.com 、 http://music.qq.com 、 http://qq.com无法进行OAuth2.0鉴权
3、如果公众号登录授权给了第三方开发者来进行管理,则不必做任何设置,由第三方代替公众号实现网页授权即可
我们要做的就是在“开发 - 接口权限 - 网页服务 - 网页帐号 - 网页授权获取用户基本信息”的配置选项中,修改授权回调域名。回调域名可以是www.****.com或者二级域名(如pay.****.com)。
第二步,获取code。https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
其中redirect_uri的地址就要指向你需要获取到code(OpenID)的页面,该页面的域名地址必须在之前授权回调域名下。appid就是你公众号的应用ID(在开发-基本配置中;另一个应用密钥AppSecret在后面要用到)。
第三步,通过code获取到access_token和OpenID(https://api.weixin.qq.com/sns/oauth2/access_token?appid=&secret=&code=&grant_type=authorization_code),
其中appid就是应用ID,secret是应用密钥,code就是第二步获取到的值。其实很简单,请求一下就获取到返回值就可以了。
在Page_Load中写事件,把这个页面放到回调域名中,在微信中打开链接就可以
(https://open.weixin.qq.com/connect/oauth2/authorize?appid=输入你的应用ID&redirect_uri=回调域名详细到指定页面&
response_type=code&scope=SCOPE&state=STATE#wechat_redirect)。
-
如何获取用户的微信openid
2018-10-26 14:17:24如何获取用户的微信openid如何获取用户的微信openid(1)首先登陆微信公众号后台(确保你有登陆微信后台的权限才可以...如何获取用户的微信openid 你是否还在烦恼通过微信API接口获得openid的步骤烦恼?哈哈,今日突... -
C#根据Code获取微信OpenId
2020-02-26 09:34:45#region "根据Code获取微信OpenId" /// <summary> /// 根据Code获取微信OpenId /// </summary> /// <param name="access_code"></param> /// <re... -
Golang通过小程序获取微信openid的方法示例
2020-09-17 16:15:05主要介绍了Golang通过小程序获取微信openid的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧 -
asp通过oauth2.0获取微信openid
2016-02-04 10:59:04目前网上用php获取微信openid的方法比较多,asp获取的方法几乎没有,这个已运用于实际项目中,确实可用 -
如何获取微信openId
2019-05-06 02:17:10获取微信openid openid定义 为了识别用户,每个用户针对每个公众号会产生一个安全的OpenID,如果需要在多公众号、移动应用之间做用户共通,则需前往微信开放平台,将这些公众号和应用绑定到一个开放平台账号下,绑定... -
ASP.NET CORE下用盛派微信SDK取微信openid
2018-07-11 22:13:44用CORE做项目用到微信的相关东西,听说那个盛派微信SDK很火,自己弄了下,只是简单的用用,用户访问页面取微信openid -
微信OpenId&UnionID
2018-08-10 15:58:26微信OpenId&UnionID 在关注者与公众号产生消息交互后,公众号可获得关注者的OpenID(加密后的微信号,每个用户对每个公众号的OpenID是唯一的。对于不同公众号,同一用户的openid不同) 注意:OpenId是... -
微信openid的生成规则研究
2016-09-26 14:24:53微信openid的生成规则研究 -
微信开发笔记-(3)获取微信OpenID
2016-12-22 17:48:25微信开发笔记-(3)获取微信OpenID 在微信开发时候在做消息接口交互的时候需要使用带微信加密ID(OpenId),下面讲讲述2中类型方式获取微信OpenID,接收事件推送方式和网页授权获取用户基本信息... -
微信openid和unionid区别
2019-04-17 15:10:11(1)微信openid和unionid长度是不一样的 openid=28,unionid=29 (2)openid同一用户同一应用唯一,unionid同一用户不同应用唯一 比如你们公司有一个公众号,一个小程序。 用户在公众号中有一个唯一openid,在小... -
springboot+vue公众号页面授权获得微信openId
2019-07-30 09:59:11springboot+vue获得微信openId 本文介绍前后端分离的开发模式如何获取用户的微信openId(用户已关注公众号,并通过公众号菜单跳转页面),后端采用springboot,前端采用vue。 一、后端所需代码 建议直接参考... -
微信公众号开发系列-获取微信OpenID
2017-11-16 16:55:33在微信开发时候在做消息接口交互的时候需要使用带微信加密ID(OpenId),下面讲讲述2中类型方式获取微信OpenID,接收事件推送方式和网页授权获取用户基本信息方式获取。 1、通过接收被动消息方式获取OpenId(接收... -
获取微信openid的步骤
2018-10-18 14:35:12微信OpenID获取 用户要求在微信端登录一次后,以后不需要再登录. 我的系统是单独的一个网站. 使用MVC的记住密码功能, 如果用户重启,就还是要输入密码,所以需要有一个唯一不变的用来标示用户的ID。 OpenID就是这样... -
在获取微信openId时携带的参数为null
2019-04-20 12:35:57在获取微信code 之后,我们进行 redirect ...在重定向的get 请求中携带一个自定义参数例如sid ,在获取微信openId 接口 String sid = request.getParameter("sid");取出是没有问题的。 但是业务需要多携带一个...
-
性能测试面面观
-
跟我练内测小分队学习礼包
-
普传科技PI7800_7600系列使用说明书.pdf
-
一款HX108-2型AM收音机收音机的安装、调试及故障分析.doc
-
【数据分析-随到随学】Python语法强化与数据处理
-
JavaEE框架(Maven+SSM)全程实战开发教程(源码+讲义)
-
thinkphp5.1博客后台实战视频
-
JVM常用调优参数(持续更新)
-
某宝TOP20万关键词查询工具下载
-
大数据Hive on MR/TEZ与hadoop的整合应用
-
FFmpeg4.3系列之26:视频监控之H265多路摄像头播控项目实战
-
基于X210的裸机时钟温度显示器-第3/3季
-
基于Multisim 10的电子电路可靠性研究.doc
-
高职院校学生职业生涯阻碍情况调查研究.doc
-
RabbitMQ 消息 100% 投递的解决方案!
-
Python/Pygame经典游戏源码飞机大战
-
VS2019安装智能提示番茄助手VAssistX
-
微服务系列第七十一季-Spring入门
-
python数据分析基础
-
android笔试面试和实战课程