• 基于 SpringBoot + Mybatis 的个人在线音乐平台


    1. 核心功能

    用到的技术:
    前端 : HTML + CSS + JavaScript + JQuery
    后端 : Spring Boot + MyBatis

    在这里插入图片描述

    2. 演示效果

    在这里插入图片描述

    在这里插入图片描述

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

    源码地址:https://gitee.com/big-white-rice/online-music-platform

    3. 创建项目

    我使用的 IDEA 工具
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    4. 数据库设计

    我使用的 MySQL 5.5

    在这里插入图片描述

    -- 数据库
    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
    );
    
    INSERT INTO user(username,password)
    VALUES("cm","$2a$10$Bs4wNEkledVlGZa6wSfX7eCSD7wRMO0eUwkJH0WyhXzKQJrnk85li");
    
    
    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
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    5. 配置数据库和xml

    application.properties 中,常用的可以保存在一个地方,方便下次直接粘贴

    #配置数据库
    spring.datasource.url=jdbc:mysql://localhost:3306/onlinemusic?characterEncoding=utf8&serverTimezone=UTC
    spring.datasource.username=root
    spring.datasource.password=root
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    
    #启动端口
    server.port=8082
    
    #配置xml
    mybatis.mapper-locations=classpath:mybatis/**Mapper.xml
    
    #配置springboot上传文件的大小,默认每个文件的配置最大为15Mb,单次请求的文件的总数不能大于100Mb
    spring.servlet.multipart.max-file-size = 15MB
    spring.servlet.multipart.max-request-size=100MB
    
    #音乐上传后的路径
    music.local.path=D:/Java/Music/
    
    #music.local.path=/root/music/
    
    
    # 配置springboot日志调试模式是否开启
    debug=true
    
    # 设置打印日志的级别,及打印sql语句
    #日志级别:trace,debug,info,warn,error
    #基本日志
    logging.level.root=INFO
    logging.level.com.example.onlinemusic.mapper=debug
    
    #扫描的包:druid.sql.Statement类和frank包
    logging.level.druid.sql.Statement=DEBUG
    logging.level.com.example=DEBUG
    #package com.example.onlinemusic.model;
    #import lombok.Data;
    
    
    • 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

    mybatis xml 文件,保留备用

    
    DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.example.onlinemusic.mapper.UserMapper">
    
       
    mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    6. 统一配置类

    6.1 设置统一响应类

    统一让响应的返回格式一样

    import lombok.Data;
    
    @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
    • 13
    • 14
    • 15
    • 16

    6.2 Constant 类

    存储不变的常量,方便我们后续使用(如 session)

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

    6.3 登录加密(了解)

    6.3.1 MD5 加密

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

    彩虹表:彩虹表就是一个庞大的、针对各种可能的字母组合预先计算好的哈希值的集合,不一定是针对MD5算法的,各种算法的都有,有了它可以快速的破解各类密码。越是复杂的密码,需要的彩虹表就越大,现在主流的彩虹表都是100G以上。

    不安全的原因:

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

    参考链接:https://md5.cc/news1.aspx
    更安全的做法是加盐或者长密码等做法,让整个加密的字符串变的更长,破解时间变慢。密码学的应用安全,是建立在破解所要付出的成本远超出能得到的利益上的 。

    盐是在每个密码中加入一些单词来变成一个新的密码,存入数据库当中

    添加依赖:

    
            <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

    测试类:

    import org.apache.commons.codec.digest.DigestUtils;
    
    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

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

    6.3.2 BCrypt 加密

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

    添加依赖:

    
            <dependency>
                <groupId>org.springframework.securitygroupId>
                <artifactId>spring-security-webartifactId>
            dependency>
            <dependency>
                <groupId>org.springframework.securitygroupId>
                <artifactId>spring-security-configartifactId>
            dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在 SpringBoot 启动了添加:

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

    测试类:

    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    
    /**
     * Created with IntelliJ IDEA.
     * Description:
     * User: cm
     * Date: 2022-07-26
     * Time: 23:06
     */
    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);
    
        }
    }
    
    
    • 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

    在这里插入图片描述

    encode方法:对用户密码进行加密
    matches方法:参数一,待检验的未加密的密码 。参数二:从数据库中查询出的加密后密码 。

    6.3.3 总结

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

    参考链接:https://blog.csdn.net/muyimo/article/details/118811514

    BCrypt加密: 一种加盐的单向Hash,不可逆的加密算法,同一种明文(plaintext),每次加密后的密文都不一样,而且不可反向破解生成明文,破解难度很大。
    MD5加密: 是不加盐的单向Hash,不可逆的加密算法,同一个密码经过hash的时候生成的是同一个hash值,在大多数的情况下,有些经过md5加密的方法将会被破解。

    Bcrypt生成的密文是60位的。而MD5的是32位的。

    目前,MD5和BCrypt比较流行。相对来说,BCrypt比MD5更安全,但加密更慢。 虽然BCrpyt也是输入的字符串+盐,但是与MD5+盐的主要区别是:每次加的盐不同,导致每次生成的结果也不相同。无法比对!

    6.4 注入 BCryptPasswordEncoder 对象

    新建 AppConfig 类

    @Configuration
    public class AppConfig implements WebMvcConfigurer {
    
        @Bean
        public BCryptPasswordEncoder getBCryptPasswordEncoder() {
            return new BCryptPasswordEncoder();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    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.USERINFO_SESSION_KEY)!=null) {
                    //此时是登录状态
                return true;
            }
            return false;
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    6.5.2 addInterceptors 方法

    在 AppConfig 类中

     /**
         * 添加拦截器,将自定义拦截器加入到系统配置
         * @param registry
         */
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            //1、配置拦截规则
            LoginInterceptor loginInterceptor = new LoginInterceptor();
            registry.addInterceptor(loginInterceptor)
                    .addPathPatterns("/**")
            //排除所有的JS
                    .excludePathPatterns("/js/**.js")
            //排除img下所有的元素
                    .excludePathPatterns("/img/**")
                    .excludePathPatterns("/css/**.css")
                    .excludePathPatterns("/fronts/**")
                    .excludePathPatterns("/player/**")
                    .excludePathPatterns("/login.html")
                    .excludePathPatterns("/reg.html")
            //排除登录注册接口
                    .excludePathPatterns("/user/login")
                    .excludePathPatterns("/user/reg");
    
    
        }
    
    • 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

    7. 登录实现

    7.1 设计登录的请求和响应

    请求
    POST /user/login 
    
    {username: "",password: ""}
    
    响应
    {
    	status: 0/-1,
    	message: "",
    	data: ""
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    响应体设计字段解释:
    {
    status:状态码,为0代表成功,负数代表失败
    message:状态描述信息,描述此次请求成功或者失败的原因
    data:返回的数据,请求成功后,需要给前端的数据信息
    }

    7.2 创建 User 类

    我们这里登录需要进行数据库的 用户查询,根据用户名判断是否存在当前用户
    注: 注解都不要忘记给加上

    创建 model 包,底下创建 User 类

    import lombok.Data;
    
    @Data
    public class User {
        private Integer id;
        private String username;
        private String password;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    7.3 创建 Mapper

    新建 mapper 包,新建 UserMapper

    import com.example.onlinemusic.model.User;
    import org.apache.ibatis.annotations.Mapper;
    
    @Mapper
    public interface UserMapper {
         /**
         * 根据名字查询用户
         * @param username
         * @return
         */
        User selectByName(String username);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    7.4 创建 UserMapper.xml

    创建 mabatis 包,添加 xml 代码

    
    DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.example.onlinemusic.mapper.UserMapper">
    
        
        <select id="selectByName" resultType="com.example.onlinemusic.model.User">
            select * from user where username=#{username}
        select>
    mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    7.5 创建 Service

    @Service
    public class UserService {
    @Autowired
        private UserMapper userMapper;
    
        public User selectByName(String username){
            return userMapper.selectByName(username);
        }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    7.6 创建 Controller

    @RestController
    @RequestMapping("/user")
    public class UserController {
    
        //注入
        @Autowired
        private UserService userService;
    
        @Resource//在自动装配之前,需要完成注入,我们再AppConfig中进行注入
        private BCryptPasswordEncoder bCryptPasswordEncoder;
     @RequestMapping("/login")
        public ResponseBodyMessage<User> login(@RequestParam String username, @RequestParam String password,
                                               HttpServletRequest request){
            
            // 查询用户是否在数据库中存在
            User user = userService.selectByName(username);
    
            // 没有查到
            if(user == null) {
                System.out.println("登录失败!");
                return new ResponseBodyMessage<>(-1,"用户名或者密码错误",user);
            }else {
                
                //查到了,但密码不一样
                if(!bCryptPasswordEncoder.matches(password,user.getPassword())) {
                    return new ResponseBodyMessage<>(-1,"用户名或者密码错误",user);
                }
                // 匹配成功,创建 session
                request.getSession().setAttribute(Constant.USERINFO_SESSION_KEY,user);
                return new ResponseBodyMessage<>(0,"登录成功",user);
            }
        }
        }
    
    • 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

    7.7 测试

    我用的是 postman 进行测试

    在这里插入图片描述

    7.8 前端代码

    在这里插入图片描述

    <script>
    	<!-- 核心业务逻辑 -->
    	$(function (){
    		$("#submit1").click(function (){
    			var username = $("#username").val();
    			var password = $("#password").val();
    			console.log(username);
    			console.log(password);
    
    			if(username.trim() == "" || password.trim() == ""){
    				alert("用户名或密码不能为空!");
    				return;
    			}
    			//执行异步HTTP(Ajax)请求
    			$.ajax({
    				url:"/user/login",
    				data:{"username":username,"password":password},
    				type:"POST",
    				dataType:"json",
    				success:function (data){
    					console.log(data);
    					if(data.status == 0){
    						alert("登录成功!");
    						window.location.href="list.html";
    					}else{
    						alert("登录失败,账号或者密码错误,请重新输入!");
    						$("#message").text("账号或者密码错误,请重新输入!");
    						$("#username").val("");
    						$("#password").val("");
    					}
    				}
    			});
    		});
    	});
    
    script>
    
    • 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

    8. 注册实现

    8.1 请求响应设计

    请求
    POST /user/reg
    
    {username: "",password: ""}
    
    响应
    {
    	status: 0/-1,
    	message: "",
    	data: ""
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    主要就是需要注意用户存在就不能进行注册

    8.2 UserMapper 层

    @Mapper
    public interface UserMapper {
       
        /**
         * 新增用户
         * @param user 
         * @return
         */
        int addUser(User user);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    8.3 UserMapper.xml 层

    
        <insert id="addUser">
            insert into user(username,password) values (#{username},#{password});
        insert>
    
    • 1
    • 2
    • 3
    • 4

    8.4 UserService 层

    public int addUser(User user){
            return userMapper.addUser(user);
        }
    
    • 1
    • 2
    • 3

    8.5 UserController 层

    @RequestMapping("/reg")
        public ResponseBodyMessage<Boolean> reg(@RequestParam String username, @RequestParam String password) {
           User user1 = userService.selectByName(username);
           if(user1 != null){
               return new ResponseBodyMessage<>(-1,"当前用户已存在!",false);
           }else{
               User user2 = new User();
               user2.setUsername(username);
               String password1 = bCryptPasswordEncoder.encode(password);
               user2.setPassword(password1);
               userService.addUser(user2);
               return new ResponseBodyMessage<>(0,"注册成功!",true);
           }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    8.6 测试

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

    8.7 前端代码

    在这里插入图片描述

    <script>
        // 注册的数据提交 AJAX
        function mySubmit(){
            // 1.对输入的内容进行非空和正确性效验
            var username = jQuery("#username");
            var password = jQuery("#password");
            var password2 = jQuery("#password2");
            if(jQuery.trim(username.val())==""){
                alert("抱歉:请先输入用户名!");
                username.focus();
                return;
            }
            if(jQuery.trim(password.val())==""){
                alert("抱歉:请先输入密码!");
                password.focus();
                return;
            }
            if(jQuery.trim(password2.val())==""){
                alert("抱歉:请先输入确认密码!");
                password2.focus();
                return;
            }
            // 密码强度效验(密码的长度必须大于 8)【扩展,密码组合强度效验】
            if(password.val().length<8){
                alert("抱歉:密码强度太低,密码位数必须大于等于8位!");
                password.focus();
                return;
            }
            if(password.val()!=password2.val()){
                alert("抱歉:两次输入的密码不一致,请检查!");
                password.focus();
                return;
            }
            // 2.发送 ajax 请求到后端
            jQuery.ajax({
                url:"user/reg",
                type:"POST",
                data:{
                    "username":username.val(),
                    "password":password.val()
                },
                dataTye:"json",
                success:function(data){
                    if(data.status == 0){
                        alert("注册成功!");
                        window.location.href="login.html";
                    }else{
                        alert("注册失败,当前用户已经存在!");
                        username.value="";
                        password.value="";
                        password2.value="";
                        username.focus();
                    }
                }
            });
        }
    
    script>
    
    • 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

    9. 上传音乐

    9.1 请求响应设计

    请求:
    {
    post,
    /music/upload
    {singer,MultipartFile file}} 
    
    响应:
    {
    "status": 0,
    "message": "上传成功!",
    "data": true
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    9.2 新建 Music 类

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

    9.3 MusicService 层

    我们上传音乐需要注意的就是是否重复上传,我们这里是根据同一首歌是否是同一个歌手来判断的

    @Service
    public class MusicService {
    
        @Autowired
        private MusicMapper musicMapper;
    
        public int insert(String title,String singer,String time,String url,Integer userid){
            return musicMapper.insert(title,singer,time,url,userid);
        }
    
        public List<Music> selectByTitle(String title) {
            return musicMapper.selectByTitle(title);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    9.4 MusicMapper 层

    @Mapper
    public interface MusicMapper {
    
        /**
         * 插入音乐
         * @param title 音乐名
         * @param singer 歌手名
         * @param time 上传时间
         * @param url 对应地址
         * @param userid 上传的用户 id
         * @return 返回受影响的行数
         */
        public int insert(String title,String singer,String time,String url,Integer userid);
    
        /**
         * 通过音乐名去查找歌曲.
         * @param title 音乐名
         * @return 对应音乐名的所有歌曲
         */
        List<Music> selectByTitle(String title);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    9.5 MusicMapper.xml 层

    
    DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.example.onlinemusic.mapper.MusicMapper">
    
        
        <insert id="insert">
            insert into music(title,singer,time,url,userid)
            value(#{title},#{singer},#{time},#{url},#{userid})
        insert>
    
        
        <select id="selectByTitle" resultType="com.example.onlinemusic.model.Music">
            select * from music where title = #{title}
        select>
    mapper>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    9.6 MusicController 层

    @RestController
    @RequestMapping("/music")
    public class MusicController {
    
        @Resource
        private LoveMusicService loveMusicService;
    
        @Resource
        private MusicService musicService;
    
        @Value("${music.local.path}")
        private String SAVE_PATH;
    
        @RequestMapping("/upload")
        public ResponseBodyMessage<Boolean> insertMusic1(@RequestParam String singer,@RequestParam("filename") MultipartFile file,
                                                         HttpServletRequest request,HttpServletResponse response){
    
            //1. 检查是否登录了
            HttpSession session = request.getSession(false);
            if (session == null || session.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 title = fileNameAndType.substring(0,fileNameAndType.lastIndexOf('.'));
            List<Music> list = musicService.selectByTitle(title);
            if(list != null){
                for (Music music : list) {
                    if(music.getSinger().equals(singer)){
                        return new ResponseBodyMessage<>(-1,"当前歌手歌曲已经存在!",false);
                    }
                }
            }
    
            // 创建文件
            String path = SAVE_PATH+fileNameAndType;
    
            File dest = new File(path);
    
            if(!dest.exists()){
                dest.mkdir();
            }
    
            try {
                file.transferTo(dest);
            } catch (IOException e) {
                e.printStackTrace();
                return new ResponseBodyMessage<>(-1,"服务器上传失败!",false);
            }
    
            // 判断是不是 MP3 文件(TAG)
            File file1 = new File(path);
            byte[] result = null;
            try {
                result = Files.readAllBytes(file1.toPath());
                if(result == null){
                    return new ResponseBodyMessage<>(-1,"当前文件不存在!",false);
                }
                String str = new String(result);
                if(!str.contains("TAG")){
                    file1.delete();
                    return new ResponseBodyMessage<>(-1,"当前上传的不是 MP3 文件!",false);
                }
            } catch (IOException e) {
                e.printStackTrace();
                return new ResponseBodyMessage<>(-1,"服务器上传失败2!",false);
            }
    
            // 进行数据库上传
            // 1. 准备数据 //2. 调用 insert
    //        int index = fileNameAndType.lastIndexOf(".");//最后一个点前面就是名字
    //        String title1 = fileNameAndType.substring(0,index);
    
            User user = (User)session.getAttribute(Constant.USERINFO_SESSION_KEY);
            int userid = user.getId();
    
            //1. 播放音乐 -> http 请求
            String url = "/music/get?path="+title;
    
            SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
            String time = sf.format(new Date());
    
            try {
                int ret = 0;
                ret = musicService.insert(title, singer, time, url, userid);
                if (ret == 1) {
                    //应该跳转到音乐列表页面
                    try {
                        response.sendRedirect("/list.html");
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    return new ResponseBodyMessage<>(0, "数据库上传成功", true);
                } else {
                    return new ResponseBodyMessage<>(-1, "数据库上传失败", false);
                }
            } catch (BindingException e) {
                dest.delete();
                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
    • 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
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108

    9.7 测试

    在这里插入图片描述

    9.8 前端代码

    在这里插入图片描述

    10. 播放音乐

    10.1 请求响应设计

    请求:
    {
    get,
    /music/get?path=xxx.mp3
    } 
    
    响应:
    {
    音乐数据本身的字节信息
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    10.2 MusicController 层

    /**
         * 播放音乐的时候,/music/get?path=xxx.mp3
         *
         * @param path
         * @return
         */
        @RequestMapping("/get")
        public ResponseEntity<byte[]> get(String path) {
            File file = new File(SAVE_PATH + "/" + path);
    
            byte[] a = new byte[0];
            try {
                a = Files.readAllBytes(file.toPath());
                if (a.length == 0) {
                    return ResponseEntity.badRequest().build();
                }
                return ResponseEntity.ok(a);
            } catch (IOException e) {
                e.printStackTrace();
            }
            //return ResponseEntity.internalServerError().build();
    //        return ResponseEntity.notFound().build();
    //        return ResponseEntity.ok(a);
            return ResponseEntity.badRequest().build();
        }
    
    • 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

    10.3 测试

    在这里插入图片描述
    有这个 TAG 就能判断是不是歌曲了

    10.4 前端代码

     //播放
            function playerSong(obj) {
                console.log(obj)
                var name = obj.substring(obj.lastIndexOf('=')+1);
    //obj:播放地址 name: 名字 0: 开始时间 true: 自动播放
                SewisePlayer.toPlay(obj,name,0,true);
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    <script type="text/javascript" src="player/sewise.player.min.js">script>
        <script type="text/javascript">
            SewisePlayer.setup({
                server: "vod",
                type: "mp3",
    //这里是默认的一个网址
                videourl:"http://jackzhang1204.github.io/materials/where_did_time_go.mp3",
                skin: "vodWhite",
    //这里需要设置false
                autostart:"false",
            });
        script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    11. 删除音乐

    11.1 删除单个音乐

    11.1.1 请求响应设计

    请求:
    {
    post,
    /music/delete,
    id
    } 
    
    响应:
    {
    "status": 0,
    "message": "删除成功!",
    "data": true
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    11.1.2 MusicService 层

    public int deleteById(int musicId) {
            return musicMapper.deleteById(musicId);
        }
    
    • 1
    • 2
    • 3

    11.1.3 MusicMapper 层

    /**
         * 删除对应音乐Id的歌曲
         * @param musicId 音乐Id
         * @return 返回影响行数
         */
        int deleteById(int musicId);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    11.1.4 MusicMapper.xml 层

     
        <delete id="deleteById" parameterType="java.lang.Integer">
    delete from music where id = #{id}
        delete>
    
    • 1
    • 2
    • 3
    • 4

    11.1.5 MusicController 层

    /**
         * 删除单个音乐
         *
         * @param id
         * @return
         */
        @RequestMapping("/delete")
        public ResponseBodyMessage<Boolean> deleteMusicById(@RequestParam String id) {
            //1. 先检查这个音乐是否存在
            int iid = Integer.parseInt(id);
            //2. 如果存在要进行删除
            Music music = musicService.findMusicById(iid);
            if (music == null) {
                System.out.println("没有这个 id 的音乐");
                return new ResponseBodyMessage<>(-1, "没有你要删除的音乐", false);
            } else {
                //2.1 删除数据库
                int ret = musicService.deleteById(iid);
                if (ret == 1) {
                    //2.2删除服务器上的数据
                    int index = music.getUrl().lastIndexOf("=");
                    String fileName = music.getUrl().substring(index + 1);
    
                    File file = new File(SAVE_PATH + "/" + fileName + ".mp3");
                    System.out.println("当前的路径: " + file.getPath());
                    if (file.delete()) {
                        //需要同步删除lovemusic表当中的音乐
                        loveMusicService.deleteLoveMusicByMusicId(iid);
    
                        return new ResponseBodyMessage<>(0, "服务器当中的音乐删除成功!", true);
                    } else {
                        return new ResponseBodyMessage<>(-1, "服务器当中的音乐删除失败!", false);
                    }
                } 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
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    11.1.6 测试

    在这里插入图片描述

    11.1.7 前端代码

     //删除
            function deleteInfo(obj){
                console.log(obj);
                $.ajax({
                    url:"/music/delete",
                    type:"POST",
                    data:{"id":obj},
                    dataType: "json",
                    success: function (obj){
                        console.log(obj);
                        if(obj.data===true){
                            alert("删除成功!");
                            window.location.href="list.html";
                        }else{
                            alert("删除失败!");
                        }
                    }
                });
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    11.2 批量删除选中音乐

    11.2.1 请求响应设计

    请求:
    {
    post,
    /music/deletesel,
    data:{"id":id}
    } 
    
    响应:
    {
    "status": 0,
    "message": "批量删除成功",
    "data": true
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    11.2.2 MusicController 层

    /**
         * 批量进行音乐删除
         *
         * @param id
         * @return
         */
        @RequestMapping("/deletesel")
        public ResponseBodyMessage<Boolean> deleteSelMusic(@RequestParam("id[]") List<Integer> id) {
            System.out.println("所有的ID: "+id);
            int sum = 0;
            for (int i = 0; i < id.size(); i++) {
                int musicId = id.get(i);
                Music music = musicService.findMusicById(musicId);
                if (music == null) {
                    System.out.println("没有这个 id 的音乐");
                    return new ResponseBodyMessage<>(-1, "没有你要删除的音乐", false);
    
                }
                int ret = musicService.deleteById(musicId);
                if (ret == 1) {
                    int index = music.getUrl().lastIndexOf("=");
                    String fileName = music.getUrl().substring(index + 1);
    
                    File file = new File(SAVE_PATH + "/" + fileName + ".mp3");
                    if (file.delete()) {
                        //需要同步删除lovemusic表当中的音乐
                        loveMusicService.deleteLoveMusicByMusicId(musicId);
                        sum += ret;
    //            return new ResponseBodyMessage<>(0,"服务器当中的音乐删除成功!",true);
                    } else {
                        return new ResponseBodyMessage<>(-1, "服务器当中的音乐删除失败!", false);
                    }
                }else {
                    return new ResponseBodyMessage<>(0,"数据库当中音乐删除失败!",true);
                }
            }
            if(sum == id.size()){
                System.out.println("整体删除成功");
                return new ResponseBodyMessage<>(0,"音乐删除成功!",true);
            }else {
                System.out.println("整体删除失败");
                return new ResponseBodyMessage<>(0,"音乐删除失败!",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

    11.2.3 测试

    在这里插入图片描述

    11.2.4 前端代码

     $(function (){
                //新增函数
                $("#submit1").click(function () {
    //获取exampleInputName2当中的值给name
                    var name = $("#exampleInputName2").val();
                    load(name);
                });
    //当load这个函数执行成功,则执行done当中的回调函数
                $.when(load).done(function () {
    //选取所有类型为CheckBox的元素
                    $("#delete").click(function () {
                        var i=0;
                        var id=new Array();
    //遍历checkbox
                        $("input:checkbox").each(function() {
    //如果被选中,this代表发生事件的dom元素,<input>
                            if($(this).is(':checked')){
    //获取id的值,存储到id数组当中
                                id[i] = $(this).attr("id");
                                i++;
                            }
                        });
                        console.log(id);
    //发送ajax请求
                        $.ajax({
                            url:"/music/deletesel",
    //将id数组,发送给deleteSelectedServlet
                            data:{"id":id},
                            type: "POST",
                            dataType:"json",
                            success:function (data) {
                                if(data.data===true){
                                    alert("删除成功");
                                    window.location.href="list.html";
                                }else{
                                    alert("删除失败");
                                }
                            }
                        });
                    });
                });
            });
        script>
    
    • 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

    12. 查询音乐

    12.1 请求响应设计

    有两种:模糊查询和空查询

    请求:
    {
    get,
    /music/findmusic,
    data:{musicName:musicName},
    } 
    
    响应:【不给musicName传参】
    {
    "status": 0/-1,
    "message": "",
    "data": ""
    } 
    
    响应:【给musicName传参】
    {
    "status": 0/-1,
    "message": "",
    "data": ""
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    12.2 MusicService 层

    public List<Music> findMusic(){
            return musicMapper.findMusic();
        }
    
        public List<Music> findMusicByName(String musicName){
            return musicMapper.findMusicByName(musicName);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    12.3 MusicMapper 层

    /**
         * 查询所有的音乐
         * @return
         */
        List<Music> findMusic();
    
        /**
         * 查询匹配音乐
         * @param musicName
         * @return
         */
        List<Music> findMusicByName(String musicName);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    12.4 MusicMapper.xml 层

    
        <select id="findMusic" resultType="com.example.onlinemusic.model.Music">
    select * from music
        select>
    
        
        <select id="findMusicByName" resultType="com.example.onlinemusic.model.Music">
            select * from music where title like concat('%',#{musicName},'%')
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    12.5 MusicController 层

    @RequestMapping("/findmusic")//(required=false)可以不传入参数
        public ResponseBodyMessage<List<Music>> findMusic(@RequestParam(required = false) String musicName){
            List<Music> musicList = null;
            if(musicName != null){
                musicList = musicService.findMusicByName(musicName);
            }else {
                musicList = musicService.findMusic();
            }
    
            return new ResponseBodyMessage<>(0,"查询到了所有的音乐",musicList);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    12.6 测试

    在这里插入图片描述

    在这里插入图片描述

    12.7 前端代码

    <script type="text/javascript">
            
    		$(function (){
    		    load();
            });
    
            // musicName 可以传参,也可以不传参
            function load(musicName){
                $.ajax({
                    url: "/music/findmusic",
                    data:{musicName:musicName},
                    type: "GET",
                    dataType:"json",
                    success:function (obj){
                        console.log(obj);
                        var data=obj.data;
                        console.log(data.length);
                        var s = '';
                        for(var i = 0;i < data.length;i++){
                            var musicUrl = data[i].url+".mp3";
                            s += '<tr>';
                            s += '<th> <input id="'+data[i].id+'"type="checkbox"> th>';
                            s += '<td>' + data[i].title + 'td>';
                            s += '<td>' + data[i].singer + 'td>';
                            s+='<td > <button class="btn btn-primary" onclick="playerSong(\''+musicUrl+'\')" >播放歌曲button>' +
                                'td>';
                            s+='<td > <button class="btn btn-primary" onclick="deleteInfo('+ data[i].id + ')" >删除button>' +'  '+
                                '<button class="btn btn-primary" onclick="loveInfo('+ data[i].id + ')" > 喜欢button>'+
                                'td>';
                            s += 'tr>';
                        }
                        $("#info").html(s);//把拼接好的页面添加到info的id下
                    }
                });
            }
    
    • 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

    13. 收藏音乐

    13.1 请求响应设计

    请求:
    {
    post,
    /lovemusic/likemusic
    data: id//音乐id
    } 
    
    响应:
    {
    "status": 0,
    "message": "点赞音乐成功",
    "data": true
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    需要看之前是否收藏过

    13.2 LoveMusicService 层

    @Service
    public class LoveMusicService {
        @Autowired
        private LoveMusicMapper loveMusicMapper;
    
       
    
        /**
         * 收藏音乐
         * @param userId
         * @param musicId
         * @return
         */
        public boolean insertLoveMusic(Integer userId,Integer musicId){
            return loveMusicMapper.insertLoveMusic(userId, musicId);
        }
    
        /**
         * 查询喜欢的音乐
         * @param userId
         * @param musicId
         * @return
         */
        public Music findLoveMusicByMusicIdAndUserId(Integer userId, Integer musicId){
            return loveMusicMapper.findLoveMusicByMusicIdAndUserId(userId,musicId);
        }
    
    }
    
    • 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

    13.3 LoveMusicMapper 层

    @Mapper
    public interface LoveMusicMapper {
    
    
        /**
         * 收藏音乐
         * @param userId
         * @param musicId
         * @return
         */
        boolean insertLoveMusic(Integer userId,Integer musicId);
    
       /**
         * 查询喜欢的音乐
         * @param userId
         * @param musicId
         * @return
         */
        Music findLoveMusicByMusicIdAndUserId(Integer userId, Integer musicId);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    13.4 LoveMusicMapper.xml 层

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

    13.5 LoveMusicController 层

    @RestController
    @RequestMapping("/lovemusic")
    public class LoveMusicController {
    
        @Resource
        private LoveMusicService loveMusicService;
    
        @RequestMapping("/likemusic")
        public ResponseBodyMessage<Boolean> likeMusic(@RequestParam String id, HttpServletRequest request){
            int musicId = Integer.parseInt(id);
            System.out.println("musicId: "+musicId);
            //1. 检查是否登录了
            HttpSession session = request.getSession(false);
            if (session == null || session.getAttribute(Constant.USERINFO_SESSION_KEY) == null) {
                System.out.println("没有登录");
                return new ResponseBodyMessage<>(-1, "请登录后上传", false);
            }
    
            User user = (User) session.getAttribute(Constant.USERINFO_SESSION_KEY);
            int userId = user.getId();
            System.out.println("userId: "+userId);
    
            Music music = loveMusicService.findLoveMusicByMusicIdAndUserId(userId,musicId);
    
            if(music != null){
    
                //之前收藏过,不能在收藏 可以在设置一个取消收藏
                return new ResponseBodyMessage<>(-1,"您之前收藏过该音乐",false);
            }
    
            boolean effect = loveMusicService.insertLoveMusic(userId,musicId);
            if(effect){
                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
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    13.6 测试

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

    13.7 前端代码

    function loveInfo(obj) {
                console.log(obj);
                $.ajax({
                    url: "/lovemusic/likemusic",
                    type: "post",
    //发送给后端的数据
                    data: {"id": obj},
                    dataType: "json",
                    success: function (data) {
                        if (data.data === true) {
                            alert("加入喜欢的列表成功");
                            window.location.href = "list.html";
                        } else {
                            alert("加入喜欢的列表失败或者已经存在该音乐");
                        }
                    }
                });
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    14. 查询喜欢的音乐

    跟之前的主页查询一样

    14.1 请求响应设计

    请求:
    {
    get,
    /lovemusic/findlovemusic,
    data:{musicName:musicName},
    } 
    
    响应:【不给musicName传参】
    {
    "status": 0/-1,
    "message": "",
    "data": ""
    } 
    
    响应:【给musicName传参】
    {
    "status": 0/-1,
    "message": "",
    "data": ""
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    14.2 LoveMusicService 层

    /**
         * 查询这个用户收藏过的所有音乐
         * @param userId
         * @return
         */
        public List<Music> findLoveMusicByUserId(Integer userId){
            return loveMusicMapper.findLoveMusicByUserId(userId);
        }
    
        /**
         * 查询当前用户,指定为musicName的音乐,支持模糊查询
         * @param musicName
         * @param userId
         * @return
         */
        public List<Music> findLoveMusicBykeyAndUID(String musicName,Integer userId){
            return loveMusicMapper.findLoveMusicBykeyAndUID(musicName, userId);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    14.3 LoveMusicMapper 层

    /**
         * 查询这个用户收藏过的所有音乐
         * @param userId
         * @return
         */
        List<Music> findLoveMusicByUserId(Integer userId);
    
        /**
         * 查询当前用户,指定为musicName的音乐,支持模糊查询
         * @param musicName
         * @param userId
         * @return
         */
        List<Music> findLoveMusicBykeyAndUID(String musicName,Integer userId);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    14.4 LoveMusicMapper.xml 层

    <select id="findLoveMusicByUserId" resultType="com.example.onlinemusic.model.Music">
          select m.* from lovemusic lm,music m where m.id = lm.music_id and lm.user_id=#{userInd}
        select>
    
        <select id="findLoveMusicBykeyAndUID" resultType="com.example.onlinemusic.model.Music">
            select m.* from lovemusic lm,music m where m.id = lm.music_id and lm.user_id=#{userId}
               and title like concat('%',#{musicName},'%')
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    14.5 LoveMusicController 层

    @RequestMapping("/findlovemusic")
        public ResponseBodyMessage<List<Music>> findLoveMusic(@RequestParam(required = false) String musicName, HttpServletRequest request){
    
            //1. 检查是否登录了
            HttpSession session = request.getSession(false);
            if (session == null || session.getAttribute(Constant.USERINFO_SESSION_KEY) == null) {
                System.out.println("没有登录");
                return new ResponseBodyMessage<>(-1, "请登录后查找", null);
            }
    
            User user = (User) session.getAttribute(Constant.USERINFO_SESSION_KEY);
            int userId = user.getId();
            System.out.println("userId: "+userId);
    
            List<Music> musicList = null;
            if(musicName == null){
                musicList = loveMusicService.findLoveMusicByUserId(userId);
            }else {
                musicList = loveMusicService.findLoveMusicBykeyAndUID(musicName,userId);
            }
            return new ResponseBodyMessage<>(0, "查询到了所有歌曲信息:", musicList);
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    14.6 测试

    在这里插入图片描述

    14.7 前端代码

    <script>
            
            $(function (){
                load();
            });
    
            // musicName 可以传参,也可以不传参
            function load(musicName){
                $.ajax({
                    url: "/lovemusic/findlovemusic",
                    data:{musicName:musicName},
                    type: "GET",
                    dataType:"json",
                    success:function (obj){
                        console.log(obj);
                        var data=obj.data;
                        console.log(data.length);
                        var s = '';
                        for(var i = 0;i < data.length;i++){
                            var musicUrl = data[i].url+".mp3";
                            s += '<tr>';
                            s += '<td>' + data[i].title + 'td>';
                            s += '<td>' + data[i].singer + 'td>';
                            s+='<td > <button class="btn btn-primary" onclick="playerSong(\''+musicUrl+'\')" >播放歌曲button>' +
                                'td>';
                            s += '<td> <button class = "btn btn-primary" onclick="deleteInfo('+data[i].id+')"> 移除 button>'+'td>';
                            s += 'tr>';
                        }
                        $("#info").html(s);//把拼接好的页面添加到info的id下
                    }
                });
            }
    
    • 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

    15. 移除收藏的音乐

    15.1 请求响应设计

    请求:
    {
    post,
    /lovemusic/deletelovemusic,
    data:{id:id}
    } 
    
    响应:
    {
    "status": 0,
    "message": "取消收藏成功!",
    "data": true
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    15.2 LoveMusicService 层

    /**
         * 移除某个用户喜欢的音乐
         * @param userId
         * @param musicId
         * @return
         */
        public int deleteLoveMusic(Integer userId,Integer musicId){
            return loveMusicMapper.deleteLoveMusic(userId, musicId);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    15.3 LoveMusicMapper 层

    /**
         * 移除某个用户喜欢的音乐
         * @param userId
         * @param musicId
         * @return
         */
        int deleteLoveMusic(Integer userId,Integer musicId);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    15.4 LoveMusicMapper.xml 层

    <delete id="deleteLoveMusic" parameterType="java.lang.Integer">
            delete from lovemusic where user_id=#{userId} and music_id=#{musicId}
        </delete>
    
    
    • 1
    • 2
    • 3
    • 4

    15.5 LoveMusicController 层

     @RequestMapping("/deletelovemusic")
        public ResponseBodyMessage<Boolean> deleteLoveMusic(@RequestParam String id,HttpServletRequest request){
            int musicId = Integer.parseInt(id);
            //1. 检查是否登录了
            HttpSession session = request.getSession(false);
            if (session == null || session.getAttribute(Constant.USERINFO_SESSION_KEY) == null) {
                System.out.println("没有登录");
                return new ResponseBodyMessage<>(-1, "请登录后删除", null);
            }
    
            User user = (User) session.getAttribute(Constant.USERINFO_SESSION_KEY);
            int userId = user.getId();
    
            int ret = loveMusicService.deleteLoveMusic(userId,musicId);
            if(ret == 1){
                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

    15.6 测试

    在这里插入图片描述

    15.7 前端代码

    //移除
            function deleteInfo(obj){
                console.log(obj);
                $.ajax({
                    url:"/lovemusic/deletelovemusic",
                    type:"POST",
                    data:{"id":obj},
                    dataType: "json",
                    success: function (obj){
                        console.log(obj);
                        if(obj.data===true){
                            alert("移除成功!");
                            window.location.href="loveMusic.html";
                        }else{
                            alert("移除失败!");
                        }
                    }
                });
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
  • 相关阅读:
    shell编程增强
    Java并发编程学习十:线程协作
    Linux学习之:进程概念
    Guide2:Consuming a RESTful Web Service
    编译一个基于debian/ubuntu,centos,arhlinux第三方系统的问题解答
    Java项目:ssm学生学籍管理系统
    文件共享服务器
    C语言有关内存的几个疑问,以memset以及memcpy为例
    ipad手写笔有必要买原装吗?第三方性价比高的手写笔推荐
    以太坊合并在即 生态用户需要注意什么?
  • 原文地址:https://blog.csdn.net/chenbaifan/article/details/126282948