java实现微信小程序服务端(登录)
微信小程序如今被广泛使用,微信小程序按照微信官网的定义来说就是:
微信小程序是一种全新的连接用户与服务的方式,它可以在微信内被便捷地获取和传播,同时具有出色的使用体验。
这就是微信小程序的魅力所在,有的时候我们不需要去下载过多的app,只要打开微信,就可以应用每一个服务,甚至连注册都变得简单起来,具有特别贴近人心的用户体验。
最近在做一个微信小程序的服务端,主要就是实现登录、业务账号和微信号绑定的基本功能,接下来总结一下如何实现微信小程序的服务端代码。
要去实现服务端的代码,就要先去了解客户端的请求。
微信小程序开发平台开发了很全面、功能很强大的开发API供我们使用:
https://developers.weixin.qq.com/miniprogram/dev/api/
我们来看下api中的登录功能:

这个是微信小程序登录的时序图,非常明显地告知了我们微信小程序登录的请求服务调用的过程
1.添加微信小程序固定信息
在注册的时候,这个小程序的appId和appSecret已经知道了,还有固定的url,然后我们可以将其做为配置文件放入后台的代码中去:

2.根据小程序信息和code获取openId和session_key
在前端代码中,每当我们刚进入小程序的时候,都会去调用wx.login()方法,会得到一个code,然后发送给我们,然后,我们通过code和这些已知的参数,去调用微信的接口,去获取openId和session_key,作为登录态的标识
/**
* 获取微信小程序的session_key和openid
*
* @author hengyang4
* @param code 微信前端login()方法返回的code
* @return jsonObject
*
* */
public JSONObject getSessionKeyAndOpenId(String code)throws Exception{
//微信登录的code值
String wxCode = code;
//读取属性文件
ResourceBundle resourceBundle = ResourceBundle.getBundle("weixin");
//服务器端调用接口的url
String requestUrl = resourceBundle.getString("url");
//封装需要的参数信息
Map<String,String> requestUrlParam = new HashMap<String,String>();
//开发者设置中的appId
requestUrlParam.put("appid",resourceBundle.getString("appId"));
//开发者设置中的appSecret
requestUrlParam.put("secret",resourceBundle.getString("appSecret"));
//小程序调用wx.login返回的code
requestUrlParam.put("js_code", wxCode);
//默认参数
requestUrlParam.put("grant_type", "authorization_code"); JSONObject jsonObject = JSON.parseObject(sendPost(requestUrl,requestUrlParam));
return jsonObject;
} /**
* 向指定 URL 发送POST方法的请求
*
* @param url 发送请求的 URL
* @return 所代表远程资源的响应结果
*/
public String sendPost(String url, Map<String, ?> paramMap) {
PrintWriter out = null;
BufferedReader in = null;
String result = ""; String param = "";
Iterator<String> it = paramMap.keySet().iterator(); while(it.hasNext()) {
String key = it.next();
param += key + "=" + paramMap.get(key) + "&";
} try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
URLConnection conn = realUrl.openConnection();
// 设置通用的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("Accept-Charset", "utf-8");
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
// 获取URLConnection对象对应的输出流
out = new PrintWriter(conn.getOutputStream());
// 发送请求参数
out.print(param);
// flush输出流的缓冲
out.flush();
// 定义BufferedReader输入流来读取URL的响应
in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
log.error(e.getMessage(),e);
}
//使用finally块来关闭输出流、输入流
finally{
try{
if(out!=null){
out.close();
}
if(in!=null){
in.close();
}
}
catch(IOException ex){
ex.printStackTrace();
}
}
return result;
}
3. 将openId和session_key生成sessionId返回客户端
第三方服务器端拿到请求回来的session_key和openid,先留着,不能给客户端;然后用操作系统提供的真正随机数算法生成一个新的session,叫session_id
· 所以,每次前端wx.login()后调用的服务端的controller我们就应该这样写:
@RequestMapping(value = "/loginByWeixin", produces = "application/json;charset=UTF-8")
public String loginByWeixin(@RequestParam("code") String code) throws Exception{
//得到用户的openId + sessionKey
JSONObject jsonObject = getSessionKeyAndOpenId(code);
log.info(jsonObject.toString());
System.out.println(jsonObject);
String openId = jsonObject.getString("openid"); String sessionKey = jsonObject.getString("session_key");
//组装结果
Map<String,Object> resMap = new HashMap<String,Object>();
//判断openId是否存在用户表中
UserInfo userInfo = userInfoMapper.selectByUserName(openId);
if(ValidateUtil.isEmpty(userInfo)){
//不存在该用户关联关系
log.info("验证是否绑定微信","未登录");
resMap.put("code",ErrorCode.ERR_WEIXIN_USER_EMPTY.getErrorCode());
resMap.put("desc",ErrorCode.ERR_WEIXIN_USER_EMPTY.getErrorMessage());
}else {
//组装结果
log.info("验证是否绑定微信", "用户查询成功");
//0:操作成功
resMap.put("code", ErrorCode.ERR_SUCCEED.getErrorCode());
resMap.put("desc", ErrorCode.ERR_SUCCEED.getErrorMessage());
resMap.put("userInfo", userInfo);
}
//将通过md5生成sessionId(一般是用个操作系统提供的真正随机数算法生成新的session)
String sessionId = MD5.EncodeByMd5(openId+sessionKey+ DateUtil.getNowTime());
jedisCache.hashSet(sessionId,"ses",openId);
resMap.put("sessionId",sessionId);
return JSONConvertor.toJSON(resMap); }
4. 使用过滤器过滤请求头中含有session_id的请求
然后我们将session_id为key,微信服务端返回的openId为值,保存起来,这里我们用了redis去缓存这个session信息,openId为我们系统用户与微信绑定的标识
接下来,我们每次请求的时候,都会将session_id放入请求头中去,然后判断在redis中是否有key为该值得键值对,从而判断用户session是否失效
我们这里使用了过滤器来拦截用户请求
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException,ServletException{
//设置跨域请求
HttpServletResponse resp = (HttpServletResponse)response;
resp.setHeader("Access-Control-Allow-Origin", "*");
HttpServletRequest req = (HttpServletRequest)request;
//获取请求时的sessionId
String sessionId = req.getHeader("sessionId");
if(StrUtil.IsNullOrEmpty(sessionId)){
//该请求不需要验证session,直接通过
log.info("sessionId过滤","该请求不需要过滤,通过");
chain.doFilter(request,response);
return;
}else {
//只有在缓存中存在该sessionId才能进行请求
if (!jedisCache.existKey(sessionId)) {
// 登录信息已过期,请重新登录
log.info("sessionId过滤", "登录信息失效,请重新登录");
response.getWriter().write("登录信息失效,请重新登录");
return;
}
log.info("sessionId过滤", "session验证成功");
chain.doFilter(request, response);
}
}
5. 在数据库中建立用户与微信用户唯一标识的关联关系
每当用户注册或者登陆时,请求中都会含有session_id,然后我们将session_id作为key去redis中查找,得到value值,也就是我们之前存的openId,然后我们将openId和用户信息进行数据库表中的关联,之后,我们调用登陆方法的时候,如果该openId有关联的用户信息,则不需要去登录,直接给前端返回用户信息即可,就是我们之前的那段代码:

在这里,我们的微信小程序服务端代码就基本实现了,可以用于微信小程序与业务系统的登录,微信小程序的功能还有很多,之后我们有机会多去试一下其他功能,感受小程序的强大和快捷。
java实现微信小程序服务端(登录)的更多相关文章
- C#微信小程序服务端获取用户解密信息
using AIOWeb.Models; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.C ...
- Node.js Koa2开发微信小程序服务端
1.promise.async.await const Koa = require('koa') const app = new Koa() // 应用程序对象 有很多中间件 // 发送HTTP KO ...
- Java 后端微信小程序支付demo (网上说的坑里面基本上都有)
Java 后端微信小程序支付 一.遇到的问题 1. 商户号该产品权限未开通,请前往商户平台>产品中心检查后重试 2.签名错误 3.已经调起微信统一下单接口,可以拿到预支付ID,但是前端支付的时候 ...
- 微信小程序Server端环境配置
主要内容:1. SSL免费证书申请步骤2. Nginx HTTPS 配置3. TLS 1.2 升级过程 微信小程序要求使用 https 发送请求,那么Web服务器就要配置成支持 https,需要先申请 ...
- 微信小程序中用户登录和登录态维护
提供用户登录以及维护用户的登录状态,是一个拥有用户系统的软件应用普遍需要做的事情.像微信这样的一个社交平台,如果做一个小程序应用,我们可能很少会去做一个完全脱离和舍弃连接用户信息的纯工具软件. 让用户 ...
- Java实现微信小程序支付(完整版)
在开发微信小程序支付的功能前,我们先熟悉下微信小程序支付的业务流程图: 不熟悉流程的建议还是仔细阅读微信官方的开发者文档. 一,准备工作 事先需要申请企业版小程序,并开通“微信支付”(即商户功能).并 ...
- Python 实现微信小程序的用户登录
小程序可以通过官方提供的登录能力来获取用户身份的标示,具体文档可以参考 这里,通过流程时序可以看到,对于需要和前端配合的服务端开发,主要实现的就是通过小程序提供的 code 换取用户的 openid ...
- WebAPI 微信小程序的授权登录以及实现
这个星期最开始 ,老大扔了2个任务过来,这个是其中之一.下面直接说步骤: 1. 查阅微信开发文档 https://developers.weixin.qq.com/miniprogram/dev/ ...
- 微信小程序实现与登录
一.小程序的实现原理 在小程序中,渲染层和逻辑层是分开的,双线程同时运行,渲染层和逻辑层这两个通信主体之间的通讯以及通讯主体与第三方服务器之间的通信,都是通过微信客户端进行转发.小程序启动运行两种情况 ...
随机推荐
- Websocket --(1)简介
最近项目需求提出前台界面实时获取后端数据,也就是数据发生变化后服务端主动通知前端页面,以往都是前端请求服务端.当然了,前人已经为我们想好了解决办法,那就是websocket.至于websocket的介 ...
- [转帖]java必备的开发知识和技能
java必备的开发知识和技能 https://blog.csdn.net/qq_34405062/article/details/89389646 学习一下java 其实上学那会儿学的 早就过时加落伍 ...
- [Codeforces 1005F]Berland and the Shortest Paths(最短路树+dfs)
[Codeforces 1005F]Berland and the Shortest Paths(最短路树+dfs) 题面 题意:给你一个无向图,1为起点,求生成树让起点到其他个点的距离最小,距离最小 ...
- springboot2.0结合fastdfs实现文件分布式上传
1. 引入依赖 在父工程中,我们已经管理了依赖,版本为: <fastDFS.client.version>1.26.7</fastDFS.client.version> 因此, ...
- Codeforces 1220C. Substring Game in the Lesson
传送门 首先显然的,如果 $l$ 能移动,那么 $r$ 一定可以随便移动,如果 $l$ 不动,那么 $r$ 一定不能动 那么我们现在只要考虑 $l$ 的移动即可 考虑找到位置 $k$ 之前的最左边的最 ...
- 20.AutoMapper 之理解你的映射(Understanding Your Mappings)
https://www.jianshu.com/p/4f5c14fbf1c2 理解你的映射(Understanding Your Mappings) AutoMapper 为你的映射创建执行计划.在调 ...
- npm学习(四)之如何安装全局包、更新全局安装的包、卸载全局安装的包
如何安装全局包 有两种方式用来安装 npm 包:本地安装和全局安装.选用哪种方式来安装,取决于你如何使用这个包. 如果你想将其作为一个命令行工具,那么你应该将其安装到全局.这种安装方式后可以让你在任何 ...
- 剑指offer-1:旋转数组的最小数字
旋转数组的最小数字1.题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素. 例如数组{3,4,5,1,2}为{1,2 ...
- vue项目1-pizza点餐系统2-配置路由跳转
功能目标:点击导航栏中的菜单.主页.路由跳转到不同的组件,点击谁就在在导航栏下展示谁. 1.在router文件夹中(在用脚手架cli搭建项目时,有个couter的选yes)的index.js中,导入如 ...
- display:inline-block元素之间空隙的产生原因和解决办法
在CSS布局中,如果我们想要将一些元素在同一行显示,其中的一种方法就是把要同行显示的元素设置display属性为inline-block.但是你会发现这些同行显示的inline-block元素之间会出 ...