侧边栏壁纸
博主头像
快乐江湖的博客博主等级

更多内容请点击CSDN关注“快乐江湖”

  • 累计撰写 127 篇文章
  • 累计创建 33 个标签
  • 累计收到 2 条评论

目 录CONTENT

文章目录

第三章Java网络编程-第八节:博客系统搭建(前后端分离)

快乐江湖
2023-10-29 / 0 评论 / 0 点赞 / 9 阅读 / 104692 字

(Java高级教程)第四章必备前端知识-最终节:博客系统搭建(页面设计部分)中我们实现了一个博客系统的前端页面。这一节我们会结合Servlet和之前的前端页面搭建一个完整的博客系统。该博客系统十分简单,虽然只包含下面最基础的功能,但足以对我们之前学习内容进行串联

  • 博客列表页展示
  • 博客详情页展示
  • 博客登录页用户登录
  • 在用户未登录并访问其他页面时强制要求登录
  • 显示用户信息(作者信息)
  • 注销登录
  • 发布博客
  • 删除博客

本文完整代码见Gihub仓库:点击跳转

一:前端页面回顾

博客登录页:BlogLoginPage.html

博客列表页:BlogListPage.html

博客详情页:BlogDetailPage.html

博客编辑页:BlogEditPage.html

二:博客功能展示

博客登录和列表页展示

  • 如果用户名或密码错误,则会弹出提示框
  • 如果用户名和密码正确,则登录成功并跳转至博客列表页

在用户未登录并访问其他页面时强制要求登录

博客列表页用户信息和博客详情页作者信息展示

  • 某用户登录后在博客列表中要显示该登录用户的信息。他可以查看到所有博客内容(部分博客是自己写的,部分博客是别人写的)
  • 当点击进入一篇具体的博客的详情后,要展示该博客的作者信息

注销账户

  • 当用户点击“注销账户”后就会退出登录并跳转至博客登录页

发布博客

  • 当用户点击“开始创作”就会跳转至博客编辑页
  • 待用户写好博客标题和内容并点击标题右侧的“发布文章”后,就会将该博客插入到数据库中
  • 发布成功后自动跳转至博客列表页

删除博客

  • 当用户点击“删除文章”时就会将该博客删除,然后跳转至博客列表页
  • 用户不能将别人的博客删除

三:数据库表设计

(1)表设计

博客数据,用户数据都是存储在数据库中的,因此数据库表设计在很大程度上决定或影响了整个程序的编写。为此,我们需要创建以下两张表

  • 博客表:blog
    • blogId:博客Id
    • title:博客标题
    • content:博客内容
    • postTime:博客插入数据库的时间(发布时间)
    • userId:用户Id
  • 用户表:user
    • userId:用户Id
    • username:用户名
    • password:用户密码

SQL语句如下,你可以在IDEA中创建一个后缀名为.sql的文件,然后在这里面编写,之后将所有SQL语句复制到终端即可

-- 创建数据库  
create database if not exists BlogSystem2;  
  
-- 使用数据库  
use BlogSystem2;  
  
  
drop table if exists blog;  
  
-- 创建博客表blog  
create table blog (  
    blogId int primary key auto_increment,  
    title varchar(256),  
    content text,  
    postTime datetime,  
    userId int  
);  
  
-- 创建用户表user  
drop table if exists user;  
create table user (  
    userId int primary key  auto_increment,  
    userName varchar(50) unique,  
    passWord varchar(50)  
);  
  
-- 插入数据测试  
insert into blog values(null, "第一篇博客", "今天我们介绍博客系统的实现", now(), 1);  
insert into blog values(null, "第二篇博客", "今天我们再次介绍博客系统的实现", now(), 2);  
insert into blog values(null, "第三篇博客", "今天我们第三次次介绍博客系统的实现", now(), 1);  
insert into blog values(null, "第四篇博客", "### 第一:任务内容 - asd1", now(), 2);  
  
insert into user values(1, "张三", "123");  
insert into user values(2, "李四", "123");

效果如下

(2)封装DataSource

在进行数据插入、删除等操作时会频繁设计如“获取数据源”、“建立连接”、“释放资源”等等重复操作,所以我们可以将它们封装在一个DBUtil中。它要符合单例模式的设计结构

import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;  
  
import javax.sql.DataSource;  
import java.sql.Connection;  
import java.sql.PreparedStatement;  
import java.sql.ResultSet;  
import java.sql.SQLException;  
  
public class DBUtil {  
    private static volatile DataSource dataSource = null;  
  
    // 获取数据源  
    private static  DataSource getDataSource() {  
        if (dataSource == null) {  
            synchronized (DBUtil.class) {  
                if (dataSource == null) {  
                    dataSource = new MysqlDataSource();  
                    ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/blogsystem2?characterEncoding=utf8&allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=UTC");  
                    ((MysqlDataSource)dataSource).setUser("root");  
                    ((MysqlDataSource)dataSource).setPassword("123456");  
                }  
            }  
        }  
  
        return dataSource;  
    }  
  
    private DBUtil() {};  
  
    // 建立连接  
    public static Connection getConnection() throws SQLException {  
        return getDataSource().getConnection();  
    }  
  
    // 释放资源  
    public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet) throws SQLException {  
        if (resultSet != null) {  
            try {  
                resultSet.close();  
            } catch (SQLException e) {  
                e.printStackTrace();  
            }  
        }  
  
        if (statement != null) {  
            try {  
                statement.close();  
            } catch (SQLException e) {  
                e.printStackTrace();  
            }  
        }  
  
        if (connection != null) {  
            try {  
                statement.close();  
            } catch (SQLException e) {  
                e.printStackTrace();  
            }  
        }  
    }  
}

四:实体类和数据访问对象

(1)实体类

数据库中有什么样的表,程序中就必须有对应的实体类。因此创建User类和Blog类,并设置对应的getset方法

  • 注意:Blog类中的postTime类型为时间戳(Timestamp),在获取时需要转换为对应的“年月日”等格式,这里借助了SimpleDateFormat

Blog类

import java.sql.Timestamp;  
import java.text.SimpleDateFormat;  
  
public class Blog {  
    private int blogId;  
    private String title;  
    private String content;  
    private Timestamp postTime;  
    private int userId;  
  
    public int getBlogId() {  
        return blogId;  
    }  
  
    public void setBlogId(int blogId) {  
        this.blogId = blogId;  
    }  
  
    public String getTitle() {  
        return title;  
    }  
  
    public void setTitle(String title) {  
        this.title = title;  
    }  
  
    public String getContent() {  
        return content;  
    }  
  
    public void setContent(String content) {  
        this.content = content;  
    }  
  
    public String getPostTime() {  
        // 返回格式化好的字符串日期类型  
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年-MM月-dd日 HH:mm:ss");  
        return simpleDateFormat.format(this.postTime);  
  
    }  
  
    public void setPostTime(Timestamp postTime) {  
        this.postTime = postTime;  
    }  
  
    public int getUserId() {  
        return userId;  
    }  
  
    public void setUserId(int userId) {  
        this.userId = userId;  
    }  
}

User类

public class User {  
    private int userId;  
    private String userName;  
    private String passWord;  
  
    public int getUserId() {  
        return userId;  
    }  
  
    public void setUserId(int userId) {  
        this.userId = userId;  
    }  
  
    public String getUserName() {  
        return userName;  
    }  
  
    public void setUserName(String userName) {  
        this.userName = userName;  
    }  
  
    public String getPassWord() {  
        return passWord;  
    }  
  
    public void setPassWord(String passWord) {  
        this.passWord = passWord;  
    }  
}

(2)数据访问对象

针对实体类肯定有各种各样的增删改查操作,十分繁琐,所以我们需要创建对应的数据访问对象(Data Access Object, DAO)。BlogDAO对应Blog类,UserDAO对应User类

BlogDAO

import java.beans.PropertyEditorSupport;  
import java.sql.Connection;  
import java.sql.PreparedStatement;  
import java.sql.ResultSet;  
import java.sql.SQLException;  
import java.util.ArrayList;  
import java.util.List;  
  
// 针对博客表的一些操作  
public class BlogDAO  {  
    // 插入博客到数据库中  
    public void insert(Blog blog) throws SQLException {  
        Connection connection = null;  
        PreparedStatement statement = null;  
        try {  
            // 获取数据源并连接  
            connection = DBUtil.getConnection();  
            // 构造SQL  
            String sql = "insert into blog values(null, ?, ?, now(), ?)";  
            statement = connection.prepareStatement(sql);  
            statement.setString(1, blog.getTitle());  
            statement.setString(2, blog.getContent());  
            statement.setInt(3, blog.getUserId());  
            // 执行SQL  
            int ret = statement.executeUpdate();  
            if (ret != 1) {  
                System.out.println("插入失败!");  
            } else {  
                System.out.println("插入成功");  
            }  
        } catch (SQLException e) {  
            e.printStackTrace();  
        } finally {  
            // 释放资源  
            DBUtil.close(connection, statement, null);  
        }  
  
    }  
  
    // 根据blogId查询指定博客  
    public Blog selectById(int blogId) throws SQLException {  
        Connection connection = null;  
        PreparedStatement statement = null;  
        ResultSet resultSet = null;  
  
        try {  
            connection = DBUtil.getConnection();  
            String sql = "select * from blog where blogId = ?";  
            statement = connection.prepareStatement(sql);  
            statement.setInt(1, blogId);  
            resultSet = statement.executeQuery();  
  
            // 遍历结果,如果有查询结果则返回  
            if (resultSet.next()) {  
                Blog blog = new Blog();  
                blog.setBlogId(resultSet.getInt("blogId"));  
                blog.setTitle(resultSet.getString("title"));  
                blog.setContent(resultSet.getString("content"));  
                blog.setPostTime(resultSet.getTimestamp("postTime"));  
                blog.setUserId(resultSet.getInt("userId"));  
                return blog;  
            }  
        } catch (SQLException e) {  
            e.printStackTrace();  
        } finally {  
            DBUtil.close(connection, statement, resultSet);  
        }  
        return null;  
    }  
  
    // 查询所有博客  
    public List<Blog> selectAll() throws SQLException {  
        List<Blog> blogs = new ArrayList<>();  
        Connection connection = null;  
        PreparedStatement statement = null;  
        ResultSet resultSet = null;  
  
        try {  
            connection = DBUtil.getConnection();  
            // 注意发布时间要降序排序  
            String sql = "select * from blog order by postTime desc";  
            statement = connection.prepareStatement(sql);  
            resultSet = statement.executeQuery();  
  
            // 遍历结果,如果有查询结果则返回  
            while (resultSet.next()) {  
                Blog blog = new Blog();  
                blog.setBlogId(resultSet.getInt("blogId"));  
                blog.setTitle(resultSet.getString("title"));  
                // 注意:为了避免因博客content太多而导致博客列表页博客摘要显示过长  
                // 规定当content长度大于100时只显示部分内容,用户如果想要查看完整内容则需要点击按钮  
                String content = resultSet.getString("content");  
                if (content.length() > 100) {  
                    content = content.substring(0, 100) + "......";  
                }  
                blog.setContent(content);  
                blog.setPostTime(resultSet.getTimestamp("postTime"));  
                blog.setUserId(resultSet.getInt("userId"));  
                blogs.add(blog);  
            }  
        } catch (SQLException e) {  
            e.printStackTrace();  
        } finally {  
            DBUtil.close(connection, statement, resultSet);  
        }  
        return blogs;  
    }  
  
    // 根据blogId删除博客 (删除博客)  
    public void delete (int blogId) throws SQLException {  
        Connection connection = null;  
        PreparedStatement statement = null;  
  
        try {  
            connection = DBUtil.getConnection();  
            String sql = "delete from blog where blogId = ?";  
            statement = connection.prepareStatement(sql);  
            statement.setInt(1, blogId);  
            int ret = statement.executeUpdate();  
            if (ret != 1) {  
                System.out.println("删除失败!");  
            } else {  
                System.out.println("删除成功!");  
            }  
  
        } catch (SQLException e) {  
            e.printStackTrace();  
        } finally {  
            DBUtil.close(connection, statement, null);  
        }  
    }  
}

UserDAO

import java.sql.Connection;  
import java.sql.PreparedStatement;  
import java.sql.ResultSet;  
import java.sql.SQLException;  
  
// 针对用户表相关操作  
public class UserDAO {  
  
    // 根据用户名查询用户   
public User selectByUserName(String userName) throws SQLException {  
        Connection connection = null;  
        PreparedStatement statement = null;  
        ResultSet resultSet = null;  
  
        try {  
            connection = DBUtil.getConnection();  
            String sql = "Select * from user where userName = ?";  
            statement = connection.prepareStatement(sql);  
            statement.setString(1, userName);  
            resultSet = statement.executeQuery();  
            if (resultSet.next()) {  
                User user = new User();  
                user.setUserId(resultSet.getInt("userId"));  
                user.setUserName(resultSet.getString("userName"));  
                user.setPassWord(resultSet.getString("passWord"));  
  
                return user;  
            }  
        } catch (SQLException e) {  
            e.printStackTrace();  
        } finally {  
            DBUtil.close(connection, statement, resultSet);  
        }  
  
        return null;  
    }  
  
    // 根据userId查询用户  
    public User selectByUserId(int userId) throws SQLException {  
  
        Connection connection = null;  
        PreparedStatement statement = null;  
        ResultSet resultSet = null;  
  
        try {  
            connection = DBUtil.getConnection();  
            String sql = "Select * from user where userId = ?";  
            statement = connection.prepareStatement(sql);  
            statement.setInt(1, userId);  
            resultSet = statement.executeQuery();  
            if (resultSet.next()) {  
                User user = new User();  
                user.setUserId(resultSet.getInt("userId"));  
                user.setUserName(resultSet.getString("userName"));  
                user.setPassWord(resultSet.getString("passWord"));  
  
                return user;  
            }  
        } catch (SQLException e) {  
            e.printStackTrace();  
        } finally {  
            DBUtil.close(connection, statement, resultSet);  
        }  
  
        return null;  
    }  
}

五:各功能实现

这里是博客系统实现最复杂的地方,要搭建一个完整的博客系统,就要处理后前后端交互的逻辑。也即页面发起HTTP请求,然后服务器返回HTTP响应。我们只需要约定后请求和响应分别是什么样的,然后按照需求分别编写前端页面和后端服务即可

(1)登录功能

处理逻辑:当用户输入用户名和密码并点击登录后,就会发送请求给服务器,服务器负责验证。如果验证成功,则让页面跳转至博客列表页,否则弹出提示让其重新登录

  • 请求
    • POST/login
    • Content-Type:application/x-www-form-urlencoded
  • 响应
    • HTTP/1.1 302
    • Location:博客列表页

前端页面BlogLoginPage.html

<!DOCTYPE html>  
<html lang="en">  
<head>  
  <meta charset="UTF-8">  
  <title>登录页</title>  
  
  <link rel="stylesheet" href="css/Common.css">  
  <link rel="stylesheet" href="css/Blog_login.css">  
  
  
</head>  
<body>  
<!--导航栏-->  
<div class="nav">  
  <img src="image/电子书.png" alt="">  
  <span class="title">博客之家·文行天下</span>  
  
</div>  
  
<!--登录框-->  
<div class="container">  
  <!--登录对话框-->  
  <form action="login" method="post">  
  <div class="dialog">  
  
    <h3>登录你的账户</h3>  
    <div class="row">  
      <span>用户名</span>  
      <input type="text" required name="username">  
  
    </div>  
    <div class="row">  
      <span>密&nbsp&nbsp&nbsp码</span>  
      <input type="password" required name="password">  
    </div>  
    <div class="row">  
      <button id="login">登录</button>  
    </div>  
  
  </div>  
  </form>  
  
</div>  
  
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>  
<script>  
  $(document).ready(function() {  
    $("#login").click(function(event) {  
      event.preventDefault(); // 阻止表单默认提交行为  
  
      var username = $('input[name="username"]').val();  
      var password = $('input[name="password"]').val();  
  
      $.ajax({  
        url: "login",  
        type: "post",  
        data: {  
          username: username,  
          password: password  
        },  
        success: function(body) {  
          alert("登录成功!");  
          // 重定向到博客列表页  
          location.assign("/BlogSystem2/BlogListPage.html");  
        },  
        error: function(body) {  
          alert("用户名或密码为空,请重新输入!");  
        }  
      });  
    });  
  });  
</script>  
  
</body>  
</html>

后端LoginServlet.java

import com.fasterxml.jackson.databind.ObjectMapper;  
  
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 javax.servlet.http.HttpSession;  
import java.io.IOException;  
import java.sql.SQLException;  
import java.util.HashMap;  
import java.util.Map;  
  
@WebServlet("/login")  
public class LoginServlet extends HttpServlet {  
    @Override  
    // 登录功能  
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {  
        // 获取用户名和密码  
        req.setCharacterEncoding("utf-8");  
        String username = req.getParameter("username");  
        String password = req.getParameter("password");  
        if (username == null || "".equals(username) || password == null || "".equals(password)) {  
            resp.setContentType("text/html; charset=utf-8");  
            resp.getWriter().write("登录失败!用户名或密码为空");  
            resp.setStatus(403);  
            return;  
        }  
  
        // 查询数据库,验证用户名和密码是否正确  
        UserDAO userDAO = new UserDAO();  
        User user = null;  
        try {  
            user = userDAO.selectByUserName(username);  
            if (user == null || !user.getPassWord().equals(password)) {  
                resp.setContentType("text/html; charset=utf-8");  
                resp.getWriter().write("登录失败!用户名或密码错误");  
                resp.setStatus(401);  
  
                return;  
            }  
        } catch (SQLException e) {  
            e.printStackTrace();  
        }  
  
        // 如果正确则创建一个会话对象,保证在访问其他页面时可以直接判定是哪个用户在访问  
        HttpSession session = req.getSession(true);  
        session.setAttribute("user", user);  
    }  
}

(2)强制登录

处理逻辑:在博客列表页、详情页和编辑页加载后,会发起一个ajax请求,从服务器获取登录状态,如果是未登录状态则提示并重定向到登录页面,如果已经登录则不做任何改变

  • 请求
    • GET/login
  • 响应
    • 如果已经登录:HTTP/1.1 200 OK
    • 如果未登录:HTTP/1.1 403

前端页面BlogDetailPage.htmlBlogEditPage.htmlBlogListPage.html需要使用下面的js函数

function getLoginStatus() {  
    $.ajax({  
        type: 'get',  
        url: 'login',  
        success: function (body) {  
            // 已经在登录状态,不处理  
        },  
        error: function () {  
            // 非登录或其他状态,则强行跳转  
            alert("未登录!请登录后再访问")  
            location.assign('BlogLoginPage.html')  
        }  
    });  
}

后端LoginServlet.java

import com.fasterxml.jackson.databind.ObjectMapper;  
  
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 javax.servlet.http.HttpSession;  
import java.io.IOException;  
import java.sql.SQLException;  
import java.util.HashMap;  
import java.util.Map;  
  
@WebServlet("/login")  
public class LoginServlet extends HttpServlet {  
    @Override  
    // 登录功能  
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {  
        // 获取用户名和密码  
        req.setCharacterEncoding("utf-8");  
        String username = req.getParameter("username");  
        String password = req.getParameter("password");  
        if (username == null || "".equals(username) || password == null || "".equals(password)) {  
            resp.setContentType("text/html; charset=utf-8");  
            resp.getWriter().write("登录失败!用户名或密码为空");  
            resp.setStatus(403);  
            return;  
        }  
  
        // 查询数据库,验证用户名和密码是否正确  
        UserDAO userDAO = new UserDAO();  
        User user = null;  
        try {  
            user = userDAO.selectByUserName(username);  
            if (user == null || !user.getPassWord().equals(password)) {  
                resp.setContentType("text/html; charset=utf-8");  
                resp.getWriter().write("登录失败!用户名或密码错误");  
                resp.setStatus(401);  
  
                return;  
            }  
        } catch (SQLException e) {  
            e.printStackTrace();  
        }  
  
        // 如果正确则创建一个会话对象,保证在访问其他页面时可以直接判定是哪个用户在访问  
        HttpSession session = req.getSession(true);  
        session.setAttribute("user", user);  
    }  
  
    @Override  
    // 防止未登录直接访问  
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {  
        // 获取会话  
        HttpSession session = req.getSession(false);  
        // 没有会话则为未登录  
        if (session == null) {  
            resp.setStatus(403);  
            return;  
        }  
  
        // 如果有会话则已经登录,获取用户  
        User user = (User)session.getAttribute("user");  
        // 这里是为了结合注销逻辑,注销时会直接删除user  
        if (user == null) {  
            resp.setStatus(403);  
            return;  
        }  
  
        // 返回200  
        resp.setStatus(200);  
  
    }  
}

(3)博客列表页

处理逻辑:当博客列表页加载时就发起请求,从数据库中获取博客数据,然后展示

  • 请求
    • GET/blog
  • 响应
    • HTTP/1/1 200ok
    • Content-Type:application

前端页面BlogListPage.html

<!DOCTYPE html>  
<html lang="en">  
<head>  
    <meta charset="UTF-8">  
    <title>博客列表</title>  
  
    <link rel="stylesheet" href="css/Common.css">  
    <link rel="stylesheet" href="css/Blog_list.css">  
  
</head>  
<body>  
  
<!--导航栏-->  
<div class="nav">  
    <img src="image/电子书.png" alt="">  
    <span class="title">博客之家·文行天下</span>  
    <!--  用于占位  -->  
    <div class="space"></div>  
    <a href="BlogListPage.html">博客主页</a>  
    <a href="logout">注销账户</a>  
    <div class="creating"><a href="BlogEditPage.html">开始创作</a></div>  
  
</div>  
  
<!--版心区域-->  
<div class="container">  
    <!-- 用户信息 -->  
    <div class = "left">  
        <div class="card">  
            <!-- 用户头像 -->  
            <img src="image/头像.png" alt="">  
            <!-- 用户名字 -->  
            <h3></h3>  
            <!-- Github地址 -->  
            <a href="#">进入Github主页</a>  
            <div class="counter">  
                <span>文章</span>  
                <span>分类</span>  
            </div>  
            <div class="counter">  
                <span>2</span>  
                <span>1</span>  
            </div>  
        </div>  
    </div>  
  
    <!-- 博文列表 -->  
    <div class = right>  
        <!-- 每个blog是一篇博文 -->  
  
<!--        <div class="blog">  
            <div class="title">我的第一篇博客</div>  
            <div class="date">2023-03-13 06:00:00</div>            <div class="desc">                在这个充满机遇和挑战的时代,我们需要不断地学习和成长。  
                只有不断地提升自己的能力才能够适应未来社会的发展趋势,                并且取得更好的成就。无论是在工作中还是生活中,                都需要具备一定的技能和知识储备,以便更好地解决问题并迎接新挑战  
            </div>            <div class="click"><a href="BlogDetailPage.html">查看全文</a></div>  
        </div>-->  
  
    </div>  
</div>  
  
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>  
<script src="js/app.js"></script>  
  
<script>  
    // 利用ajax发送请求从服务器获取博文数据  
    function getBlogs() {  
        $.ajax({  
            type: 'get',  
            url: 'blog',  
            success: function(body) {  
                // 如果成功,那么body就是一个json对象数组,每个元素为一个博客  
                let container = document.querySelector('.right')  
                for (let blog of body) {  
                    // blogDiv  
                    let blogDiv = document.createElement('div');  
                    blogDiv.className = 'blog';  
  
                    // 博客标题  
                    let titleDiv = document.createElement('div');  
                    titleDiv.className = 'title';  
                    titleDiv.innerHTML = blog.title;  
                    // 博客日期  
                    let dateDiv = document.createElement('div');  
                    dateDiv.className = 'title';  
                    dateDiv.innerHTML = blog.postTime;  
                    // 博客摘要  
                    let descDiv = document.createElement('div');  
                    descDiv.className = 'desc';  
                    descDiv.innerHTML = blog.content;  
                    // 查看全文按钮  
                    let a = document.createElement('a');  
                    a.href = 'BlogDetailPage.html?blogId=' + blog.blogId;  
                    a.innerHTML = '查看全文';  
  
                    // 点击按钮  
                    let clickdiv = document.createElement('div');  
                    clickdiv.className = 'click';  
  
                    // 拼接  
                    blogDiv.appendChild(titleDiv);  
                    blogDiv.appendChild(dateDiv);  
                    blogDiv.appendChild(descDiv);  
                    clickdiv.appendChild(a);  
                    blogDiv.appendChild(clickdiv);  
                    container.appendChild(blogDiv);  
                }  
            }  
        });  
    }  
    getBlogs();  
  
    // 获取登录状态判断是否登录  
    getLoginStatus();  
  
    
</script>  
  
</body>  
</html>

后端BlogServlet.java

import com.fasterxml.jackson.databind.ObjectMapper;

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 javax.servlet.http.HttpSession;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;


// 博客列表页和博客详情页请求处理
@WebServlet("/blog")
public class BlogServlet extends HttpServlet {
    private ObjectMapper objectMapper = new ObjectMapper();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 按照约定的接口格式返回数据
        resp.setContentType("application/json; charset=utf-8");
        BlogDAO blogDAO = new BlogDAO();

        String blogId = req.getParameter("blogId");
        try {
            List<Blog> blogs = blogDAO.selectAll();
            resp.getWriter().write(objectMapper.writeValueAsString(blogs));
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

}


(4)博客详情页

处理逻辑:当在博客列表页中点击“查看全文”时就会跳转至该博客对应的详情页。在请求对应详情页面时,需要在请求的url处加上query_string,例如http://localhost:8080/BlogSystem2/BlogDetailPage.html?blogId=2就表示请求的是blogId=2的详情页

  • 请求
    • GET/blogId=1
  • 响应
    • HTTP/1.1 200 OK
    • Content-Type:applocation/json

需要注意的是,在博客列表页中,我们已经使用了BlogServlet.doGet方法了,如果博客列表页也想要使用的话就要作出区分。具体来说,如果请求带有queryString,有blogId这个参数,就认为这是博客详情页的请求,否则则认为是博客列表页的请求

前端页面BlogDetailPage.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>博客详情</title>

    <link rel="stylesheet" href="css/Common.css">
    <link rel="stylesheet" href="css/Blog_detail.css">

    <!-- 引入 editor.md 的依赖 -->
    <link rel="stylesheet" href="editor.md/css/editormd.min.css" />
    <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
    <script src="editor.md/lib/marked.min.js"></script>
    <script src="editor.md/lib/prettify.min.js"></script>
    <script src="editor.md/editormd.js"></script>

</head>

<body>
<div class="nav">
    <img src="image/电子书.png" alt="">
    <span class="title">博客之家·文行天下</span>
    <!--  用于占位  -->
    <div class="space"></div>
    <a href="BlogListPage.html">博客主页</a>
    <a href="logout">注销账户</a>
    <div class="creating"><a href="BlogEditPage.html">开始创作</a></div>
    <div class="deleting"><a href="blog_delete" id="delete-btn">删除文章</a></div>


</div>

<!--版心区域-->
<div class="container">
    <!-- 用户信息 -->
    <div class = "left">
        <div class="card">
            <!-- 用户头像 -->
            <img src="image/头像.png" alt="">
            <!-- 用户名字 -->
            <h3></h3>
            <!-- Github地址 -->
            <a href="#">进入Github主页</a>
            <div class="counter">
                <span>文章</span>
                <span>分类</span>
            </div>
            <div class="counter">
                <span>2</span>
                <span>1</span>
            </div>
        </div>
    </div>

    <!-- 博文详情 -->
    <div class = "right">
        <div class="blog_detail">
            <h3></h3>
            <div class="date"></div>
            <div id="content" style="background-color: transparent">

            </div>
        </div>
    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <script src="js/app.js"></script>
    <script>
        <!-- 利用ajax服务器获取该博客数据-->
             function getBlog() {
                $.ajax({
                    type: 'get',
                    // location.search可以返回query-string
                    url : 'blog' + location.search,
                    success: function (body) {
                        let h3 = document.querySelector('.blog_detail h3');
                        h3.innerHTML = body.title;
                        let dateDiv = document.querySelector('.date');
                        dateDiv.innerHTML = body.postTime;
                        // 此处应该使用editor.md对markdown内容进行渲染
                        editormd.markdownToHTML('content', {markdown: body.content});
                    }
                });
             }
             getBlog();
             getLoginStatus();

    </script>


</body>
</html>

后端BlogServlet.java

import com.fasterxml.jackson.databind.ObjectMapper;

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 javax.servlet.http.HttpSession;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;


// 博客列表页和博客详情页请求处理
@WebServlet("/blog")
public class BlogServlet extends HttpServlet {
    private ObjectMapper objectMapper = new ObjectMapper();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 按照约定的接口格式返回数据
        resp.setContentType("application/json; charset=utf-8");
        BlogDAO blogDAO = new BlogDAO();

        String blogId = req.getParameter("blogId");
        if (blogId == null) {
            // 这是博客列表页请求
            try {
                List<Blog> blogs = blogDAO.selectAll();
                resp.getWriter().write(objectMapper.writeValueAsString(blogs));
            } catch (SQLException e) {
                e.printStackTrace();
            }

        } else {
            // 这是博客详情页请求
            try {
                Blog blog = blogDAO.selectById(Integer.parseInt(blogId));

                resp.getWriter().write(objectMapper.writeValueAsString(blog));
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}


(5)显示用户信息和作者信息

处理逻辑

  • 在博客列表页加载时,从服务器获取当前登录的用户信息,然后将信息展现在页面之上
    • 请求
      • GET/userinfo
    • 响应
      • HTTP/1.1 200OK
      • content-Type:application/json
  • 在博客详情页加载时,从服务器获取博客的作者信息,然后展现在页面智商
    • 请求
      • GET/userinfo?blogId=1
    • 响应
      • Content-Type:application/json

前端页面BlogListPage.htmlBlogDetailPage.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>博客列表</title>

    <link rel="stylesheet" href="css/Common.css">
    <link rel="stylesheet" href="css/Blog_list.css">

</head>
<body>

<!--导航栏-->
<div class="nav">
    <img src="image/电子书.png" alt="">
    <span class="title">博客之家·文行天下</span>
    <!--  用于占位  -->
    <div class="space"></div>
    <a href="BlogListPage.html">博客主页</a>
    <a href="logout">注销账户</a>
    <div class="creating"><a href="BlogEditPage.html">开始创作</a></div>

</div>

<!--版心区域-->
<div class="container">
    <!-- 用户信息 -->
    <div class = "left">
        <div class="card">
            <!-- 用户头像 -->
            <img src="image/头像.png" alt="">
            <!-- 用户名字 -->
            <h3></h3>
            <!-- Github地址 -->
            <a href="#">进入Github主页</a>
            <div class="counter">
                <span>文章</span>
                <span>分类</span>
            </div>
            <div class="counter">
                <span>2</span>
                <span>1</span>
            </div>
        </div>
    </div>

    <!-- 博文列表 -->
    <div class = right>
        <!-- 每个blog是一篇博文 -->

<!--        <div class="blog">
            <div class="title">我的第一篇博客</div>
            <div class="date">2023-03-13 06:00:00</div>
            <div class="desc">
                在这个充满机遇和挑战的时代,我们需要不断地学习和成长。
                只有不断地提升自己的能力才能够适应未来社会的发展趋势,
                并且取得更好的成就。无论是在工作中还是生活中,
                都需要具备一定的技能和知识储备,以便更好地解决问题并迎接新挑战
            </div>
            <div class="click"><a href="BlogDetailPage.html">查看全文</a></div>
        </div>-->


    </div>
</div>

<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script src="js/app.js"></script>

<script>
    // 利用ajax发送请求从服务器获取博文数据
    function getBlogs() {
       ....
       ....
       ...
    }
    getBlogs();

    // 获取登录状态判断是否登录
    getLoginStatus();

    // 针对博客列表页获取当前用户的登录信息
    function getUserInfo() {
        $.ajax({
            type: 'get',
            url: 'userInfo',
            success: function(body) {
                let h3 = document.querySelector('.left>.card>h3');
                h3.innerHTML = body.userName;
            }
        });
    }
    getUserInfo();
</script>

</body>
</html>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>博客详情</title>

    <link rel="stylesheet" href="css/Common.css">
    <link rel="stylesheet" href="css/Blog_detail.css">

    <!-- 引入 editor.md 的依赖 -->
    <link rel="stylesheet" href="editor.md/css/editormd.min.css" />
    <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
    <script src="editor.md/lib/marked.min.js"></script>
    <script src="editor.md/lib/prettify.min.js"></script>
    <script src="editor.md/editormd.js"></script>

</head>

<body>
<div class="nav">
    <img src="image/电子书.png" alt="">
    <span class="title">博客之家·文行天下</span>
    <!--  用于占位  -->
    <div class="space"></div>
    <a href="BlogListPage.html">博客主页</a>
    <a href="logout">注销账户</a>
    <div class="creating"><a href="BlogEditPage.html">开始创作</a></div>
    <div class="deleting"><a href="blog_delete" id="delete-btn">删除文章</a></div>


</div>

<!--版心区域-->
<div class="container">
    <!-- 用户信息 -->
    <div class = "left">
        <div class="card">
            <!-- 用户头像 -->
            <img src="image/头像.png" alt="">
            <!-- 用户名字 -->
            <h3></h3>
            <!-- Github地址 -->
            <a href="#">进入Github主页</a>
            <div class="counter">
                <span>文章</span>
                <span>分类</span>
            </div>
            <div class="counter">
                <span>2</span>
                <span>1</span>
            </div>
        </div>
    </div>

    <!-- 博文详情 -->
    <div class = "right">
        <div class="blog_detail">
            <h3></h3>
            <div class="date"></div>
            <div id="content" style="background-color: transparent">

            </div>
        </div>
    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <script src="js/app.js"></script>
    <script>
        <!-- 利用ajax服务器获取该博客数据-->
             function getBlog() {
					...
                    ...
                    ...
             }
             getBlog();
             getLoginStatus();
        // 针对博客详情页获取当前用户信息
        function getUserInfo() {
            $.ajax({
                type: 'get',
                url: 'userInfo' + location.search,
                success: function(body) {
                    let h3 = document.querySelector('.left>.card>h3');
                    h3.innerHTML = body.userName;
                }
            });
        }
        getUserInfo();

        // 博文删除,为其赋上blogId
        function updateDeleteURL() {
            let DeleteBtn = document.querySelector('#delete-btn');
            DeleteBtn.href = 'blog_delete' + location.search;
        }
        updateDeleteURL();

    </script>


</body>
</html>


后端UserInfoServlet.java

import com.fasterxml.jackson.databind.ObjectMapper;  
  
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 javax.servlet.http.HttpSession;  
import java.io.IOException;  
import java.sql.SQLException;  
  
  
@WebServlet("/userInfo")  
public class UserInfoServlet extends HttpServlet {  
    private ObjectMapper objectMapper = new ObjectMapper();  
    @Override  
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {  
        String blogId = req.getParameter("blogId");  
        if (blogId == null) {  
            // 这是列表页在请求,直接从session中获取即可  
            getUserInfoFromSession(req, resp);  
  
        } else {  
            // 这是详情页在请求,查询数据库  
            try {  
                getUserInfoFromDB(req, resp, Integer.parseInt(blogId));  
            } catch (SQLException e) {  
                throw new RuntimeException(e);  
            }  
        }  
    }  
  
    private void getUserInfoFromDB(HttpServletRequest req, HttpServletResponse resp, int blogId) throws SQLException, IOException {  
        // 根据blogId查询Blog对象,获取userId  
        BlogDAO blogDAO = new BlogDAO();  
        Blog blog = blogDAO.selectById(blogId);  
        if (blog == null) {  
            // 未找到这样的blog  
            resp.setStatus(404);  
            resp.setContentType("text/html; charset=utf-8");  
            resp.getWriter().write("blogId不存在");  
            return;  
        }  
        // 根据userId查询对应的User对象  
        UserDAO userDAO = new UserDAO();  
        User user = userDAO.selectByUserId(blog.getUserId());  
        if (user == null) {  
            resp.setStatus(404);  
            resp.setContentType("text/html; charset=utf-8");  
            resp.getWriter().write("userId不存在");  
            return;  
        }  
        // 将user对象返回  
        user.setPassWord("");  
        resp.setContentType("application/json; charset=utf-8");  
        resp.getWriter().write(objectMapper.writeValueAsString(user));  
  
    }  
  
    private void getUserInfoFromSession(HttpServletRequest req, HttpServletResponse resp) throws IOException {  
        HttpSession session = req.getSession(false);  
        if (session == null) {  
            resp.setStatus(403);  
            resp.setContentType("text/html;charset=utf-8");  
            resp.getWriter().write("当前未登录");  
            return;  
        }  
  
        User user = (User)session.getAttribute("user");  
        if (user == null) {  
            resp.setStatus(403);  
            resp.setContentType("text/html;charset=utf-8");  
            resp.getWriter().write("当前未登录");  
            return;  
        }  
  
        // 移除password,避免返回密码  
        user.setPassWord("");  
        resp.setContentType("application/json;charset=utf-8");  
        resp.getWriter().write(objectMapper.writeValueAsString(user));  
  
  
    }  
}

(6)注销

处理逻辑:点击博客列表页、博客详情页和博客编辑页导航栏中的注销按钮后,会向服务器发送一个HTTP请求(不是ajax请求),告诉服务器准备退出登录,然后服务器会把会话中的user对象删除,同时重定向的登录页。需要注意的是这里删除的user对象而不是session对象,因为HttpSession没有一个直接用于删除的方法

  • 请求
    • GET/logout
  • 响应
    • HTTP/1.1 302
    • Location:login.html

前端页面BlogDetailPage.htmlBlogEditPage.htmlBlogListPage.html,只需要再路径处填入logout即可

<div class="nav">  
    <img src="image/电子书.png" alt="">  
    <span class="title">博客之家·文行天下</span>  
    <!--  用于占位  -->  
    <div class="space"></div>  
    <a href="BlogListPage.html">博客主页</a>  
    <a href="logout">注销账户</a>  
    <div class="creating"><a href="BlogEditPage.html">开始创作</a></div>  
    <div class="deleting"><a href="blog_delete" id="delete-btn">删除文章</a></div>  
  
  
</div>

后端LogOutServlet.java

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 javax.servlet.http.HttpSession;  
import java.io.IOException;  
  
// 注销逻辑  
@WebServlet("/logout")  
public class LogOutServlet extends HttpServlet {  
    @Override  
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {  
        // 获取当前会话  
        HttpSession session = req.getSession(false);  
        if (session == null) {  
            // 没有会话,当前是未登录状态  
            resp.setStatus(403);  
            return;  
        }  
  
        // 由于在判定是否登录的逻辑中要求会话和user必须同时存在,所以在这里我们可以直接删除user即可  
        session.removeAttribute("user");  
        // 重定向到登录页面  
        resp.sendRedirect("BlogLoginPage.html");  
    }  
}

(7)发布博客

处理逻辑:用户在博客编辑页中填写标题和内容后点击”发布文章“按钮,此时会发起一个HTTP请求。当服务器收到这些数据后,会构造一个blog对象,然后插入数据库。 发布成功后跳转至列表页

  • 请求
    • post/blog
    • Content-Type:application.x-www-from-urlencoded
  • 响应
    • HTTP/1.1 032
    • Location:blog_list.html

前端页面BlogEditPage.html

<!DOCTYPE html>  
<html lang="en">  
<head>  
    <meta charset="UTF-8">  
    <title>编辑博客</title>  
  
    <link rel="stylesheet" href="css/Common.css">  
    <link rel="stylesheet" href="css/Blog_edit.css">  
  
    <!-- 引入 editor.md 的依赖 -->  
    <link rel="stylesheet" href="editor.md/css/editormd.min.css" />  
    <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>  
    <script src="editor.md/lib/marked.min.js"></script>  
    <script src="editor.md/lib/prettify.min.js"></script>  
    <script src="editor.md/editormd.js"></script>  
  
  
  
</head>  
<body>  
  
<div class="nav">  
    <img src="image/电子书.png" alt="">  
    <span class="title">博客之家·文行天下</span>  
    <!--  用于占位  -->  
    <div class="space"></div>  
    <a href="BlogListPage.html">博客主页</a>  
    <a href="logout">注销账户</a>  
    <div class="creating"><a href="BlogEditPage.html">开始创作</a></div>  
  
</div>  
  
  
<!--markdown编辑器区域-->  
<div class="container">  
    <!--标题编辑区-->  
    <div class="title">  
        <input type="text" id="title-input" placeholder="在这里输入博客标题(100字以内)">  
        <button id="title-submit">发布文章</button>  
    </div>  
    <!--正文编辑区-->  
    <div id="editor">  
  
    </div>  
  
</div>  
  
<script src="js/app.js"></script>  
<script>  
    // 初始化编辑器, 代码也是截取自 官方文档 .    var editor = editormd("editor", {  
        // 这里的尺寸必须在这里设置. 设置样式会被 editormd 自动覆盖掉.  
        width: "100%",  
        // 设定编辑器高度  
        height: "calc(100% - 50px)",  
        // 编辑器中的初始内容  
        markdown: "## hello world",  
        // 指定 editor.md 依赖的插件路径  
        path: "editor.md/lib/",  
        // 发布文章  
        // saveHTMLToTextarea: true,  
    });  
  
    getLoginStatus();  
  
    // 发布博客  
    $(document).ready(function() {  
        // 当点击发布文章按钮时执行  
        $("#title-submit").click(function() {  
            // 获取博客标题和内容  
            let title = $("#title-input").val();  
            let content = editor.getMarkdown(); // 假设你已经初始化了editor.md并赋给了变量editor  
            console.log(content);  
            // 创建一个包含标题和内容的对象  
            let postData = {  
                title: title,  
                content: content  
            };  
  
            // 发送POST请求  
            $.ajax({  
                type: "POST",  
                url: "blog", // 替换成你的服务器端处理请求的URL  
                data: JSON.stringify(postData), // 将数据转换为JSON格式  
                contentType: "application/json",  
                success: function(response) {  
                    // 请求成功处理  
                    location.assign("/BlogSystem2/BlogListPage.html");  
                },  
                error: function(error) {  
                    // 请求失败处理  
                    console.error("文章发布失败", error);  
                }  
            });  
        });  
    });  
  
  
</script>  
  
  
</body>  
</html>

后端BlogServlet.java

import com.fasterxml.jackson.databind.ObjectMapper;

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 javax.servlet.http.HttpSession;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;


// 博客列表页和博客详情页请求处理
@WebServlet("/blog")
public class BlogServlet extends HttpServlet {
    private ObjectMapper objectMapper = new ObjectMapper();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 按照约定的接口格式返回数据
		....
            ....
            	....
    }

    //提交新博客

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取会话和用户信息
    /*
    按照道理来说,这里不需要在判定登录了。因为既然能发起Post请求说明已经登录了
    但是有人可能会利用postman等工具收到发起Post请求
    同时要构造博客对象,必须知道现在谁在登录,才能知道文章作者是谁
     */
        HttpSession session = req.getSession(false);
        if (session == null) {
            resp.setStatus(403);
            resp.setContentType("text/html; charset=utf-8");
            resp.getWriter().write("未登录,请登录后再访问");
            return;
        }

        User user = (User)session.getAttribute("user");
        if (user == null) {
            resp.setStatus(403);
            resp.setContentType("text/html; charset=utf-8");
            resp.getWriter().write("未登录,请登录后再访问");
            return;
        }

        // 获取博客标题和正文
        req.setCharacterEncoding("utf-8");

        // 从请求体中获取JSON数据并解析为Blog对象
        ObjectMapper objectMapper = new ObjectMapper();
        Blog blog = objectMapper.readValue(req.getReader(), Blog.class);

        // 设置博客的用户ID为当前用户的ID
        blog.setUserId(user.getUserId());

        // 构造Blog对象并插入到数据库中
        BlogDAO blogDAO = new BlogDAO();
        try {
            blogDAO.insert(blog);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

        // 发布成功后重定向到列表页
        resp.sendRedirect("BlogListPage.html");
    }
}


(8)删除博客

处理逻辑:当点击博客详情页上的“删除文章”后,服务器会做出一个判定,如果当前登录的用户就是文章的作者,才能真正删除

  • 请求
    • GET/bloh_delete?blogId=1
  • 响应
    • 删除成功
      • HTTP/1.1 302
      • Location:blog_list.html
    • 删除失败
      • HTTP/1.1 302
      • 没有删除权限

前端页面BlogDetailPage.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>博客详情</title>

    <link rel="stylesheet" href="css/Common.css">
    <link rel="stylesheet" href="css/Blog_detail.css">

    <!-- 引入 editor.md 的依赖 -->
    <link rel="stylesheet" href="editor.md/css/editormd.min.css" />
    <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
    <script src="editor.md/lib/marked.min.js"></script>
    <script src="editor.md/lib/prettify.min.js"></script>
    <script src="editor.md/editormd.js"></script>

</head>

<body>
<div class="nav">
    <img src="image/电子书.png" alt="">
    <span class="title">博客之家·文行天下</span>
    <!--  用于占位  -->
    <div class="space"></div>
    <a href="BlogListPage.html">博客主页</a>
    <a href="logout">注销账户</a>
    <div class="creating"><a href="BlogEditPage.html">开始创作</a></div>
    <div class="deleting"><a href="blog_delete" id="delete-btn">删除文章</a></div>


</div>

<!--版心区域-->
<div class="container">
    <!-- 用户信息 -->
    <div class = "left">
        <div class="card">
            <!-- 用户头像 -->
            <img src="image/头像.png" alt="">
            <!-- 用户名字 -->
            <h3></h3>
            <!-- Github地址 -->
            <a href="#">进入Github主页</a>
            <div class="counter">
                <span>文章</span>
                <span>分类</span>
            </div>
            <div class="counter">
                <span>2</span>
                <span>1</span>
            </div>
        </div>
    </div>

    <!-- 博文详情 -->
    <div class = "right">
        <div class="blog_detail">
            <h3></h3>
            <div class="date"></div>
            <div id="content" style="background-color: transparent">

            </div>
        </div>
    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <script src="js/app.js"></script>
    <script>
        <!-- 利用ajax服务器获取该博客数据-->
             function getBlog() {
				...
                	...
             }
             getBlog();
             getLoginStatus();
        // 针对博客详情页获取当前用户信息
        function getUserInfo() {
			...
            	...
        }
        getUserInfo();

        // 博文删除,为其赋上blogId
        function updateDeleteURL() {
            let DeleteBtn = document.querySelector('#delete-btn');
            DeleteBtn.href = 'blog_delete' + location.search;
        }
        updateDeleteURL();

    </script>

</body>
</html>

后端BlogServlet.java

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 javax.servlet.http.HttpSession;  
import java.io.IOException;  
import java.sql.SQLException;  
  
  
@WebServlet("/blog_delete")  
public class BlogDeleteServlet extends HttpServlet {  
    @Override  
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {  
        // 判定用户登录状态  
        HttpSession session = req.getSession(false);  
        if (session == null) {  
            resp.setStatus(403);  
            resp.setContentType("text/html; charset=utf-8");  
            resp.getWriter().write("未登录,请登录后再访问");  
            return;  
        }  
  
        User user = (User)session.getAttribute("user");  
        if (user == null) {  
            resp.setStatus(403);  
            resp.setContentType("text/html; charset=utf-8");  
            resp.getWriter().write("未登录,请登录后再访问");  
            return;  
        }  
  
        // 获取blogId  
        String blogId = req.getParameter("blogId");  
        if (user == null) {  
            // 没有这样的blogId  
            resp.setStatus(404);  
            resp.setContentType("text/html; charset=utf-8");  
            resp.getWriter().write("blogId有误");  
            return;  
        }  
  
        // 获取对应Blog  
        BlogDAO blogDAO = new BlogDAO();  
        Blog blog = null;  
        try {  
            blog = blogDAO.selectById(Integer.parseInt(blogId));  
            if (blog == null) {  
                // 没有这样的blog  
                resp.setStatus(404);  
                resp.setContentType("text/html; charset=utf-8");  
                resp.getWriter().write("当前删除的博客不存在");  
                return;  
            }  
        } catch (SQLException e) {  
            throw new RuntimeException(e);  
        }  
  
        // 判断登录用户是否就是文章作者  
        if (blog.getUserId() != user.getUserId()) {  
            // 不能删除别人的博客  
            resp.setStatus(404);  
            resp.setContentType("text/html; charset=utf-8");  
            resp.getWriter().write("禁止删除他人博客");  
            return;  
        }  
  
        // 实际删除  
        try {  
            blogDAO.delete(Integer.parseInt(blogId));  
        } catch (SQLException e) {  
            throw new RuntimeException(e);  
        }  
        // 重定向  
        resp.sendRedirect("BlogListPage.html");  
    }  
}

0

评论区