是小张的在线音乐播放系统项目详解


该项目主要实现的功能如下:

  1. 用户登录
  2. 上传音乐
  3. 删除指定音乐
  4. 批量删除选中的音乐
  5. 查询你想要的音乐(支持模糊查询)
  6. 添加音乐至喜欢的列表
  7. 移除喜欢的音乐

此项目本地访问链接:
http://192.168.126.129:8081/login.html

所实现的主要页面如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

首先应该先创建一个spring boot项目,然后在MySQL中创建数据库。
在项目下创建所需包如下所示:
在这里插入图片描述

一、数据库设计

1.1 创建一个数据库

-- 数据库
drop database if exists `musicserver`;
create database if not exists `musicserver` character set utf8;
-- 使用数据库
use `musicserver`;

1.2 创建user表

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
	`id` INT PRIMARY KEY AUTO_INCREMENT,
	`username` varchar(20) NOT NULL,
	`password` varchar(255) NOT NULL
);

1.3 创建music表

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
);

1.4 创建lovemusic表

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
);

二、配置数据库和xml

接下来就是在项目配置文件中对数据库进行相应的配置。
打开application.properties配置如下信息:

#配置数据库
#spring.datasource.url=jdbc:mysql://127.0.0.1:3306/musicserver?characterEncoding=utf8&serverTimezone=UTC
#spring.datasource.username=root
#spring.datasource.password=123456
#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

#在服务器上进行数据库配置
server.port=8081
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/musicserver?characterEncoding=utf8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

#配置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=F:/Git_demo/java-learning-2/onlinemusic/music1
#音乐上传后服务器路径
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

logging.level.org.springframework.boot.autoconfigure: error

三、登录模块设计

3.1创建一个User

//在package com.example.musicserver.model包中创建User类
package com.example.onlinemusic.model;

import lombok.Data;

/**
 * Created With IntelliJ IDEA
 * Description:
 * Users: yyyyy
 * Date: 2022-08-04
 * Time: 8:33
 */
@Data
public class User {
   
    private int id;
    private String username;
    private String password;

}

3.2 创建对应的Mapper

分别在对应的mapper包下创建UserMapper 接口:

package com.example.onlinemusic.mapper;

import com.example.onlinemusic.model.User;
import org.apache.ibatis.annotations.Mapper;

/**
 * Created With IntelliJ IDEA
 * Description:
 * Users: yyyyy
 * Date: 2022-08-04
 * Time: 8:35
 */
@Mapper
public interface UserMapper {
   
    User login(User loginUser);
}

3.3 创建UserMapper.xml

resource目录下,新建mybatis文件夹,并在此文件夹下新建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.example.onlinemusic.mapper.UserMapper">


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

    <select id="selectByName" resultType="com.example.onlinemusic.model.User">
        select * from user where username=#{username};
    </select>
</mapper>

3.4 登录的请求和响应设计

请求:
{
   
	post,
	/user/login
	data:{
   username,password}
}
响应:
{
   
	"status": 0,
	"message": "登录成功",
	"data": {
   
		"id": xxxxx,
		"username": xxxxxx,
		"password": xxxxxxxx
		}
} 
响应体设计字段解释:
{
   
	状态码,设置为0代表成功,-1代表失败
	状态描述信息,描述此次请求成功或者失败的原因
	返回的数据,请求成功后,需要给前端的数据信息
}

3.5 设计统一的响应体类工具类

tool包下创建ResponseBodyMessage 类:

package com.example.onlinemusic.tools;

import lombok.Data;
/**
 * Created With IntelliJ IDEA
 * Description:
 * Users: yyyyy
 * Date: 2022-08-07
 * Time: 19:19
 */
@Data
public class ResponseBodyMessage <T>{
   
    private int status;//状态码  >=0代表登录成功 <0代表登录失败
    private String message;//返回的信息【出错的原因? 没错的原因?】
    private T data;//返回给前端的数据

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

3.6 创建UserController类

controller包下创建:

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

    @Resource
    private UserMapper userMapper;


    @Resource
    BCryptPasswordEncoder bCryptPasswordEncoder;


    @RequestMapping("/login1")
    public ResponseBodyMessage<User> login1(@RequestParam String username,@RequestParam String password,
                                           HttpServletRequest request){
   
        User userlogin = new User();
        userlogin.setUsername(username);
        userlogin.setPassword(password);

        User user = userMapper.login(userlogin);

        if(user != null){
   
            System.out.println("登录成功!");
//            request.getSession().setAttribute("USERINFO_SESSION_KEY",user);
      //修改session的代码为 :  
      request.getSession().setAttribute(Constant.USERINFO_SESSION_KEY,user);
            return new ResponseBodyMessage<>(0,"登录成功",userlogin);
        }else{
   
            System.out.println("登录失败!");
            return new ResponseBodyMessage<>(-1,"登录失败",userlogin);
        }
    }
 }

这里对注解进行说明:

  • @RestController: @ResponseBody + @Controller合在一起的作用。@Controller注解,表明了这个类是一个控制器类,@ResponseBody表示方法的返回值直接以指定的格式写入Http response body中。
  • @RequestMapping: 使用@RequestMapping 来映射请求,也就是通过它来指定控制器可以处理哪些URL请求
  • @RequestParam:将请求参数绑定到你控制器的方法参数上,如果这个参数是非必传的可以写为:RequestParam(required = false),默认是true。

上述代码中设置了session对象,此时的key值是一个字符串,将来在其他地方获取对应的session需要通过这个字符串获取,但是存在一定的写错的情况。所以,此时建议把他定义为一个常量。在tools包中新建一个Constant类:

package com.example.onlinemusic.tools;

/**
 * Created With IntelliJ IDEA
 * Description:
 * Users: yyyyy
 * Date: 2022-08-07
 * Time: 19:32
 */
public class Constant {
   
    public static final String USERINFO_SESSION_KEY = "USERINFO_SESSION_KEY";
}

登录成功验证

这里在进行验证之前要先在user表中插入用户信息:

INSERT INTO user(username,password)
VALUES("zhang","123");

然后使用postman验证登录功能:
在这里插入图片描述
这里可以看到返回的相应数据,但是对于密码是显式显示的,为了保证用户密码安全,对密码进行相应的加密处理。

BCrypt加密的原理

MD5加密

MD5是一个安全的散列算法,输入两个不同的明文不会得到相同的输出值,根据输出值,不能得到原始的明文,即其过程不可逆;但是虽然不可逆,但是不是说就是安全的。因为自从出现彩虹表后,这样的密码也"不安全"。
彩虹表:彩虹表就是一个庞大的、针对各种可能的字母组合预先计算好的哈希值的集合,不一定是针对MD5算法的,各种算法的都有,有了它可以快速的破解各类密码。越是复杂的密码,需要的彩虹表就越大,现在主流的彩虹表都是100G以上。

不安全的原因:

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

更安全的做法是加盐或者长密码等做法,让整个加密的字符串变的更长,破解时间变慢。密码学的应用安全,是建立在破解所要付出的成本远超出能得到的利益上的。
这里我们介绍加盐的做法:盐是在每个密码中加入一些单词来变成一个新的密码,存入数据库当中

添加相应MD5的依赖:

 <!-- 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>

tools包,新建一个MD5Util类:

package com.example.onlinemusic.tools;

import org.apache.commons.codec.digest.DigestUtils;

/**
 * Created With IntelliJ IDEA
 * Description:
 * Users: yyyyy
 * Date: 2022-08-07
 * Time: 19:48
 */
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加密设计

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

Bcrypt生成的密文是60位的。而MD5的是32位的。Bcrypt破解难度更大。
pom.xml中添加依赖:

 <!-- security依赖包 BCrypt加密(加密)-->
        <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})

它是只用到了此框架下的一个类,所以没有必要将整个框架都加载进来。

启动类如下所示:

package com.example.onlinemusic;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

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

tool包下创建BCryptTest测试类:

package com.example.onlinemusic.tools;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

/**
 * Created With IntelliJ IDEA
 * Description:
 * Users: yyyyy
 * Date: 2022-08-07
 * Time: 20:01
 */
public class BCryptTest {
   
    public static 
  • 7
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值