微信小程序后端(java)开发流程的详细步骤
微信小程序后端开发流程根据官网总结为两个步骤
1、前端调用wx.login返回了code,然后调用wx.getUserInfo获取到用户的昵称头像
2、服务端根据code去微信获取openid,接口地址:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html%EF%BC%9B%E5%90%8C%E6%97%B6%EF%BC%8C%E6%9B%B4%E6%96%B0%E7%94%A8%E6%88%B7%E6%98%B5%E7%A7%B0%E5%A4%B4%E5%83%8F%E7%AD%89%E8%B5%84%E6%96%99
微信小程序后端接口开发
controller层
publicclassOauthController{ @Autowired privateWeChatServiceweChatService; /** *微信授权用js_code换取openId *@paramcode *@return */ @GetMapping("/code2Session") publicBaseResponsecode2Session(Stringcode){ log.info("code2Session,code={}",code); if(StringUtil.isEmpty(code)){ returnBaseResponse.buildFail("参数异常"); } Code2SessionResponseres=weChatService.code2Session(code); log.info("code2Session,res={}",res); if(!res.isSuccess()){ returnBaseResponse.buildFail(res.getErrCode(),res.getErrMsg()); } returnBaseResponse.buildSuccess(res); } /** *解密获取手机号 *@paramrequest *@paramresponse *@paramparam *@return */ publicBaseResponsedecryptGetPhone(HttpServletRequestrequest,HttpServletResponseresponse, @RequestBodyOauthParamparam){ if(!StringUtil.isEmpty(param.getOpenId())){//微信授权登录 StringsessionKey=weChatService.getSessionKey(param.getOpenId()); if(StringUtil.isEmpty(sessionKey)){ returnBaseResponse.buildFail("会话不存在"); } Sha1Utilssha=newSha1Utils(); //获取用户信息 log.debug("微信登陆sessionKey={}",sessionKey); StringuserInfoStr=sha.decryptWXAppletInfo(sessionKey,param.getEncryptedData(),param.getIv()); if(StringUtil.isEmpty(userInfoStr)){ returnBaseResponse.buildFail("无法获取用户信息"); } JSONObjectjson=JSONObject.parseObject(userInfoStr); //绑定微信的手机号 Stringtel=json.getString("purePhoneNumber"); Assert.isTrue(!StringUtils.isEmpty(tel),"无法获取用户手机号"); BaseResponsebaseResponse=newBaseResponse(); baseResponse.setResultInfo(tel); baseResponse.setState(0); returnbaseResponse; } } }
接口
publicinterfaceWeChatService{ /** *用code换取openid * *@paramcode *@return */ Code2SessionResponsecode2Session(Stringcode); /** *获取凭证 * *@return */ StringgetAccessToken(); /** *获取凭证 * *@paramisForce *@return */ StringgetAccessToken(booleanisForce); StringgetSessionKey(StringopenId); }
实现类
publicclassWeChatServiceImplimplementsWeChatService{ //获取配置文件数据 @Value("${wechat.miniprogram.id}") privateStringappId; @Value("${wechat.miniprogram.secret}") privateStringappSecret; @Reference privateSysUserServicesysUserService; @Override publicCode2SessionResponsecode2Session(Stringcode){ StringrawResponse=HttpClientUtil .get(String.format(WechatConstant.URL_CODE2SESSION,appId,appSecret,code)); log.info("rawResponse====={}",rawResponse); Code2SessionResponseresponse=JSON.parseObject(rawResponse,Code2SessionResponse.class); if(response.isSuccess()){ cacheSessionKey(response); } returnresponse; } privatevoidcacheSessionKey(Code2SessionResponseresponse){ RedisCacheredisCache=RedisCache.getInstance(); Stringkey=RedisCacheKeys.getWxSessionKeyKey(response.getOpenId()); redisCache.setCache(key,2147483647,response.getSessionKey()); } @Override publicStringgetAccessToken(){ returngetAccessToken(false); } @Override publicStringgetAccessToken(booleanisForce){ RedisCacheredisCache=RedisCache.getInstance(); StringaccessToken=null; if(!isForce){ accessToken=redisCache.getCache(RedisCacheKeys.getWxAccessTokenKey(appId)); } if(StringUtil.isNotEmpty(accessToken)){ returnaccessToken; } StringrawResponse=HttpClientUtil .get(String.format(WechatConstant.URL_GET_ACCESS_TOKEN,appId,appSecret)); AccessTokenResponseresponse=JSON.parseObject(rawResponse,AccessTokenResponse.class); log.info("getAccessToken:response={}",response); if(response.isSuccess()){ redisCache.setCache(RedisCacheKeys.getWxAccessTokenKey(appId),7000,response.getAcessToken()); returnresponse.getAcessToken(); } returnnull; } @Override publicStringgetSessionKey(StringopenId){ RedisCacheredisCache=RedisCache.getInstance(); Stringkey=RedisCacheKeys.getWxSessionKeyKey(openId); StringsessionKey=redisCache.getCache(key); returnsessionKey; } }
用到的解密工具类
publicclassSha1Utils{ publicstaticStringdecryptWXAppletInfo(StringsessionKey,StringencryptedData,Stringiv){ Stringresult=null; try{ byte[]encrypData=Base64.decodeBase64(encryptedData); byte[]ivData=Base64.decodeBase64(iv); byte[]sessionKeyB=Base64.decodeBase64(sessionKey); AlgorithmParameterSpecivSpec=newIvParameterSpec(ivData); Ciphercipher=Cipher.getInstance("AES/CBC/PKCS5Padding"); SecretKeySpeckeySpec=newSecretKeySpec(sessionKeyB,"AES"); cipher.init(Cipher.DECRYPT_MODE,keySpec,ivSpec); byte[]doFinal=cipher.doFinal(encrypData); result=newString(doFinal); returnresult; }catch(Exceptione){ //e.printStackTrace(); log.error("decryptWXAppletInfoerror",e); } returnnull; } }
网络请求工具类
publicclassHttpClientUtil{ //utf-8字符编码 publicstaticfinalStringCHARSET_UTF_8="utf-8"; //HTTP内容类型。 publicstaticfinalStringCONTENT_TYPE_TEXT_HTML="text/xml"; //HTTP内容类型。相当于form表单的形式,提交数据 publicstaticfinalStringCONTENT_TYPE_FORM_URL="application/x-www-form-urlencoded"; //HTTP内容类型。相当于form表单的形式,提交数据 publicstaticfinalStringCONTENT_TYPE_JSON_URL="application/json;charset=utf-8"; //连接管理器 privatestaticPoolingHttpClientConnectionManagerpool; //请求配置 privatestaticvolatileRequestConfigrequestConfig; privatestaticCloseableHttpClientgetNewHttpClient(){ CloseableHttpClienthttpClient=HttpClients.custom() //设置连接池管理 .setConnectionManager(pool) //设置请求配置 .setDefaultRequestConfig(getRequestConfig()) //设置重试次数 .setRetryHandler(newDefaultHttpRequestRetryHandler(0,false)).build(); returnhttpClient; } /** *发送post请求 * *@paramhttpUrl *地址 */ publicstaticStringpost(StringhttpUrl){ //创建httpPost HttpPosthttpPost=newHttpPost(httpUrl); returnrequest(httpPost); } publicstaticbyte[]postRaw(StringhttpUrl){ //创建httpPost HttpPosthttpPost=newHttpPost(httpUrl); returnrequestRaw(httpPost); } /** *发送get请求 * *@paramhttpUrl */ publicstaticStringget(StringhttpUrl){ //创建get请求 HttpGethttpGet=newHttpGet(httpUrl); returnrequest(httpGet); } /** *发送post请求(带文件) * *@paramhttpUrl *地址 *@parammaps *参数 *@paramfileLists *附件 */ publicstaticStringpost(StringhttpUrl,Mapmaps,List fileLists, StringfileName){ HttpPosthttpPost=newHttpPost(httpUrl);//创建httpPost MultipartEntityBuildermeBuilder=MultipartEntityBuilder.create(); if(maps!=null){ for(Stringkey:maps.keySet()){ meBuilder.addPart(key,newStringBody(maps.get(key),ContentType.TEXT_PLAIN)); } } if(fileLists!=null){ for(Filefile:fileLists){ FileBodyfileBody=newFileBody(file); meBuilder.addPart(fileName,fileBody); } } HttpEntityreqEntity=meBuilder.build(); httpPost.setEntity(reqEntity); returnrequest(httpPost); } publicstaticStringpost(StringhttpUrl,Map maps,List fileLists){ returnpost(httpUrl,maps,fileLists,"file"); } publicstaticStringpost(StringhttpUrl,List fileLists){ returnpost(httpUrl,Collections.emptyMap(),fileLists,"file"); } /** *发送post请求 * *@paramhttpUrl *地址 *@paramparams *参数(格式:key1=value1&key2=value2) * */ publicstaticStringpost(StringhttpUrl,Stringparams){ HttpPosthttpPost=newHttpPost(httpUrl);//创建httpPost try{ //设置参数 if(params!=null&¶ms.trim().length()>0){ StringEntitystringEntity=newStringEntity(params,"UTF-8"); stringEntity.setContentType(CONTENT_TYPE_FORM_URL); httpPost.setEntity(stringEntity); } }catch(Exceptione){ e.printStackTrace(); } returnrequest(httpPost); } /** *发送post请求 * *@parammaps *参数 */ publicstaticStringpost(StringhttpUrl,Map maps){ Stringparam=convertStringParamter(maps); returnpost(httpUrl,param); } /** *发送post请求发送json数据 * *@paramhttpUrl *地址 *@paramcontent * * */ publicstaticStringpost(StringhttpUrl,Stringcontent,StringcontentType){ //HttpPosthttpPost=newHttpPost(httpUrl);//创建httpPost //try{ ////设置参数 //if(StringUtils.isNotEmpty(content)){ //StringEntitystringEntity=newStringEntity(content,"UTF-8"); //stringEntity.setContentType(contentType); //httpPost.setEntity(stringEntity); //} //}catch(Exceptione){ //e.printStackTrace(); //} //returnrequest(httpPost); returnnewString(postRaw(httpUrl,content,contentType),StandardCharsets.UTF_8); } publicstaticbyte[]postRaw(StringhttpUrl,Stringcontent,StringcontentType){ HttpPosthttpPost=newHttpPost(httpUrl);//创建httpPost try{ //设置参数 if(StringUtils.isNotEmpty(content)){ StringEntitystringEntity=newStringEntity(content,"UTF-8"); stringEntity.setContentType(contentType); httpPost.setEntity(stringEntity); } }catch(Exceptione){ e.printStackTrace(); } returnrequestRaw(httpPost); } /** *发送post请求发送json数据 * *@paramhttpUrl *地址 *@paramparamsJson *参数(格式json) * */ publicstaticStringpostJson(StringhttpUrl,StringparamsJson){ returnpost(httpUrl,paramsJson,CONTENT_TYPE_JSON_URL); } publicstaticbyte[]postJsonRaw(StringhttpUrl,StringparamsJson){ returnpostRaw(httpUrl,paramsJson,CONTENT_TYPE_JSON_URL); } /** *发送post请求发送xml数据 * *@paramurl地址 *@paramparamsXml参数(格式Xml) * */ publicstaticStringpostXml(Stringurl,StringparamsXml){ returnpost(url,paramsXml,CONTENT_TYPE_TEXT_HTML); } /** *将map集合的键值对转化成:key1=value1&key2=value2的形式 * *@paramparameterMap *需要转化的键值对集合 *@return字符串 */ publicstaticStringconvertStringParamter(MapparameterMap){ StringBuilderparameterBuffer=newStringBuilder(); if(parameterMap!=null){ Iteratoriterator=parameterMap.keySet().iterator(); Stringkey=null; Stringvalue=null; while(iterator.hasNext()){ key=(String)iterator.next(); if(parameterMap.get(key)!=null){ value=(String)parameterMap.get(key); }else{ value=""; } parameterBuffer.append(key).append("=").append(value); if(iterator.hasNext()){ parameterBuffer.append("&"); } } } returnparameterBuffer.toString(); } /** *发送请求 * *@paramrequest *@return */ publicstaticbyte[]requestRaw(HttpRequestBaserequest){ CloseableHttpClienthttpClient; CloseableHttpResponseresponse=null; //响应内容 //StringresponseContent=null; byte[]rawResponse=null; try{ //创建默认的httpClient实例. httpClient=getNewHttpClient(); //配置请求信息 request.setConfig(requestConfig); //执行请求 response=httpClient.execute(request); //得到响应实例 HttpEntityentity=response.getEntity(); //可以获得响应头 //Header[]headers=response.getHeaders(HttpHeaders.CONTENT_TYPE); //for(Headerheader:headers){ //System.out.println(header.getName()); //} //得到响应类型 //System.out.println(ContentType.getOrDefault(response.getEntity()).getMimeType()); //判断响应状态 if(response.getStatusLine().getStatusCode()>=300){ thrownewException("HTTPRequestisnotsuccess,Responsecodeis" +response.getStatusLine().getStatusCode()); } if(HttpStatus.SC_OK==response.getStatusLine().getStatusCode()){ rawResponse=EntityUtils.toByteArray(entity); //responseContent=EntityUtils.toString(entity,CHARSET_UTF_8); EntityUtils.consume(entity); } }catch(Exceptione){ e.printStackTrace(); }finally{ try{ //释放资源 if(response!=null){ response.close(); } }catch(IOExceptione){ e.printStackTrace(); } } returnrawResponse; } privatestaticStringrequest(HttpRequestBasereq){ returnnewString(requestRaw(req),StandardCharsets.UTF_8); } privatestaticRequestConfiggetRequestConfig(){ if(requestConfig==null){ synchronized(HttpClientUtil.class){ if(requestConfig==null){ try{ //System.out.println("初始化HttpClientTest~~~开始"); SSLContextBuilderbuilder=newSSLContextBuilder(); builder.loadTrustMaterial(null,newTrustSelfSignedStrategy()); SSLConnectionSocketFactorysslsf=newSSLConnectionSocketFactory( builder.build()); //配置同时支持HTTP和HTPPS Registry socketFactoryRegistry=RegistryBuilder . create() .register("http",PlainConnectionSocketFactory.getSocketFactory()) .register("https",sslsf).build(); //初始化连接管理器 pool=newPoolingHttpClientConnectionManager(socketFactoryRegistry); //将最大连接数增加到200,实际项目最好从配置文件中读取这个值 pool.setMaxTotal(200); //设置最大路由 pool.setDefaultMaxPerRoute(2); //根据默认超时限制初始化requestConfig intsocketTimeout=10000; intconnectTimeout=10000; intconnectionRequestTimeout=10000; requestConfig=RequestConfig.custom() .setConnectionRequestTimeout(connectionRequestTimeout) .setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout) .build(); }catch(NoSuchAlgorithmExceptione){ e.printStackTrace(); }catch(KeyStoreExceptione){ e.printStackTrace(); }catch(KeyManagementExceptione){ e.printStackTrace(); } //设置请求超时时间 requestConfig=RequestConfig.custom().setSocketTimeout(50000) .setConnectTimeout(50000).setConnectionRequestTimeout(50000).build(); } } } returnrequestConfig; } }
常量
publicinterfaceWechatConstant{ IntegerOK_STATUS=0; StringURL_CODE2SESSION="https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code"; StringURL_GET_ACCESS_TOKEN="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"; StringURL_GET_IMAGE="http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=%s&media_id=%s"; /** *给公众号发送信息。参考https://mp.weixin.qq.com/advanced/tmplmsg?action=faq&token=708366329&lang=zh_CN */ StringURL_SEND_TO_CHANNEL="https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s"; StringURL_SEND_MESSAGE="https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=%s"; /** *发送模板消息。参考https://developers.weixin.qq.com/miniprogram/dev/api-backend/sendMiniTemplateMessage.html */ StringURL_SEND_TEMPLATE_MESSAGE="https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=%s"; StringURL_QR_CODE_UNLIMTED="https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=%s"; StringURL_QR_CODE="https://api.weixin.qq.com/wxa/getwxacode?access_token=%s"; /** *获取标签下粉丝列表 */ StringURL_ALL_FANS_OPENID="https://api.weixin.qq.com/cgi-bin/user/tag/get?access_token=%s"; /** *获取公众号已创建的标签 */ StringURL_ALL_TAGS="https://api.weixin.qq.com/cgi-bin/tags/get?access_token=%s"; }
使用到的实体类
publicclassCode2SessionResponseimplementsSerializable{ publicstaticIntegerRESPONSE_OK=0; @JSONField(name="openid") privateStringopenId; @JSONField(name="session_key") privateStringsessionKey; @JSONField(name="unionid") privateStringunionId; @JSONField(name="errcode") privateIntegererrCode; @JSONField(name="errmsg") privateStringerrMsg; publicbooleanisSuccess(){ returnthis.errCode==null||RESPONSE_OK.equals(this.errCode); } }
总结:微信小程序的后端开发主要就是对用户进行授权,1、前端调用wx.login返回了code,然后调用wx.getUserInfo获取到用户的昵称头像2.首先通过微信授权用js_code换取openId,来获取openId,前端传微信的参数code字段3.然后解密获取手机号前端需要传openIdencryptedDataiv等字段来获取用户的的授权手机号
这些信息都获取后接着就是调用后端的登陆接口,登陆接口如果只有授权登录就是我们将接口参数为下图最后三个字段为前端必填字段
通过解密获取授权登录的手机号,然后根据自己的业务逻辑处理即可,这样我们就可以根据授权的手机号进行授权登录
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。