第5讲小程序微信用户登录实现

小程序微信用户登录实现

小程序登录和jwt,httpclient工具类详细介绍可以看下小锋老师的 小程序电商系统课程:https://www.bilibili.com/video/BV1kP4y1F7tU

application.yml加上小程序登录需要的参数,小伙伴们可以登录小程序后台管理,获取到自己的参数

weixin:jscode2sessionUrl: https://api.weixin.qq.com/sns/jscode2sessionappid: 改成你的secret: 改成你的

定义Properties属性类来映射上面的配置

package com.java1234.properties;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;/*** 微信小程序配置文件* @author java1234_小锋* @site www.java1234.com* @company 南通小锋网络科技有限公司* @create 2022-01-08 17:56*/
@Component
@ConfigurationProperties(prefix = "weixin")
@Data
public class WeixinProperties {private String jscode2sessionUrl; // 登录凭证校验请求地址private String appid; // 小程序 appIdprivate String secret; // 小程序 appSecret}
/*** 微信用户登录* @return*/
@RequestMapping("/wxlogin")
public R wxLogin(@RequestBody WxUserInfo wxUserInfo){String jscode2sessionUrl=weixinProperties.getJscode2sessionUrl()+"?appid="+weixinProperties.getAppid()+"&secret="+weixinProperties.getSecret()+"&js_code="+wxUserInfo.getCode()+"&grant_type=authorization_code";System.out.println(jscode2sessionUrl);String result = httpClientUtil.sendHttpGet(jscode2sessionUrl);System.out.println(result);JSONObject jsonObject= JSON.parseObject(result);String openid = jsonObject.get("openid").toString();System.out.println(openid);// 插入用户到数据库  假如说 用户不存在 我们插入用户  如果用户存在 我们更新用户WxUserInfo resultWxUserInfo = wxUserInfoService.getOne(new QueryWrapper<WxUserInfo>().eq("openid", openid));if(resultWxUserInfo==null){System.out.println("不存在 插入用户");wxUserInfo.setOpenid(openid);wxUserInfo.setRegisterDate(new Date());wxUserInfo.setLastLoginDate(new Date());wxUserInfoService.save(wxUserInfo);}else{System.out.println("存在 更新用户");resultWxUserInfo.setLastLoginDate(new Date());wxUserInfoService.updateById(resultWxUserInfo);}if(resultWxUserInfo!=null && resultWxUserInfo.getStatus().equals("1")){ // 被禁用return R.error(400,"用户被禁用,具体请联系管理员!");}else{// 利用jwt生成token返回到前端String token = JwtUtils.createJWT(openid, wxUserInfo.getNickName(), JwtConstant.JWT_TTL);Map<String,Object> resultMap=new HashMap<>();resultMap.put("token",token);resultMap.put("openid",openid);return R.ok(resultMap);}
}

设置appId

在这里插入图片描述

util

package com.java1234.util;import java.text.SimpleDateFormat;
import java.util.Date;/*** 日期工具类* @author Administrator**/
public class DateUtil {/*** 日期对象转字符串* @param date* @param format* @return*/public static String formatDate(Date date,String format){String result="";SimpleDateFormat sdf=new SimpleDateFormat(format);if(date!=null){result=sdf.format(date);}return result;}/*** 字符串转日期对象* @param str* @param format* @return* @throws Exception*/public static Date formatString(String str,String format) throws Exception{if(StringUtil.isEmpty(str)){return null;}SimpleDateFormat sdf=new SimpleDateFormat(format);return sdf.parse(str);}public static String getCurrentDateStr(){Date date=new Date();SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMddhhmmssSSSSSSSSS");return sdf.format(date);}public static String getCurrentDatePath()throws Exception{Date date=new Date();SimpleDateFormat sdf=new SimpleDateFormat("yyyy/MM/dd/");return sdf.format(date);}public static void main(String[] args) {try {System.out.println(getCurrentDateStr());} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}
package com.java1234.util;import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.DefaultHostnameVerifier;
import org.apache.http.conn.util.PublicSuffixMatcher;
import org.apache.http.conn.util.PublicSuffixMatcherLoader;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Component;import java.io.*;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;/*** httpClient 工具类* @author java1234_小锋* @site www.java1234.com* @company Java知识分享网* @create 2019-02-10 下午 2:49*/
@Component
public class HttpClientUtil {/*** 默认参数设置* setConnectTimeout:设置连接超时时间,单位毫秒。* setConnectionRequestTimeout:设置从connect Manager获取Connection 超时时间,单位毫秒。* setSocketTimeout:请求获取数据的超时时间,单位毫秒。访问一个接口,多少时间内无法返回数据,就直接放弃此次调用。 暂时定义15分钟*/private RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(600000).setConnectTimeout(600000).setConnectionRequestTimeout(600000).build();/*** 静态内部类---作用:单例产生类的实例* @author Administrator**/private static class LazyHolder {    private static final HttpClientUtil INSTANCE = new HttpClientUtil();    }  private HttpClientUtil(){}public static HttpClientUtil getInstance(){return LazyHolder.INSTANCE;    }/*** 发送 post请求* @param httpUrl 地址*/public String sendHttpPost(String httpUrl) {HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost  return sendHttpPost(httpPost);}/*** 发送 post请求* @param httpUrl 地址* @param params 参数(格式:key1=value1&key2=value2)*/public String sendHttpPost(String httpUrl, String params) {HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost  try {//设置参数StringEntity stringEntity = new StringEntity(params, "UTF-8");stringEntity.setContentType("application/x-www-form-urlencoded");httpPost.setEntity(stringEntity);} catch (Exception e) {e.printStackTrace();}return sendHttpPost(httpPost);}/*** 发送 post请求* @param httpUrl 地址* @param maps 参数*/public String sendHttpPost(String httpUrl, Map<String, String> maps) {HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost  // 创建参数队列  List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();for (String key : maps.keySet()) {nameValuePairs.add(new BasicNameValuePair(key, maps.get(key)));}try {httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, "UTF-8"));} catch (Exception e) {e.printStackTrace();}return sendHttpPost(httpPost);}/*** 发送Post请求* @param httpPost* @return*/private String sendHttpPost(HttpPost httpPost) {CloseableHttpClient httpClient = null;CloseableHttpResponse response = null;HttpEntity entity = null;String responseContent = null;try {// 创建默认的httpClient实例httpClient = HttpClients.createDefault();httpPost.setConfig(requestConfig);// 执行请求long execStart = System.currentTimeMillis();response = httpClient.execute(httpPost);long execEnd = System.currentTimeMillis();System.out.println("=================执行post请求耗时:"+(execEnd-execStart)+"ms");long getStart = System.currentTimeMillis();entity = response.getEntity();responseContent = EntityUtils.toString(entity, "UTF-8");long getEnd = System.currentTimeMillis();System.out.println("=================获取响应结果耗时:"+(getEnd-getStart)+"ms");} catch (Exception e) {e.printStackTrace();} finally {try {// 关闭连接,释放资源if (response != null) {response.close();}if (httpClient != null) {httpClient.close();}} catch (IOException e) {e.printStackTrace();}}return responseContent;}/*** 发送 get请求* @param httpUrl*/public String sendHttpGet(String httpUrl) {HttpGet httpGet = new HttpGet(httpUrl);// 创建get请求return sendHttpGet(httpGet);}/*** 发送 get请求Https* @param httpUrl*/public String sendHttpsGet(String httpUrl) {HttpGet httpGet = new HttpGet(httpUrl);// 创建get请求return sendHttpsGet(httpGet);}/*** 发送Get请求* @param httpGet* @return*/private String sendHttpGet(HttpGet httpGet) {CloseableHttpClient httpClient = null;CloseableHttpResponse response = null;HttpEntity entity = null;String responseContent = null;try {// 创建默认的httpClient实例.httpClient = HttpClients.createDefault();httpGet.setConfig(requestConfig);// 执行请求response = httpClient.execute(httpGet);entity = response.getEntity();responseContent = EntityUtils.toString(entity, "UTF-8");} catch (Exception e) {e.printStackTrace();} finally {try {// 关闭连接,释放资源if (response != null) {response.close();}if (httpClient != null) {httpClient.close();}} catch (IOException e) {e.printStackTrace();}}return responseContent;}/*** 发送Get请求Https* @param httpGet* @return*/private String sendHttpsGet(HttpGet httpGet) {CloseableHttpClient httpClient = null;CloseableHttpResponse response = null;HttpEntity entity = null;String responseContent = null;try {// 创建默认的httpClient实例.PublicSuffixMatcher publicSuffixMatcher = PublicSuffixMatcherLoader.load(new URL(httpGet.getURI().toString()));DefaultHostnameVerifier hostnameVerifier = new DefaultHostnameVerifier(publicSuffixMatcher);httpClient = HttpClients.custom().setSSLHostnameVerifier(hostnameVerifier).build();httpGet.setConfig(requestConfig);// 执行请求response = httpClient.execute(httpGet);entity = response.getEntity();responseContent = EntityUtils.toString(entity, "UTF-8");} catch (Exception e) {e.printStackTrace();} finally {try {// 关闭连接,释放资源if (response != null) {response.close();}if (httpClient != null) {httpClient.close();}} catch (IOException e) {e.printStackTrace();}}return responseContent;}/*** 发送xml数据* @param url* @param xmlData* @return* @throws ClientProtocolException* @throws IOException*/public static HttpResponse sendXMLDataByPost(String url, String xmlData)throws ClientProtocolException, IOException {HttpClient httpClient = HttpClients.createDefault();HttpPost httppost = new HttpPost(url);StringEntity entity = new StringEntity(xmlData);httppost.setEntity(entity);httppost.setHeader("Content-Type", "text/xml;charset=UTF-8");HttpResponse response = httpClient.execute(httppost);return response;}/*** 获得响应HTTP实体内容** @param response* @return* @throws IOException* @throws UnsupportedEncodingException*/public static String getHttpEntityContent(HttpResponse response) throws IOException, UnsupportedEncodingException {HttpEntity entity = response.getEntity();if (entity != null) {InputStream is = entity.getContent();BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"));String line = br.readLine();StringBuilder sb = new StringBuilder();while (line != null) {sb.append(line + "\n");line = br.readLine();}return sb.toString();}return "";}}
package com.java1234.util;import com.java1234.constant.JwtConstant;
import com.java1234.entity.CheckResult;
import io.jsonwebtoken.*;
import org.bouncycastle.util.encoders.Base64;import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Date;/*** jwt加密和解密的工具类* @author java1234_小锋* @site www.java1234.com* @company Java知识分享网* @create 2019-08-13 上午 10:06*/
public class JwtUtils {/*** 签发JWT* @param id* @param subject 可以是JSON数据 尽可能少* @param ttlMillis* @return*/public static String createJWT(String id, String subject, long ttlMillis) {SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;long nowMillis = System.currentTimeMillis();Date now = new Date(nowMillis);SecretKey secretKey = generalKey();JwtBuilder builder = Jwts.builder().setId(id).setSubject(subject)   // 主题.setIssuer("Java1234")     // 签发者.setIssuedAt(now)      // 签发时间.signWith(signatureAlgorithm, secretKey); // 签名算法以及密匙if (ttlMillis >= 0) {long expMillis = nowMillis + ttlMillis;Date expDate = new Date(expMillis);builder.setExpiration(expDate); // 过期时间}return builder.compact();}/*** 生成jwt token* @param username* @return*/public static String genJwtToken(String username){return createJWT(username,username,60*60*1000);}/*** 验证JWT* @param jwtStr* @return*/public static CheckResult validateJWT(String jwtStr) {CheckResult checkResult = new CheckResult();Claims claims = null;try {claims = parseJWT(jwtStr);checkResult.setSuccess(true);checkResult.setClaims(claims);} catch (ExpiredJwtException e) {checkResult.setErrCode(JwtConstant.JWT_ERRCODE_EXPIRE);checkResult.setSuccess(false);} catch (SignatureException e) {checkResult.setErrCode(JwtConstant.JWT_ERRCODE_FAIL);checkResult.setSuccess(false);} catch (Exception e) {checkResult.setErrCode(JwtConstant.JWT_ERRCODE_FAIL);checkResult.setSuccess(false);}return checkResult;}/*** 生成加密Key* @return*/public static SecretKey generalKey() {byte[] encodedKey = Base64.decode(JwtConstant.JWT_SECERT);SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");return key;}/*** 解析JWT字符串* @param jwt* @return* @throws Exception*/public static Claims parseJWT(String jwt) {SecretKey secretKey = generalKey();return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwt).getBody();}public static void main(String[] args) throws InterruptedException {//小明失效 10sString sc = createJWT("1","小明", 60 * 60 * 1000);System.out.println(sc);System.out.println(validateJWT(sc).getErrCode());System.out.println(validateJWT(sc).getClaims().getId());System.out.println(validateJWT(sc).getClaims().getSubject());//Thread.sleep(3000);System.out.println(validateJWT(sc).getClaims());Claims claims = validateJWT(sc).getClaims();String sc2 = createJWT(claims.getId(),claims.getSubject(), JwtConstant.JWT_TTL);System.out.println(sc2);}}
package com.java1234.util;import java.util.ArrayList;
import java.util.List;
import java.util.Random;/*** 字符串工具类* @author **/
public class StringUtil {/*** 判断是否是空* @param str* @return*/public static boolean isEmpty(String str){if(str==null||"".equals(str.trim())){return true;}else{return false;}}/*** 判断是否不是空* @param str* @return*/public static boolean isNotEmpty(String str){if((str!=null)&&!"".equals(str.trim())){return true;}else{return false;}}/*** 格式化模糊查询* @param str* @return*/public static String formatLike(String str){if(isNotEmpty(str)){return "%"+str+"%";}else{return null;}}/*** 过滤掉集合里的空格* @param list* @return*/public static List<String> filterWhite(List<String> list){List<String> resultList=new ArrayList<String>();for(String l:list){if(isNotEmpty(l)){resultList.add(l);}}return resultList;}/*** 去除html标签*/public static String stripHtml(String content) { // <p>段落替换为换行 content = content.replaceAll("<p .*?>", "\r\n"); // <br><br/>替换为换行 content = content.replaceAll("<br\\s*/?>", "\r\n"); // 去掉其它的<>之间的东西 content = content.replaceAll("\\<.*?>", ""); // 去掉空格 content = content.replaceAll(" ", ""); return content;   }/*** 生成六位随机数* @return*/public static String genSixRandomNum(){Random random = new Random();String result="";for (int i=0;i<6;i++){result+=random.nextInt(10);}return result;}/*** 生成由[A-Z,0-9]生成的随机字符串* @param length  欲生成的字符串长度* @return*/public static String getRandomString(int length){Random random = new Random();StringBuffer sb = new StringBuffer();for(int i = 0; i < length; ++i){int number = random.nextInt(2);long result = 0;switch(number){case 0:result = Math.round(Math.random() * 25 + 65);sb.append(String.valueOf((char)result));break;case 1:sb.append(String.valueOf(new Random().nextInt(10)));break;}}return sb.toString();}}

constant

package com.java1234.constant;/*** 系统级静态变量* @author java1234_小锋* @site www.java1234.com* @company Java知识分享网* @create 2019-08-13 上午 9:51*/
public class JwtConstant {/*** token*/public static final int JWT_ERRCODE_NULL = 4000;			//Token不存在public static final int JWT_ERRCODE_EXPIRE = 4001;			//Token过期public static final int JWT_ERRCODE_FAIL = 4002;			//验证不通过/*** JWT*/public static final String JWT_SECERT = "8677df7fc3a34e26a61c034d5ec8245d";			//密匙public static final long JWT_TTL = 24*60 * 60 * 1000;									//token有效时间
}

R

package com.java1234.entity;import java.util.HashMap;
import java.util.Map;/*** 页面响应entity* @author java1234_小锋* @site www.java1234.com* @company Java知识分享网* @create 2019-08-13 上午 10:00*/
public class R extends HashMap<String, Object> {private static final long serialVersionUID = 1L;public R() {put("code", 0);}public static R error() {return error(500, "未知异常,请联系管理员");}public static R error(String msg) {return error(500, msg);}public static R error(int code, String msg) {R r = new R();r.put("code", code);r.put("msg", msg);return r;}public static R ok(String msg) {R r = new R();r.put("msg", msg);return r;}public static R ok(Map<String, Object> map) {R r = new R();r.putAll(map);return r;}public static R ok() {return new R();}public R put(String key, Object value) {super.put(key, value);return this;}
}
package com.java1234.entity;import io.jsonwebtoken.Claims;/*** jwt验证信息* @author java1234_小锋* @site www.java1234.com* @company Java知识分享网* @create 2019-08-13 上午 10:00*/
public class CheckResult {private int errCode;private boolean success;private Claims claims;public int getErrCode() {return errCode;}public void setErrCode(int errCode) {this.errCode = errCode;}public boolean isSuccess() {return success;}public void setSuccess(boolean success) {this.success = success;}public Claims getClaims() {return claims;}public void setClaims(Claims claims) {this.claims = claims;}}

requestUtils封装:

// 同时发送异步代码的次数
let ajaxTimes=0;// 定义公共的url
const baseUrl="http://localhost:8866";/*** 返回baseUrl*/
export const getBaseUrl=()=>{return baseUrl;
}/*** 后端请求工具类* @param {*} params 请求参数*/
export const requestUtil=(params)=>{let header={...params.header};// 拼接header 带上tokenheader["token"]=uni.getStorageSync("token");ajaxTimes++;// 显示加载中 效果wx.showLoading({title: "加载中",mask: true});var start = new Date().getTime();// 模拟网络延迟加载while(true)  if(new Date().getTime()-start > 1000*1) break;return new Promise((resolve,reject)=>{wx.request({...params,header:header,url:baseUrl+params.url,success:(result)=>{resolve(result.data);},fail:(err)=>{uni.showToast({icon:'error',title:'连接服务器失败',duration:3000})reject(err);},complete:()=>{ajaxTimes--;if(ajaxTimes===0){//  关闭正在等待的图标wx.hideLoading();}}});})
}

App.vue

<script>import {requestUtil} from "./utils/requestUtil.js"export default {onLaunch: function() {console.log('App Launch')wx.login({timeout: 5000,success:(res)=>{this.wxlogin(res.code);}});},onShow: function() {console.log('App Show')},onHide: function() {console.log('App Hide')},methods:{/*** 请求后端获取用户token* @param {} code */async wxlogin(code){console.log("code="+code)// 发送请求 获取用户的tokenconst result=await requestUtil({url:"/user/wxlogin",data:{code:code},method:"post"});console.log("token="+result.token);console.log("openid="+result.openid);if(result.code==0){console.log("登录成功")uni.setStorageSync("token",result.token);uni.setStorageSync("openid",result.openid);}else{console.log("登录失败,报错信息:"+result.msg);uni.showToast({icon:'error',title:result.msg,duration:3000})}}}}
</script><style>/*每个页面公共css */body,page{background-color: #f4f5f7;}
</style>

//设置默认值为0

  //设置默认值为0private String status="0"; // 用户状态 状态 0 可用 1 封禁
package com.java1234.entity;import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lombok.Data;import java.io.Serializable;
import java.util.Date;/*** 微信用户信息实体* @author java1234_小锋* @site www.java1234.com* @company 南通小锋网络科技有限公司* @create 2022-01-08 15:59*/
@TableName("t_wxUserInfo")
@Data
public class WxUserInfo implements Serializable {private Integer id; // 用户编号private String openid; // 用户唯一标识private String nickName="微信用户"; // 用户昵称private String avatarUrl="default.png"; // 用户头像图片的 URL@JsonSerialize(using=CustomDateTimeSerializer.class)private Date registerDate; // 注册日期@JsonSerialize(using=CustomDateTimeSerializer.class)private Date lastLoginDate; // 最后登录日期//设置默认值为0private String status="0"; // 用户状态 状态 0 可用 1 封禁@TableField(select = false,exist = false)private String code; // 微信用户code 前端传来的}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/465821.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DP读书:《openEuler操作系统》(九)从IPC到网卡到卡驱动程序

DP读书&#xff1a;《openEuler操作系统》从IPC到网卡到卡驱动程序&#xff09; 上章回顾_SPI上节回顾_TCP 网卡驱动程序简介1.设备驱动2.总线与设备3.网卡及其抽象 驱动程序的注册与注销1. 注册2. 注销 设备初始化1. 硬件初始化2. 软件初始化 设备的打开与关闭1. 设备的打开2.…

Stable Diffusion 模型下载:RealCartoon-Pixar - V8

本文收录于《AI绘画从入门到精通》专栏,专栏总目录:点这里。 文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八案例九案例十

《Linux 简易速速上手小册》第10章: 性能监控与优化(2024 最新版)

文章目录 10.1 理解系统负载10.1.1 重点基础知识10.1.2 重点案例&#xff1a;服务器响应变慢10.1.3 拓展案例 1&#xff1a;多核 CPU 系统的负载解读10.1.4 拓展案例 2&#xff1a;分析具体时间段的系统负载 10.2 优化性能10.2.1 重点基础知识10.2.2 重点案例&#xff1a;优化 …

【AI大模型应用开发】【LangChain系列】6. LangChain的Callbacks模块:监控调试程序的重要手段

大家好&#xff0c;我是【同学小张】。持续学习&#xff0c;持续干货输出&#xff0c;关注我&#xff0c;跟我一起学AI大模型技能。 LangChain提供了一个回调系统&#xff0c;允许您挂接到LLM应用程序的各个阶段。这对于日志记录、监视、流式传输和其他任务非常有用。 0. Lang…

代码随想录算法训练营第二九天 | 递增子序列、排列

目录 递增子序列全排列全排列 II LeetCode 491.递增子序列 LeetCode 46.全排列 LeetCode 47.全排列 II 递增子序列 不能使用之前的去重逻辑&#xff01; 同一父节点下的同层上使用过的元素就不能再使用了 题目要求递增子序列大小至少为2&#xff0c;终止条件要限定。 class…

Minecraft的红石教程之电梯

一.前言 我记得是上初中的时候&#xff0c;就看到了这类电梯。现在我在看现在这类电梯的相关视频&#xff0c;大多是盗用创意未能领会其中的红石运作规律&#xff0c;于是我就删繁就简写了这篇。 二.步骤 1.材料 粘性活塞&#xff0c;黏液块&#xff0c;红石&#xff0c;红…

免费数据恢复软件哪个好?适用于 Windows的顶级免费数据恢复软件推荐

终于要说到Windows 11了&#xff0c;有太多令人惊叹的功能&#xff0c;让人跃跃欲试。但是&#xff0c;在升级到 Windows 11 或使用 Windows 11 时&#xff0c;人们可能会因计算机问题而导致文件被删除或丢失。这就是为什么需要 Windows 11 的免费文件恢复的原因。这是适用于 W…

依赖注入的艺术:编写可扩展 JavaScript 代码的秘密

1. 依赖注入 在 JavaScript 中&#xff0c;依赖注入&#xff08;Dependency Injection&#xff0c;简称 DI&#xff09;是一种软件设计模式&#xff0c;通过这种模式&#xff0c;可以减少代码模块之间的紧耦合。依赖注入允许开发者将模块的依赖关系从模块的内部转移到外部&…

SQLyog安装配置(注册码)连接MySQL

下载资源 博主给你打包好了安装包&#xff0c;在网盘里&#xff0c;只有几Mb&#xff0c;防止你下载到钓鱼软件 快说谢谢博主&#xff08;然后心甘情愿的点个赞~&#x1f60a;&#xff09; SQLyog.zip 安装流程 ①下载好压缩包后并解压 ②打开文件夹&#xff0c;双击安装包 ③…

案例:CentOS8 在 MySQL8.0 实现半同步复制

异步复制 MySQL 默认的复制即是异步的&#xff0c;主库在执行完客户端提交的事务后会立即将结果返给给客户端&#xff0c;并不关心从库是否已经接收并处理&#xff0c;这样就会有一个问题&#xff0c;主节点如果 crash 掉了&#xff0c;此时主节点上已经提交的事务可能并没有传…

【C++】函数指针 ③ ( 函数指针语法 | 函数名直接调用函数 | 定义函数指针变量 | 使用 typedef 定义函数类型 | 使用 typedef 定义函数指针类型 )

文章目录 一、函数指针语法1、函数名直接调用函数2、定义函数指针变量3、使用 typedef 定义函数类型4、使用 typedef 定义函数指针类型 二、完整代码示例 一、函数指针语法 1、函数名直接调用函数 定义一个函数 , 如下 函数的类型是 int(int, int) ; int add(int x, int y) {p…

【必看】Onlyfans如何使用搜索功能?Onlyfans如何搜索博主?如何在OnlyFans搜索HongkongDoll

1. 什么是Onlyfans OnlyFans是一种内容订阅服务平台&#xff0c;它成立于2016年。 它允许内容创作者在平台上面分享自己的创作&#xff0c;如图片、视频等等&#xff0c;用户需要支付订阅费用才能查看创作者的内容。此外&#xff0c;用户还可以通过打赏的方式来让创作者为自己…