本地音乐服务器(二)
4. 上传音乐模块设计
4.1 上传音乐的接口设计
请求和响应设计:
新建music实体类:
@Data
public class Music {private int id;private String title;private String singer;private String time;private String url;private int userid;
}
4.2 创建MusicController类
package com.example.spring_musicserver_1113.controller;import com.example.spring_musicserver_1113.tools.Constant;
import com.example.spring_musicserver_1113.tools.ResponseBodyMessage;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.IOException;/*** @version 1.0* @Author 作者名* @Date 2024/11/14 13:19* @注释*/
@RestController
@RequestMapping("/music")
public class MusicController {private String SAVE_PATH="D:/music/";@RequestMapping("/upload")public ResponseBodyMessage<Boolean> insertMusic(@RequestParam String singer,@RequestParam("filename") MultipartFile file, HttpServletRequest request){//1、判断登录情况HttpSession httpSession = request.getSession(false);if(httpSession == null || httpSession.getAttribute(Constant.USERINFO_SESSION_KEY) == null){System.out.println("没有登录!");return new ResponseBodyMessage<>(-1,"请登录后上传",false);}//2、上传到服务器String fileNameAndType = file.getOriginalFilename();System.out.println("fileNameAndType"+fileNameAndType);String path = SAVE_PATH + fileNameAndType;File dest = new File(path);if(!dest.exists()){dest.mkdir();}try {file.transferTo(dest);return new ResponseBodyMessage<>(0,"上传成功",true);} catch (IOException e) {e.printStackTrace();}return new ResponseBodyMessage<>(-1,"上传失败",false);}
}
使用postman进行测试:
首先登录,其次在上传音乐:
但是我们在目标路径下面得到上传的文件:
优化一下上传路径细节:
首先在properties文件里面进行配置:
其次通过@value注入上传文件的路径:
重新部署,进行测试,无误;
4.3 如何判断上传的⽂件是mp3
每一种文件都有自己的格式,不能通过后缀名判断mp3⽂件格式,如果一个文件的id3v1部分的前三个字节,这三个字节是标签标志,如果该标签存在且正确的话(包含tag字符),该文件就是音频文件或mp3文件;
MP3文件结构:
MP3 文件大体分为三部分:TAG_V2(ID3V2),Frame, TAG_V1(ID3V1)
由上图结构可知,每个Frame都由帧头和数据部分组成
参考链接: https://blog.csdn.net/ffjffjffjffjffj/article/details/99691239 https://www.cnblogs.com/ranson7zop/p/7655474.html https://blog.csdn.net/sunshine1314/article/details/2514322
我们此时的上传逻辑是,在客户端(postman通过form表单进行音乐上传请求,服务器接受文件到某一路径,服务器根据文件的路径和请求的会话信息获取网数据库上传的数据,最后通过mybaties操作数据层进行数据库添加)
4.4 实现数据库上传
上述实现只是实现了简单的本地上传⽂件,还未将数据插⼊到数据库当中,接下来我们实现数据库中数据的写⼊。
1、准备数据
2、调用insert
完善musicmapper和musicmappe.xml的代码
int insert(String title,String singer,String time,String url,int userid);
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.example.spring_musicserver_1113.mapper.MusicMapper"><insert id="insert">insert into music(title,singer,time,url,userid)values(#{title},#{singer},#{time},#{url},#{userid});</insert> </mapper>
代码如下:
//3、进行数据库的上传//准备数据int index = fileNameAndType.lastIndexOf(".");//对于文件名,从后往前扫描,找到第一个。String title = fileNameAndType.substring(0,index);User user = (User) httpSession.getAttribute(Constant.USERINFO_SESSION_KEY);int userid = user.getId();//播放音乐的时候就会发出一个http请求String url = "/music/get?path="+title;SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");String time = sf.format(new Date());//调用inserttry{int ret = 0;ret = musicMapper.insert(title,singer,time,url,userid);if (ret == 1){return new ResponseBodyMessage<>(0,"数据库上传成功",true);}else {return new ResponseBodyMessage<>(-1,"数据库上传失败",false);}}catch (BindingException e){dest.delete();return new ResponseBodyMessage<>(-1,"数据库上传失败",false);}
测试结果如下:
5. 播放音乐模块设计
请求响应设计
新增⽅法get获取mp3文件;
@RequestMapping("/get")public ResponseEntity<byte[]> get(String path){File file = new File(SAVE_PATH+"/"+path);byte[] a= null;try {a = Files.readAllBytes(file.toPath());if(a == null){return ResponseEntity.badRequest().build();}return ResponseEntity.ok(a);} catch (IOException e) {e.printStackTrace();}return ResponseEntity.badRequest().build();}
代码解释:
1. Files.readAllBytes(String path) : 读取⽂件中的所有字节,读⼊内存,参数path是⽂件的路径
2. ResponseEntity
ResponseEntity对象是Spring对请求响应的封装。它继承了HttpEntity对象,包含了Http的响应码 (httpstatus)、响应头(header)、响应体(body)三个部分。 ResponseEntity类继承⾃HttpEntity类,被⽤于Controller层⽅法。
ResponseEntity.ok⽅法有2个⽅ 法,分别是有参数和没有参数。
//这个⽅法若被调⽤的话,返回OK状态
public static ResponseEntity.BodyBuilder ok(){return status(HttpStatus.OK);}
// 这个⽅法若被调⽤的话,返回 body 内容和 OK 状态
public static <T> ResponseEntity<T> ok(T body) {ResponseEntity.BodyBuilder builder = ok();//ResponseEntity可以通过这个builder返回任意类型的body内容return builder.body(body); }
使用postman测试mp3文件能否上传成功:
如图所示,我们的文件是mp3文件;
测试一个非mp3文件,将一个图片文件格式改为MP3进行上传到服务器和数据库,最后通过get方法进行获取播放,我们发现该mp3文件没有tag标签,故此不能进行播放;
相关文章:

本地音乐服务器(二)
4. 上传音乐模块设计 4.1 上传音乐的接口设计 请求和响应设计: 新建music实体类: Data public class Music {private int id;private String title;private String singer;private String time;private String url;private int userid; } 4.2 创建Mu…...

第三十六篇——伯努利试验:到底如何理解随机性?
目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么? 四、总结五、升华 一、背景介绍 概率论指导着我们对于直觉不靠谱的事情,以及为我们如何更高效…...

【Android、IOS、Flutter、鸿蒙、ReactNative 】屏幕适配
Android Java 屏幕适配 参考 今日头条适配依赖配置 添加设计屏幕尺寸 设置字体大小 通过切换不同屏幕尺寸查看字体大小 设置文本宽高 通过切换不同屏幕尺寸查看文本宽高 Android Compose 屏幕适配 <...

candence : 如何利用EXCEL 绘制复杂、多管脚元件
如何利用EXCEL 绘制复杂、多管脚元件 前面的步骤直接略过 我们以STM32F407VEXX 系列 100pin 芯片为例讲解: 1、新建好一个空元件 2、使用阵列,放置管脚 点击 “ ok ” 3、选中所有管脚 右键 “edit properites” 出现如下页面 4、点击 左上角&…...
项目配置文件选择(Json,xml,Yaml, INI)
选择使用哪种类型的配置文件(如 JSON、XML 或其他格式)取决于多个因素,包括项目的需求、团队的熟悉程度、数据结构的复杂性以及可读性和可维护性等。以下是对常见配置文件格式的比较,以及在不同情况下的推荐: 1. JSON&…...
Android 使用Retrofit 以纯二进制文件流上传文件
一、背景 一般上传文件都是以表单形式上传文件,最近项目中涉及到非表单形式上传文件流,分为单个文件流上传、大文件分段上传,此种情景资料较少,这里记录下。 二、方案介绍 2.1 需求协议 1. 上传文件 API 端点:/serv…...

Vue3踩坑记录
目录 一、定义常变量 1.1、ref和reactive到底用谁? 二、双向绑定 2.1、直接改变表格该行数据 2.1、在弹窗改变表格该行数据 一、定义常变量 1.1、ref和reactive到底用谁? 已知:使用ref定义基础类型数据;使用reactive定义复…...

大数据-227 离线数仓 - Flume 自定义拦截器(续接上节) 采集启动日志和事件日志
点一下关注吧!!!非常感谢!!持续更新!!! Java篇开始了! 目前开始更新 MyBatis,一起深入浅出! 目前已经更新到了: Hadoop࿰…...

【热门主题】000054 ECMAScript:现代 Web 开发的核心语言
前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 💕 目录 【热…...
【Pytorch】torch.nn.functional模块中的非线性激活函数
在使用torch.nn.functional模块时,需要导入包: from torch.nn import functional 以下是常见激活函数的介绍以及对应的代码示例: tanh (双曲正切) 输出范围:(-1, 1) 特点:中心对称,适合处理归一化后的数据…...
reactflow 中 useNodesState 模块作用
1. 节点状态管理核心功能 useNodesState是一个关键的钩子函数,用于专门管理节点(Nodes)的状态。节点是流程图的核心元素,它们可以代表各种实体,如流程中的任务、系统中的组件或者数据结构中的元素。 useNodesState提…...
Go语言内存分配源码分析学习笔记
大家好,我是V 哥。GO GO GO,今天来说一说Go语言内存分配问题,Go语言内存分配的源码主要集中在runtime包中,它实现了Go语言的内存管理,包括初始化、分配、回收和释放等。下面来对这些过程详细分析一下,先赞后…...
【jvm】方法区常用参数有哪些
目录 1. -XX:PermSize2. -XX:MaxPermSize3. -XX:MetaspaceSize(Java 8及以后)4. -XX:MaxMetaspaceSize(Java 8及以后)5. -Xnoclassgc6. -XX:TraceClassLoading7.-XX:TraceClassUnLoading 1. -XX:PermSize 1.设置JVM初始分配的永久…...

JAVA环境的配置
首先找到JDK环境的官网。 Java Archive Downloads - Java SE 8u211 and laterhttps://www.oracle.com/java/technologies/javase/javase8u211-later-archive-downloads.html 我下载的最后一个x64.exe,下载后,直接双击运行,我这里默认安装到…...

LLM文档对话 —— pdf解析关键问题
一、为什么需要进行pdf解析? 最近在探索ChatPDF和ChatDoc等方案的思路,也就是用LLM实现文档助手。在此记录一些难题和解决方案,首先讲解主要思想,其次以问题回答的形式展开。 二、为什么需要对pdf进行解析? 当利用L…...
MySQL单表查询时索引使用情况
本文针对 MySQL 单表查询时索引使用的几种场景情况进行分析。 假设有一个表如下: CREATE TABLE single_table (id INT NOT NULL AUTO_INCREMENT,key1 VARCHAR(100),key2 INT,key3 VARCHAR(100),key_part1 VARCHAR(100),key_part2 VARCHAR(100),key_part3 VARCHAR(1…...

Qt邮箱程序改良版(信号和槽)
上一版代码可以正常使用,但是会报错 上一篇文章 错误信息 "QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread" 指出了一个问题,即在非主线程中尝试启用或禁用套接字通知器(QSocketNotifier)…...

入门到精通mysql数据(四)
5、运维篇 5.1、日志 5.1.1、错误日志 错误日志是MySQL中最重要的日志之一,它记录了当mysqld启动和停止,以及服务器在运行过程中发生任何严重错误时的相关信息。当数据库出现任何故障导致无法正常使用时,建议首先查看此日志。 该日志是默认开启的,默认存放目录/var/log…...
Java 设计模式 详解
在Java开发中,设计模式是一种常见的、成熟的解决方案,用于应对特定的设计问题和复杂性管理。以下是一些常用的设计模式,它们可以分为三类:创建型模式、结构型模式和行为型模式。 一、创建型模式 创建型模式主要负责对象的创建&a…...

卡尔曼滤波学习资料汇总
卡尔曼滤波学习资料汇总 其实,当初的目的,是为了写 MPU6050 的代码的,然后不知不觉学了那么多,也是因为好奇、感兴趣吧 有些还没看完,之后笔记也会同步更新的 学习原始材料 【卡尔曼滤波器】1_递归算法_Recursive P…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...

在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
绕过 Xcode?使用 Appuploader和主流工具实现 iOS 上架自动化
iOS 应用的发布流程一直是开发链路中最“苹果味”的环节:强依赖 Xcode、必须使用 macOS、各种证书和描述文件配置……对很多跨平台开发者来说,这一套流程并不友好。 特别是当你的项目主要在 Windows 或 Linux 下开发(例如 Flutter、React Na…...

rm视觉学习1-自瞄部分
首先先感谢中南大学的开源,提供了很全面的思路,减少了很多基础性的开发研究 我看的阅读的是中南大学FYT战队开源视觉代码 链接:https://github.com/CSU-FYT-Vision/FYT2024_vision.git 1.框架: 代码框架结构:readme有…...
当下AI智能硬件方案浅谈
背景: 现在大模型出来以后,打破了常规的机械式的对话,人机对话变得更聪明一点。 对话用到的技术主要是实时音视频,简称为RTC。下游硬件厂商一般都不会去自己开发音视频技术,开发自己的大模型。商用方案多见为字节、百…...

中科院1区顶刊|IF14+:多组学MR联合单细胞时空分析,锁定心血管代谢疾病的免疫治疗新靶点
中科院1区顶刊|IF14:多组学MR联合单细胞时空分析,锁定心血管代谢疾病的免疫治疗新靶点 当下,免疫与代谢性疾病的关联研究已成为生命科学领域的前沿热点。随着研究的深入,我们愈发清晰地认识到免疫系统与代谢系统之间存在着极为复…...
ubuntu系统 | docker+dify+ollama+deepseek搭建本地应用
1、docker 介绍与安装 docker安装:1、Ubuntu系统安装docker_ubuntu docker run-CSDN博客 docker介绍及镜像源配置:2、ubuntu系统docker介绍及镜像源和仓库配置-CSDN博客 docker常用命令:3、ubuntu系统docker常用命令-CSDN博客 docker compose安装:4、docker compose-CS…...

Python 解释器安装全攻略(适用于 Linux / Windows / macOS)
目录 一、Windows安装Python解释器1.1 下载并安装Python解释1.2 测试安装是否成功1.3 设置pip的国内镜像------永久配置 二、macOS安装Python解释器三、Linux下安装Python解释器3.1 Rocky8.10/Rocky9.5安装Python解释器3.2 Ubuntu2204/Ubuntu2404安装Python解释器3.3 设置pip的…...