.Net8 Avalonia跨平台UI框架——<vlc:VideoView>控件播放海康监控、摄像机视频(Windows / Linux)

一、UI效果

在这里插入图片描述
在这里插入图片描述

二、新建用户控件:VideoViewControl.axaml

需引用:VideoLAN.LibVLC.Windows包
Linux平台需安装:VLC 和 LibVLC (sudo apt-get update、sudo apt-get install vlc libvlccore-dev libvlc-dev)

.axaml 代码

注:vlc:VideoView 上无法增加鼠标和指针事件,需使用Popup浮动透明层

<UserControl xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
			 xmlns:vlc="clr-namespace:LibVLCSharp.Avalonia;assembly=LibVLCSharp.Avalonia"
			 xmlns:vm="using:TrainArrivalAnalysis.Avalonia.ViewModels"
			 xmlns:i="clr-namespace:Avalonia.Xaml.Interactivity;assembly=Avalonia.Xaml.Interactivity"
			 xmlns:controls="clr-namespace:Avalonia.Controls;assembly=Avalonia.Controls"
             mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
             x:Class="TrainArrivalAnalysis.Avalonia.Controls.VideoViewControl"
			 >
	<Design.DataContext>
		<vm:VideoWindowViewModel/>
	</Design.DataContext>
		<Grid>

		<vlc:VideoView x:Name="playerView" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"  IsHitTestVisible="False" SizeChanged="playerViewSizeChanged" >
		</vlc:VideoView>

		<Popup x:Name="videoViewPopup" Placement="Center" PlacementTarget="{Binding ElementName=playerView}" IsOpen="True" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">

			<Border Background="Transparent" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >

				<Grid Background="Transparent" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">

					<TextBlock x:Name="playBackTip" VerticalAlignment="Top" HorizontalAlignment="Right" Background="#F0F8FF" Foreground="Red" Margin="0,50,10,0" Padding="15" FontSize="16" FontWeight="Bold" IsVisible="False" />

					<TextBlock x:Name="connectTip" VerticalAlignment="Center" HorizontalAlignment="Center" Background="Transparent" Foreground="White" FontSize="40" Text="网络中断" IsVisible="False" />

				</Grid>

			</Border>

		</Popup>

	</Grid>

</UserControl>
.axaml.cs 代码
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Extensions.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using Avalonia.Threading;
using Avalonia.VisualTree;
using LibVLCSharp.Avalonia;
using LibVLCSharp.Shared;
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Net.NetworkInformation;
using System.Threading;
using System.Threading.Tasks;
using TrainArrivalAnalysis.Utility;

namespace TrainArrivalAnalysis.Avalonia.Controls;

public partial class VideoViewControl : UserControl, INotifyPropertyChanged, IDisposable
{
    private bool _disposed = false;
    private LibVLC _libVLC;
    private MediaPlayer _mediaPlayer;
    private string _url;
    public string Url
    {
        get => _url;
        set
        {
            if (_url != value)
            {
                StopPlayback(); // 停止当前播放
                _url = value;
                OnPropertyChanged(nameof(Url));
                if (!string.IsNullOrEmpty(_url))
                {
                    SetMediaPlayerAsync();
                }
            }
        }
    }
    private int _type = 0;
    public int Type
    {
        get => _type;
        set
        {
            _type = value;
            OnPropertyChanged(nameof(Type));
        }
    }
    private bool _isPlayBackTip = false;
    public bool IsPlayBackTip
    {
        get => _isPlayBackTip;
        set
        {
            _isPlayBackTip = value;
            OnPropertyChanged(nameof(IsPlayBackTip));

            Dispatcher.UIThread.InvokeAsync(() =>
            {
                playBackTip.IsVisible = _isPlayBackTip;
            });
        }
    }

    private string _playBackTipContent;
    public string PlayBackTipContent
    {
        get => _playBackTipContent;
        set
        {
            if (_playBackTipContent != value)
            {
                _playBackTipContent = value;
                OnPropertyChanged(nameof(PlayBackTipContent));

                Dispatcher.UIThread.InvokeAsync(() =>
                {
                    playBackTip.Text = _playBackTipContent;
                });
            }
        }
    }

    private bool _isConnectTip = false;
    public bool IsConnectTip
    {
        get => _isConnectTip;
        set
        {
            _isConnectTip = value;
            OnPropertyChanged(nameof(IsConnectTip));

            Dispatcher.UIThread.InvokeAsync(() =>
            {
                connectTip.IsVisible = _isConnectTip;
            });
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private int _maxRetryAttempts = 5;
    private int _retryDelayMilliseconds = 5000;
    private int _currentRetryAttempt = 0;

    public VideoViewControl()
    {
        InitializeComponent();

        var libVlcOptions = new[] { "--no-video-title-show", "--no-osd" };
        _libVLC = new LibVLC(libVlcOptions);

        this.Loaded += async (sender, e) =>
        {
            var videoView = this.FindControl<VideoView>("playerView");
            if (videoView != null)
            {
                videoView.Loaded += async (s, ev) =>
                {
                    if (!string.IsNullOrEmpty(Url))
                    {
                        await SetMediaPlayerAsync();
                    }
                };
            }
        };

        this.Unloaded += (sender, e) =>
        {
            StopPlayback();

            Dispose(false);
        };
    }
    public async Task SetMediaPlayerAsync()
    {
        try
        {
            if (!string.IsNullOrEmpty(Url))
            {
                _mediaPlayer = new MediaPlayer(_libVLC);

                await Dispatcher.UIThread.InvokeAsync(() =>
                {
                    VideoView _videoView = this.FindControl<VideoView>("playerView");
                    if (_videoView != null)
                    {
                        _videoView.MediaPlayer = _mediaPlayer;
                    }
                });
                var mediaOptions = new[] { ":network-caching=300", "avcodec-hw=any" };

                var _media = new Media(_libVLC, Url, FromType.FromLocation, mediaOptions);

                _mediaPlayer.Media = _media;

                _mediaPlayer.EncounteredError += OnEncounteredError;

                await Task.Run(() =>
                {
                    _mediaPlayer.Play();
                });
            }

            _currentRetryAttempt = 0;

            _ = CheckPlayStatus().ConfigureAwait(false);
        }
        catch (Exception ex)
        {
        }
    }
    private async Task CheckPlayStatus()
    {
        try
        {
            await Task.Delay(5000).ConfigureAwait(false);

            while (true)
            {
                if (_mediaPlayer != null && _mediaPlayer.IsPlaying)
                {
                    IsConnectTip = false;
                    if (Type == 1)
                    {
                        IsPlayBackTip = true;
                    }
                    _currentRetryAttempt = 0;
                }
                else if (_mediaPlayer.State == VLCState.Stopped || _mediaPlayer.State == VLCState.Error || (_mediaPlayer.State == VLCState.Ended && !NetworkHelper.IsNetworkConnected()))
                {
                    IsPlayBackTip = false;

                    IsConnectTip = true;

                    StopPlayback();
                }
                else if (_mediaPlayer.State == VLCState.Ended)
                {
                    IsConnectTip = false;
                    if (Type == 1)
                    {
                        IsPlayBackTip = true;
                    }
                }

                await Task.Delay(10000).ConfigureAwait(false);
            }
        }
        catch (OperationCanceledException)
        {

        }
        catch (Exception ex)
        {

        }
    }
    private async void OnEncounteredError(object sender, EventArgs e)
    {
        IsPlayBackTip = false;
        IsConnectTip = true;
    }
    private async void playerViewSizeChanged(object sender, SizeChangedEventArgs e)
    {
        if (videoViewPopup.IsOpen)
        {
            videoViewPopup.Width = playerView.ActualWidth();
            videoViewPopup.Height = playerView.ActualHeight();
        }
    }
    // 停止播放
    private void StopPlayback()
    {
        _mediaPlayer?.Stop();
    }
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
                if (_mediaPlayer != null)
                {
                    _mediaPlayer.Stop();
                    _mediaPlayer.Dispose();
                    _mediaPlayer = null;
                }
                if (_libVLC != null)
                {
                    _libVLC.Dispose();
                    _libVLC = null;
                }
            }
            _disposed = true;
        }
    }
}

三、主页面MainWindow.axaml使用

.axaml代码
<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
		xmlns:animation="clr-namespace:Avalonia.Animation;assembly=Avalonia.Animation"
        xmlns:vm="using:TrainArrivalAnalysis.Avalonia.ViewModels"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
		xmlns:controls="clr-namespace:TrainArrivalAnalysis.Avalonia.Controls"
		xmlns:converters="clr-namespace:TrainArrivalAnalysis.Avalonia.Converters"
		xmlns:md="clr-namespace:TrainArrivalAnalysis.Avalonia.Models.Dto"
        mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
        x:Class="TrainArrivalAnalysis.Avalonia.Views.MainWindow"
        x:DataType="md:ArrivalRecordDto"
        Icon="/Assets/avalonia-logo.ico"
		Title="半自动闭塞区段列车整列到达自动智能分析系统"
		WindowState="FullScreen" SystemDecorations="None"  ZIndex="1">
	<Window.Resources>
		<converters:GridLengthToDoubleConverter x:Key="GridLengthToDoubleConverter"/>
	</Window.Resources>
	<Window.Styles>
		<Style Selector="Button.blueBtn">
			<Setter Property="Foreground" Value="White"/>
			<Setter Property="Background" Value="#4C7DF7"/>
			<Setter Property="Height" Value="32"/>
			<Setter Property="FontSize" Value="16"/>
			<Setter Property="BorderBrush" Value="DarkGray"/>
			<Setter Property="Template">
				<Setter.Value>
					<ControlTemplate TargetType="Button">
						<Border x:Name="containerBorder" BorderBrush="{TemplateBinding BorderBrush}" Background="#4C7DF7" CornerRadius="13">
							<ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center" ></ContentPresenter>
						</Border>
					</ControlTemplate>
				</Setter.Value>
			</Setter>
		</Style>
	</Window.Styles>

	<Grid  x:Name="RootGrid" RowDefinitions="Auto,*"  SizeChanged="RootGridSizeChanged">
		<Grid x:Name="TopGird"  Grid.Row="0" Height="2" Background="Black" PointerMoved="TopGridPointerMovedHandler"> </Grid>
		<Grid Grid.Row="1"  Background="Black">
			<Grid.ColumnDefinitions>
				<ColumnDefinition Width="*" />
				<ColumnDefinition Width="*" />
			</Grid.ColumnDefinitions>

			<Grid.RowDefinitions>
				<RowDefinition Height="*" />
				<RowDefinition Height="*" />
			</Grid.RowDefinitions>
			
			<controls:VideoViewControl  Grid.Row="0" Grid.Column="0" x:Name="videoView"  DoubleTapped="VideoDoubleTappedHandler" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>

			<controls:VideoViewControl  Grid.Row="0" Grid.Column="1" x:Name="videoView1" DoubleTapped="VideoDoubleTappedHandler" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>


			<Image x:Name="imageArriva" Grid.Row="1" Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"   Stretch="Fill" DoubleTapped="ImageDoubleTappedHandler"></Image>

			<Image x:Name="imageLeave" Grid.Row="1" Grid.Column="1"  HorizontalAlignment="Stretch" VerticalAlignment="Stretch"   Stretch="Fill" DoubleTapped="ImageDoubleTappedHandler" ></Image>

			<Image x:Name="imageArriva_1" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"   Stretch="Fill" DoubleTapped="ImageDoubleTappedHandler"></Image>

			<Image x:Name="imageLeave_1" Grid.Row="0"  Grid.Column="1"  HorizontalAlignment="Stretch" VerticalAlignment="Stretch"   Stretch="Fill" DoubleTapped="ImageDoubleTappedHandler" ></Image>

		</Grid>

		<Popup x:Name="NavMenuPopup" Placement="Top" PlacementTarget="{Binding ElementName=TopGird}" IsOpen="False" IsVisible="False">

			<Border x:Name="PopupBorder"  Background="#F0F8FF"  HorizontalAlignment="Stretch" VerticalAlignment="Stretch">

				<Grid x:Name="NavMenuGird" Background="Transparent" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" ColumnDefinitions="Auto,*,Auto" MinHeight="30" PointerExited="NavMenuPointerExitedHandler">

					<StackPanel Orientation="Horizontal" Grid.Column="0" HorizontalAlignment="Left">
						<Button Content="标记为来车信号" Margin="5" Classes="blueBtn" Width="125" x:Name="arrivalSignalButton" Click="ArrivalSignal_Click" DockPanel.Dock="Left" />
						<TextBox x:Name="searchStartTime" Watermark="取图开始日期" Text="" Height="32" />
						<TextBox x:Name="searchEndTime" Watermark="取图结束日期" Text="" Height="32" />
						<Button Content="标记为无车信号" Margin="5" Classes="blueBtn" Width="125" x:Name="leaveSignalButton" Click="LeaveSignal_Click" DockPanel.Dock="Left" />
					</StackPanel>

					<Rectangle Grid.Column="1" Fill="Transparent"/>

					<StackPanel Orientation="Horizontal" Grid.Column="2" HorizontalAlignment="Right">
						<Button Content="最近来车记录" Margin="5" Classes="blueBtn" Width="125" x:Name="showLastArrivalRecordButton" Click="ShowLastArrivalRecordClick" />
						<Button Content="来车记录查询" x:Name="showArrivalRecordButton" Margin="5" Classes="blueBtn" Width="125" Click="ShowArrivalRecordClick" />
						<Button Content="结束查询" x:Name="closeArrivalRecordButton" Margin="5" Classes="blueBtn" Width="125" Click="CloseArrivalRecordClick"/>
						<Button Content="测试下载" x:Name="downLoadButton" Margin="5" Classes="blueBtn" Width="125" Click="DownLoadClick" IsVisible="False" />
						<Button Content="关闭系统" Margin="50,5,5,5" Classes="blueBtn" Width="125" Click="CloseAppClick" />
					</StackPanel>

				</Grid>

			</Border>
		</Popup>

		<Popup x:Name="ArrivalRecordPopup" Placement="Center" PlacementTarget="{Binding ElementName=RootGrid}" IsOpen="False" >
			<Border x:Name="ArrivalRecordPopupBorder"  Background="White"  HorizontalAlignment="Stretch" VerticalAlignment="Stretch">

				<controls:ArrivalRecordViewControl x:Name="arrivalRecordView"  HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
			</Border>
		</Popup>
	</Grid>
</Window>

.axaml.cs代码
 public partial class MainWindow : Window
 {
 public MainWindow()
{
    InitializeComponent();
  this.Loaded += async (sender, e) =>
  {
      string url = $"rtsp://用户名:密码@IP/LiveMedia/ch1/Media1";
      SetVideoViewUrl("videoView", url, "");

 	  url = $"rtsp://用户名:密码@IP/LiveMedia/ch1/Media1";
  	  SetVideoViewUrl("videoView1", url, "");
  };
 }
 public async void SetVideoViewUrl(string videoViewControlName, string url, string playBackTipContent, int type = 0, bool isPlayBackTip = false)
{
    _ = Task.Run(async () =>
    {
        await Dispatcher.UIThread.InvokeAsync(() =>
        {
            var _videoView = this.FindControl<VideoViewControl>(videoViewControlName);
            if (_videoView != null)
            {
                _videoView.Url = url;
                _videoView.Type = type;
                _videoView.PlayBackTipContent = playBackTipContent;
                _videoView.IsPlayBackTip = isPlayBackTip;
            }
        });
    });
}
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

哈尔滨有双线服务器租用吗?

哈尔滨有双线服务器租用吗&#xff1f;双线服务器是一种针对哈尔滨特有的网络环境优化的服务器解决方案&#xff0c;它能够同时支持中国电信和中国联通或移动其中两家主要ISP&#xff08;互联网服务提供商&#xff09;的连接。 由于中国南方地区多采用电信网络&#xff0c;而北…

58,【8】BUUCTF [PwnThyBytes 2019]Baby_SQL1

进入靶场 和2次注入的页面很像 不过养成查看源代码的好习惯 先访问source.zip 下载后解压&#xff0c;发现两个文件 第一个文件夹打开又有4个PHP文件 那还是先看index.php文件好了 有PHP和HTML两部分&#xff0c;下面是PHP部分代码&#xff08;HTML太长了&#xff0c;先放一…

在服务器上增加新网段IP的路由配置

在服务器上增加新网段IP的路由配置 前提条件步骤一:检查当前路由表步骤二:添加新路由步骤三:验证新路由步骤四:持久化路由配置脚本示例结论在网络管理中,路由配置是一项基本且重要的任务。它决定了数据包在网络中的传输路径。本文将详细介绍如何在服务器上增加新的路由配置…

图像处理|闭运算

闭运算&#xff08;Closing&#xff09;是形态学操作中的另一种基本操作&#xff0c;它与开运算&#xff08;Opening&#xff09;类似&#xff0c;但执行的步骤相反。闭运算结合了膨胀和腐蚀操作&#xff0c;顺序为 先膨胀后腐蚀。这种操作通常用于填补图像中的小空洞&#xff…

【Pytorch实用教程】TCN(Temporal Convolutional Network,时序卷积网络)简介

文章目录 TCN的基本特点TCN的优点TCN的应用场景典型的TCN架构总结TCN(Temporal Convolutional Network,时序卷积网络)是一种用于处理序列数据的深度学习模型,尤其适用于时间序列预测、语音识别、自然语言处理等任务。它利用卷积神经网络(CNN)来处理时序数据,相比于传统的…

Python调用go语言编译的库

要在 Python 中调用用 Go 语言编写的库&#xff0c;可以使用 Go 语言的 cgo 特性将 Go 代码编译成共享库&#xff08;如 .so 文件&#xff09;&#xff0c;然后在 Python 中通过 ctypes 或 cffi 模块加载和调用这个共享库。 新建main.go文件&#xff0c;使用go语言编写如下代码…

服务器一次性部署One API + ChatGPT-Next-Web

服务器一次性部署One API ChatGPT-Next-Web One API ChatGPT-Next-Web 介绍One APIChatGPT-Next-Web docker-compose 部署One API ChatGPT-Next-WebOpen API docker-compose 配置ChatGPT-Next-Web docker-compose 配置docker-compose 启动容器 后续配置 同步发布在个人笔记服…

深度学习项目--基于LSTM的火灾预测研究(pytorch实现)

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 前言 LSTM模型一直是一个很经典的模型&#xff0c;这个模型当然也很复杂&#xff0c;一般需要先学习RNN、GRU模型之后再学&#xff0c;GRU、LSTM的模型讲解将…

PCL K4PCS算法实现点云粗配准【2025最新版】

目录 一、算法原理1、算法概述2、算法流程3、参考文献二、 代码实现1、原始版本2、2024新版三、 结果展示本文由CSDN点云侠原创,原文链接,首发于:2020年4月27日。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的抄袭狗。 博客长期更新,本文最近一次更新时间为…

.Net Core微服务入门全纪录(二)——Consul-服务注册与发现(上)

系列文章目录 1、.Net Core微服务入门系列&#xff08;一&#xff09;——项目搭建 2、.Net Core微服务入门全纪录&#xff08;二&#xff09;——Consul-服务注册与发现&#xff08;上&#xff09; 3、.Net Core微服务入门全纪录&#xff08;三&#xff09;——Consul-服务注…

人参t2t基因组-文献精读100

Telomere-to-telomere reference genome for Panax ginseng highlights the evolution of saponin biosynthesis 人参的端粒到端粒参考基因组揭示皂苷生物合成的进化 摘要 人参&#xff08;Panax ginseng&#xff09;是中药的代表性植物之一&#xff0c;并在全球范围内广泛使…

一、1-2 5G-A通感融合基站产品及开通

1、通感融合定义和场景&#xff08;阅读&#xff09; 1.1通感融合定义 1.2通感融合应用场景 2、通感融合架构和原理&#xff08;较难&#xff0c;理解即可&#xff09; 2.1 感知方式 2.2 通感融合架构 SF&#xff08;Sensing Function&#xff09;&#xff1a;核心网感知控制…

机器学习之SVD奇异值分解实现图片降维

SVD奇异值分解实现图片降维 目录 SVD奇异值分解实现图片降维1 SVD奇异值分解1.1 概念1.2 基本步骤1.2.1 矩阵分解1.2.2 选择奇异值1.2.3 重建矩阵1.2.4 降维结果 1.3 优缺点1.3.1 优点1.3.2 缺点 2 函数2.1 函数导入2.2 函数参数2.3 返回值2.4 通过 k 个奇异值降维 3 实际测试3…

Linux《Linux简介与环境的搭建》

在学习了C或者是C语言的基础知识之后就可以开始Linux的学习了&#xff0c;现在Linux无论是在服务器领域还是在桌面领域都被广泛的使用&#xff0c;所以Linxu也是我们学习编程的重要环节&#xff0c;在此接下来我们将会花大量的时间在Linxu的学习上。在学习Linux初期你可以会像初…

二进制/源码编译安装mysql 8.0

二进制方式&#xff1a; 1.下载或上传安装包至设备&#xff1a; 2.创建组与用户&#xff1a; [rootopenEuler-1 ~]# groupadd mysql [rootopenEuler-1 ~]# useradd -r -g mysql -s /bin/false mysql 3.解压安装包&#xff1a; tar xf mysql-8.0.36-linux-glibc2.12-x86_64.ta…

boss直聘 __zp_stoken__ 逆向分析

声明: 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 有相关问题请第一时间头像私信联系我删…

pyspark连接clickhouse数据库的方式(其它数据库同样适用)

目录 一、背景简记二、pyspark连接clickhouse方式记录三、结语参考学习博文 一、背景简记 实际工作中&#xff0c;大部分所用的数据存储地址都是在数据库中&#xff0c;如我司现在常用的数据库是clickhouse&#xff0c;相关数据的统计分析都在此上操作。如果想用pyspark连接cl…

【JSqlParser】Java使用JSqlParser解析SQL语句总结

简述 Java解析SQL语句有很多工具都可以做到&#xff0c;比如Mybatis、Druid、目前用来用去最全面的仍然是Jsqlparser&#xff0c;它是一个Github上的开源项目&#xff0c;JSqlParser是一个用于解析SQL语句的Java库&#xff0c;它可以帮助开发者分析和操作SQL语句的结构。无论是…

Ubuntu本地部署网站

目录 1.介绍 2.安装apache 3.网页升级 1.介绍 网站其实就相当于一个文件夹&#xff0c;用域名访问一个网页&#xff0c;就相当于访问了一台电脑的某一个文件夹&#xff0c;在网页中看见的视频&#xff0c;视频和音乐其实就是文件夹里面的文件。为什么网页看起来不像电脑文件夹…

C++异常处理详解

概述 这篇博客将深入探讨 C异常处理的工作原理, 最佳实践以及如何编写异常安全的代码, 配有代码示例和详细说明. 1. 异常的挑战 性能开销: 异常在失败情况下会带来显著的运行时成本. 图片来自: Introduction to proposed std::expected - Niall Douglas - Meeting C 2017 推…