项目:在线音乐播放服务器——基于SSM框架和mybatis

发布于:2025-05-20 ⋅ 阅读:(21) ⋅ 点赞:(0)

介绍项目

项目主要是基于SSM框架和mybatis进行实现

主要的功能:

登陆界面,用户注册,音乐的播放列表,删除指定的歌曲,批量删除指定的歌曲,收藏歌曲,查询歌曲,从收藏列表中删除收藏音乐。

功能展示:

登录界面

用户注册

 

音乐列表

 喜欢列表

添加歌曲 

 

首先创建一个Sping Boot项目

再创建musicserver数据库

数据库一共有三个表:收藏歌曲表,歌曲表,用户表

lovemusic表

music表

user表

在.yml文件中配置数据库和xml

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/musicserver?characterEncoding=utf8&serverTimezone=UTC
    username: 你自己的数据库用户名
    password: 你自己的数据库密码
    driver-class-name: com.mysql.cj.jdbc.Driver

  servlet:
    multipart:
      max-file-size: 15MB
      max-request-size: 100MB
#音乐上传后的路径
  music:
    local:
      path: E:/music/

mybatis:
  configuration:
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath:mapper/**.xml
logging:
  file:
    name: spring-book.log

创建项目的结构目录 

登录模块的设计

创建user类

对应数据库的user表,创建用户的实体类

@Data
public class User {
    private Integer id;
    private String username;
    private String password;
}

创建UserMapper接口

@Mapper
public interface UserMapper {
    User login(User loginUser);

    User selectByName(String username);
}

 创建UserMapper.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.blame.onlinemusicserver.mapper.UserMapper">

    <select id="login" resultType="com.blame.onlinemusicserver.model.User" parameterType="com.blame.onlinemusicserver.model.User">
        select * from user where username=#{username} and password=#{password}
    </select>

    <select id="selectByName" resultType="com.blame.onlinemusicserver.model.User">
        select * from user where username=#{username}
    </select>

</mapper>

实现登录的请求和响应

创建响应类的工具类

@Data
public class ResponseBodyMessage<T> {
    private Integer status;
    private String message;
    private T data;


    public ResponseBodyMessage(Integer status, String message, T data) {
        this.status = status;
        this.message = message;
        this.data = data;
    }
}

创建UserController

        @RequestParam:将请求参数绑定到你控制器的⽅法参数上,如果你这个参数不是必须要传的,@RequestParam(required = false) ,默认是true

@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @RequestMapping("/login")
    public ResponseBodyMessage<User> login(@RequestParam("username") String username,
                                           @RequestParam("password") String password,
                                           HttpServletRequest request){
        ResponseBodyMessage<User> result = userService.login(username, password, request);
        return result;
    }
}

我们在登录时使用BCrypt加密设计

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>

在项目的启动类中添加@SpringBootApplication(exclude =
        {org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class})

//在@SpringBootApplication注解后添加(exclude =
//{org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class})的作用:
//我们虽然引用了 security的依赖,但是我们只是使用了它框架中的一个类,不适用其他的,如果不添加这个的话,SpringSecurity⽣效了的,
//此时的接⼝都是被保护的,我们需要通过验证才能正常的访问,导致我们无法登录
@SpringBootApplication(exclude =
        {org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class})
public class OnlineMusicServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(OnlineMusicServerApplication.class, args);
    }

}

创建AppConfig

定义config包,创建AppConfig,使用@Configuration注解

@Configuration
public class AppConfig implements WebMvcConfigurer {

    @Bean
    public BCryptPasswordEncoder getbCryptPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }
}

创建UserService 

request.getSession(),获取这次请求的session对象

.setAttribute()将用户信息存储到session中

因为  USERINFO_SESSION_KEY  这个常量容易拼错,所以我们将其定义在常量信息中

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    public ResponseBodyMessage<User> login(String username,
                      String password,
                      HttpServletRequest request) {
        User loginUser=new User();
        loginUser.setUsername(username);
        loginUser.setPassword(password);
        User user=userMapper.selectByName(username);
        if(user==null){
            return new ResponseBodyMessage<>(-1,"用户不存在",loginUser);
        }
        if(!bCryptPasswordEncoder.matches(password,user.getPassword())){
            return new ResponseBodyMessage<>(-1,"密码错误,请重新登录",loginUser);
        }else {
            request.getSession().setAttribute(Constant.USERINFO_SESSION_KEY,user);
            return new ResponseBodyMessage<>(0,"登陆成功",loginUser);
        }

    }
}
public class Constant {
    public static final  String USERINFO_SESSION_KEY="USERINFO_SESSION_KEY";
}

 验证

 

新增功能:注册用户功能的实现

修改数据库,在user表中添加email

ALTER TABLE user 
ADD COLUMN email VARCHAR(100) NOT NULL;

UserMapper

void insertUser(User user);
 <insert id="insertUser">
        insert into user (username, password, email) VALUES (#{username}, #{password}, #{email})
    </insert>

UserService

public ResponseBodyMessage<Boolean> register(String username,String password,String email){
        User existUser=userMapper.selectByName(username);
        if(existUser!=null){
            return new ResponseBodyMessage<>(-1,"该用户存在",false);
        }
//        将注册的密码进行加密
        String encoderPassword=bCryptPasswordEncoder.encode(password);
        User user=new User();
        user.setUsername(username);
        user.setPassword(encoderPassword);
        user.setEmail(email);
        userMapper.insertUser(user);
        return new ResponseBodyMessage<>(0,"注册成功",true);
}

UserController

使用@Valid来校验参数

使用@Valid记得添加其依赖

        <dependency>
            <groupId>jakarta.validation</groupId>
            <artifactId>jakarta.validation-api</artifactId>
            <version>3.0.2</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate.validator</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>8.0.0.Final</version>
        </dependency>

定义RequestRegister来进行请求数据的封装

@Data
public class RequestRegister {

    @Size(min = 3, max = 20, message = "用户名长度应在3到20个字符之间")
    @NotBlank(message = "username不能为空")
    private String username;

    @NotBlank(message = "password不能为空")
    private String password;


    @Email(message = "邮箱格式不正确")
    @NotBlank(message = "email不能为空")
    private String email;
}
@RequestMapping("/register")
    public ResponseBodyMessage<Boolean> register(@Valid @RequestBody RequestRegister requestRegister){
        return userService.register(requestRegister.getUsername(), requestRegister.getPassword(), requestRegister.getEmail());
    }
}

 

上传音乐模块的实现 

请求和响应的接口实现

定义music实体类

对应数据库中的music表的字段

@Data
public class Music {
    private Integer id;
    private String title;
    private String singer;
    private String time;
    private String url;
    private Integer userid;

}

定义MusicController

将音乐文件上传到这个路径

Slf4j
@RestController
@RequestMapping("/music")
public class MusicController {



    @Autowired
    private MusicService musicService;

    @RequestMapping("/upload")
    public ResponseBodyMessage<Boolean> insertMusic(@RequestParam String singer,
                                                    @RequestParam("filename") MultipartFile file,
                                                    HttpServletRequest request,
                                                    HttpServletResponse response){
        return  musicService.insertMusic(singer, file, request, response);

    }
}

定义MusicService

@Slf4j
@Service
public class MusicService {

    @Value("${spring.music.local.path}")
    private String SAVE_PATH;

    @Autowired
    private MusicMapper mapper;

    @Autowired
    private LoveMusicMapper loveMusicMapper;

    //添加音乐
    public ResponseBodyMessage<Boolean> insertMusic(String singer,
                                                     MultipartFile file,
                                                     HttpServletRequest request,
                                                     HttpServletResponse response){
        //1.检查登录
        HttpSession session=request.getSession(false);
        if(session==null || session.getAttribute(Constant.USERINFO_SESSION_KEY)==null){
            log.error("未登录,请先进行登录");
            return new ResponseBodyMessage<>(0,"没有登录",false);

        }
        //2.检查数数据库中是否有此音乐

        //得到文件的名字和类型
        String fileNameAndType=file.getOriginalFilename();
        System.out.println("fileNameAndType"+fileNameAndType);
        //以 . 将名字和类型分开,得到title
        if(fileNameAndType==null || !fileNameAndType.contains(".")){
            return new ResponseBodyMessage<>(0,"文件不合法,必须包含拓展名",false);
        }
        String title=fileNameAndType.substring(0,fileNameAndType.lastIndexOf("."));

        log.info("Checking if music exists: title = {}, singer = {}", title, singer);
        //判断数据库中是否有此歌曲
        Integer exist= mapper.selectByTitleAndSinger(title,singer);
        if(exist!=null && exist>0){
            return new ResponseBodyMessage<>(0,"数据库中已经存在此音乐",false);
        }


        //3..上传音乐到服务器
        String path=SAVE_PATH + fileNameAndType;
        File dest=new File(path);
        System.out.println("dest"+dest.getPath());
        if(!dest.exists()){

            dest.mkdirs();
        }
        //上传文件到目标
        try {
            file.transferTo(dest);
            log.info("服务器上传成功");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        //将歌曲上传到数据库
        SimpleDateFormat sf=new SimpleDateFormat("yyyy-MM-dd");
        String time=sf.format(new Date());

        String url="music/get?path="+title;
        User user=(User) session.getAttribute(Constant.USERINFO_SESSION_KEY);
        int userId=user.getId();


        try {
            int ret= mapper.insert(title,singer,time,url,userId);

            if(ret==1){
                response.sendRedirect("/list.html");
                return new ResponseBodyMessage<>(1,"数据库上传成功",true);
            }else {

                return new ResponseBodyMessage<>(-1,"数据库上传失败",false);
            }
        }catch (BindingException e){
            boolean delete= dest.delete();
            if(delete){
                log.info("数据库插入失败,已成功删除服务器上的音乐文件");
            }else{
                log.warn("数据库插入失败,未删除服务器上的音乐文件,可能需要手动删除:{}",dest.getAbsolutePath());
            }
            return new ResponseBodyMessage<>(-1,"数据库上传失败,在服务器中删除音乐",false);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

新增方法:判断上传的文件是否是MP3的形式

我们需要对上传的文件进行MP3文件类型检测,包括文件扩展名和MIME类型的两种检查

文件拓展名是文件名称的一部分,它可以轻易被修改,从而伪装成另一种文件

MIME类型是一种表示文件类型和格式的标准,比拓展名更加可靠

        //根据文件的拓展名来判断是否为.MP3文件
      String extension=fileNameAndType.substring(fileNameAndType.lastIndexOf(".")).toLowerCase();
        if(!extension.equals(".mp3")){
            return new ResponseBodyMessage<>(-0,"只支持MP3文件上传",false);
        }
        //根据MINE判断
        try {
            String mimeType=file.getContentType();
            log.info("文件的MINI类型:{}",mimeType);
            if(mimeType==null || !mimeType.equals("audio/mpeg")){
                return new ResponseBodyMessage<>(0,"文件格式不正确,只支持MP3音频上传",false);
            }
        }catch (Exception e){
            log.error("文件检验异常:{}",e.getMessage());
            return new ResponseBodyMessage<>(0,"文件类型检验异常",false);

        }

 

上传数据库的实现

@Mapper
public interface MusicMapper {

    Integer insert(String title,String singer,String time,String url,Integer userid);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.blame.onlinemusicserver.mapper.MusicMapper">

    <insert id="insert">
        insert into music (title,singer,time,url,userid) values (#{title},#{singer},#{time},#{url},#{userid})
    </insert>

测试

播放⾳乐模块设计 

请求和响应的接口实现

在MusicController中新增get方法

是Spring框架中用于构建Http响应的对象

这里返回的是一个字节数组,通常用于传输二进制的数据,图片,音频

我们在这时传入的是音频

    @GetMapping("/get")
    public ResponseEntity<byte[]> get(@RequestParam String path){
        return musicService.get(path);
    }

MsuicService

ResponseEntity对象是Spring对请求响应的封装。它继承了HttpEntity对象,包含了Http的响应码 (httpstatus)、响应头(header)、响应体(body)三个部分。

//播放音乐
    public ResponseEntity<byte[]> get(String path){
        File file=new File(SAVE_PATH+path);
        if(!file.exists()){
            return ResponseEntity.notFound().build();
        }
        try {
            byte[] bytes= Files.readAllBytes(file.toPath());
            HttpHeaders headers=new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
            headers.setContentLength(bytes.length);
            return ResponseEntity.ok().headers(headers).body(bytes);
        } catch (IOException e) {
            e.printStackTrace();
            return ResponseEntity.internalServerError().build();
        }
    }

 验证

删除⾳乐模块设计

请求和响应的接口实现

实现MusicMapper

   Integer deleteMusicById(Integer musicId);

    Music selectMusicById(Integer musicId);
    <delete id="deleteMusicById">
        delete from music where id=#{id}
    </delete>

    <select id="selectMusicById" resultType="com.blame.onlinemusicserver.model.Music">
        select * from music where id=#{id}
    </select>

实现MusicController

根据Id来进行删除

    @RequestMapping("/delete")
    public ResponseBodyMessage<Boolean> deleteMusicById(@RequestParam Integer id){
        return musicService.deleteMusicById(id);
    }

实现MusicService 

如果要将一个歌曲删除,需要判断它是否在收藏歌曲中,如果在,则需要将其从收藏音乐中删除 

 Boolean deleteLoveMusicByMusicId(Integer musicId);

 Boolean selectLoveMusicByMusicId(Integer musicId);

判断删除是否成功

 

    //删除音乐
    public ResponseBodyMessage<Boolean> deleteMusicById(Integer id){
        Music music=mapper.selectMusicById(id);
        if(music==null){
            return new ResponseBodyMessage<>(0,"该音乐不存在,无法删除",false);
        }
        //此时integer表示删除的行数,如果行数又0变为1则表示已经进行了删除的步骤
        Integer integer = mapper.deleteMusicById(id);
        Boolean isLoved = loveMusicMapper.selectLoveMusicByMusicId(id);
        if (isLoved != null && isLoved) {
            // 如果在收藏中,删除收藏记录
            loveMusicMapper.deleteLoveMusicByMusicId(id);
        } else {
            log.info("歌曲不在收藏音乐中");
        }
        if(integer==1){
            String title=music.getTitle();
            File file=new File(SAVE_PATH+File.separator+ title+".mp3");
            boolean delete=file.delete();

            if(delete){
                log.info("服务器中音乐删除成功");
                return new ResponseBodyMessage<>(1,"服务器中音乐删除成功",true);
            }else {
                log.error("服务器中音乐删除失败");
                return new ResponseBodyMessage<>(-1,"服务器中音乐删除失败",false);
            }
        }
        return new ResponseBodyMessage<>(-1,"音乐删除失败",false);
    }

 验证

批量删除选中的⾳乐

请求和响应的接口实现

实现MusicController

只需要先刚刚单首歌曲删除的基础上,在外层套一层for循环,依次进行删除,知道for循环结束,删除全部的歌曲

public ResponseBodyMessage<Boolean> deleteMusicByIdMany(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=mapper.selectMusicById(musicId);
            Boolean isLoved = loveMusicMapper.selectLoveMusicByMusicId(musicId);
            if (isLoved != null && isLoved) {
                // 如果在收藏中,删除收藏记录
                loveMusicMapper.deleteLoveMusicByMusicId(musicId);
            } else {
                log.info("歌曲不在收藏音乐中");
            }
            System.out.println("当前正在处理的 ID: " + id);
            if(music==null){
                log.error("该歌曲不存在");
                continue;
            }
            //此时integer表示删除的行数,如果行数又0变为1则表示已经进行了删除的步骤
            Integer integer = mapper.deleteMusicById(musicId);
            if(integer==1){
                String title=music.getTitle();
                File file=new File(SAVE_PATH+File.separator+ title+".mp3");
                boolean delete=file.delete();
                if(delete){
                    sum+=integer;
                    log.info("服务器中音乐删除成功");
                }else {
                    log.error("服务器中音乐删除失败");
                }
            }else {
                log.error("数据库删除失败");
            }
        }
        if(sum==id.size()){
            log.info("批量删除成功");
            return new ResponseBodyMessage<>(1,"服务器中音乐批量删除成功",true);
        }else {
            log.info("批量删除失败");
            return new ResponseBodyMessage<>(-1,"服务器中音乐批量删除失败",false);
        }
    }

验证

查询⾳乐模块设计

功能:支持模糊查询,支持输入的参数为空

输入参数为空时,查出所有的歌曲

MusicMapper

一个是根据歌名进行查询,另一个是查询全部的歌曲

    List<Music> findMusicByTitle(String name);

    List<Music> findMusic();

MusicController 

@RequestParam不传递参数时候,可以为空 

    @RequestMapping("/findmusic")
    public ResponseBodyMessage<List<Music>> findMusic(@RequestParam(required = false) String musicName){
        return  musicService.findMusic(musicName);
    }

MusicService 

 public ResponseBodyMessage<List<Music>> findMusic(String musicName){
        List<Music> musics=null;
        //musicName!=null是判断传入的歌曲名是否为空
        //musicName.trim().isEmpty()是去掉前后的空格,判断字符串是否为空,加上这个更加的严谨
        if(musicName!=null && !musicName.trim().isEmpty()){
            log.info("已找到该歌曲");
            musics=mapper.findMusicByTitle(musicName);
            if(musics.isEmpty()){
                return new ResponseBodyMessage<>(-1,"没有找到该歌曲",musics);
            }
            return new ResponseBodyMessage<>(1,"成功找到该歌曲",musics);
        }else {
            log.info("找到全部的歌曲");
            musics=mapper.findMusic();
            return new ResponseBodyMessage<>(1,"成功找到全部的歌曲",musics);
        }
    }

验证

输入为空,查询全部的歌曲

输入不为空,查询单个歌曲

 

添加⾳乐⾄喜欢的列表模块设计 

请求和响应的接口实现

LoveMusicMapper

@Mapper
public interface LoveMusicMapper {


    //检查该音乐是否已经被收藏
    Music selectMusicIsExist(Integer userId,Integer musicId);

    //将该音乐加入收藏夹
    Boolean insertLoveMusic(Integer userId,Integer musicId);
}
<select id="selectMusicIsExist" resultType="com.blame.onlinemusicserver.model.Music">
        select * from lovemusic where user_id=#{userId} and music_id=#{musicId}
    </select>

    <insert id="insertLoveMusic">
        insert into lovemusic (user_id,music_id) values (#{userId},#{musicId})
    </insert>

 

LoveMusicController

@RestController
@RequestMapping("/lovemusic")
public class LoveMusicController {

    @Autowired
    private LoveMusicService loveMusicService;

    @RequestMapping("addLikeMusic")
    public ResponseBodyMessage<Boolean> addLikeMusic(@RequestParam String id,HttpServletRequest request){
        return loveMusicService.addLikeMusic(id,request);
    }
}

LoveMusicService

@Slf4j
@Service
public class LoveMusicService {

    @Autowired
    private LoveMusicMapper loveMusicMapper;

    //添加收藏
    public ResponseBodyMessage<Boolean> addLikeMusic(String id,HttpServletRequest request){

        Integer 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){
            log.error("未登录,请先进行登录");
            return new ResponseBodyMessage<>(0,"没有登录",false);
        }
        User user =(User) session.getAttribute(Constant.USERINFO_SESSION_KEY);

        Integer userId=user.getId();
        System.out.println("userId"+userId);

        Music music=loveMusicMapper.selectMusicIsExist(userId,musicId);

        if(music!=null){
            return new ResponseBodyMessage<>(-1,"该音乐已经加入了收藏夹",false);
        }
        Boolean successAdd=loveMusicMapper.insertLoveMusic(userId,musicId);
        if(successAdd){
            return new ResponseBodyMessage<>(1,"音乐加入收藏夹成功",true);
        }
        return new ResponseBodyMessage<>(-1,"音乐加入收藏夹失败",false);
    }

验证

查询喜欢的⾳乐模块设计

请求和响应的接口实现

LoveMusicMapper

    //根据用户信息查询收藏的歌曲,支持模糊查询
    List<Music> findLoveMusicByUserId(Integer userId);


    //根据用户信息来查询想要查询的收藏的歌曲
    List<Music> findLoveMusicByUserIdAndMusicId(Integer userId,String musicName);
 <select id="findLoveMusicByUserId" resultType="com.blame.onlinemusicserver.model.Music">
        select m.* from lovemusic lm,music m where lm.music_id=m.id and lm.user_id=#{userId}
    </select>

    <select id="findLoveMusicByUserIdAndMusicId" resultType="com.blame.onlinemusicserver.model.Music">
        select m.* from lovemusic lm,music m where lm.music_id=m.id and lm.user_id=#{userId} and title like concat('%',#{musicName},'%')
    </select>

LoveMusicController

@RequestMapping("/findlovemusic")
    public ResponseBodyMessage<List<Music>> findLoveMusic(HttpServletRequest request,@RequestParam(required = false)
                                                          String musicName){
        return loveMusicService.findLoveMusic(request, musicName);
    }

 LoveMusicService

public ResponseBodyMessage<List<Music>> findLoveMusic(HttpServletRequest request,String musicName){
        //判断是否登录
        HttpSession session= request.getSession(false);
        if(session==null || session.getAttribute(Constant.USERINFO_SESSION_KEY)==null){
            log.error("未登录,请先进行登录");
            return new ResponseBodyMessage<>(0,"没有登录",null);
        }
        User user=(User) session.getAttribute(Constant.USERINFO_SESSION_KEY);
        Integer userId=user.getId();
        System.out.println("userId"+userId);
        List<Music> musics=null;
        if(userId==null){
            return new ResponseBodyMessage<>(-1,"用户不存在",null);
        }
        log.info("已经找到该用户");
        //查询用户的全部收藏音乐
        if(musicName==null){
            musics= loveMusicMapper.findLoveMusicByUserId(userId);
            //判断 musics 不为空且不为 null
            if(!CollectionUtils.isEmpty(musics)){
                return new ResponseBodyMessage<>(0,"已经找到用户的全部收藏音乐",musics);
            }else {
                return new ResponseBodyMessage<>(-1,"用户的收藏音乐为空",null);
            }
        }else {   //根据用户信息来查询想要查询的收藏的歌曲
            System.out.println("musicName"+musicName);
            musics=loveMusicMapper.findLoveMusicByUserIdAndMusicId(userId,musicName);
            //判断 musics 不为空且不为 null
            if(!CollectionUtils.isEmpty(musics)){
                return new ResponseBodyMessage<>(0,"已经找到用户查询的收藏歌曲",musics);
            }else {
                return new ResponseBodyMessage<>(-1,"用户没有收藏此音乐",null);
            }

        }
    }

验证 

移除喜欢的⾳乐模块设计 

请求和响应的接口实现

LoveMusicMapper

 Boolean deleteLoveMusic(Integer userId,Integer musicId);
    <delete id="deleteLoveMusic">
        delete from lovemusic where user_id=#{userId} and music_id=#{musicId}
    </delete>

LoveMusicController

    @RequestMapping("deleteLikeMusic")
    public ResponseBodyMessage<Boolean> deleteLikeMusic(@RequestParam String id,HttpServletRequest request){
        return loveMusicService.deleteLikeMusic(id,request);
    }

LoveMusicService

    //取消收藏
    public ResponseBodyMessage<Boolean> deleteLikeMusic(String id,HttpServletRequest request){
        Integer musicId=Integer.parseInt(id);
        System.out.println("musicId"+musicId);

        //检查登录
        HttpSession session=request.getSession(false);
        if(session==null || session.getAttribute(Constant.USERINFO_SESSION_KEY)==null){
            log.error("未登录,请先进行登录");
            return new ResponseBodyMessage<>(0,"没有登录",false);
        }
        User user =(User) session.getAttribute(Constant.USERINFO_SESSION_KEY);

        Integer userId=user.getId();
        System.out.println("userId"+userId);
        Music music=loveMusicMapper.selectMusicIsExist(userId,musicId);
        if(music==null){
            return new ResponseBodyMessage<>(-1,"该音乐不在收藏夹内",false);
        }
        Boolean successDelete=loveMusicMapper.deleteLoveMusic(userId,musicId);
        if(successDelete){
            return new ResponseBodyMessage<>(1,"音乐已经从收藏夹中删除",true);
        }
        return new ResponseBodyMessage<>(-1,"音乐从收藏夹中删除失败",false);
    }

验证

实现客户端的代码

登录界面

<script>
    $(function () {
      $("#submit").click(function () {
        var username = $("#user").val().trim();
        var password = $("#password").val().trim();

        if (username === "" || password === "") {
          $("#message").text("请输入用户名和密码!");
          $("#messageBox").fadeIn();
          return;
        }

        $.ajax({
          url: "/user/login",
          type: "post",
          dataType: "json",
          data: {
            username: username,
            password: password
          },
          success: function (result) {
            if (result.status === 0) {
              alert("登录成功!");
              window.location.href = "list.html";
            } else {
              $("#message").text("账号或密码错误,请重试!");
              $("#messageBox").fadeIn();
              $("#user").val("");
              $("#password").val("");
            }
          },
          error: function () {
            $("#message").text("服务器连接失败,请稍后重试!");
            $("#messageBox").fadeIn();
          }
        });
      });
    });
  </script>

注册界面

<script>
    $(function () {
        $("#registerBtn").click(function () {
            var username = $("#regUser").val().trim();
            var email = $("#regEmail").val().trim();
            var password = $("#regPassword").val().trim();

            if (username === "" || email === "" || password === "") {
                $("#regMessage").text("请完善注册信息!");
                $("#regMessageBox").fadeIn();
                return;
            }

            $.ajax({
                url: "/user/register",
                type: "post",
                dataType: "json",
                contentType: "application/json",
                data: JSON.stringify({
                    username: username,
                    password: password,
                    email: email
                }),
                success: function (result) {
                    if (result.status === 0) {
                        alert("注册成功!");
                        window.location.href = "login.html";
                    } else {
                        $("#regMessage").text(result.message);
                        $("#regMessageBox").fadeIn();
                    }
                },
                error: function () {
                    $("#regMessage").text("服务器连接失败,请稍后重试!");
                    $("#regMessageBox").fadeIn();
                }
            });
        });
    });
</script>

音乐列表界面

 <script type="text/javascript">
        $(function() {
            load(); // 页面加载时默认加载所有歌曲
        });

        function load(musicName) {
            $.ajax({
                url: "/music/findmusic",
                data: { musicName: musicName },
                type: "get",
                dataType: "json",
                success: function(result) {
                    var data = result.data;
                    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" onclick="playerSong(\'' + musicUrl + '\')">播放歌曲</button></td>';
                        s += '<td><button class="btn" onclick="deleteInfo(' + data[i].id + ')">删除</button>';
                        s += '<button class="btn" onclick="loveInfo(' + data[i].id + ')">喜欢</button></td>';
                        s += '</tr>';
                    }
                    $("#info").html(s);  // 更新表格
                }
            });
        }

        function playerSong(musicUrl) {
            var name = musicUrl.substring(musicUrl.lastIndexOf('/') + 1);  // 获取音乐名称
            SewisePlayer.toPlay(musicUrl, name, 0, true);  // 播放歌曲
        }

        function deleteInfo(musicId) {
            $.ajax({
                url: "/music/delete",
                data: { id: musicId },
                type: "post",
                dataType: "json",
                success: function(result) {
                    if (result.data) {
                        alert("删除成功");
                        window.location.href = "list.html";  // 页面跳转
                    } else {
                        alert("删除失败");
                    }
                }
            });
        }
        $(function(){
            $("#submit1").click( function(){
                var name = $("#exampleInputName2").val();
                load(name);
            });

            $.when(load).done(function(){
                $("#delete").click(function(){
                    var id = new Array();
                    var i = 0;//数组的小标
                    //
                    $("input:checkbox").each(function(){
                        //如果被选中,this代表发生事件的dom元素,<input>
                        if( $(this).is(":checked")) {
                            id[i] = $(this).attr("id");
                            i++;
                        }
                    });

                    console.log(id);

                    $.ajax({
                        url:"/music/deleteSel",
                        data:{"id":id},
                        dataType:"json",
                        type:"post",

                        success:function(obj){
                            if(obj.data == true) {
                                alert("删除成功!");
                                window.location.href = "list.html";
                            }else{
                                alert("删除失败!");
                            }
                        }
                    });
                });
            });
        });
        function loveInfo(musicId) {
            $.ajax({
                url: "lovemusic/addLikeMusic",
                data: { "id": musicId },
                type: "post",
                dataType: "json",
                success: function(result) {
                    if (result.data) {
                        alert("添加收藏成功");
                        window.location.href = "list.html";  // 页面跳转
                    } else {
                        alert("添加收藏失败");
                    }
                }
            });
        }
    </script>

收藏音乐界面

<script>
    $(function() {
      load();

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

    function load(musicName) {
      $.ajax({
        url: "/lovemusic/findlovemusic",
        data: {"musicName": musicName},
        type: "GET",
        dataType: "json",
        success: function(obj) {
          var data = obj.data;
          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><audio src="' + musicUrl + '" controls preload="none" loop></audio></td>';
            s += '<td><button class="btn btn-primary" onclick="deleteInfo(' + data[i].id + ')">移除</button></td>';
            s += '</tr>';
          }
          $("#info").html(s);
        }
      });
    }

    function deleteInfo(id) {
      $.ajax({
        url: "/lovemusic/deleteLikeMusic",
        type: "POST",
        data: {"id": id},
        dataType: "json",
        success: function(val) {
          if (val.data == true) {
            alert("删除成功!,重新加载当前页面!");
            window.location.href = "list.html";
          } else {
            alert("删除失败!");
          }
        }
      });
    }
  </script>

上传音乐界面

  <form method="POST" enctype="multipart/form-data" action="/music/upload">
      <div class="form-group">
        <label for="file">🎶 音乐文件</label>
        <input type="file" id="file" name="filename" required />
      </div>
      <div class="form-group">
        <label for="singer">👤 歌手名</label>
        <input type="text" id="singer" name="singer" placeholder="请输入歌手名" required />
      </div>
      <input type="submit" value="📤 上传" />
    </form>

 在这里的播放音乐的工具,我们使用的是一个开源的播放工具

demos/例子说明.md · Jack Zhang/sewise-player - Gitee.com

 <div style="width: 180px; height: 140px; position: absolute; bottom: 10px; right: 10px;">
        <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",
                autostart: "false",
            });
        </script>
    </div>

实现播放

        function playerSong(musicUrl) {
            var name = musicUrl.substring(musicUrl.lastIndexOf('/') + 1);  // 获取音乐名称
            SewisePlayer.toPlay(musicUrl, name, 0, true);  // 播放歌曲
        }

 配置拦截器

自定义拦截器

@Component
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {
        HttpSession session = request.getSession(false);
        if (session != null && session.getAttribute(Constant.USERINFO_SESSION_KEY) != null) {
            return true;
        }
        // 未登录提示
        //是告诉浏览器内容是 JSON,并且是 UTF-8 编码;
        response.setContentType("application/json;charset=utf-8");
        //手动返回一段json数据,进行错误提示
        response.getWriter().write("{\"code\":401,\"msg\":\"未登录,请先登录\"}");
        return false;
    }
}

使用拦截器

只释放静态资源和登录接口

@Configuration
public class AppConfig implements WebMvcConfigurer {


    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        LoginInterceptor loginInterceptor = new LoginInterceptor();
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**") // 拦截所有请求
                .excludePathPatterns(
                        "/js/**",
                        "/css/**",
                        "/images/**",
                        "/fonts/**",
                        "/player/**",
                        "/login.html",
                        "/user/login"
                ); // 放行静态资源和登录接口
    }
}

 项目在此全部结束,可以将项目部署到云服务器上

希望能对大家有所帮助!!!


网站公告

今日签到

点亮在社区的每一天
去签到