当前位置: 首页 > news >正文

Android学习制作app(ESP8266-01S连接-简单制作)

一、理论

部分理论见arduino学习-CSDN博客和Android Studio安装配置_android studio gradle 配置-CSDN博客

以下直接上代码和效果视频,esp01S的收发硬件代码目前没有分享,但是可以通过另一个手机网络调试助手进行模拟。也可以直接根据我的代码进行改动自行使用,代码中已经对模块进行了详细注释。本人不是java开发专业人士,也是通过ai完成的。

使用以下文件需要完成AndroidStdio的安装和SDK,SDK插件、gradle的配置,详细可以见之前的文章。

1、主xml文件制作界面

通过linearlayout布局,制作简单的界面,app头部为标题,中间为按钮和text显示。

<?xml version="1.0" encoding="utf-8"?>
<!-- CYA开发,SmartOrderDishes内容,VX:18712214828 -->
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"xmlns:app="http://schemas.android.com/apk/res-auto"android:id="@+id/main"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".MainActivity">
<!--    头部--><LinearLayoutandroid:layout_width="match_parent"android:layout_weight="1"android:layout_height="match_parent"android:gravity="top"android:orientation="horizontal"><TextViewandroid:layout_width="match_parent"android:layout_height="100dp"android:text="SmartOrderDishes"android:background="#609E9245"android:gravity="center|left"android:paddingLeft="30dp"android:textSize="20sp"android:textStyle="bold"android:letterSpacing="0.2"android:drawableStart="@mipmap/ic_launcher"/></LinearLayout>
<!--    显示模块--><LinearLayoutandroid:layout_width="match_parent"android:layout_weight="0.5"android:layout_height="match_parent"android:gravity="center"android:orientation="vertical"><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"><TextViewandroid:layout_width="400dp"android:layout_height="match_parent"android:text="在连接ESP-01S WIFI后,等待LCD1602显示CanConnectServer。点击连接按钮,连接服务器"android:textSize="20dp"android:gravity="left"/></LinearLayout><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"></LinearLayout><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"><Buttonandroid:onClick="Connect"android:layout_width="120dp"android:layout_height="60dp"android:layout_marginLeft="10dp"android:text="连接"/><Buttonandroid:onClick="OffConnect"android:layout_width="120dp"android:layout_height="60dp"android:layout_marginLeft="10dp"android:text="断开连接"/></LinearLayout><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:paddingTop="50dp"><TextViewandroid:id="@+id/Show_Text"android:layout_width="wrap_content"android:layout_height="50dp"android:textSize="20sp"android:text="Wait Checking out!"android:gravity="center"/></LinearLayout></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:layout_weight="1"android:gravity="center"android:orientation="horizontal"></LinearLayout>
</LinearLayout>

 2、主xml对应的java文件

此文件中,对socket连接和收发线程进行了使用,并且有两个按钮点击事件,和接收到服务器数据的弹窗和弹窗按钮点击事件。

package com.example.smartorderdishes;
/*
CYA开发,VX:18712214828
自动点餐系统安卓app:
1、主线程进行点击时间和线程侦听
2、手机连接ESP-01S的WIFI后点击连接即可连接ESP服务器。(通过8080端口和192.168.4.1默认服务器ip)
3、接收到数据后进行弹窗显示需要结算的桌面,和总金额。
4、弹窗中点击确定即可结算。ESP会受到数据包。*/
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;public class MainActivity extends AppCompatActivity {private static final String TAG = "MainActivity";//主java文件TAGprivate SocketClient socketClient;//socket自定义库文件变量private TextView textView;//TextView标签变量@SuppressLint("MissingInflatedId")@Overrideprotected void onCreate(Bundle savedInstanceState) {//主java文件函数,只会运行一次super.onCreate(savedInstanceState);EdgeToEdge.enable(this);setContentView(R.layout.activity_main);ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);return insets;});socketClient = new SocketClient(this);//变量对象初始化textView = findViewById(R.id.Show_Text);//获取标签id// 设置数据接收回调// 连接成功后启动持续监听socketClient.setDataReceivedCallback(new SocketClient.DataReceivedCallback() {@Overridepublic void onDataReceived(String data) {runOnUiThread(() -> {byte[]  DataPacket = socketClient.hexStringToByteArray(data);int deskNum = ((DataPacket[1]&0xF0)/16)+1;int priceCount = (DataPacket[1]*256+DataPacket[2])&0x0FFF;showDialog(data);});}});}// 连接按钮点击事件public void Connect(View view) {// 连接到服务器(内部会自动启动接收循环)socketClient.connectToServer();}//断开连接按钮点击事件public void OffConnect(View view) {// 关闭连接socketClient.closeConnection();}// 显示弹窗private void showDialog(String data) {AlertDialog.Builder builder = new AlertDialog.Builder(this);//新建弹窗对象byte[]  DataPacket = socketClient.hexStringToByteArray(data);//传入的数据转化为字节数组int deskNum = ((DataPacket[1]&0xF0)/16)+1;//桌号获取int priceCount = (DataPacket[1]*256+DataPacket[2])&0x0FFF;//总金额获取builder.setTitle("桌号"+deskNum+",结算请求:");//弹窗标题builder.setMessage("共计总金额$" + priceCount+"是否结算!");//弹窗信息// 确定按钮builder.setPositiveButton("确认结算", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {//确认按钮点击事件Toast.makeText(MainActivity.this, "You clicked OK", Toast.LENGTH_SHORT).show();//发送十六进制数据String hexData = "EBAAFF90"; //发送结算成功数据包socketClient.sendHexData(hexData);textView.setText("桌号:" + deskNum+"结算,总金额$"+priceCount+"\n");//显示/*textView.setText("桌号:" + deskNum+"结算,总金额$"+priceCount+"\n"+"Data:"+data);*/}});// 取消按钮builder.setNegativeButton("取消结算", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {Toast.makeText(MainActivity.this, "You clicked Cancel", Toast.LENGTH_SHORT).show();}});// 显示弹窗AlertDialog dialog = builder.create();dialog.show();}}

 3、socket连接服务器、侦听数据包和发送数据包线程,Java文件

package com.example.smartorderdishes;import android.content.Context;
import android.util.Log;
import android.widget.Toast;import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class SocketClient {private static final String SERVER_IP = "192.168.4.1";//连接的指定IPprivate static final int SERVER_PORT = 8080;//连接服务器的指定端口private static final int CONNECTION_TIMEOUT = 5000;//连接超时时间 msprivate static final int READ_TIMEOUT = 5000; // 新增读取超时时间 msprivate Socket socket;//socket变量private BufferedOutputStream out;//输出缓冲区变量private BufferedInputStream in;//输入缓冲区变量private Context context;//private ExecutorService executorService;//单线程 用于连接服务器private ExecutorService receiverExecutor; // 独立线程池用于接收数据public SocketClient(Context context) {this.context = context;executorService = Executors.newSingleThreadExecutor();//单线程的执行器服务(Executor Service),用于管理和调度任务的执行receiverExecutor = Executors.newSingleThreadExecutor(); // 独立线程池 线程用于接收数据}// 连接服务器(修改后的代码)public void connectToServer() {executorService.execute(() -> {//线程提交不需要返回结果的任务try {//异常抛出socket = new Socket();//socket对象socket.connect(new InetSocketAddress(SERVER_IP, SERVER_PORT), CONNECTION_TIMEOUT);//socket连接,指定地址、端口和超时时间socket.setSoTimeout(READ_TIMEOUT); // 设置读取超时out = new BufferedOutputStream(socket.getOutputStream());//发送缓冲区对象in = new BufferedInputStream(socket.getInputStream());//接收缓冲区对象runOnUiThread(() -> {//runOnUiThread() 是 Activity 类中的一个方法 ,用于在主线程执行代码Toast.makeText(context, "Connected to server", Toast.LENGTH_SHORT).show();Log.d("SocketClient", "Connected to server");});// 连接成功后启动接收循环startReceivingData();} catch (IOException e) {runOnUiThread(() -> {Toast.makeText(context, "Failed to connect: " + e.getMessage(), Toast.LENGTH_SHORT).show();Log.e("SocketClient", "Connection error: " + e.getMessage());});}});}// 发送十六进制数据public void sendHexData(String hexData) {executorService.execute(new Runnable() {@Overridepublic void run() {if (out != null && socket != null && !socket.isClosed()) {try {// 将十六进制字符串转换为字节数组byte[] data = hexStringToByteArray(hexData);out.write(data);//发送字节数组out.flush();//发送完毕后,关闭发送Log.d("SocketClient", "Sent (Hex): " + hexData);} catch (IOException e) {e.printStackTrace();runOnUiThread(new Runnable() {@Overridepublic void run() {Toast.makeText(context, "Failed to send data: " + e.getMessage(), Toast.LENGTH_SHORT).show();}});}} else {runOnUiThread(new Runnable() {@Overridepublic void run() {Toast.makeText(context, "Not connected to server", Toast.LENGTH_SHORT).show();}});}}});}// 接收数据包(0xEB 0xXX 0xXX 0x90)// 启动接收循环private void startReceivingData() {receiverExecutor.execute(() -> {//通过单线程执行器,所有提交的任务都会按顺序在一个单独的线程中执行。Log.d("SocketClient", "Starting receive loop");try {while (!Thread.currentThread().isInterrupted()//用于检查当前线程是否已被中断的方法&& socket != null//检查 Socket 对象是否已经被初始化且不为 null。这个检查通常用于确保在尝试使用 Socket 进行网络通信之前,它已经被正确创建和配置。&& !socket.isClosed()//检查 Socket 对象是否被关闭&& in != null) {//确保输入流(InputStream)对象已经被正确初始化且不为 null,避免潜在的 NullPointerExceptionbyte[] buffer = new byte[1024];//存储获取的数据int bytesRead;//存储获取的数据长度try {bytesRead = in.read(buffer); // 阻塞读取(但设置了超时),返回数组长度if (bytesRead == -1) {//未读取到数据Log.d("SocketClient", "Connection closed by server");break;}String hexResponse = byteArrayToHexString(buffer, bytesRead);//转字节数组换为字符串Log.d("SocketClient", "Received (Hex): " + hexResponse);if (isValidDataPacket(buffer, bytesRead)) {//判断是否符合数据包格式Log.d("SocketClient", "Valid packet received");// 触发回调if (dataReceivedCallback != null) {//回调接口变量是否为空dataReceivedCallback.onDataReceived(hexResponse);//回调不为空则运行回调函数,回调接收到的hex字符串}}} catch (SocketTimeoutException e) {Log.d("SocketClient", "Read timeout, retrying...");continue;} catch (IOException e) {Log.e("SocketClient", "Read error: " + e.getMessage());break;}}} finally {Log.d("SocketClient", "Exiting receive loop");}});}// 检查数据包是否符合 0xEB 0xXX 0xXX 0x90 格式private boolean isValidDataPacket(byte[] data, int length) {if (length < 4) {Log.d("SocketClient", "Invalid packet: length < 4");return false;}boolean isValid = (data[0] == (byte) 0xEB) && (data[3] == (byte) 0x90);Log.d("SocketClient", "Data validity: " + isValid);return isValid;}// 关闭连接public void closeConnection() {executorService.execute(new Runnable() {@Overridepublic void run() {try {if (out != null) out.close();if (in != null) in.close();if (socket != null) socket.close();//关闭socket连接Log.d("SocketClient", "Connection closed");} catch (IOException e) {e.printStackTrace();}}});}// 回调接口,用于接收数据/*onDataReceived 是一个常见的回调方法名称,通常用于在数据接收到时通知监听器或处理数据。这个方法一般定义在一个接口中,并由实现该接口的类提供具体的数据处理逻辑。*/public interface DataReceivedCallback {void onDataReceived(String data);}// 设置回调接口private DataReceivedCallback dataReceivedCallback;//回调接口变量,回调接口为自定义,在上面已定义public void setDataReceivedCallback(DataReceivedCallback callback) {this.dataReceivedCallback = callback;}// 在主线程中运行代码private void runOnUiThread(Runnable action) {new android.os.Handler(context.getMainLooper()).post(action);}// 将十六进制字符串转换为字节数组public byte[] hexStringToByteArray(String hex) {int len = hex.length();byte[] data = new byte[len / 2];for (int i = 0; i < len; i += 2) {data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)+ Character.digit(hex.charAt(i + 1), 16));}return data;}// 将字节数组转换为十六进制字符串private String byteArrayToHexString(byte[] bytes, int length) {StringBuilder hex = new StringBuilder();for (int i = 0; i < length; i++) {hex.append(String.format("%02X", bytes[i]));}return hex.toString();}}

 

 4、app获取网络权限文件,以及启动文件配置文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"><!-- 配置网络权限 --><!-- 互联网访问 --><uses-permission android:name="android.permission.INTERNET" /> <!-- 访问网络状态 --><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- 访问wifi状态 --><uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /><!-- 访问WiFi网络的信息 --><uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /><!-- 允许改变WiFi连接状态(如果需要的话) --><uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /><!-- 从Android 6.0(API level 23)开始,获取WiFi信息也需要位置权限 --><uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /><!-- 或者使用粗略的位置权限 --><uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /><applicationandroid:allowBackup="true"android:dataExtractionRules="@xml/data_extraction_rules"android:fullBackupContent="@xml/backup_rules"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/Theme.SmartOrderDishes"tools:targetApi="31"><!-- 配置Activity可启动输出权限 --><activityandroid:name=".MainActivity"android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>

二、效果

说明:

1、esp8266-01S开启AP模式的多连接的Station模式。设定端口为8080,默认ip应该是192.168.4.1,网络SSID(名称)为ESP-01S。这些里面目前是固定的,配置即ESP8266作为热点和服务器,手机连接ESP8266的WIFI,然后作为客户端手机连接到ESP8266的服务器,进行通信

2、手机连接ESP8266的wifi后。等待配置完毕,然后进行服务器连接,连接完成手机会有信息提醒。

3、连接完成后,esp8266给手机发送0xEB 0xXX 0xXX 0x90的数据包DATA[4](下标从0开始),其中DATA[1]的高4bit作为桌位,低12bit为总金额。

4、接收到数据后手机app进行弹窗,点击确定后手机app界面text改变。并且向ESP8266发送EBAAFF90(HEX)数据作为结账完成的标志数据包。

效果视频

智能点餐系统开发视频

 

代码详解 

 

 

 

其他代码问题(个人理解):

首先执行主线程mainactivity.java内容,创建UI和监听按钮动作。在onCreate创建的生命周期

(只执行一次,设置了数据接收回调的动作内容)。在socketclient.java中定义了回调函数,数据发送函数,数据接收函数,数据处理函数,类对象线程池创建等。

当mainactivity.java点击连接按钮时,触发Connect方法,进行服务器连接,在socketclient.java中的连接方法connectToServer启动了receiverExecutor线程。

receiverExecutor线程有while,会在while内持续运行,当

这些情况,线程才会结束,即意外断开服务器连接或者手动断开连接,线程才会退出,如果 in.read(buffer) 没有数据可读,线程会阻塞(挂起),直到有数据到达或超时。在接收到正确的数据包时,会触发回调,会在receiverExecutor运行mainactivity内的程序(想在主线程运行内容需要使用runOnUiThread())。

----------------------------------------------------------------------------------------

看一下AI的回答:

 

 

 

 

 

 

相关文章:

Android学习制作app(ESP8266-01S连接-简单制作)

一、理论 部分理论见arduino学习-CSDN博客和Android Studio安装配置_android studio gradle 配置-CSDN博客 以下直接上代码和效果视频&#xff0c;esp01S的收发硬件代码目前没有分享&#xff0c;但是可以通过另一个手机网络调试助手进行模拟。也可以直接根据我的代码进行改动…...

三甲医院大型生信服务器多配置方案剖析与应用(2024版)

一、引言 1.1 研究背景与意义 在当今数智化时代&#xff0c;生物信息学作为一门融合生物学、计算机科学和信息技术的交叉学科&#xff0c;在三甲医院的科研和临床应用中占据着举足轻重的地位。随着高通量测序技术、医学影像技术等的飞速发展&#xff0c;生物医学数据呈爆发式…...

【Unity3D】实现横版2D游戏——单向平台(简易版)

目录 问题 项目Demo直接使用免费资源&#xff1a;Hero Knight - Pixel Art &#xff08;Asset Store搜索&#xff09; 打开Demo场景&#xff0c;进行如下修改&#xff0c;注意Tag是自定义标签SingleDirCollider using System.Collections; using System.Collections.Generic;…...

大白话讲清楚embedding原理

Embedding&#xff08;嵌入&#xff09;是一种将高维数据&#xff08;如单词、句子、图像等&#xff09;映射到低维连续向量的技术&#xff0c;其核心目的是通过向量表示捕捉数据之间的语义或特征关系。以下从原理、方法和应用三个方面详细解释Embedding的工作原理。 一、Embe…...

电脑优化大师-解决电脑卡顿问题

我们常常会遇到电脑运行缓慢、网速卡顿的情况&#xff0c;但又不知道是哪个程序在占用过多资源。这时候&#xff0c;一款能够实时监控网络和系统状态的工具就显得尤为重要了。今天&#xff0c;就来给大家介绍一款小巧实用的监控工具「TrafficMonitor」。 「TrafficMonitor 」是…...

el-table组件样式如何二次修改?

文章目录 前言一、去除全选框按钮样式二、表头颜色的修改 前言 ElementUI中的组件el-table表格组件提供了丰富的样式&#xff0c;有一个全选框的el-table组件&#xff0c;提供了全选框和多选。 一、去除全选框按钮样式 原本默认是有全选框的。假如有一些开发者&#xff0c;因…...

java练习(1)

两数之和&#xff08;题目来自力扣&#xff09; 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案&#xff0c;并且你不能使用两次相…...

UbuntuWindows双系统安装

做系统盘&#xff1a; Ubuntu20.04双系统安装详解&#xff08;内容详细&#xff0c;一文通关&#xff01;&#xff09;_ubuntu 20.04-CSDN博客 ubuntu系统调整大小&#xff1a; 调整指南&#xff1a; 虚拟机中的Ubuntu扩容及重新分区方法_ubuntu重新分配磁盘空间-CSDN博客 …...

DeepSeek大模型技术深度解析:揭开Transformer架构的神秘面纱

摘要 DeepSeek大模型由北京深度求索人工智能基础技术研究有限公司开发&#xff0c;基于Transformer架构&#xff0c;具备卓越的自然语言理解和生成能力。该模型能够高效处理智能对话、文本生成和语义理解等复杂任务&#xff0c;标志着人工智能在自然语言处理领域的重大进展。 关…...

MusicFree-开源的第三方音乐在线播放和下载工具, 支持歌单导入[对标落雪音乐]

MusicFree 链接&#xff1a;https://pan.xunlei.com/s/VOI0RrVLTTWE9kkpt0U7ofGBA1?pwd4ei6#...

Versal - 基础4(VD100+Versal IBERT)

1. 简介 在之前的一篇博文中&#xff0c;我分享了在 Zynq Ultrascale MPSoC 中使用 IBERT 的方法。 《Vivado - 集成眼图分析仪 Serial I/O IBERT 误码率_vivado ibert-CSDN博客》 本文进一步探讨 Versal 中使用 IBERT 的方法。 2. 硬件平台 芯片&#xff1a;XCVE2302-SF…...

vue2和vue3路由封装及区别

Vue 2 和 Vue 3 在路由封装方面有一些区别&#xff0c;主要体现在 Vue Router 版本的升级&#xff08;Vue Router 3 -> Vue Router 4&#xff09;上。下面我们来对比一下 Vue 2 和 Vue 3 在路由封装上的主要区别&#xff0c;并提供相应的代码示例。 1. Vue 2 路由封装&#…...

Windows 系统下使用 Ollama 离线部署 DeepSeek - R1 模型指南

引言 随着人工智能技术的飞速发展&#xff0c;各类大语言模型层出不穷。DeepSeek - R1 凭借其出色的语言理解和生成能力&#xff0c;受到了广泛关注。而 Ollama 作为一款便捷的模型管理和部署工具&#xff0c;能够帮助我们轻松地在本地环境中部署和使用模型。本文将详细介绍如…...

性能测试网络风险诊断有哪些?

目录 一、网络定位分析手段 二、sar命令 三、netstat命令 以下是几种常见的网络风险诊断方法 网络连通性检查 带宽与延迟测量 丢包率分析 网络拓扑结构审查 安全设备影响评估 协议层面上的优化 负载均衡器效能检验 云化服务架构下的特殊考量 系统应用之间的交换&am…...

八股文 (一)

文章目录 项目地址一、前端1.1 大文件上传,预览1.2 首页性能优化1.2 流量染色,灰度发布1.3 Websock心跳机制,大数据实时数据优化1.4 Gpu 加速 fps优化1.5 echarts包大小优化和组件封装1.6 前端监控系统1.7 超大虚拟列表卡顿1. 实现2. 相关问题(1) 什么是虚拟化列表,为什么要…...

TVM调度原语完全指南:从入门到微架构级优化

调度原语 在TVM的抽象体系中&#xff0c;调度&#xff08;Schedule&#xff09;是对计算过程的时空重塑。每一个原语都是改变计算次序、数据流向或并行策略的手术刀。其核心作用可归纳为&#xff1a; 优化目标 max ⁡ ( 计算密度 内存延迟 指令开销 ) \text{优化目标} \max…...

c语言进阶(简单的函数 数组 指针 预处理 文件 结构体)

c语言补充 格式 void函数头 {} 中的是函数体 sum函数名 &#xff08;&#xff09; 参数表 #include <stdio.h>void sum(int begin, int end) {int i;int sum 0;for (i begin ; i < end ; i) {sum i;}printf("%d到%d的和是%d\n", begin, end, sum); …...

终极版已激活!绿话纯净,打开即用!!!

今天我想和大家聊聊一个非常实用的工具——视频转换大师最终版。 视频转换大师终极版&#xff0c;堪称一款全能型的视频制作神器&#xff0c;集视频转换与编辑功能于一体。它搭载的视频增强器技术&#xff0c;能够最大限度地保留原始视频质量&#xff0c;甚至还能实现质量的进…...

Vue.js 什么是 Composition API?

Vue.js 什么是 Composition API&#xff1f; 今天我们来聊聊 Vue 3 引入的一个重要特性&#xff1a;组合式 API&#xff08;Composition API&#xff09;。如果你曾在开发复杂的 Vue 组件时感到代码难以维护&#xff0c;那么组合式 API 可能正是你需要的工具。 什么是组合式 …...

MySQL高可用

一、mysql路由 1.利用路由器的连接路由特性&#xff0c;用户可以编写应用程序来连接到路由器&#xff0c;并令路由器使用响应的路由策略来处理连接来使其连接到正确的mysql数据库服务器 2.mysql route的部署方式 需要在所有数据库主机之外再打开一台主机mysql-router 配置mysql…...

Ubuntu系统下交叉编译openssl

一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机&#xff1a;Ubuntu 20.04.6 LTSHost&#xff1a;ARM32位交叉编译器&#xff1a;arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?

Golang 面试经典题&#xff1a;map 的 key 可以是什么类型&#xff1f;哪些不可以&#xff1f; 在 Golang 的面试中&#xff0c;map 类型的使用是一个常见的考点&#xff0c;其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

MMaDA: Multimodal Large Diffusion Language Models

CODE &#xff1a; https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA&#xff0c;它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

基于数字孪生的水厂可视化平台建设:架构与实践

分享大纲&#xff1a; 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年&#xff0c;数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段&#xff0c;基于数字孪生的水厂可视化平台的…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

Java + Spring Boot + Mybatis 实现批量插入

在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法&#xff1a;使用 MyBatis 的 <foreach> 标签和批处理模式&#xff08;ExecutorType.BATCH&#xff09;。 方法一&#xff1a;使用 XML 的 <foreach> 标签&#xff…...

MySQL 8.0 事务全面讲解

以下是一个结合两次回答的 MySQL 8.0 事务全面讲解&#xff0c;涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容&#xff0c;并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念&#xff08;ACID&#xff09; 事务是…...

Linux系统部署KES

1、安装准备 1.版本说明V008R006C009B0014 V008&#xff1a;是version产品的大版本。 R006&#xff1a;是release产品特性版本。 C009&#xff1a;是通用版 B0014&#xff1a;是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存&#xff1a;1GB 以上 硬盘&#xf…...

通过 Ansible 在 Windows 2022 上安装 IIS Web 服务器

拓扑结构 这是一个用于通过 Ansible 部署 IIS Web 服务器的实验室拓扑。 前提条件&#xff1a; 在被管理的节点上安装WinRm 准备一张自签名的证书 开放防火墙入站tcp 5985 5986端口 准备自签名证书 PS C:\Users\azureuser> $cert New-SelfSignedCertificate -DnsName &…...

【UE5 C++】通过文件对话框获取选择文件的路径

目录 效果 步骤 源码 效果 步骤 1. 在“xxx.Build.cs”中添加需要使用的模块 &#xff0c;这里主要使用“DesktopPlatform”模块 2. 添加后闭UE编辑器&#xff0c;右键点击 .uproject 文件&#xff0c;选择 "Generate Visual Studio project files"&#xff0c;重…...