TP6简单实现书籍阅读网

  • 实现功能

1-登录/注册

2-首页书籍展示

3-指定书籍章节展示

4-指定章节的章节内容展示

  • 项目配置

开发环境:phpstudy 版本:8.1.1.3

Phpstudy下载网址phpStudy-phpStudy下载-php环境集成包-2024最新版

Phpstudy配置信息:

Mysql:5.7.26

Apache:2.4.39

php:7.4.3

PHP框架:ThinkPHP6

前端框架:layui、jQuery

项目所处文件夹:\phpstudy_pro\WWW\novel

  • 搭建网站

数据库名字 数据库账号 数据库密码

伪静态:

location / {

if (!-e $request_filename){

rewrite ^(.*)$ /index.php?s=$1 last; break;

}

}

  • 配置文件及项目目录

数据库配置文件:\novel\config\database.php

数据库sql文件:\novel\novels.sql

控制器接口:\novel\app\controller\

路由文件:\novel\route\app.php

前端文件:\novel\app\view

首页:\novel\app\view\index\index.html

CSS文件:\novel\public\static\css\

JS文件:\novel\public\static\js

  • 代码展示

0.打开TP6的Session,开启TP6的多应用

1.\novel\config\database.php

// 数据库类型
'type'            => env('mysql', 'mysql'),
// 服务器地址
'hostname'        => env('', '127.0.0.1'),
// 数据库名
'database'        => env('', 'novels'),
// 用户名
'username'        => env('', 'novels'),
// 密码
'password'        => env('', '123456'),
// 端口
'hostport'        => env('', '3306'),

2.\novel\route\app.php

<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
use think\facade\Route;

Route::rule('doRegister', 'register/doRegister');
Route::rule('doLogin', 'login/doLogin');
Route::rule('logout', 'login/logout');

3.\novel\app\view\index\index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>书籍阅读网</title>
    <script src="/static/js/jquery-3.2.1.min.js"></script>
    <link rel="stylesheet" href="/static/css/layui.css" />
    <link rel="stylesheet" href="/static/css/style.css" />
    <script src="/static/js/layui.js"></script>
</head>
<body>
<div class="layui-container">
    <div class="header-buttons">
        <?php if ($username): ?>
        <span>欢迎,<?php echo $username; ?></span>
        <a href="/logout">退出</a>
        <?php else: ?>
        <a href="/login">登录</a>
        <a href="/register">注册</a>
        <?php endif; ?>
    </div>
    <h1 class="layui-text-center">红色书籍阅读网</h1>
    <div class="novel-list">
        <!-- 遍历所有小说 -->
        <div class="layui-row layui-col-space15">
            <?php if (!empty($novels)): ?>
            <?php foreach ($novels as $novel): ?>
            <div class="member_item" style="height: auto;">
                <div class="member_right">
                    <a href="<?= url('/chapters', ['novel_id' => $novel['id']]) ?>">
                        <p class="textoverflow"><?= htmlspecialchars($novel['title']) ?></p>
                    </a>
                    <p class="description"><?= htmlspecialchars($novel['description']) ?></p>
                    <div class="tips">
                        <span class="date"><?= date('Y-m-d H:i', strtotime($novel['created_at'])) ?></span>
                        <a href="<?= url('/chapters', ['novel_id' => $novel['id']]) ?>" class="view-chapter">查看章节 &gt;</a>
                    </div>
                </div>
            </div>
            <?php endforeach; ?>
            <?php else: ?>
            <p>当前没有任何小说可供展示。</p>
            <?php endif; ?>
        </div>
    </div>
</div>
</body>
</html>

4.\novel\app\view\Register.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>书籍阅读网 - 用户注册</title>
    <script src="/static/js/jquery-3.2.1.min.js"></script>
    <link rel="stylesheet" href="/static/css/style.css" />
    <script src="/static/js/layui.js"></script>
    <style>
        body {
            background-color: #f5f5f5;
            font-family: '微软雅黑', Arial, sans-serif;
            color: #333;
            margin: 0;
            padding: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
        }
    </style>
</head>
<body>

<div class="container">
    <h2 style="text-align: center;">用户注册</h2>
    <form class="layui-form" action="" method="POST">
        <div class="layui-form-item">
            <label class="layui-form-label">邮箱</label>
            <div class="layui-input-block">
                <input type="text" name="email" required lay-verify="required" placeholder="请输入邮箱" class="layui-input">
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label">用户名</label>
            <div class="layui-input-block">
                <input type="text" name="username" required lay-verify="required" placeholder="请输入用户名" class="layui-input">
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label">密码</label>
            <div class="layui-input-block">
                <input type="password" name="password" required lay-verify="required" placeholder="请输入密码" class="layui-input">
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label">确认密码</label>
            <div class="layui-input-block">
                <input type="password" name="confirm_password" required lay-verify="required" placeholder="请确认密码" class="layui-input">
            </div>
        </div>
        <div class="layui-form-item">
            <div class="layui-input-block">
                <button type="submit" class="layui-btn layui-btn-normal" lay-submit lay-filter="formSubmit">注册</button>
            </div>
        </div>
    </form>
    <div style="text-align: center;">
        <p style="display: flex;justify-content: space-between;">
            <a href="/index">返回首页</a>
            <span>已有账号?<a href="/login">去登录</a></span>
        </p>
    </div>
</div>

<script>
    layui.use('form', function() {
        var form = layui.form;
        form.on('submit(formSubmit)', function(data){
            $.ajax({
                url: '/doRegister', // 后端接口地址
                type: 'POST',
                data: data.field, // 表单数据
                success: function(response) {
                    if(response.status === "error"){
                        alert(response.message);
                    }else{
                        alert(response.message);
                        window.location.href = "/login"
                    }
                },
                error: function(error) {
                    console.error(error); // 错误信息
                    alert('提交失败');
                }
            });
            return false; // 阻止表单默认提交
        });
    });
</script>

</body>
</html>

5.\novel\app\view\Login.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>书籍阅读网 - 用户登录</title>
    <script src="/static/js/jquery-3.2.1.min.js"></script>
    <link rel="stylesheet" href="/static/css/style.css" />
    <script src="/static/js/layui.js"></script>
    <style>
        body {
            background-color: #f5f5f5;
            font-family: '微软雅黑', Arial, sans-serif;
            color: #333;
            margin: 0;
            padding: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
        }
    </style>
</head>
<body>

<div class="container">
    <h2 style="text-align: center;">用户登录</h2>
    <form class="layui-form" action="/doLogin" method="POST">
        <div class="layui-form-item">
            <label class="layui-form-label">用户名</label>
            <div class="layui-input-block">
                <input type="text" name="username" required lay-verify="required" placeholder="请输入用户名" class="layui-input">
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label">密码</label>
            <div class="layui-input-block">
                <input type="password" name="password" required lay-verify="required" placeholder="请输入密码" class="layui-input">
            </div>
        </div>
        <p style="color: red;"><?php echo $error ?></p>
        <div class="layui-form-item">
            <div class="layui-input-block">
                <button type="submit" class="layui-btn layui-btn-normal">登录</button>
            </div>
        </div>
    </form>
    <div style="text-align: center;">
        <p style="display: flex;justify-content: space-between;">
            <a href="/index">返回首页</a>
            <span>没有账号?<a href="/register">去注册</a></span>
        </p>
    </div>
</div>



</body>
</html>

6.\novel\app\view\chapters.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>书籍阅读网</title>
    <script src="/static/js/jquery-3.2.1.min.js"></script>
    <link rel="stylesheet" href="/static/css/layui.css" />
    <link rel="stylesheet" href="/static/css/style.css" />
    <script src="/static/js/layui.js"></script>
</head>
<body>
<div class="layui-container" style="position: relative;">
    <a href="index">首页</a>
    <div class="header-buttons">
        <?php if ($username): ?>
        <span>欢迎,<?php echo $username; ?></span>
        <a href="/logout">退出</a>
        <?php else: ?>
        <a href="/login">登录</a>
        <a href="/register">注册</a>
        <?php endif; ?>
    </div>
    <h2 class="layui-text-center"><?php print_r($novel['title']) ?></h2>
    <div class="novel-list">
        <!-- 这本小说所有的章节 -->
        <div class="layui-row layui-col-space15">
            <?php if (!empty($chapters)): ?>
            <div class="chapters_item" style="height: auto;">
                <?php foreach ($chapters as $chapter): ?>
                <div class="member_right">
                    <a href="<?= url('/show', ['novel_id' => $novel['id'],'chapter_id' => $chapter['id']]) ?>">
                        <p class="textoverflow"><?= htmlspecialchars($chapter['chapter_title']) ?></p>
                    </a>
                </div>
                <?php endforeach; ?>
            </div>
            <?php else: ?>
            <p>当前没有任何章节可供展示。</p>
            <?php endif; ?>
        </div>
    </div>
</div>
</body>
</html>

7.\novel\app\view\show.html

<?php
// 当前章节ID为 currentChapterId,最大章节ID为 maxChapterId,最小章节ID为 maxChapterId
$currentChapterId = $content[0]['id'];
$prevChapterId = ($currentChapterId > $minChapterId) ? $currentChapterId - 1 : null;
$nextChapterId = ($currentChapterId < $maxChapterId) ? $currentChapterId + 1 : null;
?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>书籍阅读网</title>
    <script src="/static/js/jquery-3.2.1.min.js"></script>
    <link rel="stylesheet" href="/static/css/layui.css" />
    <link rel="stylesheet" href="/static/css/style.css" />
    <script src="/static/js/layui.js"></script>
</head>
<body>
<div class="layui-container" style="position: relative;">
    <a href="<?= url('/chapters', ['novel_id' => $novelId]) ?>">返回章节</a>
    <div class="header-buttons">
        <?php if ($username): ?>
        <span>欢迎,<?php echo $username; ?></span>
        <a href="/logout">退出</a>
        <?php else: ?>
        <a href="/login">登录</a>
        <a href="/register">注册</a>
        <?php endif; ?>
    </div>

    <?php if (!empty($content) && isset($content[0])): ?>
    <h3 class="layui-text-center"><?= htmlspecialchars($content[0]['chapter_title']) ?></h3>

    <!-- 上一章和下一章按钮 -->
    <div class="chapter-navigation">
        <?php if ($prevChapterId): ?>
        <a href="<?= url('/show', ['novel_id' => $novelId, 'chapter_id' => $prevChapterId]) ?>">上一章</a>
        <?php else: ?>
        <a href="#" class="disabled">上一章</a>
        <?php endif; ?>
        <?php if ($nextChapterId): ?>
        <a href="<?= url('/show', ['novel_id' => $novelId, 'chapter_id' => $nextChapterId]) ?>">下一章</a>
        <?php else: ?>
        <a href="#" class="disabled">下一章</a>
        <?php endif; ?>
    </div>

    <div class="novel-list">
        <div class="layui-con layui-col-space15" style="">
            <div class="chapters_item" style="height: auto;">
                <p class="textoverflow"><?= htmlspecialchars($content[0]['content']) ?></p>
            </div>
        </div>
    </div>
    <?php else: ?>
    <p>当前没有任何内容可供展示。</p>
    <?php endif; ?>

</div>
</body>
</html>

<style>
    .disabled {
        color: #ccc;
        pointer-events: none;
        text-decoration: none;
    }
</style>

8.\novel\app\controller\Index.php

<?php
namespace app\controller;

use app\BaseController;
use think\facade\Db;
use think\facade\Session;
use think\facade\View;

class Index extends BaseController
{
    // 显示小说首页
    public function index()
    {
        // 获取所有小说列表
        $novels = Db::name('novels')->select();
        $username = Session::get('username');
        return View::fetch('index', ['username' => $username,'novels' => $novels]);
    }
}

9.\novel\app\controller\register.php

<?php

namespace app\controller;

use app\BaseController;
use think\facade\View;
use think\facade\Request;
use think\facade\Db;

class register extends BaseController
{
    public function index()
    {
        return View::fetch('/register');
    }

    // 处理注册请求
    public function doRegister()
    {
        // 获取表单数据
        $email = Request::post('email');
        $username = Request::post('username');
        $password = Request::post('password');
        $confirm_password = Request::post('confirm_password');

        // 表单验证
        if (empty($email) || empty($username) || empty($password) || empty($confirm_password)) {
            return json(['status' => 'error', 'message' => '所有字段都不能为空']);
        }

        if ($password !== $confirm_password) {
            return json(['status' => 'error', 'message' => '密码和确认密码不匹配']);
        }

        // 检查用户名或邮箱是否已存在
        $existingUser = Db::name('users')->where('username', $username)->find();
        if ($existingUser) {
            return json(['status' => 'error', 'message' => '用户名已存在']);
        }

        $existingEmail = Db::name('users')->where('email', $email)->find();
        if ($existingEmail) {
            return json(['status' => 'error', 'message' => '邮箱已注册']);
        }

        // 插入用户信息到数据库
        try {
            $result = Db::name('users')->insert([
                'username' => $username,
                'password' => $password,
                'email' => $email
            ]);

            if ($result) {
                return json(['status' => 'success', 'message' => '注册成功']);
            } else {
                return json(['status' => 'error', 'message' => '注册失败,请稍后重试']);
            }
        } catch (\Exception $e) {
            return json(['status' => 'error', 'message' => '系统错误: ' . $e->getMessage()]);
        }
    }
}

10.\novel\app\controller\login.php

<?php

namespace app\controller;

use app\BaseController;
// 添加引用
use think\facade\Session;
use think\facade\View;
use think\facade\Request;
use think\facade\Db;

class login extends BaseController
{
    public function index()
    {
        return View::fetch('/login', ['error' => '']);
    }

    // 处理登录请求
    public function doLogin()
    {
        $username = Request::param('username');
        $password = Request::param('password');

        //验证用户
        $user = Db::name('users')->where('username', $username)->where('password', $password)->find();

        if ($user) {
            // 登录成功:保存用户信息到 Session
            Session::set('userid', $user['id']);
            Session::set('username', $user['username']);
            // 重定向到首页
            return redirect((string) url('/',['username' => $user['username']]));
        } else {
            // 登录失败:返回错误信息
            return View::fetch('/login', ['error' => '用户名或密码错误']);
        }

    }

    public function logout()
    {
        Session::delete('userid');
        Session::delete('username');
        return redirect('/');
    }
}

11.\novel\app\controller\chapters.php

<?php
namespace app\controller;

use app\BaseController;
use think\facade\Db;
use think\facade\Session;
use think\facade\View;

class chapters extends BaseController
{
    // 显示小说首页
    public function index()
    {
        // 获取该小说章节
        $novelId = input('novel_id');
        $chapters = Db::name('chapters')->where('novel_id',$novelId)->select();
        // 获取小说的详细信息(如果需要展示)
        $novel = Db::name('novels')->where('id', $novelId)->find();
        $username = Session::get('username');
        return View::fetch('/chapters', [
            'username' => $username,
            'novel' => $novel,
            'chapters' => $chapters
        ]);
    }
}

12.\novel\app\controller\show.php

<?php
namespace app\controller;

use app\BaseController;
use think\facade\Db;
use think\facade\Session;
use think\facade\View;

class show extends BaseController
{
    // 显示小说首页
    public function index()
    {
        // 获取该小说章节
        $novelId = input('novel_id');
        $chapter_id = input('chapter_id');
        $content = Db::name('chapters')->where('novel_id',$novelId)->where('id',$chapter_id)->select();
        $maxChapterId = Db::name('chapters')->where('novel_id', $novelId)->max('id');
        $minChapterId = Db::name('chapters')->where('novel_id', $novelId)->min('id');
        $username = Session::get('username');
        // 获取小说的详细信息(如果需要展示)
        return View::fetch('/show', [
            'username' => $username,
            'novelId' => $novelId,
            'content' => $content,
            'maxChapterId' => $maxChapterId,
            'minChapterId' => $minChapterId
        ]);
    }
}

13.\novel\novels.sql

CREATE DATABASE novel_site;

USE novel_site;

-- 用户表
CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL UNIQUE,
    password VARCHAR(255) NOT NULL,
    email VARCHAR(100) NOT NULL
);

-- 小说表
CREATE TABLE novels (
    id INT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(100) NOT NULL,
    author VARCHAR(50),
    description TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 小说章节表
CREATE TABLE chapters (
    id INT AUTO_INCREMENT PRIMARY KEY,
    novel_id INT NOT NULL,
    chapter_title VARCHAR(100) NOT NULL,
    content TEXT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (novel_id) REFERENCES novels(id) ON DELETE CASCADE
);

14.\novel\public\static\css\style.css

body {
    background-color: #f2f2f2; /* 浅灰色背景 */
    font-family: "微软雅黑", Arial, sans-serif;
    color: #333;

}

.layui-container {
    background-color: white;
    min-height: 100vh; /* 最小高度 100% 的视口高度 */
    height: auto;
    padding: 20px;
    border-radius: 10px;
    box-shadow: 0 0 15px rgba(0, 0, 0, 0.1);
    background-image: url('/static/img/dq1.jpg');
    background-repeat: no-repeat; /* 防止背景图重复 */
}

/* 红色主题标题 */
h1.layui-text-center {
    color: black; /* 红色标题 */
    font-size: 2.5rem;
    font-weight: bold;
    text-align: center;
}

h2.layui-text-center {
    color: black;
    font-size: 2rem;
    font-weight: bold;
    text-align: center;
}

h3.layui-text-center {
    color: black;
    font-size: 1.5rem;
    font-weight: bold;
    text-align: center;
}

/* 小说列表的样式 */
.novel-list .layui-row {
    margin-top: 20px;
}

.member_item {
    border: 1px solid #d90000; /* 红色边框 */
    border-radius: 10px;
    margin-bottom: 15px;
    padding: 15px;
    display: flex;
    align-items: center;
    height: auto;
    transition: transform 0.3s ease;
}

.member_item:hover {
    transform: translateY(-5px); /* 鼠标悬停时上移 */
    box-shadow: 0 0 15px rgba(0, 0, 0, 0.1);
}

.member_right {
    flex: 1;
}

.member_right a {
    text-decoration: none;
    color: #d90000; /* 红色链接 */
}

.member_right p.textoverflow {
    font-size: 1.2rem;
    font-weight: bold;
    color: black; /* 红色标题 */
    margin-bottom: 10px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.description {
    color: #666;
    font-size: 1rem;
    margin-bottom: 15px;
}

.tips {
    display: flex;
    justify-content: space-between;
    font-size: 0.9rem;
    color: #888;
}

.tips .date {
    color: #999;
}

.tips .view-chapter {
    color: #777777; /* 红色按钮 */
    font-weight: bold;
}

.view-chapter:hover {
    text-decoration: underline;
}

/* 样式调整 - 页面底部和响应式布局 */
.layui-row {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
}

.member_item {
    flex: 0 0 48%; /* 每行两个项目 */

    margin-bottom: 20px;
}

.member_item:nth-child(2n) {
    margin-right: 0;
}

.header-buttons {
    position: absolute;
    top: 20px;
    right: 20px;
}

.header-buttons a {
    margin-left: 15px;
    padding: 10px 20px;
    color: black;
    text-decoration: none;
    border-radius: 5px;
    font-size: 1rem;
}

@media (max-width: 768px) {
    .member_item {
        flex: 0 0 100%; /* 小屏幕时每行一个项目 */
    }
}

/*登录注册*/
.container {
    background-color: #fff;
    border-radius: 8px;
    padding: 30px;
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
    width: 100%;
    max-width: 400px;
}
h2 {
    color: #d90000;
    font-size: 1.8rem;
    margin-bottom: 20px;
}

.layui-form-item {
    margin-bottom: 20px;
}

.layui-form-label {
    width: 90px;
    text-align: right;
    font-weight: bold;
}

.layui-input {
    border-radius: 5px;
    padding: 10px;
    border: 1px solid #ddd;
    width: 100%;
    font-size: 1rem;
    box-sizing: border-box;
}

.layui-btn {
    background-color: #d90000;
    color: white;
    border: none;
    border-radius: 5px;
    padding: 10px 20px;
    width: 100%;
    font-size: 1.2rem;
}

.layui-btn:hover {
    background-color: #b30000;
}

.layui-form-item .layui-input-block {
    display: flex;
    justify-content: center;
}

/* 其他文字样式 */
.container p {
    font-size: 1rem;
    color: #666;
}

.container a {
    color: #d90000;
    text-decoration: none;
}

.container a:hover {
    text-decoration: underline;
}

/* 响应式设计 */
@media (max-width: 768px) {
    .container {
        width: 90%;
        padding: 20px;
    }
}

.chapters_item{
    flex: 0 0 48%; /* 每行两个项目 */
    background-color: #fff;
    border: 1px solid #d90000; /* 红色边框 */
    border-radius: 10px;
    margin-bottom: 15px;
    padding: 15px;
    transition: transform 0.3s ease;
}

.layui-con{
    margin-top: 20px;
}

.layui-con p {
    text-indent: 2em;
}

.chapter-navigation{
    margin-top: 2%;
    display: flex;
    justify-content: space-around;
}

一个很简单的书籍阅览网站就做好了,以后还可以添加用户评论、收藏、浏览数、追读人数等功能。

完结撒花。