介绍项目
项目主要是基于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"
); // 放行静态资源和登录接口
}
}
项目在此全部结束,可以将项目部署到云服务器上
希望能对大家有所帮助!!!