每个人的第一个简单的小项目:个人博客 (极其适合新手)

目录

0. 项目结构

0.1 单元测试目录

1. 项目的准备工作

2. 数据库设计

3. 把JDBC操作数据库的代码进行封装

1.封装一下数据库建立连接的过程(单例)

2. 创建实体类User、Blog

3. 针对操作数据库创建Dao类(BlogDao和UserDao(重要))

4. 对dao层进行单元测试

4. 实现博客页面

4.1初始化Themeleaf模板引擎:

4.2 博客列表页的模板

4.3 博客详情页的模板

4.4 博客编辑页前端代码

4.5 服务器端删除博客代码:(删除本身在博客详情页当中体现)

4.6 登录页面前端代码:(登录本身在博客列表页当中体现)

4.7 服务器端注销业务代码:(注销本身在博客列表页当中体现)

4.8 注册页面前端代码:(注册本身在博客列表页当中体现)

5. 项目功能展示

(1)博客列表页:

(2)登录页面

(3)注册页面 

 (4)注销功能

(5)博客详情页

(6)博客编辑页

 (7)博客删除功能

6. 总结

7. 个人心得体会


0. 项目结构

0.1 单元测试目录

1. 项目的准备工作

1. 搭建一个空的maven项目(之前有博客已经写了)

2. 对maven进行基本的配置

        2.1 首先在目录 src/main 下创建一个文件目录 webapp/WEB-INF/web.xml

        web.xml内容为:

<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
    <display-name>Archetype Created Web Application</display-name>
</web-app>

        2.2 配置maven 的核心页 pom.xml

               分四步:

                a)引入依赖,分别有servlet,mysql,thymeleaf

    <dependencies>
        <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.thymeleaf/thymeleaf -->
        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf</artifactId>
            <version>3.0.12.RELEASE</version>
        </dependency>
    </dependencies>

                b)配置打包jar包改为war包(maven识别的是war包)

<packaging>war</packaging>

                c)修改war包名字

    <build>
        <finalName>rocket_blog</finalName>
    </build>

                d)设置maven用的jdk版本

    <properties>
        <encoding>UTF-8</encoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

这样maven基本配置就完毕了

2. 数据库设计

在 src/main 目录下创建 db.sql 文件

写入以下代码用于创建数据库和表:

需要两张表:博客表(博客ID,标题,正文,作者的用户ID,发布时间)

                      用户表(用户ID,用户名,密码)

create database if not exists RocketBlog;
use RocketBlog;

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

然后后把代码复制进mysql

查看一下创建的表:有2张,分别为blog和user

看一下表的详细内容:

3. 把JDBC操作数据库的代码进行封装

1.封装一下数据库建立连接的过程(单例)

在main/java文件夹下创建DBUtil文件

代码如下:DBUtil和数据库建立连接/收尾工作(重要)

1.初始化属性

2.获取数据源

3.获取数据库连接

4.关闭资源

public class DBUtil {
    private static final String URL = "jdbc:mysql://127.0.0.1:3306/RocketBlog?characterEncoding=utf8&useSSL=false";
    private static final String USERNAME = "root";
    private static final String PASSWORD = "2222";

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

2. 创建实体类User、Blog

在main/java文件夹下创建Blog和User

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 + '\'' +
                '}';
    }
}

Blog: 

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

3. 针对操作数据库创建Dao类(BlogDao和UserDao(重要))

在main/java文件夹下创建BlogDao和UserDao

BlogDao:

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(1);
//        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:

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("zhangsan");
//        user.setPassword("123");
//        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);
    }
}

4. 对dao层进行单元测试

BlogDaoTest:

public class BlogDaoTest {

    @Test
    public void insert() {
        Blog blog = new Blog();
        blog.setTitle("这是超级简约博客");
        blog.setContent("这是博客正文这是博客正文");
        blog.setUserId(1);
        BlogDao blogDao = new BlogDao();
        blogDao.insert(blog);
    }

    @Test
    public void delete() {
        dao.BlogDao blogDao = new dao.BlogDao();
        blogDao.delete(1);
    }

    @Test
    public void selectAll() {
        dao.BlogDao blogDao = new dao.BlogDao();
        List<Blog> blogs = blogDao.selectAll();
        System.out.println(blogs);
    }

    @Test
    public void selectOne() {
        dao.BlogDao blogDao = new dao.BlogDao();
        dao.Blog blog = blogDao.selectOne(1);
        System.out.println(blog);
    }
}

UserDaoTest: 

public class UserDaoTest {

    @Test
    public void insert() {
        UserDao userDao = new UserDao();
        dao.User user = new dao.User();
        user.setUsername("zhangsan");
        user.setPassword("123");
        userDao.insert(user);
    }

    @Test
    public void selectByName() {
        UserDao userDao = new UserDao();
        dao.User user = userDao.selectByName("zhangsan");
        System.out.println(user);
    }

    @Test
    public void selectById() {
        UserDao userDao = new UserDao();
        dao.User user = userDao.selectById(1);
        System.out.println(user);
    }
}

4. 实现博客页面

a)博客列表页(只是展示博客内容的摘要)

b)博客详情页

c)博客编辑页

d)删除博客

e)注册

f)登录/注销

使用模板来生成html页面,使用Themeleaf模板引擎(重要)

4.1初始化Themeleaf模板引擎:

@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) {

    }
}

4.2 博客列表页的模板

<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: 10px;
        }

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

        .spacer {
            width: 55%;
        }
    </style>
</head>

<body>
    <div class="nav">
        <!-- 如果是用户未登录, 就显示未登录, 并且显示登陆/注册按钮 -->
        <!-- 如果是用户已登录, 就显示欢迎 XXX -->
        <h3 class="nav-title">我的博客系统</h3>
        <div class="spacer"></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}">2021-07-11 17:30:00</div>
            <div class="desc" th:text="${blog.content}">我是正文的摘要...</div>
        </div>
    </div>
</body>

服务器端博客列表页的代码:

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

4.3 博客详情页的模板

<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: 55%;
        }
    </style>
</head>

<body>
    <div class="nav">
        <!-- 如果是用户未登录, 就显示未登录, 并且显示登陆/注册按钮 -->
        <!-- 如果是用户已登录, 就显示欢迎 XXX -->
        <h3 class="nav-title">我的博客系统</h3>
        <div class="spacer"></div>
        <a class="nav-button" th:href="${'blogDelete?blogId=' + blog.blogId}">删除</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}">2021-07-11 12:00:00</div>
        <div class="content" th:text="${blog.content}">
            这是博客正文
            这是博客正文
            这是博客正文
            这是博客正文
            这是博客正文
        </div>
    </div>
</body>

服务器端博客详情页的代码:

@WebServlet("/blogContent")
public class BlogContentServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws 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);
    }
}

4.4 博客编辑页前端代码

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

        .title {
            display: block;
            width: 600px;
            height: 50px;
            margin: 10px auto;
            font-size: 20px;
            text-indent: 10px;
        }

        textarea {
            display: block;
            width: 600px;
            margin: 10px auto;
            font-size: 16px;
            padding: 10px;
            box-sizing: border-box;
        }

        .button {
            display: block;
            width: 200px;
            height: 50px;
            margin: 0 auto;
        }
    </style>
</head>

<body>
    <form action="blogInsert" method="POST">
        <!-- 用 input 表示文章的标题 -->
        <input type="text" name="title" class="title">
        <!-- 用这个输入框表示正文 -->
        <textarea name="content" rows="30"></textarea>
        <input type="submit" value="发布博客" class="button">
    </form>
</body>

服务器端博客编辑页代码:

@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");
    }
}

4.5 服务器端删除博客代码:(删除本身在博客详情页当中体现)

@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");
    }
}

4.6 登录页面前端代码:(登录本身在博客列表页当中体现)

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

        html,
        body {
            height: 100%;
        }

        .container {
            width: 800px;
            margin: 0 auto;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100%;
            flex-direction: column;
        }

        input {
            display: block;
            margin-bottom: 10px;
            width: 315px;
            height: 35px;
            font-size: 20px;
            text-indent: 10px;
        }

        .button {
            color: #fff;
            background-color: orange;
            border: none;
            border-radius: 5px;
        }

        h3 {
            padding: 10px 0;
        }
    </style>
</head>

<body>
    <div class="container">
        <h3>请登录博客系统</h3>
        <form action="login" method="POST">
            <input type="text" name="username">
            <input type="password" name="password">
            <input type="submit" value="提交" class="button">
        </form>
    </div>
</body>

服务器端登录页面代码:

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1. 从 req 读取用户提交的 username 和 password
        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");
    }
}

4.7 服务器端注销业务代码:(注销本身在博客列表页当中体现)

@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");
    }
}

4.8 注册页面前端代码:(注册本身在博客列表页当中体现)

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

        html,
        body {
            height: 100%;
        }

        .container {
            width: 800px;
            margin: 0 auto;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100%;
            flex-direction: column;
        }

        input {
            display: block;
            margin-bottom: 10px;
            width: 315px;
            height: 35px;
            font-size: 20px;
            text-indent: 10px;
        }

        .button {
            color: #fff;
            background-color: orange;
            border: none;
            border-radius: 5px;
        }

        h3 {
            padding: 10px 0;
        }
    </style>
</head>

<body>
    <div class="container">
        <h3>请注册博客系统</h3>
        <form action="register" method="POST">
            <input type="text" name="username">
            <input type="password" name="password">
            <input type="submit" value="注册" class="button">
        </form>
    </div>
</body>

服务器端注册业务代码:

@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>");
    }
}

5. 项目功能展示

(1)博客列表页:

有列表内博客题目,发布时间,博客摘要等内容

点击文章标题即可进入博客详情页

有登录和注册功能

(2)登录页面

1.  未输入就登录时返回404

2. 使用未注册的用户登录时返回404

3. 登录成功后跳转到博客列表页

有写博客和注销功能

(3)注册页面 

1. 未输入就注册返回404

2. 输入已存在的用户名返回404

3.  注册成功返回字段提示

             

 (4)注销功能

在登陆成功状态点击注销即可回到初始博客列表页

(5)博客详情页

有博客的题目,作者的用户名,发布时间,博客正文等内容

点击删除即可删除此文章

(6)博客编辑页

1. 在登陆成功状态点击写博客即可跳转到博客编辑页

 2. 编辑一些内容点击发布博客就可以成功写入博客列表页

3.  点击发布博客即可跳转到博客列表页,此时发布的博客就会出现在最上方

 (7)博客删除功能

在博客详情页点击删除功能就可以实现删除

1.  每一篇博客都有userId,每个用户只能删除自己发布的博客,例如登录的是duyuhang用户,就不能删除上图zhangsan用户的博客

 

 2. 登录的是duyuhang用户,删除下图duyuhang发布的博客

删除成功后跳转到博客列表页

6. 总结

这个项目是我的第一个项目,项目本身并不难,但是代码量还是有点分量的

如下是我遇到的一些问题,给大家参考一下(其中不乏有无语且无聊的问题,汗...)

错误整理:

1. DBUtil中password应该和自己的mysql一致

2.  博客详情页blogContent出现500,出现空指针异常,原因是我的user为null,数据库中user表没有数据

3. login.html出现404,原因是login.html应该写在webapp中,我写到了WEB-INF中导致找不到

4. if();{},小括号后多加了一个;

5. 在返回值是void的方法中,return会结束方法,不执行return后面的语句

6. 博客注册页面中form表单的action填成login出错,应和registerServlet一致

7. 模板blog_content的 th:href="${'blogDelete?blogId=' + blog.blogId}"最后的引号前面少了一个花括号

改进的内容:

1. 注册页面注册成功后延时3s跳转到登录页面

7. 个人心得体会

写的过程也是磕磕绊绊,从7月17日16:00~22:30

                                           7月18日18:30~22:30

                                           7月19日10:30~12:40---1:30~4:00

总共分了4次才写完,万事开头难,第一次做项目感觉收获还是非常多的,

觉得获得了飞升的感觉~~

项目练习一遍是不够的,总结好,有时间在写一遍写到完全熟悉掌握才行

这次挑选了一张非常有意义的图片,对IG来说是,对我来说也是

最后美图收尾嘻嘻~~ (IG 2018 我们是冠军)        

                           

  • 24
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 27
    评论
评论 27
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DU777DU

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值