C#上位机开发

news2024/11/16 13:52:02

目录

  • 一、上位机简介
  • 二、C#语法
  • 三、新建VS工程
  • 四、WinForm控件
    • 4.1 属性
    • 4.2 事件
    • 4.3 窗体方法
    • 4.4 常用控件
    • 4.5 布局
  • 五、Serial上位机
    • 5.1 UI界面设计
    • 5.2 功能设计
  • 六、项目打包成安装包
    • 6.1 前提准备
    • 6.2 打包步骤


一、上位机简介

  在单片机项目开发中,上位机也是一个很重要的部分,主要用于数据显示(波形、温度等)、用户控制(LED,继电器等),下位机(单片机)与 上位机之间要进行数据通信的两种方式都是基于串口的:

  • USB转串口 —— 上位机和下位机通过USB转串口连接线直接相连进行数据交互
  • 串口转WIFI(ESP8266)—— 上位机和下位机基于TCP/IP协议通过以太网或者WIFI传输数据
  • 串口转蓝牙(HC-06)—— 不多用,暂不介绍

  Windows上位机(EXE可执行程序),最早用VB语言开发,后来由于C++的发展,采用MFC开发,近几年,微软发布了基于.NET框架的面向对象语言C#,更加稳定安全,再配合微软强大的VS进行开发,效率奇高。

  本文使用Visual Studio 2022作为开发环境,上位机开发主要有WPF框架与Winform框架,他们都是基于.NET框架

  • WPF需要C/S基础,使用XAML来构建应用UI,界面比较美观,但是内存开销大
  • Winform可以使用窗口控件来构建应用,比较简单易学,本文以Winform为例做一个简单的上位机

二、C#语法

  • C#语法基础:C#语言入门
  • Winform学习:Windows窗体入门

三、新建VS工程

  首先新建,这边我们限定选项C#、Windowws、桌面,然后选择Windows窗体应用
在这里插入图片描述
  修改项目路径、名称,最后选择框架,由于是单项目所以勾选,否则在解决方案文件夹里会生成子项目文件夹,然后下一步就可以生成工程
在这里插入图片描述

  打开解决方案,双击Program.cs可以打开主函数MainApplication.Run(new Form1())就是循环执行应用。
在这里插入图片描述
  WinForm项目结构

  • 引用:包括所有的系统库文件的引用依赖
  • App.config:当前项目的配置文件
  • Form1.cs:当前窗体的事件逻辑源码
    • Form1.Designer.cs:当前窗体的控件布局源码
    • Form1.resx:当前窗体的资源文件(图片、图标、资源等)
  • Program.cs:当前项目程序的主入口Main,启动项目,运行初始窗口

  其中双击Form1.cs就可以打开UI设计界面,如果左侧工具栏和右侧属性栏不显示,可以去视图里打开工具箱和属性窗口。然后我们添加ButtonTextBox控件,单击Button,在右侧属性Text可以修改文字
在这里插入图片描述
  双击Button按钮就可以编辑代码生成对应功能,这里textBox1就是上图属性里的Name

//按下Send按钮
textBox1.Text = "^_^Hello,World^_^";    //文本框显示

在这里插入图片描述
  点击启动就可以进入调试页面,生成我们的应用,此时点击Send按钮,下面就可以显示字符
在这里插入图片描述

四、WinForm控件

4.1 属性

在这里插入图片描述
  在Windows窗体应用程序中右击窗体或控件,在弹出的右键菜单中 选择“属性”命令,窗体的常用属性如下表所示:

属性作用
Name窗体/空间的名称
WindowState获取或设置窗体的窗口状态,取值有Normal(正常)、Minimized(最小化)、Maximized(最大化)
Text窗口标题栏中的文字
Size窗体的尺寸
MaximizeBox获取或设置窗体标题栏右上角是否有最大化按钮,默认为 True
MinimizeBox获取或设置窗体标题栏右上角是否有最小化按钮,默认为 True
BackColor获取或设置窗体的背景色
BackgroundImage获取或设置窗体的背景图像
FormBorderStyle窗体边框的样式
Enabled获取或设置窗体是否可用
Font获取或设置窗体上文字的字体
ForeColor获取或设置窗体上文字的颜色
Icon获取或设置窗体上显示的图标
Location窗体在屏幕上的位置
BackgroundImageLayout获取或设置图像布局,取值有 5 种,即 None(图片居左显示)、Tile(图像重复,默认值)、Stretch(拉伸)、Center(居中)、Zoom(按比例放大到合适大小)
StartPosition获取或设置窗体运行时的起始位置,取值有 5 种,即 Manual(窗体位置由 Location 属性决定)、CenterScreen(屏幕居中)、WindowsDefaultLocation( Windows 默认位置)、WindowsDefaultBounds(Windows 默认位置,边界由 Windows 决定)、CenterParent(在父窗体中居中)

4.2 事件

在这里插入图片描述
  在属性点击事件,常见的事件为:

事件名称描述
Load窗体加载时触发
Click在窗体上单击时触发
MouseDoubleClick鼠标双击事件
MouseMove鼠标在窗体上移动时触发
KeyPress键盘按键被按下时触发
FormClosing窗体即将关闭时触发
Resize窗体尺寸改变时触发
KeyDown键盘按下事件
KeyUp键盘释放事件
FormClosing窗体关闭事件,关闭窗体时发生
FormClosed窗体关闭事件,关闭窗体后发生

4.3 窗体方法

  自定义的窗体都继承自 System.Windows.Form 类,能使用 Form 类中已有的成员,包括属性、方法、事件等。窗体中也有一些从 System.Windows.Form 类继承的方法,如下表所示:

方法作用
Show()显示窗体
Hide()隐藏窗体
Close()关闭窗体
Activate()激活窗体并给予它焦点
Invalidate()强制重新绘制窗体
ShowDialog()以对话框模式显示窗体
CenterToParent()使窗体在父窗体边界内居中
CenterToScreen()使窗体在当前屏幕上居中

4.4 常用控件

  • TextBox:输入文本框

    • 常用属性:尺寸Size、单行/多行Multiline、密码输入PasswordChar、只读ReadOnly、显示/获取文本Text等
    • 常用事件:KeyPress按下按键(常用于输出完成点击回车,box.Text取输入值,事件e.keyChar取按下哪个键)
  • CheckBox:复选框

    • 常用属性:尺寸Size、显示文本Text、Checked是否勾选
    • 常用事件:Click点击事件、CheckedChanged勾选状态改变事件
  • ComboBox:下拉列表(只能单选)

    • 常用属性:
      • a.添加数据项:设计器编辑添加(属性->数据->Items,一行表示一个数据项)、程序手工添加(comboBox.Items.Add(“some”);)
      • b.其他设置:Size尺寸、Text提示文本等
    • 常用事件:
      • a.获取选中的项:SelectedItem(选中项的值)、SelectedIndex(选中项的索引,-1表示未选中)
      • b.选项改变事件:SelectedIndexChanged
  • ListBox:列表框(展示数据、可单选/多选)

    • 常用属性:SelectionMode(单选/多选模式)
      • a.单选模式获取选项:SelectedItem/SelectedIndex(选中项的值/索引)
      • b.多选模式获取选项:SelectedIndices/SelectedItems(选中项的索引集合/值集合)
      • c.添加数据项:设计器编辑添加(属性->数据->Items)、程序手工添加(listBox.Items.Add(“some”);)
    • 常用事件:SelectedIndexChanged(选项改变)
  • Button、RadioButton、CheckBox、CheckedListBox:按钮

  • Label、LinkLabel:标签控件

  • MenuStrip:菜单栏

    • 右键菜单栏ContextMenuStrip
    • 状态栏菜单StatusStrip
    • 工具栏ToolStrip
  • Timer:定时器,Interval设置计时时间间隔,以毫秒为单位

  • PictureBox:图片框

    • 常用属性:
      • Image:“获取或设置图片控件中显示的图片
      • ImageLocation:获取或设置图片控件中显示图片的路径
      • SizeMode:获取或设置图片控件中图片显示的大小和位置,如果值为 Normal,则图片显不在控件的左上角;如果值为 Stretchimage,则图片在图片控件中被拉伸或收缩,适合图片的大小;如果值为AutoSize,则控件的大小适合图片的大小;如果值为 Centerimage,图片在图片控件中居中;如果值为 Zoom,则图片会自动缩放至符合图片控件的大小
      • dock:停靠方式

4.5 布局

  1. 自动布局
      选中多个控件,就可以在工具栏进行对齐排列
    在这里插入图片描述

  2. 使用布局器

  • 工具箱->容器->TableLayoutPanel —— 表格布局器
  • 工具箱->容器->FlowLayoutPanel —— 排列布局器
    在这里插入图片描述
  1. 手动布局
  • 通过设计界面拖拽/手动注册组件的方式,初始化初始界面布局(此时属于自动布局)
  • 在Form.cs逻辑代码中重写Form父类的OnLayout方法,在方法内实现手动布局。OnLayout方法会在窗口大小变化时自动被回调调用,来重新设置组件的位置大小等属性实现自适应。
    • a.调用父类的OnLayout(),不是必须的。
    • b.获取当前窗口大小 CilentSize(仅客户区,不含标题栏)
    • c.计算和设置每一个控件新的的大小和位置,实现动态布局

注意

  • Size属性指窗口大小(包括工具栏),ClientSize指客户区大小(不包含工具栏)
  • 本质:OnLayout方法会在窗口大小变化时自动被调用,来设置组件的位置实现自适应
namespace WindowsFormsApp_learning
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
 
        //重写父类的OnLayout方法,实现手动布局自适应
        protected override void OnLayout(LayoutEventArgs levent)
        {
            //1.调用父类的OnLayout(),不是必须的
            base.OnLayout(levent);
            //2.获取当前客户窗口大小 ClientSize
            int w = this.ClientSize.Width;
            int h = this.ClientSize.Height;
            //3.计算并设置每一个控件的大小和位置
            int yoff = 0;
 
            yoff = 4;
            this.text_box.Location = new Point(0, yoff);//坐标(0,4)
            this.text_box.Size = new Size(w - 80, 30);//尺寸(w-80,30)
            this.btn_click.Location = new Point(w - 80, yoff);//坐标(w-80,4)
            this.btn_click.Size = new Size(80, 30);//尺寸(80,30)
 
            yoff += 30;//第一行的高度
            yoff += 4;//间隔
            this.panel1.Location = new Point(0, yoff);
            this.panel1.Size = new Size(w, h - yoff - 4);
        }
    }
}

五、Serial上位机

  首先新建一个SerialPort项目

5.1 UI界面设计

  1. 容器控件(Panel
      用容器给功能分组
    在这里插入图片描述

  2. 文本标签控件(Label
      添加文本控件,选中多个可以在工具栏选择对齐方式,选择单个控件->属性->Text可以修改文本内容
    在这里插入图片描述

  3. 文本框控件(TextBox)
      TextBox控件与label控件不同的是,文本框控件的内容可以由用户修改,这也满足我们的发送文本框需求;在默认情况下,TextBox控价是单行显示的,如果想要多行显示,需要设置其Multiline属性为true;
      TextBox的方法中最多的是APPendText方法,它的作用是将新的文本数据从末尾处追加至TextBox中,那么当TextBox一直追加文本后就会带来本身长度不够而无法显示全部文本的问题,此时我们需要使能TextBox的纵向滚动条来跟踪显示最新文本,所以我们将TextBox的属性ScrollBars的值设置为Vertical即可;
    在这里插入图片描述

  4. 下拉组合框控件(ComboBox

  DropDownStyle可以选择下拉模式:

  • DropDown模式,既可以选择下拉项,也可以选择直接编辑
  • DropDownList模式,只能从下拉列表中选择
    在这里插入图片描述
      在属性面板中Items属性中加入下拉项,默认项可以在Text里设置
    在这里插入图片描述
  • 停止位:1,1.5,2
  • 数据位:8,7,6,5
  • 波特率:230400,115200,76800,57600,38400,19200,9600,4800
  • 奇偶校验:None,奇校验,偶校验
  1. 按钮控件(Button
      在Text里修改按钮名称
    在这里插入图片描述

  2. 复选框控件(CheckBox
    在这里插入图片描述

  3. 串口组件(SerialPort
      添加串口组件后就可以调用串口的功能
    在这里插入图片描述

  4. 添加图标
      点击项目->属性->应用程序->浏览,然后添加.ico文件图标,这是.exe可执行文件图标
    在这里插入图片描述
      在属性列表里找到Form1属性,然后在Icon添加图标
    在这里插入图片描述
      最后界面设计大概这样
    在这里插入图片描述

5.2 功能设计

  1. 串口初始化
      先创建一个初始化函数Serial_init()
private void Serial_init()
{
//    int i;
    
//    for (i = 300; i <= 38400; i = i*2)//单个添加
    {
//        comboBox2.Items.Add(i.ToString());  //添加波特率列表
    }

    //批量添加波特率列表
    string[] baud = { "43000", "56000", "57600", "115200", "128000", "230400", "256000", "460800" };
    comboBox2.Items.AddRange(baud);

    //设置默认值
    comboBox1.Text = "COM1";
    comboBox2.Text = "115200";
    comboBox3.Text = "8";
    comboBox4.Text = "None";
    comboBox5.Text = "1";
}

  添加函数get_Serial_port()来获取电脑的串口

private void get_Serial_port()
{
	//获取电脑当前可用串口并添加到选项列表中
    //comboBox1.Items.AddRange(System.IO.Ports.SerialPort.GetPortNames());
    string[] ports = System.IO.Ports.SerialPort.GetPortNames(); //获得可用的串口
    for (int i = 0; i < ports.Length; i++)
    {
        comboBox1.Items.Add(ports[i]);
    }
    comboBox1.SelectedIndex = comboBox1.Items.Count > 0 ? 0 : -1;//如果里面有数据,显示第0个
}

  双击UI空白处,在Form1.cs里会生成Form1_Load()函数,然后将get_Serial_port()Serial_init()添加进来
在这里插入图片描述

  1. 打开串口
      双击UI界面“打开串口”(Button1),进入按键事件
private void button1_Click(object sender, EventArgs e)
{
    try
    {
        if (button1.Text == "打开串口")
        {
            serialPort1.PortName = comboBox1.Text;//获取要打开的串口
            serialPort1.BaudRate = int.Parse(comboBox2.Text);//获得波特率
            serialPort1.DataBits = int.Parse(comboBox3.Text);//获得数据位
                                                             //设置停止位
            if (comboBox5.Text == "1")
            {
                serialPort1.StopBits = StopBits.One;
            }
            else if (comboBox5.Text == "1.5")
            {
                serialPort1.StopBits = StopBits.OnePointFive;
            }
            else if (comboBox5.Text == "2")
            {
                serialPort1.StopBits = StopBits.Two;
            }
            //设置奇偶校验
            if (comboBox4.Text == "None")
            {
                serialPort1.Parity = Parity.None;
            }
            else if (comboBox4.Text == "奇校验")
            {
                serialPort1.Parity = Parity.Odd;
            }
            else if (comboBox4.Text == "偶校验")
            {
                serialPort1.Parity = Parity.Even;
            }
            serialPort1.Open();//打开串口
            button1.Text = "关闭串口";
            button1.BackColor = Color.Firebrick;
        }
        else
        {
            //关闭串口
            serialPort1.Close();//关闭串口
            button1.Text = "打开串口"; //按钮显示打开
            button1.BackColor = Color.ForestGreen;
        }
    }
    catch (Exception err)
    {
        MessageBox.Show("打开失败" + err.ToString(), "提示!");
    }

}
  1. 发送
      首先需要将字符串转化16进制,可以用正则表达式
private byte[] strToHexbytes(string str)
{
    str = str.Replace(" ", "");//清除空格
    byte[] buff;
    if ((str.Length % 2) != 0)
    {
        buff = new byte[(str.Length + 1) / 2];
        try
        {
            for (int i = 0; i < buff.Length; i++)
            {
                buff[i] = Convert.ToByte(str.Substring(i * 2, 2), 16);
            }
            buff[buff.Length - 1] = Convert.ToByte(str.Substring(str.Length - 1, 1).PadLeft(2, '0'), 16);
            return buff;
        }
        catch (Exception err)
        {
            MessageBox.Show("含有f非16进制的字符", "提示");
            return null;
        }
    }
    else
    {
        buff = new byte[str.Length / 2];
        try
        {
            for (int i = 0; i < buff.Length; i++)
            {
                buff[i] = Convert.ToByte(str.Substring(i * 2, 2), 16);
            }
        }
        catch (Exception err)
        {
            {
                MessageBox.Show("含有非16进制的字符", "提示");
                return null;
            }
        }
    }
    return buff;
}

  串口发送有两种方法,一种是字符串发送WriteLine,一种是Write(),可以发送一个字符串或者16进制发送,其中字符串发送WriteLine默认已经在末尾添加换行符;先双击“发送”(Button2)

private void button2_Click(object sender, EventArgs e)
{
    Task.Run(() => {
        send_();
    });
}

string data_;
//发送数据  
private void send_()
{
    data_ = textBox2.Text.ToString();
    try
    {
        if (data_.Length != 0)
        {
            data_ += " ";
            if (checkBox2.Checked) //16进制发送
            {
                serialPort1.Write(Encoding.Default.GetString(strToHexbytes(data_)));
            }
            else
            {
                serialPort1.Write(data_);     
            }
        }

    }
    catch (Exception) { }
}
  1. 接收
      在使用串口接收之前要先为串口注册一个Receive事件,相当于单片机中的串口接收中断,然后在中断内部对缓冲区的数据进行读取,如图,双击DataReceived,就会跳转到响应代码部分:
    在这里插入图片描述
      在接收之前需要注意,这里的数据全部是byte型数据,接收文本框显示的内容都是以字符串形式呈现的,所以先添加16进制的方法
private string byteToHexstr(byte[] buff)
{
    string str = "";
    try
    {
        if (buff != null)
        {
            for (int i = 0; i < buff.Length; i++)
            {
                str += buff[i].ToString("x2");
                str += " ";//两个之间用空格
            }
            return str;
        }
    }
    catch (Exception)
    {
        return str;
    }
    return str;
}

  最后在serialPort1_DataReceived()进行接收数据处理

private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    int len = serialPort1.BytesToRead; //获取可以读取的字节数

    byte[] buff = new byte[len];
    serialPort1.Read(buff, 0, len);//把数据读取到数组中
    string reslut = Encoding.Default.GetString(buff);
    //将byte值根据为ASCII值转为string
    Invoke((new Action(() =>
    {
        if (checkBox1.Checked)//16进制转化
        {
            textBox1.AppendText(" " + byteToHexstr(buff));
        }
        else
        {
            textBox1.AppendText(" " + reslut);
        }
    }
    )));
}
  1. 清空接收
      双击“清空接收”(Button3),修改如下。此时项目结束
private void button3_Click(object sender, EventArgs e)
{
    textBox1.Clear(); 
}   

六、项目打包成安装包

6.1 前提准备

  1. 生成项目文件
      首先将Debug版本变成Release版本,进行编译
  • Debug (调试):不进行优化,便于程序员调试应用程序。
  • Release (发布):进行完全优化,减少代码大小,提高运行速度。
    在这里插入图片描述
  1. 安装扩展.
      点击扩展->管理扩展,在搜索框里搜索Visual studio Installer,点击安装
    在这里插入图片描述
      也可以去插件官网下载安装:Microsoft Visual Studio Installer Projects 2022 - Visual Studio Marketplace

注意:安装需要关闭Visual Studio,如果安装失败重启一下电脑

6.2 打包步骤

  1. 新建Setup Project项目
      右击解决方案->添加->新建项目
    在这里插入图片描述
      搜索Setup Project
    在这里插入图片描述
      新建项目文件夹
    在这里插入图片描述

  2. 添加项目文件
      首先右击Application Folder->Add->文件
    在这里插入图片描述
      然后将工程目录Relese里的文件全部添加进来
    在这里插入图片描述

  3. 创建桌面文件
      对.exe文件右击创建桌面文件
    在这里插入图片描述
      然后将生成的文件拖到User’s Desktop里
    在这里插入图片描述
      点击桌面文件可以在属性里修改Name
    在这里插入图片描述
      找一个ico文件添加进来,然后点击Icon添加图标
    在这里插入图片描述

  4. 生成工程
      点击解决方案app,在属性里可以修改信息,其中Manufacturer不填会报错
    在这里插入图片描述
      右击找到属性
    在这里插入图片描述
      然后在Prerequisites添加组件
    在这里插入图片描述
      右击生成,就可以在文件夹里生成安装文件
    在这里插入图片描述
    在这里插入图片描述

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

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

相关文章

因为宇宙一片漆黑,所以地球才有昼夜之分,宇宙为什么是黑的?

因为宇宙一片漆黑&#xff0c;所以地球才有昼夜之分&#xff0c;宇宙为什么是黑的&#xff1f; 地球为何会有昼夜之分&#xff1f; 乍一看&#xff0c;这个问题很是简单&#xff0c;当然是因为地球一直在自转了&#xff0c;当地球的一部分被太阳照射时就是白昼&#xff0c;而…

【中间件系列】浅析redis是否适合做消息队列

文章目录 一、简单的list消息队列1.命令示例2.伪代码示例3.方案优劣 二、Pub/Sub发布订阅1.消息丢失2.消息堆积 三、相对成熟的Stream1.redis命令介绍2.多消费者组测试3.Stream会持久化吗&#xff1f;4.消息堆积如何解决&#xff1f; 总结 用redis也是比较久了&#xff0c;并且…

程序员的职业素养:走向成功的关键

程序员的职业素养&#xff1a;走向成功的关键 引言 在信息时代&#xff0c;程序员扮演着至关重要的角色。他们推动着技术创新&#xff0c;构建起我们赖以生存的数字世界。然而&#xff0c;仅仅精通技术&#xff0c;并不能确保一个程序员的成功。优秀的职业素养&#xff0c;是程…

Vue Router 4与路由管理实战

title: Vue Router 4与路由管理实战 date: 2024/6/7 updated: 2024/6/7 excerpt: 这篇文章介绍了如何在Vue.js应用中利用Vue Router实现单页面应用的路由管理&#xff0c;包括配置路由、导航守卫的使用、路由懒加载以优化性能以及动态路由的实现方法&#xff0c;旨在提升用户体…

钉钉二次开发-企业内部系统集成官方OA审批流程

场景&#xff1a;企业内部开发人员不足&#xff0c;需要从以前集成Activiti的方式转换成集成钉钉官方OA审批流程&#xff0c;提高开发效率和系统稳定性。 摘要&#xff1a;企业内部系统集成Acitiviti开源工作流存在的问题&#xff1a; 1. 企业需要单独搭建工作流服务&#xff…

玩转ChatGPT:最全学术论文提示词分享【上】

学境思源&#xff0c;一键生成论文初稿&#xff1a; AcademicIdeas - 学境思源AI论文写作 在当今数字时代&#xff0c;人工智能&#xff08;AI&#xff09;技术正迅速改变各行各业的运作方式。特别是&#xff0c;OpenAI的ChatGPT等语言模型以其强大的文本生成能力&#xff0c;…

大数据相关知识||电商大数据相关参数和返回||主流电商平台大数据采集

主流电商大数据&#xff1a; 公共参数 名称类型必须描述keyString是调用key&#xff08;免费测试&#xff09;secretString是调用密钥api_nameString是API接口名称&#xff08;包括在请求地址中&#xff09;[item_search,item_get,item_search_shop等]cacheString否[yes,no]默…

jupyter notebook默认工作目录修改

jupyter notebook默认工作目录修改 1、问题2、如何修改jupyter notebook默认工作目录 1、问题 anaconda安装好之后&#xff0c;我们启动jupyter notebook会发现其默认工作目录是在C盘&#xff0c;将工作目录放在C盘会让C盘很快被撑爆&#xff0c;我们应该将jupyter notebook默…

【NoSQL】Redis练习

1、redis的编译安装 systemctl stop firewalld systemctl disable firewalld setenforce 0 yum install -y gcc gcc-c make wget cd /opt wget https://download.redis.io/releases/redis-5.0.7.tar.gz tar zxvf redis-5.0.7.tar.gz -C /opt/cd /opt/redis-5.0.7/ # 编译 make…

【Spring Cloud Alibaba】开源组件Sentinel

目录 什么是Sentinel发展历史与Hystrix的异同 Sentinel可以做什么&#xff1f;Sentinel的功能Sentinel的开源生态Sentinel的用户安装Sentinel控制台预备环境准备Sentinel 分为两个部分:下载地址 项目集成Sentinel创建项目修改依赖信息添加启动注解添加配置信息在控制器类中新增…

大数据开发统计数据的详细口径是什么

在进行开发数据需求之前&#xff0c;我们先要明确数据统计的详细口径是什么。 需求1&#xff1a;&#xff08;不明确的示例&#xff09; 统计商品的销售数量。 存在的问题&#xff1a; 这个需求表述过于简单&#xff0c;未明确指出统计商品销售数量的时间范围、商品类型等关键…

《十八岁出门远行》世界很小,案牍劳形;世界很大,日短心长

《十八岁出门远行》世界很小&#xff0c;案牍劳形&#xff1b;世界很大&#xff0c;日短心长 余华&#xff0c;作家&#xff0c;著有《在细雨中呼喊》《活着》《文城》《兄弟》等。 文章目录 《十八岁出门远行》世界很小&#xff0c;案牍劳形&#xff1b;世界很大&#xff0c;日…

SOA的参考架构

1. 以服务为中心的企业集成架构 IBM的Websphere业务集成参考架构&#xff08;如图1所示&#xff0c;以下称参考架构&#xff09;是典型的以服务为中心的企业集成架构。 图1 IBM WebSphere业务集成参考架构 以服务为中心的企业集成采用“关注点分离&#xff08;Separation of Co…

Redisson分布式锁原理解析

前言 首先Redis执行命令是单线程的&#xff0c;所以可以利用Redis实现分布式锁&#xff0c;而对于Redis单线程的问题&#xff0c;是其线程模型的问题&#xff0c;本篇重点是对目前流行的工具Redisson怎么去实现的分布式锁进行深入理解&#xff1b;开始之前&#xff0c;我们可以…

正宇软件助力江西数字人大建设,高效解决群众“急难愁盼”问题

近日&#xff0c;赣州市南康区群众通过“江西数字人大”小程序成功解决道路塌陷等民生问题&#xff0c;引发社会广泛关注。这一成功案例不仅彰显了“数字人大”在解决群众“急难愁盼”问题中的重要作用&#xff0c;也凸显了江西地区近年来在数字化人大建设方面的显著成效。正宇…

【高频】什么是索引的下推和覆盖

面试回答&#xff1a; 索引的下推是指数据库引擎在执行查询时&#xff0c;将过滤条件尽可能地应用到索引上&#xff0c;以减少需要检索的数据量&#xff0c;从而提高查询性能。这样可以减少数据库引擎从磁盘加载的数据量&#xff0c;提高查询效率。覆盖索引是指一个索引包含了…

uniapp余额银行卡支付密码界面实现(直接复制)

示例&#xff1a; 插件地址&#xff1a;自定义数字/身份证/密码输入框&#xff0c;键盘密码框可分离使 - DCloud 插件市场 1.下载插件并导入HBuilderX&#xff0c;找到文件夹&#xff0c;copy number-keyboard.vue一份为number-keyboard2.vue&#xff08;number-keyboard.vue是…

Android 高德地图API(新版)

新版高德地图 前言正文一、创建应用① 获取PackageName② 获取调试版安全码SHA1③ 获取发布版安全码SHA1 二、配置项目① 导入SDK② 配置AndroidManifest.xml 三、获取当前定位信息① ViewBinding使用和导包② 隐私合规设置③ 权限请求④ 初始化定位⑤ 获取定位信息 四、显示地…

ChatGPT-4o在临床医学日常工作、数据分析与可视化、机器学习建模中的技术

2022年11月30日&#xff0c;可能将成为一个改变人类历史的日子——美国人工智能开发机构OpenAI推出了聊天机器人ChatGPT-3.5&#xff0c;将人工智能的发展推向了一个新的高度。2023年11月7日&#xff0c;OpenAI首届开发者大会被称为“科技界的春晚”&#xff0c;吸引了全球广大…

Web 网页性能优化

Web 网页性能及性能优化 一、Web 性能 Web 性能是 Web 开发的一个重要方面&#xff0c;侧重于网页加载速度以及对用户输入的响应速度 通过优化网站来改善性能&#xff0c;可以在为用户提供更好的体验 网页性能既广泛又非常深入 1. 为什么性能这么重要&#xff1f; 1. 性能…