Java小案例-MusiQ音乐网站

2023-12-24 08:36
文章标签 java 案例 音乐网站 musiq

本文主要是介绍Java小案例-MusiQ音乐网站,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


目录

前言

项目功能

技术栈

后端

前端

开发环境

项目展示

前台-首页-展示

前台-首页-代码

前台-歌单-展示

前台-歌单-代码

前台-歌手-展示

前台-歌手-代码

前台-其他页面展示

后台-登录-展示

后台-登录-代码

后台-首页-展示

首台-首页-代码

后台-其他页面-展示

视频展示

详细步骤及代码

Pom.xml导包

1.启动类

2.过滤器

3.Redis配置

4.application.properties配置文件

5.log4j.properties配置文件

源码获取


前言

本音乐网站的客户端和管理端使用 Vue 框架来实现,服务端使用 Spring Boot + MyBatis 来实现,数据库使用了 MySQL

项目功能

  • 音乐播放
  • 用户登录注册
  • 用户信息编辑、头像修改
  • 歌曲、歌单搜索
  • 歌单打分
  • 歌单、歌曲评论
  • 歌单列表、歌手列表分页显示
  • 歌词同步显示
  • 音乐收藏、下载、拖动控制、音量控制
  • 后台对用户、歌曲、歌手、歌单信息的管理

技术栈

后端

SpringBoot + MyBatis + Redis

前端

Vue3.0 + TypeScript + Vue-Router + Vuex + Axios + ElementPlus + Echarts

开发环境

JDK: jdk-8u141

mysql:mysql-5.7.21-1-macos10.13-x86_64(或者更高版本)

redis:5.0.8

node:14.17.3

IDE:IntelliJ IDEA 2018、VSCode


项目展示

前台-首页-展示

前台-首页-代码

<template><el-container><el-header><yin-header></yin-header></el-header><el-main><router-view /><yin-current-play></yin-current-play><yin-play-bar></yin-play-bar><yin-scroll-top></yin-scroll-top><yin-audio></yin-audio></el-main><el-footer><yin-footer></yin-footer></el-footer></el-container>
</template><script lang="ts" setup>
import { getCurrentInstance } from "vue";
import YinHeader from "@/components/layouts/YinHeader.vue";
import YinCurrentPlay from "@/components/layouts/YinCurrentPlay.vue";
import YinPlayBar from "@/components/layouts/YinPlayBar.vue";
import YinScrollTop from "@/components/layouts/YinScrollTop.vue";
import YinFooter from "@/components/layouts/YinFooter.vue";
import YinAudio from "@/components/layouts/YinAudio.vue";const { proxy } = getCurrentInstance();if (sessionStorage.getItem("dataStore")) {proxy.$store.replaceState(Object.assign({}, proxy.$store.state, JSON.parse(sessionStorage.getItem("dataStore"))));
}window.addEventListener("beforeunload", () => {sessionStorage.setItem("dataStore", JSON.stringify(proxy.$store.state));
});
</script><style lang="scss" scoped>
@import "@/assets/css/var.scss";
@import "@/assets/css/global.scss";.el-container {min-height: calc(100% - 60px);
}
.el-header {padding: 0;
}
.el-main {padding-left: 0;padding-right: 0;
}
</style>

前台-歌单-展示

前台-歌单-代码

<template><div class="play-list-container"><yin-nav :styleList="songStyle" :activeName="activeName" @click="handleChangeView"></yin-nav><play-list :playList="data" path="song-sheet-detail"></play-list><el-paginationclass="pagination"backgroundlayout="total, prev, pager, next":current-page="currentPage":page-size="pageSize":total="allPlayList.length"@current-change="handleCurrentChange"></el-pagination></div>
</template><script lang="ts">
import { defineComponent, ref, computed } from "vue";
import YinNav from "@/components/layouts/YinNav.vue";
import PlayList from "@/components/PlayList.vue";
import { SONGSTYLE } from "@/enums";
import { HttpManager } from "@/api";export default defineComponent({components: {YinNav,PlayList,},setup() {const activeName = ref("全部歌单");const pageSize = ref(15); // 页数const currentPage = ref(1); // 当前页const songStyle = ref(SONGSTYLE); // 歌单导航栏类别const allPlayList = ref([]); // 歌单const data = computed(() => allPlayList.value.slice((currentPage.value - 1) * pageSize.value, currentPage.value * pageSize.value));// 获取全部歌单async function getSongList() {allPlayList.value = ((await HttpManager.getSongList()) as ResponseBody).data;currentPage.value = 1;}// 通过类别获取歌单async function getSongListOfStyle(style) {allPlayList.value = ((await HttpManager.getSongListOfStyle(style)) as ResponseBody).data;currentPage.value = 1;}try {getSongList();} catch (error) {console.error(error);}// 获取歌单async function handleChangeView(item) {activeName.value = item.name;allPlayList.value = [];try {if (item.name === "全部歌单") {await getSongList();} else {await getSongListOfStyle(item.name);}} catch (error) {console.error(error);}}// 获取当前页function handleCurrentChange(val) {currentPage.value = val;}return {activeName,songStyle,pageSize,currentPage,allPlayList,data,handleChangeView,handleCurrentChange,};},
});
</script>

前台-歌手-展示

前台-歌手-代码

<template><div class="play-list-container"><yin-nav :styleList="singerStyle" :activeName="activeName" @click="handleChangeView"></yin-nav><play-list :playList="data" path="singer-detail"></play-list><el-paginationclass="pagination"backgroundlayout="total, prev, pager, next":current-page="currentPage":page-size="pageSize":total="allPlayList.length"@current-change="handleCurrentChange"></el-pagination></div>
</template><script lang="ts" setup>
import { ref, computed } from "vue";
import YinNav from "@/components/layouts/YinNav.vue";
import PlayList from "@/components/PlayList.vue";
import { singerStyle } from "@/enums";
import { HttpManager } from "@/api";// data
const activeName = ref("全部歌手");
const pageSize = ref(15); // 页数
const currentPage = ref(1); // 当前页
const allPlayList = ref([]);
// computed
const data = computed(() => {return allPlayList.value.slice((currentPage.value - 1) * pageSize.value, currentPage.value * pageSize.value);
});// 获取所有歌手
async function getAllSinger() {const result = (await HttpManager.getAllSinger()) as ResponseBody;currentPage.value = 1;allPlayList.value = result.data;
}getAllSinger();// 获取当前页
function handleCurrentChange(val) {currentPage.value = val;
}function handleChangeView(item) {activeName.value = item.name;allPlayList.value = [];if (item.name === "全部歌手") {getAllSinger();} else {getSingerSex(item.type);}
}// 通过性别对歌手分类
async function getSingerSex(sex) {const result = (await HttpManager.getSingerOfSex(sex)) as ResponseBody;currentPage.value = 1;allPlayList.value = result.data;
}
</script>

前台-其他页面展示

后台-登录-展示

后台-登录-代码

<template><div class="login-container"><div class="title">{{ nusicName }}</div><div class="login"><el-form :model="ruleForm" :rules="rules"><el-form-item prop="username"><el-input v-model="ruleForm.username" placeholder="username"></el-input></el-form-item><el-form-item prop="password"><el-input type="password" placeholder="password" v-model="ruleForm.password" @keyup.enter="submitForm"></el-input></el-form-item><el-form-item><el-button class="login-btn" type="primary" @click="submitForm">登录</el-button></el-form-item></el-form></div></div>
</template><script lang="ts">
import { defineComponent, getCurrentInstance, ref, reactive } from "vue";
import mixin from "@/mixins/mixin";
import { HttpManager } from "@/api/index";
import { RouterName, MUSICNAME } from "@/enums";export default defineComponent({setup() {const { proxy } = getCurrentInstance();const { routerManager } = mixin();const nusicName = ref(MUSICNAME);const ruleForm = reactive({username: "admin",password: "123",});const rules = reactive({username: [{ required: true, message: "请输入用户名", trigger: "blur" }],password: [{ required: true, message: "请输入密码", trigger: "blur" }],});async function submitForm() {let username = ruleForm.username;let password = ruleForm.password;const result = (await HttpManager.getLoginStatus({username,password})) as ResponseBody;(proxy as any).$message({message: result.message,type: result.type,});if (result.success) routerManager(RouterName.Info, { path: RouterName.Info });}return {nusicName,ruleForm,rules,submitForm,};},
});
</script><style scoped>
.login-container {position: relative;background: url("../assets/images/background.jpg");background-attachment: fixed;background-position: center;background-size: cover;width: 100%;height: 100%;
}.title {position: absolute;top: 50%;width: 100%;margin-top: -230px;text-align: center;font-size: 30px;font-weight: 600;color: #fff;
}.login {position: absolute;left: 50%;top: 50%;width: 300px;margin: -150px 0 0 -190px;padding: 40px;border-radius: 5px;background: #fff;
}.login-btn {width: 100%;
}
</style>

后台-首页-展示

首台-首页-代码

<template><yin-header></yin-header><yin-aside></yin-aside><div class="content-box" :class="{ 'content-collapse': collapse }"><router-view></router-view></div><yin-audio></yin-audio>
</template><script lang="ts" setup>
import { ref } from "vue";
import YinHeader from "@/components/layouts/YinHeader.vue";
import YinAudio from "@/components/layouts/YinAudio.vue";
import YinAside from "@/components/layouts/YinAside.vue";
import emitter from "@/utils/emitter";const collapse = ref(false);
emitter.on("collapse", (msg) => {collapse.value = msg as boolean;
});
</script><style scoped>
.content-box {position: absolute;left: 150px;right: 0;top: 60px;bottom: 0;overflow-y: scroll;transition: left 0.3s ease-in-out;padding: 20px;
}.content-collapse {left: 65px;
}
</style>

后台-其他页面-展示

视频展示

音乐网站

详细步骤及代码

Pom.xml导包

<?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 http://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.2</version><relativePath/></parent><artifactId>music-server</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><!--web启动 内嵌tomcat--><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></exclusion></exclusions></dependency><!--引入测试--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--mysql-connector-java就是帮助java程序操作mysql的驱动程序。通过与mysql服务端建立连接,发送sql语句并且获取结果集--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.16</version></dependency><!--mybatis用来和数据库进行交互--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.1</version></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.4</version></dependency><!--这里面有点小工具啥的--><!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.8.1</version></dependency><!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.47</version></dependency><!-- Log4j --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-log4j</artifactId><version>1.3.8.RELEASE</version></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-to-slf4j</artifactId><version>2.8.2</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.1</version></dependency><!-- 热部署模块 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!-- redis --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><version>2.6.6</version></dependency><!--<spring2.X集成redis所需common-pool2--><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId><version>2.11.1</version></dependency></dependencies><build><plugins><!-- 加上这段代码  打包插件 因为启动不起来 --><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>2.22.1</version><configuration><skipTests>true</skipTests></configuration></plugin></plugins></build></project>

1.启动类

package com.example.yin;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
@MapperScan("com.example.yin.mapper")
public class YinMusicApplication {public static void main(String[] args) {SpringApplication.run(YinMusicApplication.class, args);}}

2.过滤器

package com.example.yin.config;import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class CorsInterceptor extends HandlerInterceptorAdapter {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");response.setHeader("Access-Control-Max-Age", "3600");response.setHeader("Access-Control-Allow-Headers", "x_requested_with,x-requested-with,Authorization,Content-Type,token");response.setHeader("Access-Control-Allow-Credentials", "true");return true;}
}

3.Redis配置

package com.example.yin.config;import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;import java.time.Duration;@EnableCaching //开启缓存注解
@Configuration
public class RedisConfig extends CachingConfigurerSupport {@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template = new RedisTemplate<>();RedisSerializer<String> redisSerializer = new StringRedisSerializer();Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);ObjectMapper om = new ObjectMapper();om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(om);template.setConnectionFactory(factory);//key序列化方式template.setKeySerializer(redisSerializer);//value序列化template.setValueSerializer(jackson2JsonRedisSerializer);//value hashmap序列化template.setHashValueSerializer(jackson2JsonRedisSerializer);return template;}@Beanpublic CacheManager cacheManager(RedisConnectionFactory factory) {RedisSerializer<String> redisSerializer = new StringRedisSerializer();Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);//解决查询缓存转换异常的问题ObjectMapper om = new ObjectMapper();om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(om);// 配置序列化(解决乱码的问题),过期时间600秒RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(600)).serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer)).serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)).disableCachingNullValues();return RedisCacheManager.builder(factory).cacheDefaults(config).build();}
}

4.application.properties配置文件

mybatis.typeAliasesPackage=com.example.yin.model.domain
mybatis.mapperLocations=classpath:mapper/*.xml
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
server.port=8888
#热部署生效
spring.devtools.restart.enabled=false
#设置重启的目录
spring.devtools.restart.additional-paths=src/main/java
#classpath目录下的WEB-INF文件夹内容修改不重启
spring.devtools.restart.exclude=WEB-INF/**
# 关闭CONDITIONS EVALUATION REPORT及自动配置内容向控制台的输出
logging.level.org.springframework.boot.autoconfigure=ERROR
# redis相应的地址  还有一些配置
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.database=0
spring.redis.timeout=1800000
spring.redis.lettuce.pool.max-active=20
spring.redis.lettuce.pool.max-wait=-1
#最大阻塞等待时间(负数表示没限制)
spring.redis.lettuce.pool.max-idle=5
spring.redis.lettuce.pool.min-idle=0
spring.profiles.active=dev

5.log4j.properties配置文件

# LOG4J
log4j.rootCategory=INFO, stdout,file# print to console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L - %m%n# print to file
log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.DatePattern='-'yyyy-MM-dd'.log'
log4j.appender.file.File=./logs/musicWebsite
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} %p [%c]: %m%n

源码获取

        ✨还可以关注宫纵号《编程乐学》,菜单栏有很多优质的开源项目以及更多的编程资料等你来学习。

这篇关于Java小案例-MusiQ音乐网站的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/531196

相关文章

Java对象和JSON字符串之间的转换方法(全网最清晰)

《Java对象和JSON字符串之间的转换方法(全网最清晰)》:本文主要介绍如何在Java中使用Jackson库将对象转换为JSON字符串,并提供了一个简单的工具类示例,该工具类支持基本的转换功能,... 目录前言1. 引入 Jackson 依赖2. 创建 jsON 工具类3. 使用示例转换 Java 对象为

SpringBoot快速接入OpenAI大模型的方法(JDK8)

《SpringBoot快速接入OpenAI大模型的方法(JDK8)》本文介绍了如何使用AI4J快速接入OpenAI大模型,并展示了如何实现流式与非流式的输出,以及对函数调用的使用,AI4J支持JDK8... 目录使用AI4J快速接入OpenAI大模型介绍AI4J-github快速使用创建SpringBoot

Java中的Cursor使用详解

《Java中的Cursor使用详解》本文介绍了Java中的Cursor接口及其在大数据集处理中的优势,包括逐行读取、分页处理、流控制、动态改变查询、并发控制和减少网络流量等,感兴趣的朋友一起看看吧... 最近看代码,有一段代码涉及到Cursor,感觉写法挺有意思的。注意是Cursor,而不是Consumer

解决java.lang.NullPointerException问题(空指针异常)

《解决java.lang.NullPointerException问题(空指针异常)》本文详细介绍了Java中的NullPointerException异常及其常见原因,包括对象引用为null、数组元... 目录Java.lang.NullPointerException(空指针异常)NullPointer

javaScript在表单提交时获取表单数据的示例代码

《javaScript在表单提交时获取表单数据的示例代码》本文介绍了五种在JavaScript中获取表单数据的方法:使用FormData对象、手动提取表单数据、使用querySelector获取单个字... 方法 1:使用 FormData 对象FormData 是一个方便的内置对象,用于获取表单中的键值

前端知识点之Javascript选择输入框confirm用法

《前端知识点之Javascript选择输入框confirm用法》:本文主要介绍JavaScript中的confirm方法的基本用法、功能特点、注意事项及常见用途,文中通过代码介绍的非常详细,对大家... 目录1. 基本用法2. 功能特点①阻塞行为:confirm 对话框会阻塞脚本的执行,直到用户作出选择。②

SpringBoot项目注入 traceId 追踪整个请求的日志链路(过程详解)

《SpringBoot项目注入traceId追踪整个请求的日志链路(过程详解)》本文介绍了如何在单体SpringBoot项目中通过手动实现过滤器或拦截器来注入traceId,以追踪整个请求的日志链... SpringBoot项目注入 traceId 来追踪整个请求的日志链路,有了 traceId, 我们在排

Java实战之利用POI生成Excel图表

《Java实战之利用POI生成Excel图表》ApachePOI是Java生态中处理Office文档的核心工具,这篇文章主要为大家详细介绍了如何在Excel中创建折线图,柱状图,饼图等常见图表,需要的... 目录一、环境配置与依赖管理二、数据源准备与工作表构建三、图表生成核心步骤1. 折线图(Line Ch

Spring Boot 3 整合 Spring Cloud Gateway实践过程

《SpringBoot3整合SpringCloudGateway实践过程》本文介绍了如何使用SpringCloudAlibaba2023.0.0.0版本构建一个微服务网关,包括统一路由、限... 目录引子为什么需要微服务网关实践1.统一路由2.限流防刷3.登录鉴权小结引子当前微服务架构已成为中大型系统的标

Java集合中的List超详细讲解

《Java集合中的List超详细讲解》本文详细介绍了Java集合框架中的List接口,包括其在集合中的位置、继承体系、常用操作和代码示例,以及不同实现类(如ArrayList、LinkedList和V... 目录一,List的继承体系二,List的常用操作及代码示例1,创建List实例2,增加元素3,访问元