实验四-音乐红茶馆
音乐红茶馆
目录
音乐红茶馆网站
实验概述
本次实验,我们小组)的目标是设计并实现一个名为“音乐红茶馆”的JSP网站。实验的核心目的在于深入掌握JSP的核心技术,包括固定模板元素、各种JSP标签的使用、网站的基本架构设计,以及JSP内置对象(如Request和Response)的运用。同时,我们还希望通过实践,熟悉网页多媒体技术的应用,特别是音频和动画的集成,并最终理解JSP强大的页面显示功能。
实现方法分析
我们的网站采用了经典的三级页面结构:首页、导航页面和内容页面。
- 前端页面实现:我们使用HTML和CSS进行页面布局和美化。首页的布局主要依靠
border="0"的表格进行排版,以实现稳定的页面结构。为了提升用户体验,我们大量运用了CSS3动画,例如首页中下落的音符、茶杯,以及标题文字的动态效果,这些动画替代了传统且已被淘汰的Flash技术。 - 后台逻辑处理:网站的核心交互功能,特别是“乐迷建议”模块,由JSP和Java Servlet共同实现。我们设计了一个表单页面(
suggest.jsp),用户可以在其中提交建议。当用户点击提交按钮后,表单数据会被发送到后台的Servlet(Suggestrequest.java)。该Servlet通过HttpServletRequest对象获取用户输入的数据,进行简单的非法字符过滤后,将其存入数据库。随后,页面会跳转回建议列表页面,通过JSTL标签和EL表达式,将数据库中的所有建议动态地展示给用户。
关键技术点
- JSP内置对象(Request/Response)的使用:这是本次实验的核心。
request对象被用来获取表单提交的数据,而response对象则用于设置响应的编码格式,并向客户端返回操作结果(如成功提示)。 - 网页多媒体技术(音频/动画)的应用:我们成功地在页面中集成了背景音乐和交互式音效。通过
<audio>标签和JavaScript,我们实现了背景音乐的播放控制。同时,利用CSS3的@keyframes和animation属性,我们创造出流畅的动画效果,增强了网站的视觉吸引力。 - 表单数据提交与后台处理:我们设计了一个完整的“提交-处理-反馈”流程。前端表单使用
POST方法提交数据,后台Servlet接收并处理,最后通过response.getWriter().write()向客户端返回JavaScript提示,实现了友好的用户反馈。 - 数据库交互:通过JDBC连接MySQL数据库,我们实现了建议的持久化存储和读取。
DBUtil.java封装了数据库连接逻辑,使得代码更加模块化和易于维护。
实验成果
结果介绍
我们成功构建了一个功能完整、界面美观的音乐主题网站。网站包含以下主要功能:
-
欢迎页面:带有动画效果的欢迎界面和背景音乐。
![image]()
![image]()
-
导航系统:包含“首页”、“音乐主题”、“音乐品鉴”、“乐迷建议”四个主要导航链接。
![image]()
-
音乐主题与品鉴:展示了R&B音乐的不同风格和品鉴要点。
![image]()
![image]()
-
交互式音乐播放:在
rnb.jsp页面中,用户可以点击“胶片”图标,弹出一个播放器,并播放对应的音乐。
![image]()
-
乐迷建议系统:用户可以提交建议,并在页面上看到所有已提交的建议列表。
![image]()
代码分析
index.html
点击查看代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>R&B 音乐红茶馆</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: "微软雅黑", sans-serif; background-color: #ffffff; }
#start-screen {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #2c2420;
z-index: 9999;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
transition: opacity 1s ease;
}
#start-btn {
padding: 15px 40px;
font-size: 24px;
color: #d4a373;
background: transparent;
border: 2px solid #d4a373;
border-radius: 50px;
cursor: pointer;
transition: all 0.3s;
font-family: "微软雅黑", sans-serif;
}
#start-btn:hover {
background: #d4a373;
color: #2c2420;
box-shadow: 0 0 20px #d4a373;
}
.falling-container { width: 100%; height: 200px; background-color: #8B0000; position: relative; overflow: hidden; }
.falling { position: absolute; color: #fff; font-size: 20px; opacity: 0.7; animation: fall linear infinite; }
@keyframes fall { 0% { transform: translateY(-20px) rotate(0deg); opacity: 0; }
10% { opacity: 0.7; }
90% { opacity: 0.7; }
100% { transform: translateY(200px) rotate(360deg); opacity: 0; } }
.nav-bar { width: 100%; background-color: #8B0000; }
.nav-bar td { text-align: center; padding: 12px 0; }
.nav-bar a { color: #ffffff; text-decoration: none; font-size: 18px; display: block; }
.nav-bar a:hover { background-color: #A0522D; }
.content-area { padding: 30px; background-color: #2c2420; color: #f0e6d2; }
.content-area h3 { font-size: 22px; margin-bottom: 15px; color: #f0e6d2; }
.content-area ul { list-style-type: disc; padding-left: 25px; font-size: 18px; line-height: 1.8; }
.tea-house-container { text-align: left; margin-bottom: 30px; padding: 10px 0; }
.line-1 { font-size: 32px; font-weight: bold; margin: 0; white-space: nowrap; color: #d4a373; position: relative; animation: firstShow 1.5s ease forwards 0.2s, typeWriter 10s steps(18) infinite 3s, fadeUp 10s 13s infinite, breath 10s 23s infinite, shine 10s 33s infinite, rotateFade 10s 43s infinite; }
.line-2 { font-size: 20px; margin-top: 15px; white-space: nowrap; color: #f0e6d2; position: relative; animation: firstShow 1.8s ease forwards 1s, typeWriter 15s steps(32) infinite 5s, fadeUp 10s 15s infinite, breath 10s 25s infinite, shine 10s 35s infinite, rotateFade 10s 45s infinite; }
@keyframes firstShow {
0% { opacity: 0; transform: translateY(20px); }
100% { opacity: 1; transform: translateY(0); } }
@keyframes typeWriter {
0% { opacity:0; }
20% { opacity:1; } 80% { opacity:1; } 100% { opacity:0; } }
@keyframes fadeUp {
0% { opacity:0; transform:translateY(30px); }
20% { opacity:1; transform:translateY(0); }
80% { opacity:1; transform:translateY(0); }
100% { opacity:0; transform:translateY(-20px); } }
@keyframes breath {
0% { opacity:0.3; transform:scale(1); }
50% { opacity:1; transform:scale(1.02); }
100% { opacity:0.3; transform:scale(1); } }
@keyframes shine {
0% { color:#f0e6d2; opacity:1; }
50% { color:#fff; text-shadow:0 0 10px #d4a373; }
100% { color:#f0e6d2; opacity:1; } }
@keyframes rotateFade {
0% { opacity:0; transform:rotate(-1deg) scale(0.95); }
30% { opacity:1; transform:rotate(0) scale(1); }
70% { opacity:1; transform:rotate(0) scale(1); }
100% { opacity:0; transform:rotate(1deg) scale(0.95); } }
.footer-area { width: 100%; text-align: center; padding: 20px; color: #666; font-size: 14px; border-top: 1px solid #eee; background: #fff; }
</style>
<audio id="bg-music" src="music/rb_bgm.mp3" loop muted></audio>
</head>
<body>
<div id="start-screen">
<h2 style="color: #d4a373; margin-bottom: 30px; font-size: 28px;">R&B 音乐红茶馆</h2>
<button id="start-btn">点击进入音乐空间</button>
</div>
<table width="100%" border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<div class="falling-container">
<span class="falling" style="left:10%; animation-duration: 5s;">♪</span>
<span class="falling" style="left:20%; animation-duration: 7s;">♫</span>
<span class="falling" style="left:30%; animation-duration: 6s;">☕</span>
<span class="falling" style="left:40%; animation-duration: 8s;">♪</span>
<span class="falling" style="left:50%; animation-duration: 5s;">♫</span>
<span class="falling" style="left:60%; animation-duration: 7s;">☕</span>
<span class="falling" style="left:70%; animation-duration: 6s;">♪</span>
<span class="falling" style="left:80%; animation-duration: 8s;">♫</span>
<span class="falling" style="left:90%; animation-duration: 5s;">☕</span>
</div>
</td>
</tr>
<tr>
<td>
<table width="100%" border="0" cellpadding="0" cellspacing="0" class="nav-bar">
<tr>
<td><a href="javascript:void(0)">首页</a></td>
<td><a href="theme.jsp">音乐主题</a></td>
<td><a href="taste.jsp">音乐品鉴</a></td>
<td><a href="suggest.jsp">乐迷建议</a></td>
</tr>
</table>
</td>
</tr>
<tr>
<td class="content-area">
<div class="tea-house-container">
<h1 class="line-1">欢迎来到 R&B 音乐红茶馆</h1>
<p class="line-2">这里是放松灵魂的音乐空间,慢节奏R&B,如同红茶般温润治愈</p>
</div>
<h3>今日推荐</h3>
<ul>
<li>R&B经典金曲</li>
<li>新生代灵魂乐</li>
<li>华语节奏蓝调</li>
</ul>
</td>
</tr>
<tr>
<td class="footer-area">
集美大学 · 音乐红茶馆JSP网站 © 2026 网安2413 21小组
</td>
</tr>
</table>
<script>
var startBtn = document.getElementById('start-btn');
var startScreen = document.getElementById('start-screen');
var audio = document.getElementById('bg-music');
startBtn.addEventListener('click', function() {
audio.muted = false;
audio.play();
startScreen.style.opacity = '0';
setTimeout(function() {
startScreen.style.display = 'none';
}, 1000);
});
</script>
</body>
</html>
rnb.jsp
点击查看代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>经典复古 R&B - 音乐红茶馆</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: "微软雅黑", sans-serif; background-color:#2c2420; }
.content-area {
padding: 30px;
background-color: #2c2420;
color: #f0e6d2;
min-height: 100vh;
}
.theme-title {
font-size: 32px;
font-weight: bold;
color: #d4a373;
margin-bottom: 20px;
animation: firstShow 1.5s ease forwards 0.2s;
}
.theme-subtitle {
font-size: 20px;
color: #f0e6d2;
margin-bottom: 30px;
animation: firstShow 1.8s ease forwards 0.8s;
}
@keyframes firstShow {
0% { opacity: 0; transform: translateY(20px); }
100% { opacity: 1; transform: translateY(0); }
}
.vinyl-container {
display: flex;
flex-direction: column;
align-items: center;
gap: 50px;
margin: 40px 0;
padding-bottom: 60px;
}
.vinyl-card {
width: 180px;
height: 180px;
position: relative;
cursor: pointer;
transition: all 0.4s ease;
}
.vinyl {
width: 100%;
height: 100%;
border-radius: 50%;
background: radial-gradient(circle at 30% 30%, #333, #000);
position: relative;
box-shadow: 0 0 15px rgba(0,0,0,0.5);
transition: transform 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
font-size: 30px;
color: #d4a373;
}
.vinyl::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 40px;
height: 40px;
background: #2c2420;
border-radius: 50%;
border: 2px solid #d4a373;
}
.vinyl-card:hover .vinyl {
animation: spin 3s linear infinite;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.vinyl-name {
text-align: center;
margin-top: 15px;
color: #d4a373;
font-size: 16px;
}
.player-modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.9);
z-index: 9999;
align-items: center;
justify-content: center;
padding: 40px;
}
.player-modal.active {
display: flex;
}
.modal-vinyl-half {
width: 50%;
display: flex;
justify-content: center;
align-items: center;
}
.modal-vinyl {
width: 300px;
height: 300px;
border-radius: 50%;
background: radial-gradient(circle at 30% 30%, #333, #000);
position: relative;
box-shadow: 0 0 30px rgba(212,163,115,0.5);
animation: spin 3s linear infinite;
}
.modal-vinyl::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 60px;
height: 60px;
background: #2c2420;
border-radius: 50%;
border: 3px solid #d4a373;
}
.lyrics-half {
width: 50%;
color: #f0e6d2;
padding: 40px;
font-size: 18px;
line-height: 2;
text-align: center;
overflow-y: auto;
max-height: 100%;
}
.lyrics-title {
color: #d4a373;
font-size: 24px;
margin-bottom: 20px;
}
.close-btn {
position: absolute;
top: 30px;
right: 40px;
color: #d4a373;
font-size: 30px;
cursor: pointer;
transition: transform 0.3s;
}
.close-btn:hover {
transform: scale(1.2);
}
</style>
</head>
<body>
<table width="100%" border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="content-area">
<h1 class="theme-title">敬请收听 R&B </h1>
<p class="theme-subtitle">源自上世纪的灵魂之声,醇厚如陈年红茶</p>
<div class="vinyl-container">
<div class="vinyl-card" data-audio="../mp3/MabelWedontSay.mp3">
<div class="vinyl">🎵</div>
<div class="vinyl-name">经典灵魂乐</div>
</div>
<div class="vinyl-card" data-audio="../mp3/AshantiChristmasTimeAgain.mp3">
<div class="vinyl">🎵</div>
<div class="vinyl-name">慢板抒情R&B</div>
</div>
<div class="vinyl-card" data-audio="../mp3/TheMarvelettesllKeepHoldingOn.mp3">
<div class="vinyl">🎵</div>
<div class="vinyl-name">摩城金曲</div>
</div>
</div>
</td>
</tr>
</table>
<div class="player-modal" id="playerModal">
<div class="close-btn" id="closeBtn">×</div>
<div class="modal-vinyl-half">
<div class="modal-vinyl"></div>
</div>
<div class="lyrics-half">
<div class="lyrics-title" id="lyricsTitle">歌曲名称</div>
<div id="lyricsContent"></div>
</div>
</div>
<script>
const audioPlayer = new Audio();
const modal = document.getElementById('playerModal');
const modalLyricsTitle = document.getElementById('lyricsTitle');
const modalLyricsContent = document.getElementById('lyricsContent');
const closeBtn = document.getElementById('closeBtn');
// 全局记录当前播放的歌曲
let currentAudioSrc = '';
document.querySelectorAll('.vinyl-card').forEach(card => {
const audioSrc = card.getAttribute('data-audio');
const songName = card.querySelector('.vinyl-name').textContent;
// 悬停播放(预览)
card.addEventListener('mouseenter', () => {
if (modal.classList.contains('active')) return; // 放大时不触发悬停
currentAudioSrc = audioSrc;
audioPlayer.src = audioSrc;
audioPlayer.volume = 0.3;
audioPlayer.play().catch(() => {});
});
// 离开暂停(只有没放大时才暂停)
card.addEventListener('mouseleave', () => {
if (!modal.classList.contains('active')) {
audioPlayer.pause();
}
});
// 点击放大 → 继续播放,不中断
card.addEventListener('click', () => {
currentAudioSrc = audioSrc;
audioPlayer.src = audioSrc;
audioPlayer.volume = 1;
audioPlayer.play().catch(() => {});
modal.classList.add('active');
modalLyricsTitle.textContent = songName;
modalLyricsContent.innerHTML = `
<p>【经典复古 R&B 歌词】</p>
<p>旋律在时光里流淌</p>
<p>灵魂在音符中安放</p>
<p>醇厚的嗓音诉说过往</p>
<p>每一句都是温柔的诗行</p>
<p>...</p>
`;
});
});
// 关闭弹窗 → 停止音乐
closeBtn.onclick = () => {
modal.classList.remove('active');
audioPlayer.pause();
audioPlayer.currentTime = 0;
};
</script>
</body>
</html>
suggest.jsp
点击查看代码
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" language="java"%>
<%@ page import="java.util.*" %>
<%@ page import="java.sql.*" %>
<%@ page import="test.*" %>
<%
List<Suggest> suggests = new ArrayList<>();
try (Connection conn = DBUtil.getConn()) {
String sql = "SELECT * FROM suggest";
PreparedStatement pstmt = conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
Suggest s = new Suggest();
s.setUsername(rs.getString("username"));
s.setContent(rs.getString("content"));
suggests.add(s);
}
}catch (Exception e) {
e.printStackTrace();
}
request.setAttribute("suggests", suggests);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>乐迷建议 - 音乐红茶馆</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: "Microsoft YaHei", Arial, sans-serif;
background-color: #fdfaf6;
color: #444;
}
.container {
max-width: 900px;
margin: 0 auto;
padding: 20px;
}
h1 {
text-align: center;
color: #8b6f47;
margin: 20px 0;
font-size: 26px;
}
/* 导航 */
.nav {
background-color: #d9c7b8;
text-align: center;
height: 50px;
line-height: 50px;
}
.nav a {
margin: 0 18px;
text-decoration: none;
color: #5a4633;
font-size: 15px;
font-weight: bold;
}
.nav a:hover {
color: #fff;
}
/* 表单样式 */
.form-box {
background: #fff;
padding: 25px;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
margin-bottom: 30px;
}
.form-box input, .form-box textarea {
width: 100%;
padding: 12px;
margin: 10px 0;
border: 1px solid #ddd;
border-radius: 6px;
font-size: 14px;
font-family: "Microsoft YaHei";
}
.form-box button {
background: #d9c7b8;
color: #5a4633;
border: none;
padding: 12px 25px;
border-radius: 6px;
cursor: pointer;
font-weight: bold;
}
.form-box button:hover {
background: #8b6f47;
color: #fff;
}
/* 表格 */
.suggest-table {
width: 100%;
border-collapse: collapse;
background: #fff;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
}
.suggest-table th {
background-color: #e9ded4;
color: #6d4c41;
padding: 14px;
text-align: center;
}
.suggest-table td {
padding: 12px;
border-bottom: 1px solid #f1f1f1;
text-align: center;
}
.empty {
text-align: center;
color: #999;
padding: 30px 0;
}
</style>
</head>
<body>
<div class="nav">
<a href="index.html">首页</a>
<a href="theme.jsp">音乐主题</a>
<a href="taste.jsp">音乐品鉴</a>
<a href="suggest.jsp">乐迷建议</a>
</div>
<div class="container">
<h1>乐迷建议</h1>
<div class="form-box">
<form action="../suggestAdd" method="post">
<input type="text" name="username" placeholder="请输入用户名" required><br>
<textarea name="content" rows="5" placeholder="请输入你的建议..." required></textarea><br>
<button type="submit">提交建议</button>
</form>
</div>
<!-- 建议列表 -->
<table class="suggest-table">
<tr>
<th>用户名</th>
<th>建议内容</th>
</tr>
<%
if (suggests != null && !suggests.isEmpty()) {
for (Suggest s : suggests) {
%>
<tr>
<td><%= s.getUsername() %></td>
<td style="text-align: left;"><%= s.getContent() %></td>
</tr>
<%
}
} else {
%>
<tr>
<td colspan="2" class="empty">暂无建议</td>
</tr>
<%
}
%>
</table>
</div>
</body>
</html>
taste.jsp
点击查看代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>音乐品鉴 - R&B 音乐红茶馆</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: "微软雅黑", sans-serif; background-color: #ffffff; }
.nav-bar { width: 100%; background: transparent; }
.nav-bar td { text-align: center; padding: 12px 0; }
.nav-bar a { color: #ffffff; text-decoration: none; font-size: 18px; display: block; }
.nav-bar a:hover { background-color: #A0522D; }
.content-area { padding: 30px; background-color: #2c2420; color: #f0e6d2; }
.content-area h3 { font-size: 22px; margin-bottom: 15px; color: #f0e6d2; }
.content-area p { font-size: 18px; line-height: 1.8; margin-bottom: 12px; }
.content-area ul { list-style-type: disc; padding-left: 25px; font-size: 18px; line-height: 1.8; }
.theme-title {
font-size: 32px;
font-weight: bold;
color: #d4a373;
margin-bottom: 20px;
animation: firstShow 1.5s ease forwards 0.2s;
}
.theme-subtitle {
font-size: 20px;
color: #f0e6d2;
margin-bottom: 25px;
animation: firstShow 1.8s ease forwards 0.8s;
}
@keyframes firstShow {
0% { opacity: 0; transform: translateY(20px); }
100% { opacity: 1; transform: translateY(0); } }
.theme-item {
margin: 20px 0;
padding: 15px;
border-left: 3px solid #d4a373;
background: rgba(212, 163, 115, 0.1);
}
.theme-item h4 {
font-size: 20px;
color: #d4a373;
margin-bottom: 8px;
}
.footer-area { width: 100%; text-align: center; padding: 20px; color: #666; font-size: 14px; border-top: 1px solid #eee; background: #fff; }
</style>
<audio id="bg-music" src="music/rb_bgm.mp3" loop muted></audio>
</head>
<body>
<table width="100%" border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="content-area">
<h1 class="theme-title">R&B 音乐品鉴</h1>
<p class="theme-subtitle">细品旋律韵味,感受灵魂共鸣</p>
<div class="theme-item">
<h4>🎧 旋律品鉴</h4>
<p>R&B音乐以流畅的旋律为核心,融合蓝调的忧郁与灵魂乐的温暖,每一段曲调都能直击心灵。</p>
<p>品鉴要点:转音细腻、节奏舒缓、旋律层次丰富、氛围感强</p>
</div>
<div class="theme-item">
<h4>🎤 人声品鉴</h4>
<p>独特的转音、气声与情感表达是R&B人声的魅力所在,温柔又充满力量。</p>
<p>品鉴要点:情感饱满、转音自然、气息柔和、叙事感强</p>
</div>
<div class="theme-item">
<h4>🥁 节奏品鉴</h4>
<p>标志性的节奏律动,慵懒且松弛,如同红茶般温润舒缓,让人不自觉沉浸其中。</p>
<p>品鉴要点:节奏平稳、鼓点柔和、律动舒适、氛围感拉满</p>
</div>
<div class="theme-item">
<h4>☕ 氛围品鉴</h4>
<p>R&B适合安静独处、放松心情、深夜陪伴,如同品一杯温热红茶,治愈且安心。</p>
<p>适配场景:独处时光、深夜放松、学习工作、温柔治愈</p>
</div>
<h3 style="margin-top: 30px;">品鉴指南</h3>
<ul>
<li>佩戴耳机聆听,感受更细腻的旋律与人声</li>
<li>安静环境下体验,更容易沉浸音乐氛围</li>
<li>配合慢节奏生活,治愈感与舒适感加倍</li>
<li>细品歌词故事,体会R&B独有的情感表达</li>
</ul>
</td>
</tr>
<tr>
<td class="footer-area">
集美大学 · 音乐红茶馆JSP网站 © 2026 网安2413 21小组
</td>
</tr>
</table>
<script>
var audio = document.getElementById('bg-music');
audio.muted = false;
audio.play();
</script>
</body>
</html>
theme.jsp
点击查看代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>音乐主题 - R&B 音乐红茶馆</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: "微软雅黑", sans-serif; background-color: #ffffff; }
.nav-bar { width: 100%; background: transparent; }
.nav-bar td { text-align: center; padding: 12px 0; }
.nav-bar a { color: #ffffff; text-decoration: none; font-size: 18px; display: block; }
.nav-bar a:hover { background-color: #A0522D; }
.content-area { padding: 30px; background-color: #2c2420; color: #f0e6d2; }
.content-area h3 { font-size: 22px; margin-bottom: 15px; color: #f0e6d2; }
.content-area p { font-size: 18px; line-height: 1.8; margin-bottom: 12px; }
.content-area ul { list-style-type: disc; padding-left: 25px; font-size: 18px; line-height: 1.8; }
.theme-title {
font-size: 32px;
font-weight: bold;
color: #d4a373;
margin-bottom: 20px;
animation: firstShow 1.5s ease forwards 0.2s;
}
.theme-subtitle {
font-size: 20px;
color: #f0e6d2;
margin-bottom: 25px;
animation: firstShow 1.8s ease forwards 0.8s;
}
@keyframes firstShow {
0% { opacity: 0; transform: translateY(20px); }
100% { opacity: 1; transform: translateY(0); } }
.theme-item {
margin: 20px 0;
padding: 15px;
border-left: 3px solid #d4a373;
background: rgba(212, 163, 115, 0.1);
}
.theme-item h4 {
font-size: 20px;
color: #d4a373;
margin-bottom: 8px;
}
.footer-area { width: 100%; text-align: center; padding: 20px; color: #666; font-size: 14px; border-top: 1px solid #eee; background: #fff; }
h4 {
display: inline-block;
font-size: 2rem;
cursor: pointer;
border-bottom: 3px solid transparent;
box-shadow: none;
transition: all 0.2s ease;
}
/* 悬停时:下划线 + 底部阴影 */
h4:hover {
border-bottom-color: #d4af37; /* 金色下划线 */
box-shadow: 0 6px 0 -2px rgba(212, 175, 55, 0.4); /* 底部阴影效果 */
}
</style>
<audio id="bg-music" src="music/rb_bgm.mp3" loop muted></audio>
</head>
<body>
<table width="100%" border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="content-area">
<h1 class="theme-title">R&B 音乐主题馆</h1>
<p class="theme-subtitle">每一种旋律,都是一段温柔的故事</p>
<div class="theme-item">
<a href="./theme/rnb.jsp" style="text-decoration:none; display:block;"><h4>🎵 经典复古 R&B</h4></a>
<p>源自上世纪的灵魂之声,融合爵士、蓝调与福音音乐,醇厚如陈年红茶,是R&B最本真的模样。</p>
<p>代表风格:摩城音乐、经典灵魂乐、慢板抒情R&B</p>
</div>
<div class="theme-item">
<a href="./theme/rnb.jsp" style="text-decoration:none; display:block;"><h4>🎵 现代都市 R&B</h4></a>
<p>融合电子、嘻哈与流行元素,节奏轻快、旋律时尚,适合都市夜晚聆听,放松身心。</p>
<p>代表风格:另类R&B、都市流行、陷阱R&B</p>
</div>
<div class="theme-item">
<a href="./theme/rnb.jsp" style="text-decoration:none; display:block;"><h4>🎵 华语抒情 R&B</h4></a>
<p>东方旋律与西方节奏完美融合,歌词细腻深情,唱出属于我们的情感与故事。</p>
<p>代表风格:华语节奏蓝调、国风R&B、治愈系抒情</p>
</div>
<div class="theme-item">
<a href="./theme/rnb.jsp" style="text-decoration:none; display:block;"><h4>🎵 治愈放松 R&B</h4></a>
<p>低吟浅唱、节奏舒缓,如同红茶温润喉咙,治愈疲惫心灵,适合学习、工作、休息时聆听。</p>
<p>核心氛围:安静、温柔、治愈、慵懒</p>
</div>
<h3 style="margin-top: 30px;">主题特色</h3>
<ul>
<li>全品类R&B风格收录,满足不同心情需求</li>
<li>每日更新主题歌单,沉浸式音乐体验</li>
<li>无广告纯享空间,专注聆听音乐本身</li>
<li>乐迷专属交流区,分享你最爱的R&B瞬间</li>
</ul>
</td>
</tr>
<tr>
<td class="footer-area">
集美大学 · 音乐红茶馆JSP网站 © 2026 网安2413 21小组
</td>
</tr>
</table>
<script>
var startBtn = document.getElementById('start-btn');
var startScreen = document.getElementById('start-screen');
var audio = document.getElementById('bg-music');
startBtn.addEventListener('click', function() {
audio.muted = false;
audio.play();
startScreen.style.opacity = '0';
setTimeout(function() {
startScreen.style.display = 'none';
}, 1000);
});
</script>
</body>
</html>
Suggest.java
点击查看代码
package test;
import java.sql.Timestamp;
public class Suggest {
private int id;
private String username;
private String content;
private Timestamp createTime;
public Suggest(int id,String username,String content,Timestamp createTime) {
this.id=id;
this.username=username;
this.content=content;
this.createTime=createTime;
}
public Suggest() {
}
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getContent() { return content; }
public void setContent(String content) { this.content = content; }
public Timestamp getCreateTime() { return createTime; }
public void setCreateTime(Timestamp createTime) { this.createTime = createTime; }
}
Suggestrequest.java
点击查看代码
package test;
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.sql.Connection;
import java.sql.PreparedStatement;
@WebServlet("/suggestAdd")
public class Suggestrequest extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException {
try (Connection conn = DBUtil.getConn()) {
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
String username = request.getParameter("username");
String content = request.getParameter("content");
String[] badWords = {
"操","草","艹","妈的","傻逼","沙雕","垃圾","废物",
"日","靠","fuck","shit","妈卖批"
};
for (int i = 0; i < badWords.length; i++) {
String word = badWords[i];
if (content.contains(word) || username.contains(word)) {
response.getWriter().write("<script>alert('禁止使用不文明用语!');history.back();</script>");
return;
}
}
String sql = "INSERT INTO suggest(username,content) VALUES(?,?)";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, username);
pstmt.setString(2, content);
pstmt.executeUpdate();
// 4. 关闭连接
pstmt.close();
conn.close();
// 5. 回到建议页面
response.getWriter().write("<script>alert('提交成功!');location.href='test4/suggest.jsp';</script>");
} catch (Exception e) {
e.printStackTrace();
}
}
}
DBUtil.java
点击查看代码
package test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DBUtil {
private static final String DRIVER = "com.mysql.jdbc.Driver";
private static final String URL = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8";
private static final String USER = "root";
private static final String PASSWORD = "root";
static {
try {
Class.forName(DRIVER);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConn() throws SQLException {
return DriverManager.getConnection(URL, USER, PASSWORD);
}
}
调试过程与问题解决
在开发过程中,我们遇到了一些挑战,但通过查阅资料和不断调试,最终都找到了解决方案。以下是几个关键的调试经历:
- 问题一:背景音乐无法自动播放
- 现象:页面加载后,背景音乐始终没有声音。
- 分析与解决:经过查询,我们发现现代浏览器(如Chrome、Edge)出于用户体验考虑,默认会阻止网页自动播放带有声音的媒体。如果没有用户的点击动作,网页绝对不能自动播放有声音的东西。因此,我们设计了一个“点击进入音乐空间”的按钮,利用用户的点击事件来触发音乐的播放,成功解决了这个问题。
- 问题二:Flash动画无法使用
- 现象:尝试插入Flash动画素材,但浏览器无法加载。
- 分析与解决:我们了解到,主流的网页浏览器均已默认禁用或彻底移除了对Flash内容的支持。HTML5、CSS3和JavaScript等开放标准技术已经全面取代了Flash,成为实现网页动画和交互功能的首选方案。于是,我们果断放弃了Flash,转而使用CSS3的
@keyframes动画,成功实现了首页中下落的音符、茶杯以及字幕的动态效果。
- 问题三:MP3音乐文件路径解析错误
- 现象:导入MP3音乐时,浏览器报404错误,无法找到文件。
- 分析与解决:我们发现,最初导入格式的写法有误,写成了
data-audio="mp3/The Marvelettes ;ll Keep Holding On.mp3",导致浏览器将路径错误地解析为localhost:8080/项目名/theme/mp3/xxx.mp3。经过修正,我们将路径改为data-audio="../mp3/TheMarvelettesllKeepHoldingOn.mp3"。这里的"../"表示“回到上一级目录”,这样浏览器就能正确地找到根目录下的mp3文件夹,从而解决了路径问题。
- 问题四:鼠标悬停自动播放音频受限
- 现象:我们设计了鼠标悬停在“胶片”上就自动播放对应音乐的效果,但这个功能在浏览器中无法正常工作。
- 分析与解决:这同样是浏览器自动播放策略的限制。浏览器规定,必须用户主动点击页面后,才能播放音频。因此,我们调整了交互逻辑:用户需要先任意点击页面某处(例如“点击进入音乐空间”按钮),激活页面的音频上下文,之后,当鼠标悬停到“胶片”上时,音乐就可以自动播放了。
- 问题五:.java文件与.jsp文件联动问题
- 现象:部署至云端服务器后,访问页面出现 Tomcat 500 错误,提示无法引用 Java 类、类不存在等异常。
- 分析与解决:本地项目编译后会生成.class字节码文件,云端仅上传了.java源码文件,缺少编译后的.class文件;Tomcat 运行时无法识别 Java 源码,导致 JSP 无法调用后台 Java 工具类,联动失效。需在本地重新编译项目,完整上传WEB-INF/classes目录下所有.class文件至云端对应路径,重启 Tomcat 即可恢复联动。
- 问题六:数据库配置问题
- 现象:网页无法读取数据库数据,出现数据库连接拒绝、访问受限、连接超时等错误。
- 分析与解决:需要配置云端 MySQL 服务,统一数据库账号、密码、库名配置,导入对应数据表结构,将 MySQL 驱动 Jar 包放置在项目WEB-INF/lib目录下,完成配置后重启服务,实现正常数据库读写。
实验心得
通过本次实验,我们不仅巩固了JSP的理论知识,更重要的是,我们学会了如何在实际开发中解决遇到的问题。我们深刻体会到,现代Web开发需要紧跟技术潮流,比如用CSS3替代Flash。同时,对浏览器安全策略(如自动播放限制)的理解,也让我们在开发时更加注重用户体验。这次小组合作也让我们学会了如何分工协作,共同攻克技术难题。








浙公网安备 33010602011771号