该博客系统基于servlet和mysql数据库 , 并且通过xshell终端工具部署至云服务器. 实现的功能包括:
1.博客列表页
2.博客详情页
3.登陆页面
4.强制登陆检查
5.获取用户信息
6.退出登陆
7.发布博客
一.系统展示
登陆页面
博客列表页
博客详情页
博客编辑页
下面就开始编写代码了. (前端代码不提供) 接下来的操作主要是两个大的方面 .
1.前端和服务器的交互
2.服务器和数据库的交互
二.服务器和数据库的交互
该系统涉及的表包括blog博客表和用户登陆的user表.
一般需要把建库建表的操作,写成sql文件保留下来 , 后续如果把程序部署到别的机器上,建库操作直接赋值sql,然后执行就可以完全服务器数据库的建库建表操作.
dao层
Data Acess Object 数据访问对象 , 写一些类,通过这些类里的方法封装了数据库操作,此时数据库就是通过这样的对象来访问的
1.设计数据库
- 根据需求,找出需要有哪些实体
- 梳理清楚实体和实体之间的关系 一对一/一对多/多对多
2.封装DBUtil 实现建立连接和断开连接
package dao;
import com.mysql.cj.jdbc.MysqlDataSource;
import javax.sql.DataSource;
import javax.xml.transform.Result;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* 通过这个类,把数据库建立连接的逻辑封装好
*/
public class DBUtil {
//使用单例模式创建(懒汉模式线程不安全)
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("jdbc:mysql://127.0.0.1:13306/blogsystem?characterEncoding=utf8&useSSL=false");
((MysqlDataSource) dataSource).setUser("root");
// ((MysqlDataSource) dataSource).setPassword("chenyafen");
((MysqlDataSource) dataSource).setPassword("123456");
}
}
}
return dataSource;
}
//提供方法,和数据库建立连接
public static Connection getConnection() throws SQLException {
return getDataSource().getConnection();
}
//提供方法,和数据库断开连接
public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet) throws SQLException {
if(resultSet!=null){
resultSet.close();
}
if(statement!=null){
statement.close();
}
if(connection!=null){
connection.close();
}
}
}
3.创建实体类 后续数据库操作是围绕实体类展开的
三.服务器和数据库的交互
实现前后端交互逻辑 , 针对每个功能点的步骤都是一样的.
1.设计前后端交互接口
2.开发后端代码
3.开发前端代码
4.调试
1.博客列表页
让博客列表页再加载的时候,发起一个ajax的http 请求,请求发送到服务器上,就能获取博客列表数据. 进一步的把博客数据展示到页面上 (拼接成一些html片段)
1.前端发起一个http请求,向后端索要博客列表数据
2.后端收到请求之后查询数据库获取到数据库中的博客列表,返回给前端
3.前端拿到响应之后,就依据这里的内容,构造出html片段,最终显示出来
在进行这三个操作之前,还需要约定前后端交互接口,后续前端和后端要进行很多不同的数据交互.每一种数据交互,都需要发送不同的请求,返回不同的响应 .
此处就需要把请求具体什么样? 响应具体什么样? 都约定好 !
约定前后端交互接口
以下是一种典型的约定方式
请求:
GET blog
响应:
HTTP/1.1 200 OK
Content-Type:application/json ( 返回的是json数据)
[
{
blodId:1,
title:"第一篇",
content:"dddd",
userId:1,
posttime:"ddddd"
} ,
{
blodId:1,
title:"第一篇",
content:"dddd",
userId:1,
posttime:"ddddd"
}
]
前端负责构造请求 , 解析响应 ;
后端负责解析请求, 构造响应 ;
编写后端代码
api应用编程接口
博客系统后续还会写一些servlet给前端提供功能的支持. 这些都可以理解成服务器给前端提供的api (或者也可以叫做Controller )
说明:
jackson看到blogs是一个list,就会构造出一个json数组; 针对list中每一个blog对象,分别构造出json对象 , 具体构造过程,就是根据Blog属性:属性的名字就是json的key,属性的值就是json的值
编写前端代码
让页面通过js ajax的方式发起http请求 .
说明:
1.定义了一个函数,并调用这个函数 (不需要返回值)
2.构造这个html片段
相当于
<div> </div>
<div class="blog"> <div>
blog就是服务器返回的json数组里的一个元素 (这一个元素有五个属性)
浏览器访问该页面
Fiddler抓包
上面的请求是获取列表页这个静态页面的
下面的请求是获取博客数据的
如果出现灰色的是因为触发了浏览器自带的缓存;
浏览器为了提高页面加载速度,就会把静态的资源在本地硬盘缓存一份,后续再访问统一资源,直接从本地获取 .
前后端交互过程:
当浏览器发起一个形如blog的http请求时,服务器就会调用查询数据库,并获取到数据库中的数据,然后转换为json格式的字符串,再返回给前端,前端拿到数据之后,回调函数进行遍历数据,依据返回的数据构造出html片段
问题:
1.更早发布的博文应该在下面 .
解决方法:给查询语句加上order by ,按照时间降序排序(大的在前, 小的在后)即可
2.时间格式不对
针对这个问题,要先明确问题出在前端还是后端 , 抓包查看后端返回的响应 , 发现是后端的问题
后端将从数据库读取到的对象转换为json字符串,转成的json字符串就是根据Blog对象的getter方法来完成的 ,jackson会自动调用getter方法把得到的结果作为json字符串中属性的值. 因此问题出在posttime的getter方法上,
使用simpleDateFormat方法:
2.博客详情页
2.1.约定前后端交互接口
请求:
GET /blog?blodId=1
如果是请求中不带query string, 此时就是查询博客列表
如果带有query string (blogId) , 此时就是查询指定博客的详细情况
响应:
HTTP/1.1 200 OK
Content-Typea:application/json
{ blogId:1, title:"dfljf", content:"gjdsf", userId:1, posttime:"2023-12-4" }
2.2实现后端代码
2.3实现前端代码
注意:
1.这里需要让博客详情页,把数据库的中的原始数据,渲染成md渲染后的数据
使用editor.md的线程的方法即可(阅读文档)
2.editor.md也依赖jquery,注意引入的顺序
3.登陆页面
3.1前后端交互接口
请求:
POST /login
Content-type:aaplication/x-www-form-urlencoded
使用form表单提交 使用ajax也可以
响应:
HTTP/1.1 302
Location:blog_list.html
3.2编写后端代码
注意:
1.不要对用户名和密码分别提示,容易造成不安全
2.创建会话,参数设为true.
不存在会话就创建,存在就查询 ; 并且会生成键值对 (sesesionid : httpsession对象 ), 并且会把session通过set-cookie返回到浏览器
3.3编写前端代码
注意:
1.构造sql语句的时候 , 先用preparestatement创建statement . 再设置占位符的值
否则会出现空指针异常
4.实现强制登陆
使得网站登陆后才能使用, 此处咱们要求我们的博客系统,必须登陆才能使用 ;
如果用户在未登陆情况下,访问博客列表页/详情页/编辑页,都会自动跳转到登录页
4.1约定前后端交互接口
在博客列表页/详情页/编辑页,再发起一个get的ajax请求,询问服务器时候登陆
4.2编写前后端代码
5.实现显示用户信息
在列表页,显示当前登陆用户的个人信息 ; 在详情页,显示这个文章的作者信息
实现方法:
在博客列表页和详情页分别发起ajax请求
列表页,就需要获取到当前登陆用户的信息 ; 详情页,就需要获取到文章作者的信息.
5.1约定前后端交互接口
列表页
请求:
GET /user
响应:
HTTP/1.1 200 ok
{
userId:1,
username:'zhangsan'
}
详情页
请求:
GET /user?blogId=1
响应:
HTTP/1.1 200 OK
{
userId:1,
username:'zhangsan'
}
注意:
对于登陆功能来说,依赖了session机制,tomcat是在内存中存储session的.
当重启了tomcat服务器之后,之前的session就没了,下一次访问就需要重新登陆
但是有些smart tomcat会把session放到硬盘中持久化存储 , 重启服务器也不需要重新登陆 ;
6.退出登陆(注销)
判定登陆状态逻辑中
1.会话存在
2.会话中存储的user对象存在
两个条件同时满足,才认为用户是已经登陆了
破坏上述任何一个条件都可以实现注销
但是servlet中,并没有提供一个api来直接删除会话,但是有api可以删除会话中的user
(Attribute)
6.1约定前后端交互接口
请求:
GET /logout
响应:
HTTP/1.1 302
Location :login.html
6.2后端
6.3前端
点击页面的注销,实质上是一个a标签,通过a标签的href属性,指定要访问的请求路径即可 .
点击a标签,自然就能触发http get请求了
7.发布博客
本质上和登陆差不多, 核心都是通过form表单,把页面中用户输入的内容提高到服务器,服务器就会内容保存到数据库中.
7.1约定前后端交互接口
使用form提交数据到服务器
请求:
POST /blog
Conten-type:application/x-www-form-urlencoded (form表单格式)
body内容:
title=***&content=*****
响应:
HTTP/1.1 302
Location:blog_list.html
提交成功跳转到博客列表页,来到页表页之后,就能够看到刚才新发布的博客了 .
7.2后端
7.3前端
把form表单补齐
注意:
md编辑器怎么添加name属性呢?
在此处写一个隐藏的textarea,就可以实现form表单提交的效果,就可以指定name的值.
部署请看这篇 【博客系统】 二-CSDN博客 ~~~