• 在线音乐播放项目——BY音乐


    目录:

    1、创建 springBoot 项目

    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

    2、设计数据库

    在 onlinemusic 数据库中创建三张表:user 表,music 表,lovemusic 表

    drop database if exists onlinemusic;
    create database if not exists onlinemusic character set utf8;
    use onlinemusic;
    
    drop table if exists user;
    create table user(id int primary key auto_increment, username varchar(20) not null, `password` varchar(255) not null);
    
    drop table if exists music;
    create table music(id int primary key auto_increment, title varchar(50) not null, singer varchar(30) not null, `time` varchar(13) not null, `url` varchar(1000) not null, userId int(11) not null);
    
    drop table if exists lovemusic;
    create table lovemusic(id int primary key auto_increment, user_id int(11) not null, music_id int(11) not null);
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    3、引入项目配置

    # 配置数据库
    spring:
      datasource:
        url: jdbc:mysql://127.0.0.1:3306/onlinemusic?characterEncoding=utf8&serverTimezone=UTC
        username: root;
        password: 1234
        driver-class-name: com.mysql.jdbc.Driver
      servlet: #上传文件的大小
        multipart:
          max-file-size: 15MB
          max-request-size: 100MB
    
    
    
    
    # 配置 xml 保存路径
    mybatis:
      mapper-locations: classpath:mybatis/**Mapper.xml
    
    # 日志调试模式开启
    debug: true
    
    # 日志打印级别 及打印 sql 语句 扫描的包是 frank 包和 druid.sql.Statement 包
    logging:
      level:
        root: INFO
        com:
          example: DEBUG
          musicserver:
            mapper: debug
    
        druid:
          sql:
            Statement: DEBUG
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    4、实现登录功能

    user登录功能的 model 层

    @Data
    public class User {
        private int id;
        private String username;
        private String password;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    user登录功能的 mapper 层,数据持久层

    @Mapper
    public interface UserMapper {
        public User login(User loginUser);
    }
    
    • 1
    • 2
    • 3
    • 4

    对应的 xml 文件:

    <?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.musicserver.mapper.UserMapper">
    
    </mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    实现功能:

    约定前后端交互接口:
    在这里插入图片描述
    实现基本登录的框架:(没有处理请求返回响应的过程)

    public interface UserMapper {
        User login(User loginUser);
    }
    
    • 1
    • 2
    • 3
    <select id="login" resultType="com.example.musicserver.model.User">
            select * from user where username = #{username} and password = #{password}
        select>
    
    • 1
    • 2
    • 3
    @RestController
    @RequestMapping("/user")
    public class UserController {
        @Resource
        private UserMapper userMapper;
    
        @RequestMapping("/login")
        public void login(@RequestParam String username, @RequestParam String password){
    
            User userLogin = new User();
            userLogin.setUsername(username);
            userLogin.setPassword(password);
    
            User user = userMapper.login(userLogin);
    
            if(user != null){
                System.out.println("登录成功");
            }else{
                System.out.println("登录失败");
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    封装响应:(使用一个类封装响应的信息)

    @Data
    public class ResponseBodyMessage<T>{
        private int status;//状态码
        private String message;//返回的信息【出错原因】
        private T data;//返回个前端的数据
    
        public ResponseBodyMessage(int status, String message, T data) {
            this.status = status;
            this.message = message;
            this.data = data;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    保存成功登录的 user 对象到 session 中:

    if(user == null){
                return new ResponseBodyMessage<>(-1,"登录失败",userLogin);
            }else{
                request.getSession().setAttribute(Constant.USERINFO_SESSION_KEY,user);
                return new ResponseBodyMessage<>(0,"登录成功",userLogin);
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    用一个类存储一个静态常量代表 session 中的 key ,避免 key 长度过长,发生拼写错误

    public class Constant {
        public static final String USERINFO_SESSION_KEY = "USERINFO_SESSION_KEY";
    }
    
    • 1
    • 2
    • 3

    对用户登录的密码进行加密:

    ①、MD5 加密

    MD5是一个安全的散列算法,输入两个不同的明文不会得到相同的输出值,根据输出值,不能得到原始的明文,即其过程不可逆; 但是虽然不可逆,但是不是说就是安全的。因为自从出现彩虹表后,这样的密码也"不安全"。

    不安全的原因:

    1. 暴力攻击速度很快
    2. 字典表很大
    3. 碰撞

    更安全的做法是加盐或者长密码等做法,让整个加密的字符串变的更长,破解时间变慢。密码学的应用安全,是建立在破解所要付出的成本远超出能得到的利益上的 。这里我们介绍加盐的做法:盐是在每个密码中加入一些单词来变成一个新的密码,存入数据库当中

    
    <dependency>
    <groupId>commons-codecgroupId>
    <artifactId>commons-codecartifactId>
    dependency>
    <dependency>
    <groupId>org.apache.commonsgroupId>
    <artifactId>commons-lang3artifactId>
    <version>3.9version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    /**
    * @Author GaoBo
    * @Description:
    */
    public class MD5Util {
    //定义一个固定的盐值
    private static final String salt = "1b2i3t4e";
    public static String md5(String src) {
    return DigestUtils.md5Hex(src);
    }
    /**
    * 第一次加密 :模拟前端自己加密,然后传到后端
    * @param inputPass
    * @return
    */
    public static String inputPassToFormPass(String inputPass) {
    String str = ""+salt.charAt(1)+salt.charAt(3) + inputPass
    +salt.charAt(5) + salt.charAt(6);
    return md5(str);
    }
    /**
    * 第2次MD5加密
    * @param formPass 前端加密过的密码,传给后端进行第2次加密
    * @param salt 用户数据库当中的盐值
    * @return
    */
    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);
    }
    /**
    * 上面两个函数合到一起进行调用
    * @param inputPass
    
    * @param saltDB
    * @return
    */
    public static String inputPassToDbPass(String inputPass, String saltDB) {
    String formPass = inputPassToFormPass(inputPass);
    String dbPass = formPassToDBPass(formPass, saltDB);
    return dbPass;
    }
    public static void main(String[] args) {
    System.out.println("对用户输入密码进行第1次加密:"+inputPassToFormPass("123456"));
    System.out.println("对用户输入密码进行第2次加密:"+formPassToDBPass(inputPassToFormPass("123456"),
    "1b2i3t4e"));
    System.out.println("对用户输入密码进行第2次加密:"+inputPassToDbPass("123456", "1b2i3t4e"));
    }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    不管运行多少次,这个密码是规定的。因为这里没有用随机盐值。当密码长度很大,盐值也是随机的情况下,密码的强度也加大了。破解成本也增加了。

    ②、Bcrypt加密数据

    Bcrypt就是一款加密工具,可以比较方便地实现数据的加密工作。你也可以简单理解为它内部自己实现了随机加盐处理 。我们使用MD5加密,每次加密后的密文其实都是一样的,这样就方便了MD5通过大数据的方式进行破解。Bcrypt生成的密文是60位的。而MD5的是32位的。Bcrypt破解难度更大。

    在 pom.xml 中添加 Bcrypt 依赖:

    <!-- security依赖包 (加密)-->
    <dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
    </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    springboot 启动类添加:

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

    总结:

    1. 密码学的应用安全,是建立在破解所要付出的成本远超出能得到的利益上的 。
    2. 使用BCrypt相比于MD5加密更好的一点在于,破解的难度上加大
    3. BCrypt的破解成本增加了,导致系统的运行成本也会大大的增加 。
    4. 回到本质的问题,你的数据库中的数据价值如何?如果你是银行类型的,那么使用BCrypt是不错的,一般情
      况使用MD5加盐,已经够用了。

    二者对比:

    BCrypt加密: 一种加盐的单向Hash,不可逆的加密算法,同一种明文(plaintext),每次加密后的密文都不一样,而且不可反向破解生成明文,破解难度很大。
    MD5加密: 是不加盐的单向Hash,不可逆的加密算法,同一个密码经过hash的时候生成的是同一个hash值,在大多数的情况下,有些经过md5加密的方法将会被破解。
    Bcrypt生成的密文是60位的。而MD5的是32位的。目前,MD5和BCrypt比较流行。相对来说,BCrypt比MD5更安全,但加密更慢。 虽然BCrpyt也是输入的字符串+盐,但是与MD5+盐的主要区别是:每次加的盐不同,导致每次生成的结果也不相同。无法比对!

    实现登录加密:

    提前在数据库中插入一条加密好的数据,然后使用 BCryptPasswordEncoder 中的 matchs 方法进行比对用户输入的密码和数据库中的密码是否匹配,匹配则显示登录成功

    boolean flg = bCryptPasswordEncoder.matches(password,user.getPassword());
                if(!flg){
                    return new ResponseBodyMessage<>(-1,"用户名或密码错误",user);
                }
                request.getSession().setAttribute(Constant.USERINFO_SESSION_KEY,user);
                return new ResponseBodyMessage<>(0,"登录成功",user);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    重新编写 sql 语句,只去数据库查询用户名,如果用户名一致,再通过 matchs 方法比较加密后的密码和当前输入密码是否一致来判断是否登录成功

    User selectByName(String username);
    
    • 1
    <select id="selectByName" resultType="com.example.musicserver.model.User">
            select * from user where username = #{username}
        select>
    
    • 1
    • 2
    • 3

    在这里插入图片描述
    在这里插入图片描述

    上传音乐接口和实体类设计

    在这里插入图片描述
    创建一个 music 实体类:

    @Data
    public class Music {
        private int id;
        private String title;
        private String singer;
        private String time;
        private String url;
        private int userId;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    实现 MusicController 类:

    ①、服务器的上传

    先检查用户是否登录,如果为登录提示未登录,登录后再进行后续的判断:

    HttpSession session = request.getSession(false);
    
            if(session == null || session.getAttribute(Constant.USERINFO_SESSION_KEY) == null){
                System.out.println("没有登录 !!! ");
                return new ResponseBodyMessage<>(-1,"请登录后上传",false);
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    先获取到文件的文件名 + 后缀名:

    //获取文件名 xx.mp3
            String fileNameAndType = file.getOriginalFilename();
    
            System.out.println("fileName:" + fileNameAndType);
    
    • 1
    • 2
    • 3
    • 4

    进行文件名的拼接:和保存路径拼接成完整的路径名:

    String path = SAVE_PATH + fileNameAndType;
    
    • 1

    去 new 这个文件:

    File dest = new File(path);
    
    • 1

    如果 dest 不存在,就创建一个文件夹,存储此路径的文件夹就使用其即可

    if(!dest.exists()){
                dest.mkdir();
            }
    
    • 1
    • 2
    • 3

    上传文件到目标位置:

    try {
                file.transferTo(dest);
                return new ResponseBodyMessage<>(0,"上传成功",true);
            } catch (IOException e) {
                e.printStackTrace();
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    如何判断上传的文件是 MP3 格式的

    检测你当前上传的文件是,判断这个文件是不是 MP3 文件,每个文件都有自己的组成格式,可以通过代码判断上传的音频文件中总共的 128 字节中,有3 字节有一个 TAG 标签

    ②、数据库的上传

    创建上传接口:

    @Mapper
    public interface MusicMapper {
        //插入音乐
        int insert(String title, String singer, String time, String url, int userId);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    实现 sql 语句:

    <insert id="insert">
            insert into music(title,singer,time,url,userId) values(#{title},#{singer},#{time},#{url},#{userId})
        insert>
    
    • 1
    • 2
    • 3

    得到各个属性:

    int index = fileNameAndType.lastIndexOf(".");
    String title = fileNameAndType.substring(0, index);
    User user = (User) session.getAttribute(Constant.USERINFO_SESSION_KEY);
    int userId = user.getId();
    String url = "/music/get?path=" + title;
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
    String time = simpleDateFormat.format(new Date());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    进行插入:

    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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    如果存在同名同歌手的情况下,不能进行插入:
    现在数据库中进行查询,同 singer 同 title 的歌曲有没有存在,如果存在就不进行插入:

    <select id="select" resultType="com.example.musicserver.model.Music">
            select * from music where title = #{title} and singer = #{singer}
        select>
    
    • 1
    • 2
    • 3
    Music music = musicMapper.select(title,singer);
    
            if(music != null){
                return new ResponseBodyMessage<>(-1, "已有同名同歌手的歌曲", false);
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    播放音乐模块设计

    约定前后端交互接口:

    在这里插入图片描述
    借助 ResponseEntity 类实现:返回音乐的字节信息,前端传来文件的 path(文件名 + 文件类型),返回字节给前端,前端再进行解析进行音乐的播放

    @RequestMapping("/get")
        public ResponseEntity<byte[]> func(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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述

    验证文件为音乐文件

    插入一个文本文件,可以发现是查找不到 TAG 标签的

    在这里插入图片描述

    在这里插入图片描述

    删除单个音乐:

    约定前后端交互接口:

    在这里插入图片描述
    先查询在数据库中有没有需要删除的歌曲 id:

    <select id="selectById" resultType="com.example.musicserver.model.Music">
            select * from music where id = #{id}
        select>
    
    • 1
    • 2
    • 3
    Music selectById(Integer id);
    
    • 1

    再进行删除逻辑:

    <delete id="deleteById">
            delete from music where id = #{id};
        </delete>
    
    • 1
    • 2
    • 3
    int deleteById(Integer id);
    
    • 1

    在 Controller 类里进行具体的实现:

     @RequestMapping("delete")
        public ResponseBodyMessage<Boolean> deleteMusicById(@RequestParam String id){
            int id1 = Integer.parseInt(id);
            Music music = musicMapper.selectById(id1);
            //检测要删除的 音乐 是否存在
            if(music == null){
                return new ResponseBodyMessage<>(-1,"没有此音乐,无法删除",false);
            }
    
            //进行数据库删除
            int ret = 0;
            ret = musicMapper.deleteById(id1);
    
            if(ret == 1){
                //数据库删除后 再进行服务器的删除
                File file = new File(SAVE_PATH + "/" + music.getTitle());
                if(file.delete()){
                    return new ResponseBodyMessage<>(0,"服务器删除成功",true);
                }else{
                    return new ResponseBodyMessage<>(0,"服务器删除失败",true);
                }
            }else{
                return new ResponseBodyMessage<>(-1,"删除失败",false);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    查询音乐:

    在这里插入图片描述

    两种查询,第一种默认没有参数是查询所有音乐,第二种是进行模糊查询,查询带关键字的歌曲:

    	List<Music> findMusic();
        List<Music> findMusicByName(String name);
    
    • 1
    • 2
    <select id="findMusic" resultType="com.example.musicserver.model.Music">
            select * from music;
        select>
        <select id="findMusicByName" resultType="com.example.musicserver.model.Music">
            select * from music where title like concat('%',#{name},'%')
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在 controller 中进行实现:

    @RequestMapping("findmusic")
        public ResponseBodyMessage<List<Music>> findMusic(@RequestParam(required = false) String name){
            List<Music> music = null;
            if(name == null){
                music = musicMapper.findMusic();
            }else {
                music = musicMapper.findMusicByName(name);
            }
    
            return new ResponseBodyMessage<>(0,"查找成功",music);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    收藏音乐:

    三个接口:查询收藏音乐是否在表中,如果在进行收藏删除操作,如果不在进行收藏插入操作:

    Music findLoveMusicByMusicIdAndUserId(int userId, int musicId);
        boolean insertLoveMusic(int userId, int musicId);
        boolean deleteLoveMusic(int userId, int musicId);
    
    • 1
    • 2
    • 3

    实现:

    
    DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.example.musicserver.mapper.LoveMusicMapper">
        <insert id="insertLoveMusic">
            insert into lovemusic (user_id,music_id) values(#{userId},#{musicId})
        insert>
        <delete id="deleteLoveMusic">
            delete from lovemusic where music_id = #{musicId} and user_id = #{userId}
        delete>
    
        <select id="findLoveMusicByMusicIdAndUserId" resultType="com.example.musicserver.model.Music">
            select * from lovemusic where music_id = #{musicId} and user_id = #{userId}
        select>
    mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在 controller 类中进行实现:

    package com.example.musicserver.controller;
    
    import com.example.musicserver.mapper.LoveMusicMapper;
    import com.example.musicserver.model.Music;
    import com.example.musicserver.model.User;
    import com.example.musicserver.tools.Constant;
    import com.example.musicserver.tools.ResponseBodyMessage;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.annotation.Resource;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpSession;
    
    /**
     * Created with IntelliJ IDEA.
     * Description:
     * User: Lenovo
     * Date: 2022-07-28
     * Time: 15:01
     */
    @RestController
    @RequestMapping("lovemusic")
    public class LoveMusicController {
        @Resource
        private LoveMusicMapper loveMusicMapper;
    
        @RequestMapping("likemusic")
        public ResponseBodyMessage<Boolean> insertLoveMusic(@RequestParam String id, HttpServletRequest request){
            int musicId = Integer.parseInt(id);
    
            HttpSession session = request.getSession(false);
            if(session == null || session.getAttribute(Constant.USERINFO_SESSION_KEY) == null){
                return new ResponseBodyMessage<>(-1,"当前尚未登录",false);
            }
            User user = (User) session.getAttribute(Constant.USERINFO_SESSION_KEY);
            int userId = user.getId();
    
            Music music = loveMusicMapper.findLoveMusicByMusicIdAndUserId(userId,musicId);
    
            if(music != null){
                boolean flg = loveMusicMapper.deleteLoveMusic(userId,musicId);
                if(flg){
                    return new ResponseBodyMessage<>(1,"取消收藏成功",true);
                }else{
                    return new ResponseBodyMessage<>(-1,"取消收藏失败",false);
                }
            }else{
                boolean ret = loveMusicMapper.insertLoveMusic(userId,musicId);
    
                if(!ret){
                    return new ResponseBodyMessage<>(-1,"当前歌曲收藏失败",false);
                }else{
                    return new ResponseBodyMessage<>(1,"当前歌曲成功收藏",true);
                }
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    postman 验证:

    在这里插入图片描述

    查询收藏的音乐:

    两种查询一种是查询一个用户的所有收藏音乐,第二种是根据歌曲关键字或者全名进行查询(支持模糊查询),需要 music 表和 lovemusic 表进行联合查询

    List<Music> findLoveMusicByName(String musicName, int id);
    List<Music> findLoveMusic(int id);
    
    • 1
    • 2

    xml 实现:

    <select id="findLoveMusicByName" resultType="com.example.musicserver.model.Music">
            select m.* from lovemusic lm,music m where m.id = lm.music_id and lm.user_id = #{id} and title like concat('%',#{musicName},'%')
        </select>
        <select id="findLoveMusic" resultType="com.example.musicserver.model.Music">
            select m.* from lovemusic lm,music m where m.id = lm.music_id and lm.user_id = #{id}
        </select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    具体 Controller 实现:

    @RequestMapping("findLoveMusic")
        public ResponseBodyMessage<List<Music>> findLoveMusic(@RequestParam(required = false) String musicName, HttpServletRequest request){
            HttpSession session = request.getSession(false);
    
            if(session == null || session.getAttribute(Constant.USERINFO_SESSION_KEY) == null){
                return new ResponseBodyMessage<>(-1,"当前用户尚未登录",null);
            }
    
            User user = (User) session.getAttribute(Constant.USERINFO_SESSION_KEY);
            int id = user.getId();
    
            List<Music> music = null;
    
            if(musicName == null){
                music = loveMusicMapper.findLoveMusic(id);
            }else{
                music = loveMusicMapper.findLoveMusicByName(musicName,id);
            }
    
            return new ResponseBodyMessage<>(1,"查询成功",music);
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    删除收藏音乐

  • 相关阅读:
    关于原型交互设计文档的一些建议
    Python自动生成小学生口算试卷源代码,可设置各算数项和取值范围、可以生成求结果、求算数项、带括号的算式
    大家一起来学习如何使用spring.factories
    参与开源之夏 x OpenTiny 跨端跨框架 UI 组件库贡献,可以赢取奖金🏆!这份《OpenTiny 开源贡献指南》请收好🎁!
    idea 插件推荐(持续更新)
    基于大规模MIMO通信系统的半盲信道估计算法matlab性能仿真
    Win11怎么设置用独立显卡来运行游戏
    《微服务实战》 第二十章 Redis连接指令 客户端指令 服务器指令
    iOS打包 rebuild from bitcode对ipa大小的影响
    Python中主要数据结构的使用
  • 原文地址:https://blog.csdn.net/baiyang2001/article/details/125936231