栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

基于 SpringBoot + MyBatis 的在线音乐播放器

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

基于 SpringBoot + MyBatis 的在线音乐播放器

文章目录
  • 1. 项目设计
  • 2. 效果展示
  • 3. 创建项目 配置文件
    • 3.1 创建项目
    • 3.2 配置文件
      • 3.2.1 在 application.properties 中添加配置文件
      • 3.2.2 在 resources 目录下创建mapper
  • 4. 数据库的设计与实现
  • 5. 交互接口的设计
  • 6. 工具包
    • 6.1 设置统一响应类
    • 6.2 Constant类
    • 6.3 了解 MD5 加密 和 BCrypt 加密
      • MD5使用示例 (加盐)
      • BCrypt使用示例
    • 6.4 在Config中 注入 BCryptPasswordEncoder 对象
    • 6.5 添加拦截器
      • 6.5.1 LoginInterceptor 类
      • 6.5.2 AppConfig 类
  • 7. 登录模块
    • 7.1 创建 User 实体类
    • 7.2 使用 Mybatis 操作数据库
      • 7.2.1 在 UserServer 中添加代码
      • 7.2.2 在 UserMapper 中添加代码
      • 7.2.3 在 UserMapper.xml 中添加代码
    • 7.3 创建 UserConroller 添加代码
    • 7.4 前端代码
  • 8. 注册模块
    • 8.1 使用 Mybatis 操作数据库
      • 8.1.1 在 UserServer 中添加代码
      • 8.1.2 在 UserMapper 中添加代码
      • 8.1.3 在 UserMapper.xml 中添加代码
    • 8.2 向 UserController 中添加代码
    • 8.3 前端代码
  • 9. 退出功能
    • 9.1 向 UserController 中添加代码
    • 9.2 登录注册测试.
  • 10. 上传音乐模块
    • 10.1 创建 Music 实体类
    • 10.2 使用 Mybatis 操作数据库
      • 10.2.1 在 MusicServer 中添加代码
      • 10.2.2 在 MusicMapper 中添加代码
      • 10.2.3 在 MusicMapper.xml 中添加代码
    • 10.3 向 MusicController 中添加代码
    • 10.4 前端代码
    • 10.5 测试代码
  • 11. 播放音乐模块
    • 11.1 向 MusicController 中添加代码
    • 11.2 测试代码
  • 12. 删除音乐模块
    • 12.1 使用 Mybatis 操作数据库
      • 12.1.1 在 MusicServer 和 CollectServer 中添加代码
      • 12.1.2 在 MusicMapper 和 CollectMapper 中添加代码
      • 12.1.3 在 MusicMapper.xml 和 CollectMapper.xml 中添加代码
    • 12.2 删除单一音乐功能
      • 12.2.1 向 MusicController 中添加代码
      • 12.2.2 前端代码
      • 12.2.3 测试代码
    • 12.3 删除多个音乐功能
      • 12.3.1 向 MusicConroller 中添加代码
      • 12.3.2 前端代码
      • 12.3.3 测试代码
  • 13. 收藏音乐模块
    • 13.1 创建 Collect 实体类
    • 13.2 使用 Mybatis 操作数据库
      • 13.2.1 在 CollectServer 中添加代码
      • 13.2.2 在 CollectMapper 中添加代码
      • 13.2.3 在 CollectMapper.xml 中添加代码
    • 13.3 向 CollectControll 中添加代码
    • 13.4 前端代码
    • 13.5 测试代码
  • 14. 取消收藏音乐模块
    • 14.1 使用 Mybatis 操作数据库
      • 14.1.1 在 CollectServer 中添加代码
      • 14.1.2 在 CollectMapper 中添加代码
      • 14.1.3 在 CollectMapper.xml 中添加代码
    • 14.2 向 CollectControll 中添加代码
    • 14.3 前端代码
    • 14.4 测试代码
  • 15. 主页面 - 查询模块
    • 15.1 使用 Mybatis 操作数据库
      • 15.1.1 在 MusicServer 中添加代码
      • 15.1.2 在 MusicMapper 中添加代码
      • 15.1.3 在 MusicMapper.xml 中添加代码
    • 15.2 向 MusicController 中添加代码
    • 15.3 前端代码
    • 15.4 测试代码
  • 16. 收藏页面 - 查询模块
    • 16.1 使用 Mybatis 操作数据库
      • 16.1.1 在 CollectServer 中添加代码
      • 16.1.2 在 CollectMapper 中添加代码
      • 16.1.3 在 CollectMapper.xml 中添加代码
    • 16.2 向 CollectController 中添加代码
    • 16.3 前端代码
    • 16.4 测试代码

1. 项目设计

前端 : HTML+CSS+JavaScript+JQuery
后端 : Spring MVC+Spring Boot+MyBatis

2. 效果展示





3. 创建项目 配置文件 3.1 创建项目

3.2 配置文件 3.2.1 在 application.properties 中添加配置文件

配置数据库

spring.datasource.url=jdbc:mysql://localhost:3306/onlinemusicserver?characterEncoding=utf8&useSSL=true
spring.datasource.username=root
spring.datasource.password=0000
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

配置 Mybatis

mybatis.mapper-locations=classpath:mapper
    public static String inputPassToFormPass(String inputPass) {
        String str = ""+salt.charAt(1)+salt.charAt(3) + inputPass
                +salt.charAt(5) + salt.charAt(6);
        return md5(str);
    }

    
    public static String formPassToDBPass(String formPass, String salt) {
        String str = ""+salt.charAt(0)+salt.charAt(2) + formPass +salt.charAt(5)
                + salt.charAt(4);
        return md5(str);
    }

    
    public static String inputPassToDbPass(String inputPass, String saltDB) {
        String formPass = inputPassToFormPass(inputPass);
        String dbPass = formPassToDBPass(formPass, saltDB);
        return dbPass;
    }
}

BCrypt使用示例

添加依赖



org.springframework.security
spring-security-web


org.springframework.security
spring-security-config

在springboot启动类添加:

@SpringBootApplication(exclude ={org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class})

创建BCryptTest测试类:

public class BCryptTest {
public static void main(String[] args) {
    //模拟从前端获得的密码
    String password = "123456";
    BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
    String newPassword = bCryptPasswordEncoder.encode(password);
    System.out.println("加密的密码为: "+newPassword);
    //使用matches方法进行密码的校验
    boolean same_password_result = bCryptPasswordEncoder.matches(password,newPassword);
    //返回true
    System.out.println("加密的密码和正确密码对比结果: "+same_password_result);
    boolean other_password_result = bCryptPasswordEncoder.matches("987654",newPassword);
    //返回false
    System.out.println("加密的密码和错误的密码对比结果: " + other_password_result);
}

运行结果: (每次加密的密码都不同)

6.4 在Config中 注入 BCryptPasswordEncoder 对象
@Configuration
public class AppConfig implements WebMvcConfigurer {

    @Bean
    public BCryptPasswordEncoder getBCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
6.5 添加拦截器 6.5.1 LoginInterceptor 类
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession httpSession = request.getSession(false);
        if(httpSession != null && httpSession.getAttribute(Constant.USER_SESSION_KEY) != null) {
            return true;
        }
        response.sendRedirect("/login.html");
        return false;
    }
}
6.5.2 AppConfig 类
@Configuration
public class AppConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        LoginInterceptor loginInterceptor = new LoginInterceptor();
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("login.html")
                .excludePathPatterns("cssimagesfontsjsscssuser/login")
                .excludePathPatterns("user/register")
                .excludePathPatterns("user/logout");
    }
}
7. 登录模块 7.1 创建 User 实体类

创建 model 包, 然后创建 User 类

@Data
public class User {
    private int userId;
    private String username;
    private String password;
}
7.2 使用 Mybatis 操作数据库

这里登录 需要进行 数据库的查询. 查询是否存在当前 username 的用户.

所以要设计, 通过用户名查找用户信息

7.2.1 在 UserServer 中添加代码
public User selectByName(String username) {
        return userMapper.selectByName(username);
    }
7.2.2 在 UserMapper 中添加代码
    
    User selectByName(String username);
7.2.3 在 UserMapper.xml 中添加代码
    
    select * from music where title = #{title};


10.3 向 MusicController 中添加代码
  1. 这里首先对session判断, 判断是否存在session. (配置拦截器之后就不需要判断了)

  2. 去数据库中查询所有title相同的歌曲. 如果歌曲名相同,歌手也相同, 那么就上传失败.

  3. 创建文件夹. 将文件上传到文件夹中.(文件名是以歌手-歌名创建, 为了防止重名无法读取)

  4. 然后对该文件, 进行判断, 判断是不是 MP3 文件, 注意MP3文件, 字节码中有 字符"TAG"

  5. 在数据库中上传数据. 注意这里的path.

@RestController
@RequestMapping("/music")
public class MusicController {
    @Autowired
    private MusicServer musicServer;

    @Value("${upload.path}")
    public String SAVE_PATH;

    
    @RequestMapping("/upload")
    public ResponseBodyMessage insertMusic(@RequestParam String singer,
                                                    @RequestPart("filename") MultipartFile file,
                                                    HttpServletRequest request,
                                                    HttpServletResponse response) {
        // 检测登录
        HttpSession session = request.getSession(false);
        if (session == null || session.getAttribute(Constant.USER_SESSION_KEY) == null) {
            System.out.println("当前未登录!");
            return new ResponseBodyMessage<>(-1,"请登录后上传",false);
        }

        // 文件的类型
        String fileNameAndType = file.getOriginalFilename();

        // 防止出现重复的相同歌曲和相同歌手.可以出现相同歌曲不同歌手
        String title = fileNameAndType.substring(0,fileNameAndType.lastIndexOf('.'));
        // 可能出现多首名称相同的歌曲, 所以用 List
        List list = musicServer.selectByTitle(title);
        if(list != null){
            for(Music music : list) {
                if(music.getAuthor().equals(singer)){
                    return new ResponseBodyMessage<>(-1,"当前歌手的歌曲已经存在!",false);
                }
            }
        }

        // 创建文件
        String path = SAVE_PATH +singer+"-"+fileNameAndType;

        File dest = new File(path);
        if(!dest.exists()) {
            dest.mkdirs();
        }

        try {
            file.transferTo(dest);
            //return new ResponseBodyMessage<>(1,"上传成功!",true);
        } catch (IOException e) {
            e.printStackTrace();
            return new ResponseBodyMessage<>(-1,"服务器上传失败!",false);
        }

        // 这里对是不是 MP3 文件进行判断. 主要是判断是否存在 TAG 这个字符
        File file1 = new File(path);
        byte[] res = null;
        try {
            res = Files.readAllBytes(file1.toPath());
            if(res == null) {
                return new ResponseBodyMessage<>(-1,"当前文件不存在",false);
            }
            String str = new String(res);
            if(!str.contains("TAG")) {
                file1.delete();
                return new ResponseBodyMessage<>(-1,"当前不是mp3文件",false);
            }
        }catch (IOException e){
            e.printStackTrace();
            return new ResponseBodyMessage<>(-1,"服务器出现问题", false);
        }

        // 在数据库中上传数据
        User user = (User) session.getAttribute(Constant.USER_SESSION_KEY);
        // 这里传递的 path 没有带 `.MP3` 后期在前端进行设置
        String uploadPath = "/music/play?path="+singer+"-"+title;
        try {
            int ret = musicServer.insert(title,singer,uploadPath,user.getUserId());
            if(ret == 1) {
                response.sendRedirect("/index.html");
                return new ResponseBodyMessage<>(1,"上传成功",true);
            }else {
                return new ResponseBodyMessage<>(-1,"数据库上传失败",false);
            }
        }catch (BindingException | IOException e) {
            dest.delete();
            return new ResponseBodyMessage<>(-1,"数据库上传失败",false);
        }
    }
}
10.4 前端代码
文件上传: 歌手名:
10.5 测试代码

11. 播放音乐模块 11.1 向 MusicController 中添加代码
  1. 获取存储路径的文件.
  2. 读取文件中的所有字节,读入内存, 如果不为空, 返回字节码回去.
    
    @RequestMapping("/play")
    public ResponseEntity playMusic(@RequestParam String path){
        File file = new File(SAVE_PATH + path);
        byte[] res = null;
        try {
            res = Files.readAllBytes(file.toPath());
            if (res == null) {
                return ResponseEntity.badRequest().build();
            }
            return ResponseEntity.ok(res);
        } catch (IOException e) {
            e.printStackTrace();
            return ResponseEntity.badRequest().build();
        }
    }
11.2 测试代码

观察字节码可以看出, 有 TAG 这个字符

12. 删除音乐模块 12.1 使用 Mybatis 操作数据库

删除音乐, 主要是两个删除, 一个是删除单个, 根据单个musicId 删除. 另一个是删除多个, 根据多个 musicId 删除.
 
这里根据 musicId 删除, 需要去数据库里查找 是否存在当前 musicId 的歌曲. 存在删成功, 不存在删失败.
 
注意, 删除的时候, 不仅要删除 music表里的歌曲. 也要删除 collect 表里的歌曲.

12.1.1 在 MusicServer 和 CollectServer 中添加代码

musicServer

	public Music selectById(int musicId) {
        return musicMapper.selectById(musicId);
    }

    public int deleteById(int musicId) {
        return musicMapper.deleteById(musicId);
    }

collectServer

	public int deleteLoveMusicById(int musicId){
        return collectMapper.deleteLoveMusicById(musicId);
    }
12.1.2 在 MusicMapper 和 CollectMapper 中添加代码

musicMapper

 	
    Music selectById(int musicId);

    
    int deleteById(int musicId);

collectMapper

    
    int deleteLoveMusicById(int musicId);
12.1.3 在 MusicMapper.xml 和 CollectMapper.xml 中添加代码

MusicMapper.xml

	
        select * from collect where userId = #{userId} and musicId = #{musicId};
    

	
        insert into collect(userId,musicId) values(#{userId},#{musicId});
    
13.3 向 CollectControll 中添加代码
  1. 通过用户Id 和 musicId查看是否存在歌曲
  2. 如果存在就返回收藏失败
  3. 如果不存在, 就根据用户id和musicId 添加收藏
@RequestMapping("/loveMusic")
public ResponseBodyMessage AddLoveMusic(@RequestParam String musicId, HttpServletRequest request) {
    int music_Id = Integer.parseInt(musicId);
    HttpSession session = request.getSession(false);
    User user = (User) session.getAttribute(Constant.USER_SESSION_KEY);
    int userId = user.getUserId();

    Collect collect = collectServer.findCollectMusic(userId,music_Id);
    if (collect != null) {
        return new ResponseBodyMessage<>(-1, "当前已经收藏了",false);
    }else{
        int ret = collectServer.insertLoveMusic(userId,music_Id);
        if(ret == 1) {
            return new ResponseBodyMessage<>(1, "收藏成功!",true);
        }else{
            return new ResponseBodyMessage<>(-1,"收藏失败",false);
        }
    }
}
13.4 前端代码
function collectMusic(musicId) {
          $.ajax({
            url: "collect/loveMusic",
            method: "post",
            data:{"musicId":musicId},
            dataType: "json",
            success:function(data,status){
              if(data.status == 1) {
                alert(data.message);
                location.assign("collect.html");
              }else{
                alert(data.message);
              }
            }
          })
}
13.5 测试代码

14. 取消收藏音乐模块 14.1 使用 Mybatis 操作数据库
  1. 根据userId 和 musicId 删除歌曲
14.1.1 在 CollectServer 中添加代码
    public int deleteLoveMusic(int userId,int musicId){
        return collectMapper.deleteLoveMusic(userId,musicId);
    }
14.1.2 在 CollectMapper 中添加代码
     
    int deleteLoveMusic(int userId,int musicId);
14.1.3 在 CollectMapper.xml 中添加代码
    
        delete from collect where userId = #{userId} and musicId = #{musicId}
    
14.2 向 CollectControll 中添加代码
  1. 这里登录之后去收藏页面,去删除歌曲.
  2. 通过 musicId 和 userId 去删除歌曲
    
    @RequestMapping("/deleteLoveMusic")
    public ResponseBodyMessage deleteLoveMusic(@RequestParam String musicId,HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        if(session == null) {
            return new ResponseBodyMessage<>(-1,"当前未登录",false);
        }
        User user = (User) session.getAttribute(Constant.USER_SESSION_KEY);
        int userId = user.getUserId();

        int ret =  collectServer.deleteLoveMusic(userId,Integer.parseInt(musicId));
        if(ret == 1) {
            return new ResponseBodyMessage<>(1,"取消收藏成功!",true);
        }else{
            return new ResponseBodyMessage<>(-1,"取消收藏失败!",false);
        }
    }
14.3 前端代码
		function deleteLoveMusic(musicId) {
          $.ajax({
            url: "collect/deleteLoveMusic",
            method: "post",
            data:{"musicId":musicId},
            dataType: "json",
            success:function(data,status) {
              if(data.status == 1) {
                alert(data.message);
                location.assign("collect.html");
              }else{
                alert(data.message);
              }
            }
          })
        }
14.4 测试代码

15. 主页面 - 查询模块 15.1 使用 Mybatis 操作数据库
  1. 这里有空查询和模糊查询两种数据库操作
  2. 空查询 不带 name
  3. 模糊查询带name
15.1.1 在 MusicServer 中添加代码
	public List findMusic() {
        return musicMapper.findMusic();
    }

    public List findMusicByName(String name) {
        return musicMapper.findMusicByName(name);
    }
15.1.2 在 MusicMapper 中添加代码
	
    List findMusic();

    
    List findMusicByName(String name);
15.1.3 在 MusicMapper.xml 中添加代码
    
        select * from music where title like concat('%',#{name},'%');
    
15.2 向 MusicController 中添加代码

这里判断前端传来的 name是否为空

  1. 不为空, 进入模糊查询
  2. 为空, 进入空查询
    
    @RequestMapping("/findMusic")
    public ResponseBodyMessage> findMusic(@RequestParam(required = false) String name) {
        List list = null;
        if(name != null) {
            list = musicServer.findMusicByName(name);
        }else {
            list = musicServer.findMusic();
        }
        return new ResponseBodyMessage<>(1,"查询完毕!",list);
    }
15.3 前端代码
	  $(function(){load()});

      function load(musicName) {
        $.ajax({
          url: 'music/findMusic',
          method: 'POST',
          data: {"name":musicName},
          dataType: "json",
          success: function(data,status) {
            if(data.data!=null){
              createMusic1(data.data);
            let audios = document.querySelectorAll('#player2');
            for(let audio of audios) {
              new MediaElementPlayer(audio, {
                            pluginPath: 'https://cdn.jsdelivr.net/npm/mediaelement@4.2.7/build/',
                            shimScriptAccess: 'always',
                            success: function () {
                              let play = document.querySelector('.player');
                              play.style = "visibility: visible;";
                            }
              });
            }
            }
          }
        })
      }

      function createMusic1(lists) {
        let s = '';
        for(let list of lists) {
            s+= '';
            s+= '';
            s+= '';
            s+= '';
            s+= '

'+list.title+''; s+= ''+list.author+'/'+DateFormat(list.uploadtime)+''; s+= ''; s+= ''; s+= ''; s+= ''; s+= ''; s+= ''; } $("#list23").html(s); } // 把毫秒级时间戳转化成格式化日期 function DateFormat(timeStampMS) { var date = new Date(timeStampMS); var year = date.getFullYear(), month = date.getMonth()+1,//月份是从0开始的 day = date.getDate(), hour = date.getHours(), min = date.getMinutes(), sec = date.getSeconds(); var newTime = year + '-' + (month < 10? '0' + month : month) + '-' + (day < 10? '0' + day : day) + ' ' + (hour < 10? '0' + hour : hour) + ':' + (min < 10? '0' + min : min) + ':' + (sec < 10? '0' + sec : sec); return newTime; } $(function(){ $("#submit1").click( function(){ var name = $("#exampleInputName2").val(); load(name); }); });

15.4 测试代码


16. 收藏页面 - 查询模块 16.1 使用 Mybatis 操作数据库
  1. 这里有空查询和模糊查询两种数据库操作
  2. 空查询 不带 name
  3. 模糊查询带name
16.1.1 在 CollectServer 中添加代码
    public List findLoveMusicByUserId(int userId){
        return collectMapper.findLoveMusicByUserId(userId);
    }

    public List findLoveMusicByNameAndUserId(String name,int userId){
        return collectMapper.findLoveMusicByNameAndUserId(name,userId);
    }
16.1.2 在 CollectMapper 中添加代码
    
    List findLoveMusicByUserId(int userId);

    
    List findLoveMusicByNameAndUserId(String name,int userId);
16.1.3 在 CollectMapper.xml 中添加代码
    
        select m.* from collect c,music m where m.musicId = c.musicId and c.userId = #{userId} and m.title like concat('%',#{name},'%');
    

16.2 向 CollectController 中添加代码

这里判断前端传来的 name是否为空

  1. 不为空, 进入模糊查询
  2. 为空, 进入空查询
@RequestMapping("findLoveMusic")
public ResponseBodyMessage> findLoveMusic(@RequestParam(required = false) String musicName,HttpServletRequest request) {
    HttpSession session = request.getSession(false);
    if(session == null) {
        return new ResponseBodyMessage<>(-1,"当前未登录",null);
    }
    User user = (User) session.getAttribute(Constant.USER_SESSION_KEY);
    int userId = user.getUserId();

    List list = null;
    if(musicName == null) {
        list = collectServer.findLoveMusicByUserId(userId);
    }else{
        list = collectServer.findLoveMusicByNameAndUserId(musicName,userId);
    }
    return new ResponseBodyMessage<>(1,"查询成功!",list);
}
16.3 前端代码
 $(function(){load()});


      function load(musicName) {
        $.ajax({
          url: 'collect/findLoveMusic',
          method: 'POST',
          data: {"musicName":musicName},
          dataType: "json",
          success: function(data,status) {
            if(data.data!=null){
              createMusic1(data.data);
            let audios = document.querySelectorAll('#player2');
            for(let audio of audios) {
              new MediaElementPlayer(audio, {
                            pluginPath: 'https://cdn.jsdelivr.net/npm/mediaelement@4.2.7/build/',
                            shimScriptAccess: 'always',
                            success: function () {
                              let play = document.querySelector('.player');
                              play.style = "visibility: visible;";
                            }
              });
            }
            }
          }
        })
      }

      $(function(){
        $("#submit1").click( function(){
            var name = $("#exampleInputName2").val();
            load(name);
        });
    });

    function createMusic1(lists) {
        let s = '';
        for(let list of lists) {
            s+= '';
            s+= '';
            s+= '';
            s+= '

'+list.title+''; s+= ''+list.author+'/'+DateFormat(list.uploadtime)+''; s+= ''; s+= ''; s+= ''; s+= ''; s+= ''; } $("#list23").html(s); } // 把毫秒级时间戳转化成格式化日期 function DateFormat(timeStampMS) { var date = new Date(timeStampMS); var year = date.getFullYear(), month = date.getMonth()+1,//月份是从0开始的 day = date.getDate(), hour = date.getHours(), min = date.getMinutes(), sec = date.getSeconds(); var newTime = year + '-' + (month < 10? '0' + month : month) + '-' + (day < 10? '0' + day : day) + ' ' + (hour < 10? '0' + hour : hour) + ':' + (min < 10? '0' + min : min) + ':' + (sec < 10? '0' + sec : sec); return newTime; }

16.4 测试代码

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1035146.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号