ToB企服应用市场:ToB评测及商务社交产业平台
标题:
本地音乐服务器(一)
[打印本页]
作者:
熊熊出没
时间:
前天 09:04
标题:
本地音乐服务器(一)
1. 准备工作
1.1 项目创建
修改当前的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.7.17</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>musicServer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>musicServer</name>
<description>musicServer</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</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>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.3.1</version>
</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>
复制代码
1.2 数据库设计
1.2.1 user表
(id,username,password)
1.2.2 music表
(id,title,singer歌手,time上传时间,url音乐存储位置,未来需要播放的时间需要请求的地点,userid这首歌是是谁人用户上传的)
1.2.3 lovemusic表
(id,userid,music_id)绑定关系的表,即某用户喜欢某音乐的关系;
三个表设计如下代码所示:
drop database if exists spring_musicserver;
create database if not exists spring_musicserver character set utf8;
use spring_musicserver;
drop table if exists user;
create table user (
id int primary key auto_increment,
username varchar(20) not null,
password varchar(255) not null
);
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
);
复制代码
1.3 举行properties配置
server.port=8089
#配置数据库
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/spring_musicserver?useUnicode=true&characterEncoding=UTF-8&userSSL=false&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=111111
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
#配置spring日志调试模式是否开启
debug=true
#⽇志级别:trace,debug,info,warn,error
#基本⽇志
logging.level.root=INFO
logging.level.com.example.musicserver.mapper=debug
#扫描的包:druid.sql.Statement类和frank包
logging.level.druid.sql.Statement=DEBUG
logging.level.com.example=DEBUG
复制代码
2. 登录模块设计
2.1创建User类
创建model包,将实体类都存放到该包内里;
package com.example.spring_musicserver.model;
import lombok.Data;
/**
* @version 1.0
* @Author 上嘉路
* @Date 2024/11/13 11:21
* @注释
*/
@Data
public class User {
private int id;
private String username;
private String password;
}
复制代码
2.2创建接⼝UserMapper
新建mapper包,新建UserMapper
@Mapper
public interface UserMapper {
User login(User loginUser);
}
复制代码
2.3 创建UserMapper.xml
在resource⽬录下,新建mybatis⽂件夹,新建UserMapper.xml,下面代码是.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.spring_musicserver_1113.mapper.UserMapper">
<select id="login" resultType="com.example.spring_musicserver_1113.model.User">
select * from user where username=#{username} and password=#{password}
</select>
</mapper>
复制代码
3. 实现登录
3.1 登录的请求和响应设计
响应体设计字段表明:
1、状态码,为0代表乐成,负数代表失败
2、状态形貌信息,形貌此次请求乐成或者失败的缘故原由
3、返回的user范例的数据,请求乐成后,需要给前端的数据信息
对于数据库中的user表中数据添加乐成;
3.2 创建UserController类
在controller包下,创建UserController类
package com.example.spring_musicserver_1113.controller;
/**
* @version 1.0
* @Author 作者名
* @Date 2024/11/13 14:48
* @注释
*/
import com.example.spring_musicserver_1113.mapper.UserMapper;
import com.example.spring_musicserver_1113.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserMapper userMapper;
@RequestMapping("/login")
public void login(@RequestParam String username,
@RequestParam String password) {
User loginUser = new User();
loginUser.setUsername(username);
loginUser.setPassword(password);
User user = userMapper.login(loginUser);
if (user != null) {
System.out.println("登录成功");
} else {
System.out.println("登录失败");
}
}
}
复制代码
向数据库中插入数据举行postman验证接口的精确性设计性:
由此可知当前的代码畅通无阻;
3.3 设计同一的的响应体类工具类
将服务器向客户端给出的响应举行封装;
新建tools工具包,新建ResponseBodyMessage类;
package com.example.spring_musicserver_1113.tools;
import lombok.Data;
/**
* @version 1.0
* @Author 作者名
* @Date 2024/11/13 18:40
* @注释
*/
@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;
}
}
复制代码
对于usercontroller类举行更新:
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserMapper userMapper;
@RequestMapping("/login")
public ResponseBodyMessage<User> login(@RequestParam String username,
@RequestParam String password) {
User loginUser = new User();
loginUser.setUsername(username);
loginUser.setPassword(password);
User user = userMapper.login(loginUser);
if (user == null) {
System.out.println("登录失败!");
return new ResponseBodyMessage<>(-1,"登录失败",loginUser);
} else {
return new ResponseBodyMessage<>(0,"登录成功",loginUser);
}
}
}
复制代码
使用postman举行测试:
此时我们针对响应封装的使用乐成运行,根据响应可以看到,我们的数据容易泄露,且等登录乐成之后就需要把用户信息写到新创建的httpsession内里,修改代码如下所示:
创建constant类,界说常量字符串:
public class Constant {
public static final String USERINFO_SESSION_KEY = "USERINFO_SESSION_KEY";
}
复制代码
修改的usercontroller:
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserMapper userMapper;
@RequestMapping("/login")
public ResponseBodyMessage<User> login(@RequestParam String username,
@RequestParam String password,
HttpServletRequest request) {
User loginUser = new User();
loginUser.setUsername(username);
loginUser.setPassword(password);
User user = userMapper.login(loginUser);
if (user == null) {
System.out.println("登录失败!");
return new ResponseBodyMessage<>(-1,"登录失败",loginUser);
} else {
//request.getSession().setAttribute("USERINFO_SESSION_KEY",user);
//上述代码由于USERINFO_SESSION_KEY是字符串由于容易写错,所以
//创建枚举类constant,来定义一个常量USERINFO_SESSION_KEY为一个字符串,这样就方便我们后期调用
request.getSession().setAttribute(Constant.USERINFO_SESSION_KEY,user);
return new ResponseBodyMessage<>(0,"登录成功",loginUser);
}
}
}
复制代码
HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的全部信息都封装在这个对象中,通过这个对象提供的方法,可以获得客户端请求的全部信息。该对象的getsession,即用于获取与当前请求关联的会话对象, 如果不存在会话对象(第一次登录),则创建一个新的会话。
我们使用postman举行登录验证:
3.4 md5加密使用
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类,代码如下:
public class MD5Util {
//定义⼀个固定的盐值
private static final String salt = "1b2i3t4e";
//进行加密的成员方法
public static String md5(String src) {
return DigestUtils.md5Hex(src);
}
//第⼀次加密:模拟前端⾃⼰加密,然后传到后端
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加密前端加密过的密码,传给后端进⾏第2次加密
⽤⼾数据库当中的盐值
* @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"));
}
}
复制代码
运行结果如下:
3.5 BCrypt加密设计
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})
public class SpringMusicserver1113Application {
public static void main(String[] args) {
SpringApplication.run(SpringMusicserver1113Application.class, args);
}
}
复制代码
bcrypt加密测试代码如下:
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);
}
}
复制代码
BCrypt加密:⼀种加盐的单向Hash,不可逆的加密算法,同⼀种明⽂(plaintext),每次加密后的 密⽂都不⼀样,⽽且不可反向破解⽣成明⽂,破解难度很⼤。
MD5加密:是不加盐的单向Hash,不可逆的加密算法,同⼀个密码经过hash的时间⽣成的是同⼀个 hash值,在⼤多数的情况下,有些经过md5加密的⽅法将会被破解。
Bcrypt⽣成的密⽂是60位的。⽽MD5的是32位的。
⽬前,MD5和BCrypt⽐较流⾏。相对来说,BCrypt⽐MD5更安全,但加密更慢。 虽然BCrpyt也是输⼊的字符串+盐,但是与MD5+盐的重要区别是:每次加的盐差别,导致每次⽣成的 结果也不类似。⽆法⽐对!
3.6 加密登录实现
3.6.1 数据库插⼊数据
将上述BCryptTest运⾏⽣成的对123456加密后的结果,插⼊到数据库当中
3.6.2 UserMapper类新增⽅法
@Mapper
public interface UserMapper {
User login(User loginUser);
User selectByName(String username);
}
复制代码
3.6.3 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.spring_musicserver_1113.mapper.UserMapper">
<select id="login" resultType="com.example.spring_musicserver_1113.model.User">
select * from user where username=#{username} and password=#{password};
</select>
<select id="selectByName" resultType="com.example.spring_musicserver_1113.model.User">
select * from user where username = #{username};
</select>
</mapper>
复制代码
3.6.4 修改UserController类
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserMapper userMapper;
@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
@RequestMapping("/login")
public ResponseBodyMessage<User> login(@RequestParam String username,
@RequestParam String password,
HttpServletRequest request) {
User user = userMapper.selectByName(username);
if (user == null) {
System.out.println("登录失败!");
return new ResponseBodyMessage<>(-1,"用户名或密码错误",user);
} else {
boolean flag = bCryptPasswordEncoder.matches(password,user.getPassword());
if(!flag){
return new ResponseBodyMessage<>(-1,"用户名或密码错误!",user);
}
request.getSession().setAttribute(Constant.USERINFO_SESSION_KEY,user);
return new ResponseBodyMessage<>(0,"登录成功",user);
}
}
}
复制代码
我们这里将创建BCryptPasswordEncoder对象变成了注入该对象,以是就需要举行创建配置相对用类,然后使用注解来注入;
3.6.5 创建包config,新建AppConfig类
@Configuration
public class AppConfig {
@Bean
public BCryptPasswordEncoder getBCryptPasswordEncoder(){
return new BCryptPasswordEncoder();
}
}
复制代码
注解介绍:
@Configuration:表明当前类是⼀个配置类,被注解的类内部包罗有⼀个或多个被@Bean注解的⽅法,⽤于构建bean界说,初始化Spring容器。
@Bean注解:⽤于告诉⽅法,产⽣⼀个Bean对象,然后这个Bean对象交给Spring管理。产⽣这个 Bean对象的⽅法Spring只会调⽤⼀次,随后这个Spring将会将这个Bean对象放在⾃⼰的IOC容器中。
SpringIOC 容器管理⼀个或者多个bean,这些bean都需要在@Configuration注解下进⾏创建,在⼀ 个⽅法上使⽤@Bean注解就表明这个⽅法需要交给Spring进⾏管理。
3.6.6 spring-boot启动类注解
@SpringBootApplication(exclude =
{org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class})
复制代码
当启动类,没有加这个过滤的时间,我们发现不能进⾏登录 ,来由如下:
我们在pom文件内里添加依靠的时间,添加的是spring-security的依靠,但是spring-security是一个很大的框架,我们所使用的org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;(BCryptPasswordEncoder类是spring-security框架下的一个包内里的类,在整个大框架下我们仅仅使用BCryptPasswordEncoder这一个类),以是我们要添加这一行代码来禁止启动步伐扫描spring-security的默认路径,因为在SpringBoot中,默认的SpringSecurity是⽣效了的,此时的接⼝都是被保护的,我们需要通过验证才气正常的访问。此时通过上述配置,即可禁⽤默认的登录验证。
测试登录:
ps:未完待续
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/)
Powered by Discuz! X3.4