当用post方法上传,base64编码的图片太大,导致后台接收的时候总是为null。

本文介绍了解决Tomcat服务器在使用Base64上传大文件时遇到的问题,详细解释了如何通过调整Tomcat配置文件server.xml中的maxPostSize参数来增加POST请求的数据大小限制,以避免空指针异常。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

服务器采用base64的方式进行上传文件的时候,出现接收到的数据为null,抛空指针异常,后来发现是tomcat默认为2M的字符串限制,因此修改如下配置即可。

post请求理论上对参数的大小没有限制,但是服务器有限制,把Tomcat的server.xml里设置一下就好了

注:Tomcat的版本低于等于7,设置maxPostSize=“0” 表示post参数无限大。
Tomcat的版本大于等于8,设置maxPostSize=“104857600” 表示post参数最大100MB。

<Connector connectionTimeout="8080" protocol="HTTP/1.1" redirectPort="8443" maxPostSize="104857600">

package com.example.demoapplication; // 定义包名 // 导入Android音频相关的类 import android.media.AudioTrack; import android.Manifest; import android.content.pm.PackageManager; import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioRecord; import android.media.MediaRecorder; // 导入Android系统组件相关类 import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; // 导入语音合成相关类 import android.speech.tts.TextToSpeech; // 导入Android工具类 import android.util.Base64; import android.util.Log; // 导入Android UI组件 import android.widget.Button; import android.widget.Toast; // 导入Android兼容库组件 import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; // 导入JSON处理库 import org.json.JSONException; import org.json.JSONObject; // 导入IO流相关类 import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; // 导入网络通信相关类 import java.net.ServerSocket; import java.net.Socket; // 导入数据结构和并发工具 import java.util.LinkedList; import java.util.Locale; import java.util.Queue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; /** * 主活动类,实现音频录制、播放、网络通信和TTS功能 */ public class MainActivity extends AppCompatActivity implements TextToSpeech.OnInitListener { private static final String TAG = "AudioRecorder"; // 日志标签 // 按钮成员变量 private Button startRecordButton, stopRecordButton; private Button playSoundButton, pauseSoundButton, stopSoundButton, resumeSoundButton, clearSoundsButton; // 音频录制对象 private AudioRecord audioRecord; // 音频采样率常量 private static final int SAMPLE_RATE = 16000; // 缓冲区大小常量 private static final int BUFFER_SIZE; // 静态代码块初始化缓冲区大小 static { // 获取最小缓冲区大小 int minBufferSize = AudioRecord.getMinBufferSize( SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT ); // 取较大值作为实际使用的缓冲区大小 BUFFER_SIZE = Math.max(minBufferSize, 4096); } // 调度执行器 private ScheduledExecutorService scheduler; // 录音状态标志 private AtomicBoolean isRecording = new AtomicBoolean(false); // 权限请求码 private static final int PERMISSION_REQUEST_CODE = 1; // 线程池服务 private final ExecutorService executorService = Executors.newCachedThreadPool(); // 服务器套接字 private ServerSocket serverSocket; // 服务器运行状态 private volatile boolean isServerRunning = true; // 客户端套接字 private volatile Socket clientSocket; // 套接字写入器 private volatile BufferedWriter socketWriter; // 文语转换引擎 private TextToSpeech ttsEngine; // TTS初始化状态 private boolean isTtsInitialized = false; // 播放队列相关变量 private final Queue<byte[]> playbackQueue = new LinkedList<>(); private final Queue<byte[]> pausedQueue = new LinkedList<>(); private final AtomicBoolean isPlaying = new AtomicBoolean(false); private final AtomicBoolean isPaused = new AtomicBoolean(false); private volatile boolean isPlaybackThreadActive = false; // ... existing code ... // 对象锁用于同步访问 private final Object audioTrackLock = new Object(); private final Object playbackQueueLock = new Object(); private final Object recordingQueueLock = new Object(); // 新增的成员变量 - 音频播放器 private AudioTrack audioTrack; // 新增的成员变量 // ... existing code ... // 录制音频数据队列 private final Queue<byte[]> recordingQueue = new LinkedList<>(); // 主线程消息处理器 private final Handler handler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(@NonNull Message msg) { switch (msg.what) { case 0x11: // 客户端连接 Toast.makeText(MainActivity.this, "客户端已连接", Toast.LENGTH_SHORT).show(); break; case 0x12: // 开始录音 Toast.makeText(MainActivity.this, "开始录音", Toast.LENGTH_SHORT).show(); sendJsonPacket("startRecorder", null); playTts("开始录音"); break; case 0x14: // 停止录音 Toast.makeText(MainActivity.this, "停止录音", Toast.LENGTH_SHORT).show(); sendJsonPacket("stopRecorder", null); playTts("停止录音"); break; case 0x16: // 错误消息 Toast.makeText(MainActivity.this, "错误: " + msg.obj, Toast.LENGTH_LONG).show(); break; case 0x17: // 播放完成 Toast.makeText(MainActivity.this, "播放完成", Toast.LENGTH_SHORT).show(); isPlaying.set(false); isPlaybackThreadActive = false; updatePlayButtonsState(); break; case 0x18: // 添加到播放队列 Toast.makeText(MainActivity.this, "已添加到播放队列", Toast.LENGTH_SHORT).show(); break; case 0x19: // 更新播放按钮状态 updatePlayButtonsState(); break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 调用父类onCreate方法 setContentView(R.layout.activity_main); // 设置布局文件 // 初始化TTS引擎 ttsEngine = new TextToSpeech(this, this); // 初始化视图组件 initViews(); // 设置点击监听器 setupClickListeners(); // 检查权限 checkPermissions(); // 启动服务器(端口30000) startServer(30000); // 启动套接字监听 startSocketListener(); } // 初始化视图组件 private void initViews() { // 绑定按钮控件 startRecordButton = findViewById(R.id.startRecordButton); stopRecordButton = findViewById(R.id.stopRecordButton); playSoundButton = findViewById(R.id.playSoundButton); pauseSoundButton = findViewById(R.id.pauseSoundButton); stopSoundButton = findViewById(R.id.stopSoundButton); resumeSoundButton = findViewById(R.id.resumeSoundButton); clearSoundsButton = findViewById(R.id.clearSoundsButton); // 初始化按钮状态 stopRecordButton.setEnabled(false); pauseSoundButton.setEnabled(false); stopSoundButton.setEnabled(false); resumeSoundButton.setEnabled(false); } // 设置点击事件监听器 private void setupClickListeners() { // 录音控制 startRecordButton.setOnClickListener(v -> startRecording()); stopRecordButton.setOnClickListener(v -> stopRecording()); // 播放控制 playSoundButton.setOnClickListener(v -> playNextInQueue()); pauseSoundButton.setOnClickListener(v -> pausePlayback()); stopSoundButton.setOnClickListener(v -> stopPlayback()); resumeSoundButton.setOnClickListener(v -> resumePlayback()); clearSoundsButton.setOnClickListener(v -> { clearPlaybackQueue(); handler.sendEmptyMessage(0x19); }); } // ==================== 录音功能 ==================== // 开始录音 private void startRecording() { // 检查录音权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { sendErrorMessage("没有录音权限"); return; } // 如果已经在录音则先释放资源 if (isRecording.get()) { releaseAudioResources(); } try { // 创建AudioRecord对象 audioRecord = new AudioRecord( MediaRecorder.AudioSource.MIC, SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, BUFFER_SIZE ); // 检查初始化状态 if (audioRecord.getState() != AudioRecord.STATE_INITIALIZED) { throw new IllegalStateException("AudioRecord 初始化失败"); } // 开始录音 audioRecord.startRecording(); isRecording.set(true); startRecordButton.setEnabled(false); stopRecordButton.setEnabled(true); updatePlayButtonsState(); // 关闭之前的调度器 if (scheduler != null && !scheduler.isShutdown()) { scheduler.shutdownNow(); } // 创建新的调度器 scheduler = Executors.newSingleThreadScheduledExecutor(); // 每100毫秒采集一次音频数据 scheduler.scheduleAtFixedRate(this::captureAudioData, 0, 100, TimeUnit.MILLISECONDS); handler.sendEmptyMessage(0x12); } catch (Exception e) { Log.e(TAG, "录音启动失败", e); sendErrorMessage("录音启动失败: " + e.getMessage()); releaseAudioResources(); } } // 停止录音 private void stopRecording() { if (!isRecording.get()) return; isRecording.set(false); releaseAudioResources(); stopRecordButton.setEnabled(false); startRecordButton.setEnabled(true); updatePlayButtonsState(); handler.sendEmptyMessage(0x14); } // 采集音频数据 private void captureAudioData() { if (!isRecording.get() || audioRecord == null) return; byte[] buffer = new byte[BUFFER_SIZE]; try { int bytesRead = audioRecord.read(buffer, 0, BUFFER_SIZE); if (bytesRead > 0) { synchronized (recordingQueueLock) { recordingQueue.offer(buffer.clone()); } String base64Data = Base64.encodeToString(buffer, Base64.DEFAULT); sendJsonPacket("recording", base64Data); } } catch (Exception e) { Log.e(TAG, "音频采集失败", e); } } // ==================== 录音功能结束 ==================== // ==================== 播放队列管理 ==================== // 将声音数据添加到播放队列 private void addSoundToQueue(byte[] soundData) { synchronized (playbackQueueLock) { playbackQueue.offer(soundData); } handler.sendEmptyMessage(0x18); // 如果没有在播放且没有激活的播放线程,则开始播放 if (!isPlaying.get() && !isPlaybackThreadActive) { handler.post(this::playNextInQueue); } } // 播放下一个队列中的音频 private void playNextInQueue() { if (isPlaybackThreadActive) { return; } isPlaybackThreadActive = true; new Thread(() -> { try { while (!playbackQueue.isEmpty() && !isPaused.get()) { byte[] soundData; synchronized (playbackQueueLock) { soundData = playbackQueue.poll(); } if (soundData != null) { playSoundDirectly(soundData); } } if (!isPaused.get()) { isPlaying.set(false); isPlaybackThreadActive = false; handler.sendEmptyMessage(0x17); } } catch (Exception e) { Log.e(TAG, "播放队列处理失败", e); sendErrorMessage("播放失败: " + e.getMessage()); } }).start(); } // 直接播放音频 private void playSoundDirectly(byte[] soundData) { if (soundData == null || soundData.length == 0) { return; } try { isPlaying.set(true); isPaused.set(false); synchronized (audioTrackLock) { int bufferSize = AudioTrack.getMinBufferSize( SAMPLE_RATE, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT ); if (audioTrack != null) { audioTrack.release(); } audioTrack = new AudioTrack( AudioManager.STREAM_MUSIC, SAMPLE_RATE, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize, AudioTrack.MODE_STREAM ); if (audioTrack.getState() != AudioTrack.STATE_INITIALIZED) { throw new IllegalStateException("AudioTrack 初始化失败"); } audioTrack.play(); ByteArrayInputStream inputStream = new ByteArrayInputStream(soundData); byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1 && !isPaused.get()) { audioTrack.write(buffer, 0, bytesRead); } audioTrack.stop(); audioTrack.release(); audioTrack = null; if (!isPaused.get()) { runOnUiThread(this::updatePlayButtonsState); } } } catch (Exception e) { Log.e(TAG, "音频播放失败", e); sendErrorMessage("播放失败: " + e.getMessage()); } } // 暂停播放 private void pausePlayback() { if (!isPlaying.get() || isPaused.get()) { return; } isPaused.set(true); synchronized (audioTrackLock) { if (audioTrack != null) { audioTrack.pause(); } } // 将当前播放的数据移到暂停队列 byte[] currentData = null; synchronized (playbackQueueLock) { if (!playbackQueue.isEmpty()) { currentData = playbackQueue.poll(); } } if (currentData != null) { synchronized (playbackQueueLock) { pausedQueue.offer(currentData); } } updatePlayButtonsState(); } // 恢复播放 private void resumePlayback() { if (!isPaused.get()) { return; } isPaused.set(false); // 将暂停的数据移回播放队列 byte[] pausedData = null; synchronized (playbackQueueLock) { if (!pausedQueue.isEmpty()) { pausedData = pausedQueue.poll(); } } if (pausedData != null) { synchronized (playbackQueueLock) { playbackQueue.offer(pausedData); } } synchronized (audioTrackLock) { if (audioTrack != null && audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PAUSED) { audioTrack.play(); } } if (!isPlaybackThreadActive) { new Thread(() -> { isPlaybackThreadActive = true; try { while (!playbackQueue.isEmpty() && !isPaused.get()) { byte[] soundData; synchronized (playbackQueueLock) { soundData = playbackQueue.poll(); } if (soundData != null) { playSoundDirectly(soundData); } } if (!isPaused.get()) { isPlaying.set(false); isPlaybackThreadActive = false; handler.sendEmptyMessage(0x17); } } catch (Exception e) { Log.e(TAG, "恢复播放失败", e); sendErrorMessage("恢复播放失败: " + e.getMessage()); } }).start(); } updatePlayButtonsState(); } // 停止播放 private void stopPlayback() { if (!isPlaying.get() && !isPaused.get()) { return; } isPlaying.set(false); isPaused.set(false); synchronized (playbackQueueLock) { playbackQueue.clear(); if (!pausedQueue.isEmpty()) { pausedQueue.clear(); } } synchronized (audioTrackLock) { if (audioTrack != null) { try { audioTrack.stop(); audioTrack.release(); } catch (Exception e) { Log.e(TAG, "停止音频播放失败", e); } finally { audioTrack = null; } } } updatePlayButtonsState(); handler.sendEmptyMessage(0x19); } // 清空播放队列 private void clearPlaybackQueue() { synchronized (playbackQueueLock) { playbackQueue.clear(); pausedQueue.clear(); } } // ==================== 播放队列管理结束 ==================== // ==================== 辅助方法 ==================== // 更新播放按钮状态 private void updatePlayButtonsState() { runOnUiThread(() -> { boolean hasRecordings = !playbackQueue.isEmpty() || !pausedQueue.isEmpty(); boolean isPlayingState = isPlaying.get() && !isPaused.get(); boolean isPausedState = isPaused.get(); playSoundButton.setEnabled(hasRecordings && !isPlayingState); pauseSoundButton.setEnabled(isPlayingState); stopSoundButton.setEnabled(isPlaying.get() || isPausedState); resumeSoundButton.setEnabled(isPausedState); clearSoundsButton.setEnabled(hasRecordings); }); } // 播放文本转语音 private void playTts(String text) { if (isTtsInitialized) { ttsEngine.speak(text, TextToSpeech.QUEUE_FLUSH, null); } } // 释放音频资源 private void releaseAudioResources() { if (audioRecord != null) { try { if (audioRecord.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) { audioRecord.stop(); } audioRecord.release(); } catch (IllegalStateException e) { Log.e(TAG, "停止录音失败", e); } finally { audioRecord = null; } } if (scheduler != null) { try { scheduler.shutdownNow(); if (!scheduler.awaitTermination(500, TimeUnit.MILLISECONDS)) { Log.w(TAG, "录音线程池未正常关闭"); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { scheduler = null; } } } // 发送JSON数据包 private void sendJsonPacket(String type, Object data) { if (clientSocket == null || clientSocket.isClosed() || socketWriter == null) { return; } try { JSONObject packet = new JSONObject(); packet.put("type", type); if (data != null) { packet.put("data", data); } synchronized (this) { if (socketWriter != null) { socketWriter.write(packet.toString()); socketWriter.write("\n\n"); socketWriter.flush(); } } } catch (Exception e) { Log.e(TAG, "发送数据包失败: " + type, e); } } // 发送错误消息 private void sendErrorMessage(String message) { handler.obtainMessage(0x16, message).sendToTarget(); } // 检查权限 private void checkPermissions() { if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions( this, new String[]{Manifest.permission.RECORD_AUDIO}, PERMISSION_REQUEST_CODE ); } } // 启动服务器 private void startServer(int port) { executorService.execute(() -> { try { serverSocket = new ServerSocket(port); Log.i(TAG, "服务器启动: " + port); while (isServerRunning) { try { Socket socket = serverSocket.accept(); clientSocket = socket; synchronized (this) { socketWriter = new BufferedWriter( new OutputStreamWriter(socket.getOutputStream(), "UTF-8") ); } handler.sendEmptyMessage(0x11); } catch (IOException e) { if (isServerRunning) Log.e(TAG, "接受连接失败", e); } } } catch (IOException e) { Log.e(TAG, "服务器启动失败", e); runOnUiThread(() -> Toast.makeText( this, "服务器启动失败: " + e.getMessage(), Toast.LENGTH_LONG ).show()); } finally { closeServerSocket(); } }); } // 启动套接字监听 private void startSocketListener() { executorService.execute(() -> { while (true) { if (clientSocket != null && !clientSocket.isClosed()) { try { BufferedReader reader = new BufferedReader( new InputStreamReader(clientSocket.getInputStream(), "UTF-8") ); StringBuilder packetBuilder = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { if (line.isEmpty()) { if (packetBuilder.length() > 0) { String packet = packetBuilder.toString(); Log.d(TAG, "收到数据包: " + packet); try { JSONObject command = new JSONObject(packet); String type = command.getString("type"); switch (type) { case "playSound": String base64Sound = command.optString("data"); if (base64Sound != null && !base64Sound.isEmpty()) { byte[] soundData = Base64.decode(base64Sound, Base64.DEFAULT); addSoundToQueue(soundData); handler.sendEmptyMessage(0x18); } break; case "pauseSound": pausePlayback(); break; case "stopSound": stopPlayback(); break; case "resumeSound": resumePlayback(); break; case "clearSounds": clearPlaybackQueue(); handler.sendEmptyMessage(0x19); break; } } catch (JSONException e) { Log.e(TAG, "JSON解析失败", e); } packetBuilder.setLength(0); } } else { packetBuilder.append(line); } } } catch (IOException e) { Log.e(TAG, "Socket读取失败", e); } } else { try { Thread.sleep(500); } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } } } }); } // 关闭服务器套接字 private void closeServerSocket() { try { if (serverSocket != null && !serverSocket.isClosed()) { serverSocket.close(); } } catch (IOException e) { Log.w(TAG, "关闭ServerSocket失败", e); } } // TTS初始化回调 @Override public void onInit(int status) { if (status == TextToSpeech.SUCCESS) { int result = ttsEngine.setLanguage(Locale.CHINESE); if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) { Log.e(TAG, "TTS语言不支持中文"); } else { isTtsInitialized = true; } } } // 销毁活动时清理资源 @Override protected void onDestroy() { super.onDestroy(); isServerRunning = false; if (ttsEngine != null) { ttsEngine.stop(); ttsEngine.shutdown(); } closeServerSocket(); closeSocket(clientSocket); stopRecording(); executorService.shutdown(); try { if (!executorService.awaitTermination(800, TimeUnit.MILLISECONDS)) { executorService.shutdownNow(); } } catch (InterruptedException e) { executorService.shutdownNow(); Thread.currentThread().interrupt(); } releaseAudioResources(); } // 关闭套接字 private void closeSocket(Socket socket) { try { if (socket != null && !socket.isClosed()) { socket.close(); } } catch (IOException e) { Log.w(TAG, "关闭Socket失败", e); } if (socket == clientSocket) { clientSocket = null; synchronized (this) { socketWriter = null; } } } } 怎么把这些修改成安卓代码接收脚本文字用MP3格式接收
最新发布
07-05
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值