文章目录

  • 设计前提:明确用户的需求
  • 一、实现那些功能
  • 1.当前博客列表(摘要)
  • 2.博客正文页
  • 3.博客编辑页
  • 4.删除博客功能
  • 5.注册&登录功能
  • 二、功能的实现
  • 1.数据库实体类设计
  • 2.数据库连接工具类
  • 3.前端页面的实现
  • 4.实现前后端交互
  • 结果
  • 登录
  • 注册
  • 博客列表
  • 博客详情页
  • 删除该博客
  • 发表博客
  • 注销




设计前提:明确用户的需求

一、实现那些功能

1.当前博客列表(摘要)

博客列表展示了很多篇博客,每一篇博客都包含标题、发布时间、作者、摘要,点击标题可以跳转至对应博客正文页。

2.博客正文页

显示博客的详细内容,正文包含标题、发布时间、完整正文(暂不考虑图片)

3.博客编辑页

显示一个编辑框,用户可以编辑内容并提交给服务器,在列表中可以看到该博客。

4.删除博客功能

在博客的详情页加一个删除按钮

5.注册&登录功能

要求:若登陆成功,才能发布博客;
若没有登陆成功,只能看,不能发布。

二、功能的实现

1.数据库实体类设计

首先分析需要建立几张表来存储博客的数据,每张表字段间的关联关系。
注:为了后面此表结构的重复创建,将建表的sql写到一个sql文件中。
表1:表示“博客”Blog
字段:博客编号blogId、标题title、正文content、发布时间postTime、作者编号userId。
表2:表示“用户”user
字段:用户编号userId、用户名username、密码password。
封装数据库:
(1)使用“单例”类封装数据库建立连接过程。
(2)创建实体类,博客(Blog)是一个实体,一个用户(User)是一个实体,确定博客和用户之间的关系(一对多)。
db.sql

`create database if not exists BlogSystem;
use BlogSystem;

drop table if exists blog;
create table blog (
blogId int primary key auto_increment,
title varchar(512),
content text,
userId int,
postTime datetime
);

drop table if exists user;
create table user (
userId int primary key auto_increment,
username varchar(50),
password varchar(50)
);`
Blog表

import java.sql.Date;
import java.sql.Timestamp;

public class Blog {
    private int blogId;
    private String title;
    private String content;
    private int userId;
    // java.sql.Date 这个类型只能表示日期, 没有时分秒
    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;
    }

    public Timestamp getPostTime() {
        return postTime;
    }

    public void setPostTime(Timestamp postTime) {
        this.postTime = postTime;
    }

    @Override
    public String toString() {
        return "dao.Blog{" +
                "blogId=" + blogId +
                ", title='" + title + '\'' +
                ", content='" + content + '\'' +
                ", userId=" + userId +
                ", postTime=" + postTime +
                '}';
    }
}

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;
    }

    @Override
    public String toString() {
        return "dao.User{" +
                "userId=" + userId +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

(3)针对用户和博客进行具体的增删改查操作。(暂不考虑用户的删除 )
注:查找时,如果查询结果较多,采用limit offset实现分页查询,此项目暂时不考虑。
BlogDao

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) {
        // 1. 和数据库服务器建立连接.
        Connection connection = DBUtil.getConnection();
        // 2. 拼装 SQL
        String sql = "insert into blog values(null, ?, ?, ?, now())";
        PreparedStatement statement = null;
        try {
            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 e) {
            e.printStackTrace();
        } finally {
            // 4. 收尾工作.
            DBUtil.close(connection, statement, null);
        }
    }



    // 从数据库删除博客
    public void delete(int blogId) {
        // 1. 和数据库服务器建立连接.
        Connection connection = DBUtil.getConnection();
        // 2. 拼装 SQL
        String sql = "delete from blog where blogId = ?";
        PreparedStatement statement = null;
        try {
            statement = connection.prepareStatement(sql);
            statement.setInt(1, blogId);
            // 3. 执行 SQL
            statement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(connection, statement, null);
        }
    }

    // 从数据库中查找出所有的博客.
    // 实现博客列表页的时候, 就需要这个方法.
    // 如果博客数目少, 都无所谓. 如果博客数目很多, 应该要支持 "分页查询"
    // limit offset
    public List<Blog> selectAll() {
        List<Blog> blogs = new ArrayList<Blog>();
        // 1. 和数据库服务器建立连接.
        Connection connection = DBUtil.getConnection();
        // 2. 拼装 SQL
        String sql = "select * from blog order by blogId desc";
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            statement = connection.prepareStatement(sql);
            // 3. 执行 SQL
            resultSet = statement.executeQuery();
            // 4. 遍历结果集合.
            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() > 40) {
                    content = content.substring(0, 40) + "...";
                }
                blog.setContent(content);
                blog.setUserId(resultSet.getInt("userId"));
                blog.setPostTime(resultSet.getTimestamp("postTime"));
                blogs.add(blog);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(connection, statement, resultSet);
        }
        return blogs;
    }

    // 从数据库查询出指定的一篇博客.
    // 实现博客详情页的时候, 需要这个方法.
    public Blog selectOne(int blogId) {
        // 1. 和数据库建立连接.
        Connection connection = DBUtil.getConnection();
        // 2. 拼装 SQL
        String sql = "select * from blog where blogId = ?";
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            statement = connection.prepareStatement(sql);
            statement.setInt(1, blogId);
            // 3. 执行 SQL
            resultSet = statement.executeQuery();
            // 4. 遍历结果集. 要么是 0 个记录, 要么只有 1 条记录.
            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.getInt("userId"));
                blog.setPostTime(resultSet.getTimestamp("postTime"));
                return blog;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(connection, statement, resultSet);
        }
        return null;
    }

    public static void main(String[] args) {
        // 通过这里的代码对上面的数据库操作进行验证.
        // 1. 验证插入.
        // 此处的测试, 只是一个简单的 "冒烟测试"
//        Blog blog = new Blog();
//        blog.setTitle("滕王阁序");
//        blog.setContent("");
//        blog.setUserId(3);
//        BlogDao blogDao = new BlogDao();
//        blogDao.insert(blog);

        // 2. 验证查找.
//        dao.BlogDao blogDao = new dao.BlogDao();
//        List<dao.Blog> blogs = blogDao.selectAll();
//        System.out.println(blogs);
//        dao.Blog blog = blogDao.selectOne(1);
//        System.out.println(blog);

        // 3. 验证删除.
//        dao.BlogDao blogDao = new dao.BlogDao();
//        blogDao.delete(1);
    }
}

UserDao

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class UserDao {
    // 注册的时候, 需要新增用户到数据库中.
    // 期望 username 不能重复. (username 是用于登陆的用户名)
    // 注册的时候(insert 之前), 先判定一下该 username 是否已经存在.
    // 如果存在, 就直接不执行后续的 insert 操作.
    // username 的唯一性不一定非得通过 数据库的约束 来完成.
    // 也可以通过用户代码来完成.
    public void insert(User user) {
        // 1. 和数据库建立连接.
        Connection connection = DBUtil.getConnection();
        // 2. 拼装 SQL
        String sql = "insert into user values(null, ?, ?)";
        PreparedStatement statement = null;
        try {
            statement = connection.prepareStatement(sql);
            statement.setString(1, user.getUsername());
            statement.setString(2, user.getPassword());
            // 3. 执行 SQL
            statement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 4. 关闭连接.
            DBUtil.close(connection, statement, null);
        }
    }

    // 登陆的时候, 需要根据用户名获取到密码
    public User selectByName(String username) {
        // 1. 和数据库建立连接.
        Connection connection = DBUtil.getConnection();
        // 2. 拼装 SQL
        String sql = "select * from user where username = ?";
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            statement = connection.prepareStatement(sql);
            statement.setString(1, username);
            // 3. 执行 SQL
            resultSet = statement.executeQuery();
            // 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 e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(connection, statement, resultSet);
        }
        return null;
    }

    // 根据用户 id 来查用户信息
    // 显示博客作者的时候需要用到.
    public User selectById(int userId) {
        // 1. 和数据库建立连接.
        Connection connection = DBUtil.getConnection();
        // 2. 拼装 SQL
        String sql = "select * from user where userId = ?";
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            statement = connection.prepareStatement(sql);
            statement.setInt(1, userId);
            // 3. 执行 SQL
            resultSet = statement.executeQuery();
            // 4. 遍历结果集. 预期结果只是有 0 个或者 1 个.
            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;
    }

    public static void main(String[] args) {
        UserDao userDao = new UserDao();
        // 1. 测试 插入用户 功能
        dao.User user = new dao.User();
        user.setUsername("王勃");
        user.setPassword("120");
        userDao.insert(user);
        // 2. 测试根据名字查找.
//        dao.User user = userDao.selectByName("zhangsan");
//        System.out.println(user);

        // 3. 测试根据 id 查找.
//        dao.User user = userDao.selectById(1);
//        System.out.println(user);
    }
}

2.数据库连接工具类

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 final String URL = "jdbc:mysql://127.0.0.1:3306/BlogSystem?characterEncoding=utf8&useSSL=false";
    private static final String USERNAME = "root";
    private static final String PASSWORD = "shanA.l931f";

    private static DataSource dataSource = null;

    public static DataSource getDataSource() {
        // 看一下 dataSource 当前是否已经持有一个实例了.
        // 如果没有持有, 就创建一个新的.
        // 如果持有了, 就不必创建新的, 直接返回之前的.
        if (dataSource == null) {
            MysqlDataSource mysqlDataSource = new MysqlDataSource();
            mysqlDataSource.setUrl(URL);
            mysqlDataSource.setUser(USERNAME);
            mysqlDataSource.setPassword(PASSWORD);
            dataSource = mysqlDataSource;
        }
        return dataSource;
    }

    public static Connection getConnection() {
        try {
            return getDataSource().getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void close(Connection connection,
                             PreparedStatement statement,
                             ResultSet resultSet) {
        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 {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

3.前端页面的实现

1.先写html代码,使用Thymeleaf中的一些特殊几号,把关键性数据进行占位。
2.在Servlet代码中获取关键数据,再通过Thymeleaf的数据替换到html模板的特殊记号中,形如th:XXX="${XXX}"的特殊几号。
3.使用Thymeleaf进行渲染(把代码中计算生成的数据,替换到模板)。
Thymeleaf

1.使用模板技术实现前会断分离

初始化Thymeleaf
1)创建engine对象(用于渲染)
2)创建resolver对象(加载html模板文件并解析)
3)指定resolver字符集,以及加载哪些文件,初始化好的engine一般放到ServletContext中,就可以使初始化的一份engine,能够被多个Servlet共享使用。(初始化的代码借助“助听器(listener)”)
4)使用Thymeleaf渲染模板,创建一个WebContext对象(数据集合)将关键数据放入WebContext中。

Thymeleaf

import com.sun.xml.internal.ws.api.policy.PolicyResolver;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

@WebListener
public class ThymeleafConfig implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        // 使用这个!!!
        // 这个方法就会在当前 webapp 的 ServletContext 初始化之后
        // 立即执行. Thymeleaf 的初始化就在这里调用即可!!!
        // 初始化 Thymeleaf
        // 1) 创建一个 engine(引擎), 负责把 Java 中的数据替换到模板中.
        TemplateEngine engine = new TemplateEngine();
        // 2) 创建一个 resolver 对象(解析器), 负责找到 html 模板在哪, 并加载到内存中.
        //    供 engine 对象来使用.
        ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(sce.getServletContext());
        // 3) 给 resolver 设置一些属性, 让它能够找到 html 模板.
        resolver.setCharacterEncoding("utf-8");
        //    Prefix 表示 "前缀", 设定了满足啥样条件的文件被加载到内存中作为 HTML 模板
        resolver.setPrefix("/WEB-INF/template/");
        //    Suffix 表示 "后缀"
        resolver.setSuffix(".html");
        // 4) 把 resolver 和 engine 关联起来.
        engine.setTemplateResolver(resolver);

        // 把初始化好的 engine 对象交给 ServletContext 来保管.
        ServletContext context = sce.getServletContext();
        context.setAttribute("engine", engine);
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {

    }
}

2.登录&注册页面

登录

<!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>
    
    <style>

    .container{
        text-align: center;
        margin-top: 50px;
    }

    body{
        background: gainsboro;
    }

    .nav{
        width: 60%;
        height: 300px;
    }

    </style>
</head>
<body>
    <div class="container">
        <h1>发表博客</h1>
        <form action="blogInsert" method="POST">
            标题:<input type="text" name="title"><p></p>
            正文:<textarea name="content" class="nav"></textarea><p></p>
            <!--<textarea>:多行的文本输入控件-->
                <input value="提 交" type="submit">
        </form>
    </div>
</body>
</html>

注册

<!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>
    
    <style>
        .container{
            text-align: center;
            margin-top: 80px;
            opacity: 0.9;/*div 元素的不透明级别*/
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>用户注册</h1>
        <form action="register" method="POST">
            用 户 名:<input type="text" name="username"><p></p>
            密    码:<input type="password" name="password"><p></p>
            <a href="login.html">账号已存在 直接登录</a><p></p>
            <input type="submit" value="注  册">
    </div>
</body>
</html>

3.博客列表
罗列当前系统中都存在哪些博客,博客列表中的博客不时地更新,并不是固定的,首先将博客存至数据库,博客列表中显示数据库的内容,用动态页面实现。

blog_list

<!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>
    <style>
        /*清除浏览器默认样式*/
        *{
            margin: 0;
            padding: 0;
        }

        body{
            background-color: #f3f3f3;
        }

        .container{
            width: 800px;
            margin: 0 auto;
            background-color: #fff;
        }

        .title{
            display: block;
            text-align: center;
            color: #000;
            font-size: 20px;
            font-weight: 700;
            text-decoration: none;/*下划线*/
            padding: 10px 0;
        }

        .post-time{
            text-align: center;
            color: #999aaa;
        }

        .desc{
            padding-bottom: 10px;
            text-indent: 20px;
        }

        .nav{
            height: 50px;
            background: #000;
            color:  #fff;
            display: flex;
            align-items: center;
        }
        .nav-title{
            padding-left: 20px;
        }

        .nav-button{
            color: #fff;
            text-decoration: none;
            padding: 0 10px;
        }

        .apacer{
            width: 70%;
        }
    </style>
</head>
<body>
    <div class="nav">
        <h3 class="nav-title">我的博客列表</h3>
        <div class="apacer"></div>
        <a href="login.html" class="nav-button" th:if="${!isLogin}">登录</a>
        <a href="register.html" class="nav-button" th:if="${!isLogin}">注册</a>
        <div th:if="${isLogin}" th:text="${'欢迎' + user.username}"></div>
        <a href="blog_insert.html" class="nav-button" th:if="${isLogin}">写博客</a>
        <a href="logout" class="nav-button" th:if="${isLogin}">注销</a>
    </div>
     <!-- .container 存放了所有的博客 -->
     <div class="container">
         <!-- .blog 对应到一篇博客 -->
         <div class="blog" th:each="blog : ${blogs}">
            <a th:href="${'blogContent?blogId=' + blog.blogId}" class="title" th:text="${blog.title}">标题</a>
            <div class="post-time" th:text="${blog.postTime}">2020-07-17 18:39:00</div>
            <div class="desc" th:text="${blog.content}">正文</div>
         </div>
     </div>
</body>
</html>

4.博客详情页

在博客列表页只显示摘要,点击标题进去查看博客详情

<!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>
    <style>
        *{
            margin: 0;
            padding: 0;
        }

        body{
            background-color: #f3f3f3;
        }

        .container{
            width: 800px;
            margin: 0 auto;
            background-color: #fff;
        }

        .title{
            text-align: center;
            padding: 10px 0;
            font-size: 36px;
        }

        .author{
            text-align: center;
            padding: 10px 0;
            color: #999aaa;
        }

        .post-time{
            text-align: center;
            color: #999aaa;
        }

        .content{
            padding: 10px 0;
            text-indent: 20px;
        }

        .nav{
            height: 50px;
            background: #000;
            color: #fff;
            display: flex;
            align-items: center;
        }

        .nav-title{
            padding-left: 10px;
        }

        .nav-button{
            color: #fff;
            text-decoration: none;
            padding: 0 10px;
        }

        .spacer{
            width: 86%;
        }
    </style>
</head>
<body>
    <div class="nav">
    <h3 class="nav-title">我的博客系统</h3>
    <div class="spacer"></div>
    <a th:href="${'blogDelete?blogId=' + blog.blogId}" class="nav-button">删除</a>
    </div>
    
    <!-- 作为整个博客的容器 -->
    <div class="container">
        <h3 th:text="${blog.title}" class="title">博客标题</h3>
        <div class="author" th:text="${username}">作者</div>
        <div class="post-time" th:text="${blog.postTime}">2020-07-17 19:28:00</div>
        <div class="content" th:text="${blog.content}">正文</div>
    </div>
</body>
</html>

5.博客编辑页

<!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>
    
    <style>

    .container{
        text-align: center;
        margin-top: 50px;
    }

    body{
        background: gainsboro;
    }

    .nav{
        width: 60%;
        height: 300px;
    }

    </style>
</head>
<body>
    <div class="container">
        <h1>发表博客</h1>
        <form action="blogInsert" method="POST">
            标题:<input type="text" name="title"><p></p>
            正文:<textarea name="content" class="nav"></textarea><p></p>
            <!--<textarea>:多行的文本输入控件-->
                <input value="提 交" type="submit">
        </form>
    </div>
</body>
</html>

4.实现前后端交互

登录时的交互
LoginServlet

import dao.User;
import dao.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 {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1. 从 req 读取用户提交的 username 和 password
        req.setCharacterEncoding("utf-8");
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        if (username == null || "".equals(username)
            || password == null || "".equals(password)) {
            resp.sendError(404, "用户名或密码不能为空");
            return;
        }
        // 2. 从数据库中查找指定用户名的用户信息.
        UserDao userDao = new UserDao();
        User user = userDao.selectByName(username);
        if (user == null) {
            resp.sendError(404, "用户名或者密码错误");
            return;
        }
        if (!password.equals(user.getPassword())) {
            // 密码不匹配
            resp.sendError(404, "用户名或者密码错误");
            return;
        }
        // 3. 登陆成功! 创建会话.
        HttpSession session = req.getSession(true);
        session.setAttribute("user", user);
        // 4. 直接把用户页面重定向到博客列表页.
        resp.sendRedirect("blogList");
    }
}

注册时的交互
RegisterServlet

import dao.User;
import dao.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("/register")
public class RegisterServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 如果不做任何限定, 此时服务器这边读取 Parameter 的时候默认不是按照 utf-8 的方式来理解字符编码的.
        req.setCharacterEncoding("utf-8");
        // 1. 先读取用户提交的用户名和密码
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        if (username == null || "".equals(username)
            || password == null || "".equals(password)) {
            resp.sendError(404, "提交的用户名或者密码为空");
            return;
        }
        // 2. 查询数据库, 看看 username 是否存在
        UserDao userDao = new UserDao();
        User existsUser = userDao.selectByName(username);
        if (existsUser != null) {
            // 用户已经存在! 提示注册失败!
            resp.sendError(404, "用户名已经存在, 注册失败!");
            return;
        }
        // 3. 构造 dao.User 对象, 插入到数据库中.
        User newUser = new User();
        newUser.setUsername(username);
        newUser.setPassword(password);
        userDao.insert(newUser);
        // 4. 返回一个结果.
        resp.setContentType("text/html; charset=utf-8");
        resp.getWriter().write("<h3>注册成功!</h3>");
    }
}

博客列表页的交互
BlogListServlet

import dao.Blog;
import dao.BlogDao;
import dao.User;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.WebContext;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
import java.util.List;

@WebServlet("/blogList")
public class BlogListServlet extends HttpServlet {
    @Override
    public void init() throws ServletException {
    }

    private User checkLogin(HttpServletRequest req) {
        HttpSession session = req.getSession(false);
        if (session == null) {
            return null;
        }
        User user = (User) session.getAttribute("user");
        return user;
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 0. 从 req 里面读取一下当前用户信息. 判定用户是否登陆.
        User user = checkLogin(req);
        boolean isLogin = false;
        if (user != null) {
            isLogin = true;
        }
        // 1. 先从数据库查询出都有哪些博客.
        BlogDao blogDao = new BlogDao();
        List<Blog> blogList = blogDao.selectAll();
        // 2. 构造博客页面.
        // 1) 通过 Thymeleaf 进行渲染. 渲染的时候需要定义 "数据集合" 这样的概念.
        // WebContext 功能就是把要替换的数据给收集起来, 统一的传给模板引擎.
        WebContext webContext = new WebContext(req, resp, getServletContext());
        // 2) setVariable 可以设置多个键值对. 完全取决于模板代码怎么写.
        // 模板里的每个 ${ } 里面的内容都需要在 webContext 设定进去.
        webContext.setVariable("blogs", blogList);
        webContext.setVariable("isLogin", isLogin);
        webContext.setVariable("user", user);
        // 3) 进行渲染.
        TemplateEngine engine = (TemplateEngine) getServletContext().getAttribute("engine");
        String html = engine.process("blog_list", webContext);
        System.out.println("模板渲染的内容: " + html);
        resp.setContentType("text/html; charset=utf-8");
        resp.getWriter().write(html);
    }
}

发表博客界面交互
BlogInsertServlet

import dao.Blog;
import dao.BlogDao;
import dao.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("/blogInsert")
public class BlogInsertServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        // 0. 判定用户是否已经登陆
        HttpSession session = req.getSession(false);
        if (session == null) {
            resp.sendError(404, "当前尚未登陆, 不能发布博客!");
            return;
        }
        User user = (User) session.getAttribute("user");
        if (user == null) {
            resp.sendError(404, "当前尚未登陆, 不能发布博客!");
            return;
        }
        // 1. 读取请求中的参数.
        String title = req.getParameter("title");
        String content = req.getParameter("content");
        if (title == null || "".equals(title)
            || content == null || "".equals(content)) {
            resp.sendError(404, "标题或者正文为空");
            return;
        }
        // 2. 根据读到的数据构造 dao.Blog 对象, 并插入数据库
        Blog blog = new Blog();
        blog.setTitle(title);
        blog.setContent(content);
        blog.setUserId(user.getUserId());
        BlogDao blogDao = new BlogDao();
        blogDao.insert(blog);
        // 3. 重定向到博客列表页, 也能直接看到新的博客
        resp.sendRedirect("blogList");
    }
}

博客详情页的交互
BlogContentServlet

import dao.Blog;
import dao.BlogDao;
import dao.User;
import dao.UserDao;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.WebContext;

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("/blogContent")
public class BlogContentServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html; charset=utf-8");
        // 1. 从 req 中读取出 blogId
        String blogId = req.getParameter("blogId");
        if (blogId == null || "".equals(blogId)) {
            // /rocket_blog/blogContent => blogId = null
            // /rocket_blog/blogContent?blogId=   blogId = ""
            // resp.getWriter().write("<h3>blogId 不存在</h3>");
            resp.sendError(404, "blogId 参数错误!");
            return;
        }
        // 2. 根据 blogId 在数据库中查询出博客的详细内容.
        BlogDao blogDao = new BlogDao();
        Blog blog = blogDao.selectOne(Integer.parseInt(blogId));
        if (blog == null) {
            resp.sendError(404, "blogId 指定的文章不存在!");
            return;
        }
        // 3. 根据 blog.userId 找到对应的 dao.User 对象
        UserDao userDao = new UserDao();
        User user = userDao.selectById(blog.getUserId());
        // 4. 根据详细内容, 渲染到模板中.
        TemplateEngine engine = (TemplateEngine) getServletContext().getAttribute("engine");
        WebContext webContext = new WebContext(req, resp, getServletContext());
        webContext.setVariable("blog", blog);
        webContext.setVariable("username", user.getUsername());
        String html = engine.process("blog_content", webContext);
        // 5. 把渲染好的结果写回客户端.
        resp.getWriter().write(html);
    }
}

删除博客交互
BlogDeleteServlet

import dao.Blog;
import dao.BlogDao;
import dao.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. 从 req 中读取要删除的 blogId
        String blogId = req.getParameter("blogId");
        if (blogId == null || "".equals(blogId)) {
            resp.sendError(404, "blogId 为空!");
            return;
        }
        // 2. 判定用户的登陆状态, 未登陆不能删除.
        HttpSession session = req.getSession(false);
        if (session == null) {
            resp.sendError(404, "当前未登录, 不能删除!");
            return;
        }
        User user = (User) session.getAttribute("user");
        if (user == null) {
            resp.sendError(404, "当前未登录, 不能删除!");
            return;
        }
        // 3. 根据 blogId, 查询 blogId 的作者 id, 看看和当前登陆的用户 id 是否相同
        //    不相同也不能删除.
        BlogDao blogDao = new BlogDao();
        Blog blog = blogDao.selectOne(Integer.parseInt(blogId));
        if (blog == null) {
            resp.sendError(404, "当前博客不存在!");
            return;
        }
        if (blog.getUserId() != user.getUserId()) {
            resp.sendError(403, "不能删除别人的博客!");
            return;
        }
        // 4. 如果用户相同, 从数据库中删除这个博客即可.
        blogDao.delete(Integer.parseInt(blogId));
        // 5. 重定向到博客列表页
        resp.sendRedirect("blogList");
    }
}

注销用户交互
LogoutServlet

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 {
        // 把当前用户的 session 中的 user 这个数据给删掉.
        HttpSession session = req.getSession(false);
        if (session == null) {
            resp.sendError(404, "当前尚未登陆, 不能注销");
            return;
        }
        session.removeAttribute("user");
        resp.sendRedirect("blogList");
    }
}

结果

登录

大型博客架构设计案例 博客系统设计_css

注册

大型博客架构设计案例 博客系统设计_css_02

博客列表

大型博客架构设计案例 博客系统设计_css_03

博客详情页

大型博客架构设计案例 博客系统设计_maven_04

删除该博客

大型博客架构设计案例 博客系统设计_css_05

发表博客

大型博客架构设计案例 博客系统设计_java_06


大型博客架构设计案例 博客系统设计_maven_07

注销

大型博客架构设计案例 博客系统设计_css_08