实验四-音乐红茶馆

音乐红茶馆


音乐红茶馆网站

实验概述

本次实验,我们小组)的目标是设计并实现一个名为“音乐红茶馆”的JSP网站。实验的核心目的在于深入掌握JSP的核心技术,包括固定模板元素、各种JSP标签的使用、网站的基本架构设计,以及JSP内置对象(如Request和Response)的运用。同时,我们还希望通过实践,熟悉网页多媒体技术的应用,特别是音频和动画的集成,并最终理解JSP强大的页面显示功能。


实现方法分析

我们的网站采用了经典的三级页面结构:首页、导航页面和内容页面。

  1. 前端页面实现:我们使用HTML和CSS进行页面布局和美化。首页的布局主要依靠border="0"的表格进行排版,以实现稳定的页面结构。为了提升用户体验,我们大量运用了CSS3动画,例如首页中下落的音符、茶杯,以及标题文字的动态效果,这些动画替代了传统且已被淘汰的Flash技术。
  2. 后台逻辑处理:网站的核心交互功能,特别是“乐迷建议”模块,由JSP和Java Servlet共同实现。我们设计了一个表单页面(suggest.jsp),用户可以在其中提交建议。当用户点击提交按钮后,表单数据会被发送到后台的Servlet(Suggestrequest.java)。该Servlet通过HttpServletRequest对象获取用户输入的数据,进行简单的非法字符过滤后,将其存入数据库。随后,页面会跳转回建议列表页面,通过JSTL标签和EL表达式,将数据库中的所有建议动态地展示给用户。

关键技术点

  1. JSP内置对象(Request/Response)的使用:这是本次实验的核心。request对象被用来获取表单提交的数据,而response对象则用于设置响应的编码格式,并向客户端返回操作结果(如成功提示)。
  2. 网页多媒体技术(音频/动画)的应用:我们成功地在页面中集成了背景音乐和交互式音效。通过<audio>标签和JavaScript,我们实现了背景音乐的播放控制。同时,利用CSS3的@keyframesanimation属性,我们创造出流畅的动画效果,增强了网站的视觉吸引力。
  3. 表单数据提交与后台处理:我们设计了一个完整的“提交-处理-反馈”流程。前端表单使用POST方法提交数据,后台Servlet接收并处理,最后通过response.getWriter().write()向客户端返回JavaScript提示,实现了友好的用户反馈。
  4. 数据库交互:通过JDBC连接MySQL数据库,我们实现了建议的持久化存储和读取。DBUtil.java封装了数据库连接逻辑,使得代码更加模块化和易于维护。

实验成果

结果介绍

我们成功构建了一个功能完整、界面美观的音乐主题网站。网站包含以下主要功能:

  • 欢迎页面:带有动画效果的欢迎界面和背景音乐。
    image
    image

  • 导航系统:包含“首页”、“音乐主题”、“音乐品鉴”、“乐迷建议”四个主要导航链接。
    image

  • 音乐主题与品鉴:展示了R&B音乐的不同风格和品鉴要点。
    image
    image

  • 交互式音乐播放:在rnb.jsp页面中,用户可以点击“胶片”图标,弹出一个播放器,并播放对应的音乐。
    image

  • 乐迷建议系统:用户可以提交建议,并在页面上看到所有已提交的建议列表。
    image

  • 网站链接:http://47.111.183.105:8080/homework/test4/index.html

代码分析

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网站 &copy; 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网站 &copy; 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网站 &copy; 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);
    }
}

调试过程与问题解决

在开发过程中,我们遇到了一些挑战,但通过查阅资料和不断调试,最终都找到了解决方案。以下是几个关键的调试经历:

  1. 问题一:背景音乐无法自动播放
    • 现象:页面加载后,背景音乐始终没有声音。
    • 分析与解决:经过查询,我们发现现代浏览器(如Chrome、Edge)出于用户体验考虑,默认会阻止网页自动播放带有声音的媒体。如果没有用户的点击动作,网页绝对不能自动播放有声音的东西。因此,我们设计了一个“点击进入音乐空间”的按钮,利用用户的点击事件来触发音乐的播放,成功解决了这个问题。
  2. 问题二:Flash动画无法使用
    • 现象:尝试插入Flash动画素材,但浏览器无法加载。
    • 分析与解决:我们了解到,主流的网页浏览器均已默认禁用或彻底移除了对Flash内容的支持。HTML5、CSS3和JavaScript等开放标准技术已经全面取代了Flash,成为实现网页动画和交互功能的首选方案。于是,我们果断放弃了Flash,转而使用CSS3的@keyframes动画,成功实现了首页中下落的音符、茶杯以及字幕的动态效果。
  3. 问题三: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文件夹,从而解决了路径问题。
  4. 问题四:鼠标悬停自动播放音频受限
    • 现象:我们设计了鼠标悬停在“胶片”上就自动播放对应音乐的效果,但这个功能在浏览器中无法正常工作。
    • 分析与解决:这同样是浏览器自动播放策略的限制。浏览器规定,必须用户主动点击页面后,才能播放音频。因此,我们调整了交互逻辑:用户需要先任意点击页面某处(例如“点击进入音乐空间”按钮),激活页面的音频上下文,之后,当鼠标悬停到“胶片”上时,音乐就可以自动播放了。
  5. 问题五:.java文件与.jsp文件联动问题
    • 现象:部署至云端服务器后,访问页面出现 Tomcat 500 错误,提示无法引用 Java 类、类不存在等异常。
    • 分析与解决:本地项目编译后会生成.class字节码文件,云端仅上传了.java源码文件,缺少编译后的.class文件;Tomcat 运行时无法识别 Java 源码,导致 JSP 无法调用后台 Java 工具类,联动失效。需在本地重新编译项目,完整上传WEB-INF/classes目录下所有.class文件至云端对应路径,重启 Tomcat 即可恢复联动。
  6. 问题六:数据库配置问题
    • 现象:网页无法读取数据库数据,出现数据库连接拒绝、访问受限、连接超时等错误。
    • 分析与解决:需要配置云端 MySQL 服务,统一数据库账号、密码、库名配置,导入对应数据表结构,将 MySQL 驱动 Jar 包放置在项目WEB-INF/lib目录下,完成配置后重启服务,实现正常数据库读写。

实验心得

通过本次实验,我们不仅巩固了JSP的理论知识,更重要的是,我们学会了如何在实际开发中解决遇到的问题。我们深刻体会到,现代Web开发需要紧跟技术潮流,比如用CSS3替代Flash。同时,对浏览器安全策略(如自动播放限制)的理解,也让我们在开发时更加注重用户体验。这次小组合作也让我们学会了如何分工协作,共同攻克技术难题。

posted @ 2026-04-26 11:52  穗和  阅读(28)  评论(0)    收藏  举报