【JavaEE初阶】博客系统后端

文章目录

  • 一. 创建项目 引入依赖
  • 二. 设计数据库
  • 三. 编写数据库代码
  • 四. 创建实体类
  • 五. 封装数据库的增删查改
  • 六. 具体功能书写
    • 1. 博客列表页
    • 2. 博客详情页
    • 3. 博客登录页
    • 4. 检测登录状态
    • 5. 实现显示用户信息的功能
    • 6. 退出登录状态
    • 7. 发布博客

一. 创建项目 引入依赖

创建blog_system项目.将之前写的博客系统前端代码复制到webapp目录下.
在这里插入图片描述
pom.xml中引入Servlet mysql jackson三个依赖:
pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>blog_system</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.49</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.14.2</version></dependency></dependencies>
</project>

二. 设计数据库

结合之前的需求,在当前博客系统中,主要涉及到两个实体.即 用户博客.
经过分析我们可以得到,用户博客之间是一对多的关系.即一个用户可以拥有多篇博客.
所以我们可以创建两张表,来表示用户和博客.
blog(blogId,title,content,postTime,userId)
user(userId,userName,password)

三. 编写数据库代码

把一些基本的数据库操作,先封装好.
在这里插入图片描述
需要手动粘贴至MySQL

-- 这个文件主要用来写 建库建表 语句create database if not exists javaee_blog_system;
use javaee_blog_system;-- 删除旧表,重新建表
drop table if exists user;
drop table if exists blog;-- 创建表
create table blog(blogId int primary key auto_increment,title varchar(128),content varchar(4096),postTime datetime,userId int
);create table user(userId int primary key auto_increment,username varchar(20) unique,-- 要求用户名和别人的不重复password varchar(20)
);

接下来是封装数据库的连接操作:
DBUtil:

import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;import javax.sql.DataSource;
import java.sql.*;public class DBUtil {private static DataSource dataSource = new MysqlDataSource();static {((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/javaee_blog_system?characterEncoding=utf8&useSSL=false");((MysqlDataSource)dataSource).setUser("root");((MysqlDataSource)dataSource).setPassword("0828");}public static Connection getConnection() throws SQLException {return dataSource.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();}}}
}

四. 创建实体类

实体类就是和表中的记录对应的类:
blog表 =>Blog类对应Blog的一个对象,就对应表中的一条记录.
user表 =>User类对应User的一个对象,就对应表中的一个记录.
实体类有哪些属性,都是和当前表中的列是密切相关的.
User:


public class User {private int userId;private String username;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;}private String password;
}

Blog:

import java.sql.Timestamp;public class Blog {private int blogId;private String title;private String content;private Timestamp postTime;private int userId;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 Timestamp getPostTime() {return postTime;}public void setPostTime(Timestamp postTime) {this.postTime = postTime;}public int getUserId() {return userId;}public void setUserId(int userId) {this.userId = userId;}
}

五. 封装数据库的增删查改

针对博客表,创建BlogDao;(Data Access Object)
针对用户表,创建UserDao.
上述Dao用来提供一些方法.来进行增删查改.
BlogDao:

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 add(Blog blog){Connection connection = null;PreparedStatement statement = null;try {//1.和数据库建立连接connection = DBUtil.getConnection();//2.构造SQLString sql = "insert into blog values(null,?,?,?,?)";statement = connection.prepareStatement(sql);statement.setString(1,blog.getTitle());statement.setString(2, blog.getContent());statement.setTimestamp(3,blog.getPostTime());statement.setInt(4,blog.getUserId());//3.执行SQLstatement.executeUpdate();} catch (SQLException e) {throw new RuntimeException(e);}finally {DBUtil.close(connection,statement,null);}}//2.根据博客id来查询指定博客(博客详情页)public Blog selectById(int blogId){Connection connection = null;PreparedStatement statement = null;ResultSet resultSet = null;try {//1.与数据库建立连接connection = DBUtil.getConnection();//2.构造sqlString sql = "select * from blog where blogId = ?";statement = connection.prepareStatement(sql);statement.setInt(1,blogId);//3.执行sqlresultSet = statement.executeQuery();//4.遍历结果集合if(resultSet.next()){Blog blog = new Blog();blog.setBlogId(resultSet.getInt("blogId"));blog.setTitle(resultSet.getString("title"));blog.setContent(resultSet.getString("content"));blog.setPostTime(resultSet.getTimestamp("postTime"));blog.setUserId(resultSet.getInt("userId"));}} catch (SQLException e) {throw new RuntimeException(e);}finally {//5.释放资源DBUtil.close(connection,statement,resultSet);}return null;}//3.查询数据库中所有的博客列表(用于博客列表页)public List<Blog> selectAll(){List<Blog> blogs = new ArrayList<>();Connection connection = null;PreparedStatement statement = null;ResultSet resultSet = null;try {//1.与数据库建立连接connection = DBUtil.getConnection();//2.构造sql语句String sql = "select * from blog";statement = connection.prepareStatement(sql);//3.执行sqlresultSet = statement.executeQuery();//4.遍历结果集合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() >= 100){content = content.substring(0,100) +"...";}blog.setContent(content);blog.setPostTime(resultSet.getTimestamp("postTime"));blog.setUserId(resultSet.getInt("userId"));blogs.add(blog);}} catch (SQLException e) {throw new RuntimeException(e);}finally {DBUtil.close(connection,statement,resultSet);}return blogs;}//4.删除指定博客public void delect(int blogId){Connection connection = null;PreparedStatement statement = null;try {//1.与数据库建立连接connection = DBUtil.getConnection();//2.构造sql语句String sql = "delete from blog where bolgId = ?";statement = connection.prepareStatement(sql);statement.setInt(1,blogId);//3.执行sqlstatement.executeUpdate();} catch (SQLException e) {throw new RuntimeException(e);}finally {//4.关闭资源DBUtil.close(connection,statement,null);}}
}

UserDao:

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;//针对用户表提供的基本操作
public class UserDao {//1.根据 userId 来查用户信息public User selectById(int userId){Connection connection = null;PreparedStatement statement = null;ResultSet resultSet = null;try {//1.与数据库建立连接connection = DBUtil.getConnection();//2.构造sqlString sql = "select * from user where userId = ?";statement = connection.prepareStatement(sql);statement.setInt(1,userId);//3.执行SQLresultSet = statement.executeQuery();//4.遍历结果集合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) {throw new RuntimeException(e);}finally {//5.释放资源DBUtil.close(connection,statement,resultSet);}return null;}//2.根据username来查找用户信息.public User selectByUsername(int username){Connection connection = null;PreparedStatement statement = null;ResultSet resultSet = null;try {//1.与数据库建立连接connection = DBUtil.getConnection();//2.构造sqlString sql = "select * from user where userId = ?";statement = connection.prepareStatement(sql);statement.setInt(1,username);//3.执行SQLresultSet = statement.executeQuery();//4.遍历结果集合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) {throw new RuntimeException(e);}finally {//5.释放资源DBUtil.close(connection,statement,resultSet);}return null;}
}

六. 具体功能书写

1. 博客列表页

在这里插入图片描述
当前博客列表页上的数据都是写死的.正确的做法,应该是通过数据库读取数据显示到页面上.
此处就需要打通前后端交互的操作.
让博客列表页,在加载的时候,通过ajax给服务器发一个请求服务器查数据库获取到博客列表数据,返回给浏览器,浏览器再根据数据构造页面内容.这样的交互过程,也称为“前后端分离"
前端只向后端请求数据,而不请求具体的页面,后端也仅仅是返回数据.这样的设定的目的就是为了前端和后端更加解耦,由浏览器进行具体的页面渲染.减少了服务器的工作量.

上述进行实现博客列表页的基本思路

接下来需要:

  1. 约定前后端交互接口
  2. 开发后端代码
  3. 开发前端代码
  1. 约定前后端交互接口
    请求:GET /blog
    响应:使用json格式的数据来组织
[{blogId:1,title:"这是第一篇博客",content:"从今天开始,我要认真学习",postTime:"2023-08-01 09:40:45",userId:1}{blogId:1,title:"这是第一篇博客",content:"从今天开始,我要认真学习",postTime:"2023-08-01 09:40:45",userId:1}{blogId:1,title:"这是第一篇博客",content:"从今天开始,我要认真学习",postTime:"2023-08-01 09:40:45",userId:1}
]
  1. 开发后端代码
    BlogServlet:
package api;import com.fasterxml.jackson.databind.ObjectMapper;
import model.Blog;
import model.BlogDao;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;public class BlogServlet extends HttpServlet {private ObjectMapper objectMapper = new ObjectMapper();@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {BlogDao blogDao = new BlogDao();List<Blog> blogs = blogDao.selectAll();//需要把blogs转成符合要求的 json 格式字符串String respJson = objectMapper.writeValueAsString(blogs);resp.setContentType("application/json;charset = utf8");resp.getWriter().write(respJson);}
}

在这里插入图片描述
此处注意文件所在位置.model是管理数据/操作数据的部分.

  1. 开发前端代码
    在博客列表页加载过程中,触发ajax,访问服务器中的数据.再把拿到的数据构造到页面中.
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><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="image/logo2.jpg" alt=""><span class="title">我的博客系统</span><!-- 用于占位,将a标签挤到右侧去 --><div class="spacer"></div><a href="#">主页</a><a href="#">写博客</a><a href="#">注销</a></div><!-- 页面主体部分 --><div class="container"><!-- 左侧信息 --><div class="container-left"><!-- 使用.card表示用户信息 --><div class="card"><!-- 用户头像 --><img src="image/touxiang.jpg" alt=""><!-- 用户名 --><h3>xxxflower</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="container-right"></div></div><script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.3/jquery.min.js"></script><script>// 在页面加载时, 向服务器发起请求, 获取博客列表数据function getBlogs() {$.ajax({type: 'get',url: 'blog',success: function(body) {// 响应的正文 是一个 json 字符串, 此处已经被 jquery 自动解析成 js 对象数组了. // 直接 for 循环遍历即可. let containerRight = document.querySelector('.container-right');for (let blog of body) {// 构造页面内容, 参考之前写好的 html 代码// 构造整个博客 divlet blogDiv = document.createElement('div');blogDiv.className = 'blog';// 构造标题let titleDiv = document.createElement('div');titleDiv.className = 'title';titleDiv.innerHTML = blog.title;blogDiv.appendChild(titleDiv);// 构造发布时间let dateDiv = document.createElement('div');dateDiv.className = 'date';dateDiv.innerHTML = blog.postTime;blogDiv.appendChild(dateDiv);// 构造 博客 摘要let descDiv = document.createElement('div');descDiv.className = 'desc';descDiv.innerHTML = blog.content;blogDiv.appendChild(descDiv);// 构造查看全文按钮let a = document.createElement('a');a.innerHTML = '查看全文 &gt;&gt;';// 期望点击之后能跳转到博客详情页. 为了让博客详情页知道是点了哪个博客, 把 blogId 给传过去a.href = 'blog_detail.html?blogId=' + blog.blogId;blogDiv.appendChild(a);// 把 blogDiv 加到父元素中containerRight.appendChild(blogDiv);}}});}// 要记得调用getBlogs();</script>
</body>
</html>

效果如下图所示:
在这里插入图片描述
但是我们发现这里的时间显示有问题:
我们需要使用SimpleDateFormat类.注意该类使用时的书写格式!
在这里插入图片描述
在这里插入图片描述

2. 博客详情页

关于博客详情页,点击查看全文按钮,就能跳转到博客详情页中.跳转过去之后,在博客详情页中发起一个ajax,从服务器获取到当前的博客的具体内容.再进行显示.

分为以下几个步骤:

  1. 约定前后端交互接口
  2. 实现后端代码
  3. 实现前端代码
  1. 约定前后端交互接口
    请求:GET/blog?blogId = 1
    响应:
    HTTP/1.1 200 OK
    {
    blogId:1,
    title:“这是第一篇博客”,
    content:“从今天开始我要认真学习”,
    postTime:“2023-08-01 17:00:00”,
    userId:1
    }

  2. 实现后端代码

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><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">
</head>
<body><!-- 导航栏 --><div class="nav"><img src="image/logo2.jpg" alt=""><span class="title">我的博客系统</span><!-- 用于占位,将a标签挤到右侧去 --><div class="spacer"></div><a href="#">主页</a><a href="#">写博客</a><a href="#">注销</a></div><!-- 页面主体部分 --><div class="container"><!-- 左侧信息 --><div class="container-left"><!-- 使用.card表示用户信息 --><div class="card"><!-- 用户头像 --><img src="image/touxiang.jpg" alt=""><!-- 用户名 --><h3>xxxflower</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="container-right"><!-- 博客标题 --><h3 class="title"></h3><!-- 博客发布时间 --><div class="date"></div><!-- 博客正文, 为了配合 editormd 进行格式转换, 此处务必改成 id  --><div id="content"></div></div></div><script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.3/jquery.min.js"></script><!-- 要保证这几个 js 的加载在 jquery 之后. editor.md 依赖了 jquery --><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>$.ajax({type: 'get',url: 'blog' + location.search,success: function(body) {// 处理响应结果, 此处的 body 就是表示一个博客的 js 对象. // 1. 更新标题let titleDiv = document.querySelector('.container-right .title');titleDiv.innerHTML = body.title;// 2. 更新日期let dateDiv = document.querySelector('.date');dateDiv.innerHTML = body.postTime;// 3. 更新博客正文// 此处不应该直接把博客正文填充到这个标签里editormd.markdownToHTML('content', { markdown: body.content });}})</script>
</body>
</html>
  1. 开发后端代码
package api;import com.fasterxml.jackson.databind.ObjectMapper;
import model.Blog;
import model.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;@WebServlet("/blog")
public class BlogServlet extends HttpServlet {private ObjectMapper objectMapper = new ObjectMapper();@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {BlogDao blogDao = new BlogDao();String blogId = req.getParameter("blogId");if(blogId == null){List<Blog> blogs = blogDao.selectAll();//需要把blogs转成符合要求的 json 格式字符串String respJson = objectMapper.writeValueAsString(blogs);resp.setContentType("application/json;charset = utf8");resp.getWriter().write(respJson);}else{// queryString 存在, 说明本次请求获取的是指定 id 的博客.Blog blog = blogDao.selectById(Integer.parseInt(blogId));if (blog == null) {System.out.println("当前 blogId = " + blogId + " 对应的博客不存在!");}String respJson = objectMapper.writeValueAsString(blog);resp.setContentType("application/json; charset=utf8");resp.getWriter().write(respJson);}}
}

在这里插入图片描述
这是因为浏览器自身也有缓存机制.
浏览器从服务器这边获取页面,这个操作是通过网络传输完成的,速度是比较慢的.浏览器就会把页面给缓存到本地(客户端电脑的硬盘上).后续再访问同一个页面,就直接读缓存.但是这样做有一些问题,即客户端命中缓存之后就不一定能及时感知到变化.
解决方法:强制刷新.(无视缓存,100%重新访问服务器)Ctrl + f5
在这里插入图片描述

3. 博客登录页

在这里插入图片描述
在此处输入用户名和密码,点击登录,就会触发一个http请求.
服务器验证用户名和密码,然后就可以根据结果,判定是否登录成功.

分为以下几个步骤:

  1. 约定前后端交互接口
  2. 实现前端代码
  3. 实现后端代码
  1. 约定前后端交互接口
    请求:
    POST/login
    username = zhangsan&password = 123
    响应:
    HTTP/1.1 302
    Location:blog_list.html

注意:
此处的响应应是from表单(本身就会触发页面跳转),响应是302才能够进行页面跳转.
如果是ajax请求(本身不会触发),响应是302,此时是无法进行跳转的.

  1. 实现前端代码
    往页面上加入from表单,使得点击登录操作能够触发请求.
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><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/login.css">
</head>
<body><!-- 导航栏 --><div class="nav"><img src="image/logo2.jpg" alt=""><span class="title">我的博客系统</span><!-- 用于占位,将a标签挤到右侧去 --><div class="spacer"></div><a href="#">主页</a><a href="#">写博客</a></div><!-- 正文部分 --><!-- 贯穿整个页面的容器 --><div class="login-container"><!-- 垂直水平登录的对话框 --><div class="login-dialog"><form action="login" method="post"><h3>登录</h3><div class="row"><span>用户名:</span><input type="text" id="username" placeholder="手机号/邮箱号" name="username"></div><div class="row"><span>密码:</span><input type="password" id="password" placeholder="请输入密码" name="password"></div><div class="row"><input type="submit" id="submit" value="登录"></div></form></div></div>
</body>
</html>

在这里插入图片描述
注意此处对应的关系:
在这里插入图片描述
3. 修改后端代码

package api;import model.User;
import model.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 {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//设置请求的编码,使用 utf8 理解请求req.setCharacterEncoding("utf8");//设置响应的编码,使用 utf8 构造响应//resp.setCharacterEncoding("utf8");resp.setContentType("text/html;charset=utf8");//1.读取参数中的用户名和密码String username = req.getParameter("username");String password = req.getParameter("password");if(username == null ||"".equals(username) || password == null ||"".equals(password)){//登录失败String html = "<h3>登录失败!用户名/密码为空!</h3>";resp.getWriter().write(html);return;}//2.读取数据库,查看用户名是否存在.密码是否匹配UserDao userDao = new UserDao();User user =userDao.selectByUsername(username);if(user == null){//用户不存在String html = "<h3>登录失败!用户名或密码错误</h3>";resp.getWriter().write(html);return;}if(!password.equals(user.getPassword())){String html = "<h3>登录失败!用户名或密码错误</h3>";resp.getWriter().write(html);return;}//3.用户名密码验证通过,登录成功,接下来就创建会话,使用该会话保存用户信息HttpSession session = req.getSession();session.setAttribute("user",user);//4.重定向,跳转到博客列表页resp.sendRedirect("blog_list.html");}
}

在这里插入图片描述

4. 检测登录状态

实现让页面强制要求登录,
当用户访问博客列表页/详情页/编辑页,要求用户必须是已经登录的状态.如果用户还没登录,就会强制跳转到登录页面.

实现思路:
在页面加载的时候,专门发起一个新的 ajax . (一个页面里可以发N个ajax请求)以博客列表页为例,先会发一个请求获取博客列表,再发个ajax获取用户的登录状态,如果用户已登录,相安无事.如果未登录,则页面跳转到登录页.

  1. 约定前后端交互接口
  2. 实现前端代码
  3. 实现后端代码
  1. 约定前后端交互接口
    请求:GET/login
    响应:
    HTTP/1.1 200 OK
    {
    userId:1,
    username:‘xxxflower’
    }

响应就把当前登录的用户信息返回回来了,如果未登录,就返回一个userld0user 对象

  1. 实现后端代码
@Overrideprotected 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 user = new User();String respJson = objectMapper.writeValueAsString(user);resp.getWriter().write(respJson);return;}User user = (User) session.getAttribute("user");if (user == null) {user = new User();String respJson = objectMapper.writeValueAsString(user);resp.getWriter().write(respJson);return;}// 确实成功取出了 user 对象, 就直接返回即可.String respJson = objectMapper.writeValueAsString(user);resp.getWriter().write(respJson);}
  1. 开发后端代码:
function checkLogin() {$.ajax({type: 'get',url: 'login',success: function(body) {if (body.userId && body.userId > 0) {// 登录成功!!console.log("当前用户已经登录!!");h3.innerHTML = body.username;} else {// 当前未登录// 强制跳转到登录页. location.assign('login.html');}}});}checkLogin();

将此代码粘贴至博客列表页
则效果如下:
在这里插入图片描述

5. 实现显示用户信息的功能

在这里插入图片描述
此处我们是写死的,我们希望这个地方可以动态生成.

  1. 如果是博客列表页,此处显示登陆用户的信息
  2. 如果此处是博客详情页,此时显示的是该文章的作者
  1. 约定前后端接口
    博客列表页:(复用监测登录状态的接口)
    请求:
    GET /login
    响应:
    HTTP/1.1 200 OK
    {
    userId:1,
    username:‘huang’,
    password:‘234’
    }
    由于是在监测登录的接口中直接写,所以后端代码不变,只需要微调前端代码即可
    在这里插入图片描述
    登录可以看到:
    在这里插入图片描述
    博客详情页:
  2. 前后端交互接口
    请求:
    GET/author?blogId = 1
    响应:
    HTTP/1.1 200 OK
    {
    userId:1,
    username:‘huang’,
    password:‘234’
    }
  3. 后端代码:
package api;import com.fasterxml.jackson.databind.ObjectMapper;
import model.Blog;
import model.BlogDao;
import model.User;
import model.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("/author")
public class AuthorServlet extends HttpServlet {private ObjectMapper objectMapper = new ObjectMapper();@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String blogId = req.getParameter("blogId");if(blogId == null){resp.setContentType("text/html;charset = utf8");resp.getWriter().write("参数非法,缺少blogId!");return;}//根据 blog 查询Blog对象BlogDao blogDao = new BlogDao();Blog blog = blogDao.selectById(Integer.parseInt("blogId"));if(blog == null){resp.setContentType("text/html;charset = utf8");resp.getWriter().write("没有找到指定博客");return;}//根据BLog中UserId 获取到对应的用户信息UserDao userDao = new UserDao();User author = userDao.selectById(blog.getUserId());String respJson = objectMapper.writeValueAsString(author);resp.setContentType("application/json;charset=utf8");resp.getWriter().write(respJson);}
}
  1. 前端代码:
function getAuthor(){$.ajax({type:'get',url:'author' + location.search,success: function(body){//将username设置到页面上let h3 = document.querySelector('.container-left .card h3');h3.innerHTML = body.userId;}})}getAuthor();

在这里插入图片描述

6. 退出登录状态

判断登录状态:

  1. 看是否能查到http session对象
  2. session对象里面有没有user

在这里插入图片描述

实现退出登录:

  1. 处理HttpSession
    getSession能够创建/获取会话,但是没有删除会话的方法.但是我们可以通过设置过期时间来达到类似效果
  2. 处理user(推荐) 可以通过removeAttribute来处理
  1. 约定前后端接口
    请求:
    GET/logout
    响应:
    HTTP/1.1 302
    Location:login.html

  2. 实现后端代码:

package api;import model.User;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 {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {HttpSession httpSession = req.getSession(false);if(httpSession == null){//未登录,直接出错resp.setContentType("text/html;charset=utf8");resp.getWriter().write("当前未登录!");return;}httpSession.removeAttribute("user");resp.sendRedirect("login.html");}
}
  1. 实现前端代码
    修改博客列表页 ,博客编辑页的前端代码:
    在这里插入图片描述
    在这里插入图片描述

7. 发布博客

  1. 约定前后端交互接口
    使用form表单:页面中更多了form标签,同时让form里面能够感知到博客的内容.
    请求:POST/blog
    title=标题&content=正文
    响应:HTTP/1.1 302
    Location:blog_list.html
  2. 编写服务器代码
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 发布博客// 读取请求, 构造 Blog 对象, 插入数据库中即可!!HttpSession httpSession = req.getSession(false);if (httpSession == null) {resp.setContentType("text/html; charset=utf8");resp.getWriter().write("当前未登录, 无法发布博客!");return;}User user = (User) httpSession.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 blog = new Blog();blog.setTitle(title);blog.setContent(content);blog.setUserId(user.getUserId());// 发布时间, 在 java 中生成 / 数据库中生成 都行blog.setPostTime(new Timestamp(System.currentTimeMillis()));// 插入数据库BlogDao blogDao = new BlogDao();blogDao.add(blog);// 跳转到博客列表页resp.sendRedirect("blog_list.html");}
  1. 客户端代码:
    <!-- 编辑区的容器 --><div class="blog-edit-container"><form action="blog" method="post" style="height: 100%;"><!-- 博客标题编辑区 --><div class="title"><input type="text" id="title" placeholder="输入文章标题" name="title"><input type="submit" id="submit" value="发布文章"></div><!-- 博客编辑器, 这里用 id 是为了和 markdown 编辑器对接, 而设置的 --><div id="editor"><textarea name="content" style="display:none"></textarea></div></form></div>

在这里插入图片描述
后续点击submit就能自动提交
display:none是隐藏元素.
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/24320.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ffmpeg.c源码与函数关系分析

介绍 FFmpeg 是一个可以处理音视频的软件&#xff0c;功能非常强大&#xff0c;主要包括&#xff0c;编解码转换&#xff0c;封装格式转换&#xff0c;滤镜特效。FFmpeg支持各种网络协议&#xff0c;支持 RTMP &#xff0c;RTSP&#xff0c;HLS 等高层协议的推拉流&#xff0c…

基于Java+SpringBoot+SpringCloud+Vue的智慧养老平台设计与实现(源码+LW+部署文档等)

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…

Opencv-C++笔记 (15) : 像素重映射 与 图像扭曲

文章目录 一、重映射简介二、图像扭曲 一、重映射简介 重映射&#xff0c;就是把一幅图像中某位置的像素放置到另一图像指定位置的过程。即&#xff1a; 在重映射过程中&#xff0c;图像的大小也可以同时发生改变。此时像素与像素之间的关系就不是一一对应关系&#xff0c;因…

TCP Socket 基础知识点(实例是以Java进行演示)

本篇根据TCP & Socket 相关知识点和学习所得进行整理所得。 文章目录 前言1. TCP相关知识点1.1 双工/单工1.2 TCP协议的主要特点1.3 TCP的可靠性原理1.4 报文段1.4.1 端口1.4.2 seq序号1.4.3 ack确认号1.4.4 数据偏移1.4.5 保留1.4.6 控制位1.4.7 窗口1.4.8 校验和1.4.9 紧…

VS+Qt环境下解决中文乱码问题

目录 原因解决方案总结 原因 使用VSQt出现中文乱码的情况一般都是给控件添加中文文本时出现&#xff0c;而控件需要的字符串类型是QString&#xff0c;默认是utf-8。在 Visual Studio 中&#xff0c;源代码文件的默认执行字符集可能是 Windows 默认的 ANSI 字符集&#xff0c;…

【力扣】23. 合并 K 个升序链表 <链表指针、堆排序、分治>

目录 【力扣】23. 合并 K 个升序链表题解方法一&#xff1a;暴力&#xff0c;先遍历取出来值到数组中排序&#xff0c;再生成新链表方法二&#xff1a;基础堆排序&#xff08;使用优先队列 PriorityQueue&#xff09;方法三&#xff1a;基础堆排序&#xff08;使用优先队列 Pri…

对 CXL.cache 伪数据(Bogus Data)的解读

&#x1f525;点击查看精选 CXL 系列文章&#x1f525; &#x1f525;点击进入【芯片设计验证】社区&#xff0c;查看更多精彩内容&#x1f525; &#x1f4e2; 声明&#xff1a; &#x1f96d; 作者主页&#xff1a;【MangoPapa的CSDN主页】。⚠️ 本文首发于CSDN&#xff0c…

Element的el-select下拉框多选添加全选功能

先看效果图 全选&#xff1a; 没有选中时&#xff1a; 选中部分&#xff1a; 作者项目使用的是vue3写法&#xff0c;如果是vue2的自己转换一下 html代码&#xff1a; js代码&#xff1a; 拓展 另一种方法&#xff0c;如果不想使用勾选框&#xff0c;可以试试下面的方…

Spring Boot介绍--快速入门--约定优于配置

文章目录 SpringBoot 基本介绍官方文档Spring Boot 是什么?SpringBoot 快速入门需求/图解说明完成步骤快速入门小结 Spring SpringMVC SpringBoot 的关系总结梳理关系如何理解-约定优于配置 SpringBoot 基本介绍 官方文档 官网: https://spring.io/projects/spring-boot 学习…

Leaflet入门,地图平移跳转到指定位置和飞行到指定位置效果

前言 本章讲解如何Leaflet如何实现操作地图平移到指定位置或者飞行到指定位置效果。 vue如何使用Leaflet vue2如何使用:《Leaflet入门,如何使用vue2-leaflet实现vue2双向绑定式的使用Leaflet地图,以及初始化后拿到leaflet对象,方便调用leaflet的api》 vue3如何使用:《L…

XXL-JOB定时任务框架(Oracle定制版)

特点 xxl-job是一个轻量级、易扩展的分布式任务调度平台&#xff0c;能够快速开发和简单学习。开放源代码并被多家公司线上产品使用&#xff0c;开箱即用。尽管其确实非常好用&#xff0c;但我在工作中使用的是Oracle数据库&#xff0c;因为xxl-job是针对MySQL设计的&#xff…

MySql的Windows安装指南

目录 一、MySQL的4大版本 二、软件的下载 三、MySQL8.0 版本的安装 四、配置MySQL8.0 五、配置MySQL8.0 环境变量 六、登录验证 一、MySQL的4大版本 MySQL Community Server 社区版本&#xff0c;开源免费&#xff0c;自由下载&#xff0c;但不提供官方技术支持&#xff…

一款界面精美的商城微信小程序源码 蔬菜生鲜商城小程序源码

一款界面精美的商城微信小程序源码 蔬菜生鲜商城小程序源码 界面非常漂亮的一款我厨蔬菜生鲜商城小程序源码&#xff0c;tab切换效果&#xff0c;分享给大家参考。

一、7.协同式任务切换与抢占式任务切换

使用TSS来在任务切换时保护现场和恢复现场 内核任务&#xff1a;单纯由内核组成的任务&#xff0c;和其他用户程序组成其他任务 内核任务的创建 ;为内核任务创建任务控制块TCB mov ecx, 0x46 call sys_routine_seg_sel:allocate_memory call append_to_tcb_link ;将此TCB添加…

BClinux8.6 制作openssh9.2p2 rpm升级包和升级实战

一、背景说明 BClinux8.6 安装的openssh 版本为9.3p1&#xff0c;经绿盟扫描&#xff0c;存在高危漏洞&#xff0c;需要升级到最新。 OpenSSH 命令注入漏洞(CVE-2020-15778) OpenSSH 安全漏洞(CVE-2023-38408) 目前官网只提供编译安装包&#xff0c;而BClinux8.6 为rpm方…

回归预测 | MATLAB实现基于SVM-RFE-BP支持向量机递归特征消除特征选择算法结合BP神经网络的多输入单输出回归预测

回归预测 | MATLAB实现基于SVM-RFE-BP支持向量机递归特征消除特征选择算法结合BP神经网络的多输入单输出回归预测 目录 回归预测 | MATLAB实现基于SVM-RFE-BP支持向量机递归特征消除特征选择算法结合BP神经网络的多输入单输出回归预测预测效果基本介绍研究内容程序设计参考资料…

Vue中,$forceUpdate()的使用

在Vue官方文档中指出&#xff0c;$forceUpdate具有强制刷新的作用。 那在vue框架中&#xff0c;如果data中有一个变量:age&#xff0c;修改他&#xff0c;页面会自动更新。 但如果data中的变量为数组或对象&#xff0c;我们直接去给某个对象或数组添加属性&#xff0c;页面是识…

antv/l7地图,鼠标滚动,页面正常滑动-- 我们忽略的deltaY

背景 在官网项目中&#xff0c;需要使用一个地图&#xff0c;展示产品的分布区域及数量。希望的交互是&#xff0c;鼠标放上标点&#xff0c;tooltip展示地点和数量等信息。鼠标滚动&#xff0c;则页面随着滚动。但是鼠标事件是被地图代理了的&#xff0c;鼠标滚动意味着地图的…

性能测试入门知识总结

目录 1.什么是性能测试&#xff1f; 2.为什么要进行性能测试&#xff1f; 3.性能测试的常见术语 4.性能测试的分类 5.性能测试如何展开&#xff1f; 1.什么是性能测试&#xff1f; 性能测试是一种测试类型&#xff0c;旨在确定系统的性能以衡量性能&#xff0c;验证或验证…

8.15锁的优化

1.锁升级(锁膨胀) 无锁 -> 偏向锁 -> 轻量级锁 -> 重量级锁 偏向锁:不是真的加锁,而是做了一个标记,如果有别的线程来竞争才会真的加锁,如果没有别的线程竞争就不会加锁. 轻量级锁:一个线程占领锁资源后,另一个线程通过自旋的方式反复确认锁是否被是否(这个过程比较…