Android 蓝牙开发( 二 )

前言

上一篇文章给大家分享了Android蓝牙的基础知识和基础用法,不过上一篇都是一些零散碎片化的程序,这一篇给大家分享Android蓝牙开发实战项目的初步使用

效果演示 : 

Android蓝牙搜索,配对,连接,通信

Android蓝牙实战开发步骤

1.新建Android项目添加蓝牙权限

下图所示:MyBluetoothDemo为刚刚创建的Android空项目,我们现在清单文件中把我们需要用到的权限声明一下,其中定位权限还需要做动态申请

2.封装BluetoothAdapter类

BluetoothAdapter类提供了常用的蓝牙API,我这里创建了一个BlueToothController类,小编这里是先将这些API封装到了一个BlueToothController类中,方便后续使用和操作

package com.example.mybluetoothdemo;import android.annotation.SuppressLint;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.content.Intent;import java.util.ArrayList;
import java.util.List;public class BlueToothController {private BluetoothAdapter mBluetoothAdapter;public BlueToothController(){//初始化蓝牙适配器mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();}public BluetoothAdapter getBluetoothAdapter() {return mBluetoothAdapter;}/*** 检查设备是否支持蓝牙*/public boolean isBluetoothSupport(){if(mBluetoothAdapter == null){return false;}else {return true;}}/*** 检查该设备蓝牙是否开启*/public boolean isBluetoothEnabled(){if(mBluetoothAdapter.isEnabled()){return true;}else {return false;}}/*** 打开蓝牙*/@SuppressLint("MissingPermission")public void turnOnBlueTooth(Activity activity, int requestCode) {Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);activity.startActivityForResult(intent, requestCode);}/*** 打开蓝牙可见性*/@SuppressLint("MissingPermission")public void enableVisibily(Context context){Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,300);context.startActivity(intent);}/*** 停止查找设备*/@SuppressLint("MissingPermission")public void cancelFindDevice(){mBluetoothAdapter.cancelDiscovery();}/*** 判断当前设备是否在查找蓝牙设备*/@SuppressLint("MissingPermission")public boolean isStartDiscovering(){if(mBluetoothAdapter.isDiscovering()){return true;}else {return false;}}/*** 判断当前设备是否未在查找蓝牙设备*/@SuppressLint("MissingPermission")public boolean isCancelDiscovering(){if(!mBluetoothAdapter.isDiscovering()){return true;}else {return false;}}/*** 查找设备*/@SuppressLint("MissingPermission")public void findDevice() {mBluetoothAdapter.startDiscovery();}/*** 获取已绑定设备*/@SuppressLint("MissingPermission")public List<BluetoothDevice> getBondedDeviceList(){return new ArrayList<>(mBluetoothAdapter.getBondedDevices());}/*** 判断蓝牙是否连接*/@SuppressLint("MissingPermission")public boolean isConnectBlue(BluetoothSocket bluetoothSocket){return bluetoothSocket !=null && bluetoothSocket.isConnected();}
}

3. 编写UI页面

activity_main.xml:这是我们MainActivity的UI,放置了一个ListView和一个按钮,ListView用来显示搜索到的蓝牙设备和已配对的蓝牙设备,Button控件用来与连接后的设备发送信息时使用

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingLeft="16.dp"android:paddingRight="16.dp"android:paddingBottom="16.dp"><ListViewandroid:id="@+id/device_list"android:layout_width="match_parent"android:layout_height="match_parent"android:divider="#e90423"android:dividerHeight="1px"></ListView><Buttonandroid:id="@+id/btn_write_1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentRight="true"android:layout_alignParentBottom="true"android:text="发送消息"/></RelativeLayout>

既然有了ListView,那就一定有ListView的每条子元素UI,新建list_item.xml

list_item.xml:    用来显示ListView列表的子内容

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:orientation="horizontal"android:layout_height="wrap_content"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><TextView android:id="@+id/text1"android:layout_width="match_parent"android:layout_height="wrap_content"android:textStyle="bold"android:textSize="18sp"/><TextView android:id="@+id/text3"android:layout_width="match_parent"android:layout_height="wrap_content"android:textSize="13sp"/></LinearLayout></LinearLayout>

然后,我们再为页面右上角写一个menu列表按钮,新建menu_main.xml

menu_main.xml:  

<menu xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"tools:context=".MainActivity" ><itemandroid:id="@+id/is_bluetooth_support"android:title="@string/is_bluetooth_support"android:orderInCategory="1" /><itemandroid:id="@+id/is_bluetooth_enabled"android:title="@string/is_bluetooth_enabled"android:orderInCategory="2" /><itemandroid:id="@+id/bonded_device"android:title="@string/bonded_device"android:orderInCategory="2" /><itemandroid:id="@+id/find_device"android:title="@string/find_device"android:orderInCategory="3" /></menu>

最后,再为大家分享一下string.xml字符串配置信息

4. 蓝牙列表适配器

创建DeviceAdapter类,具体如下图所示:

package com.example.mybluetoothdemo;import android.annotation.SuppressLint;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;import java.util.List;public class DeviceAdapter extends BaseAdapter{private List<BluetoothDevice> mData;private Context mContext;public DeviceAdapter(List<BluetoothDevice> data, Context context){mData = data;mContext = context.getApplicationContext();}@Overridepublic int getCount() {return mData.size();}@Overridepublic Object getItem(int i) {return mData.get(i);}@Overridepublic long getItemId(int i) {return i;}@SuppressLint("MissingPermission")@Overridepublic View getView(int i, View view, ViewGroup viewGroup) {View itemView = view;//复用view,优化性能if(itemView == null){itemView = LayoutInflater.from(mContext).inflate(R.layout.list_item, viewGroup,false);}TextView text1 = itemView.findViewById(R.id.text1);TextView text2 = itemView.findViewById(R.id.text3);text1.setTextColor(Color.BLACK);text2.setTextColor(Color.BLACK);//获取对应的蓝牙设备BluetoothDevice device = (BluetoothDevice) getItem(i);//显示设备名称if(device.getName()==null){text1.setText("N/A");}else {text1.setText(device.getName());}//显示设备地址text2.setText(device.getAddress());return itemView;}//刷新列表,防止搜索结果重复出现public void refresh(List<BluetoothDevice> data){mData = data;notifyDataSetChanged();}}

5. 蓝牙搜索,配对,连接,通信

小编这里为了让大家方便,便将搜索,配对,连接都写在了MainActivity中了

package com.example.mybluetoothdemo;import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;import android.Manifest;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;import java.util.ArrayList;
import java.util.List;
import java.util.UUID;public class MainActivity extends AppCompatActivity {private final String TAG = "yf";private BlueToothController blueToothController = new BlueToothController();private static final int REQUEST_ENABLE_BT = 1;private ListView listView;private DeviceAdapter blueToothDeviceAdapter,bondBlueToothDeviceAdapter;private List<BluetoothDevice> deviceList = new ArrayList<>();private List<BluetoothDevice> bondedDeviceList = new ArrayList<>();private BluetoothDevice device;private BluetoothGatt bluetoothGatt;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initUI();//判断是否有访问位置的权限,没有权限,直接申请位置权限isPermission();registerBluetoothReceiver();}@SuppressLint("MissingPermission")private void initUI(){listView = findViewById(R.id.device_list);blueToothDeviceAdapter = new DeviceAdapter(deviceList,this);bondBlueToothDeviceAdapter = new DeviceAdapter(bondedDeviceList,this);findViewById(R.id.btn_write_1).setOnClickListener(view -> {if (null == mWriter){Log.e("cx12345","ble:发送失败:null == writer !!!!");}else {mWriter.setValue(new byte[]{(byte)0x0c,(byte)0x11,(byte)0x09,(byte)0x41,(byte)0x23,(byte)0x00,(byte)0x01,(byte)0x03,(byte)0xFF});mGatt.writeCharacteristic(mWriter);}});}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {getMenuInflater().inflate(R.menu.menu_main,menu);return true;}@SuppressLint("MissingPermission")@Overridepublic boolean onOptionsItemSelected(MenuItem item) {int id = item.getItemId();switch (id){case R.id.is_bluetooth_support:if (blueToothController.isBluetoothSupport()){Toast.makeText(MainActivity.this, "该设备支持蓝牙功能", Toast.LENGTH_SHORT).show();}else {Toast.makeText(MainActivity.this, "该设备不支持蓝牙功能", Toast.LENGTH_SHORT).show();}break;case R.id.is_bluetooth_enabled:if (blueToothController.isBluetoothEnabled()){Toast.makeText(MainActivity.this, "蓝牙已开启", Toast.LENGTH_SHORT).show();}else {blueToothController.turnOnBlueTooth(this,REQUEST_ENABLE_BT);}break;case R.id.bonded_device:setTitle("已配对的设备");bondedDeviceList = blueToothController.getBondedDeviceList();listView.setAdapter(bondBlueToothDeviceAdapter);bondBlueToothDeviceAdapter.refresh(bondedDeviceList);break;case R.id.find_device:setTitle("可用设备");if(blueToothController.isStartDiscovering()){blueToothController.cancelFindDevice();}blueToothController.findDevice();
//                blueToothController.getBluetoothAdapter().startLeScan(leScanCallback);listView.setAdapter(blueToothDeviceAdapter);blueToothDeviceAdapter.refresh(deviceList);listView.setOnItemClickListener(deviceBluetooth);break;default:break;}return super.onOptionsItemSelected(item);}private AdapterView.OnItemClickListener deviceBluetooth = new AdapterView.OnItemClickListener() {@SuppressLint("MissingPermission")public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {device = deviceList.get(i);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {//蓝牙绑定
//                device.createBond();//Gatt协议连接蓝牙bluetoothGatt = device.connectGatt(MainActivity.this,true,mGattCallback);bluetoothGatt.connect();}}};//动态获取位置权限private void isPermission(){if ((checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)|| (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)) {requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, 200);}}@SuppressLint("MissingPermission")@Overrideprotected void onDestroy() {super.onDestroy();// 停止设备搜索blueToothController.getBluetoothAdapter().cancelDiscovery();//注销广播unregisterReceiver(receiver);}private void registerBluetoothReceiver(){//filter注册广播接收器IntentFilter filter = new IntentFilter();//蓝牙当前状态filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);//开始扫描蓝牙设备广播filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);//找到蓝牙设备广播filter.addAction(BluetoothDevice.ACTION_FOUND);//扫描蓝牙设备结束广播filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//蓝牙设备配对状态改变广播filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);//设备扫描模式改变广播filter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);registerReceiver(receiver, filter);}//处理找到蓝牙设备和搜索完成的广播消息BroadcastReceiver receiver = new BroadcastReceiver() {@SuppressLint("MissingPermission")@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();//开始查找设备if(BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)){//初始化适配器列表deviceList.clear();bondedDeviceList.clear();blueToothDeviceAdapter.refresh(deviceList);bondBlueToothDeviceAdapter.refresh((bondedDeviceList));}//找到蓝牙设备else if(BluetoothDevice.ACTION_FOUND.equals(action)){//搜到蓝牙设备BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);//把搜索到的设备添加到已找到列表中,显示它的信息deviceList.add(device);blueToothDeviceAdapter.refresh(deviceList);}//查找设备结束else if(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)){//搜索完毕Toast.makeText(MainActivity.this, "选择要配对的蓝牙设备", Toast.LENGTH_SHORT).show();blueToothDeviceAdapter.refresh(deviceList);}//配对状态else if(BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)){BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);if(device == null){Toast.makeText(MainActivity.this, "无设备", Toast.LENGTH_SHORT).show();return;}int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,0);if(state == BluetoothDevice.BOND_BONDED){Toast.makeText(MainActivity.this, "已配对", Toast.LENGTH_SHORT).show();}else if(state == BluetoothDevice.BOND_BONDING){Toast.makeText(MainActivity.this, "正在配对", Toast.LENGTH_SHORT).show();}else if(state == BluetoothDevice.BOND_NONE){Toast.makeText(MainActivity.this, "未配对", Toast.LENGTH_SHORT).show();}}}};private BluetoothGatt mGatt;private BluetoothGattCharacteristic mWriter;/*** @param gatt     返回连接建立的gatt对象* @param status   返回的是此次gatt操作的结果,成功了返回0* @param newState 每次client连接或断开连接状态变化,*                 STATE_CONNECTED 0,*                 STATE_CONNECTING 1,*                 STATE_DISCONNECTED 2,*                 STATE_DISCONNECTING 3*/private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {@SuppressLint("MissingPermission")@Overridepublic void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {//连接成功if(newState == BluetoothProfile.STATE_CONNECTED){//进行服务发现gatt.discoverServices();Log.d(TAG,"连接成功");}else if(newState == BluetoothProfile.STATE_DISCONNECTED){//连接断开,处理断开逻辑Log.d(TAG,"连接断开");}}@SuppressLint("MissingPermission")@Overridepublic void onServicesDiscovered(BluetoothGatt gatt, int status) {Log.d(TAG,"onServicesDiscovered : " + status + " ==>> " + gatt.toString());//发现服务成功,处理服务和特征值if(status == BluetoothGatt.GATT_SUCCESS){//发送消息mGatt = gatt;BluetoothGattService service = gatt.getService(UUID.fromString("0000180a-0000-1000-8000-00805F9B34FB"));mWriter = service.getCharacteristic(UUID.fromString("00002ad9-0000-1000-8000-00805F9B34FB"));//打开消息通知mGatt.setCharacteristicNotification(mWriter,true);BluetoothGattDescriptor descriptor = mWriter.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);mGatt.writeDescriptor(descriptor);}else {Log.d(TAG,"发现服务失败");}}@Overridepublic void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {Log.e(TAG,"onCharacteristicRead " + status);//读取特征成功,处理特征值if(status == BluetoothGatt.GATT_SUCCESS){}}@Overridepublic void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {Log.e(TAG,"onCharacteristicWrite " + status);//写入特征成功if(status == BluetoothGatt.GATT_SUCCESS){Log.d(TAG,"发送成功");}else {Log.d(TAG,"发送失败");}}@Overridepublic void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {//接收到数据byte[] data = characteristic.getValue();//处理接收到的数据Log.d(TAG,"Received data: " + bytesToHexFun2(data));}@Overridepublic void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {super.onDescriptorRead(gatt, descriptor, status);}@Overridepublic void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {super.onDescriptorWrite(gatt, descriptor, status);}@Overridepublic void onReliableWriteCompleted(BluetoothGatt gatt, int status) {super.onReliableWriteCompleted(gatt, status);}@Overridepublic void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {super.onReadRemoteRssi(gatt, rssi, status);}@Overridepublic void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {super.onMtuChanged(gatt, mtu, status);}@Overridepublic void onServiceChanged(@NonNull BluetoothGatt gatt) {super.onServiceChanged(gatt);}@Overridepublic void onPhyUpdate(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {super.onPhyUpdate(gatt, txPhy, rxPhy, status);}@Overridepublic void onPhyRead(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {super.onPhyRead(gatt, txPhy, rxPhy, status);}};private char[] HEX_CHAR = {'0', '1', '2', '3', '4', '5','6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};private  String bytesToHexFun2(byte[] bytes) {char[] buf = new char[bytes.length * 2];int index = 0;for(byte b : bytes) { // 利用位运算进行转换,可以看作方法一的变种buf[index++] = HEX_CHAR[b >>> 4 & 0xf];buf[index++] = HEX_CHAR[b & 0xf];}return new String(buf);}}

到此为止,我们的程序就到这里了,蓝牙搜索,配对,连接,通信便已经成功实现了,大家可以把代码copy一下拿去运行,具体效果演示图在文章最上方,大家还想了解更多关于Android蓝牙开发的可以继续看我下一篇给大家的分享

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

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

相关文章

模拟实现应用层协议

模拟实现应用层协议 文章目录 模拟实现应用层协议应用层再谈协议 序列化和反序列化 网络版计算器自定义协议利用Json进行序列化和反序列化json库的安装条件编译 应用层 应用层&#xff08;Application layer&#xff09;是OSI模型的第七层。应用层直接和应用程序接口并提供常见…

在 WSL2 中使用 NVIDIA Docker 进行全栈开发和深度学习 TensorFlow pytorch GPU 加速

在 WSL2 中使用 NVIDIA Docker 进行全栈开发和深度学习 TensorFlow pytorch GPU 加速 0. 背景 0.1 起源 生产环境都是在 k8d pod 中运行&#xff0c;直接在容器中开发不好嘛&#xff1f;每次换电脑&#xff0c;都要配配配&#xff0c;呸呸呸新电脑只安装日常用的软件不好嘛&…

INDEMIND:“大+小”多机协同,实现机器人商用场景全覆盖

随着商用清洁机器人进入越来越多的场景中&#xff0c;单一的中型机器人并不能有效覆盖所有区域&#xff0c;更加细分化的产品组合正在成为新的趋势。 产品形态的“新趋势” 在商用场景中&#xff0c;目前的商用清洁机器人几乎均是中大型的产品形态&#xff0c;较大的体型意味…

视频汇聚/视频云存储/视频监控管理平台EasyCVR新增首次登录强制修改密码

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。视频汇聚平台既具…

[JDK8下的HashMap类应用及源码分析] 数据结构、哈希碰撞、链表变红黑树

系列文章目录 [Java基础] StringBuffer 和 StringBuilder 类应用及源码分析 [Java基础] 数组应用及源码分析 [Java基础] String&#xff0c;分析内存地址&#xff0c;源码 [JDK8环境下的HashMap类应用及源码分析] 第一篇 空构造函数初始化 [JDK8环境下的HashMap类应用及源码分…

Vue3列表竖向滚动(包含使用swiper的翻页效果)

一、使用element-plus表格进行滚动&#xff1a; 可以满足的需求&#xff1a;表格一行一行竖向滚动&#xff0c;类似走马灯。 不能满足的需求&#xff1a;表格分页竖向滚动&#xff0c;有翻页的效果。 代码&#xff1a; <template><el-table:data"tableData"…

Redis——》Redis的部署方式对分布式锁的影响

推荐链接&#xff1a; 总结——》【Java】 总结——》【Mysql】 总结——》【Redis】 总结——》【Kafka】 总结——》【Spring】 总结——》【SpringBoot】 总结——》【MyBatis、MyBatis-Plus】 总结——》【Linux】 总结——》【MongoD…

Java常见的排序算法

排序分为内部排序和外部排序&#xff08;外部存储&#xff09; 常见的七大排序&#xff0c;这些都是内部排序 。 1、插入排序&#xff1a;直接插入排序 1、插入排序&#xff1a;每次将一个待排序的记录&#xff0c;按其关键字的大小插入到前面已排序好的记录序列 中的适当位置…

ChatGPT AIGC 一个指令总结Python所有知识点

在ChatGPT中,直接输入一个指令就可以生成Python的所有知识点大纲。 非常实用的ChatGPT功能。 AIGC ChatGPT ,BI商业智能, 可视化Tableau, PowerBI, FineReport, 数据库Mysql Oracle, Office, Python ,ETL Excel 2021 实操,函数,图表,大屏可视化 案例实战 http://t.…

Angular中使用drag and drop实现文件拖拽上传,及flask后端接收

效果&#xff1a;拖拽文件到组件上面时 边框变大变红 松手后发送到服务器(或者点击蓝字手动选择文件)并且把文件名显示在框内&#xff0c;美化还没做 html <div class"drapBox"><div id"drop" (dragenter)"dragenter($event)" (dragov…

redis 应用 4: HyperLogLog

我们先思考一个常见的业务问题&#xff1a;如果你负责开发维护一个大型的网站&#xff0c;有一天老板找产品经理要网站每个网页每天的 UV 数据&#xff0c;然后让你来开发这个统计模块&#xff0c;你会如何实现&#xff1f; img 如果统计 PV 那非常好办&#xff0c;给每个网页一…

后台管理系统:项目路由搭建与品牌管理

路由的搭建 先删除一些不需要的界面 然后发现跑不起来&#xff0c;我们需要去配置 删减成这样&#xff0c;然后自己新建需要的路由组件 改成这样&#xff0c;这里要注意。我们是在layout这个大的组件下面的&#xff0c;meta 中的title就是我们侧边栏的标题&#xff0c;icon可…

Java eight 解读流(Stream)、文件(File)、IO和异常处理的使用方法

目录 Java 流(Stream)、文件(File)和IO读取控制台输入读写文件FileInputStreamFileOutputStream Java目录 Java 异常处理 Java 流(Stream)、文件(File)和IO java.io 包几乎包含了所有操作输入、输出需要的类。所有这些流类代表了输入源和输出目标。 Java.io 包中的流支持很多种…

51页企业数字化转型战略实践与启示PPT(附400份转型资料)

本资料来源公开网络&#xff0c;仅供个人学习&#xff0c;请勿商用&#xff0c;如有侵权请联系删除&#xff0c;更多内容浏览公众号&#xff1a;智慧方案文库 企业数字化转型之路.pptx企业数字化转型大数据湖一体化平台项目建设方案PPT.pptx企业数字化转型大数据湖一体化运营管…

Angular安全专辑之四 —— 避免服务端可能的资源耗尽(NodeJS)

express-rate-limit是一个简单实用的npm包,用于在Express应用程序中实现速率限制。它可以帮助防止DDoS攻击和暴力破解,同时还允许对API端点进行流控。 express-rate-limit及其主要功能 express-rate-limit是Express框架的一个流行中间件,它允许根据IP地址或其他标准轻松地对请求…

U盘文件恢复软件推荐,这几款高效恢复数据!

“我真的可以算得上是一个u盘杀手了&#xff0c;好多资料保存在u盘中&#xff0c;但经常都会由于粗心导致u盘中的数据丢失。大家有什么u盘文件恢复软件可以推荐吗&#xff1f;救救我的u盘吧&#xff01;” 在现代社会&#xff0c;人手一个u盘一点也不夸张。尤其是学生党和打工人…

阿里云架构

负载均衡slb 分类以及应用场景 负载均衡slb clb 传统的负载均衡(原slb) 支持4层和7层(仅支持对uri(location),域名进行转发) 一般使用slb(clb) alb 应用负载均衡 只支持7层,整合了nginx负载均衡的各种功能,可以根据用户请求头,响应头 如果需要详细处理用户请求(浏…

华为数通方向HCIP-DataCom H12-821题库(单选题:141-160)

第141题 Router-LSA 能够描述不同的链路类型&#xff0c;不属于Router LSA 链路类型的是以下哪一项? A、Link Type 可以用来描述到末梢网络的连接&#xff0c;即 SubNet B、Link Type 可以用来描述到中转网络的连接&#xff0c;即 TranNet C、Link Type 可以用来描述到另一…

2023京东口腔护理赛道行业数据分析(京东销售数据分析)

近年来&#xff0c;口腔护理逐渐成为年轻人重视的健康领域&#xff0c;从口腔护理整体市场来看&#xff0c;牙膏和牙刷等基础口腔护理产品仍占据主导地位。不过&#xff0c;随着口腔护理市场逐步朝向精致化、专业化、多元化等方向发展&#xff0c;不少新兴口腔护理产品受到消费…

算法通关村第8关【白银】| 二叉树的深度和高度问题

1.最大深度问题 思路&#xff1a;递归三部曲 第一步&#xff1a;确定参数和返回值 题目要求求二叉树的深度&#xff0c;也就是有多少层&#xff0c;需要传递一个root从底层向上统计 int maxDepth(TreeNode root) 第二步&#xff1a;确定终止条件 当递归到null时就说明到底了…