前言: 我是一个平时挺喜欢沉浸在音乐声中的人,恰巧今年在学校学了JavaWeb课程,利用寒假业余时间写了一个在线音乐播放器小项目,接下来对它进行一个小小的总结!
在线音乐播放器项目总结
功能分析
这里我简单的把我的想法画了出来:
核心功能
- 简单的注册和登录;
- 上传音乐;
- 删除某首音乐;
- 批量删除多首音乐;
- 查询音乐(包括模糊匹配和指定查找);
- 添加音乐到喜欢列表;
- 查询喜欢列表内的歌曲;
- 从喜欢列表中删除歌曲;
数据库设计
一个用户可以喜欢多首歌,一首歌也可以被多个用户喜欢;因此需要建立一张中间表loveMusic用来表示这种多对多的关系;
User表
属性 | 类型 | 要求 |
---|---|---|
userId | int,auto_increment | primary key(user的唯一标识) |
userName | varchar(30) | unique,not null |
password | varchar(50) | not null |
age | int | not null |
gender | varchar(3) | not null |
varchar(50) | not null |
Music表
属性 | 类型 | 要求 |
---|---|---|
musicId | int,auto_increment | primary key(music的唯一标识) |
title | varchar(60) | not null |
siger | varchar(30) | not null |
time | varchar(40) | not null |
url | varchar(100) | not null |
userId | int | not null |
loveMusic表
属性 | 类型 | 要求 |
---|---|---|
id | int,auto_increment | primary key(loveMusic的唯一标识) |
userId | int | not null |
musicId | int | not null |
服务器API设计
注册
请求:
Post /registerServlet
data:{username,password,age,gender,email}
响应:
{msg : true}
登录
请求:
Post /loginServlet
data: {username,password}
响应:
{msg:true}
上传音乐
请求1:上传音乐到服务器目录
Post /upload
请求2::上传音乐同步插入到数据库中
Post /uploadsucess
删除某首音乐
请求:
Post /deleteServlet
data:{"id":id}
响应:
{msg:true}
批量删除多首音乐
请求:
Post /deleteSelMusicServlet
data:{"id":id}//此处的id为数组
响应:
{msg:true}
查询音乐(包括模糊匹配和指定查找)
请求:
Post /findMusicServlet
data:{musicName:musicName}
添加音乐到喜欢列表
请求:
Post /loveMusicServlet
data:{"id":obj}
响应:
{msg:true}
查询喜欢列表内的歌曲
请求:
Post /findLoveMusic
data:{musicName:musicName}
从喜欢列表中删除歌曲
请求:
Post /removeLoveServlet
data:{"id":obj}
封装数据库操作
使用数据库连接池,减少多次创建(释放)连接带来的开销
单例模式(双重校验锁)
- volatile关键字:一个进程进行读操作,一个线程进行写操作;当实例化dataSource对象时涉及读取操作和修改操作,因此需要使用 volatile;
- synchronized关键字:涉及对象操作非原子性;当实例化dataSource对象时涉及判断对象是否为空,然后再对其进行实例化,操作不是原子的,可能线程不安全,因此需要使用synchronized;
package util;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class DBUtils {
private static String url = "jdbc:mysql://localhost:3306/music_server?characterEncoding=utf-8&useSSL=false";
private static String username = "root";
private static String password = "261919Zss";
private static volatile DataSource dataSource;
private static DataSource getDataSource(){
if (dataSource == null){
synchronized (DBUtils.class){
if (dataSource == null){
dataSource = new MysqlDataSource();
((MysqlDataSource)dataSource).setURL(url);
((MysqlDataSource)dataSource).setUser(username);
((MysqlDataSource)dataSource).setPassword(password);
}
}
}
return dataSource;
}
public static Connection getConnection(){
try {
Connection connection = getDataSource().getConnection();
return connection;
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("数据库连接异常");
}
}
public static void getClose(Connection connection, Statement statement,ResultSet resultSet){
try {
if (resultSet != null){
resultSet.close();
}
if (statement != null){
statement.close();
}
if (connection != null){
connection.close();
}
}catch (SQLException e){
e.printStackTrace();
}
}
public static void getClose(Connection connection, Statement statement){
getClose(connection, statement,null);
}
}
UserDao类(用于user在数据库中的CRUD操作)
MusicDao类(用于music在数据库中的CRUD操作)
Service层(对数据库进行进一步的封装,减少代码的耦合性)
Servlet层的具体实现
注册(登录功能类似)
import Entity.User;
import com.fasterxml.jackson.databind.ObjectMapper;
import service.UserService;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@WebServlet("/registerServlet")
public class RegisterServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置前端的响应格式
resp.setContentType("application/json; charset=utf-8");
//获取到前端提交的数据(获取用户名和密码),并校验用户名密码
String username = req.getParameter("username");
String password = req.getParameter("password");
String age = req.getParameter("age");
String gender = req.getParameter("gender");
String email = req.getParameter("email");
Map<String,Object> message = new HashMap<>();
//根据用户名在数据库中查找,如果存在,则注册失败
UserService userService = new UserService();
User exitsUser =userService.selectByName(username);
if (exitsUser == null){
//根据用户提交的数据,构造user数据,插入数据库
User user = new User();
user.setUsername(username);
user.setPassword(password);
user.setAge(Integer.parseInt(age));
user.setGender(gender);
user.setEmail(email);
userService.register(user);
req.getSession().setAttribute("user", user);//绑定数据
message.put("msg",true);
}else {
message.put("msg",false);
}
//将信息返回给前端
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(resp.getWriter(), message);
}
}
前后端交互过程:
上传功能
需要注意的是在上传过程中,一方面需要将歌曲相关信息写入数据库,与此同时还要将其部署到服务器上去;
运行结果展示
- 注册页面
- 登录页面
源码链接