通过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.mzph.cn/news/668164.shtml

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

相关文章

sql相关子查询

1.什么是相关子查询 相关子查询是一个嵌套在外部查询中的查询&#xff0c;它使用了外部查询的某些值。每当外部查询处理一行数据时&#xff0c;相关子查询就会针对那行数据执行一次&#xff0c;因此它的结果可以依赖于外部查询中正在处理的行。 2.为什么要使用相关子…

Python 数据可视化:配色方案

1、引言 在这篇文章中&#xff0c;我们将研究Python的一些配色方案&#xff0c;主要是Seaborn库。这将采用 Python Notebook 格式&#xff0c;其中包括绘图的代码。 2、实验数据 首先导入必要的库&#xff1a; import pandas as pd import seaborn as sns import matplotlib…

unordered_map和unordered_set

目录 一、unordered_map 1.1、unordered_map的特点 1.2、unordered_map和map的区别 二、unordered_set 2.1、unordered_set的特点 2.2、unordered_set和set的区别 三、哈系桶的改造 3.1 结构设置 3.2 构造函数和析构函数 3.3 数据插入 3.4 数据查找 3.5 数据删除 …

STM32学习笔记三——深度讲解GPIO及其应用

目录 STM32GPIO端口位基本结构图&#xff1a; 结构图I/O引脚&#xff1a; GPIO输入输出总结 1.GPIO引脚的四种输入方式及其特点&#xff1a; 1)上拉输入(GPIO_Mode_IPU) 2)下拉输入(GPIO_Mode_IPD) 3)模拟输入(GPIO_Mode_AIN) 4)浮空输入(GPIO_Mode_IN_FLOATING…

【git】本地项目推送到github、合并分支的使用

1. github上创建仓库信息 点击个人头像&#xff0c;选择【你的仓库】 点击【新增】 填写仓库信息 2. 本地项目执行的操作 1.生成本地的git管理 (会生成一个.git的文件夹) git init 2.正常提交到暂存区&#xff0c;并填写提交消息 git add . git commit -m "init…

彻底学会系列:一、机器学习之线性回归

1.基本概念 线性回归&#xff1a; 有监督学习的一种算法。主要关注多个因变量和一个目标变量之间的关系。 因变量&#xff1a; 影响目标变量的因素&#xff1a; X 1 , X 2 . . . X_1, X_2... X1​,X2​... &#xff0c;连续值或离散值。 目标变量&#xff1a; 需要预测的值: t…

Openresty+Lua+Redis实现高性能缓存

一、背景 当我们的程序需要提供较高的并发访问时&#xff0c;往往需要在程序中引入缓存技术&#xff0c;通常都是使用Redis作为缓存&#xff0c;但是要再更进一步提升性能的话&#xff0c;就需要尽可能的减少请求的链路长度&#xff0c;比如可以将访问Redis缓存从Tomcat服务器…

MQ面试题整理(持续更新)

1. MQ的优缺点 优点&#xff1a;解耦&#xff0c;异步&#xff0c;削峰 缺点&#xff1a; 系统可用性降低 系统引入的外部依赖越多&#xff0c;越容易挂掉。万一 MQ 挂了&#xff0c;MQ 一挂&#xff0c;整套系统崩 溃&#xff0c;你不就完了&#xff1f;系统复杂度提高 硬生…

ES高可用架构涉及常用功能整理

ES高可用架构涉及常用功能整理 1. es的高可用系统架构和相关组件2. es的核心参数2.1 常规配置2.2 特殊优化配置2.2.1 数据分片按ip打散2.2.2 数据分片机架感知2.2.3 强制要求数据分片机架感知2.2.4 写入线程池优化2.2.5 分片balance优化2.2.6 限流控制器优化 3. es常用命令3.1 …

前缀和 acwing

思路&#xff1a;两个数组&#xff0c;一个数组用来保存数据&#xff0c;一个数组来求对应项的和 前缀和S[r]-s[r-1] 空出来下标0 从1开始 方便表示&#xff0c;防止越界 c代码实现: #include<iostream> using namespace std; const int N1000000; int a[N],s[N]; …

344. Reverse String(反转字符串)

题目描述 编写一个函数&#xff0c;其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。 不要给另外的数组分配额外的空间&#xff0c;你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。 问题分析 以中间字符为轴&#xff0c;将两边的字符对换…

CSS-IN-JS

CSS-IN-JS 为什么会有CSS-IN-JS CSS-IN-JS是web项目中将CSS代码捆绑在JavaScript代码中的解决方案。 这种方案旨在解决CSS的局限性&#xff0c;例如缺乏动态功能&#xff0c;作用域和可移植性。 CSS-IN-JS介绍 1&#xff1a;CSS-IN-JS方案的优点&#xff1a; 让css代码拥…

Java与SpringBoot:实现高效车险理赔信息管理系统

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

ArcGIS学习(三)数据可视化

ArcGIS学习(三)数据可视化 1.矢量数据可视化 需要提前说明的是,在ArcGIS中,所有的可视化选项设置都是在“图层属性”对话框里面的“符号系统”中实现的。 对于矢量数据的可视化,主要有四种可视化方式: 按“要素”可视化按“类别”可视化按“数量”可视化按“图表”可视…

【Elasticsearch】从入门到精通

目前java常见的针对大数据存储的方案并不多&#xff0c;常见的就是mysql的分库分表、es存储 这里偏向es存储方案&#xff0c;es不同的版本之间其实差异还挺大的&#xff0c;本篇博文版本Elasticsearch 7.14.0 Springboot整合Easy-Es Easy-Es官方文档 Elasticsearch的初步认识 …

机器翻译后的美赛论文怎么润色

美赛论文的语言表达一直是组委会看重的点&#xff0c;清晰的思路和地道的语言在评审中是重要的加分项。 今天我们就来讲讲美赛论文的语言问题。 我相信有相当一部分队伍在打美赛的时候&#xff0c;出于效率的考量&#xff0c;都会选择先写中文论文&#xff0c;再机翻成英文。 …

【蓝桥杯冲冲冲】[NOIP2003 普及组] 栈

蓝桥杯备赛 | 洛谷做题打卡day27 文章目录 蓝桥杯备赛 | 洛谷做题打卡day27题目背景题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示题解代码我的一些话 [NOIP2003 普及组] 栈 题目背景 栈是计算机中经典的数据结构&#xff0c;简单的说&#xff0c;栈就是限制在一…

Linux校准时间 Centos

Linux校准时间 Centos 首先&#xff0c;确保系统中已经安装了tzdata包。如果没有安装&#xff0c;可以使用以下命令安装&#xff1a; sudo yum install tzdata设置系统时区为上海&#xff1a; sudo timedatectl set-timezone Asia/Shanghai验证时区设置是否生效&#xff1a;…

图解支付-金融级密钥管理系统:构建支付系统的安全基石

经常在网上看到某某公司几千万的个人敏感信息被泄露&#xff0c;这要是放在持牌的支付公司&#xff0c;可能就是一个非常大的麻烦&#xff0c;不但会失去用户的信任&#xff0c;而且可能会被吊销牌照。而现实情况是很多公司的技术研发人员并没有足够深的安全架构经验来设计一套…

RK3568平台 设备模型基本框架-kobject 和kset

一.什么是设备模型 字符设备驱动通常适用于相对简单的设备&#xff0c;对于一些更复杂的功能&#xff0c;比如说电源管理和热插拔事件管理&#xff0c;使用字符设备框架可能不够灵活和高效。为了应对更复杂的设备和功能&#xff0c;Linux内核提供了设备模型。设备模型允许开发…