IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 博客系统——前后端分离 -> 正文阅读

[Java知识库]博客系统——前后端分离


引言:

tomcat版本:8.5
开发工具:IDEA
jdk版本:jdk1.8.0_161
此项目是对本博主之前编写的一个纯HTML页面的博客系统进行的一个改进

准备工作

1.创建maven项目

依次点击File→New→Project,选择左侧的Maven项目,点击Next,然后填写项目名称,点击Finish,至此一个maven项目就创建好了。

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

去中央仓库搜索下载即可,👉地址传送门(一般搜索关键字后第一个就是我们所需要的,注意版本)

<dependencies>//这个需要手动敲上去
    <!-- 加入 servlet 依赖 -->
    <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <!-- servlet 版本和 tomcat 版本有对应关系,切记 -->
        <version>3.1.0</version>
        <!-- 这个意思是我们只在开发阶段需要这个依赖,部署到 tomcat 上时就不需要了 -->
        <scope>provided</scope>
    </dependency>
    <!--引入mysql驱动包-->
    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</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.12.6.1</version>
    </dependency>
</dependencies>

引入依赖后记得手动刷新一下,以防万一。(第一次引入的时候时间可能会长一些,要耐心等待,有的时候可能因为网络问题导致引入失败,这时候不要慌,多刷新几次试试)
在这里插入图片描述
在这里插入图片描述

3.创建必要的目录

在这里插入图片描述
web.xml新建的时候选择File选项
在这里插入图片描述
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. 编写代码

在这里插入图片描述

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

如何下载tomcat

tomcat直接在官网下载即可:👉官网下载
在这里插入图片描述
下载完解压即可,解压的时候最好不要解压到带中文的文件夹里。

如何下载smart Tomcat

在这里插入图片描述
然后就按照下面的步骤进行部署??????
在这里插入图片描述

7. 在浏览器中验证

点击上方小绿三角运行,然后在浏览器中输入:http://localhost(也可以是127.0.0.1):8080/blog_system/hello
在这里插入图片描述
到这里准备工作算是做完了,接下来就可以执行接下来的步骤了??😊

编写数据库的操作代码

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

设计数据库,需要根据当前的需求来进行设计,而我们这个博客页面,一共需要以下几个页面:

  1. 博客列表页,显示博客的列表
  2. 博客详情页,点击博客列表页,上面列出的博客条目,跳转到的页面,显示博客的完整内容
  3. 登录页面
  4. 博客编辑页,基于editor.md搞一个markdown编辑器,基于这个页面来发布博客

我们需要以下需求:

  • 存储博客:当点击发布的时候,博客被发布到服务器上,就要被存起来
  • 存取博客:在博客列表页和博客详情页,能够拿到博客的内容
  • 能够进行登录校验

我们设计表,就需要抓住需求中的实体(关键性的名词)

  1. 博客表:用来存储所有的博客数据
  2. 用户表:用户登录时需要用到

在这里插入图片描述

-- 编写建库建表的 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,'第一篇博客','好好学习',1,now());
insert into blog values(null,'第二篇博客','天天向上',1,now());
insert into blog values(null,'第三篇博客','明天开始学Java',1,now());
insert into blog values(null,'第四篇博客','努力去见易烊千玺',2,now());
insert into blog values(null,'第五篇博客','累死自己,卷死同学',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,'panpan','123');
insert into user values(null,'ajiao','123456');

在这里插入图片描述

2. 封装数据库操作

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

package util;

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

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

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,所以我们可以把实现这类功能的类统一放在一个dao包里面。

BlogDao类

package dao;

import bean.Blog;
import util.DBUtil;

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 {
    //1.往博客表里,插入一个博客
    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();
            //4.关闭连接,释放资源
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DBUtil.close(connection,statement,null);
        }
    }
    //2.能够获取到博客表中的所有博客的信息(用于在博客列表页,此处每篇博客不一定会获取到完整的正文)
    public List<Blog>selectAll(){
        Connection connection=null;
        PreparedStatement statement=null;
        ResultSet resultSet=null;
        List<Blog>blogs=new ArrayList<>();
        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.getInt("userId"));
                blog.setPostTime(resultSet.getTimestamp("postTime"));
                blogs.add(blog);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DBUtil.close(connection,statement,resultSet);
        }
        return blogs;
    }
    //3.能够根据博客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();
            //此处我们是使用主键来作为查询条件的,查询结果要么是1要么是0,所以用if即可
            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.getInt("userId"));
                blog.setPostTime(resultSet.getTimestamp("postTime"));
                return blog;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DBUtil.close(connection,statement,resultSet);
        }
        return null;
    }
    //4.从博客表中,根据博客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 e) {
            e.printStackTrace();
        }finally {
            DBUtil.close(connection,statement,null);
        }
    }
}

UserDao类

package dao;

import bean.User;
import util.DBUtil;

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

/**
 * 提供了针对用户表的基本操作
 */
public class UserDao {
    //主要实现
    //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();
            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 e) {
            e.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 e) {
            e.printStackTrace();
        }finally {
            DBUtil.close(connection,statement,resultSet);
        }
        return null;
    }
}

到此数据库操作都给准备好了,下面就开始编写前后端的代码了

约定前后端交互接口

在编写前后端代码之前,先把之前纯页面的博客系统全部拷贝到webapp里面
在这里插入图片描述
博客系统:码云地址

1. 实现博客列表

1.1约定前后端交互接口

[请求]  GET/blog
[响应] [
   {
        blogId: 1,
        title: "第一篇博客",
        content: "博客正文",
        userId: 1,
        postTime: "2022-06-08 18:08:05"
   },
   {
        blogId: 2,
        title: "第二篇博客",
        content: "博客正文",
        userId: 2,
        postTime: "2022-06-08 18:08:05"
   },
    ...
]

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

1.2 实现服务器代码

package servlet;
import bean.Blog;
import com.fasterxml.jackson.databind.ObjectMapper;
import dao.BlogDao;

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;
import java.util.List;

//通过这个类,来处理/blog路径对应的请求
@WebServlet("/blog")
public class BlogServlet extends HttpServlet {
    private ObjectMapper objectMapper=new ObjectMapper();
    //这个方法用来获取到数据库中的博客列表
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //从数据库中查询到博客列表,转成json格式,然后直接返回即可
        BlogDao blogDao=new BlogDao();
        List<Blog>blogs=blogDao.selectAll();
        //把blog对象转成JSON格式
        String respJson= objectMapper.writeValueAsString(blogs);
        resp.setContentType("application/json;charset=utf8");
        resp.getWriter().write(respJson);
    }
}

1.3 编写客户端代码

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>博客列表</title>
	<link rel="stylesheet" href="css/common.css">
	<link rel="stylesheet" href="css/blog_list.css">
</head>
<body>
	<div class="nav">
		<img src="img/yyqx.jpg" alt="">
		<span >我的博客系统</span>
		
		<!-- 空白元素,用来占位置 -->
		<div class="spacer"></div>
		<a href="blog_list.html">主页</a>
		<a href="blog_edit.html">写博客</a>
		<a href="logout">注销</a>
	</div>
	<!-- 这里的.container 作为页面的版心 -->
	<div class="container">
		<!-- 左侧个人信息 -->
		<div class="left">
			<div class="card">
				<img src="./img/jackson.jpg" alt="">
				<h3>同学潘</h3>
				<a href="#">gitHub地址</a>
				<div class="counter">
					<span>文章</span>
					<span>分类</span>
				</div>
				<div class="counter">
					<span>2</span>
					<span>1</span>
				</div>
		</div>
		</div>
		<!-- 右侧内容详情 -->
		<div class="right">
		<!-- .blog 就对应一篇博客 -->
			<!-- <div class="blog">//这是之前页面原有的内容
				<div class="title">
					我的第一篇博客
				</div>
				<div class="data">
					2022-5-11 23:07:25
				</div>
				<div class="desc">
					从今以后,我要好好学习,天天向上。Lorem ipsum dolor sit amet consectetur adipisicing elit. Labore obcaecati tenetur itaque accusantium, commodi iste at aut ipsam ducimus temporibus culpa voluptatibus dolorem, exercitationem magnam. Molestiae ducimus dolore amet inventore?Lorem ipsum dolor sit amet consectetur adipisicing elit. Ex, saepe officia. Perferendis error pariatur hic numquam et recusandae reprehenderit cupiditate fugit? Facere officiis deserunt saepe iste eius iure modi cum.
	
				</div>
				<a href="blog_detail.html">查看全文&gt;&gt;</a>
			</div>
			<div class="blog">
				<div class="title">
					我的第二篇博客
				</div>
				<div class="data">
					2022-5-20 17:20:26
				</div>
				<div class="desc">
					青年兴则国家兴,青年强则国家强。Lorem ipsum dolor sit amet consectetur adipisicing elit. Labore obcaecati tenetur itaque accusantium, commodi iste at aut ipsam ducimus temporibus culpa voluptatibus dolorem, exercitationem magnam. Molestiae ducimus dolore amet inventore?Lorem ipsum dolor sit amet consectetur adipisicing elit. Ex, saepe officia. Perferendis error pariatur hic numquam et recusandae reprehenderit cupiditate fugit? Facere officiis deserunt saepe iste eius iure modi cum.
	
				</div>
				<a href="#">查看全文&gt;&gt;</a>
			</div> -->
		</div>
	</div>
	<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
	<script>
		//在页面加载的时候,通过Ajax给服务器发送数据,获取到博客列表信息,并且显示在界面上
		function getBlogList(){
			$.ajax({
				type:'get',
				url:'blog',
				success:function(body){
					//获取到的body就是一个js对象数组,每个元素就是一个js对象,根据这个对象构造div
					//1.先把.right里原有的内容给清空
					let rightDiv=document.querySelector('.right');
					rightDiv.innerHTML='';
					//2.遍历body,构造出一个个的blogDiv
					for(let blog of body){
						let blogDiv =document.createElement('div');
						blogDiv.className='blog';
						//构造标题
						let titleDiv=document.createElement('div');
						titleDiv.className='title';
						titleDiv.innerHTML=blog.title;
						blogDiv.appendChild(titleDiv);
						//构造发布时间
						let dataDiv=document.createElement('div');
						dataDiv.className='data';
						dataDiv.innerHTML=blog.postTime;
						blogDiv.appendChild(dataDiv);
						//构造博客的摘要
						let descDiv=document.createElement('div');
						descDiv.className='desc';
						descDiv.innerHTML=blog.content;
						blogDiv.appendChild(descDiv);
						//构造查看全文
						let a =document.createElement('a');
						a.innerHTML='查看全文 &gt;&gt;';
						//此处希望点击之后能够跳转到博客详情页!!
						//这个跳转过程需要告知服务器要访问的是哪个博客的详情页
						a.href='blog_detail.html?blogId='+blog.blogId;
						blogDiv.appendChild(a);
						//把blogDiv挂到dom树上
						rightDiv.appendChild(blogDiv);
					}
				},
				error:function(body){
					alert('获取博客列表失败!');
				}
			});
		}
		getBlogList();
	</script>
</body>
</html>

效果图如下:
在这里插入图片描述

图中的用户名显示的是panpan,而上面的客户端代码中用户名给的是同学潘,这是因为后面我们要实现登录的是哪个用户就显示哪个用户名,因此这里有点差异。

2. 实现博客详情

由于目前点击博客列表页的 “查看全文” , 进入博客详情页后是写死的内容,所以 我们期望能够根据当前的 博客 id 从服务器动态获取博客内容。

2.1 约定前后端交互接口

[请求]
GET /blog?blogId=1 

[响应] {
HTTP/1.1 200OK
Content-Type:application/json;
{
    blogId: 2,
    title: "第二篇博客",
    content: "博客正文",
    userId: 1,
    postTime: "2022-06-08 18:08:05"
},

2.2 实现服务器代码

获取详情页跟获取列表基本相同,所以我们只需要更改一下代码判断是否带参数 blogId,以此来返回是列表页还是详情页。

package servlet;
import bean.Blog;
import com.fasterxml.jackson.databind.ObjectMapper;
import dao.BlogDao;

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 javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.List;

//通过这个类,来处理/blog路径对应的请求
@WebServlet("/blog")
public class BlogServlet extends HttpServlet {
    private ObjectMapper objectMapper=new ObjectMapper();
    //这个方法用来获取到数据库中的博客列表
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //从数据库中查询到博客列表,转成json格式,然后直接返回即可
        //先尝试获取到rep中的blogId参数,如果参数存在,说明是要请求博客详情
        //如果该参数不存在,说明是要请求博客的列表
        BlogDao blogDao=new BlogDao();
        resp.setContentType("application/json;charset=utf8");
        String param=req.getParameter("blogId");
        if(param==null){
            //不存在参数,获取博客列表
            List<Blog>blogs=blogDao.selectAll();
            //把blog对象转成JSON格式
            String respJson= objectMapper.writeValueAsString(blogs);
            resp.getWriter().write(respJson);
        }else{
             //存在参数,获取博客详情
            int blogId=Integer.parseInt(param);
            Blog blog=blogDao.selectOne(blogId);
            String respJson=objectMapper.writeValueAsString(blog);
            resp.getWriter().write(respJson);
        }
    }
}

2.3 实现客户端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>博客详情页</title>
    <link rel="stylesheet" href="css/common.css">
    <link rel="stylesheet" href="css/blog_detail.css">
    <!-- 引入editor.md的依赖 -->
    <link rel="stylesheet" href="editor.md/css/editormd.min.css" />
<script src="js/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>
</head>
<body>
    <div class="nav">
		<img src="img/yyqx.jpg" alt="">
		<span >我的博客系统</span>
		<!-- 空白元素,用来占位置 -->
		<span class="spacer"></span>
		<a href="blog_list.html">主页</a>
		<a href="blog_edit.html">写博客</a>
		<a href="logout">注销</a>
	</div>
	<div class="container">
		<!-- 左侧个人信息 -->
		<div class="left">
			<div class="card">
				<img src="./img/jackson.jpg" alt="">
				<h3>同学潘</h3>
				<a href="#">gitHub地址</a>
				<div class="counter">
					<span>文章</span>
					<span>分类</span>
				</div>
				<div class="counter">
					<span>2</span>
					<span>1</span>
				</div>
		</div>
		</div>
		<!-- 右侧内容详情 -->
		<div class="right">
            <!-- 使用这个div来包裹整个博客的内容详情 -->
			<div class="blog-content">
                <!-- 博客标题 -->
                <h3></h3>
                <!-- 博客的发布时间 -->
                <div class="date"></div>
                <!-- 博客的正文内容 -->
                <div id="content" style="opacity: 80%;">

                </div>
            </div>
		</div>
	</div>
    <script>
        function getBlogDetail(){
            $.ajax({
                type:'get',
                //location.search拿到了形如'?blogId=5'这样的一段内容
                url:'blog'+location.search,
                success:function(body){
                    //根据body中的内容来构造页面
                    //1.构造博客标题
                    let h3=document.querySelector(".blog-content>h3");
                    h3.innerHTML=body.title;
                    //2.构造博客发布时间
                    let dateDiv=document.querySelector(".date");
                    dateDiv.innerHTML=body.postTime;
                    //3.构造博客正文
                    //如果直接把conent设为innerHTML,此时展示在界面上的内容,是原始的markdown字符串
                    //咱们需要的是渲染后的,带有格式的效果
                    // let contentDiv=document.querySelector("#content");
                    // contentDiv.innerHTML=body.content;
                    //第一个参数对应id=content的html标签,渲染后得到的html片段就会被放到这个标签下
                    editormd.markdownToHTML('content',{
                        markdown:body.content
                    });
                }
            });
        }
        getBlogDetail();
    </script>
</body>
</html>

在这里插入图片描述
效果图如下:
在这里插入图片描述

注意:当我们在进行程序验证的时候,要牢记一件事情,浏览器的缓存可能会影响到结果,你可能修改了之后再去同一个浏览器访问的时候,他并没有发生改变,因为浏览器可能把你上次访问的页面给保存到本地了,下次在尝试访问的时候访问的就是本地的内容,所以这个时候我们要按下: Ctrl + F5强制刷新一下

3. 实现登录

  1. 登陆页面提供一个 form 表单,通过 form 的方式把用户名密码提交给服务器
  2. 服务器端验证用户名密码是否正确
  3. 如果密码正确, 则在服务器端创建 Session,并把 sessionId 通过 Cookie 返回给浏览器

3.1 约定前后端交互接口

[请求]
POST /login
Content-Type: application/x-www-form-urlencoded
username=panpan&password=123
[响应]
HTTP/1.1 302 
Location: blog_list.html//登录成功以后,自动跳转到主页(博客列表页blog_list.html)

3.2 实现服务器代码

package servlet;

import bean.User;
import com.fasterxml.jackson.databind.ObjectMapper;
import dao.UserDao;

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 javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    private ObjectMapper objectMapper=new ObjectMapper();
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf8");
        resp.setCharacterEncoding("utf8");
        //1.获取到请求中的参数
        String username=req.getParameter("username");
        String password=req.getParameter("password");
        if(username==null||"".equals(username)||password==null||"".equals(password)){
            //请求的内容缺失,肯定是登陆失败!
            resp.setContentType("text/html;charset=utf8");
            resp.getWriter().write("当前的用户名或密码为空!");
            return;
        }
        //2.和数据库中的内容进行比较
        UserDao userDao=new UserDao();
        User user=userDao.selectByName(username);
        if(user==null||!user.getPassword().equals(password)){
            //用户没有查到或者密码不匹配,也是登录失败!
            resp.setContentType("text/html;charset=utf8");
            resp.getWriter().write("用户名或者密码错误!");
            return;
        }
        //3.如果通过比较,就创建会话
        HttpSession session= req.getSession(true);
        //把刚才的用户信息,存储到会话中
        session.setAttribute("user",user);
        //返回一个重定向报文,跳转到博客列表页
        resp.sendRedirect("blog_list.html");
    }
}

在这里插入图片描述

3.3 实现客户端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>登录页面</title>
    <link rel="stylesheet" href="css/common.css">
    <link rel="stylesheet" href="css/blog_login.css">
</head>
<body>
    <div class="nav">
		<img src="img/yyqx.jpg" alt="">
		<span >我的博客系统</span>
		<!-- 空白元素,用来占位置 -->
		<span class="spacer"></span>
		<a href="blog_list.html">主页</a>
		<a href="blog_edit.html">写博客</a>
		<!-- <a href="#">注销</a> -->
	</div>
    <div class="login-container">
        <form action="login" method="post">
            <div class="login-dialog">
                <h3>登录</h3>
                <div class="row">
                    <span>用户名</span>
                    <input type="text" id="username" name="username">
                </div>
                <div class="row">
                    <span>密码</span>
                    <input type="password" id="password" name="password">
                </div>
                <div class="row">
                    <!-- <button>提交</button> -->
                    <input type="submit"id="submit" value="提交">
                </div>
            </div>
        </form>
        
    </div>
</body>
</html>

实现强制要求登录

当用户访问 博客列表页博客详情页 时, 如果用户当前尚未登陆, 就自动跳转到登陆页面

这个可以在博客列表页/详情页加载的时候,通过 ajax 访问一下服务器,获取当前的登录状态,看看能不能获取到,如果获取到了,就说明当前确实是已经登陆了,此时就可以留在这个页面;如果没有获取到,说明是未登录的,就会跳转到登录页面让你登录。

约定前后端交互接口

[请求]
GET/login
[响应]
HTTP/1.1 200OK
Content-Type:application/json

{
    userId: 1,
    username: 'panpan',
}

登陆了,就直接返回当前登录的用户信息;如果未登录,则直接返回一个userId 为 0 的对象

实现服务器代码

LoginServlet中加入以下代码即可:

//这个方法用来让前端检测当前的登陆状态
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("application/json;charset=utf8");
        HttpSession session= req.getSession(false);
        if(session==null){
            //检测下会话是否存在,不存在说明未登录
            User user=new User();
            resp.getWriter().write(objectMapper.writeValueAsString(user));
            return;
        }
        User user=(User)session.getAttribute("user");
        if(user==null){
            //虽然有会话,但是会话里面没有user对象,也视为未登录
            user=new User();
            resp.getWriter().write(objectMapper.writeValueAsString(user));
            return;
        }
        //已经登录的状态
        //注意,此处不要把密码给返回到前端
        user.setPassword("");
        resp.getWriter().write(objectMapper.writeValueAsString(user));
    }

实现客户端代码

blog_list.html中加入以下代码即可:

//加上一个逻辑,通过GET/login这个接口来获取下当前的登录状态
		function getUserInfo(){
			$.ajax({
				type:'get',
				url:'login',
				success:function(body){
					//判定此处的body是不是一个有效的user对象(userId是否非0)
					if(body.userId&&body.userId>0){
						//登录成功,不做处理
						console.log("当前用户登录成功!用户名:"+body.username);
					}else{
						//登录失败,让前端页面跳转到blog_login.html
						alert("当前您尚未登录!请登录后再访问博客列表!");
						location.assign('blog_login.html');
					}
				},
				error:function(){
					alert("当前您尚未登录!请登录后再访问博客列表!");
					location.assign('blog_login.html');
				}
			});
		}
		getUserInfo();

博客详情页也可以有这样的功能,把这段代码添加到blog_detail.html中即可

function getUserInfo(){
			$.ajax({
				type:'get',
				url:'login',
				success:function(body){
					//判定此处的body是不是一个有效的user对象(userId是否非0)
					if(body.userId&&body.userId>0){
						//登录成功,不做处理
						console.log("当前用户登录成功!用户名:"+body.username);
					}else{
						//登录失败,让前端页面跳转到blog_login.html
						alert("当前您尚未登录!请登录后再访问博客详情!");
						location.assign('blog_login.html');
					}
				},
				error:function(){
					alert("当前您尚未登录!请登录后再访问博客列表详情!");
					location.assign('blog_login.html');
				}
			});
		}
		getUserInfo();

效果图如下:
在这里插入图片描述

4. 实现显示用户信息

我们期望用户信息可以随着用户的登陆而发生改变,如果当前页面是博客列表页,则显示当前登陆用户的信息;如果当前页面是博客详情页,则显示该博客的作者用户信息。

4.1 约定前后端交互接口

在博客列表页,获取登录用户的用户信息:

[请求]
GET /user
[响应] {
 userId: 1,
 username: test
}

在博客详情页,获取当前文章作者的用户信息:

[请求]
GET /user?blogId=1
[响应] {
 userId: 1,
 username: test
}

4.2 实现服务器代码

主要针对博客详情页:

package servlet;

import bean.Blog;
import bean.User;
import com.fasterxml.jackson.databind.ObjectMapper;
import dao.BlogDao;
import dao.UserDao;

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("/authorInfo")
public class AuthorServlet extends HttpServlet {
    private  ObjectMapper objectMapper=new ObjectMapper();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("application/json;charset=utf8");
        //通过这个方法,来获取到指定的博客的作者信息
        String param=req.getParameter("blogId");
        if(param==null||"".equals(param)){
            //参数缺少了
            resp.getWriter().write("{\"ok\":false,\"reason\":\"参数缺失!\"}");
            return;
        }
        //根据当前blogId在数据库中进行查找,找到对应的Blog对象,再进一步的根据blog对象,找到作者信息
        BlogDao blogDao=new BlogDao();
        Blog blog=blogDao.selectOne(Integer.parseInt(param));
        if(blog==null){
            resp.getWriter().write("{\"ok\":false,\"reason\":\"要查询的博客不存在!\"}");
            return;
        }
        //根据blog对象,查询到用户对象
        UserDao userDao=new UserDao();
        User author= userDao.selectById(blog.getUserId());
        if(author==null){
            resp.getWriter().write("{\"ok\":false,\"reason\":\"要查询的用户不存在!\"}");
            return;
        }
        //把author返回到浏览器这边
        //不要把密码给返回到前端
        author.setPassword("");
        resp.getWriter().write(objectMapper.writeValueAsString(author));
    }
}

4.3 实现客户端代码

对上述blog_list.htmlblog_detail.html代码进行修改,实现登录成功过后显示相应的用户名

blog_list.html

//加上一个逻辑,通过GET/login这个接口来获取下当前的登录状态
		function getUserInfo(){
			$.ajax({
				type:'get',
				url:'login',
				success:function(body){
					//判定此处的body是不是一个有效的user对象(userId是否非0)
					if(body.userId&&body.userId>0){
						//登录成功,不做处理
						console.log("当前用户登录成功!用户名:"+body.username);
						//根据当前用户登录的情况,把当前用户名设置到界面上
						ChangeUserName(body.username);
					}else{
						//登录失败,让前端页面跳转到blog_login.html
						alert("当前您尚未登录!请登录后再访问博客列表!");
						location.assign('blog_login.html');
					}
				},
				error:function(){
					alert("当前您尚未登录!请登录后再访问博客列表!");
					location.assign('blog_login.html');
				}
			});
		}
		getUserInfo();
		function ChangeUserName(username){
			let h3=document.querySelector('.card>h3');
			h3.innerHTML=username;
		}

blog_detail.html

function ChangeUserName(username){
			let h3=document.querySelector('.card>h3');
			h3.innerHTML=username;
		}
		//从服务器获取一下当前博客的作者信息,并显示到界面上
		//参数user就是刚才从服务器拿到的当前登陆用户的信息
		function getAuthorInfo(user){
			$.ajax({
				type:'get',
				url:'authorInfo'+location.search,
				success:function(body){
					//此处的body,就是服务器返回的User对象,是文章的作者信息
					if(body.username){
						//如果响应中的username存在,就把这个值设置到页面上
						ChangeUserName(body.username);
					}else{
						console.log("获取作者信息失败!"+body.reason);
					}
				}
			});
		}

效果图如下:
在这里插入图片描述
总结:

  1. 对于博客列表页,要显示登录用户信息,由于登录用户信息在检测用户是否登录的接口中,就已经拿到了,所以只需要把拿到的用户信息,显示到界面上即可(只需要动前端,后端不必修改)
  2. 对于博客详情页,要显示出文章作者的信息,需要提供一个新的 api ,让客户端传一个博客 id 过去,然后在服务器这里查询到用户信息,查到之后返回给页面

页面和服务器之间的交互,不一定只有一次,大概率是会有多次的。
我们这里写的博客列表页涉及到两次交互:

  1. 从服务器拿到博客列表数据
  2. 从服务器拿到当前的登录用户信息

博客详情页涉及到三次交互:

  1. 从服务器拿到博客的详细内容
  2. 从服务器拿到了当前的登录用户信息
  3. 从服务器拿到了当前文章的作者信息

我们以后可能还会遇到不止两次三次的,有些可能复杂的十几次也是正常的😅😅😅

5. 实现注销登录

就是退出登录状态,在导航栏安排一个"注销"按钮,当用户点击注销之后,就会在服务器上取消登录状态,并且跳回到登录页面,希望在点击之后,能够给服务器发送一个 HTTP 请求,从而触发注销动作(其实就是把会话中的信息给删除掉)

5.1 约定前后端接口

[请求]
GET /logout
[响应]
HTTP/1.1 302
Location: login.html

5.2 实现服务器代码

从 session 中删除掉保存的 User 对象,响应重定向到 login.html 页面

package servlet;

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 javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //先找到当前用户的会话
        HttpSession session=req.getSession(false);
        if(session==null){
            //用户没有登录!那么也就谈不上注销
            resp.getWriter().write("当前用户尚未登录!无法注销!");
            return;
        }
        //然后把这个用户的会话中的信息给删除掉就行了!
        session.removeAttribute("user");
        resp.sendRedirect("blog_login.html");
    }
}

5.3 实现客户端代码

只需要把blog_list.html,blog_detail.html,blog_edit.html中a标签中的href属性改为logout即可??

<a href="logout">注销</a>

6. 实现发布博客

在博客编辑页中,当用户输入博客标题和正文之后,点击发布,这个时候就会把博客数据提交到服务器,由服务器存储到数据库中。

6.1 约定前后端接口

[请求]
POST /blog
Content-Type: application/x-www-form-urlencoded
title=标题&content=正文...
[响应]
HTTP/1.1 302
Location: blog_list.html

6.2 实现服务器代码

在 BlogServlet 里面添加 一个 doPost 方法来处理 post 请求,核心的操作就是读取请求中的标题和正文,构造 Blog 对象,并插入数据库

@Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        HttpSession session=req.getSession(false);
        if(session==null){
            //当前用户未登录,不能提交博客!
            resp.setContentType("text/html;charset=utf8");
            resp.getWriter().write("当前用户未登录,不能提交博客!");
            return;
        }
        User user=(User)session.getAttribute("user");
        if(user==null){
            //当前用户未登录,不能提交博客!
            resp.setContentType("text/html;charset=utf8");
            resp.getWriter().write("当前用户未登录,不能提交博客!");
            return;
        }
        //一定要先指定好请求按照哪种编码来解析
        req.setCharacterEncoding("utf8");
        //先从请求中,取出参数(博客的标题和正文)
        String title=req.getParameter("title");
        String content=req.getParameter("content");
        if(title==null||"".equals(title)||content==null||"".equals(content)){
            //直接告诉客户端,请求参数不对
            resp.setContentType("text/html;charset=utf8");
            resp.getWriter().write("提交博客失败!缺少必要的参数!");
            return;
        }
        //构造Blog对象,把当前的信息填进去,并插入数据库中
        //此处要给Blog设置的属性,主要是title,content,userId(作者信息)
        //postTime和blogId哦都不需要手动指定,都是插入数据的时候自动生成的
        Blog blog=new Blog();
        blog.setTitle(title);
        blog.setContent(content);
        //作者id就是当前提交这个博客的用户的身份信息
        blog.setUserId(user.getUserId());
        BlogDao blogDao=new BlogDao();
        blogDao.insert(blog);
        //重定向到博客列表页
        resp.sendRedirect("blog_list.html");
    }

6.3 实现客户端代码

需要一个form表单,把这里的内容嵌套上:
在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>博客编辑页</title>
    <link rel="stylesheet" href="css/common.css">
    <link rel="stylesheet" href="css/blog_edit.css">
    <!-- 引入editor.md的依赖 -->
    <link rel="stylesheet" href="editor.md/css/editormd.min.css" />
<script src="js/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>
</head>
<body>
    <div class="nav">
		<img src="img/yyqx.jpg" alt="">
		<span >我的博客系统</span>
		<!-- 空白元素,用来占位置 -->
		<span class="spacer"></span>
		<a href="blog_list.html">主页</a>
		<a href="blog_edit.html">写博客</a>
		<a href="logout">注销</a>
	</div>
    <!-- 包裹整个博客编辑页内容的顶级容器 -->
    <div class="blog-edit-container">
        <form action="blog" method="post" style="height: 100%;">
            <div class="title">
                <input type="text" placeholder="在此处输入标题" name="title" id="title">
                <!-- <button>发布文章</button> -->
                <input type="submit" value="发布文章" id="submit">
            </div>
            <!-- 放置md编辑器 -->
            <div id="editor">
                <!-- 为了进行form的提交,此处搞一个textarea多行编辑框,借助这个编辑框来实现表单的提交 -->
                <!-- 可以设置editor.md,让编辑器把markdown内容也同步的保存到这个隐藏的textarea中,从而可以惊醒form提交 -->
                <textarea name="content" style="display:none ;"></textarea>
            </div>
        </form>
    </div>
    <script>
        // 初始化编辑器
var editor = editormd("editor", {
    // 这里的尺寸必须在这里设置. 设置样式会被 editormd 自动覆盖掉. 
    width: "100%",
    // 高度 100% 意思是和父元素一样高. 要在父元素的基础上去掉标题编辑区的高度
    height: "calc(100% - 90px)",
    // 编辑器中的初始内容
    markdown: "# 在这里写下一篇博客",
    // 指定 editor.md 依赖的插件路径
    path: "editor.md/lib/",
    //此处要加上一个重要的选项,然后editor.md就会自动把用户再编辑器输入的内容同步保存到隐藏的textarea中了
    saveHTMLToTextarea:true
});

    </script>
</body>
</html>

效果图如下:
在这里插入图片描述
在这里插入图片描述

7. 实现删除博客

删除博客,肯定不是可以随便删除的,约定只有自己能删除自己的博客,不能删除别人的博客?? (此处咱们暂时不考虑管理员)

界面上的处理: 在博客详情页这里,就去进行判定,判定看当前这个博客的作者,是否就是登录的用户。如果是,就在导航栏里显示一个“删除按钮";如果不是,就不显示删除按钮
服务器处理: 用户点击删除按钮,触发一个HTTP请求, HTTP请求就会让服务器删除指定的博客,服务器收到请求之后,就会把这个博客从数据库里给删除掉

7.1 约定前后端交互接口

[请求]
GET /blogDelete?blogId=1
[响应] 
直接跳转到 博客列表页 即可

7.2 实现服务器代码

package servlet;

import bean.Blog;
import bean.User;
import dao.BlogDao;

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 javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/blogDelete")
public class BlogDeleteServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.检查当前用户是否登录
        HttpSession session= req.getSession(false);
        if(session==null){
            resp.setContentType("text/html;charset=utf8");
            resp.getWriter().write("当前尚未登录,不能删除!");
            return;
        }
        User user=(User)session.getAttribute("user");
        if(user==null){
            resp.setContentType("text/html;charset=utf8");
            resp.getWriter().write("当前尚未登录,不能删除!");
            return;
        }
        //2.获取到参数中的blogId
        String blogId=req.getParameter("blogId");
        if(blogId==null||"".equals(blogId)){
            resp.setContentType("text/html;charset=utf8");
            resp.getWriter().write("当前blogId的参数不对!");
            return;
        }
        //3.获取要删除的博客信息
        BlogDao blogDao=new BlogDao();
        Blog blog =blogDao.selectOne(Integer.parseInt(blogId));
        if(blog==null){
            resp.setContentType("text/html;charset=utf8");
            resp.getWriter().write("当前要删除的博客不存在!");
            return;
        }
        //4.再次校验,当前的用户是否就是博客的作者
        if(user.getUserId()!= blog.getUserId()){
            resp.setContentType("text/html;charset=utf8");
            resp.getWriter().write("当前登录的用户不是作者,没有权限删除!");
            return;
        }
        //5.确认无误,开始删除
        blogDao.delete(Integer.parseInt(blogId));
        //6.重定向到博客列表页
        resp.sendRedirect("blog_list.html");
    }
}

7.3 实现客户端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>博客详情页</title>
    <link rel="stylesheet" href="css/common.css">
    <link rel="stylesheet" href="css/blog_detail.css">
    <!-- 引入editor.md的依赖 -->
    <link rel="stylesheet" href="editor.md/css/editormd.min.css" />
<script src="js/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>
</head>
<body>
    <div class="nav">
		<img src="img/yyqx.jpg" alt="">
		<span >我的博客系统</span>
		<!-- 空白元素,用来占位置 -->
		<span class="spacer"></span>
		<a href="blog_list.html">主页</a>
		<a href="blog_edit.html">写博客</a>
		<a href="logout">注销</a>
	</div>
	<div class="container">
		<!-- 左侧个人信息 -->
		<div class="left">
			<div class="card">
				<img src="./img/jackson.jpg" alt="">
				<h3></h3>
				<a href="#">gitHub地址</a>
				<div class="counter">
					<span>文章</span>
					<span>分类</span>
				</div>
				<div class="counter">
					<span>2</span>
					<span>1</span>
				</div>
		</div>
		</div>
		<!-- 右侧内容详情 -->
		<div class="right">
            <!-- 使用这个div来包裹整个博客的内容详情 -->
			<div class="blog-content">
                <!-- 博客标题 -->
                <h3></h3>
                <!-- 博客的发布时间 -->
                <div class="date"></div>
                <!-- 博客的正文内容 -->
                <div id="content" style="opacity: 80%;">

                </div>
            </div>
		</div>
	</div>
    <script>
        function getBlogDetail(){
            $.ajax({
                type:'get',
                //location.search拿到了形如'?blogId=5'这样的一段内容
                url:'blog'+location.search,
                success:function(body){
                    //根据body中的内容来构造页面
                    //1.构造博客标题
                    let h3=document.querySelector(".blog-content>h3");
                    h3.innerHTML=body.title;
                    //2.构造博客发布时间
                    let dateDiv=document.querySelector(".date");
                    dateDiv.innerHTML=body.postTime;
                    //3.构造博客正文
                    //如果直接把conent设为innerHTML,此时展示在界面上的内容,是原始的markdown字符串
                    //咱们需要的是渲染后的,带有格式的效果
                    // let contentDiv=document.querySelector("#content");
                    // contentDiv.innerHTML=body.content;
                    //第一个参数对应id=content的html标签,渲染后得到的html片段就会被放到这个标签下
                    editormd.markdownToHTML('content',{
                        markdown:body.content
                    });
                }
            });
        }
        getBlogDetail();
        function getUserInfo(){
			$.ajax({
				type:'get',
				url:'login',
				success:function(body){
					//判定此处的body是不是一个有效的user对象(userId是否非0)
					if(body.userId&&body.userId>0){
						//登录成功,不做处理
						console.log("当前用户登录成功!用户名:"+body.username);
						//在getUserInfo的回调函数中,来调用获取作者信息
						getAuthorInfo(body);
						
					}else{
						//登录失败,让前端页面跳转到blog_login.html
						alert("当前您尚未登录!请登录后再访问博客详情!");
						location.assign('blog_login.html');
					}
				},
				error:function(){
					alert("当前您尚未登录!请登录后再访问博客列表详情!");
					location.assign('blog_login.html');
				}
			});
		}
		getUserInfo();
		function ChangeUserName(username){
			let h3=document.querySelector('.card>h3');
			h3.innerHTML=username;
		}
		//从服务器获取一下当前博客的作者信息,并显示到界面上
		//参数user就是刚才从服务器拿到的当前登陆用户的信息
		function getAuthorInfo(user){
			$.ajax({
				type:'get',
				url:'authorInfo'+location.search,
				success:function(body){
					//此处的body,就是服务器返回的User对象,是文章的作者信息
					if(body.username){
						//如果响应中的username存在,就把这个值设置到页面上
						ChangeUserName(body.username);
						if(body.username==user.username){
							//作者和登陆的用户是一个人,则显示删除按钮
							let navDiv=document.querySelector('.nav');
							let a=document.createElement('a');
							a.innerHTML='删除博客';
							//期望点击删除,构造一个形如blogDelete?blogId=1这样的请求
							a.href='blogDelete'+location.search;
							navDiv.appendChild(a);
						}
					}else{
						console.log("获取作者信息失败!"+body.reason);
					}
				}
			});
		}
		
    </script>
</body>
</html>

效果图如下:
在这里插入图片描述
在这里插入图片描述

目前实现的功能只有这么多,具体其他功能以后随缘实现???
在这里插入图片描述

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-06-25 17:56:45  更:2022-06-25 17:56:55 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 16:46:49-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码