项目名称: 博客系统
项目介绍: 本项目是一个 Web 项目,前端开发主要是基于 Ajax 发送 HTTP 请求,后端开发主要是基于 Servlet 接收处理 HTTP 请求,采用的开发模式是前后端分离模式。
主要有四个页面:
-
博客列表页
列表页展示了当前登录用户的信息以及所有用户的博客摘要信息,点击查看全文标签可查看该篇博客详情
页面效果如下图:
-
博客详情页
详情页展示了当前文章作者的基本信息,不同文章显示不同作者信息
页面效果如下图:
-
博客登录页
根据数据库所已有的信息验证用户是否能够登录进入博客系统
页面效果如下图:
-
博客编辑页
编辑页面可以进行编辑博客并且支持 markdow 语法
页面效果如下图:
主要实现的功能有:
- 实现登录功能
- 实现注销功能
- 实现发布博客功能
- 实现删除博客功能
**开发环境:**IDEA、Tomcat、Maven、JDK1.8、MySQL、VScode
**相关技术栈:**HTML、CSS、JavaScript、Ajax、Servlet
本项目已部署到 Linux 云服务器上~链接: 博客系统
一、项目搭建- 创建 maven 项目
- 创建目录结构
wepapp/WEB-INF/web.xml
- 引入依赖,更改 pox.xml
- servlet 依赖 ,版本 3.1.0
- jackson 依赖,版本 2.12.6.1
- mysql 依赖,版本 5.1.47
- 写一个简单的 hello world 响应验证一下程序是否正确启动
- 打包和部署
这里使用 SmartTomcat 来完成(Tomcat 使用 8.5 版本)
设计表结构,主要有两个表:用户表 和 博客表
用户表的信息有:用户ID、用户名、用户密码
博客表的信息有:博客ID、博客标题、博客内容、博客类型、作者ID、创作日期
2、封装数据库操作- 创建一个 DBUtil 类来封装数据库连接的操作
- 创建两个实体类 User类 和 Blog类 来表示数据库中的一条记录
- 针对数据库增删查改封装为 DAO 类,创建 UserDao 类 和 BolgDao 类
关于数据库的操作都给准备好了,接下来就可以实现服务器代码了
三、具体业务功能实现 1、实现博客列表页 让前端页面给服务器发送一个 HTTP 请求(基于 ajax)服务器处理这个请求,从数据库查询博客列表,把数据 以 json 的格式返回给浏览器,浏览器再根据得到的数据拼装 html 页面
1)约定好前后端交互的接口请求格式: GET /bolg HTTP/1.1
响应格式:
HTTP/1.1 200 ok
Content-type: application/json; charset=utf8
json格式:
[
{
blogId: 1,
title: "博客标题",
content: "博客正文",
userId: 1,
postTime: "2022-7-24 9:13"
},
{
blogId: 1,
title: "博客标题",
content: "博客正文",
userId: 1,
postTime: "2022-7-24 9:13"
},
{
blogId: 1,
title: "博客标题",
content: "博客正文",
userId: 1,
postTime: "2022-7-24 9:13"
},
]
2)实现服务器代码
创建一个 BlogServlet 类来处理 /blog 路径对应的请求,使用 doGET 方法来获取到数据库中的博客列表数据,并将 blog 对象转换成 JSON 格式的数据返回给客户端
3)实现客户端代码这里遇到了一个问题:
这里验证响应的时候,发现 postTime 发布日期的格式有问题,是一个时间戳而不是一个格式化的日期时间
这里可以需要修改 Blog 类的 getPostTime 方法,使用 SimpleDateFormat 类来完成从时间戳到格式化日期的转换
在页面加载的时候,让页面通过 ajax 访问服务器,获取到数据库中的博客数据,并且填写到 html 页面中
2、实现博客详情页 1)约定前后端交互接口请求格式: GET /blog?blogId=1
响应格式:
{
blogId: 1,
title: "博客标题",
content: "博客正文",
userId: 1,
postTime: "2022-7-24 9:13"
}
2)实现后端代码
还是通过 /blog 这个 URL 路径,使用 BlogServlet 这个类来处理获取博客详情页请求和获取博客列表请求,可以根据请求中是否带有 ?blogId=1 这样的 query string 来区分当前是获取博客列表还是详情页。如果query string 中带有 blogId 参数就返回对应用户的详情页,否则就返回列表页
3)实现前端代码通过 ajax 发送 GET 请求,并带有 blogId 这样的参数
3、实现登录功能并检测用户登录状态 1)约定前后端交互的接口这里遇到了一个问题:
当进入博客详情页的时候,就需要给服务器发送 ajax 请求获取博客数据,这个请求中就需要带有 blogId ,那么 blogId 从哪里来?
- 在从 blog_list.html 跳转到 blog_detail.html 的过程中,其实就已经在 query string 中传入了 blogId 只要把当前 blog_detail.html 的 query string 拿到,在拼接到 ajax 的请求里即可
- 使用 location.search 方法就可获取到当前页面的 query string
请求格式: POST /login Content-Type: application/x-www-form-urlencoded 例: username=admin&password=123
响应格式: HTTP/1.1 302 Location: blog_list.html2)实现服务器代码
创建 LoginServlet 类并把路径设为 /login 然后在 LoginServlet 类中使用 GET 方法中实现登录代码,获取到请求中的参数,然后和数据库中的用户内容进行比较,判断用户名和密码格式是否正确,如果比较通过就加入一个 session 会话并返回一个重定向报文跳转到博客列表页面
如何检测登录状态?3)实现前端代码在 LoginServlet 类中使用 POST 方法中实现检测代码,用这个方法来查看 user 对应的会话是否存在,并将用户信息(要把用户密码置为空)返回给前端
通过 form 表单发送 POST 请求,可以在博客列表页/详情页加载的时候,通过 ajax 访问服务器,获取当前的登录状态,看能不能获取到。如果获取到了,就说明当前确实登录了,否则跳转到登录页面
4、显示用户信息这里需要检查登录状态,创建一个 getLoginStatus 方法来获取当前的登录状态,需要让博客列表和博客详情页在登录状态下可使用,如果检测到用户未登录则直接重定向到 login.html 中
这里需要实现的是,在博客列表页,显示当前用户的信息。在博客详情页,显示具体文章作者的信息
1)约定前后端交互的接口定义一个新的接口,专门供页面从服务器拿到当前用户信息
请求: GET /user?blogId=1
响应:
{
userId: 1,
username: "张三"
}
2)实现服务器代码
创建一个 UserServlet 类来处理 /user 这样的请求,后端就根据 blogId 参数是否存在分别进行处理。首先根据 blogId 查询 Blog 对象,然后再根据 Blog 中的 userId 信息来找到对应的用户,最后将 用户信息返回到前端
3)实现客户端代码前端分别在 blog_list.html 和 blog_detail.html 来进行处理,可以 getLoginStatus 方法中修改对应的用户信息
5、实现注销功能当用户点击注销之后,就会在服务器上取消登录状态,并跳转到登录页面
1)约定前后端交互接口请求: GET /logout
响应: HTTP/1.1 302 Location: login.html2)实现服务器代码
创建一个 LogoutServlet 类来接收注销请求,先从请求中找到当前用户的 session 会话,然后把会话中的信息删掉就可以实现注销这样的一个效果了
3)实现客户端代码将 a 标签路 url 改为 logout 就可以向服务器发送 GET 请求了
6、实现发布博客功能 1)约定好前后端交互接口请求: POST /blog Content-Type: application/x-www-form-urlencoded title=博客标题&content=博客正文
响应: HTTP/1.1 302 Location: blog_list.html2)实现服务器代码
可以在前面创建好的 BlogServlet 类中使用 doPost 方法来处理发布博客的请求。首先从请求中获取当前用户的 session 会话,从会话中获取到用户信息,并判断用户是否登录。然后读取请求, 取出参数 (即博客的标题和正文),构造 Blog 对象并插入数据库,最后返回重定向响应报文跳转到博客列表页
3)实现前端代码在前端的博客编辑这里可以给整个页面套上一个 form 标签来进行发送发布博客请求。为了能够进行 form 表单的提交, 这里还需要搞一个 teextarea 多行编辑框, 借助这个编辑框来实现表单的提交。并设置 editor.md 让编辑器把 markdown 内容也同步保存到这个隐藏的 textarea 中
7、实现删除博客 1)约定前后端交互接口注意问题
- 这里在添加了 form 表单后会影响到整个页面的样式和布局因此需要做出一定的修改
请求: GET /blogDelete?blogId=1
响应: HTTP/1.1 3022)实现服务器代码
创建一个 BlogDeleteServlet 类并把路径设置为 /blogDelete 来处理删除操作,使用 BlogDao 类封装的删除方法即可删除数据库中的该篇博客
3)实现前端代码在前端博客详情页的导航栏里面加个 删除 按钮,如果当前登录的用户就是文章作者,则删除按钮显示否则就隐藏
这里遇到的问题
如何区分登录用户和当前文章的作者是不是同一个人?
在前端博客详情页中,既从服务器那里获取了当前用户的登录信息,又获取到了博客的作者信息。因此就可以看,这两个接口返回的用户信息是不是一样的。如果一样就显示一个删除按钮,不一样就不予显示,这样一来就可以辨别出当前用户是否有权限删除该博客



