网站建设数据库实训体会/项目优化seo
思路:
通过媒体录制器MediaRecorder实现:MediaRecorder是Android自带的音频和视频录制工具,它通过操纵摄像头和麦克风完成媒体录制,既可录制视频,又可单独录制音频。
MediaRecorder常用方法(录音与录像通用):
- reset:重置录制资源。
- prepare:准备录制。
- start:开始录制。
- stop:结束录制。
- release:释放录制资源。
- setOnErrorListener:设置错误监听器。可监听服务器异常和未知错误的事件。需要实现接口MediaRecorder.OnErrorListener的onError方法。
- setOnInfoListener:设置信息监听器。可监听录制结束事件,包括达到录制时长或达到录制大小。需要实现接口MediaRecorder.OnInfoListener的onInfo方法。
- setMaxDuration:设置可录制的最大时长,单位毫秒。
- setMaxFileSize:设置可录制的最大文件大小,单位字节。
- setOutputFile:设置输出文件的路径。
setOutputFormat:设置媒体输出格式 | |||
OutputFormat类的输出格式 | 格式分类 | 扩展名 | 格式说明 |
AMR_NB | 音频 | .amr | 窄带格式 |
AMR_WB | 音频 | .amr | 宽带格式 |
AAC_ADTS | 音频 | .aac | 高级的音频传输流格式 |
MPEG_4 | 视频 | .mp4 | MPEG4格式 |
THREE_GPP | 视频 | .3gp | 3GP格式 |
音频录制示例,上代码
一.权限添加
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /><uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /><uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /><uses-permission android:name="android.permission.RECORD_AUDIO"/><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32"/><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32"/>
权限区分版本33及以上和以下
动态权限请求:
使用权限请求库,在app的build.gradle添加
// 权限请求implementation 'com.guolindev.permissionx:permissionx:1.7.1'
使用音频抖动动效
// https://github.com/xfans/VoiceWaveView
implementation 'com.github.xfans:VoiceWaveView:1.0.2'
/*** 请求视频、音频、图片权限*/private void requestPermission() {ArrayList<String> requestList = new ArrayList<>();if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {requestList.add(Manifest.permission.READ_MEDIA_IMAGES);requestList.add(Manifest.permission.RECORD_AUDIO);requestList.add(Manifest.permission.READ_MEDIA_VIDEO);} else {requestList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);requestList.add(Manifest.permission.READ_EXTERNAL_STORAGE);requestList.add(Manifest.permission.RECORD_AUDIO);}PermissionX.init(this).permissions(requestList).onExplainRequestReason((scope, deniedList) -> {scope.showRequestReasonDialog(deniedList, UiUtil.getString(R.string.toast_permission_request), UiUtil.getString(R.string.toast_permission_allow), UiUtil.getString(R.string.toast_permission_deny));}).request((allGranted, grantedList, deniedList) -> {if (allGranted) {showVoiceAddDialog();LogUtil.i(TAG, "所有申请的权限都已通过");} else {LogUtil.i(TAG, "您拒绝了如下权限:" + deniedList);}});}/*** 判断是否有存储、音频权限* @return */public boolean hasStoragePermissions() {boolean isStorage, isAudio, isVideo, isImages;if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {isImages = ContextCompat.checkSelfPermission(MyApplication.getInstance(), Manifest.permission.READ_MEDIA_IMAGES)== PackageManager.PERMISSION_GRANTED;isAudio = ContextCompat.checkSelfPermission(MyApplication.getInstance(), Manifest.permission.RECORD_AUDIO)== PackageManager.PERMISSION_GRANTED;isVideo = ContextCompat.checkSelfPermission(MyApplication.getInstance(), Manifest.permission.READ_MEDIA_VIDEO)== PackageManager.PERMISSION_GRANTED;return isImages && isAudio && isVideo;} else {isStorage = ContextCompat.checkSelfPermission(MyApplication.getInstance(), Manifest.permission.WRITE_EXTERNAL_STORAGE)== PackageManager.PERMISSION_GRANTED;isAudio = ContextCompat.checkSelfPermission(MyApplication.getInstance(), Manifest.permission.RECORD_AUDIO)== PackageManager.PERMISSION_GRANTED;return isStorage || isAudio;}}
二.录制代码
package com.calendar.master.gp.dialog;import android.app.AlertDialog;
import android.app.Dialog;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.format.DateFormat;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;import com.calendar.master.gp.R;
import com.calendar.master.gp.bean.NoteVoice;
import com.calendar.master.gp.databinding.DialogAddVoiceBinding;
import com.calendar.master.gp.databinding.DialogEmojiBinding;
import com.calendar.master.gp.fragment.EmojiFragment;
import com.calendar.master.gp.listener.IVoiceSaveListener;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
import com.oooppqqzzz.base.utils.LogUtil;import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;import me.xfans.lib.voicewaveview.VoiceWaveView;/*** 描述:* 作者: shawn* 时间: 2023/4/2716:44*/
public class VoiceAddDialogFragment extends DialogFragment {private static final String TAG = "VoiceAddDialogFragment";private MediaRecorder mMediaRecorder;private String voicePath;private String outputFileName;private File fileVoice;private IVoiceSaveListener iVoiceSaveListener;private DialogAddVoiceBinding mBinding;private int recordingTime = 0; // 记录录音时长(秒)private Handler handler = new Handler(Looper.getMainLooper()) {@Overridepublic void handleMessage(@NonNull Message msg) {// 更新UI显示录音时长mBinding.tvVoiceTime.setText(getRecordTime(recordingTime));}};;@Overridepublic void onStart() {super.onStart();setCustomStyle();}@Nullable@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {if (getDialog() == null) {return super.onCreateView(inflater, container, savedInstanceState);}// 设置宽度为屏宽、靠近屏幕底部。final Window window = getDialog().getWindow();window.setBackgroundDrawableResource(R.color.transparent);window.getDecorView().setPadding(0, 0, 0, 0);WindowManager.LayoutParams wlp = window.getAttributes();wlp.gravity = Gravity.BOTTOM;wlp.width = WindowManager.LayoutParams.MATCH_PARENT;wlp.height = WindowManager.LayoutParams.WRAP_CONTENT;window.setAttributes(wlp);return super.onCreateView(inflater, container, savedInstanceState);}@NonNull@Overridepublic Dialog onCreateDialog(Bundle savedInstanceState) {// 加载布局文件mBinding = DialogAddVoiceBinding.inflate(getLayoutInflater());// 音频抖动控件VoiceWaveView voiceWaveView = mBinding.vwvVoice;voiceWaveView.setDuration(100);voiceWaveView.addHeader(12).addHeader(14).addHeader(26);voiceWaveView.addBody(27).addBody(17).addBody(38).addBody(88).addBody(38).addBody(24).addBody(8).addBody(18).addBody(48).addBody(30).addBody(60).addBody(38);voiceWaveView.addFooter(24).addFooter(14).addFooter(8);mBinding.ivClose.setOnClickListener(v -> {this.dismiss();});mBinding.ivVoiceEdit.setOnClickListener(new View.OnClickListener() {boolean isInput = true;@Overridepublic void onClick(View v) {if (isInput) {isInput = false;voiceWaveView.start();mBinding.ivVoiceEdit.setBackgroundResource(R.mipmap.icon_voice_edit_stop);getPath();startRecord();} else {isInput = true;voiceWaveView.stop();cancelRecord();// 移除定时任务handler.removeCallbacks(timerRunnable);voiceStop(true);}}});mBinding.ivVoiceCancel.setOnClickListener(v -> {voiceStop(false);fileVoice.delete();recordingTime = 0;mBinding.tvVoiceTime.setText("00:00");mBinding.ivVoiceEdit.setBackgroundResource(R.mipmap.icon_voice_edit_start);});mBinding.ivVoiceSave.setOnClickListener(v -> {NoteVoice noteVoice = new NoteVoice();noteVoice.setUrl(voicePath);noteVoice.setTime(getRecordTime(recordingTime));noteVoice.setFileName(outputFileName);if (iVoiceSaveListener != null) {iVoiceSaveListener.save(noteVoice);}dismiss();});return new AlertDialog.Builder(getActivity()).setView(mBinding.getRoot()).create();}private void showAd(int selectIndex) {}private void voiceStop(boolean isStop) {if (isStop) {mBinding.ivVoiceCancel.setVisibility(View.VISIBLE);mBinding.ivVoiceSave.setVisibility(View.VISIBLE);mBinding.ivVoiceEdit.setVisibility(View.GONE);} else {mBinding.ivVoiceCancel.setVisibility(View.GONE);mBinding.ivVoiceSave.setVisibility(View.GONE);mBinding.ivVoiceEdit.setVisibility(View.VISIBLE);}}private void setCustomStyle() {// 设置主题,这里只能通过xml方式设置主题,不能通过Java代码处理,因为这是getWindow还是null,// 而且window的几乎所有属性,都可以通过xml设置setStyle(STYLE_NORMAL, R.style.AddDialogTheme);}/*** 录制前创建一个空文件并获取路径*/private void getPath() {File appDir = new File(Environment.getExternalStorageDirectory() + File.separator + Environment.DIRECTORY_MUSIC, "NoteToVoice");if (!appDir.exists()) {appDir.mkdirs();}outputFileName = System.currentTimeMillis() + ".amr";fileVoice = new File(appDir, outputFileName);if (!fileVoice.exists()) {try {fileVoice.createNewFile();voicePath = fileVoice.getPath();LogUtil.i("shawn", "音频保存路径:" + voicePath);} catch (IOException e) {e.printStackTrace();}}}/*** 开始录音*/private void startRecord() {// 充值录音时长recordingTime = 0;//开始录音操作mMediaRecorder = new MediaRecorder(); // 创建一个媒体录制器mMediaRecorder.setOnErrorListener(new MediaRecorder.OnErrorListener() {@Overridepublic void onError(MediaRecorder mr, int what, int extra) {if (mr != null) {mr.reset(); // 重置媒体录制器}}}); // 设置媒体录制器的错误监听器mMediaRecorder.setOnInfoListener(new MediaRecorder.OnInfoListener() {@Overridepublic void onInfo(MediaRecorder mr, int what, int extra) {// 录制达到最大时长,或者达到文件大小限制,都停止录制if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED|| what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED) {cancelRecord();}}}); // 设置媒体录制器的信息监听器mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); // 设置音频源为麦克风mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB); // 设置媒体的输出格式mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); // 设置媒体的音频编码器// mMediaRecorder.setAudioSamplingRate(8); // 设置媒体的音频采样率。可选// mMediaRecorder.setAudioChannels(2); // 设置媒体的音频声道数。可选// mMediaRecorder.setAudioEncodingBitRate(1024); // 设置音频每秒录制的字节数。可选mMediaRecorder.setMaxDuration(10 * 1000); // 设置媒体的最大录制时长// mMediaRecorder.setMaxFileSize(1024*1024*10); // 设置媒体的最大文件大小// setMaxFileSize与setMaxDuration设置其一即可mMediaRecorder.setOutputFile(voicePath); // 设置媒体文件的保存路径try {mMediaRecorder.prepare(); // 媒体录制器准备就绪mMediaRecorder.start(); // 媒体录制器开始录制startRecordingTimer();} catch (Exception e) {LogUtil.i("shawn", "录音出错 = " + e.getMessage());e.printStackTrace();}}// 取消录制操作private void cancelRecord() {if (mMediaRecorder != null) {mMediaRecorder.setOnErrorListener(null); // 错误监听器置空mMediaRecorder.setPreviewDisplay(null); // 预览界面置空try {LogUtil.i("shawn", "结束录音");mMediaRecorder.stop(); // 媒体录制器停止录制} catch (Exception e) {LogUtil.i("shawn", "结束录音出错 = " + e.getMessage());e.printStackTrace();}mMediaRecorder.release(); // 媒体录制器释放资源mMediaRecorder = null;}}@Overridepublic void onDestroy() {super.onDestroy();// 移除定时任务handler.removeCallbacks(timerRunnable);}public void setVoiceSaveListener(IVoiceSaveListener iVoiceSaveListener) {this.iVoiceSaveListener = iVoiceSaveListener;}private void startRecordingTimer() {handler.postDelayed(timerRunnable, 1000); // 每隔一秒执行一次}private Runnable timerRunnable = new Runnable() {@Overridepublic void run() {recordingTime++;handler.sendEmptyMessage(0); // 通知UI更新startRecordingTimer(); // 继续下一次定时}};private String getRecordTime(int recordingTime) {StringBuilder stringBuilder = new StringBuilder();if (recordingTime < 10) {stringBuilder.append("00:0").append(recordingTime);} else if (recordingTime < 60) {stringBuilder.append("00:").append(recordingTime);} else {int minutes = recordingTime / 60;int seconds = recordingTime % 60;if (minutes < 10) {stringBuilder.append("0").append(minutes).append(":");} else {stringBuilder.append(minutes).append(":");}if (seconds < 10) {stringBuilder.append("0").append(seconds);} else {stringBuilder.append(seconds);}}return stringBuilder.toString();}
}
设置dialog样式,在style.xml
<!-- 这里的parent必须是Theme.AppCompat.Dialog --><style name="AddDialogTheme" parent="Theme.AppCompat.Dialog"><!-- 这两个属性对于一个常规的Dialog,一般必须设置的--><!-- 这两个属性按照下面的值设置之后,确保了弹窗的实际显示效果,跟你在layout文件中的定义效果是一样的 --><item name="android:windowIsFloating">false</item>
<!-- <item name="android:windowBackground">@drawable/radius_add_dialog_bg</item>--></style>
相关文章:

Android 实现录音功能
思路: 通过媒体录制器MediaRecorder实现:MediaRecorder是Android自带的音频和视频录制工具,它通过操纵摄像头和麦克风完成媒体录制,既可录制视频,又可单独录制音频。 MediaRecorder常用方法(录音与录像通用)…...

drawio导出矢量图
1.选中要导出的图 2.导出为pdf 3.用adobe打开pdf,另存为eps...

关于angular router-outlet
关于angular router-outlet Angular是一个现代化的前端框架,它提供了很多强大的工具来帮助我们开发出高效的Web应用。其中一个最常用的功能是路由(routing)系统,它允许我们在不同的URL之间导航并加载不同的组件。而<router-ou…...

设计模式详解-桥接模式
类型:结构型模式 实现原理:将抽象类和实现类分离,使其独立,然后使用接口再将二者连接起来。 意图:将抽象部分与实现部分分离,使它们都可以独立的变化。 主要解决:类变化频繁时用继承可能会出…...

设计模式—— 单一职责原则
文章目录 设计模式的目的设计模式原则单一职责原则基本介绍应用实例单一职责原则注意事项和细节 设计模式的目的 1,代码重用性(即:相同功能的代码,不用多次编写) 2,可读性(即:编程…...
嵌入式系统中如何选择RTC电池?
RTC(Real Time Clock)是一种用于提供系统时间的独立定时器,它可以在系统断电或低功耗模式下继续运行,只需要一个后备电池作为供电源。在嵌入式系统中,选择合适的RTC电池时非常关键的,它会影响系统时间的准确…...

56 | 国内游戏直播竞品分析
国内游戏直播竞品分析 一、需求分析 当前直播用户群可分为两大类: 主播观众用户需求: 1.主播: 作为直播内容的创造者,主播表现方式和内容很大程度上决定了观众的需求, 其中主播主要只有三点需求: (一) 通过某一手段(如游戏技术、唱歌技巧)获取他人关注,满足虚荣心…...

STM32 CubeMX (第一步Freertos任务管理:创建、删除、挂起、恢复)
STM32 CubeMX Freertos STM32 CubeMX (Freertos任务:创建、删除、挂起、恢复) STM32 CubeMX Freertos前言一、STM32 CubeMX 配置时钟树配置HAL时基选择TIM1(不要选择滴答定时器;滴答定时器留给OS系统做时基)…...

0101读写分离测试-jdbc-shardingsphere-中间件
文章目录 1 前言2、创建SpringBoot程序2.1、创建项目2.2、添加依赖2.3、生成实体类、service与Mapper1.5、配置读写分离 2、测试2.1、读写分离测试2.2、事务测试2.3、负载均衡测试 结语 1 前言 shardingshpere-jdbc定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的…...

sqlite3将词典导入数据库
使用sqlite3代码实现将词典导入数据库中 #include <head.h> #include <sqlite3.h> #include <strings.h> #include <unistd.h> int main(int argc, const char *argv[]) {sqlite3 *db NULL;if(sqlite3_open("./dict.db",&db) ! SQLITE…...

浏览器 - 事件循环机制详解
目录 1,浏览器进程模型进程线程浏览器的进程和线程1,浏览器进程2,网络进程3,渲染进程 2,渲染主线程事件循环异步同步 JS 为什么会阻塞渲染任务优先级 3,常见面试题1,如何理解 js 的异步2&#x…...

析构函数中不应该抛出异常(摘录)
析构函数中抛出异常时概括性总结 从语法上面讲,析构函数抛出异常是可以的,C并没有禁止析构函数引发异常,但是C不推荐这一做法,从析构函数中抛出异常是及其危险的。 如果析构函数抛出异常,则异常点之后的程序不会执行&a…...

Windows定时任务计划无法显示任务程序界面的问题解决
笔者这两天写了一个python脚本程序,用来自动从公司的主数据系统获取数据,并按格式编制成excel。脚本程序编写一切顺利,运行结果很是完美,笔者很是舒心。但在最后一步,用上班的电脑每天早上定时运行它时,出了…...

【Azure API 管理】APIM如何实现对部分固定IP进行访问次数限制呢?如60秒10次请求
问题描述 使用Azure API Management, 想对一些固定的IP地址进行访问次数的限制,如被限制的IP地址一分钟可以访问10次,而不被限制的IP地址则可以无限访问? ChatGPT 解答 最近ChatGPT爆火,所以也把这个问题让ChatGPT来解答&#x…...

Python学习笔记_进阶篇(二)_django知识(一)
本章简介: Django 简介Django 基本配置Django urlDjango viewDjango 模板语言Django Form Django 简介 Django是一个开放源代码的Web应用框架,由Python写成。采用了MVC的软件设计模式,即模型M,视图V和控制器C。它最初是被开发来…...

【hive】hive中row_number() rank() dense_rank()的用法
hive中row_number() rank() dense_rank()的用法 一、函数说明 主要是配合over()窗口函数来使用的,通过over(partition by order by )来反映统计值的记录。 rank() over()是跳跃排序,有两个第二名时接下来就是第四名(同样是在各个分组内)dense_rank() …...

【云原生】【k8s】Kubernetes+EFK构建日志分析安装部署
目录 EFK安装部署 一、环境准备(所有主机) 1、主机初始化配置 2、配置主机名并绑定hosts,不同主机名称不同 3、主机配置初始化 4、部署docker环境 二、部署kubernetes集群 1、组件介绍 2、配置阿里云yum源 3、安装kubelet kubeadm …...

计算实数数组中所有元素的绝对值 numpy.fabs()
【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 计算实数数组中所有元素的绝对值 numpy.fabs() [太阳]选择题 请问关于以下代码表述错误的是? iimport numpy as np a np.array([-1,-3]) b np.array([-1,34j]) print("【显…...

深入浅出Pytorch函数——torch.nn.init.orthogonal_
分类目录:《深入浅出Pytorch函数》总目录 相关文章: 深入浅出Pytorch函数——torch.nn.init.calculate_gain 深入浅出Pytorch函数——torch.nn.init.uniform_ 深入浅出Pytorch函数——torch.nn.init.normal_ 深入浅出Pytorch函数——torch.nn.init.c…...

ORACLE中UNION、UNION ALL、MINUS、INTERSECT学习
1、UNION和UNION ALL的使用与区别 如果我们需要将两个select语句的结果作为一个整体显示出来,我们就需要用到union或者union all关键字。union的作用是将多个结果合并在一起显示出来。 union和union all的区别是union会自动压缩多个结果集合中的重复结果ÿ…...

【k8s、云原生】基于metrics-server弹性伸缩
第四阶段 时 间:2023年8月18日 参加人:全班人员 内 容: 基于metrics-server弹性伸缩 目录 一、Kubernetes部署方式 (一)minikube (二)二进制包 (三)Kubeadm 二…...

回归预测 | MATLAB实现WOA-SVM鲸鱼算法优化支持向量机多输入单输出回归预测(多指标,多图)
回归预测 | MATLAB实现WOA-SVM鲸鱼算法优化支持向量机多输入单输出回归预测(多指标,多图) 目录 回归预测 | MATLAB实现WOA-SVM鲸鱼算法优化支持向量机多输入单输出回归预测(多指标,多图)效果一览基本介绍程…...

VSCode快捷键
CtrlShiftP,F1:显示命令面板 CtrlP:快速打开 CtrlShiftN:新窗口/实例 CtrlShiftW:关闭窗口/实例 CtrlX:剪切行 CtrlC:复制行 ALT↑/↓:上下移动 ShiftAlt↓/↑:向…...

贪心算法求数组中能组成三角形的最大周长
题目:三角形的最大周长 给定由一些正数(代表长度)组成的数组arr,返回由其中三个长度组成的、面积不为零的三角形的最大周长。 如果不能形成任何面积不为零的三角形,返回0。 分析: 对数组排序,再从大到小选择三个数,再…...

VMWare Workstation 17 Pro 网络设置 桥接模式 网络地址转换(NAT)模式 仅主机模式
文章目录 网络模式配网要求CentOSDHCP虚拟网络桥接模式默认配置测试手动配置测试 网络地址转发模式 (NAT)还原配置虚拟网络配置默认配置测试手动配置测试 仅主机模式 网络模式 桥接模式: 主机与虚拟机对等, 虚拟机注册到主机所在的局域网, 会占用该网络的IP该局域网内的所有机…...

拒绝摆烂!C语言练习打卡第四天
🔥博客主页:小王又困了 📚系列专栏:每日一练 🌟人之为学,不日近则日退 ❤️感谢大家点赞👍收藏⭐评论✍️ 目录 一、选择题 📝1.第一题 📝2.第二题 Ὅ…...

KubeSphere 社区双周报 | Java functions framework 支持 SkyWalking | 2023.8.4-8.17
KubeSphere 社区双周报主要整理展示新增的贡献者名单和证书、新增的讲师证书以及两周内提交过 commit 的贡献者,并对近期重要的 PR 进行解析,同时还包含了线上/线下活动和布道推广等一系列社区动态。 本次双周报涵盖时间为:2023.08.04-2023.…...

【学习笔记之java】使用RestTemplate调用第三方接口
1.首先需要导入依赖 <!-- RestTemplate使用导入的依赖--><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.13</version></dependency>2.跟启动类同级创建…...

数据集成革新:去中心化微服务集群的无限潜能
在当今数据密集型的业务环境下,传统的集中式架构已经难以满足高可用性和高并发性的要求。而去中心化微服务集群则通过分散式的架构,将系统划分为多个小型的、独立部署的微服务单元,每个微服务负责特定的业务功能,实现了系统的高度…...

后端返回可下载的xlsx文件,但是前端接收下载后为乱码
我的接收数据进行处理的代码为: download_signal_list() {return new Promise((resolve, reject) > {get_download_signal({project_id: this.projectId,version_id: this.versionId}).then(response > {const url window.URL.createObjectURL(new Blob([res…...