网站排名系统wordpress 面包屑导航修改

当前位置: 首页 > news >正文

网站排名系统,wordpress 面包屑导航修改,高端网站设计杭州,搜索引擎 网站模板文章目录 一#xff1a;前端页面回顾二#xff1a;博客功能展示三#xff1a;数据库表设计#xff08;1#xff09;表设计#xff08;2#xff09;封装DataSource 四#xff1a;实体类和数据访问对象#xff08;1#xff09;实体类#xff08;2#xff09;数据访问… 文章目录 一前端页面回顾二博客功能展示三数据库表设计1表设计2封装DataSource 四实体类和数据访问对象1实体类2数据访问对象 五各功能实现1登录功能2强制登录3博客列表页4博客详情页5显示用户信息和作者信息6注销7发布博客8删除博客 在Java高级教程第四章必备前端知识-最终节博客系统搭建页面设计部分中我们实现了一个博客系统的前端页面。这一节我们会结合Servlet和之前的前端页面搭建一个完整的博客系统。该博客系统十分简单虽然只包含下面最基础的功能但足以对我们之前学习内容进行串联 博客列表页展示博客详情页展示博客登录页用户登录在用户未登录并访问其他页面时强制要求登录显示用户信息作者信息注销登录发布博客删除博客 本文完整代码见Gihub仓库点击跳转 一前端页面回顾 博客登录页BlogLoginPage.html
博客列表页BlogListPage.html 博客详情页BlogDetailPage.html 博客编辑页BlogEditPage.html 二博客功能展示 博客登录和列表页展示 如果用户名或密码错误则会弹出提示框如果用户名和密码正确则登录成功并跳转至博客列表页 在用户未登录并访问其他页面时强制要求登录
博客列表页用户信息和博客详情页作者信息展示 某用户登录后在博客列表中要显示该登录用户的信息。他可以查看到所有博客内容部分博客是自己写的部分博客是别人写的当点击进入一篇具体的博客的详情后要展示该博客的作者信息 注销账户 当用户点击“注销账户”后就会退出登录并跳转至博客登录页 发布博客 当用户点击“开始创作”就会跳转至博客编辑页待用户写好博客标题和内容并点击标题右侧的“发布文章”后就会将该博客插入到数据库中发布成功后自动跳转至博客列表页 删除博客 当用户点击“删除文章”时就会将该博客删除然后跳转至博客列表页用户不能将别人的博客删除 三数据库表设计 1表设计 博客数据用户数据都是存储在数据库中的因此数据库表设计在很大程度上决定或影响了整个程序的编写。为此我们需要创建以下两张表 博客表blog blogId博客Idtitle博客标题content博客内容postTime博客插入数据库的时间发布时间userId用户Id 用户表user userId用户Idusername用户名password用户密码
SQL语句如下你可以在IDEA中创建一个后缀名为.sql的文件然后在这里面编写之后将所有SQL语句复制到终端即可 – 创建数据库
create database if not exists BlogSystem2; – 使用数据库
use BlogSystem2; drop table if exists blog; – 创建博客表blog
create table blog ( blogId int primary key auto_increment, title varchar(256), content text, postTime datetime, userId int
); – 创建用户表user
drop table if exists user;
create table user ( userId int primary key auto_increment, userName varchar(50) unique, passWord varchar(50)
); – 插入数据测试
insert into blog values(null, 第一篇博客, 今天我们介绍博客系统的实现, now(), 1);
insert into blog values(null, 第二篇博客, 今天我们再次介绍博客系统的实现, now(), 2);
insert into blog values(null, 第三篇博客, 今天我们第三次次介绍博客系统的实现, now(), 1);
insert into blog values(null, 第四篇博客, ### 第一任务内容 - asd1, now(), 2); insert into user values(1, 张三, 123);
insert into user values(2, 李四, 123);效果如下 2封装DataSource 在进行数据插入、删除等操作时会频繁设计如“获取数据源”、“建立连接”、“释放资源”等等重复操作所以我们可以将它们封装在一个DBUtil中。它要符合单例模式的设计结构 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/blogsystem2?characterEncodingutf8allowPublicKeyRetrievaltrueuseSSLfalseserverTimezoneUTC); ((MysqlDataSource)dataSource).setUser(root); ((MysqlDataSource)dataSource).setPassword(123456); } } } return dataSource; } private DBUtil() {}; // 建立连接 public static Connection getConnection() throws SQLException { return getDataSource().getConnection(); } // 释放资源 public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet) throws SQLException { 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 { statement.close(); } catch (SQLException e) { e.printStackTrace(); } } }
}四实体类和数据访问对象 1实体类 数据库中有什么样的表程序中就必须有对应的实体类。因此创建User类和Blog类并设置对应的get和set方法 注意Blog类中的postTime类型为时间戳Timestamp在获取时需要转换为对应的“年月日”等格式这里借助了SimpleDateFormat Blog类 import java.sql.Timestamp;
import java.text.SimpleDateFormat; 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 String getPostTime() { // 返回格式化好的字符串日期类型 SimpleDateFormat simpleDateFormat new SimpleDateFormat(yyyy年-MM月-dd日 HH:mm:ss); return simpleDateFormat.format(this.postTime); } public void setPostTime(Timestamp postTime) { this.postTime postTime; } public int getUserId() { return userId; } public void setUserId(int userId) { this.userId userId; }
}User类 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; }
}2数据访问对象 针对实体类肯定有各种各样的增删改查操作十分繁琐所以我们需要创建对应的数据访问对象(Data Access Object, DAO)。BlogDAO对应Blog类UserDAO对应User类 BlogDAO import java.beans.PropertyEditorSupport;
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 { // 插入博客到数据库中 public void insert(Blog blog) throws SQLException { Connection connection null; PreparedStatement statement null; try { // 获取数据源并连接 connection DBUtil.getConnection(); // 构造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()); // 执行SQL int ret statement.executeUpdate(); if (ret ! 1) { System.out.println(插入失败); } else { System.out.println(插入成功); } } catch (SQLException e) { e.printStackTrace(); } finally { // 释放资源 DBUtil.close(connection, statement, null); } } // 根据blogId查询指定博客 public Blog selectById(int blogId) throws SQLException { 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(); // 遍历结果如果有查询结果则返回 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)); return blog; } } catch (SQLException e) { e.printStackTrace(); } finally { DBUtil.close(connection, statement, resultSet); } return null; } // 查询所有博客 public ListBlog selectAll() throws SQLException { ListBlog blogs new ArrayList(); Connection connection null; PreparedStatement statement null; ResultSet resultSet null; 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)); // 注意为了避免因博客content太多而导致博客列表页博客摘要显示过长 // 规定当content长度大于100时只显示部分内容用户如果想要查看完整内容则需要点击按钮 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) { e.printStackTrace(); } finally { DBUtil.close(connection, statement, resultSet); } return blogs; } // 根据blogId删除博客 (删除博客) public void delete (int blogId) throws SQLException { 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); int ret statement.executeUpdate(); if (ret ! 1) { System.out.println(删除失败); } else { System.out.println(删除成功); } } catch (SQLException e) { e.printStackTrace(); } finally { 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 { // 根据用户名查询用户
public User selectByUserName(String userName) throws SQLException { 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; } // 根据userId查询用户 public User selectByUserId(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; }
}五各功能实现 这里是博客系统实现最复杂的地方要搭建一个完整的博客系统就要处理后前后端交互的逻辑。也即页面发起HTTP请求然后服务器返回HTTP响应。我们只需要约定后请求和响应分别是什么样的然后按照需求分别编写前端页面和后端服务即可 1登录功能 处理逻辑当用户输入用户名和密码并点击登录后就会发送请求给服务器服务器负责验证。如果验证成功则让页面跳转至博客列表页否则弹出提示让其重新登录 请求 POST/loginContent-Typeapplication/x-www-form-urlencoded 响应 HTTP/1.1 302Location:博客列表页
前端页面BlogLoginPage.html !DOCTYPE html
html langen
head meta charsetUTF-8 title登录页/title link relstylesheet hrefcss/Common.css link relstylesheet hrefcss/Blog_login.css /head
body
!–导航栏–
div classnav img srcimage/电子书.png alt span classtitle博客之家·文行天下/span /div !–登录框–
div classcontainer !–登录对话框– form actionlogin methodpost div classdialog h3登录你的账户/h3 div classrow span用户名/span input typetext required nameusername /div div classrow span密nbspnbspnbsp码/span input typepassword required namepassword /div div classrow button idlogin登录/button /div /div /form /div script srchttp://libs.baidu.com/jquery/2.0.0/jquery.min.js/script
script \((document).ready(function() { \)(#login).click(function(event) { event.preventDefault(); // 阻止表单默认提交行为 var username \((input[nameusername]).val(); var password \)(input[namepassword]).val(); \(.ajax({ url: login, type: post, data: { username: username, password: password }, success: function(body) { alert(登录成功); // 重定向到博客列表页 location.assign(/BlogSystem2/BlogListPage.html); }, error: function(body) { alert(用户名或密码为空请重新输入); } }); }); }); /script /body /html后端LoginServlet.java import com.fasterxml.jackson.databind.ObjectMapper; 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.util.HashMap; import java.util.Map; WebServlet(/login) public class LoginServlet extends HttpServlet { Override // 登录功能 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 获取用户名和密码 req.setCharacterEncoding(utf-8); String username req.getParameter(username); String password req.getParameter(password); if (username null || .equals(username) || password null || .equals(password)) { resp.setContentType(text/html; charsetutf-8); resp.getWriter().write(登录失败用户名或密码为空); resp.setStatus(403); return; } // 查询数据库验证用户名和密码是否正确 UserDAO userDAO new UserDAO(); User user null; try { user userDAO.selectByUserName(username); if (user null || !user.getPassWord().equals(password)) { resp.setContentType(text/html; charsetutf-8); resp.getWriter().write(登录失败用户名或密码错误); resp.setStatus(401); return; } } catch (SQLException e) { e.printStackTrace(); } // 如果正确则创建一个会话对象,保证在访问其他页面时可以直接判定是哪个用户在访问 HttpSession session req.getSession(true); session.setAttribute(user, user); } }2强制登录 处理逻辑在博客列表页、详情页和编辑页加载后会发起一个ajax请求从服务器获取登录状态如果是未登录状态则提示并重定向到登录页面如果已经登录则不做任何改变 请求 GET/login 响应 如果已经登录HTTP/1.1 200 OK如果未登录HTTP/1.1 403 前端页面BlogDetailPage.html、BlogEditPage.html、BlogListPage.html需要使用下面的js函数 function getLoginStatus() { \).ajax({ type: get, url: login, success: function (body) { // 已经在登录状态不处理 }, error: function () { // 非登录或其他状态则强行跳转 alert(未登录请登录后再访问) location.assign(BlogLoginPage.html) } });
}后端LoginServlet.java import com.fasterxml.jackson.databind.ObjectMapper; 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.util.HashMap;
import java.util.Map; WebServlet(/login)
public class LoginServlet extends HttpServlet { Override // 登录功能 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 获取用户名和密码 req.setCharacterEncoding(utf-8); String username req.getParameter(username); String password req.getParameter(password); if (username null || .equals(username) || password null || .equals(password)) { resp.setContentType(text/html; charsetutf-8); resp.getWriter().write(登录失败用户名或密码为空); resp.setStatus(403); return; } // 查询数据库验证用户名和密码是否正确 UserDAO userDAO new UserDAO(); User user null; try { user userDAO.selectByUserName(username); if (user null || !user.getPassWord().equals(password)) { resp.setContentType(text/html; charsetutf-8); resp.getWriter().write(登录失败用户名或密码错误); resp.setStatus(401); return; } } catch (SQLException e) { e.printStackTrace(); } // 如果正确则创建一个会话对象,保证在访问其他页面时可以直接判定是哪个用户在访问 HttpSession session req.getSession(true); session.setAttribute(user, user); } Override // 防止未登录直接访问 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 获取会话 HttpSession session req.getSession(false); // 没有会话则为未登录 if (session null) { resp.setStatus(403); return; } // 如果有会话则已经登录获取用户 User user (User)session.getAttribute(user); // 这里是为了结合注销逻辑注销时会直接删除user if (user null) { resp.setStatus(403); return; } // 返回200 resp.setStatus(200); }
}3博客列表页 处理逻辑当博客列表页加载时就发起请求从数据库中获取博客数据然后展示 请求 GET/blog 响应 HTTP/1/1 200okContent-Type:application
前端页面BlogListPage.html !DOCTYPE html
html langen
head meta charsetUTF-8 title博客列表/title link relstylesheet hrefcss/Common.css link relstylesheet hrefcss/Blog_list.css /head
body !–导航栏–
div classnav img srcimage/电子书.png alt span classtitle博客之家·文行天下/span !– 用于占位 – div classspace/div a hrefBlogListPage.html博客主页/a a hreflogout注销账户/a div classcreatinga hrefBlogEditPage.html开始创作/a/div /div !–版心区域–
div classcontainer !– 用户信息 – div class left div classcard !– 用户头像 – img srcimage/头像.png alt !– 用户名字 – h3/h3 !– Github地址 – a href#进入Github主页/a div classcounter span文章/span span分类/span /div div classcounter span2/span span1/span /div /div /div !– 博文列表 – div class right !– 每个blog是一篇博文 – !– div classblog div classtitle我的第一篇博客/div div classdate2023-03-13 06:00:00/div div classdesc 在这个充满机遇和挑战的时代我们需要不断地学习和成长。 只有不断地提升自己的能力才能够适应未来社会的发展趋势 并且取得更好的成就。无论是在工作中还是生活中 都需要具备一定的技能和知识储备以便更好地解决问题并迎接新挑战 /div div classclicka hrefBlogDetailPage.html查看全文/a/div /div– /div
/div script srchttp://libs.baidu.com/jquery/2.0.0/jquery.min.js/script
script srcjs/app.js/script script // 利用ajax发送请求从服务器获取博文数据 function getBlogs() { \(.ajax({ type: get, url: blog, success: function(body) { // 如果成功那么body就是一个json对象数组每个元素为一个博客 let container document.querySelector(.right) for (let blog of body) { // blogDiv let blogDiv document.createElement(div); blogDiv.className blog; // 博客标题 let titleDiv document.createElement(div); titleDiv.className title; titleDiv.innerHTML blog.title; // 博客日期 let dateDiv document.createElement(div); dateDiv.className title; dateDiv.innerHTML blog.postTime; // 博客摘要 let descDiv document.createElement(div); descDiv.className desc; descDiv.innerHTML blog.content; // 查看全文按钮 let a document.createElement(a); a.href BlogDetailPage.html?blogId blog.blogId; a.innerHTML 查看全文; // 点击按钮 let clickdiv document.createElement(div); clickdiv.className click; // 拼接 blogDiv.appendChild(titleDiv); blogDiv.appendChild(dateDiv); blogDiv.appendChild(descDiv); clickdiv.appendChild(a); blogDiv.appendChild(clickdiv); container.appendChild(blogDiv); } } }); } getBlogs(); // 获取登录状态判断是否登录 getLoginStatus(); /script /body /html后端BlogServlet.java import com.fasterxml.jackson.databind.ObjectMapper;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.util.List;// 博客列表页和博客详情页请求处理 WebServlet(/blog) public class BlogServlet extends HttpServlet {private ObjectMapper objectMapper new ObjectMapper();Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 按照约定的接口格式返回数据resp.setContentType(application/json; charsetutf-8);BlogDAO blogDAO new BlogDAO();String blogId req.getParameter(blogId);try {ListBlog blogs blogDAO.selectAll();resp.getWriter().write(objectMapper.writeValueAsString(blogs));} catch (SQLException e) {e.printStackTrace();}}} 4博客详情页 处理逻辑当在博客列表页中点击“查看全文”时就会跳转至该博客对应的详情页。在请求对应详情页面时需要在请求的url处加上query_string例如http://localhost:8080/BlogSystem2/BlogDetailPage.html?blogId2就表示请求的是blogId2的详情页 请求 GET/blogId1 响应 HTTP/1.1 200 OKContent-Typeapplocation/json 需要注意的是在博客列表页中我们已经使用了BlogServlet.doGet方法了如果博客列表页也想要使用的话就要作出区分。具体来说如果请求带有queryString有blogId这个参数就认为这是博客详情页的请求否则则认为是博客列表页的请求 前端页面BlogDetailPage.html !DOCTYPE html html langen headmeta charsetUTF-8title博客详情/titlelink relstylesheet hrefcss/Common.csslink relstylesheet hrefcss/Blog_detail.css!-- 引入 editor.md 的依赖 --link relstylesheet hrefeditor.md/css/editormd.min.css /script srchttps://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js/scriptscript srceditor.md/lib/marked.min.js/scriptscript srceditor.md/lib/prettify.min.js/scriptscript srceditor.md/editormd.js/script/headbody div classnavimg srcimage/电子书.png altspan classtitle博客之家·文行天下/span!-- 用于占位 --div classspace/diva hrefBlogListPage.html博客主页/aa hreflogout注销账户/adiv classcreatinga hrefBlogEditPage.html开始创作/a/divdiv classdeletinga hrefblog_delete iddelete-btn删除文章/a/div/div!--版心区域-- div classcontainer!-- 用户信息 --div class leftdiv classcard!-- 用户头像 --img srcimage/头像.png alt!-- 用户名字 --h3/h3!-- Github地址 --a href#进入Github主页/adiv classcounterspan文章/spanspan分类/span/divdiv classcounterspan2/spanspan1/span/div/div/div!-- 博文详情 --div class rightdiv classblog_detailh3/h3div classdate/divdiv idcontent stylebackground-color: transparent/div/div/divscript srchttps://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js/scriptscript srcjs/app.js/scriptscript!-- 利用ajax服务器获取该博客数据--function getBlog() {\).ajax({type: get,// location.search可以返回query-stringurl : blog location.search,success: function (body) {let h3 document.querySelector(.blog_detail h3);h3.innerHTML body.title;let dateDiv document.querySelector(.date);dateDiv.innerHTML body.postTime;// 此处应该使用editor.md对markdown内容进行渲染editormd.markdownToHTML(content, {markdown: body.content});}});}getBlog();getLoginStatus();/script/body /html后端BlogServlet.java import com.fasterxml.jackson.databind.ObjectMapper;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.util.List;// 博客列表页和博客详情页请求处理 WebServlet(/blog) public class BlogServlet extends HttpServlet {private ObjectMapper objectMapper new ObjectMapper();Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 按照约定的接口格式返回数据resp.setContentType(application/json; charsetutf-8);BlogDAO blogDAO new BlogDAO();String blogId req.getParameter(blogId);if (blogId null) {// 这是博客列表页请求try {ListBlog blogs blogDAO.selectAll();resp.getWriter().write(objectMapper.writeValueAsString(blogs));} catch (SQLException e) {e.printStackTrace();}} else {// 这是博客详情页请求try {Blog blog blogDAO.selectById(Integer.parseInt(blogId));resp.getWriter().write(objectMapper.writeValueAsString(blog));} catch (SQLException e) {e.printStackTrace();}}} } 5显示用户信息和作者信息 处理逻辑 在博客列表页加载时从服务器获取当前登录的用户信息然后将信息展现在页面之上 请求 GET/userinfo 响应 HTTP/1.1 200OKcontent-Type:application/json 在博客详情页加载时从服务器获取博客的作者信息然后展现在页面智商 请求 GET/userinfo?blogId1 响应 Content-Type:application/json
前端页面BlogListPage.html和BlogDetailPage.html !DOCTYPE html html langen headmeta charsetUTF-8title博客列表/titlelink relstylesheet hrefcss/Common.csslink relstylesheet hrefcss/Blog_list.css/head body!–导航栏– div classnavimg srcimage/电子书.png altspan classtitle博客之家·文行天下/span!– 用于占位 –div classspace/diva hrefBlogListPage.html博客主页/aa hreflogout注销账户/adiv classcreatinga hrefBlogEditPage.html开始创作/a/div/div!–版心区域– div classcontainer!– 用户信息 –div class leftdiv classcard!– 用户头像 –img srcimage/头像.png alt!– 用户名字 –h3/h3!– Github地址 –a href#进入Github主页/adiv classcounterspan文章/spanspan分类/span/divdiv classcounterspan2/spanspan1/span/div/div/div!– 博文列表 –div class right!– 每个blog是一篇博文 –!– div classblogdiv classtitle我的第一篇博客/divdiv classdate2023-03-13 06:00:00/divdiv classdesc在这个充满机遇和挑战的时代我们需要不断地学习和成长。只有不断地提升自己的能力才能够适应未来社会的发展趋势并且取得更好的成就。无论是在工作中还是生活中都需要具备一定的技能和知识储备以便更好地解决问题并迎接新挑战/divdiv classclicka hrefBlogDetailPage.html查看全文/a/div/div–/div /divscript srchttp://libs.baidu.com/jquery/2.0.0/jquery.min.js/script script srcjs/app.js/scriptscript// 利用ajax发送请求从服务器获取博文数据function getBlogs() {………..}getBlogs();// 获取登录状态判断是否登录getLoginStatus();// 针对博客列表页获取当前用户的登录信息function getUserInfo() {\(.ajax({type: get,url: userInfo,success: function(body) {let h3 document.querySelector(.left.cardh3);h3.innerHTML body.userName;}});}getUserInfo(); /script/body /html!DOCTYPE html html langen headmeta charsetUTF-8title博客详情/titlelink relstylesheet hrefcss/Common.csslink relstylesheet hrefcss/Blog_detail.css!-- 引入 editor.md 的依赖 --link relstylesheet hrefeditor.md/css/editormd.min.css /script srchttps://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js/scriptscript srceditor.md/lib/marked.min.js/scriptscript srceditor.md/lib/prettify.min.js/scriptscript srceditor.md/editormd.js/script/headbody div classnavimg srcimage/电子书.png altspan classtitle博客之家·文行天下/span!-- 用于占位 --div classspace/diva hrefBlogListPage.html博客主页/aa hreflogout注销账户/adiv classcreatinga hrefBlogEditPage.html开始创作/a/divdiv classdeletinga hrefblog_delete iddelete-btn删除文章/a/div/div!--版心区域-- div classcontainer!-- 用户信息 --div class leftdiv classcard!-- 用户头像 --img srcimage/头像.png alt!-- 用户名字 --h3/h3!-- Github地址 --a href#进入Github主页/adiv classcounterspan文章/spanspan分类/span/divdiv classcounterspan2/spanspan1/span/div/div/div!-- 博文详情 --div class rightdiv classblog_detailh3/h3div classdate/divdiv idcontent stylebackground-color: transparent/div/div/divscript srchttps://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js/scriptscript srcjs/app.js/scriptscript!-- 利用ajax服务器获取该博客数据--function getBlog() {.........}getBlog();getLoginStatus();// 针对博客详情页获取当前用户信息function getUserInfo() {\).ajax({type: get,url: userInfo location.search,success: function(body) {let h3 document.querySelector(.left.cardh3);h3.innerHTML body.userName;}});}getUserInfo();// 博文删除为其赋上blogIdfunction updateDeleteURL() {let DeleteBtn document.querySelector(#delete-btn);DeleteBtn.href blog_delete location.search;}updateDeleteURL();/script/body /html后端UserInfoServlet.java import com.fasterxml.jackson.databind.ObjectMapper; 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; WebServlet(/userInfo)
public class UserInfoServlet extends HttpServlet { private ObjectMapper objectMapper new ObjectMapper(); Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String blogId req.getParameter(blogId); if (blogId null) { // 这是列表页在请求直接从session中获取即可 getUserInfoFromSession(req, resp); } else { // 这是详情页在请求查询数据库 try { getUserInfoFromDB(req, resp, Integer.parseInt(blogId)); } catch (SQLException e) { throw new RuntimeException(e); } } } private void getUserInfoFromDB(HttpServletRequest req, HttpServletResponse resp, int blogId) throws SQLException, IOException { // 根据blogId查询Blog对象获取userId BlogDAO blogDAO new BlogDAO(); Blog blog blogDAO.selectById(blogId); if (blog null) { // 未找到这样的blog resp.setStatus(404); resp.setContentType(text/html; charsetutf-8); resp.getWriter().write(blogId不存在); return; } // 根据userId查询对应的User对象 UserDAO userDAO new UserDAO(); User user userDAO.selectByUserId(blog.getUserId()); if (user null) { resp.setStatus(404); resp.setContentType(text/html; charsetutf-8); resp.getWriter().write(userId不存在); return; } // 将user对象返回 user.setPassWord(); resp.setContentType(application/json; charsetutf-8); resp.getWriter().write(objectMapper.writeValueAsString(user)); } private void getUserInfoFromSession(HttpServletRequest req, HttpServletResponse resp) throws IOException { HttpSession session req.getSession(false); if (session null) { resp.setStatus(403); resp.setContentType(text/html;charsetutf-8); resp.getWriter().write(当前未登录); return; } User user (User)session.getAttribute(user); if (user null) { resp.setStatus(403); resp.setContentType(text/html;charsetutf-8); resp.getWriter().write(当前未登录); return; } // 移除password避免返回密码 user.setPassWord(); resp.setContentType(application/json;charsetutf-8); resp.getWriter().write(objectMapper.writeValueAsString(user)); }
}6注销 处理逻辑点击博客列表页、博客详情页和博客编辑页导航栏中的注销按钮后会向服务器发送一个HTTP请求不是ajax请求告诉服务器准备退出登录然后服务器会把会话中的user对象删除同时重定向的登录页。需要注意的是这里删除的user对象而不是session对象因为HttpSession没有一个直接用于删除的方法 请求 GET/logout 响应 HTTP/1.1 302Location:login.html
前端页面BlogDetailPage.html、BlogEditPage.html、BlogListPage.html只需要再路径处填入logout即可 div classnav img srcimage/电子书.png alt span classtitle博客之家·文行天下/span !– 用于占位 – div classspace/div a hrefBlogListPage.html博客主页/a a hreflogout注销账户/a div classcreatinga hrefBlogEditPage.html开始创作/a/div div classdeletinga hrefblog_delete iddelete-btn删除文章/a/div /div后端LogOutServlet.java 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.setStatus(403); return; } // 由于在判定是否登录的逻辑中要求会话和user必须同时存在所以在这里我们可以直接删除user即可 session.removeAttribute(user); // 重定向到登录页面 resp.sendRedirect(BlogLoginPage.html); }
}7发布博客 处理逻辑用户在博客编辑页中填写标题和内容后点击”发布文章“按钮此时会发起一个HTTP请求。当服务器收到这些数据后会构造一个blog对象然后插入数据库。 发布成功后跳转至列表页 请求 post/blogContent-Typeapplication.x-www-from-urlencoded 响应 HTTP/1.1 032Location:blog_list.html
前端页面BlogEditPage.html !DOCTYPE html
html langen
head meta charsetUTF-8 title编辑博客/title link relstylesheet hrefcss/Common.css link relstylesheet hrefcss/Blog_edit.css !– 引入 editor.md 的依赖 – link relstylesheet hrefeditor.md/css/editormd.min.css / script srchttps://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js/script script srceditor.md/lib/marked.min.js/script script srceditor.md/lib/prettify.min.js/script script srceditor.md/editormd.js/script /head
body div classnav img srcimage/电子书.png alt span classtitle博客之家·文行天下/span !– 用于占位 – div classspace/div a hrefBlogListPage.html博客主页/a a hreflogout注销账户/a div classcreatinga hrefBlogEditPage.html开始创作/a/div /div !–markdown编辑器区域–
div classcontainer !–标题编辑区– div classtitle input typetext idtitle-input placeholder在这里输入博客标题100字以内 button idtitle-submit发布文章/button /div !–正文编辑区– div ideditor /div /div script srcjs/app.js/script
script // 初始化编辑器, 代码也是截取自 官方文档 . var editor editormd(editor, { // 这里的尺寸必须在这里设置. 设置样式会被 editormd 自动覆盖掉. width: 100%, // 设定编辑器高度 height: calc(100% - 50px), // 编辑器中的初始内容 markdown: ## hello world, // 指定 editor.md 依赖的插件路径 path: editor.md/lib/, // 发布文章 // saveHTMLToTextarea: true, }); getLoginStatus(); // 发布博客 \((document).ready(function() { // 当点击发布文章按钮时执行 \)(#title-submit).click(function() { // 获取博客标题和内容 let title \((#title-input).val(); let content editor.getMarkdown(); // 假设你已经初始化了editor.md并赋给了变量editor console.log(content); // 创建一个包含标题和内容的对象 let postData { title: title, content: content }; // 发送POST请求 \).ajax({ type: POST, url: blog, // 替换成你的服务器端处理请求的URL data: JSON.stringify(postData), // 将数据转换为JSON格式 contentType: application/json, success: function(response) { // 请求成功处理 location.assign(/BlogSystem2/BlogListPage.html); }, error: function(error) { // 请求失败处理 console.error(文章发布失败, error); } }); }); }); /script /body
/html后端BlogServlet.java import com.fasterxml.jackson.databind.ObjectMapper;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.util.List;// 博客列表页和博客详情页请求处理 WebServlet(/blog) public class BlogServlet extends HttpServlet {private ObjectMapper objectMapper new ObjectMapper();Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 按照约定的接口格式返回数据…………}//提交新博客Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 获取会话和用户信息/按照道理来说这里不需要在判定登录了。因为既然能发起Post请求说明已经登录了但是有人可能会利用postman等工具收到发起Post请求同时要构造博客对象必须知道现在谁在登录才能知道文章作者是谁/HttpSession session req.getSession(false);if (session null) {resp.setStatus(403);resp.setContentType(text/html; charsetutf-8);resp.getWriter().write(未登录请登录后再访问);return;}User user (User)session.getAttribute(user);if (user null) {resp.setStatus(403);resp.setContentType(text/html; charsetutf-8);resp.getWriter().write(未登录请登录后再访问);return;}// 获取博客标题和正文req.setCharacterEncoding(utf-8);// 从请求体中获取JSON数据并解析为Blog对象ObjectMapper objectMapper new ObjectMapper();Blog blog objectMapper.readValue(req.getReader(), Blog.class);// 设置博客的用户ID为当前用户的IDblog.setUserId(user.getUserId());// 构造Blog对象并插入到数据库中BlogDAO blogDAO new BlogDAO();try {blogDAO.insert(blog);} catch (SQLException e) {throw new RuntimeException(e);}// 发布成功后重定向到列表页resp.sendRedirect(BlogListPage.html);} } 8删除博客 处理逻辑当点击博客详情页上的“删除文章”后服务器会做出一个判定如果当前登录的用户就是文章的作者才能真正删除 请求 GET/bloh_delete?blogId1 响应 删除成功 HTTP/1.1 302Location:blog_list.html 删除失败 HTTP/1.1 302没有删除权限
前端页面BlogDetailPage.html !DOCTYPE html html langen headmeta charsetUTF-8title博客详情/titlelink relstylesheet hrefcss/Common.csslink relstylesheet hrefcss/Blog_detail.css!– 引入 editor.md 的依赖 –link relstylesheet hrefeditor.md/css/editormd.min.css /script srchttps://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js/scriptscript srceditor.md/lib/marked.min.js/scriptscript srceditor.md/lib/prettify.min.js/scriptscript srceditor.md/editormd.js/script/headbody div classnavimg srcimage/电子书.png altspan classtitle博客之家·文行天下/span!– 用于占位 –div classspace/diva hrefBlogListPage.html博客主页/aa hreflogout注销账户/adiv classcreatinga hrefBlogEditPage.html开始创作/a/divdiv classdeletinga hrefblog_delete iddelete-btn删除文章/a/div/div!–版心区域– div classcontainer!– 用户信息 –div class leftdiv classcard!– 用户头像 –img srcimage/头像.png alt!– 用户名字 –h3/h3!– Github地址 –a href#进入Github主页/adiv classcounterspan文章/spanspan分类/span/divdiv classcounterspan2/spanspan1/span/div/div/div!– 博文详情 –div class rightdiv classblog_detailh3/h3div classdate/divdiv idcontent stylebackground-color: transparent/div/div/divscript srchttps://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js/scriptscript srcjs/app.js/scriptscript!– 利用ajax服务器获取该博客数据–function getBlog() {……}getBlog();getLoginStatus();// 针对博客详情页获取当前用户信息function getUserInfo() {……}getUserInfo();// 博文删除为其赋上blogIdfunction updateDeleteURL() {let DeleteBtn document.querySelector(#delete-btn);DeleteBtn.href blog_delete location.search;}updateDeleteURL();/script/body /html后端BlogServlet.java 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; WebServlet(/blog_delete)
public class BlogDeleteServlet extends HttpServlet { Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 判定用户登录状态 HttpSession session req.getSession(false); if (session null) { resp.setStatus(403); resp.setContentType(text/html; charsetutf-8); resp.getWriter().write(未登录请登录后再访问); return; } User user (User)session.getAttribute(user); if (user null) { resp.setStatus(403); resp.setContentType(text/html; charsetutf-8); resp.getWriter().write(未登录请登录后再访问); return; } // 获取blogId String blogId req.getParameter(blogId); if (user null) { // 没有这样的blogId resp.setStatus(404); resp.setContentType(text/html; charsetutf-8); resp.getWriter().write(blogId有误); return; } // 获取对应Blog BlogDAO blogDAO new BlogDAO(); Blog blog null; try { blog blogDAO.selectById(Integer.parseInt(blogId)); if (blog null) { // 没有这样的blog resp.setStatus(404); resp.setContentType(text/html; charsetutf-8); resp.getWriter().write(当前删除的博客不存在); return; } } catch (SQLException e) { throw new RuntimeException(e); } // 判断登录用户是否就是文章作者 if (blog.getUserId() ! user.getUserId()) { // 不能删除别人的博客 resp.setStatus(404); resp.setContentType(text/html; charsetutf-8); resp.getWriter().write(禁止删除他人博客); return; } // 实际删除 try { blogDAO.delete(Integer.parseInt(blogId)); } catch (SQLException e) { throw new RuntimeException(e); } // 重定向 resp.sendRedirect(BlogListPage.html); }
}