目录
🌟一、数据库设计部分
1、建表分析:系统中一共要实现几张表?
2、开始建表
🌟二、大概框架与实现功能
🌟 三、代码实现部分
🌈前言1:工具类的实现(utils包下)
1、数据库连接的工具类
2 、 用户信息判空的工具类
3、判断当前用户是否已经登录的工具类
🌈前言2:java实体类的定义(model包下)
1、User实体类
2、 Blog实体类
🌈前言3:AppResult类定义响应的返回格式json(Common包下)
🌈1、实现登录功能
1.1 UserDao下:selectByUsername通过用户名查询对应用户
1.2 Servlet实现后端
1.3 前端实现 blog_login.html
🌈2、获取当前用户的登录信息
2.1 Servlet实现后端
2.2 前端代码实现:blog_list.html
🌈3、获取当前所有的文章列表
3.1 BlogDao:selectAll在数据库中查询所有的博客记录
3.2 Servlet实现后端
3.3 前端实现:blog_list.html
🌈4、查看全文功能
界面1实现 :显示这篇博客的具体内容
4.1 UserDao下 :User selectById(Long id)通过Id获取对应用户信息
4.2 BolgDao下:Blog selectById(Long Id)通过Id查询对应博客
4.3 Servlet实现后端
4.4 前端实现:blog_details.html
界面2实现 :显示用户信息
4.1 Servlet实现后端
4.2 前端实现 blog_details.html
🌈 5、发布博客
5.1 blogDao下:insert(Blog blog)写入博客到数据库
5.2 Servlet实现后端
5.3 前端实现 blog_eidt.html
🌈6、删除当前文章
6.1 BlogDao下:deleteById(Long id)通过Id删除博客
6.2 Servlet实现后端
(1)更新后的UserServlet
(2)blogServlet中实现doDelete方法
6.3 前端实现:blog_details.html
🌈7、注销功能
7.1 Servlet实现后端
7.2 前端实现 blog_list.html
🌟一、数据库设计部分
1、建表分析:系统中一共要实现几张表?
分析:系统中一共要实现几张表?
注意:凡是不能被数据库或者编程系统中的基本数据类型表示的,都可以考虑成是一个类或者是一张表。比如:学生类:学生有Id,姓名,成绩...就可以设计为一张表,这个学生对象就可以设计为一个类,类的属性和表的字段一一对应。
1、用户表:一共有四个字段(后面根据博客功能实现,又新增了一个属性:是否为同一个用户)
(1)用户名
(2)密码
(3)Github地址
(4)发表的文章数量
2、博客表
(1)标题
(2)发布内容
(3)发布时间
(4)作者Id(与用户表关联)
2、开始建表
#创建数据库
create database blog_db char set utf8mb4 collate utf8mb4_general_ci;
#选择数据库
use blog_db;
#建立用户表
create table user(
id bigint primary key auto_increment comment'用户Id,自增类型',
username varchar(50) unique not null comment'用户名',
password varchar(50) not null comment '密码'
);
# 查看表是否建立成功
select * from user;
# 建立博客表
use blog_db;
create table blog(
id bigint primary key auto_increment comment'id,自增类型',
title varchar(1024) not null comment'标题',
content text not null comment'内容',
createTime datetime not null comment'发布时间',
userId bigint not null comment'用户名'
);
select * from blog;
最终建表效果
由于不实现注册功能,所以这里我们给它初始化两个用户,方便后续直接进行登录。
use blog_db; insert into user values (null,'小花花','123456'); insert into user values (null,'小叶子','123456');
blog表中也初始化两条数据方便后续使用;
🌟二、大概框架与实现功能
在具体开始实现代码之前,我们首先要分析出做的这个Blog系统大概都有什么样的功能。我们将实现的功能总结如下:
(1)登录功能
(2)获取当前用户的登录信息
(3)获取当前所有的文章列表
(4)查看文章详情
(5)写博客
(6)退出登录
在实现代码的过程中,为了方便管理,我们将不同功能的代码放在不同的包下,主要分为五个包:
(1)Utils:存放各种工具类
(2)model:存放Java实体类,根据数据库中的表创建各种实体类
(3)dao:负责实体类与数据库之间的联系
(4)Servlet:后端代码的实现
(5)common:存放公共类,用于响应的时候以Json格式返回。
一般Utils,model提前写好,commom中随用随写,真正要写的代码:先写Dao中的,从数据库中查询内容——>写Servlet中的后端代码:从前端获取数据进行处理并返回响应,在这个过程中一般会用到Dao包中从数据库中获取到的内容——>写前端html中的代码:主要是从控件中获取内容用ajax发送数据给后端,并通过回调函数来处理后端的响应。(自己的一点点感悟~~有一点点写代码的感觉,但不多...哈哈哈)简单知道这些之后,接下来我们就可以愉快的写代码啦~~
🌟 三、代码实现部分
🌈前言1:工具类的实现(utils包下)
1、数据库连接的工具类
建立用户表和博客表之后,后续要进行数据库的连接等操作,所以在这里我们将数据库的部分功能进行封装,方便后续直接使用。
public class DBUtils {
//1、定义数据源
private static DataSource dataSource;
//定义三个属性
private static final String URL = "jdbc:mysql://localhost:3306/blog_db?characterEncoding=utf8&useSSL=false";
private static final String USER = "root";
private static final String PASSWORD = "123456";
//2、完成数据的初始化
static {
MysqlDataSource mysqlDataSource = new MysqlDataSource();
mysqlDataSource.setURL(URL);
mysqlDataSource.setUser(USER);
mysqlDataSource.setPassword(PASSWORD);
dataSource = mysqlDataSource;
}
//3、构造方法私有化
private DBUtils(){};
//4、构造一个连接
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
//5、依次关闭连接,释放资源
public static void close(PreparedStatement statement, Connection connection, 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 、 用户信息判空的工具类
用户信息的判空,封装成一个类:检验字符串是否为空。
public class StringUtils {
public static boolean isEmpty(String value){
if(value == null || value.equals("")){
//true表示为空
return true;
}
//不为空:返回false
return false;
}
}
3、判断当前用户是否已经登录的工具类
在完成登录之后,后续所有的子页面的各种操作都是在保证当前用户已经登录的情况下完成的,所以将用户是否登录封装为一个类。
public class UserUtils {
public static User checkUserLoginStatus(HttpServletRequest request){
//先判断req是否为空
if(request == null){
return null;
}
//否则获取session
HttpSession session = request.getSession(false);
//获取用户对象
User user = (User) session.getAttribute(AppConfig.USER_SESSION_KEY);
return user;
}
}
🌈前言2:java实体类的定义(model包下)
实体类的每个属性都和数据库表中的字段名一一对应。isAuthor属性后面会介绍到。
1、User实体类
public class User {
//三个属性和数据库表中的字段要对应
private Long id;
private String username;
@JsonIgnore//不参与json序列化
private String password;
private boolean isAuthor;
//无参构造
public User(){}
//提供相应的get和set方法
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
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;
}
public boolean isAuthor() {
return isAuthor;
}
public void setAuthor(boolean author) {
isAuthor = author;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
2、 Blog实体类
public class Blog {
private Long id;
private String title;
private String content;
private Timestamp createTime;//发布时间,类型 java.sql.Timestamp
private Long userId;//用户id
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
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 Timestamp getCreateTime() {
return createTime;
}
public void setCreateTime(Timestamp createTime) {
this.createTime = createTime;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
@Override
public String toString() {
return "Blog{" +
"id=" + id +
", title='" + title + '\'' +
", content='" + content + '\'' +
", createTime=" + createTime +
", userId=" + userId +
'}';
}
}
🌈前言3:AppResult类定义响应的返回格式json(Common包下)
第一点: 实现一个统一的数据返回格式,定义一个AppResult类来实现。
第二点:
/**
* 响应的时候以json的形式返回,这里定义一个共用的类
*/
public class AppResult<T> {
//用于描述状态码的属性
private int code;
//描述信息
private String message;
//返回数据:泛型当类里面传的是User,后面data里面存的就是User
private T data;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
//三个参数的构造方法
public AppResult(int code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}
//工厂方法
/**
* 普通的成功方法
* @return
*/
public static AppResult success(){
return new AppResult(0,"操作成功",null);
}
public static AppResult success(String message){
return new AppResult(1,message,null);
}
public static <T>AppResult success(T data){
return new AppResult(0,"操作成功",data);
}
public static <T>AppResult success(String message,T data){
return new AppResult(0,message,data);
}
/**
* 失败方法
* @return
*/
public static AppResult failed(){
return new AppResult(1000,"操作失败",null);
}
public static AppResult failed(String message){
return new AppResult(1000,message,null);
}
}
//定义全局的配置变量
public class AppConfig {
public static final String USER_SESSION_KEY = "USER_SESSION_KEY";
}
🌈1、实现登录功能
1.1 UserDao下:selectByUsername通过用户名查询对应用户
分析:在登录的时候,前端输入用户名和密码,此时我们需要从数据库中获取用户名,判断该用户名是否存在,因此提供一个通过用户名来查询用户信息的数据库访问方法,给定用户名,该用户名在数据库中存在的话,就返回该用户信息(包括id,用户名,密码);否则返回null。
提供一个selectByUsername的数据库访问方法:UserDao.java。
public class UserDao {
/**
* 根据用户名查询用户信息
* @param username 用户名
* @return 返回一个user对象
*/
public User selectByUsername(String username){
//1、判断username是否为空
if(StringUtils.isEmpty(username)){
return null;
}
//2、说明username有值,连接数据库,查询用户名为username的用户
//(1)进行数据库连接操作,定义数据库访问的相关对象
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
//(2)连接数据库
connection = DBUtils.getConnection();
//(3)定义sql语句
String sql = "select id,username,password from user where username = ?";
//(4)对sql进行预处理
statement = connection.prepareStatement(sql);
//(5)设置占位符的值
statement.setString(1,username);
//(6)执行sql,获取结果
resultSet = statement.executeQuery();
//(7)解析结果集,构造对象
if(resultSet.next()){
//创建一个User对象
User user = new User();
user.setId(resultSet.getLong(1));
user.setUsername(resultSet.getString(2));
user.setPassword(resultSet.getString(3));
//返回结果
return user;
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
//3、释放资源
DBUtils.close(statement,connection,resultSet);
}
//4、说明没有查询到结果,返回null
return null;
}
}
每次写完一个方法,就测试是否能通过:
1.2 Servlet实现后端
@WebServlet("/user")
public class UserServlet extends HttpServlet {
ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1、设置编码格式
req.setCharacterEncoding("UTF-8");
resp.setContentType("application/json;charset = utf-8");
//定义统一返回的数据类型
AppResult appResult;
//2、获取session对象
HttpSession session = req.getSession(false);
//3、判断session
//如果session为空,说明用户没有登录,是不能获取当前的用户信息的
// if(session == null || session.getAttribute(AppConfig.USER_SESSION_KEY) == null){
// //设置HTTP状态码:403表示没有权限访问,在前端的时候会调用到error方法
// resp.setStatus(403);
// //返回错误信息
// appResult = AppResult.failed("用户没有登录,请登录后再试!");
// resp.getWriter().write(objectMapper.writeValueAsString(appResult));
// //中断代码流程
// return;
// }
//3、也可以直接调用工具类的方法
if(UserUtils.checkUserLoginStatus(req) == null){
//设置HTTP状态码:403表示没有权限访问,在前端的时候会调用到error方法
resp.setStatus(403);
//返回错误信息
appResult = AppResult.failed("用户没有登录,请登录后再试!");
resp.getWriter().write(objectMapper.writeValueAsString(appResult));
//中断代码流程
return;
}
//4、校验成功,获取用户信息
User user = (User) session.getAttribute(AppConfig.USER_SESSION_KEY);
//5、设置返回结果中的对象,返回对象
appResult = AppResult.success(user);
resp.getWriter().write(objectMapper.writeValueAsString(appResult));
}
}
Postman测试后端 登录功能
每次写完一个接口,就用Postman测试一下。打开Postman,进行如下操作
情况1:用户名和密码为空
情况2:输入错误的密码
情况3:输入错误的用户名
情况4:输入正确的用户名和密码
OK~实现前端代码啦!
1.3 前端实现 blog_login.html
1、前后端交互协议
(1)请求:POST/login
Content-Type;application/x-www.form-urlencoded
username = test & password=123456
(2)响应: 返回json格式
{
"code":0
"message":"登录成功"
}
2、前端现在要做的事情:
(1)往后端login下发送POST请求;
(2)构造 username = test & password=123456形式的数据发送给后端;
(3)根据后端返回的响应做出操作:如果后端返回的是0,说明登录成功,跳转到博客列表页;如果失败,弹出message的错误信息。
3、实现前端:提交数据的方式有两种
(1)通过表单提交
(2)通过ajax提交
4、注意点:
error表示HTTP响应状态码返回的不是200的时候都会调用。
<!-- 引入jquery -->
<script src = "./js/jquery-3.6.3.min.js"></script>
<script>
// <!-- 在页面加载完成之后再执行jS,目的是保证元素已经初始化成功后再执行后续操作 -->
$(function(){
//4、为登录按钮绑定事件
$('#btn_login_submit').click(function(){
//1、获取控件输入的用户名和密码:id选择器
let usernameEl = $('#username');
if(!usernameEl.val()){
alert('用户名不能为空');
//让用户名输入框获得焦点
usernameEl.focus();
return;
}
//获取输入的密码并做校验
let passwordEl = $('#password');
if(!passwordEl.val()){
console.log(passwordEl.val());
alert('请输入密码');
passwordEl.focus();
return;
}
//2、构造要给后端发送的数据
let postData = {
username : usernameEl.val(),
password : passwordEl.val()
};
//3、发送ajax请求
$.ajax({
type:'post',
url: 'login',
contentType:'application/x-www-form-urlencoded',
data : postData,
//成功回调
success : function(respData){
if(respData.code == 0){
//登录成功,跳转到博客页面
location.assign('blog_list.html');
}else{
//登录失败
alert(respData.message);
}
},
//回调失败
error : function(){
console.log('访问出现问题');
}
});
});
})
</script>
</html>
🌈2、获取当前用户的登录信息
在第一步登录功能实现中,当用户登录成功之后,已经将用户的信息保存在了session中,所以直接从session中获取即可。
(1)用户发送请求到URL;
(2)服务器从session中取出用户信息;
(3)转化为Json字符串并返回。
2.1 Servlet实现后端
@WebServlet("/user")
public class UserServlet extends HttpServlet {
ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1、设置编码格式
req.setCharacterEncoding("UTF-8");
resp.setContentType("application/json;charset = utf-8");
//定义统一返回的数据类型
AppResult appResult;
//2、获取session对象
HttpSession session = req.getSession(false);
//3、判断session
//如果session为空,说明用户没有登录,是不能获取当前的用户信息的
if(session == null || session.getAttribute(AppConfig.USER_SESSION_KEY) == null){
//设置HTTP状态码:403表示没有权限访问,在前端的时候会调用到error方法
resp.setStatus(403);
//返回错误信息
appResult = AppResult.failed("用户没有登录,请登录后再试!");
resp.getWriter().write(objectMapper.writeValueAsString(appResult));
//中断代码流程
return;
}
//4、校验成功,获取用户信息
User user = (User) session.getAttribute(AppConfig.USER_SESSION_KEY);
//5、设置返回结果中的对象,返回对象
appResult = AppResult.success(user);
resp.getWriter().write(objectMapper.writeValueAsString(appResult));
}
}
1、代码关键点1
Postman测试后端
在Postman中线执行登录流程再获取用户信息。
但是通过上面的结果我们可以看到,关于用户的隐私字段不应该在网上显示出来,所以在Json序列化的时候就应该排除这个字段。
序列化:将java对象转化为可以在网络上传输的数据类型,便于在网络上传输,比如字符串,byte数组等等(java->json,java->xml);反序列化:就是将字符串,byte数组,json格式等还原为java对象(json->java,xml->java)。
再次测试:
2.2 前端代码实现:blog_list.html
步骤:
(1)给h3标签(用户名标签)设置id选择器名;
(2)引入Js依赖
(3)页面加载之后就发送ajax请求
(4)在回调函数中处理响应
statusCode是一个对象,每个状态码表示一个属性,属性的类型是一个function。
部分关键代码实现如下:
<script src = "js/jquery-3.6.3.min.js"></script>
<script>
// 目标:只要博客页面一启动,就发送ajax请求给后端,同时回调函数获取响应的用户信息,设置到前端的控件上
//实现功能2:用户控件上显示用户信息
$(function(){
//1、发送ajax请求获取响应数据
$.ajax({
type:'get',
url:'user',
//回调函数
//HTTP状态码返回为200的时候调用
success : function(respData){
if(respData.code == 0){
//成功
//获取从后端返回的User信息
let user = respData.data;
//给前端的控件上设置该用户信息
$('#h_list_username').html(user.username);
}else{
//失败
}
},
//HTTP返回状态码不是200的时候都会调用error
error : function(){
},
//403状态可以调用error,但是有一个更加具体的方法statusCode,专门为不同的HTTP状态码定义不同的方法
statusCode : {
403:function(){
//打印日志并跳转到登录界面
console.log('用户无权访问,强制跳转到登录界面');
location.assign('blog_login.html');
}
}
});
</script>
🌈3、获取当前所有的文章列表
约定前后端交互接口:
根据以上响应的格式,在DAO中的sql,应该是从数据库的blog中查询所有,查询出来的是一个集合,集合的每个对象都是一条博客记录,包括id,标题,内容,发布时间,用户id。
3.1 BlogDao:selectAll在数据库中查询所有的博客记录
public class BlogDao {
/**
* 获取所有的文章列表
* @return
*/
public List<Blog> selectAll(){
//1、定义数据库访问的相关对象
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
//2、建立数据库连接
try {
connection = DBUtils.getConnection();
//3、定义sql语句:按发布时间排序
String sql = "select id,title,content,createTime,userId " +
"from blog order by createTime desc";
//4、处理sql
statement = connection.prepareStatement(sql);
//5、执行sql语句,获取结果集
resultSet = statement.executeQuery();
//6、遍历结果集
List<Blog> blogList = null;
while (resultSet.next()){
//为空的时候初始化一个集合
if(blogList == null){
blogList = new ArrayList<Blog>();
}
//集合中的每个元素都是一个blog对象
Blog blog = new Blog();
blog.setId(resultSet.getLong(1));
blog.setTitle(resultSet.getString(2));
blog.setContent(resultSet.getString(3));
//判断一下内容长度,如果内容长度大于20,就显示前20个字,否则显示所有
if(blog.getContent().length()>=20){
blog.setContent(blog.getContent().substring(0,20)+"...");
}
blog.setCreateTime(resultSet.getTimestamp(4));
blog.setUserId(resultSet.getLong(5));
//把blog对象加入集合中
blogList.add(blog);
}
//返回结果
return blogList;
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtils.close(statement,connection,resultSet);
}
return null;
}
}
写完之后用测试类测试:
3.2 Servlet实现后端
注意:要实现博客表中所有信息的获取,前提是要保证用户已经登录。
@WebServlet("/blog")
public class BlogServlet extends HttpServlet {
//用户数据库访问的Dao
private BlogDao blogDao = new BlogDao();
//用于转换Json
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1、设置编码格式
req.setCharacterEncoding("UTF-8");
resp.setContentType("application/json;charset=utf-8");
//2、前提:要获取所有的博客的前提是:要保证用户已经登录
//校验用户的登录状态
if(UserUtils.checkUserLoginStatus(req) == null){
//设置HTTP状态码:403表示没有权限访问,在前端的时候会调用到error方法
resp.setStatus(403);
//返回错误信息
resp.getWriter().write(objectMapper.writeValueAsString(AppResult.failed("用户没有登录,请登录后再试!")));
//中断代码流程
return;
}
//3、获取所有的博客(是个集合)并返回
List<Blog> blogs = blogDao.selectAll();
//在这里处理一下:如果集合为空的话,就返回一个空集合[],而不是null的形式
if(blogs == null){
blogs = new ArrayList<Blog>();
}
//正常返回给前端
resp.getWriter().write(objectMapper.writeValueAsString(AppResult.success(blogs)));
}
}
Postman测试后端代码
进行登录之后,再次测试;
3.3 前端实现:blog_list.html
注意,在获取时间的时候,要对时间格式进行处理,用一个写好的函数formatDate。
(1)引入js文件
// common.js文件内容 function formatDate(time) { var date = new Date(time); var year = date.getFullYear(), month = date.getMonth() + 1,//月份是从0开始的 day = date.getDate(), hour = date.getHours(), min = date.getMinutes(), sec = date.getSeconds(); var newTime = year + '-' + (month < 10 ? '0' + month : month) + '-' + (day < 10 ? '0' + day : day) + ' ' + (hour < 10 ? '0' + hour : hour) + ':' + (min < 10 ? '0' + min : min) + ':' + (sec < 10 ? '0' + sec : sec); return newTime; }
(2)调用函数
处理之前
处理之后
//实现功能3:页面一加载就进行博客列表的获取
$.ajax({
type:'get',
url:'blog',
//回调方法
success:function(respData){
//根据自定义的状态码处理
if(respData.code == 0){
//成功,构造文章列表:构造一个函数
buildArticlelList(respData.data);
}else{
//失败
alert(respData.message);
}
},
error:function(respData){
console.log("访问出现错误");
},
statusCode:{
403:function(){
//未登录状态:强制让用户跳转到登录界面
location.assign('blog_login.html');
}
}
});
// 构建文章列表:data是一个集合
function buildArticlelList(data){
//如果集合为空
if(data.length == 0 || data == null){
//当文章列表为空时
let htmlString = '<h3>没有文章,快发布一篇吧!</h3>'
$('#container-right').html(htmlString);
return;
}
//说明文章列表不为空:遍历集合方式1:
for(let i=0;i<data.length;i++){
let blogItem = data[i];
// 对对应的控件进行相应的赋值
let htmlString = ' <div class="blog-content">'
+ ' <div class="blog-title">'
+ blogItem.title
+ ' </div>'
+ ' <div class="blog-datetime">'
+ formatDate(blogItem.createTime)
+ ' </div>'
+ ' <div class="content">'
+ blogItem.content
+ ' </div>'
+ ' <div class="aEl">'
+ ' <a href="./blog_details.html?blog_Id='+blogItem.id+'">+查看全文 >> </a>'
+ ' </div>'
+ ' <hr>'
+ ' </div>';
// console.log(htmlString);
//这里用append,表示追加元素 .html()表示只添加一条数据
$('.container-right').append(htmlString);
}
//遍历集合方式2:data是要遍历的数组或集合
// data.forEach(element=>{
// //element相当于data[i]
// })
}
🌈4、查看全文功能
实现功能:点击“查看全文”按钮会调转到新的blog_details.html页面。这里需要明确当前要查看的是哪一个文章,此时就要从数据库中查询出文章id作为参数传入,在前端对应代码如下:
此时在博客子页面,显示的界面如下:
界面1:右侧显示这篇博客的具体内容——>需要根据文章Id查询文章详情——>在BlogDao中实现一个Blog selectById(Long Id)方法;
界面2:左侧实现这篇博客的作者——>需要根据用户Id查询用户信息——>在UserDao中实现一个User selectById(Long Id)方法。
界面1实现 :显示这篇博客的具体内容
4.1 UserDao下 :User selectById(Long id)通过Id获取对应用户信息
/**
* 根据用户Id查询用户信息
* @param id 用户信息
* @return 对应的用户记录
*/
public User selectById(Long id){
//判断id是否为空
if(id == null || id <=0){
return null;
}
//连接数据库获取查询数据
//(1)初始化数据库对象
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
//(2)获取数据库连接
try {
connection = DBUtils.getConnection();
//(3)定义sql
String sql = "select id,username,password from user where id = ?";
//(4)预处理sql
statement = connection.prepareStatement(sql);
//(5)设置占位符
statement.setLong(1,id);
//(6)获取结果集
resultSet = statement.executeQuery();
//(7)获取结果集
if(resultSet.next()){
//(8)封装对象:创建一个用户对象并设置参数
User user = new User();
user.setId(resultSet.getLong(1));
user.setUsername(resultSet.getString(2));
user.setPassword(resultSet.getString(3));
//(9)返回结果
return user;
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtils.close(statement,connection,resultSet);
}
return null;
}
测试代码
4.2 BolgDao下:Blog selectById(Long Id)通过Id查询对应博客
/**
* 根据博客Id查询对应的博客信息
* @param id 博客Id
* @return 一条博客记录
*/
public Blog selectById(Long id){
//非空校验
if(id == null || id <= 0){
return null;
}
//数据库操作
//(1)定义数据库对象
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
//(2)获取数据库连接
try {
connection = DBUtils.getConnection();
//(3)定义sql语句
String sql = "select id,title,content,createTime,userId from blog where id =?";
//(4)预处理sql
statement = connection.prepareStatement(sql);
//(5)设置占位符
statement.setLong(1,id);
//(6)执行sql
resultSet = statement.executeQuery();
//(7)获取结果集
if(resultSet.next()){
//封装Blog对象
Blog blog = new Blog();
blog.setId(resultSet.getLong(1));
blog.setTitle(resultSet.getString(2));
blog.setContent(resultSet.getString(3));
blog.setCreateTime(resultSet.getTimestamp(4));
blog.setUserId(resultSet.getLong(5));
//(8)返回结果
return blog;
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtils.close(statement,connection,resultSet);
}
return null;
}
测试
4.3 Servlet实现后端
之前我们在实现“获取所有的博客列表”时,BlogServlet中写了一个doGet方法是直接获取所有的博客记录。所以现在我们的目标是,传入id,返回一个blog记录,也是一个doGet方法。所以我们现在有两种方法,重新实现一个新的Servlet的doGet方法,接收blogId参数,返回对应的博客内容,还有一种是在我们现有的BlogServlet代码中,判断有没有传进来参数blogId,如果有的话,就执行新的方法,返回对应的博客记录;否则就执行之前的selectAll方法,查询出所有的博客列表信息。在这里我们采用后面这种方式实现。
更新后的BlogServlet代码
@WebServlet("/blog")
public class BlogServlet extends HttpServlet {
//用户数据库访问的Dao
private BlogDao blogDao = new BlogDao();
//用于转换Json
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1、设置编码格式
req.setCharacterEncoding("UTF-8");
resp.setContentType("application/json;charset=utf-8");
//2、前提:要获取所有的博客的前提是:要保证用户已经登录
//校验用户的登录状态
if(UserUtils.checkUserLoginStatus(req) == null){
//设置HTTP状态码:403表示没有权限访问,在前端的时候会调用到error方法
resp.setStatus(403);
//返回错误信息
resp.getWriter().write(objectMapper.writeValueAsString(AppResult.failed("用户没有登录,请登录后再试!")));
//中断代码流程
return;
}
//-------------功能4实现:在原先基础上实现:如果传入blogId参数,就返回对应的博客信息,否则返回所有的博客列表信息
//获取blogId参数
String blogId = req.getParameter("blog_Id");
//定义返回的Json变量
String jsonStr = null;
//判断参数是否为空:如果是空的话,就查询所有的博客列表
if(StringUtils.isEmpty(blogId)){
//3、获取所有的博客(是个集合)并返回
List<Blog> blogs = blogDao.selectAll();
//在这里处理一下:如果集合为空的话,就返回一个空集合[],而不是null的形式
if(blogs == null){
blogs = new ArrayList<Blog>();
}
//序列化
jsonStr = objectMapper.writeValueAsString(AppResult.success(blogs));
}else{
//否则根据传入的blogId查询对应的博客信息
Blog blog = blogDao.selectById(Long.valueOf(blogId));
//序列化成字符串
jsonStr = objectMapper.writeValueAsString(AppResult.success(blog));
}
//正常返回给前端
resp.getWriter().write(jsonStr);
}
}
问题:
怎么从前端将blogId的参数传递给后端?注意代码中的blog_Id在前后端之间的联系,是怎么将其传递给后端的。 就像我们在网址栏输入地址后会出现一个参数。
方法:
在postman中测试:在url后面直接拼接?blog_Id=5的参数,可以成功查询。(可以查询成功的是blog_Id是5和4,其他的都不能成功)
上述总结:前端可以通过JS中的location对象获取浏览器地址栏中query string中的参数列表。
接下来在前端实现代码。
4.4 前端实现:blog_details.html
<!--引入Jquery-->
<script src = 'js/jquery-3.6.3.min.js'></script>
<script src = 'js/common.js'></script>
<!-- 再引入编辑器插件 -->
<script src="./editor.md/editormd.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>
<script>
$(function(){
//动态为标签赋值
//获取当前博客的详细信息
$.ajax({
type:'get',
url:'blog' + location.search,//这里的blog对应servlet中的相对应@WebServlet后的"/blog"
//回调函数
success : function(respData){
if(respData.code == 0){
//成功,为页面中的相应标签赋值
//查询
let blog = respData.data;
//赋值
$('#div_datails_title').html(blog.title);
$('#div_datails_createTime').html(formatDate(blog.createTime));
// $('#div_datails_content').html(blog.content);
// 在这里对内容做markdown格式处理
editormd.markdownToHTML('div_datails_content',{markdown:blog.content})
}else{
//错误
alert(respData.message);
}
},
error : function(){
//打印日志
console.log('访问出现错误');
},
statusCode : {
403 : function(){
//强制跳转到登录界面
location.assign('blog_login.html')
}
}
})
})
</script>
注意点
界面2实现 :显示用户信息
4.1 Servlet实现后端
注意这里的用户信息不能从sessio获取,session中获取的是当前登录的用户信息,是唯一且固定的,但是现在显示的是每个博客的作者,也就是博客是谁写的。因为我们一开始在数据库设计的时候,blog表中的useId其实就是对应user表中的id,因此可以查询出当前的用户名,显示在前端控件上。所以这里的用户信息是从数据库中获取的。
所以在表中设立关联字段的目的就是为了与其他表建立联系。
做法:和上面的BlogServlet的实现过程相同,可以通过新实现一个Servlet,也可以修改现有的UserServlet,判断是否有参数传入来执行不同的接口。
更新后的UserServlet代码
@WebServlet("/user")
public class UserServlet extends HttpServlet {
ObjectMapper objectMapper = new ObjectMapper();
private UserDao userDao = new UserDao();
private BlogDao blogDao = new BlogDao();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1、设置编码格式
req.setCharacterEncoding("UTF-8");
resp.setContentType("application/json;charset = utf-8");
//定义统一返回的数据类型
AppResult appResult;
//2、获取session对象
HttpSession session = req.getSession(false);
//3、判断session
//如果session为空,说明用户没有登录,是不能获取当前的用户信息的
// if(session == null || session.getAttribute(AppConfig.USER_SESSION_KEY) == null){
// //设置HTTP状态码:403表示没有权限访问,在前端的时候会调用到error方法
// resp.setStatus(403);
// //返回错误信息
// appResult = AppResult.failed("用户没有登录,请登录后再试!");
// resp.getWriter().write(objectMapper.writeValueAsString(appResult));
// //中断代码流程
// return;
// }
//3、也可以直接调用工具类的方法
if(UserUtils.checkUserLoginStatus(req) == null){
//设置HTTP状态码:403表示没有权限访问,在前端的时候会调用到error方法
resp.setStatus(403);
//返回错误信息
appResult = AppResult.failed("用户没有登录,请登录后再试!");
resp.getWriter().write(objectMapper.writeValueAsString(appResult));
//中断代码流程
return;
}
//-----功能4实现:子页面对应显示用户信息:根据是否传入参数来判断执行哪个方法
String blogId = req.getParameter("blog_Id");
//定义返回的json格式
String jsonStr = null;
//(1)如果当前没有传入参数
if(StringUtils.isEmpty(blogId)){
//校验成功,获取用户信息
User user = (User) session.getAttribute(AppConfig.USER_SESSION_KEY);
//设置返回结果中的对象,返回对象
jsonStr = objectMapper.writeValueAsString(AppResult.success(user));
} else{
//(2)说明当前传入了参数
//先查询博客信息
Blog blog = blogDao.selectById(Long.valueOf(blogId));
//查询到的博客为空
if(blog == null){
jsonStr = objectMapper.writeValueAsString(AppResult.failed("没有找到对应的博客"));
resp.getWriter().write(jsonStr);
return;
}
//说明查到了博客信息,则根据博客表中的userId查询用户
User user = userDao.selectById(blog.getUserId());
//判断user是否为空
if(user == null){
jsonStr = objectMapper.writeValueAsString(AppResult.failed("没有找到对应的用户"));
resp.getWriter().write(jsonStr);
return;
}
//返回用户作者
jsonStr = objectMapper.writeValueAsString(AppResult.success(user));
}
resp.getWriter().write(jsonStr);
}
}
postman测试
情况1:给定一个存在的博客记录
情况2:给定一条不存在的博客记录
4.2 前端实现 blog_details.html
控件赋值的时候要与标签对应。
//获取作者信息
$.ajax({
type:'get',
url:'user'+location.search,
//回调函数
success : function(respData){
//成功
if(respData.code == 0){
let user = respData.data;
//为控件赋值
$('#h_details_username').html(user.username);
}else{
alert(respData.message);
}
},
error: function(){
//打印日志
console.log('访问出现问题');
},
statusCode :{
403 : function(){
//强制跳转到登录界面
location.assign(blog_login.html);
}
}
});
})
前端:
博客列表页面下:blog_list.html中与后端BlogServlet中的blog_Id要对应。
🌈 5、发布博客
(1)dao包下:在blogDao中实现:sql要做的事情,将新写入的内容用Insert(Blog blog)语句插入到数据库中;
(2)Servlet中对提交的参数做非空校验,并且从sessio中获取用户信息(作者)->博客作者就是当前系统中的登录用户;
(3)前端发送post请求,将用户在页面上输入的数据提交到服务器;成功之后,前端跳转到list界面,展示相应的blog页面。
5.1 blogDao下:insert(Blog blog)写入博客到数据库
/**
* 发布一篇新的博客
* @param blog Blog对象
* @return 受影响的行数
*/
public int insert(Blog blog){
//1、非空校验
if(blog == null || StringUtils.isEmpty(blog.getTitle())
|| StringUtils.isEmpty(blog.getContent())
|| blog.getUserId() == null
|| blog.getCreateTime() == null){
return 0;
}
//数据库操作
//(1)定义操作数据库过程中的变量
Connection connection = null;
PreparedStatement statement = null;
//(2)创建数据库连接
try {
connection = DBUtils.getConnection();
//(3)定义SQL语句
String sql = "insert into blog values (null,?,?,?,?);";
//(4)预处理sql
statement = connection.prepareStatement(sql);
//(5)设置占位符的值
statement.setString(1,blog.getTitle());
statement.setString(2,blog.getContent());
statement.setTimestamp(3,blog.getCreateTime());
statement.setLong(4,blog.getUserId());
//(6)执行sql
int row = statement.executeUpdate();
//返回结果
return row;
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtils.close(statement,connection,null);
}
return 0;
}
测试:
在数据库中查询:发现数据写入成功。
5.2 Servlet实现后端
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置编码集
req.setCharacterEncoding("UTF-8");
resp.setContentType("application/json;charset=utf-8");
//获取当前用户的登录信息:从session中获取
User user = UserUtils.checkUserLoginStatus(req);
//登录用户的校验:没有登录的用户是不能写博客的
if(user == null){
//设置HTTP状态码,用于前端处理不同的响应方法
resp.setStatus(403);
//返回错误信息
String jsonStr = objectMapper.writeValueAsString(AppResult.failed("无权访问,请先登录!"));
resp.getWriter().write(jsonStr);
return;
}
//说明用户已经登录
//(1)接收用户提供的参数
String title = req.getParameter("title");
String content = req.getParameter("content");
if(StringUtils.isEmpty(title) || StringUtils.isEmpty(content)){
String jsonStr = objectMapper.writeValueAsString(AppResult.failed("标题或者正文不能为空"));
resp.getWriter().write(jsonStr);
}
//(2)创建blog对象,传入blogDao中的insert方法
Blog blog = new Blog();
blog.setTitle(title);
blog.setContent(content);
blog.setCreateTime(new Timestamp(System.currentTimeMillis()));
//当前登录用户是谁,写博客的作者就是谁
blog.setUserId(user.getId());
//(3)调用数据库
int row = blogDao.insert(blog);
//(4)判断行数
if(row <= 0){
//返回错误信息
String jsonStr = objectMapper.writeValueAsString(AppResult.failed("保存文章失败,请联系管理员!"));
resp.getWriter().write(jsonStr);
return;
}
//(5)返回成功信息
resp.getWriter().write(objectMapper.writeValueAsString(AppResult.success("文章发布成功")));
}
postman测试后端
情况1:标题和内容都正常输入
在数据库查询:发现数据插入成功:
情况2:当标题和内容为空的时候
5.3 前端实现 blog_eidt.html
介绍:前端要集成一个编辑器插件:
(1)引入编辑器样式
(2)引入Jquery
(3)引入编辑器插件
(4)初始化编辑器
(5)现在我们要在前端输入参数,并获取参数的值。比如 要输入title,我们可以通过input标签获取输入的值;但是现在对于"内容”,在div标签里面生成的值是在editor编辑器里面。所以这里需要进行一点改动,设置隐藏域。
要与获取的控件Id名对应。
要处理的小细节:
(1)markdown格式问题
上面说这个编辑器是支持markdown格式的,现在我们输入文字并提交;
返回博客列表页面并查看详情,发现并没有显示markdown格式,因此我们要对这个问题做一下处理。
在blog_details.html文件下也要引入插件,并对内容做markdown格式处理。(具体代码见4.4节)这样就可以用markdown格式显示内容了。
现在再打开查看详情界面,显示正常。
(2)文字长度问题
解决办法:blogDao下的selectAll方法,增加一个判断条件。(完整代码见3.1节)
// blog_eidt.html文件下
// 绑定按钮的点击事件
$('#submit').click(function(){
// alert(123); 测试按钮是否绑定成功
//(1)获取用户输入并提交数据
let titleEl = $('#title');
let contentEl = $('#text_edit_content');
// 判断输入的标题和内容是否为空
if(!titleEl.val()){
alert('请输入文章标题');
return;
}
if(!contentEl.val()){
alert('请输入内容');
return;
}
//(2)构造发送的数据
let postData = {
title : titleEl.val(),
content : contentEl.val()
}
//(3)提交请求
$.ajax({
type : 'post',
url : 'blog',
contentType :'application/x-www-form-urlencoded',
data : postData,
//回调函数
success : function(respData){
//发送成功,则跳转到blog_list.html页面
if(respData.code == 0){
location.assign('blog_list.html');
}else{
alert(respData.message);
}
},
error : function(){
console.log('访问出现错误!');
},
statusCode : {
403 : function(){
//未登录,没有权限访问。强制跳转到登录界面
location.assign('blog_login.html');
}
}
})
})
🌈6、删除当前文章
删除文章:只能当前用户自己删自己的:
(1)登录人(从session中获取use对象,获取该对象的id)和博客作者(根据传入的blogId)要相同:后端UserServlet实现,返回Booean类型给前端;
(2)前端User类设置一个isAuthor属性,根据根据author是否为True来初始化一个删除按钮并绑定事件;
(3)Dao下:sql的delete方法;
6.1 BlogDao下:deleteById(Long id)通过Id删除博客
/**
* 删除博客
* @param id 传入要删除的博客id
* @return 返回受影响的行数
*/
public int deleteById(Long id){
//非空校验
if(id == null || id == 0){
return 0;
}
//(1)定义sql的对象
Connection connection = null;
PreparedStatement statement = null;
//(2)定义数据库连接
try {
connection = DBUtils.getConnection();
//(3)定义sql语句
String sql = "delete from blog where id = ?";
//(4)预处理sql
statement = connection.prepareStatement(sql);
//(5)设置占位符
statement.setLong(1,id);
//(6)执行sql
int row = statement.executeUpdate();
//(7)返回结果
return row;
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtils.close(statement,connection,null);
}
return 0;
}
6.2 Servlet实现后端
(1)更新后的UserServlet
主要在之前的基础上:加了下面的代码
@WebServlet("/user")
public class UserServlet extends HttpServlet {
ObjectMapper objectMapper = new ObjectMapper();
private UserDao userDao = new UserDao();
private BlogDao blogDao = new BlogDao();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1、设置编码格式
req.setCharacterEncoding("UTF-8");
resp.setContentType("application/json;charset = utf-8");
//定义统一返回的数据类型
AppResult appResult;
//2、获取session对象
HttpSession session = req.getSession(false);
//3、判断session
//如果session为空,说明用户没有登录,是不能获取当前的用户信息的
// if(session == null || session.getAttribute(AppConfig.USER_SESSION_KEY) == null){
// //设置HTTP状态码:403表示没有权限访问,在前端的时候会调用到error方法
// resp.setStatus(403);
// //返回错误信息
// appResult = AppResult.failed("用户没有登录,请登录后再试!");
// resp.getWriter().write(objectMapper.writeValueAsString(appResult));
// //中断代码流程
// return;
// }
//3、也可以直接调用工具类的方法
if(UserUtils.checkUserLoginStatus(req) == null){
//设置HTTP状态码:403表示没有权限访问,在前端的时候会调用到error方法
resp.setStatus(403);
//返回错误信息
appResult = AppResult.failed("用户没有登录,请登录后再试!");
resp.getWriter().write(objectMapper.writeValueAsString(appResult));
//中断代码流程
return;
}
//-----功能4实现:子页面对应显示用户信息:根据是否传入参数来判断执行哪个方法
String blogId = req.getParameter("blog_Id");
//定义返回的json格式
String jsonStr = null;
//(1)如果当前没有传入参数
if(StringUtils.isEmpty(blogId)){
//校验成功,获取用户信息
User user = (User) session.getAttribute(AppConfig.USER_SESSION_KEY);
//设置返回结果中的对象,返回对象
jsonStr = objectMapper.writeValueAsString(AppResult.success(user));
} else{
//(2)说明当前传入了参数
//先查询博客信息
Blog blog = blogDao.selectById(Long.valueOf(blogId));
//查询到的博客为空
if(blog == null){
jsonStr = objectMapper.writeValueAsString(AppResult.failed("没有找到对应的博客"));
resp.getWriter().write(jsonStr);
return;
}
//说明查到了博客信息,则根据博客表中的userId查询用户
User user = userDao.selectById(blog.getUserId());
//判断user是否为空
if(user == null){
jsonStr = objectMapper.writeValueAsString(AppResult.failed("没有找到对应的用户"));
resp.getWriter().write(jsonStr);
return;
}
//判断当前登录的用户是不是文章作者
User currentUser = (User) session.getAttribute(AppConfig.USER_SESSION_KEY);
if(currentUser.getId() == blog.getUserId()){
//表示当前登录用户就是作者,设置user的isAuthor为True
user.setAuthor(true);
}
//返回用户作者
jsonStr = objectMapper.writeValueAsString(AppResult.success(user));
}
resp.getWriter().write(jsonStr);
}
}
postman测试:使用用户名为“小花花”登录,其中blog_id=4是小花花写的博客,blog_id=5是另一个作者写的博客。
情况1:登录是小花花,博客作者也是小花花,说明是作者;
情况2:登录作者是小花花,博客作者是小叶子,不是同一个 作者,返回false。
(2)blogServlet中实现doDelete方法
@Override
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//(1)设置编码格式
req.setCharacterEncoding("UTF-8");
resp.setContentType("application/json;charset = utf-8");
//(2)获取前端控件参数
String blogId = req.getParameter("blog_Id");
//非空校验
if(StringUtils.isEmpty(blogId)){
resp.getWriter().write(objectMapper.writeValueAsString(AppResult.failed("没有找到文章编号!")));
}
//(3)获取当前登录的用户,session中获取
User user = UserUtils.checkUserLoginStatus(req);
//表明用户没有登录
if(user == null){
String jsonStr = objectMapper.writeValueAsString(AppResult.failed("当前用户没有登录,请登录后再试!"));
resp.getWriter().write(jsonStr);
//设置HTTP状态码
resp.setStatus(403);
//中断代码流程
return;
}
//(4)判断当前登录的用户与博客作者是否相同:通过登录用户的用户Id与写博客的用户Id做比较
//首先获取博客对象
Blog blog = blogDao.selectById(Long.valueOf(blogId));
//判断博客是否存在
if(blog == null){
resp.getWriter().write(objectMapper.writeValueAsString(AppResult.failed("文章不存在")));
}
//判断是否同一个作者
if(user.getId() != blog.getUserId()){
resp.getWriter().write(objectMapper.writeValueAsString(AppResult.failed("无权删除别人的文章!")));
return;
}
//(5)否则调用Dao进行删除操作
int row = blogDao.deleteById(Long.valueOf(blogId));
//(6)判断结果
if(row != 1){
resp.getWriter().write(objectMapper.writeValueAsString(AppResult.failed("删除失败")));
return;
}
//说明删除成功
resp.getWriter().write(objectMapper.writeValueAsString(AppResult.success("删除成功")));
}
postman测试:
(1)情况1:无权删除文章
(2)登录用户和博客作者是同一个人,可以删除;
去数据库查看,对应的文章也已经删除成功。
6.3 前端实现:blog_details.html
根据后端传回来的结果是否成功(成功说明可以删除文章),初始化一个删除按钮并绑定事件 。
对应前端代码增加如下:deleteBlog是一个删除方法,封装好之后调用。
在点击详情之后,都会初始化一个删除按钮,但是只有右权限删除的时候,删除按钮才起作用,否则会给出提示无权删除。不论是不是
重点代码如下:
//获取作者信息
$.ajax({
type:'get',
url:'user'+location.search,
//回调函数
success : function(respData){
//成功
if(respData.code == 0){
let user = respData.data;
//为控件赋值
$('#h_details_username').html(user.username);
//生成删除按钮
let htmlStr = '<a href="javascript:void(0);">删除</a>'
//javascript:void(0)表示点击按钮什么事情都不干
//将html转为jquery对象并追加到页面上
let deleteEl = $(htmlStr);
//得到这个按钮的父标签
$('.opts').append(deleteEl);
//绑定事件
deleteEl.click(deleteBlog);
}else{
alert(respData.message);
}
},
error: function(){
//打印日志
console.log('访问出现问题');
},
statusCode :{
403 : function(){
//强制跳转到登录界面
location.assign(blog_login.html);
}
}
});
//删除文章事件
function deleteBlog(){
//如果是否定,则直接删除
if(!confirm("是否删除?")){
return;
};
//否则向后端发送请求,删除文章
$.ajax({
type : 'delete',
url : 'blog' + location.search,
//回调函数
success : function(respData){
//成功
if(respData.code == 0){
//成功,则跳转到详情页
location.assign('blog_list.html');
}else{
alert(respData.message);
}
},
error: function(){
//打印日志
console.log('访问出现问题');
},
statusCode :{
403 : function(){
//强制跳转到登录界面
location.assign(blog_login.html);
}
}
});
🌈7、注销功能
作用:在服务器把用户对应的session销毁。
(1)LogOutServlet:获取session;销毁:session.invalitate();
(2)前端退出按钮a_list_logout:绑定事件。
7.1 Servlet实现后端
@WebServlet("/logout")
public class LogOutServlet extends HttpServlet {
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("application/json;charset = utf-8");
//获取session
HttpSession session = req.getSession();
//判断session是否有效
if(session!=null){
//销毁session
session.invalidate();
}
resp.getWriter().write(objectMapper.writeValueAsString(AppResult.success("注销成功")));
}
}
postman测试
7.2 前端实现 blog_list.html
目前只在这个页面实现bblog_list.htmllog_list.html。
// 功能7:为注销按钮绑定事件
$('#a_list_logout').click(function(){
//发送ajax请求
$.ajax({
type: 'type',
url : 'logout',
success : function(respData){
//成功
if(respData.code == 0){
//跳转到登录页面
location.assign('nlog_login.html');
}else{
//失败
alert(respData.message);
}
},
error : function(){
console.log('访问出现问题');
}
})
})
第一次做完这个项目,在知识上,主要有以下体会:
- 一般都和数据库有关联,第一步是分析需求,建表;
- 创建这个项目主要分为几个包:utils下存放工具类,model中存放各种实体类(这个类的属性和数据库中表的字段一一对应),dao包下实现类与数据库之间的交互,一般是进行数据库的增删改查获取结果供servlet包使用;common包中定义定义全局的配置变量,比如sessionId;还有响应时候的数据格式:以json的形式返回,定义为一个共用的类;servlet包下负责从前端获取请求,主要有获取控件的参数,对参数进行校验,然后对前端发送的请求进行相应的处理,一般会调用dao的结果,然后再将响应结果返回给前端;前端一般通过给控件设置选择器(id选择器,类选择器,或者button按钮绑定事件),然后获取控件输入的值封装成数据,对参数进行校验,发送ajax 请求给后端(主要是type,url,data,content-type)然后通过会回调函数获取后端结果做处理。
- 在前后端交互的过程中,要约定好参数的解析方式。
行文至此,历时一周,终于完成了这个简单的博客系统项目。虽然做的功能比较简单且单薄,而且掌握的不够充分,但是对于自己来说确实学习到了很多东西。感觉有一种“哦~原来是这样的”恍然大悟,或者说某个时刻的豁然开朗。虽然掌握的内容不多,写的也不是很全面,但是是对自己所学东西的一个记录吧~希望之后回过头来再看,能有更多的启发和思考。