[MAUI]集成高德地图组件至.NET MAUI Blazor项目

news2024/10/1 7:36:39

文章目录

    • 前期准备:注册高德开发者并创建 key
      • 登录控制台
      • 创建 key
      • 获取 key 和密钥
    • 创建项目
      • 创建JS API Loader
      • 配置权限
      • 创建定义
      • 创建模型
      • 创建地图组件
      • 创建交互逻辑
    • 项目地址

地图组件在手机App中常用地理相关业务,如查看线下门店,设置导航,或选取地址等。是一个较为常见的组件。

在.NET MAUI 中,有两种方案可以集成高德地图,一种是使用原生库绑定。网上也有人实现过:https://blog.csdn.net/sD7O95O/article/details/125827031

但这种方案需要大量平台原生开发的知识,而且需要对每一个平台进行适配。

在这里我介绍第二种方案:.NET MAUI Blazor + 高德地图JS API 2.0 库的实现。

JS API 2.0 是高德开放平台基于WebGL的地图组件,可以将高德地图模块集成到.NET MAUI Blazor中的BlazorWebView控件,由于BlazorWebView的跨平台特性,可以达到一次开发全平台通用,无需为每个平台做适配。

今天用此方法实现一个地图选择器,使用手机的GPS定位初始化当前位置,使用高德地图JS API库实现地点选择功能。混合开发方案涉及本机代码与JS runtime的交互,如果你对这一部分还不太了解,可以先阅读这篇文章:[MAUI]深入了解.NET MAUI Blazor与Vue的混合开发

.NET MAUI Blazor

使用.NET MAU实现跨平台支持,本项目可运行于Android、iOS平台。

前期准备:注册高德开发者并创建 key

登录控制台

登录 高德开放平台控制台,如果没有开发者账号,请 注册开发者。

在这里插入图片描述

创建 key

进入应用管理,创建新应用,新应用中添加 key,服务平台选择 Web端(JS API)。再创建一个Web服务类型的Key,用于解析初始位置地址。

在这里插入图片描述

获取 key 和密钥

创建成功后,可获取 key 和安全密钥。

在这里插入图片描述

创建项目

新建.NET MAUI Blazor项目,命名AMap

创建JS API Loader

前往https://webapi.amap.com/loader.js另存js文件至项目wwwroot文件夹

在这里插入图片描述

在wwwroot创建amap_index.html文件,将loader.js引用到页面中。创建_AMapSecurityConfig对象并设置安全密钥。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
    <title>AmapApp</title>
    <base href="/" />
    <link href="css/app2.css" rel="stylesheet" />
</head>

<body>

    <div class="status-bar-safe-area"></div>

    <div id="app">Loading...</div>

    <div id="blazor-error-ui">
        An unhandled error has occurred.
        <a href="" class="reload">Reload</a>
        <a class="dismiss">🗙</a>
    </div>

    <script src="_framework/blazor.webview.js" autostart="false"></script>
    <script src="lib/amap/loader.js"></script>
    <script type="text/javascript">
        window._AMapSecurityConfig = {
            securityJsCode: "764832459a38e824a0d555b62d8ec1f0",
        };
    </script>

</body>

</html>


配置权限

打开Android端AndroidManifest.xml文件

在这里插入图片描述

添加权限:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

打开Info.plist文件,添加权限描述信心

在这里插入图片描述

<key>NSLocationWhenInUseUsageDescription</key>
<string>允许使用设备的GPS更新您的位置信息。</string>

创建定义

创建Position,Poi,Location等类型,用于描述位置信息。由于篇幅这里不展开介绍。

创建模型

创建一个MainPageViewModel类,用于处理页面逻辑。代码如下:

public class MainPageViewModel : ObservableObject
{
    public event EventHandler<FinishedChooiseEvenArgs> OnFinishedChooise;
    private static AsyncLock asyncLock = new AsyncLock();
    public static RateLimitedAction throttledAction = Debouncer.Debounce(null, TimeSpan.FromMilliseconds(1500), leading: false, trailing: true);
    public MainPageViewModel()
    {
        Search = new Command(SearchAction);
        Done = new Command(DoneAction);
        Remove = new Command(RemoveAction);
    }

    private void RemoveAction(object obj)
    {
        this.Address=null;
        this.CurrentLocation=null;
        OnFinishedChooise?.Invoke(this, new FinishedChooiseEvenArgs(Address, CurrentLocation));
    }

    private void DoneAction(object obj)
    {
        OnFinishedChooise?.Invoke(this, new FinishedChooiseEvenArgs(Address, CurrentLocation));

    }

    private void SearchAction(object obj)
    {
        Init();
    }

    public async void Init()
    {
        var location = await GeoLocationHelper.GetNativePosition();
        if (location==null)
        {
            return;
        }
        var amapLocation = new Location.Location()
        {
            Latitude=location.Latitude,
            Longitude=location.Longitude
        };
        CurrentLocation=amapLocation;

    }

    private Location.Location _currentLocation;

    public Location.Location CurrentLocation
    {
        get { return _currentLocation; }
        set
        {

            if (_currentLocation != value)
            {
                if (value!=null &&_currentLocation!=null&&Location.Location.CalcDistance(value, _currentLocation)<100)
                {
                    return;
                }

                _currentLocation = value;
                OnPropertyChanged();
            }
        }
    }

    private string _address;

    public string Address
    {
        get { return _address; }
        set
        {
            _address = value;
            OnPropertyChanged();
        }
    }


    private ObservableCollection<Poi> _pois;

    public ObservableCollection<Poi> Pois
    {
        get { return _pois; }
        set
        {
            _pois = value;
            OnPropertyChanged();
        }
    }

    private Poi _selectedPoi;

    public Poi SelectedPoi
    {
        get { return _selectedPoi; }
        set
        {
            _selectedPoi = value;
            OnPropertyChanged();

        }
    }


    public Command Search { get; set; }
    public Command Done { get; set; }
    public Command Remove { get; set; }

}

注意这里的Init方法,用于初始化位置。

GeoLocationHelper.GetNativePosition()方法用于从你设备的GPS模块,获取当前位置。它调用的是Microsoft.Maui.Devices.Sensors提供的设备传感器访问功能
,详情可参考官方文档地理位置 - .NET MAUI

创建地图组件

创建Blazor页面AMapPage.razor以及AMapPage.razor.js

AMapPage.razor中引入

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (!firstRender)
        return;
    await JSRuntime.InvokeAsync<IJSObjectReference>(
   "import", "./AMapPage.razor.js");
    await Refresh();
    await JSRuntime.InvokeVoidAsync("window.initObjRef", this.objRef);
}

razor页面的 @Code 代码段中,放置MainPageViewModel属性,以及一个DotNetObjectReference对象,用于在JS中调用C#方法。

@code {
    [Parameter]
    public MainPageViewModel MainPageViewModel { get; set; }
    private DotNetObjectReference<AMapPage> objRef;


    protected override void OnInitialized()
    {
        objRef = DotNetObjectReference.Create(this);
    }

    private async Task Refresh()
    {

        ...
    }

AMapPage.razor.js我们加载地图,并设置地图的中心点。和一些地图挂件。此外,我们还需要监听地图的中心点变化,更新中心点。 这些代码可以从官方示例中复制。(https://lbs.amap.com/demo/javascript-api-v2/example/map/map-moving)。

console.info("start load")
window.viewService = {
    map: null,
    zoom: 13,
    amaplocation: [116.397428, 39.90923],
    SetAmapContainerSize: function (width, height) {
        console.info("setting container size")

        var div = document.getElementById("container");
        div.style.height = height + "px";

    },
    SetLocation: function (longitude, latitude) {
        console.info("setting loc", longitude, latitude)
        window.viewService.amaplocation = [longitude, latitude];
        if (window.viewService.map) {
            window.viewService.map.setZoomAndCenter(window.viewService.zoom, window.viewService.amaplocation);

            console.info("set loc", window.viewService.zoom, window.viewService.map)
        }
    },
    isHotspot: true

}
AMapLoader.load({ //首次调用 load
    key: '0896cedc056413f83ca0aee5b029c65d',//首次load key为必填
    version: '2.0',
    plugins: ['AMap.Scale', 'AMap.ToolBar', 'AMap.InfoWindow', 'AMap.PlaceSearch']
}).then((AMap) => {
    console.info("loading..")
    var opt = {
        resizeEnable: true,
        center: window.viewService.amaplocation,
        zoom: window.viewService.zoom,
        isHotspot: true
    }
    var map = new AMap.Map('container', opt);
    console.info(AMap, map, opt)

    map.addControl(new AMap.Scale())
    map.addControl(new AMap.ToolBar())
    window.viewService.marker = new AMap.Marker({
        position: map.getCenter()
    })
    map.add(window.viewService.marker);
    var placeSearch = new AMap.PlaceSearch();  //构造地点查询类
    var infoWindow = new AMap.InfoWindow({});
    map.on('hotspotover', function (result) {
        placeSearch.getDetails(result.id, function (status, result) {
            if (status === 'complete' && result.info === 'OK') {
                onPlaceSearch(result);
            }
        });
    });

    map.on('moveend', onMapMoveend);
    // map.on('zoomend', onMapMoveend);
    //回调函数

    window.viewService.map = map;

    function onMapMoveend() {
        var zoom = window.viewService.map.getZoom(); //获取当前地图级别
        var center = window.viewService.map.getCenter(); //获取当前地图中心位置
        if (window.viewService.marker) {
            window.viewService.marker.setPosition(center);

        }
        window.objRef.invokeMethodAsync('OnMapMoveend', center);


    }
    function onPlaceSearch(data) { //infoWindow.open(map, result.lnglat);
        var poiArr = data.poiList.pois;
        if (poiArr[0]) {
            var location = poiArr[0].location;
            infoWindow.setContent(createContent(poiArr[0]));
            infoWindow.open(window.viewService.map, location);
        }
    }
    function createContent(poi) {  //信息窗体内容
        var s = [];
        s.push('<div class="info-title">' + poi.name + '</div><div class="info-content">' + "地址:" + poi.address);
        s.push("电话:" + poi.tel);
        s.push("类型:" + poi.type);
        s.push('<div>');
        return s.join("<br>");
    }


    console.info("loaded")

}).catch((e) => {
    console.error(e);
});
window.initObjRef = function (objRef) {
    window.objRef = objRef;
}

地图中心点改变时,我们需要使用window.objRef.invokeMethodAsync('OnMapMoveend', center);从JS runtime中通知到C#代码。

同时,在AMapPage.razor中配置一个方法,用于接收从JS runtime发来的回调通知。
在此赋值CurrentLocation属性。


[JSInvokable]
public async Task OnMapMoveend(dynamic location)
{
    await Task.Run(() =>
     {
         var locationArray = JsonConvert.DeserializeObject<double[]>(location.ToString());
         MainPageViewModel.CurrentLocation=new Location.Location()
             {
                 Longitude=locationArray[0],
                 Latitude =locationArray[1]
             };
     });
}

同时监听CurrentLocation属性的值,一旦发生变化,则调用JS runtime中的viewService.SetLocation方法,更新地图中心点。

protected override async Task OnInitializedAsync()
{
    MainPageViewModel.PropertyChanged +=  async (o, e) =>
    {
        if (e.PropertyName==nameof(MainPageViewModel.CurrentLocation))
        {
            if (MainPageViewModel.CurrentLocation!=null)
            {
                var longitude = MainPageViewModel.CurrentLocation.Longitude;
                var latitude = MainPageViewModel.CurrentLocation.Latitude;
                await JSRuntime.InvokeVoidAsync("viewService.SetLocation", longitude, latitude);
            }
        }


    };

}

MainPageViewModel类中,我们添加一个PropertyChanged事件,用于监听CurrentLocation属性的改变。

当手指滑动地图触发位置变化,导致CurrentLocation属性改变时,将当前的中心点转换为具体的地址。这里使用了高德逆地理编码API服务(https://restapi.amap.com/v3/geocode/regeo)解析CurrentLocation的值, 还需使用了防抖策略,避免接口的频繁调用。


public MainPageViewModel()
{
    PropertyChanged+=MainPageViewModel_PropertyChanged;
    ...
}



private async void MainPageViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
    if (e.PropertyName == nameof(CurrentLocation))
    {
        if (CurrentLocation!=null)
        {

            // 使用防抖
            using (await asyncLock.LockAsync())
            {

                var amapLocation = new Location.Location()
                {
                    Latitude=CurrentLocation.Latitude,
                    Longitude=CurrentLocation.Longitude
                };
                var amapInverseHttpRequestParamter = new AmapInverseHttpRequestParamter()
                {
                    Locations= new Location.Location[] { amapLocation }
                };
                ReGeocodeLocation reGeocodeLocation = null;
                try
                {
                    reGeocodeLocation = await amapHttpRequestClient.InverseAsync(amapInverseHttpRequestParamter);
                }
                catch (Exception ex)
                {

                    Console.WriteLine(ex.ToString());
                }

                throttledAction.Update(() =>
                {
                    MainThread.BeginInvokeOnMainThread(() =>
                    {
                        CurrentLocation=amapLocation;
                        if (reGeocodeLocation!=null)
                        {
                            Address = reGeocodeLocation.Address;
                            Pois=new ObservableCollection<Poi>(reGeocodeLocation.Pois);

                        }
                    });
                });
                throttledAction.Invoke();
            }
        }
    }
}

至此我们完成了地图组件的基本功能。

创建交互逻辑

在MainPage.xaml中,创建一个选择器按钮,以及一个卡片模拟选择器按钮点击后的弹窗。


<Button Clicked="Button_Clicked"
        Grid.Row="1"
        x:Name="SelectorButton"
        HorizontalOptions="Center"
        VerticalOptions="Center"
        Text="{Binding Address, TargetNullValue=请选择地点}"></Button>


<Border StrokeShape="RoundRectangle 10"
    Grid.RowSpan="2"
    x:Name="SelectorPopup"
    IsVisible="False"
    Margin="5,50"
    MinimumHeightRequest="500">

    <Grid Padding="0">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>

        <Grid Grid.Row="0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"></ColumnDefinition>
                <ColumnDefinition></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <Label FontSize="Large"
                    Margin="10, 10, 10, 0"
                    FontAttributes="Bold"
                    Text="选择地点"></Label>
            <HorizontalStackLayout Grid.Column="1"
                                    HorizontalOptions="End">
                <Button Text="删除"
                        Margin="5,0"
                        Command="{Binding Remove}"></Button>
                <Button Text="完成"
                        Margin="5,0"
                        Command="{Binding Done}"></Button>
            </HorizontalStackLayout>
        </Grid>

        <Grid Grid.Row="1"
                Margin="10, 10, 10, 0">
            <Grid.RowDefinitions>
                <RowDefinition></RowDefinition>
                <RowDefinition Height="Auto"></RowDefinition>
            </Grid.RowDefinitions>
            <Label HorizontalTextAlignment="Center"
                    VerticalOptions="Center"
                    x:Name="ContentLabel"
                    Text="{Binding Address}"></Label>
            <Border IsVisible="False"
                    Grid.RowSpan="2"
                    x:Name="ContentFrame">
                <Entry Text="{Binding Address, Mode=TwoWay}"
                        Placeholder="请输入地址, 按Enter键完成"
                        Completed="Entry_Completed"
                        Unfocused="Entry_Unfocused"
                        ClearButtonVisibility="WhileEditing"></Entry>
            </Border>
            <Border x:Name="ContentButton"
                    Grid.Row="1"
                    HorizontalOptions="Center"
                    VerticalOptions="Center">
                <Label>
                    <Label.FormattedText>
                        <FormattedString>
                            <Span FontFamily="FontAwesome"
                                    Text="&#xf044;"></Span>
                            <Span Text=" 修改"></Span>
                        </FormattedString>
                    </Label.FormattedText>

                </Label>
                <Border.GestureRecognizers>
                    <TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped">
                    </TapGestureRecognizer>
                </Border.GestureRecognizers>
            </Border>
        </Grid>
        <BlazorWebView Grid.Row="2"
                        Margin="-10, 0"
                        x:Name="mainMapBlazorWebView"
                        HostPage="wwwroot/amap_index.html">
            <BlazorWebView.RootComponents>
                <RootComponent Selector="#app"
                                x:Name="rootComponent"
                                ComponentType="{x:Type views:AMapPage}" />
            </BlazorWebView.RootComponents>
        </BlazorWebView>
    </Grid>
</Border>

在这里插入图片描述

最终效果如下:

在这里插入图片描述

项目地址

Github:maui-samples

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

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

相关文章

【MySQL】深入解析事务与MVCC

文章目录 1、事务四大特性1.1、原子性1.2、一致性1.3、隔离性1.4、持久性 2、并发事务带来问题2.1、脏读2.2、不可重复读2.3、幻读 3、事务隔离级别3.1、读未提交3.2、读已提交3.3、可重复读3.4、串行化 4、MVCC4.1、InnoDB隐藏字段4.2、undo log版本链4.3、ReadView4.4、MVCC工…

『K8S 入门』三:资源调度

『K8S 入门』三&#xff1a;资源调度 一、Label 和 Selector 可以通过 Selector 基于 Label 匹配需要的资源 Label 标签 配置文件中&#xff08;metadata.labels&#xff09;配置 metadata: # Pod相关的元数据&#xff0c;用于描述Pod的数据name: nginx-demo #Pod的名称lab…

阅读笔记(ICIP2023)Rectangular-Output Image Stitching

“矩形输出”图像拼接 Zhou, H., Zhu, Y., Lv, X., Liu, Q., & Zhang, S. (2023, October). Rectangular-Output Image Stitching. In 2023 IEEE International Conference on Image Processing (ICIP) (pp. 2800-2804). IEEE. 0. 摘要 图像拼接的目的是将两幅视场重叠的…

GDC期间LayaAir启动全球化战略

3 月 18 日至 3 月 22 日&#xff0c;一年一度的游戏开发者大会&#xff08;GDC&#xff09;在美国旧金山举行。在此期间&#xff0c;Layabox宣布LayaAir引擎启动全球扩张战略&#xff0c;这标志着引擎将步入快速发展的新阶段。此举旨在利用公司先进的3D引擎技术&#xff0c;将…

力扣每日一题 2024/3/23 统计桌面上的不同数字

题目描述 用例说明 思路讲解 给定整数n&#xff0c;找出循环十亿天后桌上的数字。可以先通过一天来找找规律。 第一天 n%i1 &#xff08;1<i<n&#xff09;只有n-1符合.加入桌面 第二天(n-1)%i1 &#xff08;1<i<n-1&#xff09;只有n-2符合 加入桌面 依次类推…

RHEL9部署Docker环境

华子目录 Docker引擎架构docker引擎架构示意图执行过程示例 RHEL9上安装Docker1.系统要求2.安装yum-utils工具包3.yum安装docker-ce4.配置docker镜像加速docker拉取镜像的过程配置阿里云镜像仓库重新加载守护进程重启Docker服务 5.拉取并运行hello-world镜像6.测试是否安装成功…

【LabVIEW FPGA入门】FPGA 存储器(Memory)

可以使用内存项将数据存储在FPGA块内存中。内存项以2kb为倍数引用FPGA目标上的块内存。每个内存项引用一个单独的地址或地址块&#xff0c;您可以使用内存项访问FPGA上的所有可用内存。如果需要随机访问存储的数据&#xff0c;请使用内存项。 内存项不消耗FPGA上的逻辑资源&…

stm32平衡车

目录 一.所需材料 二.PID算法&#xff08;简单说明&#xff09; 直立环 速度环 串级PID 三.使用到的外设 1.定时器输出比较-PWM 2.定时器编码器模式 3.编码器读取速度 4.电机驱动函数 5.外部中断 四、小车 调试 一.所需材料 1.陀螺仪MPU6050--读取三轴的加速度…

C++类和对象进阶

CSDN成就一亿技术人 C类的6个默认成员函数(构造)-CSDN博客https://blog.csdn.net/lh11223326/article/details/136917667?spm1001.2014.3001.5502 目录 一.再谈构造函数 1.构造函数体赋值&#xff1a; 在创建对象时&am…

# Maven Bom 的使用

Maven Bom 的使用 文章目录 Maven Bom 的使用概述BOM特点优点缺点 MavenMaven 安装安装步骤settingx.ml常用仓库地址Idea 使用maven常见坑 SpringBoot 项目Bom使用案例项目结构主项目 zerocode-back-servezc-dependency&#xff08;第三方jar管理&#xff09;子模块zc-serve子模…

Qt creator构建DLL库

文章目录 一、构建DLL库二、隐式调用DLL库 一、构建DLL库 Qt creator创建DLL项目。 实现功能函数。 运行代码&#xff0c;debug目录下会有.dll和.lib文件。 二、隐式调用DLL库 QT新建控制台项目。将.lib文件和与之关联的头文件赋值到项目文件夹。 3. 添加头文件和外部依赖库…

目标检测——YOLOR算法解读

论文&#xff1a;YOLOR-You Only Learn One Representation: Unifified Network for Multiple Tasks 作者&#xff1a;Chien-Yao Wang, I-Hau Yeh, Hong-Yuan Mark Liao 链接&#xff1a;https://arxiv.org/abs/2105.04206 代码&#xff1a;https://github.com/WongKinYiu/yolo…

Python界面库Flet(1)介绍和快速使用

Python界面库Flet(1)快速上手使用 Author&#xff1a;Once Day Date&#xff1a;2024年3月19日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文章可参考专栏: Pyt…

利用sealos安装k8s集群

1. 环境准备 准备三台干净&#xff08;未安装过k8s环境&#xff09;的虚拟机 # 所有的主机都要配置主机名和域名映射 # 设置主机名 hostnamectl set-hostname k8s-master01 # vim /etc/hosts 192.168.59.201 k8s-master01 192.168.59.202 k8s-worker01 192.168.59.203 k8…

飞鸟写作能用吗 #笔记#笔记

飞鸟写作是一个强大的论文写作工具&#xff0c;不仅可以帮助用户高效、准确地完成论文写作&#xff0c;还能帮助用户对论文进行查重和降重。那么&#xff0c;飞鸟写作能用吗&#xff1f;答案是肯定的&#xff0c;飞鸟写作非常好用&#xff01; 首先&#xff0c;飞鸟写作拥有强大…

视频记录历史播放位置效果

简介 每次打开页面视频从上一次的播放位置开始播放 利用lodash库做节流 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-sca…

MySQL | 视图

视图是一个虚拟表&#xff0c;其内容由查询定义。同真实的表一样&#xff0c;视图包含一系列带有名称的列和行数据。视图的数据变化会影响到基表&#xff0c;基表的数据变化也会影响到视图。 1. 基本使用 1.1. 创建视图 create view 视图名 as select语句&#xff1b; 创建测…

自动驾驶轨迹规划之时空语义走廊(一)

欢迎大家关注我的B站&#xff1a; 偷吃薯片的Zheng同学的个人空间-偷吃薯片的Zheng同学个人主页-哔哩哔哩视频 (bilibili.com) 目录 1.摘要 2.系统架构 3.MPDM 4.时空语义走廊 ​4.1 种子生成 4.2 具有语义边界的cube inflation ​4.3 立方体松弛 本文解析了丁文超老师…

JetBrains数据库驱动下载失败解决方法

本方法可通用于解决PyCharm等JetBrains家的IDE下载数据库驱动问题。 在Jet家IDE内连接数据库时&#xff0c;mysql、sqlite等的驱动有部分在 https://download.jetbrains.com 网站上&#xff0c;可能由于网络问题无法访问。 解决方法是修改 JetBrains 路径下的 jdbc.drivers.xm…

计算机基础系列 —— 从 Nand 门、DFF 到 RAM

Memory: The faculty of the brain by which data or information is encoded, stored, and retrieved when needed.It is the retention of information over time for the purpose of influencing future action —— Wikipedia 文中提到的所有实现都可以参考&#xff1a;nan…