初学者-----基于前后端分离实现个人博客系统

每天学习多一点!烦恼少一点!

在这里插入图片描述

当JavaWeb知识学习结束之后,通过一个项目让我们能够更好更扎实的理解和掌握知识!!
我将我学习的过程编写为一篇文章,能够让每个初学者小伙伴有一个更好的学习。

项目连接:https://gitee.com/XiaoCBird/personal-items


项目介绍

我们通过前后端分离的技术来实现。
前端通过我们所学三剑客:HTML+CSS+JS来编写我们博客系统所需要的页面、通过ajax和form表单来实现浏览器和Web服务器之间的数据传输。
后端通过Servet+Tomcat+JDBC+MySQL来实现博客系统后端主要逻辑的实现。
博客系统中主要包含:
前端实现四个页面:博客登录页、博客列表页、博客详情页、博客编辑页。(详情见代码,这里就不进行详细讲解了)
后端实现八个功能:实现博客列表页的展示功能、实现博客详情页的展示功能、登录功能、限制用户权限、显示用户权限、退出登录、发布博客、删除博客。


项目实现

1.项目创建

1.1 创建一个Maveni项目

在这里插入图片描述

1.2 引入依赖

通过maven将代码中所需要依赖的jar包添加到项目中
Servlet、mysql、jackson
将依赖添加到pom.xml文件中

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

    </dependencies>

1.3 创建项目所用到的目录

如下图:在WEB-INF目录下创建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.设计项目所需要的数据库

项目中我们会用到两个表:

博客表blog(blogId title content postTime userId)

用户表user (userId username password);

我们将数据库建表语句写到一个文件中,之间进行粘贴复制,方便我们使用:

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  -- 发布时间
);

drop table if exists user;
create table user (
                      userId int primary key auto_increment,
                      username varchar(128) unique,
                      password varchar(128)
);
insert into blog values(null,"这是第一篇博客","认真学Java",1,'2022-12-13');
insert into blog values(null,"这是第一篇博客","认真学Java",2,'2022-12-13');

insert into user values(null,"admin","123");
insert into user values(null,"Jack","123");

设计的关键要素:我们要找到数据库中所包含的“实体”
auto_increment:主键自增长 数据库系统根据定义自动赋值。每增加一条记录,主键会自动以相同的步长进行增长。

我们将构建好的语句直接粘贴到Mysql中,在我们的数据库中存好信息
在这里插入图片描述
查询数据库:
在这里插入图片描述
查询表:
在这里插入图片描述
在这里插入图片描述在这里插入图片描述


3.封装数据库操作

在java文件夹下创建model文件夹,我们将操作数据库所用到的代码都存放到这个文件夹中
我们先将数据库建立和断开操作的代码进行封装,这样以后我们在使用的时候比较方便
在model文件夹中创建DBUtil类
在这里插入图片描述

我们这里的编写的是一个懒汉模式的单例。所以要考虑线程安全问题~~
Servlet 程序是运行在多线程环境中,每个请求可能对应着一个线程,Tomcat也是通过多线程的方式来处理请求

然后我们将用到的增删改查也进行封装

3.1 Blog类和User类

先创建一个Blog类,表示一篇博客
在这里插入图片描述

创建一个User类,表示一个用户

在这里插入图片描述

3.2 BlogDao类和UserDao类

然后再创建两个类:BlogDao、UserDao。这两个类主要包对博客表和用户表的增删改查操作
在BlogDao类中我们要实现以下几点功能:
1.新增博客(博客编辑页)
2.查询出博客列表(博客列表页)
3.查询出指定博客的详细内容(博客详情页)
4.删除指定的博客
在这里插入图片描述
这四步操作就代表的上述所要实现的四个功能,对于四个功能的详细编写,均为JDBC操作,这里只展示一个方法的实现。这里当我们把所有的都写完之后会发现,同质化很严重。网上查了之后发现有一种方便操作的框架–MyBatis(数据库操作框架)这个只有制定好SQL语句,框架会自动生成JDBC代码。(这个还没学0-0)

 public void insert(Blog blog) {
            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
                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);
            }

    }

这里我们用到的setXXX方法,是从下标1开始,计算的是第几个,而不是第几列
所以 statement.setString(1, blog.getTitle()); 对应的就为查询语句中的第一个

然后我们对照User表将UserDao类编写完成,这里主要涉及俩个操作:
1.当我们实现登录时,能够根据用户名实现查询
2.通过用户的Id来查询用户信息

在这里插入图片描述
这俩步操作就代表这要实现的俩个功能,这里也通过JDBC操作进行实现,只展示一个方法的具体实现

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();
            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.核心业务功能实现

我们先将设计好的前端代码粘贴到我们的项目中webapp文件夹下
在这里插入图片描述
然后通过配置Tomcat观察是否成功
在这里插入图片描述
配置成功后启动
在这里插入图片描述
如下图我们能够成功启动,说明文件没有错误。
在这里插入图片描述

4.1 博客列表页

这一模块关键工作为:在页面加载时候,我们通过ajax来访问服务器。然后从服务器拿到博客列表页所需要的详细情况,这个时候需要查询数据库,然后页面再将查询到的数据显示到界面中
我们通过下面三个步骤来完成上述功能的实现:
1.约定前后端交互所用接口(重点内容)
2.编写后端代码
3.编写前端代码

4.1.1 约定前后端交互所用接口(方法不唯一)
请求:博客列表页加载时给服务器发送的ajax请求

GET /blog

响应:服务器把博客列表数据返回给页面

Content-Type:application/json

> {
>
>{
>
> ​		blogId:1,
>
> ​		title:'第一篇博客'
>
> ​		content:"今天起开始好好写代码“,
>
> ​		userId:1,
>
> ​		postTime:"2022-12-25 21:34:00
>
>},
>
> }
4.1.2 编写后端代码

在java下创建一个新的包:controller,我们将所用到的业务代码均放到这个包中
在包中创建一个BlogServlet 来实现GET /blog接口
在这里插入图片描述

4.1.3 编写前端代码

在前端我们需要在编写好的blog-list.html中进行修改
前后端交互需要引入Jquery

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

在这里插入图片描述

根据返回的 json 数据, 来构造出页面内容, jquery ajax 会自动的把响应得到的 body 按照响应的 Content-Type 进行转换格式. 如果响应的 Content-Type 是 json, 此时就会自动把 body 转成 js 的对象。这里的body就是我们约定前后端接口中{ }里面所包含的内容

编写完之后我们通过启动Tomcat,查看前端是否能够查询到我们数据库中所存的数据
在这里插入图片描述

这里有一个需要改动的地方就是:我们博客创建的时间
我们需要将后端Blog代码中 getPostTime() 这个方法进行魔改,这样返回的时间就能按照咱们所规定的进行返回。

public String getPostTime() {
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    return simpleDateFormat.format(this.postTime);
}

4.2 博客详情页

这一模块所要实现功能为:当我们点击查看详情时让页面跳转到博客详情页(blog-detail.html)然后在跳转的过程中,url带上当前获取到的博客Id。然后在blog-detail.html页面中,通过ajax从数据库中查询到博客详情内容,然后显示到界面中
我们还是通过下面三个步骤来完成上述功能的实现:
1.约定前后端交互所用接口
2.编写后端代码
3.编写前端代码

4.2.1 约定前后端交互所用接口
请求:

GET /blog?blogId=1

响应:

HTTP/1.1 200 OK

Content-Type:application/json

{

​	blogId:1,

​	title:'我的第一篇博客',

​	content:'这是正文',

	userId:1,

​	postTime:'2022-12-26 10:00:00'

}
4.2.2 编写后端代码

因为代码中已经有一个 /blog 的 Servlet 了,就在之前的 Servlet 基础上做出修改即可,基于同一个 Servlet ,同一个doGet方法,让它既可以处理获取博客列表,又能获取博客详情。通过判断 /blog后边所带的参数是否存在来绝对返回的是播客列表还是博客详情!!
在这里插入图片描述

4.2.3 编写前端代码

在blog-list.html中做出如下修改,来实现页面的跳转

    //构造查看全文按钮
	let a = document.createElement('a');
	a.href = 'blog_detail.html?blogId = ' + blog.blogId;
	a.innerHTML = '查看全文 &gt;&gt';
	blogDiv.appendChild(a);

在blog-detail.html中加入ajax,发送请求给后端
在这里插入图片描述

这里有一个需要改动的地方:在返回博客详情数据时,我们添加了editor.md来进行渲染,让我们的博客能够以markdown类型在页面中输出
我们需要在blog_detail.html中添加editor.md依赖

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

编写完成之后我们再次重启Tomcat,观察我们前端页面是否成功
在这里插入图片描述

4.3 博客登录页

这一模块所要实现功能为:在登录页面中,输入用户名密码,在数据库中验证,完成登录功能。因为该项目暂时没有实现注册功能,所以测试所用账户和密码以提前存入到数据库中,具体数据请看数据库设计步骤。
我们还是通过下面三个步骤来完成上述功能的实现:
1.约定前后端交互所用接口
2.编写后端代码
3.编写前端代码

4.3.1 约定前后端交互所用接口

这里通过使用form表单来提交数据(ajax也可以,但是相比较还是form表单更为简单)

请求:

POST /login

Content-Type:application/x-www-form-urlencoded

Username=admin&password=123

响应:

HTTP/1.1 302 OK
/*如果登录成功,自动跳转到博客列表页。如果登录失败,则返回登录失败*/

Location:blog-list.html
4.3.2 编写后端代码

我们在controller包下创建一个LoginServlet 来处理请求

在这里插入图片描述

4.3.3 编写前端代码

将login.html进行一下修改:

1.添加form 2.给input添加name属性 3.将登录的type改成submit

在这里插入图片描述
编写完成之后,再次重新启动Tomcat,测试一下是否成功:
在这里插入图片描述

4.4 限制用户权限

在用户未登录时,用户无法实现直接进入到博客详情页和博客列表页。若用户未登录直接访问博客详情和列表页时,会强制用户跳转到登录页进行登录。
我们还是通过下面三个步骤来完成上述功能的实现:
1.约定前后端交互所用接口
2.编写后端代码
3.编写前端代码

4.4.1 约定前后端交互所用接口
请求:
GET /login
CookieJSESSIONID=xxxxxxx

响应:
HTTP/1.1 200 OK         【已登录】
HTTP/1.1 403 Forbidden  【未登录】

4.4.2 编写后端代码

在LoginServlet中加上这样一段代码:

在这里插入图片描述

4.4.3 编写前端代码

我们按照第一步所设计好的约定,然后通过ajax发送请求:
在blog-list.html中进行如下修改:
因为登录验证在多处调用,所以我们将这段代码写入到一个app.js文件中,然后直接引入这个文件就行
在这里插入图片描述
引入之后直接调用该方法即可:

在这里插入图片描述

4.5 左侧标签显示用户信息

如果是博客列表页,则左侧标签显示当前用户信息
如果是博客详情页,则左侧标签显示当前文章作者
我们还是通过下面三个步骤来完成上述功能的实现:
1.约定前后端交互所用接口
2.编写后端代码
3.编写前端代码

4.5.1 约定前后端交互所用接口

在博客列表页:发送一个ajax,获取到当前用户登录的用户信息,将这个用户信息显示到页面上即可

请求:
GET /userinfo

响应:

HTTP/1.1.200  OK

{

​	userid:1,

​	username:‘admin’(当前登录的用户)

}

在博客详情页,发送一个ajax并且带参数:blogId,获取到这个指定的blogId对应的作者信息,将这个信息显示到页面上

请求:

GET /userinfo?blogId=1

响应:

HTTP/1.1.200  OK

{

​	userid:1,

​	username:‘user’(当前文章的作者)

}
4.5.2 编写后端代码

在controller下创建一个UserInfoServlet
在这里插入图片描述

4.5.3 编写前端代码

在blog-list和blog-detail中添加如下代码
在这里插入图片描述
在这里插入图片描述

4.6 退出登录

这里我们要具体实现的功能是:清除当前用户的登录状态、跳转到博客登录页
我们通过下面三个步骤来完成上述功能的实现:
1.约定前后端交互所用接口
2.编写后端代码
3.编写前端代码

4.6.1 约定前后端交互所用接口

点击退出登录的时候,发送 一个get请求,并且跳转到博客登录页

请求:
GET /logout

响应:
HTTP/1.1 302
Location:login.html
4.6.2 编写后端代码

在controlller中创建一个新的类LogoutServlet

在这里插入图片描述

4.6.3 编写前端代码

这里直接通过使用a标签进行实现,不需要使用ajax来实现
我们将详情页、编辑页、列表页中退出登录均改成a标签
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.7 发布博客

4.7.1 约定前后端交互所用接口
请求:
POST /blog
Content-Type:application/x-www-form=urlencoded

title=标题&content=正文

响应:
HTTP/1.1 302
Location:blog-list.html
4.7.2 编写后端代码

把请求中的博客数据拿到同时写入数据库
在blogServler中添加如下代码:

@Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf8");
        // 1. 获取到用户的登录状态.
        HttpSession session = req.getSession(false);
        if (session == null) {
            resp.setStatus(403);
            return;
        }
        User user = (User) session.getAttribute("user");
        if (user == null) {
            resp.setStatus(403);
            return;
        }
        // 2. 读取请求的内容
        String title = req.getParameter("title");
        String content = req.getParameter("content");
        if (title == null || title.equals("") || content == null || content.equals("")) {
            resp.setStatus(400);
            resp.setContentType("text/html; charset=utf8");
            resp.getWriter().write("请求中的标题或正文不完整");
            return;
        }
        // 3. 构造 Blog 对象, 并插入到数据库中.
        Blog blog = new Blog();
        blog.setTitle(title);
        blog.setContent(content);
        // 博客的作者. 作者是谁? 当前谁登录, 作者就是谁!!
        blog.setUserId(user.getUserId());
        BlogDao blogDao = new BlogDao();
        blogDao.insert(blog);
        // 4. 插入成功之后, 跳转到博客列表页.
        resp.sendRedirect("blog_list.html");
    }

在BlogDao中修改一下查询语句:使得我们查询出来的内容是按照发布时间进行排序的,最新发布的位于最前

String sql = "select * from blog order by postTime desc";
4.7.3 编写前端代码

首先我们需要在div中添加form
在这里插入图片描述
其次在input type=“text” 添加name属性、将发布文章改为submit
在script 标签中添加:

// 加上这个属性, 效果就是把编辑器里的内容给自动保存到 textarea 里.
        saveHTMLToTextArea: true,

4.8 删除博客

4.8.3 编写后端代码

对UserInfo的接口做出修改,从而判断当前登录的用户是否是同一个人,如果是则返回true,如果不是则返回false。然后前端可以通过返回的结果来决定是否删除按钮

在User里添加如下代码:

 private int isYourBlog = 0;

    public int getIsYourBlog() {
        return isYourBlog;
    }

    public void setIsYourBlog(int isYourBlog) {
        this.isYourBlog = isYourBlog;
    }

在UserInfoServlet里添加:

if (user.getUserId() == author.getUserId()) {
                author.setIsYourBlog(1);
            } else {
                author.setIsYourBlog(0);
            }

然后在controller中新建一个BlogDeleteServlet

在这里插入图片描述

4.8.3 编写前端代码

如果当前博客作者是登录用户自己,则在详情页导航栏中显示这个删除按钮

如果当前博客不是登录的用户,则不显示删除按钮

我们通过复用这个接口,根据结果判断是否显示接口
在这里插入图片描述

小结

到这里我们的一个简单的博客系统项目算是告一段落了。整个系统中涉及到两个表、四个页面以及上述这些功能。但是项目仍然还有很多需要补充的地方:如用户注册、用户头像、博客中插入图片等众多功能。这些仍需要我们继续去拓展。
在整个系统完成过程中也遇到了很多问题:前端页面的实现、前后端交互是出现的编码错误、在插入博客数据后无法正确返回等等。
在第一次完成项目时,我们会遇到很多困难,而这些也是我们复习知识最好的方式
当我们遇到问题时,一定不要放弃。通过输出日志、添加断点调试等工具慢慢细心的寻找错误。学会调试的过程就是我们成长的过程!

“让我们成为哪种人的不是我们的能力,而是我们的选择。”

在这里插入图片描述

  • 52
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值