博客系统 - (servlet总结,前后端分离)

本文详细介绍了如何利用Maven、Servlet和Jackson库构建一个前后端分离的个人博客系统。首先,通过创建Maven项目并引入相关依赖,接着配置web.xml和编写HelloServlet。然后,设计数据库表结构,使用DBUtil、BlogDao、UserDao等类封装数据库操作。在实现博客列表、详情、登录、注销、发布、删除和显示用户信息等功能时,约定前后端交互接口,并编写相应的服务器和客户端代码。最后,通过Postman验证了各个接口的正确性,实现了完整的个人博客系统。

前面我们学习了前端的博客系统,然后我们现在又学了后端的 servlet 技术,基本就可以写一个可以自己增删查改的网页了

所谓的前后端分离,通俗的说,就是这种方式下的服务器端不关注页面的内容,而只是给网页端提供数据,然后网页端通过 ajax 的方式和服务器之间交互数据,网页拿到数据之后再根据数据的内容渲染到页面上..

渲染就是相当于给你一个模板,然后里面的内容可以通过后端数据随意更改.

一. 准备工作

先准备好servlet:servlet准备工作

之前讲过的,我这里就简单点写了

1.创建Maven项目

在这里插入图片描述

2. 引入依赖. (servlet,jackson,mysql)

去中央仓库搜索下载(版本别搞错了):https://mvnrepository.com/

<!-- 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/com.fasterxml.jackson.core/jackson-databind -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.13.0</version>
        </dependency>

在这里插入图片描述
引入后记得刷新一下:
在这里插入图片描述

3.创建必要的目录

在这里插入图片描述
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>

在这里插入图片描述

4. 编写代码

在 java目录里新建一个HelloServlet

在这里插入图片描述

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("/hello")
public class HelloServlet extends HttpServlet {
   
   
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
   
   
        resp.getWriter().write("hello");
    }
}

注意路径

5/6. 打包部署程序

我们下载的 smart tomcat,就不用频繁的去打包部署了
在这里插入图片描述

7. 在浏览器中验证

点击小三角运行:
在这里插入图片描述

到这里准备工作算是做完了,接下来就可以执行接下来的步骤了

二. 编写数据库的操作代码

1.创建数据库/表结构(数据库设计)

这里就要根据你的前端页面来设计了,之前搞得什么页面,需求是什么就设计什么,我们实现的博客系统,需要用户表和博客表,我们就设计这俩

建议大家现在记事本上写好了在直接拷贝到数据库上,这样不容易出错
在这里插入图片描述

db.sql

-- 编写建库建表的 sql

create database if not exists blog_system;

use blog_system;

-- 创建一个博客表.
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());

-- 创建一个用户表
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');

在这里插入图片描述

2. 封装数据库操作

2.1 先创建 DBUtil 封装数据库连接的操作

我们相关都操作放到各自的包里面,这样让我们后面写起来不容易混乱!!
在这里插入图片描述

这里就先用之前学过的 JDBC 来连接数据库

package model;

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/blog_system?characterEncoding=utf8&useSSL=false";
    private static final String USERNAME = "root";
    private static final String PASSWORD = "root";

    private static volatile DataSource dataSource = null;

    private static DataSource getDataSource() {
   
   
        if (dataSource == null) {
   
   
            synchronized (DBUtil.class) {
   
   
                if (dataSource == null) {
   
   
                    dataSource = new MysqlDataSource();
                    ((MysqlDataSource)dataSource).setUrl(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 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.2 创建实体类

使用实体类来表示数据库中的一条记录,根据数据库创建的表,我们需要创建 Blog 类和 User 类
在这里插入图片描述

这样写方便我们观察:
在这里插入图片描述

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

    //    public Timestamp getPostTime() {
   
   
//        return postTime;
//    }

    // 把这里的 getter 方法给改了, 不是返回一个时间戳对象, 而是返回一个 String (格式化好的时间)
    public String getPostTime() {
   
   
        // 使用 SimpleDateFormat 来完成时间戳到格式化日期时间的转换.
        // 这个转换过程, 需要在构造方法中指定要转换的格式, 然后调用 format 来进行转换
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return simpleDateFormat.format(postTime);
    }


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

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

2.3 封装针对数据的增删改查

我们把提供了增删改查这样的类,称为 DAO

BlogDao
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 {
   
   
    // 一. 往博客列表里插入一个博客.
    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);
        }
    }

    //二. 能够获取到博客表中的所有博客的信息(用于博客列表页,注意此处的获取不一定就是 里面的所有内容)
    public List<Blog> selectAll(){
   
   
        List<Blog> blogs = new ArrayList<>();
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
   
   
            connection = DBUtil.getConnection();
            //我们想要让最新的排在博客列表最上面
            String sql = "select * from blog order by postTime desc";
            statement = connection.prepareStatement(sql);
            resultSet = statement.executeQuery();
            while(resultSet.next()){
   
   
                Blog blog = new Blog();
                blog.setBlogId(resultSet.getInt("blogId"));
                blog.setTitle(resultSet.getString("title"));
                //这里我们要针对长的内容进行截取
                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;
    }

    //三. 能够根据博客 id 获取到指定的博客内容(用于在博客详情页)
    public Blog selectOne(int blogId){
   
   
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
   
   
            connection = DBUtil.getConnection();
            String sql = "select * from blog where blogId = ?";
            statement = connection.prepareStatement(sql);
            statement.setInt(1,blogId);
            resultSet = statement.executeQuery();
            // 这里根据主键来查询的,查到的要么是 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.getShort("userId"));
                blog.setPostTime(resultSet.getTimestamp("postTime"));
                return blog;
            }
        } catch (SQLException throwables) {
   
   
            throwables.printStackTrace();
        }finally {
   
   
            DBUtil.close(connection,statement,resultSet);
        }
        return null;
    }

    //四. 从博客列表中,根据博客 id 删除博客
    public void delete(int blogId){
   
   
        Connection connection = null;
        PreparedStatement statement = null;
        try {
   
   
            connection = DBUtil.getConnection();
            String sql = "delete from blog where blogId = ?";
            statement = connection.prepareStatement(sql);
            statement.setInt(1,blogId);
            statement.executeUpdate();
        } catch (SQLException throwables) {
   
   
            throwables.printStackTrace();
        }finally {
   
   
            DBUtil.close(connection,statement,null);
        }
    }


    //五. 修改
    public void update(Blog blog) {
   
   
        Connection connection = null;
        PreparedStatement statement = null;
        try {
   
   
            // 1. 建立连接
            connection = DBUtil.getConnection();
            // 2. 拼装 SQL 语句
            String sql = "update blog set content = ? ,title = ? where blogId = ?";
            statement = connection.prepareStatement(sql);
            statement.setString(1, blog.getContent());
            statement.setString(2, blog.getTitle());

            statement.setInt(3, blog.getBlogId());
            // 3. 执行 SQL 语句
            int ret = statement.executeUpdate();
            if (ret == 1) {
   
   
                System.out.println("编辑成功");
            } else {
   
   
                System.out.println("编辑失败");
            }
        } catch (SQLException e) {
   
   
            e.printStackTrace();
        } finally {
   
   
            DBUtil.close(connection, statement, null);
        }
    }

    //6. 计算个人文章的总数
    public static Integer selectTotal(int userId){
   
   
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
   
   
            connection = DBUtil.getConnection();
            String sql = "select count(userId) from blog where userId = ?";
            statement = connection.prepareStatement(sql);
            statement.setInt(1,userId);
            resultSet = statement.executeQuery();
            if(resultSet.next()){
   
   

            }
            return resultSet.getInt(1);

        } catch (SQLException throwables) {
   
   
            throwables.printStackTrace();
        }finally {
   
   
            DBUtil.close(connection,statement,resultSet);
        }
        return null;
    }

    public static void main(String[] args) {
   
   

        Integer ret1 = selectTotal(2);
        System.out.println(ret1);
        BlogDao blogDao = new BlogDao();
        Blog blog = new Blog();
        blog.setUserId(1);
        blog.setBlogId(1);
        blog.setTitle("hahah");
        blog.setContent("fff");
        blogDao.update(blog);
    }
}


UserDao
package model;

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

//提供了针对用户表的基本操作
public class UserDao {
   
   

    public void insert(User user){
   
   
        Connection connection = null;
        PreparedStatement statement = null;
        try {
   
   
            connection = DBUtil.getConnection();
            String sql = "insert into user values(null,?,?)";
            statement = connection.prepareStatement(sql);
            statement.setString(1, user.getUsername());
            statement.setString(2, user.getPassword());
            statement.executeUpdate();
        } catch (SQLException throwables) {
   
   
            throwables.printStackTrace();
        }finally {
   
   
            DBUtil.close(connection,statement,null);
        }
    }

    //主要实现
    // 1. 根据用户名来查找用户信息
      //这个会在登录逻辑中使用
    public User selectByName(String username) {
   
   
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
   
   
            connection = DBUtil.getConnection();
            String sql = "select * from user where username = ?";
            statement = connection.prepareStatement(sql);
            statement.setString(1, username);
            resultSet = statement.executeQuery();
            // 此处 username 使用 unique 约束, 要么能查到一个, 要么一个都查不到.
            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;
    }

    // 2. 根据用户 id 来找用户信息.
    //    博客详情页, 就可以根据用户 id 来查询作者的名字, 把作者名字显示出来.
    public User selectById(int userId) {
   
   
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
   
   
            connection = DBUtil.getConnection();
            String sql = "select * from user where userId = ?";
            statement = connection.prepareStatement(sql);
            statement.setInt(1, userId);
            resultSet = statement.executeQuery();
            // 此处 username 使用 unique 约束, 要么能查到一个, 要么一个都查不到.
            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;
    }
}

到这里 数据库操作都给准备好了
下面就是实现服务器的代码了

三. 约定前后端交互接口

我们先把之前写的前端博客系统给拷贝到 webapp 里面
在这里插入图片描述

博客系统:链接

1. 实现博客列表

1.1约定前后端交互接口
[请求]
GET /blog
[响应] [
   {
        blogId: 1,
        title: "第一篇博客",
        content: "博客正文",
        userId: 1,
        postTime: "2022-05-27 12:00:00"
   },
   {
        blogId: 2,
        title: "第二篇博客",
        content: "博客正文",
        userId: 1,
        postTime: "2022-05-27 12:10:00"
   },
    ...
]

我们约定, 浏览器给服务器发送一个 GET /blog 这样的 HTTP 请求, 服务器给浏览器返回了一个 JSON 格式的数据.

1.2 实现服务器代码
package controller;

import model.Blog;
import model.BlogDao;
import com.fasterxml.jackson.databind.ObjectMapper;

import javax.servlet.ServletException;
import javax
评论 14
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

粉色的志明

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

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

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

打赏作者

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

抵扣说明:

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

余额充值