JavaWeb项目—— 博客系统

文章目录

  • 效果展示
    • 1. 创建 maven 项目
    • 2. 设计数据库
    • 3. 封装数据库的操作代码
      • 3.1 创建 DBUtil 类
      • 3.2 创建 Blog(代表一篇博客
      • 3.3 创建 User(代表一个用户
      • 3.4 创建类 BlogDao(对博客表进行操作
      • 3.5 创建类 UserDao (对用户表进行操作)
    • 4. 导入之前已经写好的前端代码
    • 5. 实现博客主页界面
      • 5.1 约定好前后端交互接口
      • 5.2 实现 BlogServlet
      • 5.3 实现 前端代码
    • 6. 实现博客详情界面
      • 6.1 约定好前后端交互接口
      • 6.2 实现BlogServlet
      • 6.3 实现前端代码
    • 7. 实现登录界面
      • 7.1 约定好前后端交互接口
      • 7.2 实现 LoginServlet
      • 7.3 实现前端代码
    • 8. 实现登录状态判定功能
      • 8.1 约定前后端交互接口
      • 8.2 在 LoginServlet 进行代码添加
      • 8.3 在前端代码中创建 common.js
      • 8.4 修改前端代码
    • 9. 实现显示用户信息功能
      • 9.1 约定好前后端交互接口
      • 9.2 实现 AuthorServlet 代码
      • 9.3 实现前端代码
        • 针对博客列表页进行修改
        • 针对博客详情页
    • 10. 实现注销功能
      • 10.1 约定好前后端交互接口
      • 10.2 实现 LogouServlet
      • 10.3 实现前端代码
    • 11. 实现发布博客功能
      • 11.1 约定好前后端交互的接口
      • 11.2 在BlogServlet中添加doPost方法
      • 11.3 实现前端代码
    • 12. 删除博客
      • 12.1 约定号前后端交互接口
      • 12.1 实现前端代码
      • 12.2 实现BlogDeleteServlet

效果展示

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


1. 创建 maven 项目

创建必要的目录,引入需要的依赖

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2. 设计数据库

本系统要存入博客文章的信息和用户的信息

创建博客表

博客的 id,博客的标题,博客的内容,博客的日期,博文的博主 id

创建用户表

用户 id 用户名 用户密码

-- 创建一个数据库create database if not exists java102_blog;use java102_blog;-- 创建一个博客表.drop table if exists blog;create table blog (    blogId int primary key auto_increment,    title varchar(1024),    content mediumtext,    userId int,         -- 文章作者的 id    postTime datetime   -- 发布时间);---- 给博客表中插入点数据, 方便测试.insert into blog values(null, '这是第一篇博客', '从今天开始, 我要认真学 Java', 1, now());insert into blog values(null, '这是第二篇博客', '从昨天开始, 我要认真学 Java', 1, now());insert into blog values(null, '这是第三篇博客', '从前天开始, 我要认真学 Java', 1, now());insert into blog values(null, '这是第一篇博客', '从今天开始, 我要认真学 C++', 2, now());insert into blog values(null, '这是第二篇博客', '从昨天开始, 我要认真学 C++', 2, now());insert into blog values(null, '这是第三篇博客', '# 一级标题n ### 三级标题n > 这是引用内容', 2, now());-- 创建一个用户表drop table if exists user;create table user (    userId int primary key auto_increment,    username varchar(128) unique,    -- 后续会使用用户名进行登录, 一般用于登录的用户名都是不能重复的.    password varchar(128));insert into user values(null, 'zhangsan', '123');insert into user values(null, 'lisi', '123');insert into user values(null, 'ling', '123');

3. 封装数据库的操作代码

创建包 model 用来存放数据库的代码

3.1 创建 DBUtil 类

用于和数据库建立连接

package model;import com.mysql.cj.jdbc.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 final String URL = "jdbc:mysql://127.0.0.1:3306/java102_blog?characterEncoding=utf8&useSSL=false";    private static final String USERNAME = "root";    private static final String PASSWORD = "707703";    private volatile static DataSource dataSource = null;    private static DataSource getDataSource() {        if(dataSource == null) {            synchronized (DBUtil.class) {                if(dataSource == null) {                    dataSource = new MysqlDataSource();                    ((MysqlDataSource)dataSource).setUrl(URL);                    ((MysqlDataSource)dataSource).setUser(USERNAME);                    ((MysqlDataSource)dataSource).setPassword(PASSWORD);                }            }        }        return dataSource;    }    // 建立链接    public static Connection getConnection() throws SQLException {        return getDataSource().getConnection();    }    // 断开链接    public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet)  {        if(resultSet != null) {            try {                resultSet.close();            } catch (SQLException throwables) {                throwables.printStackTrace();            }        }        if(statement != null) {            try {                statement.close();            } catch (SQLException throwables) {                throwables.printStackTrace();            }        }        if(connection != null) {            try {                connection.close();            } catch (SQLException throwables) {                throwables.printStackTrace();            }        }    }}

3.2 创建 Blog(代表一篇博客

package model;import java.sql.Timestamp;import java.text.SimpleDateFormat;// 每个 blog对象 ,对应 blog 表里的一条记录public class Blog {    private int blogId;    private String title;    private String content;    private int userId;    private Timestamp postTime;    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 int getUserId() {        return userId;    }    public void setUserId(int userId) {        this.userId = userId;    }        // 把这里 的 getter 方法给改了,不是返回一个 时间搓对象,而是返回一个 string(格式化的时间)    public String getPostTime() {        // 使用这个类 来完成时间戳到格式化日期的转换        // 这个 转换过程,需要构造方法中制定要转换的格式,然后调用 format 来进行转换        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");        return simpleDateFormat.format(postTime);    }    public void setPostTime(Timestamp postTime) {        this.postTime = postTime;    }}

3.3 创建 User(代表一个用户

package model;// 每个 model.User 对象, 期望能够表示 user 表中的一条记录.public class User {    private int userId = 0;    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;    }}

3.4 创建类 BlogDao(对博客表进行操作

注意
对数据进行插入删除操作时,执行 sql
在这里插入图片描述
其他操作
在这里插入图片描述
插入顺序
在这里插入图片描述

package model;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 {    // 1.往博客表里,插入一个博客    public void insert(Blog blog) {        // JDBC 代码        Connection connection = null;        PreparedStatement statement = null;        try {            // 1. 先和数据库建立连接            connection = DBUtil.getConnection();            // 2. 构造 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());            // 3. 执行 sql            statement.executeUpdate();        } catch (SQLException throwables) {            throwables.printStackTrace();        }finally {            // 4. 关闭连接,释放资源            DBUtil.close(connection,statement,null);        }    }    // 2. 获取博客列表中的所有博客信息    public List<Blog> selectAll() {        List<Blog> blogs = new ArrayList<>();        // JDBC 代码        Connection connection = null;        PreparedStatement statement = null;        ResultSet resultSet = null;        try {            // 1. 先建立链接            connection = DBUtil.getConnection();            // 2. 构造 sql 语句            String sql = "select * from blog order by postTime desc";            statement = connection.prepareStatement(sql);            // 3. 执行 sql            resultSet = statement.executeQuery();            // 把查询到的数据 存储到 blogs 当中            while (resultSet.next()) {                Blog blog = new Blog();                blog.setBlogId(resultSet.getInt("blogId"));                blog.setTitle(resultSet.getString("title"));                // 这里需要针对内容进行截断(太长,就去掉后面的)                String content = resultSet.getString("content");                if(content.length() > 50) {                    content = content.substring(0,50) + "..点进来吧我的宝";                }                blog.setContent(content);                blog.setUserId(resultSet.getShort("userId"));                blog.setPostTime(resultSet.getTimestamp("postTime"));                blogs.add(blog);            }        } catch (SQLException throwables) {            throwables.printStackTrace();        }finally {            DBUtil.close(connection,statement,resultSet);        }        return blogs;    }    // 3. 能够根据博客 id 获取到制定的博客内容(用于博客详情页)    public Blog selectOne(int blogId) {        Connection connection = null;        PreparedStatement statement = null;        ResultSet resultSet = null;        try{            // 1. 建立连接            connection = DBUtil.getConnection();            // 2. 构造 sql 语句            String sql = "select * from blog where blogId = ?";            statement = connection.prepareStatement(sql);            statement.setInt(1,blogId);            // 3. 执行 sql            resultSet = statement.executeQuery();            // 此处我们是使用 主键 来作为 查询条件,查询结果,要么是 1,要么是 0            if(resultSet.next()) {                Blog blog = new Blog();                blog.setBlogId(resultSet.getInt("blogId"));                blog.setTitle(resultSet.getString("title"));                blog.setContent(resultSet.getString("content"));                blog.setUserId(resultSet.getShort("userId"));                blog.setPostTime(resultSet.getTimestamp("postTime"));                return blog;            }        } catch (SQLException throwables) {            throwables.printStackTrace();        }finally {            // 4. 关闭连接 释放资源            DBUtil.close(connection,statement,resultSet);        }        return null;    }    // 4.  从博客列表中,根据博客 id 删除博客    public void delete(int blogId) {        Connection connection = null;        PreparedStatement statement = null;        try {            // 1. 建立 连接            connection = DBUtil.getConnection();            // 2. 构造 sql 语句            String sql = "delete from blog where blogId = ";            statement = connection.prepareStatement(sql);            statement.setInt(1,blogId);            // 3. 执行 sql            statement.executeUpdate();        } catch (SQLException throwables) {            throwables.printStackTrace();        }finally {            DBUtil.close(connection,statement,null);        }    }}

3.5 创建类 UserDao (对用户表进行操作)

package model;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;public class UserDao {    // 1. 根据用户名 查找用户信息    public User selectByName(String username) {        Connection connection = null;        PreparedStatement statement = null;        ResultSet resultSet = null;        try{            // 1. 建立 连接            connection = DBUtil.getConnection();            // 2. 构造 sql 语句            String sql = "select * from user where username = ?";            statement = connection.prepareStatement(sql);            statement.setString(1,username);            // 3. 执行 sql            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 throwables) {            throwables.printStackTrace();        }finally {            // 4. 关闭连接 释放资源            DBUtil.close(connection,statement,resultSet);        }        return null;    }    // 2. 根据 用户 id 来找 用户信息    // 博客详情页 就可以根据用户 id 来查询作者的名字,把作者名字显示出来    public User selectById(int userId) {        Connection connection = null;        PreparedStatement statement = null;        ResultSet resultSet = null;        try {            // 1. 建立连接            connection = DBUtil.getConnection();            // 2. 构造 sql 语句            String sql = "select * from user where userId = ?";            statement = connection.prepareStatement(sql);            statement.setInt(1,userId);            // 3. 执行sql            resultSet = statement.executeQuery();            // 此处的 username 使用 unique 约束,要么能查到一个,要么一个都查不到            // 4. 遍历结果集            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 throwables) {            throwables.printStackTrace();        }finally {            DBUtil.close(connection,statement,resultSet);        }        return null;    }}

4. 导入之前已经写好的前端代码

在这里插入图片描述

5. 实现博客主页界面

5.1 约定好前后端交互接口

在这里插入图片描述

5.2 实现 BlogServlet

import model.BlogDao;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.io.IOException;import java.util.List;// 通过这个类, 来处理 /blog 路径对应的请求@WebServlet("/blog")public class BlogServlet extends HttpServlet {    private ObjectMapper objectMapper = new ObjectMapper();    // 这个方法用来获取到数据库中的博客列表.    @Override    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {        // 从数据库中查询到博客列表, 转成 JSON 格式, 然后直接返回即可.        BlogDao blogDao = new BlogDao();        List<Blog> blogs = blogDao.selectAll();         //把 blogs 对象转成 JSON 格式.        String respJson = objectMapper.writevalueAsString(blogs);        resp.setContentType("application/json; charset=utf8");        resp.getWriter().write(respJson);    }}

5.3 实现 前端代码

在 blog_list.html 中 实现 ajax

注意:引入依赖

<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>    <script>        // 在页面加载的时候, 通过 ajax 给服务器发送数据, 获取到博客列表信息, 并且显示在界面上.         function getBlogList() {            $.ajax({                type: 'get',                url: 'blog',                success: function(body) {                    // 获取到的 body 就是一个 js 对象数组, 每个元素就是一个 js 对象, 根据这个对象构造 div                    // 1. 先把 .right 里原有的内容给清空                    let rightDiv = document.querySelector('.right');                    rightDiv.innerHTML = '';                    // 2. 遍历 body, 构造出一个个的 blogDiv                    for (let blog of body) {                        let blogDiv = document.createElement('div');                        blogDiv.className = 'blog';                        // 构造标题                        let titleDiv = document.createElement('div');                        titleDiv.className = 'title';                        titleDiv.innerHTML = blog.title;                        blogDiv.appendChild(titleDiv);                        // 构造发布时间                        let dateDiv = document.createElement('div');                        dateDiv.className = 'date';                        dateDiv.innerHTML = blog.postTime;                        blogDiv.appendChild(dateDiv);                        // 构造博客的摘要                        let descDiv = document.createElement('div');                        descDiv.className = 'desc';                        descDiv.innerHTML = blog.content;                        blogDiv.appendChild(descDiv);                        // 构造 查看全文                        let a = document.createElement('a');                        a.innerHTML = '查看全文 &gt;&gt;';                        // 此处希望点击之后能够跳转到 博客详情页 !!                        // 这个跳转过程需要告知服务器要访问的是哪个博客的详情页.                         a.href = 'blog_detil.html?blogId=' + blog.blogId;                        blogDiv.appendChild(a);                        // 把 blogDiv 挂到 dom 树上!                        rightDiv.appendChild(blogDiv);                    }                },                 error: function() {                    alert("获取博客列表失败!");                }            });        }        getBlogList();        </script>

6. 实现博客详情界面

6.1 约定好前后端交互接口

在这里插入图片描述

6.2 实现BlogServlet

这里后端代码和博客列表页的获取,基本相同,就直接放到一个方法中,来实现!使用blogId参数来区别是获取博客列表还是详情
这里注意:博客列表页在也在BlogServlet中实现的,我们如何去区别呢
在这里插入图片描述

package controller;import com.fasterxml.jackson.databind.ObjectMapper;import model.Blog;import model.BlogDao;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.io.IOException;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=utf8");        BlogDao blogDao = new BlogDao();        // 先尝试获取到 req 中的 blogId 参数. 如果该参数存在, 说明是要请求博客详情        // 如果该参数不存在, 说明是要请求博客的列表.        String param = req.getParameter("blogId");        if (param == null) {            // 不存在参数, 获取博客列表            List<Blog> blogs = blogDao.selectAll();            // 把 blogs 对象转成 JSON 格式.            String respJson = objectMapper.writevalueAsString(blogs);            resp.getWriter().write(respJson);        } else {            // 存在参数, 获取博客详情            int blogId = Integer.parseInt(param);            Blog blog = blogDao.selectOne(blogId);            String respJson = objectMapper.writevalueAsString(blog);            resp.getWriter().write(respJson);        }    }}

6.3 实现前端代码

修改 blog_detail.html,让这个页面加载的时候,能够调用到上述的接口,来从服务器获取到博客数据

注意
在这里插入图片描述

在这里插入图片描述

在博客详情页中引入 editor


<script>              function getBlogDetail() {            $.ajax({                type: 'get',                // location.search 拿到了形如 '?blogId=5' 这样的一段内容                url: 'blog2' + location.search,                success: function(body) {                    // 根据 body 中的内容来构造页面                                        // 1. 构造博客标题S                    let h3 = document.querySelector(".blog-content>h3");                    h3.innerHTML = body.title;                    // 2. 构造博客发布时间                    let dateDiv = document.querySelector('.date');                    dateDiv.innerHTML = body.postTime;                    // 3. 构造博客正文                    // 如果直接把 content 设为 innerHTML, 此时展示在界面上的内容, 是原始的 markdown 字符串                    // 咱们需要的是渲染后的, 带有格式的效果                    // let content = document.querySelector('#content');                    // content.innerHTML = body.content;                    // 第一个参数对应 id=content 的 html 标签. 渲染后得到的 html 片段就会被放到这个 标签下.                     editormd.markdownToHTML('content', {                        markdown: body.content                    });                }            });        }        getBlogDetail();    </script>

7. 实现登录界面

这里需要注意:啥样才算是已经登录

用户有一个 session,同时 session 有一个 user 属性 ~
两者同时具备,才叫登录状态

这里先给注销做铺垫:理解一下注销是如何操作的

注销只要破坏掉上面的任意一个条件就行了

7.1 约定好前后端交互接口

在这里插入图片描述

7.2 实现 LoginServlet

package controller;import com.fasterxml.jackson.databind.ObjectMapper;import model.User;import model.UserDao;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("/login")public class LoginServlet extends HttpServlet {    private  ObjectMapper objectMapper = new ObjectMapper();    @Override    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {        req.setCharacterEncoding("utf-8");        resp.setCharacterEncoding("utf-8");        // 1. 获取到请求中的参数        String username = req.getParameter("username");        String password = req.getParameter("password");        if(username == null || "".equals(username) || password == null || "".equals(password)) {            // 请求内容缺失,登录失败            resp.setContentType("text/html; charset=utf8");            resp.getWriter().write("当前的用户名或者密码为空");            return;        }        // 2. 和数据库中的的内容进行比较        UserDao userDao = new UserDao();        User user = userDao.selectByName(username);        if(user == null || !user.getPassword().equals(password)) {            // 用户没有查到或者密码不匹配,登录失败            resp.setContentType("text/html;charset=utf8");            resp.getWriter().write("用户名或密码错误");            return;        }        // 3. 如果比较通过,则创建会话        HttpSession session = req.getSession(true);        // 把刚才的用户信息,存储到会话中        session.setAttribute("user",user);        // 4. 返回一个重定向报文,跳转到博客列表页        resp.sendRedirect("blog_list.html");    } }

7.3 实现前端代码

修改blog_login.html 这里只需要在原来登录操作上套上一层 form 标签就可以了
在这里插入图片描述

因为这里在原有的基础上填上了 form表单,我们在 css 中也会有一些改动

在这里插入图片描述

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>登录页面</title>    <link rel="stylesheet" href="css/common.css">    <link rel="stylesheet" href="css/blog_login.css"></head><body>     <!--这是导航栏 nav-->     <div class = "nav">        <img src="imge/ph.png" alt="">        <!--标题 span-->        <span>我的博客系统</span>       <!--这是一个空白元素用来占位置-->        <div class="spacer"></div>        <!--链接标签<a>-->        <a href="blog_list.html">主页</a>        <a href="blog_edit.html">写博客</a>        <!--# 空链接--> <!--注销没必要显示在登录页面-->>        <!-- <a href="#">注销</a> -->    </div>    <div class="login-container">        <form action="login" method="post">            <!--空白页-->        <div class="login-dialog">            <h3>登录</h3>            <div class="row"> <!--一行-->                <span>用户名</span>                <input type="text" id="username" name="username">            </div>            <div class="row">                <span>密码</span>                <input type="password" id="password" name="password">            </div>            <div class="row">                <!-- <button>提交</button> -->                <input type="submit" id="submit" value="提交">            </div>        </div>        </form>        </div>    </div></body></html>

8. 实现登录状态判定功能

在这里插入图片描述

8.1 约定前后端交互接口

在这里插入图片描述

8.2 在 LoginServlet 进行代码添加

package controller;import com.fasterxml.jackson.databind.ObjectMapper;import model.User;import model.UserDao;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("/login")public class LoginServlet extends HttpServlet {    private  ObjectMapper objectMapper = new ObjectMapper();    @Override    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {        req.setCharacterEncoding("utf-8");        resp.setCharacterEncoding("utf-8");        // 1. 获取到请求中的参数        String username = req.getParameter("username");        String password = req.getParameter("password");        if(username == null || "".equals(username) || password == null || "".equals(password)) {            // 请求内容缺失,登录失败            resp.setContentType("text/html; charset=utf8");            resp.getWriter().write("当前的用户名或者密码为空");            return;        }        // 2. 和数据库中的的内容进行比较        UserDao userDao = new UserDao();        User user = userDao.selectByName(username);        if(user == null || !user.getPassword().equals(password)) {            // 用户没有查到或者密码不匹配,登录失败            resp.setContentType("text/html;charset=utf8");            resp.getWriter().write("用户名或密码错误");            return;        }        // 3. 如果比较通过,则创建会话        HttpSession session = req.getSession(true);        // 把刚才的用户信息,存储到会话中        session.setAttribute("user",user);        // 4. 返回一个重定向报文,跳转到博客列表页        resp.sendRedirect("blog_list.html");    } //   //  这个方法用来让前端检测当前的登录状态~~~~~~~~~~~~~~~~~~~~~~    // 1)检测有无会话 2)检测有无属性    @Override    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {       resp.setContentType("application/json;charset=utf8");       HttpSession session =  req.getSession(false);       if(session == null) {           // 1) 检测有无会话,无说明未登录           // 创建对象--> 里面为空           User user = new User();           resp.getWriter().write(objectMapper.writevalueAsString(user));           return;       }       User user = (User) session.getAttribute("user");       if(user == null) {           // 2)虽然有会话,但是会话里如果没有 user 对象,也视为未登录           user = new User();           resp.getWriter().write(objectMapper.writevalueAsString(user));           return;       }       // 已经登录的状态!        // 注意,此处不要把密码返回到前端        user.setPassword("");        resp.getWriter().write(objectMapper.writevalueAsString(user));    }}

8.3 在前端代码中创建 common.js

在这里插入图片描述

// 这个文件里放一些 页面公共的代码// 加上一个逻辑,通过 GET/login 这个接口来获取下当前的登录状态function getUserInfo() {    $.ajax({        type: 'get',        url: 'login',        success: function(body) {            // 判定此处的 body 是不是一个有效的 user 对象(userId 是否非 0)            if(body.userId && body.userId >0) {                // 登录成功                // 不做处理                console.log("当前用户登录成功!用户名" + body.username);            }else{                // 登录失败                // 让前端页面,跳转到 login.html                alert("当前你尚未登录!请登录后再访问博客列表");                location.assign('blog_login.html');            }        },        error: function() {            alert("当前你尚未登录!请登录后再访问博客列表");                location.assign('blog_login.html');        }    });    }getUserInfo();

8.4 修改前端代码

blog_list.html blog_detil.html 中引入 js文件,就可以执行到里面的代码,也就进行了登录状态的监测了

 <script src="js/commom.js"></script>

在这里插入图片描述
在这里插入图片描述

9. 实现显示用户信息功能

9.1 约定好前后端交互接口

9.2 实现 AuthorServlet 代码

package controller;import com.fasterxml.jackson.databind.ObjectMapper;import model.Blog;import model.BlogDao;import model.User;import model.UserDao;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.io.IOException;@WebServlet("/authorInfo")public class AuthorServlet  extends HttpServlet {    private ObjectMapper objectMapper = new ObjectMapper();    @Override    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {        resp.setContentType("application/json; charset=utf8");        // 通过这个方法, 来获取到指定的博客的作者信息.        String param = req.getParameter("blogId");        if (param == null || "".equals(param)) {            // 参数缺少了.            resp.getWriter().write("{ "ok": false, "reason": "参数缺失!" }");            return;        }        // 根据当前 blogId 在数据库中进行查找, 找到对应的 Blog 对象, 再进一步的根据 blog 对象, 找到作者信息.        BlogDao blogDao = new BlogDao();        Blog blog = blogDao.selectOne(Integer.parseInt(param));        if (blog == null) {            resp.getWriter().write("{ "ok": false, "reason": "要查询的博客不存在!" }");            return;        }        // 根据 blog 对象, 查询到用户对象        UserDao userDao = new UserDao();        User author = userDao.selectById(blog.getUserId());        if (author == null) {            resp.getWriter().write("{ "ok": false, "reason": "要查询的用户不存在!" }");            return;        }        // 把 author 返回到浏览器这边        // 注意要把密码给干掉!        author.setPassword("");        resp.getWriter().write(objectMapper.writevalueAsString(author));    }}

9.3 实现前端代码

在这里插入图片描述

针对博客列表页进行修改

在 common.js 中 修改代码
在这里插入图片描述

针对博客详情页

10. 实现注销功能

在导航栏中安排一个“注销”按钮,当用户点击注销之后,就会在服务器上取消登录状态,并且能够跳转到登录页面

10.1 约定好前后端交互接口

在这里插入图片描述

10.2 实现 LogouServlet

package controller;import javax.servlet.ServletContext;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.*;import java.io.IOException;import java.util.Enumeration;@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.getWriter().write("当前用户尚未登录! 无法注销!");                return;            }            // 然后把这个用户的会话中的信息给删掉就行了!!            session.removeAttribute("user");            resp.sendRedirect("blog_login.html");        }}

10.3 实现前端代码

将 blog_detail.html blog_list.html bloh_edit.htm中的注销标签进行修改

在这里插入图片描述

11. 实现发布博客功能

博客编辑页,当用户输入博客标题,和正文之后,点击发布
此时就会把博客数据提交到服务器,由服务器存储到数据中

11.1 约定好前后端交互的接口

在这里插入图片描述

11.2 在BlogServlet中添加doPost方法

@Override    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {        HttpSession session = req.getSession(false);        if (session == null) {            // 当前用户未登录, 不能提交博客!            resp.setContentType("text/html;charset=utf8");            resp.getWriter().write("当前用户未登录, 不能提交博客!");            return;        }        User user = (User) session.getAttribute("user");        if (user == null) {            // 当前用户未登录, 不能提交博客!            resp.setContentType("text/html;charset=utf8");            resp.getWriter().write("当前用户未登录, 不能提交博客!");            return;        }        // 一定要先指定好请求按照哪种编码来解析        req.setCharacterEncoding("utf8");        // 先从请求中, 取出参数(博客的标题和正文)        String title = req.getParameter("title");        String content = req.getParameter("content");        if (title == null || "".equals(title) || content == null || "".equals(content)) {            // 直接告诉客户端, 请求参数不对            resp.setContentType("text/html;charset=utf8");            resp.getWriter().write("提交博客失败! 缺少必要的参数!");            return;        }        // 构造 Blog 对象, 把当前的信息填进去, 并插入数据库中        // 此处要给 Blog 设置的属性, 主要是 title, content, userId (作者信息)        // postTime 和 blogId 都不需要手动指定, 都是插入数据库的时候自动生成的.        Blog blog = new Blog();        blog.setTitle(title);        blog.setContent(content);        // 作者 id 就是当前提交这个博客的用户的身份信息!!        blog.setUserId(user.getUserId());        BlogDao blogDao = new BlogDao();        blogDao.insert(blog);        // 重定向到, 博客列表页!        resp.sendRedirect("blog_list.html");    }

11.3 实现前端代码

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <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="js/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.min.js"></script></head><body>    <!-- 这是导航栏 -->    <div class="nav">        <img src="imge/ph.png" alt="">        <span>我的博客系统</span>        <!-- 空白元素, 用来占位置 -->        <div class="spacer"></div>        <a href="blog_list.html">主页</a>        <a href="blog_edit.html">写博客</a>        <a href="logout">注销</a>    </div>    <!-- 包裹整个博客编辑页内容的顶级容器 -->        <div class="blog-edit-container">        <form action="blog" method="post" style="height: 100%">            <div class="title">                <input type="text" placeholder="在此处输入标题" name="title">                <!-- <button>发布文章</button> -->                <input type="submit" value="发布文章" id="submit">            </div>            <!-- 放置 md 编辑器 -->            <div id="editor">                    <!-- 为了进行 form的提交,此处搞一下 textarea 多行编辑框,借助这个编辑框来实现表单的提交-->                    <textarea name="content" style="display: none"></textarea>            </div>        </form>    </div>    <script>        // 初始化编辑器        let editor = editormd("editor", {            // 这里的尺寸必须在这里设置. 设置样式会被 editormd 自动覆盖掉.             width: "100%",            // 设定编辑器高度            height: "calc(100% - 50px)",            // 编辑器中的初始内容            markdown: "# 在这里写下一篇博客",            // 指定 editor.md 依赖的插件路径            path: "editor.md/lib/",            // 此处要加上一个重要的选项,然后 editr.md 就会自动把用户在编辑器输入的内容同步保存到 隐藏的 textarea中            saveHTMLTotextarea:true,        });    </script></body></html>

12. 删除博客

在这里插入图片描述

12.1 约定号前后端交互接口

在这里插入图片描述

12.1 实现前端代码

 <script>         function getBlogDetail() {            $.ajax({                type: 'get',                // location.search 拿到了形如 '?blogId=5' 这样的一段内容                url: 'blog' + location.search,                success: function(body) {                    // 根据 body 中的内容来构造页面                    // 1. 构造博客标题                    let h3 = document.querySelector(".blog-content>h3");                    h3.innerHTML = body.title;                    // 2. 构造博客发布时间                    let dateDiv = document.querySelector('.date');                    dateDiv.innerHTML = body.postTime;                    // 3. 构造博客正文                    // 如果直接把 content 设为 innerHTML, 此时展示在界面上的内容, 是原始的 markdown 字符串                    // 咱们需要的是渲染后的, 带有格式的效果                    // let content = document.querySelector('#content');                    // content.innerHTML = body.content;                    // 第一个参数对应 id=content 的 html 标签. 渲染后得到的 html 片段就会被放到这个 标签下.                     editormd.markdownToHTML('content', {                        markdown: body.content                    });                }            });        }     // 加上一个逻辑,通过 GET /login 这个接口来获取下当前的登录状态              function getUserInfo(pageName) {        $.ajax({        type:'get',        url: 'login',        success: function(body) {            // 判断此处的 body 是不是一个有效的user 对象(userId 是否为0)            if(body.userId && body.userId > 0) {                // 登录成功                // 不做处理                console.log("当前用户登录成功!用户名" + body.username);                // 在getUserInfo 的回调函数中,来调用获取用户信息                getAuthorInfo(body);                            }else {                // 登录失败                // 让前端页面,跳转到 login.html                alert("当前您尚未登录!请登录后再访问博客列表");                location.assign('blog_login.html');            }        },        error: function() {            alert("当前您尚未登录!请登录后再访问博客列表");            location.assign('blog_login.html');        }        });    }      // 判定用户的登录状态    getUserInfo('blog_detail.html');     // 从服务器获取一下当前博客的作者信息, 并显示到界面上.     // 参数 user 就是刚才从服务器拿到的当前登录用户的信息            function getAuthorInfo(user) {                $.ajax({                   type: 'get',                   url: 'authorInfo' + location.search,                   success: function(body) {                       // 此处的body,就是服务器返回的User对象,是文章作者信息                       if(body.username) {                            getBlogDetail();                           changeUserName(body.username);                           if(body.username == user.username ) {                               // 作业和登录的用户是一个人,则显示 删除按钮                               let navDiv = document.querySelector('.nav');                               let a = document.createElement('a');                               a.innerHTML = '删除';                               // 点击删除,构造一个 形如 blogDelete?blogId = 6 这样的请求                               a.href = 'blogDelete' + location.search;                               navDiv.appendChild(a);                           }                       }else{                           console.log("获取信息失败" + body.reason);                       }                   }                });            }            function changeUserName(username) {            let h3 = document.querySelector('.card>h3');            h3.innerHTML = username;            }         </script>

12.2 实现BlogDeleteServlet

package controller;import model.Blog;import model.BlogDao;import model.User;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("/blogDelete")public class BlogDeleteServlet extends HttpServlet {    @Override    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {        // 1. 检查当前用户是否登录        HttpSession session = req.getSession(false);        if (session == null) {            resp.setContentType("text/html; charset=utf8");            resp.getWriter().write("当前尚未登录, 不能删除!");            return;        }        User user = (User) session.getAttribute("user");        if (user == null) {            resp.setContentType("text/html; charset=utf8");            resp.getWriter().write("当前尚未登录, 不能删除!");            return;        }        // 2. 获取到参数中的 blogId        String blogId = req.getParameter("blogId");        if (blogId == null || "".equals(blogId)) {            resp.setContentType("text/html; charset=utf8");            resp.getWriter().write("当前 blogId 参数不对!");            return;        }        // 3. 获取要删除的博客信息.        BlogDao blogDao = new BlogDao();        Blog blog = blogDao.selectOne(Integer.parseInt(blogId));        if (blog == null) {            resp.setContentType("text/html; charset=utf8");            resp.getWriter().write("当前要删除的博客不存在!");            return;        }        // 4. 再次校验, 当前的用户是否就是博客的作者        if (user.getUserId() != blog.getUserId()) {            // 这一点在前端这里其实也处理过~~ 但是此处还是再校验一次, 不是坏事!!!            resp.setContentType("text/html; charset=utf8");            resp.getWriter().write("当前登录的用户不是作者, 没有权限删除!");            return;        }        // 5. 确认无误, 开始删除        blogDao.delete(Integer.parseInt(blogId));        // 6. 重定向到博客列表页        resp.sendRedirect("blog_list.html");    }    }
 
友情链接
鄂ICP备19019357号-22