Android 开发音频录播中媒体录制器MediaRecorder和媒体播放器MediaPlayer的讲解及实战(超详细 附源码)

news2025/7/29 22:07:31

需要源码请点赞关注收藏后评论区留下QQ~~~

一、媒体录制器MediaRecorder

MediaRecorder是Android自带的音视频录制工具,它通过操纵摄像头和麦克风完成媒体录制,既可录制视频又可以单独录制音频  下面是它的常用方法

reset 重置录制资源

prepare 准备录制

start 开始录制

stop 结束录制

release 释放录制资源

setOnErrorListener 设置错误监听器

setOnInfoListener 设置信息监听器

setMaxDuration  设置可录制的最大时长

setMaxFileSize 设置可录制的最大文件大小

setOutputFile 设置输出我呢见的存储路径

媒体输出格式如下

amr 窄带格式

aac 高级的音频传输流格式

mp4 MPEG4格式

3gp 3GP格式

注意 录音之前要再AndroidManifest.xml中添加录音权限

    <uses-permission android:name="android.permission.RECORD_AUDIO"/>

 二、媒体播放器MediaPlayer

MediaPlayer是Android自带的音视频播放器,可播放MediaRecorder录制的媒体文件,有各种格式

它的常用方法如下

reset 重置播放器

prepareAsync 异步加载媒体文件 播放大文件或者网络媒体时建议使用该方法

setOnPrepareListener 设置准备监听播放器

setOnCompletionListener 设置结束监听播放器

setOnSeekCompleteListener 设置播放拖动监听器

create 创建指定URI的媒体播放器

setDataSource 设置播放数据来源的文件路径

setVolume 设置音量

...

输出效果如下 可在下拉框中选择不同的编码格式和输出格式 录制时长等等

此处连接真机测试更佳  因为模拟机没有麦克风~~

 

 

 

 代码如下

Java类

package com.example.audio;

import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import com.example.audio.util.DateUtil;
import com.example.audio.util.MediaUtil;

import java.util.Timer;
import java.util.TimerTask;

public class AudioCommonActivity extends AppCompatActivity {
    private static final String TAG = "AudioCommonActivity";
    private Button btn_record; // 声明一个按钮对象
    private LinearLayout ll_record_progress; // 声明一个线性布局对象
    private ProgressBar pb_record_progress; // 声明一个进度条对象
    private TextView tv_record_progress; // 声明一个文本视图对象
    private Button btn_play; // 声明一个按钮对象
    private LinearLayout ll_play_progress; // 声明一个线性布局对象
    private ProgressBar pb_play_progress; // 声明一个进度条对象
    private TextView tv_play_progress; // 声明一个文本视图对象

    private int mAudioEncoder; // 音频编码
    private int mOutputFormat; // 输出格式
    private int mDuration; // 录制时长
    private String mRecordFilePath; // 录音文件的保存路径
    
    private MediaRecorder mMediaRecorder = new MediaRecorder(); // 媒体录制器
    private boolean isRecording = false; // 是否正在录音
    private Timer mRecordTimer = new Timer(); // 录音计时器
    private int mRecordTimeCount; // 录音时间计数
    
    private MediaPlayer mMediaPlayer = new MediaPlayer(); // 媒体播放器
    private boolean isPlaying = false; // 是否正在播音
    private Timer mPlayTimer = new Timer(); // 录音计时器
    private int mPlayTimeCount; // 录音时间计数

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_audio_common);
        btn_record = findViewById(R.id.btn_record);
        ll_record_progress = findViewById(R.id.ll_record_progress);
        pb_record_progress = findViewById(R.id.pb_record_progress);
        tv_record_progress = findViewById(R.id.tv_record_progress);
        btn_play = findViewById(R.id.btn_play);
        ll_play_progress = findViewById(R.id.ll_play_progress);
        pb_play_progress = findViewById(R.id.pb_play_progress);
        tv_play_progress = findViewById(R.id.tv_play_progress);
        btn_record.setOnClickListener(v -> {
            if (!isRecording) { // 未在录音
                startRecord(); // 开始录音
            } else { // 正在录音
                stopRecord(); // 停止录音
            }
        });
        btn_play.setOnClickListener(v -> {
            if (!isPlaying) { // 未在播音
                startPlay(); // 开始播音
            } else { // 正在播音
                stopPlay(); // 停止播音
            }
        });
        initEncoderSpinner(); // 初始化音频编码的下拉框
        initFormatSpinner(); // 初始化输出格式的下拉框
        initDurationSpinner(); // 初始化录制时长的下拉框
    }

    // 初始化音频编码的下拉框
    private void initEncoderSpinner() {
        ArrayAdapter<String> encoderAdapter = new ArrayAdapter<>(this,
                R.layout.item_select, encoderDescArray);
        Spinner sp_encoder = findViewById(R.id.sp_encoder);
        sp_encoder.setPrompt("请选择音频编码");
        sp_encoder.setAdapter(encoderAdapter);
        sp_encoder.setOnItemSelectedListener(new EncoderSelectedListener());
        sp_encoder.setSelection(0);
    }

    private String[] encoderDescArray = {
            "默认编码",
            "窄带编码",
            "宽带编码",
            "低复杂度的高级编码",
            "高效率的高级编码",
            "增强型低延时的高级编码"
    };
    private int[] encoderArray = {
            MediaRecorder.AudioEncoder.DEFAULT,
            MediaRecorder.AudioEncoder.AMR_NB,
            MediaRecorder.AudioEncoder.AMR_WB,
            MediaRecorder.AudioEncoder.AAC,
            MediaRecorder.AudioEncoder.HE_AAC,
            MediaRecorder.AudioEncoder.AAC_ELD
    };

    class EncoderSelectedListener implements AdapterView.OnItemSelectedListener {
        public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
            mAudioEncoder = encoderArray[arg2];
        }

        public void onNothingSelected(AdapterView<?> arg0) {}
    }

    // 初始化输出格式的下拉框
    private void initFormatSpinner() {
        ArrayAdapter<String> formatAdapter = new ArrayAdapter<>(this,
                R.layout.item_select, formatDescArray);
        Spinner sp_format = findViewById(R.id.sp_format);
        sp_format.setPrompt("请选择输出格式");
        sp_format.setAdapter(formatAdapter);
        sp_format.setSelection(0);
        sp_format.setOnItemSelectedListener(new FormatSelectedListener());
    }

    private String[] formatDescArray = {
            "默认格式",
            "窄带格式",
            "宽带格式",
            "高级的音频传输流格式"
    };
    private int[] formatArray = {
            MediaRecorder.OutputFormat.DEFAULT,
            MediaRecorder.OutputFormat.AMR_NB,
            MediaRecorder.OutputFormat.AMR_WB,
            MediaRecorder.OutputFormat.AAC_ADTS
    };
    class FormatSelectedListener implements AdapterView.OnItemSelectedListener {
        public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
            mOutputFormat = formatArray[arg2];
        }

        public void onNothingSelected(AdapterView<?> arg0) {}
    }

    // 初始化录制时长的下拉框
    private void initDurationSpinner() {
        ArrayAdapter<String> durationAdapter = new ArrayAdapter<>(this,
                R.layout.item_select, durationDescArray);
        Spinner sp_duration = findViewById(R.id.sp_duration);
        sp_duration.setPrompt("请选择录制时长");
        sp_duration.setAdapter(durationAdapter);
        sp_duration.setSelection(0);
        sp_duration.setOnItemSelectedListener(new DurationSelectedListener());
    }

    private String[] durationDescArray = {"5秒", "10秒", "20秒", "30秒", "60秒"};
    private int[] durationArray = {5, 10, 20, 30, 60};
    class DurationSelectedListener implements AdapterView.OnItemSelectedListener {
        public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
            mDuration = durationArray[arg2];
        }

        public void onNothingSelected(AdapterView<?> arg0) {}
    }

    // 开始录音
    private void startRecord() {
        Log.d(TAG, "startRecord mAudioEncoder="+mAudioEncoder+", mOutputFormat="+mOutputFormat+", mDuration="+mDuration);
        ll_record_progress.setVisibility(View.VISIBLE);
        isRecording = !isRecording;
        btn_record.setText("停止录音");
        pb_record_progress.setMax(mDuration); // 设置进度条的最大值
        mRecordTimeCount = 0; // 录音时间计数清零
        mRecordTimer = new Timer(); // 创建一个录音计时器
        mRecordTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                pb_record_progress.setProgress(mRecordTimeCount); // 设置进度条的当前进度
                tv_record_progress.setText(MediaUtil.formatDuration(mRecordTimeCount*1000));
                mRecordTimeCount++;
            }
        }, 0, 1000); // 计时器每隔一秒就更新进度条上的录音进度
        // 获取本次录制的媒体文件路径
        mRecordFilePath = String.format("%s/%s.amr",
                getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString(),
                DateUtil.getNowDateTime());
        // 下面是媒体录制器的处理代码
        mMediaRecorder.reset(); // 重置媒体录制器
        // 设置媒体录制器的信息监听器
        mMediaRecorder.setOnInfoListener((mr, what, extra) -> {
            // 录制达到最大时长,或者达到文件大小限制,都停止录制
            if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED
                    || what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED) {
                stopRecord(); // 停止录音
            }
        });
        // 设置音频源为麦克风
        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mMediaRecorder.setOutputFormat(mOutputFormat); // 设置媒体的输出格式。该方法要先于setAudioEncoder调用
        mMediaRecorder.setAudioEncoder(mAudioEncoder); // 设置媒体的音频编码器
        mMediaRecorder.setAudioSamplingRate(8000); // 设置媒体的音频采样率。可选
        // mMediaRecorder.setAudioChannels(2); // 设置媒体的音频声道数。可选
        // mMediaRecorder.setAudioEncodingBitRate(1024); // 设置音频每秒录制的字节数。可选
        mMediaRecorder.setMaxDuration(mDuration * 1000); // 设置媒体的最大录制时长
        // mMediaRecorder.setMaxFileSize(1024*1024*10); // 设置媒体的最大文件大小
        // setMaxFileSize与setMaxDuration设置其一即可
        mMediaRecorder.setOutputFile(mRecordFilePath); // 设置媒体文件的保存路径
        try {
            mMediaRecorder.prepare(); // 媒体录制器准备就绪
            mMediaRecorder.start(); // 媒体录制器开始录制
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 停止录音
    private void stopRecord() {
        btn_record.setText("开始录音");
        mRecordTimer.cancel(); // 取消录音定时器
        if (isRecording) {
            isRecording = !isRecording;
            mMediaRecorder.stop(); // 媒体录制器停止录制
            Toast.makeText(this, "已结束录音,音频文件路径为"+mRecordFilePath, Toast.LENGTH_LONG).show();
            btn_play.setVisibility(View.VISIBLE);
        }
    }

    // 开始播音
    private void startPlay() {
        ll_play_progress.setVisibility(View.VISIBLE);
        isPlaying = !isPlaying;
        btn_play.setText("停止播音");
        mMediaPlayer.reset(); // 重置媒体播放器
        // 设置媒体播放器的完成监听器
        mMediaPlayer.setOnCompletionListener(mp -> stopPlay());
        mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); // 设置音频流的类型为音乐
        try {
            mMediaPlayer.setDataSource(mRecordFilePath); // 设置媒体数据的文件路径
            mMediaPlayer.prepare(); // 媒体播放器准备就绪
            mMediaPlayer.start(); // 媒体播放器开始播放
        } catch (Exception e) {
            e.printStackTrace();
        }
        pb_play_progress.setMax(mMediaPlayer.getDuration()/1000); // 设置进度条的最大值
        mPlayTimeCount = 0; // 播音时间计数清零
        mPlayTimer = new Timer(); // 创建一个播音计时器
        mPlayTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                pb_play_progress.setProgress(mPlayTimeCount); // 设置进度条的当前进度
                tv_play_progress.setText(MediaUtil.formatDuration(mPlayTimeCount*1000));
                mPlayTimeCount++;
            }
        }, 0, 1000); // 计时器每隔一秒就更新进度条上的播音进度
    }

    // 停止播音
    private void stopPlay() {
        btn_play.setText("开始播音");
        mPlayTimer.cancel(); // 取消播音定时器
        if (mMediaPlayer.isPlaying() || isPlaying) { // 如果正在播放
            isPlaying = !isPlaying;
            mMediaPlayer.stop(); // 停止播放
            Toast.makeText(this, "已结束播音", Toast.LENGTH_LONG).show();
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        stopRecord(); // 停止录音
        stopPlay(); // 停止播音
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mMediaRecorder.release(); // 释放媒体录制器
        mMediaPlayer.release(); // 释放媒体播放器
    }
}

XML文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:paddingLeft="5dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:gravity="center"
            android:text="音频编码:"
            android:textColor="@color/black"
            android:textSize="17sp" />

        <Spinner
            android:id="@+id/sp_encoder"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="left|center"
            android:spinnerMode="dialog" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:paddingLeft="5dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:gravity="center"
            android:text="输出格式:"
            android:textColor="@color/black"
            android:textSize="17sp" />

        <Spinner
            android:id="@+id/sp_format"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="left|center"
            android:spinnerMode="dialog" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:paddingLeft="5dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:gravity="center"
            android:text="录制时长:"
            android:textColor="@color/black"
            android:textSize="17sp" />

        <Spinner
            android:id="@+id/sp_duration"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="left|center"
            android:spinnerMode="dialog" />
    </LinearLayout>

    <Button
        android:id="@+id/btn_record"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="开始录音"
        android:textColor="@color/black"
        android:textSize="17sp" />

    <LinearLayout
        android:id="@+id/ll_record_progress"
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:paddingLeft="5dp"
        android:paddingRight="5dp"
        android:orientation="horizontal"
        android:visibility="gone">

        <ProgressBar
            android:id="@+id/pb_record_progress"
            style="?android:attr/progressBarStyleHorizontal"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="4" />

        <TextView
            android:id="@+id/tv_record_progress"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="right|center"
            android:textColor="@color/black"
            android:textSize="15sp" />
    </LinearLayout>

    <Button
        android:id="@+id/btn_play"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="开始播音"
        android:textColor="@color/black"
        android:textSize="17sp"
        android:visibility="gone"/>

    <LinearLayout
        android:id="@+id/ll_play_progress"
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:paddingLeft="5dp"
        android:paddingRight="5dp"
        android:orientation="horizontal"
        android:visibility="gone">

        <ProgressBar
            android:id="@+id/pb_play_progress"
            style="?android:attr/progressBarStyleHorizontal"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="4" />

        <TextView
            android:id="@+id/tv_play_progress"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="right|center"
            android:textColor="@color/black"
            android:textSize="15sp" />
    </LinearLayout>

</LinearLayout>

创作不易 觉得有帮助请点赞关注收藏~~~

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

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

相关文章

C/C++语言 3 —— 输入输出

C语言的io函数&#xff1a; printf 输出 和 scanf输入 是 C语言的标准IO函数的一部分&#xff1a; scanf函数会将屏幕上输入的字符&#xff0c;根据格式的要求转化为对应的数据&#xff1a; scanf 需要提供内存地址代码&#xff1a; #include <iostream> using nam…

【数字电路基础】进制转换:二进制、十进制、八进制、十六进制、反码、补码、原码

文章目录 一、无符号数进制转换1.1、十进制转二、八、十六1.1.1、 十进制转二进制1.1.2、 十进制转八进制1.1.2、 十进制转十六进制1.2、二、八、十六转十进制1.3 二进制转八、十六1.4 八、十六转二进制1.4 八转十六二、有符号数进制转换2.1 正数进制转换2.2 负数进制转换一、无…

Linux安装Tomcat详细教程(图文)

1、下载Linux版本****的Tomcat 下载地址 2、在usr目录下新建tomcat目录&#xff0c;然后将下载的tomcat拷贝到新建的tomcat目录中 创建目录命令&#xff1a;mkdir /usr/tomcat 3、进入到tomcat目录中解压下载的tomcat安装包 解压命令&#xff1a;tar -zxvf apache-tomcat-8…

自动驾驶感知算法实战13——自动驾驶感知未来发展方向分享

自动驾驶感知算法实战专栏:https://blog.csdn.net/charmve/category_12097938.html目录 发展方向:分享:自动驾驶3.0未来需要解决的问题发展方向: 多模态感知 多任务处理 大模型(通用智能) 分享: 自动驾驶3.0 第一,自动驾驶3.0是数据驱动,更是“真实场景下的海量大数据…

底物多肽Phe-Gly-His-Phe(NO2)-Phe-Ala-Phe-OMe、50572-79-7

胃蛋白酶的良好底物&#xff0c;也被组织蛋白酶 D 切割。 A good substrate for pepsin which is also cleaved by cathepsin D.编号: 402332 中文名称: Phe-Gly-His-Phe(NO2)-Phe-Ala-Phe-OMe CAS号: 50572-79-7 单字母: H2N-FGH-F(4NO2)-FAF-OMe 三字母: H2N-Phe-Gly-His-Phe…

企业信息化的供给侧改革

企业信息化建设供给侧改革的新思路 传统的企业信息化建设思路是什么呢&#xff1f;它是从需求侧的规划跟实施入手的&#xff0c;然后解决做哪些和怎么做业务信息化的问题&#xff0c;用不着关注承担这个项目建设的供给体系的质量、效率、结构问题。这就会导致在项目建设过程中…

[附源码]java毕业设计在线视频网站

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

垃圾分类解决方案-最新全套文件

垃圾分类解决方案-最新全套文件一、建设背景垃圾分类的意义1.为什么要进行垃圾分类2.智慧垃圾分类的重要性二、建设思路三、建设方案四、获取 - 垃圾分类全套最新解决方案合集一、建设背景 垃圾分类的意义 1.为什么要进行垃圾分类 将易腐有机成分为主的厨房垃圾单独分类&…

运动需要的装备有哪些?2022年运动装备推荐

全民开始运动的今天&#xff0c;越来越多的年轻人会选择在一天的忙碌之后通过简单的运动缓解疲劳。而在运动装备的选择上&#xff0c;由于种类和品牌太多&#xff0c;小白很难从中选择到适合自己的运动装备&#xff0c;作为一个资深运动爱好者&#xff0c;对这方面是非常在行的…

「运维有小邓」如何更有效的避免密码攻击

在这表文章中&#xff0c;让我们一起了解密码在网络安全中的重要性&#xff0c;在我们的日常工作中&#xff0c;密码泄露事件是常发生的&#xff0c; 那今天我们就一起了解ManageEngine ADSelfService Plus 是如何强化您的密码并加强您的企业AD域安全性的。 运维有小邓 2022 年…

MCE | 打破 Western Blot 玄学操作

看我一顿操作猛如虎&#xff1a; 电泳 → 转膜 → 封闭 → 孵一抗 → 孵二抗 → 检测&#xff0c;剩下的就是等待。 图 1. Western blot 操作流程简介[1] 我的实验结果中出现了各种稀奇古怪的玩意儿&#xff1f;&#xff1f;&#xff1f; ■ 古怪一&#xff1a;高背景 萌 Cece…

合作|创邻科技携手海颐软件成功中标,Galaxybase图平台赋能广西电网业务升级

近日&#xff0c;烟台海颐软件股份有限公司&#xff08;简称“海颐软件”&#xff09;携手浙江创邻科技有限公司&#xff08;简称“创邻科技”&#xff09;成功中标南方电网广西电网有限责任公司&#xff08;简称“广西电网”&#xff09;课题项目。期待通过结合双方产品优势&a…

【车间调度】遗传算法求解车间调度问题(含甘特图)【含Matlab源码 2216期】

⛄一、车间调度简介 1 车间调度定义 车间调度是指根据产品制造的合理需求分配加工车间顺序&#xff0c;从而达到合理利用产品制造资源、提高企业经济效益的目的。车间调度问题从数学上可以描述为有n个待加工的零件要在m台机器上加工。问题需要满足的条件包括每个零件的各道工序…

如何将带GPS的网络化的软件定义无线电接收机应用于分布式和移动频谱监测?(一)

导言 无线信号无处不在。无线网络为我们的移动设备&#xff0c;物联网&#xff08;IoT&#xff09;&#xff0c;智能城市&#xff0c;自动驾驶汽车等提供动力。从基本视频流到整个公用电网的所有内容现在都依赖于可靠&#xff0c;高速和不间断的连接。这一新现实给频谱监测用户…

文本攻击textattack->openattack

一 文本对抗攻击的定义 很小的扰动&#xff0c;无法映射到原始输出。那么就是对抗样本&#xff0c;生成对抗样本的过程称为对抗攻击。 1.1 类型分类 根据是攻击者否了解模型的具体细节&#xff1a; 白盒攻击【攻击者可以访问模型的完整信息&#xff0c;包括模型结构&#xff0c…

表格软件之FineReport-JS实现大数据集导出(二)

1. 示例&#xff1a;大数据集导出动态参数值 1.1 新建模板 1.1.1 新建数据集 新建普通报表&#xff0c;新建数据集&#xff0c;SQL 语句如下&#xff1a; ds1&#xff1a;SELECT * FROM 销量 where 11 and 地区 in (${area}) and 销售员 in (${stuff}) ds2&#xff1a;SEL…

178. 分数排名

文章目录1.题目2.示例3.答案①系统自带函数1.题目 表: Scores -------------------- | Column Name | Type | -------------------- | id | int | | score | decimal | -------------------- Id是该表的主键。 该表的每一行都包含了一场比赛的分数。Score是一个有两位小数点的…

LigaAI X 猴子无限 | AIGC 火了,专业设计者的福音来了!

「人工智能团队协作」还能有多少种打开方式&#xff1f; 致力于打造新一代智能研发协作平台&#xff0c;LigaAI在不断强化自身智能化能力的同时&#xff0c;也持续关注着整个「AI协作」领域的发展。 Gartner在《 2022 年重要战略技术趋势报告》中指出&#xff0c;未来三到五年…

MySQL基础命令高级操作

文章目录一、案例拓展二、数据库高级操作1、克隆表2、清空表&#xff0c;删除表内的所有数据3、创建临时表三、创建外键约束&#xff0c;保证数据的完整性和一直性1、创建主从表2、为主表zhu添加一一个主键约束。主键名建议以“PK_ "开头3、为从表cong表添加外键&#xff…

本地web服务器配置(IIS)

文章目录环境说明操作流程环境说明 Windows 10 操作流程 打开控制面板&#xff0c;输入功能&#xff0c;回车&#xff0c;选择启用或关闭 Windows 功能&#xff0c; 点击确定&#xff0c;等待配置&#xff0c;接着按照提示&#xff0c;重新启动计算机。&#xff08;此处我的…