赞
踩
用到的技术:
前端 :HTML + CSS + JavaScript + JQuery
后端 :Spring Boot + MyBatis
我使用的 IDEA 工具
我使用的 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 );
在 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;
mybatis xml 文件,保留备用
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.onlinemusic.mapper.UserMapper">
</mapper>
统一让响应的返回格式一样
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; } }
存储不变的常量,方便我们后续使用(如 session)
public class Constant {
public static final String USERINFO_SESSION_KEY = "USERINFO_SESSION_KEY";
}
MD5是一个安全的散列算法,输入两个不同的明文不会得到相同的输出值,根据输出值,不能得到原始的明文,即其过程不可逆; 但是虽然不可逆,但是不是说就是安全的。因为自从出现彩虹表后,这样的密码也"不安全"。
彩虹表:彩虹表就是一个庞大的、针对各种可能的字母组合预先计算好的哈希值的集合,不一定是针对MD5算法的,各种算法的都有,有了它可以快速的破解各类密码。越是复杂的密码,需要的彩虹表就越大,现在主流的彩虹表都是100G以上。
不安全的原因:
参考链接:https://md5.cc/news1.aspx
更安全的做法是加盐或者长密码等做法,让整个加密的字符串变的更长,破解时间变慢。密码学的应用安全,是建立在破解所要付出的成本远超出能得到的利益上的 。
盐是在每个密码中加入一些单词来变成一个新的密码,存入数据库当中
添加依赖:
<!-- md5 依赖 -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
测试类:
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")); } }
不管运行多少次,这个密码是规定的。因为这里没有用随机盐值。当密码长度很大,盐值也是随机的情况下,密码的强度也加大了。破解成本也增加了
Bcrypt就是一款加密工具,可以比较方便地实现数据的加密工作。你也可以简单理解为它内部自己实现了随机加盐处理 。我们使用MD5加密,每次加密后的密文其实都是一样的,这样就方便了MD5通过大数据的方式进行破解。Bcrypt生成的密文是60位的。而MD5的是32位的。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>
在 SpringBoot 启动了添加:
@SpringBootApplication(exclude = {org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class})
测试类:
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); } }
encode方法:对用户密码进行加密
matches方法:参数一,待检验的未加密的密码 。参数二:从数据库中查询出的加密后密码 。
参考链接: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+盐的主要区别是:每次加的盐不同,导致每次生成的结果也不相同。无法比对!
新建 AppConfig 类
@Configuration
public class AppConfig implements WebMvcConfigurer {
@Bean
public BCryptPasswordEncoder getBCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}
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;
}
}
在 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"); }
请求
POST /user/login
{username: "",password: ""}
响应
{
status: 0/-1,
message: "",
data: ""
}
响应体设计字段解释:
{
status:
状态码,为0代表成功,负数代表失败
message:
状态描述信息,描述此次请求成功或者失败的原因
data:
返回的数据,请求成功后,需要给前端的数据信息
}
我们这里登录需要进行数据库的 用户查询,根据用户名判断是否存在当前用户
注: 注解都不要忘记给加上
创建 model 包,底下创建 User 类
import lombok.Data;
@Data
public class User {
private Integer id;
private String username;
private String password;
}
新建 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);
}
创建 mabatis 包,添加 xml 代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.onlinemusic.mapper.UserMapper">
<!-- 根据用户名查找用户用户 -->
<select id="selectByName" resultType="com.example.onlinemusic.model.User">
select * from user where username=#{username}
</select>
</mapper>
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public User selectByName(String username){
return userMapper.selectByName(username);
}
}
@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); } } }
我用的是 postman 进行测试
<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>
请求
POST /user/reg
{username: "",password: ""}
响应
{
status: 0/-1,
message: "",
data: ""
}
主要就是需要注意用户存在就不能进行注册
@Mapper
public interface UserMapper {
/**
* 新增用户
* @param user
* @return
*/
int addUser(User user);
}
<!-- 新增用户 -->
<insert id="addUser">
insert into user(username,password) values (#{username},#{password});
</insert>
public int addUser(User user){
return userMapper.addUser(user);
}
@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);
}
}
<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>
请求:
{
post,
/music/upload
{singer,MultipartFile file},
}
响应:
{
"status": 0,
"message": "上传成功!",
"data": true
}
@Data
public class Music {
private Integer id;
private String title;
private String singer;
private String time;
private String url;
private Integer userid;
}
我们上传音乐需要注意的就是是否重复上传,我们这里是根据同一首歌是否是同一个歌手来判断的
@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);
}
}
@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); }
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.example.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>
@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); } } }
请求:
{
get,
/music/get?path=xxx.mp3
}
响应:
{
音乐数据本身的字节信息
}
/** * 播放音乐的时候,/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(); }
有这个 TAG 就能判断是不是歌曲了
//播放
function playerSong(obj) {
console.log(obj)
var name = obj.substring(obj.lastIndexOf('=')+1);
//obj:播放地址 name: 名字 0: 开始时间 true: 自动播放
SewisePlayer.toPlay(obj,name,0,true);
}
<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>
请求:
{
post,
/music/delete,
id
}
响应:
{
"status": 0,
"message": "删除成功!",
"data": true
}
public int deleteById(int musicId) {
return musicMapper.deleteById(musicId);
}
/**
* 删除对应音乐Id的歌曲
* @param musicId 音乐Id
* @return 返回影响行数
*/
int deleteById(int musicId);
<!-- 根据 id 删除音乐 -->
<delete id="deleteById" parameterType="java.lang.Integer">
delete from music where id = #{id}
</delete>
/** * 删除单个音乐 * * @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); } } }
//删除 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("删除失败!"); } } }); }
请求:
{
post,
/music/deletesel,
data:{"id":id}
}
响应:
{
"status": 0,
"message": "批量删除成功",
"data": true
}
/** * 批量进行音乐删除 * * @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); } }
$(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>
有两种:模糊查询和空查询
请求: { get, /music/findmusic, data:{musicName:musicName}, } 响应:【不给musicName传参】 { "status": 0/-1, "message": "", "data": "" } 响应:【给musicName传参】 { "status": 0/-1, "message": "", "data": "" }
public List<Music> findMusic(){
return musicMapper.findMusic();
}
public List<Music> findMusicByName(String musicName){
return musicMapper.findMusicByName(musicName);
}
/**
* 查询所有的音乐
* @return
*/
List<Music> findMusic();
/**
* 查询匹配音乐
* @param musicName
* @return
*/
List<Music> findMusicByName(String musicName);
<!-- 查询所有音乐 -->
<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>
@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);
}
<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下 } }); }
请求:
{
post,
/lovemusic/likemusic
data: id//音乐id
}
响应:
{
"status": 0,
"message": "点赞音乐成功",
"data": true
}
需要看之前是否收藏过
@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); } }
@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); }
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.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>
@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); } } }
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("加入喜欢的列表失败或者已经存在该音乐"); } } }); }
跟之前的主页查询一样
请求: { get, /lovemusic/findlovemusic, data:{musicName:musicName}, } 响应:【不给musicName传参】 { "status": 0/-1, "message": "", "data": "" } 响应:【给musicName传参】 { "status": 0/-1, "message": "", "data": "" }
/** * 查询这个用户收藏过的所有音乐 * @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); }
/**
* 查询这个用户收藏过的所有音乐
* @param userId
* @return
*/
List<Music> findLoveMusicByUserId(Integer userId);
/**
* 查询当前用户,指定为musicName的音乐,支持模糊查询
* @param musicName
* @param userId
* @return
*/
List<Music> findLoveMusicBykeyAndUID(String musicName,Integer userId);
<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>
@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); }
<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下 } }); }
请求:
{
post,
/lovemusic/deletelovemusic,
data:{id:id}
}
响应:
{
"status": 0,
"message": "取消收藏成功!",
"data": true
}
/**
* 移除某个用户喜欢的音乐
* @param userId
* @param musicId
* @return
*/
public int deleteLoveMusic(Integer userId,Integer musicId){
return loveMusicMapper.deleteLoveMusic(userId, musicId);
}
/**
* 移除某个用户喜欢的音乐
* @param userId
* @param musicId
* @return
*/
int deleteLoveMusic(Integer userId,Integer musicId);
<delete id="deleteLoveMusic" parameterType="java.lang.Integer">
delete from lovemusic where user_id=#{userId} and music_id=#{musicId}
</delete>
@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); } }
//移除 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("移除失败!"); } } }); }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。