【公众号开发】Access Token的获取 · 请求公众号服务器创建自定义菜单 · 处理自定义菜单按钮事件

news2024/11/18 11:22:58

【公众号开发】(3)

在这里插入图片描述

文章目录

  • 【公众号开发】(3)
    • 1. 获取Access token
      • 1.1 确定参数
      • 1.2 补全URL(添加query string)
      • 1.3 测试
    • 2. 封装AccessToken以便保存与后期使用
      • 2.1 TokenUtils做出一些调整
      • 2.2 单例模式的AccessToken
      • 2.3 TokenUtils获取全局唯一的token字符串的方法
    • 3. 自定义菜单
      • 3.1 菜单显示的原理
      • 3.2 封装菜单类
      • 3.3 构造一个菜单对象
      • 3.4 发送post请求
      • 3.5 启动main方法查看效果
    • 4. 处理自定义菜单事件
      • 4.1 了解公众号发过来的post请求机制
      • 4.2 了解公众号发过来的post请求格式
      • 4.3 分支处理请求
      • 4.4 测试

【公众号开发】(3)

开始开发 / 获取 Access token (qq.com)

access_token是公众号的全局唯一的接口调用凭据,公众号调用各接口时都需使用access_token

开发者需要进行妥善保存

  1. access_token的存储至少要保留512个字符空间
  2. access_token的有效期目前为2个小时(7200s),需定时刷新,重复获取将导致上次获取的access_token失效

获取到Access token,我们才能够去调用微信公众号给我们提供的一些接口(Access token就类似于第三方接口的key,验证凭据后才可以去实现一些功能)

1. 获取Access token

这里是几张来自文档的重点截图:

在这里插入图片描述

在这里插入图片描述

1.1 确定参数

在这里插入图片描述

public class TokenUtils {


    private static final String APP_ID = "wxdadd0122365919e8";

    private static final String APP_SECRET = "69fd4a3ad04167f288e49bea9dce3e45";


    public static String getAccessToken() {
        // 获取token的url
        final String URL = "https://api.weixin.qq.com/cgi-bin/token";
        // 获取token的grant_type
        final String GRANT_TYPE = "client_credential";

    }

}

1.2 补全URL(添加query string)

public static String getAccessToken() {
    // 获取token的url
    final String URL = "https://api.weixin.qq.com/cgi-bin/token";
    // 获取token的grant_type
    final String GRANT_TYPE = "client_credential";
    // 构造参数表
    Map<String, Object> param = new HashMap<String, Object>(){{
        this.put("grant_type", GRANT_TYPE);
        this.put("appid", APP_ID);
        this.put("secret", APP_SECRET);
    }};
    // 发起get请求
    String response = HttpUtils.doGet(URL, param);
    // 解析json
    Map<String, Object> result = JsonUtils.jsonToMap(response);
    System.out.println(result);
    // 返回token
    return (String) result.get("access_token");
}

1.3 测试

public static void main(String[] args) {
    System.out.println(getAccessToken());
}

在这里插入图片描述

2. 封装AccessToken以便保存与后期使用

这里我们全局的AccessToken唯一一份,我们希望其未过期就无需刷新,这里用的是**单例模式**!

2.1 TokenUtils做出一些调整

为了实现这个初心,在TokenUtils做出一些调整

在这里插入图片描述

  • 改为获取map

2.2 单例模式的AccessToken

  • 单例模式参考文章:【JavaEE】线程案例-单例模式 and 阻塞队列_s:103的博客-CSDN博客
@Data
public class AccessToken {

    private String token;

    private long expireTime;//有效期限


    volatile private static AccessToken accessToken = null;

    public void setExpireTime(long expireIn) {
        // 设置有效期限的时候的时间戳
        this.expireTime = System.currentTimeMillis() + expireIn * 1000;
    }

    public boolean isExpired() {
        return System.currentTimeMillis() > this.getExpireTime();
    }


    private static void setAccessToken() {
        if(accessToken == null) {
            accessToken = new AccessToken();
        }
        Map<String, Object> map = TokenUtils.getAccessTokenMap();
        accessToken.setToken((String) map.get("access_token"));
        accessToken.setExpireTime((Integer) map.get("expires_in"));
    }

    public static AccessToken getAccessToken() {
        if(accessToken == null || accessToken.isExpired()) {
            synchronized (AccessToken.class) {
                if(accessToken == null || accessToken.isExpired()) {
                    setAccessToken();
                }
            }
        }
        return accessToken;
    }

}

2.3 TokenUtils获取全局唯一的token字符串的方法

public static String getToken() {
    return AccessToken.getAccessToken().getToken();
}

测试

public static void main(String[] args) {
    System.out.println(getToken());
    System.out.println(getToken());
    System.out.println(getToken());
}

在这里插入图片描述

  • 三个一样,代表我们的AccessToken单例第一次被实例和设置并且因为没有过期而没有被更新~

有了凭据之后,我们就可以去调用微信公众号给我们提供的一些接口了,实现一些功能~

3. 自定义菜单

你会发现,我们的测试公众号现在还没有菜单的选项

在这里插入图片描述

而我们的常识也知道,公众号的菜单是必不可少的,接下来我们来完成一下自定义菜单吧

在这里插入图片描述

开发手册:自定义菜单 / 创建接口 (qq.com)

抓重点:

在这里插入图片描述

  • 按字数截取…
  • 刷新策略我们创建后再讲

自定义菜单接口,就相当于触发各种各样事件

在这里插入图片描述

3.1 菜单显示的原理

在这里插入图片描述
我们提交的信息会给公众号服务器保存起来,构造成菜单显示给用户~

这里我们来看个post请求body的例子:

  • (要求是json,这也合理,因为我们要传递的信息就是多个菜单,多级菜单,这个可是对象~)

在这里插入图片描述

我们需要什么功能,我们就查看与学习对应的按钮类型和其他参数就行了

  • 自定义菜单 / 创建接口 (qq.com)

3.2 封装菜单类

对于这个post请求的body,也就是这个json字符串的构造,是最大的问题,我们首先要封装菜单类

@Data
public class Button {

    private List<AbstractButton> button;

}

这是构造最外层的button属性:

{
    "button": [...]
}

AbstractButton是我们抽象出来的按钮类(可以是一些按钮/二级菜单)

@Data
public abstract class AbstractButton {

    private String name;

    public AbstractButton(String name) {
        this.name = name;
    }
    public AbstractButton() {
        
    }
}

这个name属性是按钮/二级菜单的共性(二级菜单没有type,所以这里不应该写type)

根据刚才的json字符串,里面提到的属性就是对应类型按钮的属性~

以这几个为示例(其他根据实际举一反三就行):

在这里插入图片描述

@Data
public class ViewButton extends AbstractButton {

    private final String type = "view";

    private String url;

    public ViewButton(String name) {
        super(name);
    }
}

在这里插入图片描述

@Data
public class ClickButton extends AbstractButton {

    private final String type = "click";

    private String key;

    public ClickButton(String name) {
        super(name);
    }

}

在这里插入图片描述

@Data
public class PicPhotoOrAlbumButton extends AbstractButton {

    private final String type = "pic_photo_or_album";

    private String key;


    public PicPhotoOrAlbumButton(String name) {
        super(name);
    }
}

在这里插入图片描述

@Data
public class SubButton extends AbstractButton {

    private List<AbstractButton> sub_button;


    public SubButton(String name) {
        super(name);
    }
}

3.3 构造一个菜单对象

预计菜单效果如下:

在这里插入图片描述

public class ButtonUtils {

    public static Button createButton() {
        Button button = new Button();
        button.setButton(new ArrayList<>());
        return button;
    }

    public static ClickButton createClickButton(String name, String key) {
        ClickButton clickButton = new ClickButton(name);
        clickButton.setKey(key);
        return clickButton;
    }

    public static ViewButton createViewButton(String name, String url) {
        ViewButton viewButton = new ViewButton(name);
        viewButton.setUrl(url);
        return viewButton;
    }

    public static SubButton createSubButton(String name) {
        SubButton subButton = new SubButton(name);
        subButton.setSub_button(new ArrayList<>());
        return subButton;
    }
    public static PicPhotoOrAlbumButton createPicPhotoOrAlbumButton(String name, String key) {
        PicPhotoOrAlbumButton picPhotoOrAlbumButton = new PicPhotoOrAlbumButton(name);
        picPhotoOrAlbumButton.setKey(key);
        return picPhotoOrAlbumButton;
    }



    public static void main(String[] args) {
        Button button = createButton();
        // 一级菜单的两个按钮
        button.getButton().add(createClickButton("mara\uD83D\uDE00😀😀😀", "1"));
        button.getButton().add(createViewButton("baidu\uD83D\uDE00", "https://www.baidu.com"));
        // 二级菜单
        SubButton subButton = createSubButton("更多\uD83D\uDE00");
        subButton.getSub_button().add(createClickButton("mason\uD83D\uDE00", "2"));
        subButton.getSub_button().add(createViewButton("blog\uD83D\uDE00", "https://blog.csdn.net/Carefree_State?type=blog"));
        subButton.getSub_button().add(createPicPhotoOrAlbumButton("上传图片\uD83D\uDE00", "3"));
        // 二级菜单加入到一级菜单中
        button.getButton().add(subButton);
//        System.out.println(button);
        String json = JsonUtils.objectToJson(button);
        System.out.println(json);
    }
}

emoji可以直接复制或者用unicode码,本质没啥区别,跟普通字符差不多:

  • 之前我做的网站,文本中有emoji是不行的,因为我的服务器并不支持emoji存到数据库
  • 可以这样:👨‍💻你知道如何使用MySQL存储Emoji表情吗?明白MySQL中UTF-8和UTF-8MB4字符编码有何区别吗? - 知乎 (zhihu.com)

Unicode 11.0版本的emoji表情 - emoji大全,emoji百科 (emojidaquan.com)

打印json后查看效果:

在这里插入图片描述

在线 JSON 解析 | 菜鸟工具 (runoob.com)

在这里插入图片描述

在这里插入图片描述

😊符合预期😊

对于json集合属性的序列,各个元素json字符串都不一样或者有联系,可以试试抽象成一个类,具体类继承这个抽象类,序列化的时候序列的是具体的实例

或者,你干脆写成List<Object>也行,序列化的时候自然知道这个Object是谁向上转型来的,序列化也能正确,不过每个按钮都有name的~

3.4 发送post请求

url的创建:

  1. https://api.weixin.qq.com/cgi-bin/menu/create,访问的接口~
  2. queryString:携带我们的access_token,调用方法获取即可~
// 构造url
String url = " https://api.weixin.qq.com/cgi-bin/menu/create" + HttpUtils.getQueryString(new HashMap<String, Object>() {{
    this.put("access_token", TokenUtils.getToken());
}});
// 发送post请求
String response = HttpUtils.doPost(url, json);
System.out.println(response);

这里,doPost是区别于提交form格式的doPost的一个重载方法,作用就是根据url,提交json字符串:

public static String doPost(String httpUrl, String json) {
    HttpURLConnection connection = null;
    InputStream inputStream = null;
    OutputStream outputStream = null;
    BufferedReader bufferedReader = null;
    String result = null;
    try {
        URL url = new URL(httpUrl);
        // 通过远程url连接对象打开连接
        connection = (HttpURLConnection) url.openConnection();
        // 设置连接请求方式
        connection.setRequestMethod("POST");
        // 设置连接主机服务器超时时间:15000毫秒
        connection.setConnectTimeout(15000);
        // 设置读取主机服务器返回数据超时时间:60000毫秒
        connection.setReadTimeout(60000);
        // 默认值为:false,当向远程服务器传送数据/写数据时,需要设置为true
        connection.setDoOutput(true);
        // 设置传入参数的格式:请求参数应该是 name1=value1&name2=value2 的形式。
        connection.setRequestProperty("Content-Type", "application/json; charset=utf-8");
        // 通过连接对象获取一个输出流
        outputStream = connection.getOutputStream();
        // 通过输出流对象将参数写出去/传输出去,它是通过字节数组写出的
        outputStream.write(json.getBytes());
        // 通过连接对象获取一个输入流,向远程读取
        if (connection.getResponseCode() == 200) {
            inputStream = connection.getInputStream();
            // 对输入流对象进行包装:charset根据工作项目组的要求来设置
            bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
            StringBuilder sbf = new StringBuilder();
            String temp;
            // 循环遍历一行一行读取数据
            while ((temp = bufferedReader.readLine()) != null) {
                sbf.append(temp);
                sbf.append(System.getProperty("line.separator"));
            }
            result = sbf.toString();
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        // 关闭资源
        if (null != bufferedReader) {
            try {
                bufferedReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (null != outputStream) {
            try {
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (null != inputStream) {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (connection != null) {
            connection.disconnect();
        }
    }
    return result;
}

在这里插入图片描述

3.5 启动main方法查看效果

在这里插入图片描述

微信公众号查看:

在这里插入图片描述

点击baidu😀(view按钮)跳转:

在这里插入图片描述

点击更多😀上拉菜单:

在这里插入图片描述

点击上传按钮(photo按钮)😀:

在这里插入图片描述

对于click按钮,点击了似乎没什么作用,接下来俺们来研究研究这个!

4. 处理自定义菜单事件

其实,用户每点击一次按钮,就相当于与公众号交互,对于这个“按钮事件”,消息类型为Event

也就是这里的其他消息类型:

在这里插入图片描述

而只要是用户发来的消息,都会触发公众号服务器发送post请求到我们的服务器的根路径

  • 也就是之前写的那个接口一致

在这里插入图片描述

开发文档:基础消息能力 / 接收事件推送 (qq.com)

在这里插入图片描述

以自定义菜单事件为例,其他的举一反三、自行学习😊

这里以click按钮为例子!

4.1 了解公众号发过来的post请求机制

在这里插入图片描述

如果是上拉菜单的按钮,则不会上报,也就是不会发post请求

  • 或者是弹出“拍照/上传图片”,这也算是子菜单吧,等等类似的~

4.2 了解公众号发过来的post请求格式

在这里插入图片描述

在这里插入图片描述

这个key,就是我们之前的按钮属性里的key:

在这里插入图片描述

这个key对于公众号服务器而已没啥作用,但是对于开发者而言很重要,因为post请求访问的是同一个接口,并且,请求并没有发送按钮名参数,并且按钮名也不一定唯一,开发者用按钮名来区分每个按钮不合理!

所以有公众号辅助我们,以key为按钮的标识,作为参数传递给开发者

开发者以key作为区分按钮触发事件的手段,不同的key执行不同的业务~

4.3 分支处理请求

对于不同的消息类型、不同的事件类型、不同的key,你可以用哈希表记录“键与业务方法”,这里的业务方法可以是一个接口,用普通类去实现接口,最后结合多态实现,输入键执行对于业务

这里我为了方便,易懂,任意演示/调试,用的是swtich分支处理

@PostMapping("/")
public String receiveMessage(HttpServletRequest request) throws IOException {
    String body = HttpUtils.getBody(request);
    Map<String, Object> map = XmlUtils.xmlToMap(body);
    System.out.println(map);
    // 回复消息
    String message = "";
    String MsgType = (String) map.get("MsgType");
    switch (MsgType) {
        case "event":
            message = handleEvent(map);//处理事件
            break;
        case "text":
            message = handleText(map);//处理文本
            break;
        default:
            System.out.println("其他消息类型");
            break;
    }
    return message;
}
  • message返回空字符串才是正常的不回复,其他都是因为错误而不回复的

handleText:

private String handleText(Map<String, Object> map) {
    String message = "";
    if("图文".equals(map.get("Content"))) {
        NewsMessage newsMessage = NewsMessage.getReplyNewsMessage(map);
        message = XmlUtils.objectToXml(newsMessage);
        System.out.println(message);
    }else {
        // 1. 封装对象
        TextMessage textMessage = TextMessage.getAntonym(map);
        // 2. 序列化对象
        message = XmlUtils.objectToXml(textMessage);
    }
    return message;
}

handleEvent:

  • 通过事件类型分支
private String handleEvent(Map<String, Object> map) {
    String message = "";
    // 获取event值
    String event = (String) map.get("Event");
    // 事件分支
    switch (event) {
        case "CLICK":
            message = EventUtils.handleClick(map);
            break;
        case "VIEW":
            System.out.println("view");
            break;
        default:
            break;
    }
    return message;
}

EventUtils.handleClick:

public class EventUtils {
    public static String handleClick(Map<String, Object> map) {
        String message = "";
        String key = (String) map.get("EventKey");
        switch (key) {
            case "1":
                map.put("Content","\"触发了点击事件,key = 1\"");
                break;
            case "2":
                map.put("Content","\"触发了点击事件,key = 2\"");
                break;
            case "3":
                map.put("Content","\"触发了点击事件,key = 3\"");
                break;
            default:
                break;
        }
        TextMessage textMessage = TextMessage.getReplyTextMessage(map);
        message = XmlUtils.objectToXml(textMessage);
        return message;
    }
}

这个只是示例,至于你要执行什么业务,是你的事咯

4.4 测试

在这里插入图片描述

在这里插入图片描述

点击view类型按钮:

在这里插入图片描述

查看控制台:

在这里插入图片描述

还是那句话,这个只是示例,至于你要执行什么业务,是你的事咯

举一反三,由你发挥,一生万物!


文章到此结束!谢谢观看
可以叫我 小马,我可能写的不好或者有错误,但是一起加油鸭🦆

代码:wx-demo · 游离态/马拉圈2023年10月 - 码云 - 开源中国 (gitee.com)


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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

YOLOv5改进实战 | 更换主干网络Backbone(三)之轻量化模型Shufflenetv2

前言 轻量化网络设计是一种针对移动设备等资源受限环境的深度学习模型设计方法。下面是一些常见的轻量化网络设计方法: 网络剪枝:移除神经网络中冗余的连接和参数,以达到模型压缩和加速的目的。分组卷积:将卷积操作分解为若干个较小的卷积操作,并将它们分别作用于输入的不…

【手把手教你】使用Python玩转多元时间序列分析

在探索和理解复杂的金融市场行为时&#xff0c;时间序列分析成为了一种无法忽视的强有力工具。特别是&#xff0c;当我们处理的不仅是单一的时间序列&#xff0c;而是多个时间序列并存&#xff0c;并且它们之间存在一种或多种形式的互动时&#xff0c;多元时间序列分析的重要性…

线性代数3:矢量方程

一、前言 欢迎回到系列文章的第三篇文章&#xff0c;内容是线性代数的基础知识&#xff0c;线性代数是机器学习背后的基础数学。在我之前的文章中&#xff0c;我介绍了梯队矩阵形式。本文将介绍向量、跨度和线性组合&#xff0c;并将这些新想法与我们已经学到的内容联系起来。本…

如何使用内网穿透技术实现USB设备(USB Redirector)共享

文章目录 前言1. 安装下载软件1.1 内网安装使用USB Redirector1.2 下载安装cpolar内网穿透 2. 完成USB Redirector服务端和客户端映射连接3. 设置固定的公网地址 前言 USB Redirector是一款方便易用的USB设备共享服务应用程序&#xff0c;它提供了共享和访问本地或互联网上的U…

驱动开发 CoetexA7核 字符设备驱动(LED亮灯)(单独映射寄存器实现+封装结构体映射实现)

一、单独映射寄存器实现 可参考arm点灯C语言 cortex-A7核 点LED灯 &#xff08;附 汇编实现、使用C语言 循环实现、使用C语言 封装函数实现【重要、常用】&#xff09;-CSDN博客 1 应用程序 test.c #include <stdio.h> #include <sys/types.h> #include <sys/s…

我的电子萝卜刀火了吗?

引言 大家好&#xff0c;我是亿元程序员&#xff0c;一位有着8年游戏行业经验的主程。 笔者在上一篇文章《萝卜刀真的太危险了,于是我用Cocos做了一个》中说到因女儿从学校回来之后想要我给她买一把萝卜刀被我拒绝&#xff0c;但是又想要让她体验一下&#xff0c;因此用Cocos…

【广州华锐互动】建筑安全事故VR沉浸式体验系统

在建筑行业中&#xff0c;安全永远是首要的考虑因素。传统的安全培训方法&#xff0c;如书本教学、现场演示等&#xff0c;虽然能在一定程度上提高员工的安全意识&#xff0c;但这些方法往往缺乏实际体验&#xff0c;员工在真正面临危险时可能无法做出正确的判断和反应。近年来…

nvm管理不同版本nodejs

文章目录 nvm下载卸载本地node安装nvm安装nodejsnvm查看已安装版本nvm切换nodejs版本nvm删除nodejs版本 nvm下载 nvm github下载链接 nvm 1.1.7-setup.zip&#xff1a;安装版&#xff0c;推荐使用 卸载本地node 打开cmd where node 找到上面找到的路径&#xff0c;将node.…

gulp打包vue3+jsx+less插件

最终转换结果如下 在根目录下添加gulpfile.js文件&#xff0c;package.json添加命令npm run gulp var gulp require(gulp) var babel require(gulp-babel) var less require(gulp-less) var del require(del); var spawn require(child_process).spawn;const outDir &…

亚马逊测评,买家号支付不了、砍单率高是什么问题,需要怎么解决

下半年旺季很多卖家都在使用自养号测评给产品冲一波权重&#xff0c;但是很多朋友会遇到下不了单或者砍单率过高等问题。有人以为是支付卡的问题&#xff0c;也有人觉得是IP被关联了。其实他们讲的也没错&#xff0c;但是&#xff0c;亚马逊风控不会针对某个点去进行检测&#…

中小型企网搭建

企业网项目建设实践 目录 企业网项目建设实践 一、 项目背景 二、 需求分析 三、 项目拓扑规划 四、 规划表 1. vlan规划 2. 设备管理规划 3. 端口互联规划 4. IP规划 5. SSH服务规划 五、 仿真拓扑 六、 项目实践&#xff08;配置过程&#xff09; 七…

复杂的菱形继承及菱形虚拟继承(详解)

复杂的菱形继承及菱形虚拟继承 复杂的菱形继承及菱形虚拟继承虚拟继承解决数据冗余和二义性的原理笔试面试题 复杂的菱形继承及菱形虚拟继承 单继承&#xff1a;一个子类只有一个直接父类时称这个继承关系为单继承 多继承&#xff1a;一个子类有两个或以上直接父类时称这个继…

计算机算法分析与设计(15)---贪心算法(虚拟汽车加油问题和最优分解问题)

文章目录 一、虚拟汽车加油问题1.1 问题描述1.2 思路分析1.3 代码编写 二、最优分解问题2.1 问题描述2.2 思路分析2.3 代码编写 一、虚拟汽车加油问题 1.1 问题描述 一辆虚拟汽车加满油后可行驶 n n n km。旅途中有若干加油站。设计一个有效算法&#xff0c;指出应在哪些加油…

【STL】bitset位图的介绍和使用

⭐博客主页&#xff1a;️CS semi主页 ⭐欢迎关注&#xff1a;点赞收藏留言 ⭐系列专栏&#xff1a;C进阶 ⭐代码仓库&#xff1a;C进阶 家人们更新不易&#xff0c;你们的点赞和关注对我而言十分重要&#xff0c;友友们麻烦多多点赞&#xff0b;关注&#xff0c;你们的支持是我…

优思学院|精益管理涵盖哪些内容?

精益生产管理涵盖哪些内容&#xff1f;精益生产是一种以客户需求为引导、以消除浪费和持续改进为核心的生产管理模式&#xff0c;有效提升了公司的效率和利润&#xff0c;投入却极少。它包含哪些具体要素呢&#xff1f; 准时化生产&#xff08;JIT&#xff09; JIT&#xff0…

idea调教-全键盘操作

先转个vim&#xff0c;现在代码编辑可以使用全部键盘 接下来键盘使用目录 现在需要在项目文件中进行跳转&#xff0c;idea在左边目录等进行切换使用alt1等可以切换左右目录等&#xff0c;用方向建可以选中对应的文件&#xff0c;使用shiftenter可以在右边打开新的标签页,使用a…

日常--windows11右键切换回win10

文章目录 一&#xff0e;前言二&#xff0e;方法1.一键切换2.恢复回Win11右键菜单&#xff1a; 一&#xff0e;前言 从win10更新成win11后&#xff0c;很多地方不适应&#xff0c;这里演示如何将windows11右键切换回win10 二&#xff0e;方法 1.一键切换 winr打开运行 输入…

C++ 友元函数和友元类

前言 在本文中&#xff0c;您将学习在C 中创建友元函数和友元类&#xff0c;并在程序中有效地使用它们。OOP的重要概念之一是数据隐藏&#xff0c;即非成员函数无法访问对象的私有或受保护的数据。但是&#xff0c;有时这种限制可能迫使程序员编写冗长而复杂的代码。因此&#…

反向传播back propagation

深度学习概述 决定要怎么连接这些neuron的时候 就已经确定了function set 相比于之前做logistic regression&#xff0c;linear regression的时候&#xff0c;换一个方式来决定function set 比较大&#xff0c;包含了logistic regression&#xff0c;linear regression没法包含…

【C++入门 一 】学习C++背景、开启C++奇妙之旅

目录 1.什么是C2. C的发展史3. C的重要性3.1 语言的使用广泛度3.2 在工作领域1. 操作系统以及大型系统软件开发2. 服务器端开发3. 游戏开发4. 嵌入式和物联网领域5. 数字图像处理6. 人工智能7. 分布式应用 3.3 在校招领域3.3.1 岗位需求3.3.2 笔试题 4. 如何学习C4.1 别人怎么学…