VibePlayer
源代码地址:
VibePlayer: VibePlayer是一款功能强大的Android音乐播放器应用,专为音乐爱好者设计,提供了丰富的音乐播放和管理功能。
用户需求
VibePlayer是一款功能强大的Android音乐播放器应用,专为音乐爱好者设计,提供了丰富的音乐播放和管理功能。
功能特点
音乐播放
- 支持多种播放模式:顺序播放、单曲循环、列表循环、随机播放
- 前台服务保证后台播放稳定运行
音乐库管理
- 自动扫描设备中的音乐文件
- 支持文件浏览器手动导入音乐
- 播放列表创建和管理
音频处理
- 内置均衡器,支持多种预设
- 低音增强和虚拟环绕声效果
- 支持音频可视化
歌词功能
- 歌词编辑器,支持添加时间戳
- 歌词实时同步显示
- 歌词预览功能
用户界面
- 现代化UI设计
- 支持深色/浅色主题切换
- 响应式布局,适配不同尺寸设备
- 直观的播放控制界面
权限说明
应用需要以下权限才能正常工作:
- 读取媒体音频(Android 13及以上)
- 读取外部存储(Android 13以下)
- 前台服务
- 通知权限(可选)
- 媒体内容控制
系统要求
- Android 5.0 (API级别21)或更高版本
- 建议安装在Android 8.0或更高版本上获得最佳体验
使用指南
首次使用
- 启动应用后,系统会请求必要的权限
- 授予权限后,应用会自动扫描设备中的音乐文件
- 若未找到音乐文件,可使用内置的文件浏览器导入音乐
播放控制
- 底部控制栏提供基本播放控制
- 点击正在播放的歌曲可进入全屏播放界面
- 左右滑动可切换歌曲
- 长按歌曲可查看更多选项
播放列表管理
- 点击"+"按钮创建新播放列表
- 长按歌曲可添加到播放列表
- 在播放列表详情页可管理列表内歌曲
均衡器设置
- 在均衡器页面可启用/禁用音效处理
- 选择预设或自定义均衡器设置
- 调整低音增强和虚拟环绕声效果
歌词编辑
- 在全屏播放界面点击歌词编辑按钮
- 输入歌词内容,每行一句
- 播放歌曲,在适当的时间点点击"添加时间戳"
- 保存歌词后可在播放界面同步显示
技术特点
- 使用MediaPlayer和MediaSession管理音乐播放
- 支持MediaBrowserService实现跨组件媒体控制
- 采用Room数据库存储播放列表和歌曲信息
- 利用Fragment和ViewPager实现多页面导航
- 前台服务确保后台播放稳定性
- 适配Android不同版本的权限处理
MainActivity.java:
package com.vibeplayer.app;import android.Manifest;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import androidx.viewpager.widget.ViewPager;import com.google.android.material.bottomnavigation.BottomNavigationView;
import com.vibeplayer.app.fragment.NowPlayingFragment;
import com.vibeplayer.app.fragment.PlaylistsFragment;
import com.vibeplayer.app.fragment.SettingsFragment;
import com.vibeplayer.app.fragment.SongsFragment;
import com.vibeplayer.app.fragment.EqualizerFragment;
import com.vibeplayer.app.model.Song;
import com.vibeplayer.app.service.MusicPlayerService;
import com.vibeplayer.app.util.MediaScanner;import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;public class MainActivity extends AppCompatActivity {private static final int PERMISSION_REQUEST_STORAGE = 1;private static final int PERMISSION_REQUEST_NOTIFICATION = 2;private ViewPager viewPager;private BottomNavigationView bottomNav;// 底部播放控制栏组件private View playerControlLayout;private ImageView btnPlayPause;private ImageView btnNext;private ImageView btnPrevious;private TextView txtSongTitle;private TextView txtArtist;private SeekBar seekBar;private TextView txtCurrentTime;private TextView txtTotalTime;private MusicPlayerService musicService;private boolean isBound = false;private MediaScanner mediaScanner;private Timer timer;// 服务连接private ServiceConnection serviceConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {MusicPlayerService.MusicBinder binder = (MusicPlayerService.MusicBinder) service;musicService = binder.getService();isBound = true;// 服务连接后更新UIupdatePlayerControls();startProgressTimer();}@Overridepublic void onServiceDisconnected(ComponentName name) {isBound = false;stopProgressTimer();}};@Overrideprotected void onNewIntent(Intent intent) {super.onNewIntent(intent);handleMusicControlIntent(intent);}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 处理可能的音乐控制动作handleMusicControlIntent(getIntent());// 初始化媒体扫描器mediaScanner = new MediaScanner(this);// 设置扫描完成监听器mediaScanner.setScanCompletedListener(songs -> {Log.d("MainActivity", "Auto scan completed, found " + songs.size() + " songs");if (isBound && musicService != null) {musicService.setSongs(songs);runOnUiThread(() -> {if (!songs.isEmpty()) {// 显示播放控制栏playerControlLayout.setVisibility(View.VISIBLE);} else {// 没有找到音乐文件Toast.makeText(this, "未找到音乐文件", Toast.LENGTH_SHORT).show();}});}});// 检查权限checkPermissions();// 初始化视图initializeViews();// 设置ViewPager适配器setupViewPager();// 设置底部导航setupBottomNavigation();// 设置播放控制栏setupPlayerControls();// 绑定音乐服务bindMusicService();}@Overrideprotected void onStart() {super.onStart();if (!isBound) {bindMusicService();}// 注册媒体观察者mediaScanner.registerMediaObserver();}@Overrideprotected void onStop() {super.onStop();if (isBound) {unbindService(serviceConnection);isBound = false;}stopProgressTimer();// 注销媒体观察者mediaScanner.unregisterMediaObserver();}@Overrideprotected void onDestroy() {super.onDestroy();stopProgressTimer();}@Overrideprotected void onResume() {super.onResume();// 检查权限状态boolean hasPermission = false;if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {hasPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_AUDIO)== PackageManager.PERMISSION_GRANTED;} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {hasPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)== PackageManager.PERMISSION_GRANTED;} else {hasPermission = true;}// 如果已经有权限,直接加载音乐if (hasPermission) {Log.d("MainActivity", "Permission already granted in onResume, loading songs...");loadSongs();}// 如果没有权限且还没有检查过权限,则进行权限检查else if (!hasCheckedPermissions) {Log.d("MainActivity", "No permission in onResume, checking permissions...");checkPermissions();}}private void initializeViews() {viewPager = findViewById(R.id.viewPager);bottomNav = findViewById(R.id.bottomNav);playerControlLayout = findViewById(R.id.playerControlLayout);btnPlayPause = findViewById(R.id.btnPlayPause);btnNext = findViewById(R.id.btnNext);btnPrevious = findViewById(R.id.btnPrevious);txtSongTitle = findViewById(R.id.txtSongTitle);txtArtist = findViewById(R.id.txtArtist);seekBar = findViewById(R.id.seekBar);txtCurrentTime = findViewById(R.id.txtCurrentTime);txtTotalTime = findViewById(R.id.txtTotalTime);}private void setupViewPager() {ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());adapter.addFragment(new SongsFragment(), "歌曲");adapter.addFragment(new PlaylistsFragment(), "播放列表");adapter.addFragment(new EqualizerFragment(), "均衡器");adapter.addFragment(new SettingsFragment(), "设置");viewPager.setAdapter(adapter);viewPager.setCurrentItem(0); // 默认显示歌曲页面// 设置页面切换监听viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {@Overridepublic void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}@Overridepublic void onPageSelected(int position) {bottomNav.getMenu().getItem(position).setChecked(true);}@Overridepublic void onPageScrollStateChanged(int state) {}});}private void setupBottomNavigation() {bottomNav.setOnNavigationItemSelectedListener(item -> {int itemId = item.getItemId();if (itemId == R.id.nav_songs) {viewPager.setCurrentItem(0);return true;} else if (itemId == R.id.nav_playlists) {viewPager.setCurrentItem(1);return true;} else if (itemId == R.id.nav_equalizer) {viewPager.setCurrentItem(2);return true;} else if (itemId == R.id.nav_settings) {viewPager.setCurrentItem(3);return true;}return false;});}private void setupPlayerControls() {// 播放/暂停按钮点击事件btnPlayPause.setOnClickListener(v -> {if (isBound && musicService != null) {musicService.playPause();updatePlayPauseButton();}});// 下一曲按钮点击事件btnNext.setOnClickListener(v -> {if (isBound && musicService != null) {musicService.playNext();}});// 上一曲按钮点击事件btnPrevious.setOnClickListener(v -> {if (isBound && musicService != null) {musicService.playPrevious();}});// 进度条拖动事件seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {if (fromUser && isBound && musicService != null) {musicService.seekTo(progress);updateCurrentTimeText(progress);}}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {}@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {}});// 点击播放控制栏打开全屏播放界面playerControlLayout.setOnClickListener(v -> {if (isBound && musicService != null && musicService.getCurrentSong() != null) {NowPlayingFragment nowPlayingFragment = NowPlayingFragment.newInstance();nowPlayingFragment.show(getSupportFragmentManager(), "now_playing");}});}private void bindMusicService() {Intent intent = new Intent(this, MusicPlayerService.class);startService(intent);bindService(intent, serviceConnection, BIND_AUTO_CREATE);}private void checkPermissions() {hasCheckedPermissions = true; // 标记已经检查过权限// Android 6.0 (API 23)以下版本不需要动态请求权限if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {loadSongs();return;}// 检查是否已经有权限boolean hasPermission = false;if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {// Android 13及以上版本检查READ_MEDIA_AUDIO权限hasPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_AUDIO)== PackageManager.PERMISSION_GRANTED;if (!hasPermission) {// 请求音频权限ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_MEDIA_AUDIO},PERMISSION_REQUEST_STORAGE);}} else {// Android 13以下版本检查READ_EXTERNAL_STORAGE权限hasPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)== PackageManager.PERMISSION_GRANTED;if (!hasPermission) {// 请求存储权限ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},PERMISSION_REQUEST_STORAGE);}}// 如果已经有权限,直接加载音乐if (hasPermission) {Log.d("MainActivity", "Permission already granted in checkPermissions, loading songs...");loadSongs();} else {Log.d("MainActivity", "Requesting permissions...");}}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);if (grantResults.length == 0) {Log.d("MainActivity", "Permission request cancelled");return;}switch (requestCode) {case PERMISSION_REQUEST_STORAGE:if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {Log.d("MainActivity", "Permission granted in onRequestPermissionsResult, loading songs...");loadSongs();} else {Log.d("MainActivity", "Permission denied");// 用户拒绝了权限if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&!shouldShowRequestPermissionRationale(permissions[0])) {// 用户选择了"不再询问"showPermissionSettingsDialog();} else {showRetryDialog();}}break;case PERMISSION_REQUEST_NOTIFICATION:if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {// 通知权限已授权,继续检查其他权限checkPermissions();} else {// 通知权限被拒绝,但这不是必需的,所以继续加载音乐loadSongs();}break;}}private void showRetryDialog() {new AlertDialog.Builder(this).setTitle("权限请求").setMessage("没有存储权限,应用将无法访问音乐文件。是否重新请求权限?").setPositiveButton("重试", (dialog, which) -> checkPermissions()).setNegativeButton("退出", (dialog, which) -> finish()).setCancelable(false).show();}private void showPermissionSettingsDialog() {String message;if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {message = "应用需要访问音频文件的权限才能播放音乐。\n\n" +"操作步骤:\n" +"1. 点击\"立即开启\"\n" +"2. 找到\"音频文件访问权限\"\n" +"3. 点击开关开启权限";} else {message = "应用需要存储权限才能播放音乐。\n\n" +"操作步骤:\n" +"1. 点击\"立即开启\"\n" +"2. 找到\"存储空间\"\n" +"3. 点击开关开启权限";}new AlertDialog.Builder(this).setTitle("需要开启权限").setMessage(message).setPositiveButton("立即开启", (dialog, which) -> {try {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {// Android 13及以上,尝试直接跳转到媒体权限设置Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);Uri uri = Uri.fromParts("package", getPackageName(), null);intent.setData(uri);// 尝试直接打开权限页面intent.putExtra(":settings:fragment_args_key", "permission");intent.putExtra(":settings:show_fragment_args", true);Bundle bundle = new Bundle();bundle.putString(":settings:fragment_args_key", "permission");intent.putExtra("android.provider.extra.APP_PACKAGE", getPackageName());startActivity(intent);} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {// Android 11及以上,使用MANAGE_EXTERNAL_STORAGEIntent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);intent.setData(Uri.parse("package:" + getPackageName()));startActivity(intent);} else {// Android 10及以下,使用APPLICATION_DETAILS_SETTINGSIntent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);intent.setData(Uri.parse("package:" + getPackageName()));intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);intent.addCategory(Intent.CATEGORY_DEFAULT);intent.putExtra("android.provider.extra.APP_PACKAGE", getPackageName());startActivity(intent);}} catch (Exception e) {// 如果特定跳转失败,回退到通用设置页面try {Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);Uri uri = Uri.fromParts("package", getPackageName(), null);intent.setData(uri);startActivity(intent);} catch (Exception e2) {// 如果还是失败,使用最基本的设置页面Intent intent = new Intent(Settings.ACTION_SETTINGS);startActivity(intent);Toast.makeText(this, "请在设置中找到本应用并开启所需权限", Toast.LENGTH_LONG).show();}}}).setNegativeButton("退出应用", (dialog, which) -> finish()).setCancelable(false).show();}private void loadSongs() {Log.d("MainActivity", "Starting to load songs...");// 再次确认权限boolean hasPermission = false;if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {hasPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_AUDIO)== PackageManager.PERMISSION_GRANTED;} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {hasPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)== PackageManager.PERMISSION_GRANTED;} else {hasPermission = true; // Android 6.0以下版本}if (!hasPermission) {Log.d("MainActivity", "Permission not granted when trying to load songs");if (!hasCheckedPermissions) {checkPermissions();}return;}// 使用增强版的异步扫描方法mediaScanner.scanMediaAsync();}private void updatePlayerControls() {if (!isBound || musicService == null) {playerControlLayout.setVisibility(View.GONE);return;}Song currentSong = musicService.getCurrentSong();if (currentSong != null) {playerControlLayout.setVisibility(View.VISIBLE);txtSongTitle.setText(currentSong.getTitle());txtArtist.setText(currentSong.getArtist());updatePlayPauseButton();int duration = musicService.getDuration();seekBar.setMax(duration);txtTotalTime.setText(formatTime(duration));updateSeekBar();} else {playerControlLayout.setVisibility(View.GONE);}}private void updatePlayPauseButton() {if (isBound && musicService != null && musicService.isPlaying()) {btnPlayPause.setImageResource(R.drawable.ic_pause);} else {btnPlayPause.setImageResource(R.drawable.ic_play);}}private void updateSeekBar() {if (isBound && musicService != null && musicService.isPrepared()) {int currentPosition = musicService.getCurrentPosition();seekBar.setProgress(currentPosition);updateCurrentTimeText(currentPosition);}}private void updateCurrentTimeText(int currentPosition) {txtCurrentTime.setText(formatTime(currentPosition));}private void startProgressTimer() {stopProgressTimer();timer = new Timer();timer.scheduleAtFixedRate(new TimerTask() {@Overridepublic void run() {runOnUiThread(() -> {if (isBound && musicService != null && musicService.isPlaying()) {updateSeekBar();updatePlayPauseButton();}});}}, 0, 1000);}private void stopProgressTimer() {if (timer != null) {timer.cancel();timer = null;}}private String formatTime(int milliseconds) {int seconds = (milliseconds / 1000) % 60;int minutes = (milliseconds / (1000 * 60)) % 60;return String.format("%02d:%02d", minutes, seconds);}// ViewPager适配器private static class ViewPagerAdapter extends FragmentPagerAdapter {private final List<Fragment> fragmentList = new ArrayList<>();private final List<String> fragmentTitleList = new ArrayList<>();public ViewPagerAdapter(FragmentManager manager) {super(manager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);}@NonNull@Overridepublic Fragment getItem(int position) {return fragmentList.get(position);}@Overridepublic int getCount() {return fragmentList.size();}public void addFragment(Fragment fragment, String title) {fragmentList.add(fragment);fragmentTitleList.add(title);}@Overridepublic CharSequence getPageTitle(int position) {return fragmentTitleList.get(position);}}// 公开方法,供Fragment调用public void playSong(int position) {if (isBound && musicService != null) {musicService.playSong(position);updatePlayerControls();}}public MusicPlayerService getMusicService() {return musicService;}public boolean isServiceBound() {return isBound;}private void handleMusicControlIntent(Intent intent) {if (intent == null || intent.getAction() == null) {return;}String action = intent.getAction();Intent broadcastIntent = new Intent(action);LocalBroadcastManager.getInstance(this).sendBroadcast(broadcastIntent);}@Overridepublic void onBackPressed() {View viewPager = findViewById(R.id.viewPager);View fragmentContainer = findViewById(R.id.fragmentContainer);if (fragmentContainer.getVisibility() == View.VISIBLE) {// 如果Fragment容器可见,先处理Fragment的返回栈if (getSupportFragmentManager().getBackStackEntryCount() > 0) {getSupportFragmentManager().popBackStack();// 检查返回栈是否为空if (getSupportFragmentManager().getBackStackEntryCount() == 1) {// 如果返回栈即将清空,显示ViewPagerviewPager.setVisibility(View.VISIBLE);fragmentContainer.setVisibility(View.GONE);}}} else {super.onBackPressed();}}// 添加标志位,记录是否已经检查过权限private boolean hasCheckedPermissions = false;
}
其余部分代码已经全部开源。
这是我开源的第一个小项目,同时也是接单的第一单。
开发工具:Android Studio、Navicat Premium 17、IntelliJ IDEA、Cursor
相关文章:

VibePlayer
源代码地址: VibePlayer: VibePlayer是一款功能强大的Android音乐播放器应用,专为音乐爱好者设计,提供了丰富的音乐播放和管理功能。 用户需求 VibePlayer是一款功能强大的Android音乐播放器应用,专为音乐爱好者设计࿰…...

【汇编逆向系列】三、函数调用包含单个参数之float类型-xmm0寄存器,sub,rep,stos,movss,mulss,addss指令
一、汇编代码 single_float_param:0000000000000060: F3 0F 11 44 24 08 movss dword ptr [rsp8],xmm00000000000000066: 57 push rdi0000000000000067: 48 83 EC 10 sub rsp,10h000000000000006B: 48 8B FC mov …...
JAVA开发工具——IntelliJ IDEA
JAVA开发工具——IntelliJ IDEA 软件下载地址https://www.jetbrains.com/idea/ IDEA项目结构介绍 项目(project)模块(module)包(package)类(class) 包含关系:项目 > 模块 >…...

基于fpga的疲劳驾驶检测
基于fpga的疲劳驾驶检测 前言一、系统硬件设计二、系统软件设计系统上板实验测试 前言 代码基于网络大佬代码进行修改的。限制性比较大,不太灵活,当个本科毕业设计还是够的。 基于FPGA的疲劳检测模块硬件设计以FPGA核心控制模块为中心,通过…...

感谢阿里云RDS产品及时的“光速服务”
❝ 开头还是介绍一下群,如果感兴趣PolarDB ,MongoDB ,MySQL ,PostgreSQL ,Redis, OceanBase, Sql Server等有问题,有需求都可以加群群内有各大数据库行业大咖,可以解决你的问题。加群请联系 liuaustin3 ,(共3000人左右…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(十一)
下载buildroot https://buildroot.org/download.html下载交叉工具链 使用ST官方交叉工具链的话,在buildroot配置外部工具会有问题,所以直接使用正点原子的交叉编译工具 buildroot构建根文件系统 - 参考正点原子 配置 buildroot tar -vxf buildroot-20…...
18-Oracle 23ai JSON二元性颠覆传统
在当今百花齐放的多模型数据库时代,开发人员常在关系型与文档型数据库间艰难取舍。Oracle Database 23ai推出的JSON关系二元性(JSON Relational Duality) 和二元性视图(Duality Views) 创新性地统一了两者优势…...

Linux68 FTP 测试 上传下载
6.在vi编辑器里,哪个命令能将光标移到第200行?( B ) 7.A、200g B、:200 C、g200 D、G200 假如您需要找出 /etc/my.conf 文件属于哪个包 (package) ,您可以执行( D )C A、 rpm -q /etc/my.co…...

山东大学《数据可视化》期末复习宝典
🌈 个人主页:十二月的猫-CSDN博客 🔥 系列专栏:🏀山东大学期末速通专用_十二月的猫的博客-CSDN博客 💪🏻 十二月的寒冬阻挡不了春天的脚步,十二点的黑夜遮蔽不住黎明的曙光 目录 1…...

【Elasticsearch】映射:Join 类型、Flattened 类型、多表关联设计
映射:Join 类型、Flattened 类型、多表关联设计 1.Join 类型1.1 主要应用场景1.1.1 一对多关系建模1.1.2 多层级关系建模1.1.3 需要独立更新子文档的场景1.1.4 文档分离但需要关联查询 1.2 使用注意事项1.3 与 Nested 类型的区别 2.Flattened 类型2.1 实际运用场景和…...

SpringBoot十二、SpringBoot系列web篇之过滤器Filte详解
一、前言 JavaWeb三大组件Servlet、Filter、Listener,其中之一便是过滤器Filter。 其实,Filter我们平常用的不多,一般多为项目初期搭建web架构的时候使用,后面用的就少了,在日常业务开发中不太可能碰到需要手写Filte…...

【RTSP从零实践】1、根据RTSP协议实现一个RTSP服务
😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C、数据结构、音视频🍭 🤣本文内容🤣&a…...

行为设计模式之Iterator(迭代器)
行为设计模式之Iterator(迭代器) 摘要: 迭代器模式(Iterator)是一种行为设计模式,它提供顺序访问聚合对象元素的方法,同时不暴露内部结构。该模式由迭代器接口(Iterator)、具体迭代器(ConcreteIterator)、聚合接口(Ag…...

FPGA点亮ILI9488驱动的SPI+RGB接口LCD显示屏(一)
FPGA点亮ILI9488驱动的SPIRGB接口LCD显示屏 ILI9488 RGB接口初始化 目录 前言 一、ILI9488简介 二、3线SPI接口简介 三、配置寄存器介绍 四、手册和初始化verilog FPGA代码 总结 前言 ILI9488是一款广泛应用于嵌入式系统和电子设备的彩色TFT LCD显示控制器芯片。本文将介…...
6板块公共数据典型应用场景【政务服务|公共安全|公共卫生|环境保护|金融风控|教育科研]
1. 政务服务 1.1 城市规划与管理 公共数据在城市规划与管理中可发挥关键作用。通过汇聚自然资源、建筑物、人口分布等基础数据,构建数字孪生城市模型,辅助城市总体规划编制、决策仿真模拟。在城市基础设施建设、安全运营、应急管理等方面,公共数据也是不可或缺的基础支撑。例…...

如何实现本地mqtt服务器和云端服务器同步?
有时候,一个物联网项目,A客户想要本地使用,B客户想要线上使用,C客户想要本地部署,当有网环境时能线上使用。这个时候就需要本地MQTT服务和线上MQTT服务能相互自动转发。 后来经我一翻研究,其实Activemq支持…...

windows10下搭建nfs服务器
windows10下搭建nfs服务器 有参考这篇博客 Windows10搭建NFS服务 - fuzidage - 博客园 下载 NFS Server这个app 通过网盘分享的文件:nfs1268 (1).exe 链接: https://pan.baidu.com/s/1rE4h710Uh-13kWGXvjkZzw 提取码: mwa4 --来自百度网盘超级会员v5的分享 下载后…...
CSS中justify-content: space-between首尾贴边中间等距(两端元素紧贴左右边缘,中间元素等距均匀分布)
justify-content: space-between; 是 CSS Flexbox 布局中的一个属性值,主要作用是在弹性容器的主轴方向上均匀分布子元素,具有以下核心特性: 作用效果: 首尾贴边 第一个子元素紧贴容器起始端 最后一个子元素紧贴容器结束端 中…...
【知识扫盲】分布式系统架构或分布式服务中的管理面,数据面和业务面
🧩 一、三大“面”的定义与职责(以大模型推理平台为例) 层级英文名职责关键组件举例数据面Data Plane处理用户请求、模型推理、输入输出数据转换等核心任务模型服务引擎、Tokenizer/Detokenizer、推理加速器(TensorRT、ONNX Runt…...

华为云Flexus+DeepSeek征文|Dify - LLM 云服务单机部署大语言模型攻略指南
前言:在当今人工智能快速发展的时代,华为云推出的 Dify - LLM 对话式 AI 开发平台为企业和开发者提供了便捷的大语言模型应用开发解决方案。 通过在华为云 Flexus 云服务器上单机部署 Dify,并成功集成 DeepSeek 模型,我们能够快速…...
Python爬虫:trafilatura 的详细使用(快速提取正文和评论以及结构,转换为 TXT、CSV 和 XML)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、trafilatura 概述1.1 trafilatura介绍1.2 亮点特色1.3 安装二、基本使用2.1 从URL直接提取内容2.2 输出格式控制2.3 从HTML字符串提取2.4 使用命令行工具三、高级功能3.1 全局设置3.2 提取参数定制3.3 多线程批量处…...
Cursor 工具项目构建指南: Uniapp Miniprogram 环境下的 Prompt Rules 约束
简简单单 Online zuozuo: 简简单单 Online zuozuo 简简单单 Online zuozuo 简简单单 Online zuozuo 简简单单 Online zuozuo :本心、输入输出、结果 简简单单 Online zuozuo : 文章目录 Cursor 工具项目构建指南: Uniapp Miniprogram 环境下的 Prompt Rules 约束前言项目简…...

JAVA反序列化应用 : URLDNS案例
反序列化的基本原理 基础普及 : 对象初始化数据方法 :1、使用构造方法 2、使用封装中的 set,get方法 这边我们就使用 1 注意 我们之后还需要进行 接入 序列化的接口 : 先进行序列化 : 反序列化: 反序列化导致的安…...

Vue-Leaflet地图组件开发(三)地图控件与高级样式设计
第三篇:Vue-Leaflet地图控件与高级样式设计 1. 专业级比例尺组件实现 1.1 比例尺控件集成 import { LControl } from "vue-leaflet/vue-leaflet";// 在模板中添加比例尺控件 <l-control-scaleposition"bottomleft":imperial"false&qu…...

174页PPT家居制造业集团战略规划和运营管控规划方案
甲方集团需要制定一个清晰的集团价值定位,从“指引多元”、“塑造 能力”以及“强化协同”等方面引领甲方做大做强 集团需要通过管控模式、组织架构及职能、授权界面、关键流程、战略 实施和组织演进路径,平衡风险控制和迅速发展,保证战略落地…...

wsl开启即闪退
[ 问题 ]: 在一次电脑卡住,强制关机重启后,遇到打开WSL就闪退的问题在CMD中打开WSL,出现如上图的描述: C:\Users\admin>wsl wsl: 检测到 localhost 代理配置,但未镜像到 WSL。NAT 模式下的 WSL 不支持…...
Spark 写文件
Repartition Spark 输出文件数量 假设每个 Task 的输出数据都包含了全部 8 个分区值,那么最终的文件生成情况如下: 总文件数 = Task 数量 分区组合数 假设: Task 数量:200 分区组合数:8 个 (from_cluster 和 ds 的组合) 则: 总文件数:200 8 = 1600 …...
PostgreSQL 的扩展pg_prewarm
PostgreSQL 的扩展pg_prewarm pg_prewarm 是 PostgreSQL 提供的一个实用扩展,用于将数据预先加载到共享缓冲区或操作系统缓存中,从而提升查询性能。 一、扩展概述 核心功能 手动预热:将指定的表或索引数据加载到内存自动预热:…...
F5 – TCP 连接管理:会话、池级和节点级操作
在 F5 BIG-IP 中,您可以在池成员级别或节点级别管理流向服务器的流量。节点级别状态会影响与该节点关联的所有池,而池成员状态则仅限于单个池。了解每种方法以及何时使用它们对于顺利进行维护窗口和流量管理至关重要。 池级状态:启用、禁用、强制离线、移除 在 BIG-IP 配置…...
金融预测模型开发:数据预处理、机器学习预测与交易策略优化
金融预测模型开发:数据预处理、机器学习预测与交易策略优化 概述 本文将详细介绍一个完整的金融预测模型开发流程,包含数据预处理、机器学习预测和交易策略优化三个核心模块。我们使用Python实现一个端到端的解决方案,适用于股票价格预测和量化交易策略开发。 # 导入必要…...