这两天在做一个项目,在线音乐播放器。在设计上传音乐模块的时候,我想到有以下几点问题:
1. 用户是否已经登录?
2. 音乐是否已经上传过?
3. 文件是否真的是mp3文件?
而在这三个问题当中最不好解决的就是第三个问题。我花了将近一天的时间,去查找资料、博客,但经过尝试,发现都没有一个准确的答案。
最后我发现一个问题,就是在上传非MP3文件的时候,它总是会抛异常,于是我就在想,把异常 catch 住,然后在 catch 的时候,同时返回错误信息,在经过多次尝试后发现真的可以。
首先你需要引入一个依赖
<!-- https://mvnrepository.com/artifact/net.jthink/jaudiotagger 判断文件是否是音乐 -->
<dependency>
<groupId>net.jthink</groupId>
<artifactId>jaudiotagger</artifactId>
<version>2.2.6-PATHRIK</version>
</dependency>
这是部分源码:
@RestController
@RequestMapping("/music")
public class MusicController {
@Value("${music.local.path}")
private String SAVE_PATH;
@Autowired
private MusicMapper musicMapper;
@RequestMapping("/upload")
public Result<Boolean> uploadMusic(String singer, MultipartFile file, HttpServletRequest request) throws ReadOnlyFileException, CannotReadException, TagException, InvalidAudioFrameException {
// 获取文件的名字 xxx.mp3
String fileName = file.getOriginalFilename();
System.out.println("fileName:" + fileName);
// 整个路径
String path = SAVE_PATH + fileName;
System.out.println("path:" + path);
File dest = new File(path);
if(!dest.exists()) {
dest.mkdirs();
}
// 上传文件到目标路径
try {
file.transferTo(dest);
// 判断上传的文件是否为音乐
MP3File mp3File = (MP3File) AudioFileIO.read(dest);
if(!mp3File.hasID3v1Tag() || !mp3File.hasID3v2Tag()) {
dest.delete();
return new Result<>(-1, "请上传音乐文件", false);
}
} catch (IOException e) {
if(dest != null) {
dest.delete();
}
e.printStackTrace();
return new Result<>(-1, "上传文件失败", false);
}
}
}
这是最开始的写法,当我用 postman 测试时,发现上传非MP3文件,它会抛异常,异常信息会返回到 postman 上。

上传的文件是一个 txt 文件,只不过我把后缀名改成了 MP3,可以看到,异常信息被返回到了 客户端。
这是部分异常信息:
{
"timestamp": "2025-03-24T01:30:18.835+00:00",
"status": 500,
"error": "Internal Server Error",
"trace": "org.jaudiotagger.audio.exceptions.InvalidAudioFrameException: No audio header found within 错题本 - 副本.mp3\r\n\tat
"message": "No audio header found within 错题本 - 副本.mp3",
"path": "/music/upload"
}
可以看到抛出了 InvalidAudioFrameException 的异常:No audio header found within 错题本 - 副本.mp3(在 错题本 - 副本.mp3 中没有找到音频头),说明文件并不是一个MP3文件
那么当我上传的文件不是 MP3文件(后缀也不是mp3) 时呢,比如说 txt文件

可以看到抛出了 CannotReadException 的异常:No Reader associated with this extension:txt(没有Reader与此扩展相关联:txt),大概意思是说无法读取这个文件因为这是 txt 文件,由此也可看出文件不是MP3文件
可见这样写是完全可以的,但是把异常信息写回到客户端很不雅观,于是我就 catch 了一下,并且返回了一些错误信息。
这里采用的是先上传再判断的方式。也就是说不管文件是什么类型,先上传,如果 catch 到异常了
再把上传过的文件删除掉即可。
具体实现方式看代码:
@RestController
@RequestMapping("/music")
public class MusicController {
@Value("${music.local.path}")
private String SAVE_PATH;
@Autowired
private MusicMapper musicMapper;
@RequestMapping("/upload")
public Result<Boolean> uploadMusic(String singer, MultipartFile file, HttpServletRequest request) throws ReadOnlyFileException {
// 获取文件的名字 xxx.mp3
String fileName = file.getOriginalFilename();
System.out.println("fileName:" + fileName);
// 整个路径
String path = SAVE_PATH + fileName;
System.out.println("path:" + path);
File dest = new File(path);
if(!dest.exists()) {
dest.mkdirs();
}
// 上传文件到目标路径
try {
file.transferTo(dest);
// 判断上传的文件是否为音乐
MP3File mp3File = (MP3File) AudioFileIO.read(dest);
// 这个 if 语句其实没什么用,本来是想通过 if 语句来判断到底是不是mp3文件
// 但是后来发现它会抛异常,根本执行不到这里,所有就不用这种方式了
// if(!mp3File.hasID3v1Tag() || !mp3File.hasID3v2Tag()) {
// dest.delete();
// return new Result<>(-1, "请上传音乐文件", false);
}
} catch (IOException e) {
if(dest != null) {
dest.delete();
}
e.printStackTrace();
return new Result<>(-1, "上传文件失败", false);
} catch (InvalidAudioFrameException | CannotReadException | TagException e) {
dest.delete();
e.printStackTrace();
return new Result<>(-1, "请上传音乐文件", false);
}
}
}
此时再通过 postman 测试,会返回错误信息:

上传 txt 文件(非MP3后缀文件也是):

那么 使用 AudioFileIO.read() 这个还需要抛出两个异常,在上面源码上也可以看到 ,一个是 ReadOnlyFileException,另一个是 TagException。第一个不难理解,看字面意思就知道是只读文件异常,但是具体什么情况会抛异常,我就不清楚了。那么第二个异常的话是 标签异常,我猜测应该 MP3文件中有某个标签,如果没有这个标签就会抛异常,这纯属个人猜测。
如果有大佬可以帮忙解读一下,那真的太感谢了!!!!!!
最后希望这篇博客可以带给大家帮助。

2547

被折叠的 条评论
为什么被折叠?



