通过servlet设计一个博客系统

博客系统

  • 准备工作
    • servlrt依赖
    • mysql依赖
    • jackson依赖
  • 服务器和数据库的交互
    • 设计数据库/数据表
    • 封装DBUtil,实现建立连接和断开连接
    • 创建实体类
      • blog
      • user
    • 编写Dao类
      • BlogDao
      • UserDao
  • 前端和服务器的交互
    • 功能一:博客列表页
      • 约定格式
      • 后端代码
      • 前端代码
    • 功能二:实现博客详情页
      • 约定格式
      • 后端代码
      • 前端代码
    • 功能三:实现登录功能
      • 约定格式:
      • 后端代码
      • 前端代码
    • 功能四:强制检查登录
      • 约定格式
      • 后端代码
      • 前端代码
      • 前端代码
    • 功能五:实现显示用户信息
      • 约定格式
        • 博客列表页
        • 博客详情页
      • 后端代码
      • 后端代码
    • 功能六:退出登录(注销)
      • 约定格式
      • 后端代码
      • 前端代码
    • 功能七:发布博客
      • 约定格式
      • 后端代码
      • 前端代码

这里贴一个链接,大家可以看看成品http://115.159.31.84:8080/blog_system/blog_list.html
用户名是zhangsan或者lisi,密码是123

准备工作

在这里插入图片描述

通过ideal创建一个maven文件 在pom.xml中引入依赖

servlrt依赖

<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><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.49</version>
</dependency>

jackson依赖

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.14.2</version>
</dependency>

接下来要进行的操作,分为两个大的方面

服务器和数据库的交互

设计数据库/数据表

在main中创建一个dp.sql文件,在这里面编写SQL完成建库建表操作

在这里插入代码片//编写SQL完成建库建表操作
//建库
create database if not exists blog_system charset utf8;
//建表,使用一个表表示博客,另一个表表示用户
use blog_system;
drop table if exists user;
drop table if exists blog;
create table blog(blogId int primary key auto_increment,title varchar(256),content varchar(4096),userId int,postTime datetime
);
create table user(userId int primary key auto_increment,username varchar(64) unique,password varchar(64)
);

通过封装JDBC代码,来实现基础的数据库操作,因为在咱们的程序里,是需要针对blog表和user表进行一些增删查改的
首先,我们在Java这个包中再创建一个dao包(data access object
数据访问对象),在里面写一些类,通过这些类里的方法封装了数据库,之后的数据库就是通过这样的对象来访问的

封装DBUtil,实现建立连接和断开连接

在dao包中创建一个类,通过这个类,把数据库建立连接和断开连接的逻辑进行封装

package dao;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 volatile DataSource dataSource = null;//此处需要为单例模式private static DataSource getDataSource() {if (dataSource == null) {synchronized (DBUtil.class) {if (dataSource == null) {dataSource = new MysqlDataSource();((MysqlDataSource) dataSource).setURL("jdbc:mysql://127.0.0.1:3306/blog_system?useSSL=false&characterEncoding=utf8");((MysqlDataSource) dataSource).setUser("root");((MysqlDataSource) dataSource).setPassword("111111");}}}return dataSource;}//提供一个方法,和数据库建立连接public static Connection getConnection(){try {return getDataSource().getConnection();} catch (SQLException e) {e.printStackTrace();}return null;}//提供一个方法,和数据库断开连接public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet) throws SQLException {if (resultSet!=null){resultSet.close();}if (statement!=null){statement.close();}if (connection!=null){connection.close();}}
}

创建实体类

此处的实体类,就是要和数据库的表有对应关系,每个表都需要有一个实体类(不绝对),然后就可以使用这个类的对象来表示这个表里的一条记录了(因此,就要求这个对象的属性,能和表里的属性一一对应)
后续数据库操作是围绕实体类来展开的
同样的,我们需要在dao这个包里面创建blog类和user类

blog

package dao;
import java.sql.Timestamp;
//通过这个类的一个对象,来表示一条blog表中的记录
//这个类的属性,要和表中的列一致
public class blog {private int blogId;private String title;private String content;private int userId;//SQL里面有Timestamp类型(4个字节,2038年就不够用了),还有 datetime类型//使用SQL时,推荐使用datetimeprivate Timestamp postTime;public int getBlogId() {return blogId;}public String getTitle() {return title;}public String getContent() {return content;}public int getUserId() {return userId;}public String getPostTime() {//此处需要把时间戳转换为格式化时间//先构造一个对象,构造的时候,指定具体的格式.SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");return format.format(postTime);}public void setBlogId(int blogId) {this.blogId = blogId;}public void setTitle(String title) {this.title = title;}public void setContent(String content) {this.content = content;}public void setUserId(int userId) {this.userId = userId;}public void setPostTime(Timestamp postTime) {this.postTime = postTime;}@Overridepublic String toString() {return "blog{" +"blogId=" + blogId +", title='" + title + '\'' +", content='" + content + '\'' +", userId=" + userId +", postTime=" + postTime +'}';}
}

user

package dao;public class user {private int userId;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;}@Overridepublic String toString() {return "user{" +"userId=" + userId +", username='" + username + '\'' +", password='" + password + '\'' +'}';}
}

编写Dao类

通过实现Dao类,来封装对实体类(数据表)的增删查改

BlogDao

package dao;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;//通过这个类,封装对blog表的增删查改
public class BlogDao {//1.新增一个blog//调用insert的时候,需要先构造一个blog对象//作为参数,传递给insert,再由insert内部完成数据库的插入操作public void insert(blog blog) throws SQLException {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();}catch (SQLException e){e.printStackTrace();} finally{//4.关闭连接,释放资源DBUtil.close(connection,statement,null);}}//2.查询blog表里的所有的博客public List<blog>getblogs() throws SQLException {Connection connection = null;PreparedStatement statement = null;ResultSet resultSet =null;List<blog>blogs = new ArrayList<>();try{//1.建立连接connection = DBUtil.getConnection();//2.构造一个SQL语句String sql = "select * from blog";statement = connection.prepareStatement(sql);//3.执行语句resultSet = statement.executeQuery();//4.遍历结果集合while(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"));blogs.add(blog);}return blogs;} catch (SQLException e) {e.printStackTrace();}finally {DBUtil.close(connection,statement,resultSet);}return null;}//3.指定blogId,查询某一个博客public blog getblog(int blogId) throws SQLException {Connection connection = null;PreparedStatement statement = null;ResultSet resultSet = null;try{//1.建立连接connection = DBUtil.getConnection();//2.构造SQL语句String sql = "select * from blog where blogId=?";statement = connection.prepareStatement(sql);statement.setInt(1,blogId);//3.执行sql语句resultSet = statement.executeQuery(sql);//4.获取blogif(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.指定blogId进行删除public void delete(int blogId) throws SQLException {Connection connection = null;PreparedStatement statement = null;try{//1.建立连接connection = DBUtil.getConnection();//2.创建SQL语句String sql = "delete from blog where blogId=?";statement = connection.prepareStatement(sql);statement.setInt(1,blogId);//3.执行sql语句statement.executeUpdate();} catch (SQLException e) {e.printStackTrace();}finally {DBUtil.close(connection, statement, null);}}
}

UserDao

package dao;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;public class UserDao {//1.根据userId来查询用户信息(后续根据博客查询出作者详情)public user getuserById(int userId) throws SQLException {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();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.根据username来查询用户信息(实现登录功能)public user getuserByName(String username) throws SQLException {Connection connection = null;PreparedStatement statement = null;ResultSet resultSet = null;try{connection = DBUtil.getConnection();String sql = "select * from 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;}
}

前端和服务器的交互

接下来,就可以进行一些前后端交互的逻辑的实现了 接下来以功能点为维度进行展开
针对每个功能点,分别进行"设计前后端交互接口",“开发后端代码”,“开发前端代码”,“调试”

功能一:博客列表页

让博客列表页能够加载出博客列表内容
1.发起一个http请求,向后端索要博客列表数据
2.后端收到请求之后查询数据库获取到数据库中的博客列表,并返回给前端
3.前端拿到响应之后,就依据响应中的内容,构造出html片段,最终显示出来 在进行这三个操作之前,还需要约定好前后端交互接口,后续前端和后端要进行很多种不同的数据交互,每一种数据交互都需要发送不同的请求,返回不同的响应,此处就需要把请求和响应具体都约定好
首先创建一个名为api的包,用来存放一些前后端交互的代码,也就是一些重要的servlet,这些servlet给前端提供功能支持,也可以理解为服务器给前端提供的api(编程接口),也可以叫做Controller

约定格式

以下是一种典型的约定方式
请求:
方法: GET
路径: blog
响应: HTTP/1.1 200 OK
Content-Type:application/json json格式如下:

[{blogId:1,title:"西游记",content:"三打白骨精“,userId:1,postTime:"2023-09-25 12:00:00"}{blogId:2,title:"水浒传",content:"武松打虎“,userId:1,postTime:"2023-09-25 12:00:00"}
]

后端代码

后端要做的事,就是当收到一个上述约定的请求的时候,构造并返回一个约定的响应数据即可

在api这个包种创建一个BlogServlet
在这里插入图片描述

package api;import com.fasterxml.jackson.databind.ObjectMapper;
import dao.BlogDao;
import dao.blog;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.sql.SQLException;
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 {//查询数据库,获取到数据后,构造成要求的json格式并返回BlogDao blogDao = new BlogDao();List<blog>blogs = null;try {blogs = blogDao.getblogs();} catch (SQLException e) {e.printStackTrace();}String respJson = objectMapper.writeValueAsString(blogs);//jackson看到blogs是一个List,就会构造出一个json数组[],针对List种的每个blog对象,分别构造出json对象//具体构造的过程,也就是根据blog的属性来的,属性的名字,就是json的key,属性的值,就是json的valueresp.setContentType("application/json;charset=utf8");resp.getWriter().write(respJson);}
}

前端代码

让页面通过js ajax的方式发起一个http请求,来获取到刚才服务器这里的数据

这里需要先引入jquery的依赖:

<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>

创建一个script标签,在里面编写前端代码

<script>//编写js代码//构造http请求,获取到博客列表数据,并展示到页面上function getBlogs(){$.ajax({type:'get',url:'blog',success:function(body){//根据响应的内容,构造出html片段,展示到页面上//由于服务器在响应种已经设置了content-type为application/json,此时//jQuery就能够自动 的把此处响应的内容给解析成js对象数组let container = document.querySelector('.container-right');for(let blog of body){//相当于Java中的for each//根据当前这个blog来构造出一个html片段let 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.href = "blog_detail.html?blogId="+blog.blogId;a.innerHTML = '查看全文 &gt;&gt;';blogDiv.appendChild(a);container.appendChild(blogDiv);}}});}getBlogs();

功能二:实现博客详情页

约定格式

请求:
方法: GET
路径: blog?query string
此处与博客列表页访问的是同一个路径,通过请求中是否携带query string来区分两个业务
响应: HTTP/1.1 200 OK
Content-Type:application/json json格式如下:

 {blogId:1,title:"西游记",content:"三打白骨精“,userId:1,postTime:"2023-09-25 12:00:00"}

这里的数据格式和博客列表页返回的非常相似,这里是一条记录,博客列表则是一个数组

后端代码

package api;import com.fasterxml.jackson.databind.ObjectMapper;
import dao.Blog;
import dao.BlogDao;
import dao.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;
import java.sql.SQLException;
import java.sql.Timestamp;
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 {// 查询数据库, 获取到数据之后, 构造成要求的 json 格式并返回.// 先尝试获取下 blogId 这个参数, 看看能不能获取到.BlogDao blogDao = new BlogDao();String blogId = req.getParameter("blogId");if (blogId == null) {// 此时说明是获取博客列表. 没有 blogId 参数List<Blog> blogs = null;blogs = blogDao.getBlogs();String respJson = objectMapper.writeValueAsString(blogs);resp.setContentType("application/json; charset=utf8");resp.getWriter().write(respJson);} else {// 此时说明是获取博客详情. 有 blogId 参数.Blog blog = null;blog = blogDao.getBlog(Integer.parseInt(blogId));if (blog == null) {// 返回一个 id 为 0 的 blog 对象. 前端再根据这里进行判定.blog = new Blog();}String respJson = objectMapper.writeValueAsString(blog);resp.setContentType("application/json; charset=utf8");resp.getWriter().write(respJson);}}
}

前端代码

function getBlog() {$.ajax({url: 'blog' + location.search,type: 'get',success: function(body) {// 根据拿到的响应数据, 构造页面内容. let h3 = document.querySelector('.container-right h3');h3.innerHTML = body.title;let dateDiv = document.querySelector('.container-right .date');dateDiv.innerHTML = body.postTime;editormd.markdownToHTML('content', { markdown: body.content });}});}getBlog();

这里为了使用markdown编辑器来渲染博客,因此需要引入markdown的依赖

 <link rel="stylesheet" href="editor.md/css/editormd.min.css" /><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>

注意:这里的markdown的依赖是建立在jQuery中引入的前提下的,因此我们需要先引入jQuery,再引入markdown

功能三:实现登录功能

约定格式:

请求:
方法: post
路径: login
Content-Type:application/x-www-form-urlencoded(使用form表单的形式提交)
username=zhangsan&password=123
响应: HTTP/1.1 200 OK
Location:blog_list_html

后端代码

package api;import dao.User;
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 {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//1.请求中的用户名和密码//给请求对象设置字符集,保证请求中的用户名或者密码为中文的情况下也是可以的req.setCharacterEncoding("utf8");String username = req.getParameter("username");String password = req.getParameter("password");if (username == null || password == null || "".equals(username) || "".equals(password)) {//提交的密码有误resp.setContentType("text/html;charset=utf8");resp.getWriter().write("当前传过来的username或者password为空");}//2.和数据库的数据进行对比,看是否匹配UserDao userDao = new UserDao();User user = userDao.getUserByName(username);if (user==null){resp.setContentType("text/html;charset=utf8");resp.getWriter().write("您的用户名或者密码错误");return;}//当前用户名正确,看密码是否正确if (!password.equals(user.getPassword())){resp.setContentType("text/html;charset=utf8");resp.getWriter().write("您的用户名或者密码错误");return;}//3.创建会话HttpSession session = req.getSession(true);//把当前用户的登录信息保存到session中,方便后续进行获取session.setAttribute("user",user);//4.跳转到博客列表页resp.sendRedirect("blog_list_html");}
}

前端代码

<form action="login" method="post"><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"><input type="submit" id="submit" value="登录"></div></form>

功能四:强制检查登录

如果用户在未登录的情况下,访问博客详情列/列表页/编辑页,就会自动的跳转到登录页
在博客详情列/列表页/编辑页,再发起一个get的ajax,询问服务器看当前是否已经登录

约定格式

请求:
方法: get
路径: login
响应: HTTP/1.1 200 OK(已登录)
HTTP/1.1 403 Forbidden(未登录)

后端代码

前端代码

  @Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//会话不存在,就是未登录HttpSession session = req.getSession(false);if (session==null){//未登录resp.setStatus(403);return;}//不仅仅是看session对象本身是否存在,还需要看user对象是否存在(为了后续实现退出登录的功能)User user = (User) session.getAttribute("user");if (user==null){resp.setStatus(403);return;}//返回200表示已登录resp.setStatus(200);}

前端代码

function checkLogin() {$.ajax({type: 'get',url: 'login',success: function(body) {},error: function(body) {location.assign('login.html');}});
}

功能五:实现显示用户信息

在当前博客列表页中,显示出当前登录的用户的个人信息,在博客详情页中,显示出这个文章的作者
让博客详情列表页和详情页分别发起ajax请求,博客列表中.就需要获取到当前登录的用户的信息
博客详情页中,就需要获取到当前文章作者的信息

约定格式

博客列表页

请求:
方法: get
路径: user
响应:
HTTP/1.1 200 OK

json格式
{
userId:1,
username:‘zhangsan’
}

博客详情页

请求:
方法: get
路径: user?blogId=
响应:
HTTP/1.1 200 OK

json格式
{
userId:1,
username:‘zhangsan’
}

后端代码

package api;import com.fasterxml.jackson.databind.ObjectMapper;
import dao.Blog;
import dao.BlogDao;
import dao.User;
import dao.UserDao;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;public class UserServlet 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){//说明是博客列表页HttpSession session = req.getSession(false);if (session==null){User user = new User();String respJson = objectMapper.writeValueAsString(user);resp.setContentType("application/json;charset=utf8");resp.getWriter().write(respJson);return;}User user = (User) session.getAttribute("user");if (user==null){user = new User();String respJson = objectMapper.writeValueAsString(user);resp.setContentType("application/json;charset=utf8");resp.getWriter().write(respJson);return;}String respJson = objectMapper.writeValueAsString(user);resp.setContentType("application/json;charset=utf8");resp.getWriter().write(respJson);}else {//博客详情页//需要查询数据库BlogDao blogDao = new BlogDao();Blog blog = blogDao.getBlog(Integer.parseInt(blogId));if (blog==null){User user = new User();String respJson = objectMapper.writeValueAsString(user);resp.setContentType("application/json;charset=utf8");resp.getWriter().write(respJson);return;}UserDao userDao = new UserDao();User user = userDao.getUserById(blog.getUserId());if (user==null){user = new User();String respJson = objectMapper.writeValueAsString(user);resp.setContentType("application/json;charset=utf8");resp.getWriter().write(respJson);return;}String respJson = objectMapper.writeValueAsString(user);resp.setContentType("application/json;charset=utf8");resp.getWriter().write(respJson);}}
}

后端代码

function getUser() {$.ajax({type: 'get',url: 'user',success: function(body) {// body 就是解析后的 user 对象了. let h3 = document.querySelector('.card h3');h3.innerHTML = body.username;}})}getUser();
function getUser() {$.ajax({type: 'get',url: 'user' + location.search,success: function(body) {// body 就是解析后的 user 对象了. let h3 = document.querySelector('.card h3');h3.innerHTML = body.username;}})}getUser();

功能六:退出登录(注销)

判定登录状态逻辑中,
1.会话存在
2.会话中存储的user对象存在
两个条件同时具备,才认为用户是已经登录了
破坏上述的任何一个条件,都可以达成注销这样的效果
但是servlet中,并没有直接提供一个api来删除会话
但是有api能够删除会话中的user(attribute)

约定格式

请求:
方法: get
路径: logout
响应:
HTTP/1.1 302
location:login.html

后端代码

package api;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;public class LogoutServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {HttpSession session = req.getSession(false);if (session==null){//当前是未登录状态,谈不上注销resp.sendRedirect("login.html");return;}//之前在登录成功之后,就会给session中存储user这样的attribute//现在需要将其删除session.removeAttribute("user");resp.sendRedirect("login.html");}
}

前端代码

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

通过点击a标签就能实现退出登录

功能七:发布博客

这里本质上和登录非常相似
核心都是通过form表单,把页面中用户的内容,给提交到服务器这边,服务器就可以把内容保存到数据中即可

约定格式

请求:
方法:post
路径:blog
Content-Type:application/x-www-form-urlencoded
body:title=xxxxx&content=xxxx
响应:
HTTP/1.1 302
location:blog_list.html
提交成功后,跳转到博客列表页,来到列表页之后,就能够看到刚才发布的博客了

后端代码

    @Overrideprotected 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("未登录");}User user = (User) session.getAttribute("user");if (user==null){resp.setContentType("text/html;charset=utf8");resp.getWriter().write("未登录");}//获取到请求中传递过来的内容req.setCharacterEncoding("utf8");String title = req.getParameter("title");String content = req.getParameter("content");if(title==null||content==null||"".equals(title)||"".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());//由于在sql中插入数据的时候,已经使用sql自带的now获取到当前的时间,不需要此处代码中手动设置时间了
//        blog.setPostTime(new Timestamp(System.currentTimeMillis()));BlogDao blogDao = new BlogDao();blogDao.insert(blog);resp.sendRedirect("blog_list.html");}
}

前端代码

 <form action="blog" method="post"><!-- 标题编辑区 --><div class="title"><input type="text" id="title-input" name="title"><input type="submit" id="submit"></div><!-- 博客编辑器 --><!-- 把 md 编辑器放到这个 div 中 --><div id="editor"><textarea name="content" style="display: none;"></textarea>//此处是editor.md文档上给出的解决方案,在此处写一个隐藏的text area(多行编辑框),就可以实现form表单的提交了,在这里就可以指定name的值了</div></form>

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

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

相关文章

STM32外部中断(红外传感器与旋转编码器计数案例)

文章目录 一、介绍部分简介中断系统中断执行流程STM32中断NVIC基本结构NVIC优先级分组外部中断外部中断简介外部中断基本结构外部中断的流程AFIOEXTI框图 相关外设介绍旋转编码器介绍硬件电路对射式红外传感器 二、代码实现对射式红外传感器计次连接电路封装红外传感器与中断函…

【Linux】统信服务器操作系统V20 1060a-AMD64 Vmware安装

目录 ​编辑 一、概述 1.1 简介 1.2 产品特性 1.3 镜像下载 二、虚拟机安装 一、概述 1.1 简介 官网&#xff1a;统信软件 – 打造操作系统创新生态 统信服务器操作系统V20是统信操作系统&#xff08;UOS&#xff09;产品家族中面向服务器端运行环境的&#xff0c;是一款…

mysql升级到8.x

1.下载和安装 1.1.下载 mysql下载地址&#xff1a; https://dev.mysql.com/downloads/mysql/5.5.html?os31&version5.1 应该下载这个类似版本 mysql-8.0.36-linux-glibc2.17-x86_64-minimal.tar.xz 1.2 安装 解压&#xff1a; tar xvf mysql-8.0.36-linux-glibc2.17…

C语言-2

自定义类型 基本认识 /*引入&#xff1a;学生&#xff1a;姓名&#xff0c;学号&#xff0c;年龄&#xff0c;成绩请为学生们专门定制一个类型&#xff08;创造一个类型&#xff09;结构体格式&#xff1a;struct 标识符 // 标识符即自定义类型的名称{成员; // 自己设置…

【洛谷】P2392 kkksc03考前临时抱佛脚

本题最重要的思路是&#xff1a;将题目转化为 01 背包模型。 注意点&#xff1a; &#xff08;1&#xff09;要求最短时间&#xff0c;则需让左右脑花费的时间最接近&#xff0c;极限状态下是左脑时间和右脑时间相等&#xff0c;且等于 m sum / 2&#xff08;其中sum是一道…

如何使用项目管理工具进行任务分配和进度跟踪

项目管理是一项重要的工作&#xff0c;有效的任务分配和进度跟踪是项目成功的关键因素。 项目经理可以选择合适的项目管理工具来管理项目&#xff0c;在选择项目管理工具时&#xff0c;需要根据项目的特点和需求进行评估。本文将介绍如何使用项目管理工具来进行任务分配和进度…

已解决: ModuleNotFoundError: No module named ‘tensorflow‘ 问题

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

【蓝桥杯冲冲冲】[NOIP2001 普及组] 装箱问题

蓝桥杯备赛 | 洛谷做题打卡day26 文章目录 蓝桥杯备赛 | 洛谷做题打卡day26题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示思路 题解代码我的一些话 [NOIP2001 普及组] 装箱问题 题目描述 有一个箱子容量为 V V V&#xff0c;同时有 n n n 个物品&#xff0c;每…

2024年【熔化焊接与热切割】考试题及熔化焊接与热切割操作证考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 熔化焊接与热切割考试题根据新熔化焊接与热切割考试大纲要求&#xff0c;安全生产模拟考试一点通将熔化焊接与热切割模拟考试试题进行汇编&#xff0c;组成一套熔化焊接与热切割全真模拟考试试题&#xff0c;学员可通…

手把手教你开发Python桌面应用-PyQt6图书管理系统-图书类别添加代码逻辑实现

锋哥原创的PyQt6图书管理系统视频教程&#xff1a; PyQt6图书管理系统视频教程 Python桌面开发 Python入门级项目实战 (无废话版) 火爆连载更新中~_哔哩哔哩_bilibiliPyQt6图书管理系统视频教程 Python桌面开发 Python入门级项目实战 (无废话版) 火爆连载更新中~共计24条视频&…

大模型增量预训练新技巧:解决灾难性遗忘

大家好&#xff0c;目前不少开源模型在通用领域具有不错的效果&#xff0c;但由于缺乏领域数据&#xff0c;往往在一些垂直领域中表现不理想&#xff0c;这时就需要增量预训练和微调等方法来提高模型的领域能力。 但在领域数据增量预训练或微调时&#xff0c;很容易出现灾难性…

c++重载、隐藏和覆盖

重载 函数名字相同&#xff0c;但参数列表或者返回值不同一组函数要重载必须处在同一作用域中 class Base { public:Base(int data0):m_a(data){}void show(){cout<<"Base::show()"<<endl;}void show(int){cout<<"Base:show(int)"<&l…