Spring Boot音乐服务器项目-登录模块

发布于:2025-07-23 ⋅ 阅读:(14) ⋅ 点赞:(0)

登录模块->项目结构图

一、项目准备与数据库设计

1. 创建Spring Boot项目

  • 先创建一个Maven项目:

  • 项目结构图如上

2. 数据库设计

-- 创建数据库
CREATE DATABASE IF NOT EXISTS musicserver CHARACTER SET utf8;

USE musicserver;

-- 用户表
CREATE TABLE user (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(20) NOT NULL,
    password VARCHAR(255) NOT NULL
);

-- 音乐表
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
);

-- 收藏表
CREATE TABLE lovemusic (
    id INT PRIMARY KEY AUTO_INCREMENT,
    user_id INT(11) NOT NULL,
    music_id INT(11) NOT NULL
);

二、项目配置

整体项目的pom依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>musicplayer</artifactId>(自己项目名称)
    <version>0.0.1-SNAPSHOT</version>
    <name>musicplayer</name>(自己项目名称)
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- mybatis 依赖 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.2</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

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

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

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>
application.properties配置(resources包下)
# 数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/musicserver?characterEncoding=utf8&serverTimezone=UTC
spring.datasource.username=root(自己数据库)
spring.datasource.password=123456(自己数据库)
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# MyBatis配置
mybatis.mapper-locations=classpath:mybatis/**Mapper.xml

# 文件上传大小限制
spring.servlet.multipart.max-file-size=15MB
spring.servlet.multipart.max-request-size=100MB

# 日志配置
logging.level.com.example.musicserver.mapper=debug

三、登录模块实现

1. 用户实体类(model->User)
@Data
public class User {
    private int id;
    private String username;
    private String password;
}
2. Mapper接口与XML
// UserMapper.java
@Mapper
public interface UserMapper {
    User selectByName(String username);
}
<!-- UserMapper.xml -->
<select id="selectByName" resultType="com.example.musicserver.model.User">
    SELECT * FROM user WHERE username=#{username}
</select>

3. 统一响应信息工具类(tools->ResponseBodyMessage)

@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;
    }
}

4. 登录控制器(Controller层)

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserMapper userMapper;
    
    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @PostMapping("/login")
    public ResponseBodyMessage<User> login(
            @RequestParam String username,
            @RequestParam String password,
            HttpServletRequest request) {
        
        User userInfo = userMapper.selectByName(username);
        
        if (userInfo == null || !bCryptPasswordEncoder.matches(password, userInfo.getPassword())) {
            return new ResponseBodyMessage<>(-1, "用户名或密码错误", null);
        }
        
        request.getSession().setAttribute(Constant.USERINFO_SESSION_KEY, userInfo);
        return new ResponseBodyMessage<>(0, "登录成功", userInfo);
    }
}

注解介绍:

@RestController:@ResponseBody+ @Controller合在⼀起的作⽤。@Controller注解,表明了这 个类是⼀个控制器类 ,@ResponseBody表⽰⽅法的返回值直接以指定的格式写⼊Http response  body中 。 

@RequestMapping:使⽤ @RequestMapping来映射请求,也就是通过它来指定控制器可以处理哪 些URL请求 

@RequestParam:将请求参数绑定到你控制器的⽅法参数上 。

如果这个参数是⾮必传的可以写为: @RequestParam(required = false) ,默认是true.  

5. 常量类(tools->Constant)

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

6. BCrypt加密配置

  • BCrypt加密: 一种加盐的单向Hash,不可逆的加密算法,同一种明文(plaintext),每次加密后的密文都不一样,而且不可反向破解生成明文,破解难度很大。

  • MD5加密: 是不加盐的单向Hash,不可逆的加密算法,同一个密码经过hash的时候生成的是同一个hash值,在大多数的情况下,有些经过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>
<dependency>
 <groupId>org.springframework.security</groupId>
 <artifactId>spring-security-web</artifactId>
</dependency>
<dependency>
 <groupId>org.springframework.security</groupId>
 <artifactId>spring-security-config</artifactId>
</dependency>

接下来就创建⼀个tools包,新建MD5Util类 

package com.example.musicplayer.tools;

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

/**
 @Author hy
 @Description:
 */
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"));
    }
}

创建⼀个tools包,新建BCryptTest类 

package com.example.musicplayer.tools;

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

/**
 * @Author 12629
 * @Date 2022/4/11 14:29
 * @Description:
 */
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);

    }
}

基于此我们来实现加密登录!

UserMapper新增逻辑

@Mapper

public interface UserMapper {
 User login(User loginUser);
 //username⽤⼾名是唯⼀的 
 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.example.musicserver.mapper.UserMapper">
 <select id="login" resultType="com.example.musicserver.model.User">
 select * from user where username=#{username} and password=#{password}
 </select>
 <select id="selectByName" resultType="com.example.musicserver.model.User">
 select * from user where username=#{username}
 </select>
</mapper>

修改UserController类

@RestController//@ResponseBody + @Controller合在⼀起的作⽤ 

@RequestMapping("/user")//使⽤ @RequestMapping 来映射请求,也就是通过它来指定控制器可
以处理哪些URL请求 

public class UserController {
 @Autowired

 private UserMapper userMapper;
 @Autowired//在⾃动装配之前,需要完成注⼊,我们再AppConfig中进⾏注⼊ 
 private BCryptPasswordEncoder bCryptPasswordEncoder;
 @RequestMapping("/login")

 public ResponseBodyMessage<User> login(@RequestParam String username, 

@RequestParam String password, HttpServletRequest request) {
 User loginUser = new User();
 loginUser.setUsername(username);
 loginUser.setPassword(password);
 System.out.println(loginUser);
 User userInfo = userMapper.selectByName(username);
 if(userInfo == null) {
 return new ResponseBodyMessage<>(-1,"⽤⼾名或者密码错误",userInfo);
 }else {
 

if(!bCryptPasswordEncoder.matches(password,userInfo.getPassword())) {
 return new ResponseBodyMessage<>(-1,"⽤⼾名或者密码错
误",userInfo);
 }
 
request.getSession().setAttribute(Constant.USERINFO_SESSION_KEY,userInfo);
 return new ResponseBodyMessage<>(0,"登录成功",userInfo);
 }
 }
}

@Autowired:可以更准确地控制应该在何处以及如何进⾏⾃动装配。

此注解⽤于在setter⽅法,构造 函数,具有任意名称或多个参数的属性或⽅法上⾃动装配bean。默认情况下,它是类型驱动的注⼊ 

上面我们提到了在⾃动装配之前,需要完成注⼊,我们再AppConfig中进⾏注⼊

创建包config,新建AppConfig类

@Configuration
public class AppConfig {
    @Bean
    public BCryptPasswordEncoder getBCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

7. 启动类配置

@SpringBootApplication(exclude = {SecurityAutoConfiguration.class})
public class MusicserverApplication {
    public static void main(String[] args) {
        SpringApplication.run(MusicserverApplication.class, args);
    }
}

四、密码加密原理

BCrypt vs MD5对比:

特性 BCrypt MD5
安全性 高(每次加密结果不同) 中(彩虹表可破解)
密文长度 60位 32位
盐值处理 自动生成随机盐 需手动加盐
破解难度 极高 中等
适用场景 高安全需求(如金融) 一般安全需求

五、功能测试

登录测试:

  1. 使用Postman发送POST请求

  2. URL:http://localhost:8080/user/login

  3. 参数:username=bit&password=123456

  4. 成功响应:

{
    "status": 0,
    "message": "登录成功",
    "data": {
        "id": ,
        "username": "",
        "password": ""
    }
}

这是我自己成功的数据

这是错误的数据,因为数据库就没有这组

所有内容在:Jared/音乐服务器 - 码云


网站公告

今日签到

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