目录
前言
目前为止,已经学完了前端知识和部分的后端知识,现在,基于所学知识,实现一个简易的个人博客系统,技术栈后端为Tomcat+Servlet+Mysql,前端为css+html+js
创建maven项目
创建目录,引入依赖
数据库的设计
整个博客系统所用到的有两个表:博客表和用户表
博客表
blog(blogId,title,content,postTime,useId)
用户表
user(userId,username,password)
create database if not exists java105_blog_system;
use java105_blog_system;
drop table if exists blog;
create table blog (
blogId int primary key auto_increment,
title varchar(256),
content text,
postTime datetime,
-- userId 就是文章作者的用户 id
userId int
);
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, "这是第一篇博客", "Byeon BAEK HYUN, born on May 6, 1992 in Bucheon, Gyeonggi Province, South Korea, is a South Korean male singer and actor, member of male singing groups EXO, EXO-K, EXO-CBX and SuperM.", '2022-11-24 20:00:00', 1);
insert into blog values(null, "这是第二篇博客", "都敬秀,艺名D.O.(包括两个大写字母和两个标点符号),曾用名都暻秀,1993年1月12日出生于韩国日山,韩国男歌手、演员。2012年2月15日,D.O.通过Teaser正式被公开;同年4月8日,作为组合EXO/EXO-K的成员出道,在组合中担任主唱、EXO-K第三领舞,擅长欧美R&B式唱腔。", '2022-11-25 20:00:00', 1);
insert into blog values(null, "这是第三篇博客", "朴灿烈(박찬열、Park Chanyeol),1992年11月27日出生于韩国首尔,仁荷大学研究生在读,韩国男子演唱组合EXO、EXO-K、EXO-SC成员,韩国男歌手、演员。2012年4月8日,随EXO-K发行首张迷你专辑《MAMA》并正式出道。", '2022-11-26 20:00:00', 1);
insert into user values(null, "啵啵", "123");
insert into user values(null, "嘟嘟", "123");
封装数据库的操作代码
1、创建DBUtil类
用来封装数据库的DataSource
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;
/**
* @author krystal
* @date 2022/12/2 13:01
* 博客系统
*/
//通过这个类来封装DataSource
public class DBUtil {
private static DataSource dataSource=null;
public 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/java105_blog_system?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");
((MysqlDataSource)dataSource).setPassword("19930112");
}
}
}
return dataSource;
}
public static Connection getConnection() throws SQLException {
return getDataSource().getConnection();
}
public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet){
if (resultSet!=null){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (statement!=null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (resultSet!=null){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
2、创建Blog
代表一篇博客
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
/**
* @author krystal
* @date 2022/12/2 15:19
* 博客系统
*/
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("yy-MM-dd HH:mm:ss");
return simpleDateFormat.format(postTime);
}
public void setPostTime(Timestamp postTime) {
this.postTime = postTime;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
}
3、创建User
代表一个用户
/**
* @author krystal
* @date 2022/12/2 15:19
* 博客系统
*/
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;
}
}
4、创建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;
/**
* @author krystal
* @date 2022/12/2 15:44
* 博客系统
*/
//封装针对博客表的相关操作
public class BlogDao {
//1、插入一个博客到数据库中-发布博客
public void insert(Blog blog){
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
int ret=statement.executeUpdate();
if (ret!=1){
System.out.println("博客插入失败!");
}else {
System.out.println("博客插入成功!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
//4、释放相应的资源
DBUtil.close(connection,statement,null);
}
}
//2、根据博客id来查询指定博客-博客详情页
public Blog selectOne(int blogId){
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();
//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"));
return blog;
}
} catch (SQLException e) {
e.printStackTrace();
}
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 order by postTime desc";
statement=connection.prepareStatement(sql);
//3、执行sql
resultSet=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) {
e.printStackTrace();
}
return blogs;
}
//4、删除指定博客
public void delete(int blogId){
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
int ret=statement.executeUpdate();
if (ret!=1){
System.out.println("博客删除失败!");
}else {
System.out.println("博客删除成功!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
//4、释放相应的资源
DBUtil.close(connection,statement,null);
}
}
}
5、创建UserDao
针对用户表进行增查操作
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* @author krystal
* @date 2022/12/2 15:55
* 博客系统
*/
public class UserDao {
//根据用户名来查询用户的详情
public User selectByName(String username){
Connection connection=null;
PreparedStatement statement=null;
ResultSet resultSet=null;
try {
//1、和数据库建立连接
connection=DBUtil.getConnection();
//2、构造sql
String sql="select * from user where username=?";
statement=connection.prepareStatement(sql);
statement.setString(1,username);
//3、执行sql
resultSet=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) {
e.printStackTrace();
}
return null;
}
//根据用户id来查询用户详情
public User selectById(int userId){
Connection connection=null;
PreparedStatement statement=null;
ResultSet resultSet=null;
try {
//1、和数据库建立连接
connection=DBUtil.getConnection();
//2、构造sql
String sql="select * from user where userId=?";
statement=connection.prepareStatement(sql);
statement.setInt(1,userId);
//3、执行sql
resultSet=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) {
e.printStackTrace();
}
return null;
}
}
博客系统的前端代码
1、博客列表页
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>博客列表</title>
<link rel="stylesheet" href="css/common.css">
<link rel="stylesheet" href="css/blog_list.css">
</head>
<body>
<div class="nav">
<img src="img/logo1.jpg" alt="">
<span class="title">我的博客系统</span>
<!-- spacer不显示内容,占位 -->
<div class="spacer"></div>
<a href="blog_list.html">主页</a>
<a href="blog_edit.html">写博客</a>
<a href="#">注销</a>
</div>
<!-- 这个div表示页面的主区域(版心) -->
<div class="container">
<!-- 左侧内容区域 -->
<div class="container-left">
<!-- 用这个表示用户的信息 -->
<div class="card">
<!--用户头像-->
<img src="img/logo3.jpg" alt="">
<!-- 用户名字 -->
<h3>啵啵虎的抽抽</h3>
<a href="#">github地址</a>
<div class="counter">
<span>文章</span>
<span>分类</span>
</div>
<div class="counter">
<span>2</span>
<span>1</span>
</div>
</div>
</div>
<!-- 右侧内容区域 -->
<div class="container-right">
<!-- 每个.blog代表一篇博客 -->
<div class="blog">
<a href="blog_detail.html">查看全文 >></a>
</div>
</div>
</div>
</body>
</html>
2、博客详情页
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>博客详情</title>
<link rel="stylesheet" href="css/common.css">
<link rel="stylesheet" href="css/blod_detail.css">
</head>
<body>
<div class="nav">
<img src="img/logo1.jpg" alt="">
<span class="title">我的博客系统</span>
<!-- spacer不显示内容,占位 -->
<div class="spacer"></div>
<a href="blog_list.html">主页</a>
<a href="blog_edit.html">写博客</a>
<a href="#">注销</a>
</div>
<!-- 这个div表示页面的主区域(版心) -->
<div class="container">
<!-- 左侧内容区域 -->
<div class="container-left">
<!-- 用这个表示用户的信息 -->
<div class="card">
<!--用户头像-->
<img src="img/logo3.jpg" alt="">
<!-- 用户名字 -->
<h3>啵啵虎的抽抽</h3>
<a href="#">github地址</a>
<div class="counter">
<span>文章</span>
<span>分类</span>
</div>
<div class="counter">
<span>2</span>
<span>1</span>
</div>
</div>
</div>
<!-- 右侧内容区域 -->
<div class="container-right">
<div class="blog_detail">
<h3>我的第一篇博客</h3>
<div class="date">1992-5-4 00.00.00</div>
<p>
边伯贤,艺名BAEK HYUN,1992年5月6日生于韩国京畿道富川市,韩国男歌手、演员,男子演唱组合EXO、EXO-K、EXO-CBX、SuperM成员。
</p>
</div>
</div>
</body>
</html>
3、登录页
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>登录页面</title>
<link rel="stylesheet" href="css/common.css">
<link rel="stylesheet" href="css/login.css">
</head>
<body>
<div class="nav">
<img src="img/logo1.jpg" alt="">
<span class="title">我的博客系统</span>
<!-- spacer不显示内容,占位 -->
<div class="spacer"></div>
<a href="blog_list.html">主页</a>
<a href="blog_edit.html">写博客</a>
<a href="#">注销</a>
</div>
<!-- 用这个元素作为页面的版心 -->
<div class="login-container">
<!-- 登录对话框 -->
<div class="dialog">
<h3>登录</h3>
<div class="row">
<span>用户名</span>
<input type="text" id="username">
</div>
<div class="row">
<span>密码</span>
<input type="password" id="password">
</div>
<div class="row">
<button id="login-btn">登录</button>
</div>
</div>
</div>
</body>
</html>
4、博客编辑页
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>博客编辑</title>
<link rel="stylesheet" href="css/common.css">
<link rel="stylesheet" href="css/blog_edit.css">
<!-- 引入 editor.md 的依赖 -->
<link rel="stylesheet" href="editor.md/css/editormd.min.css" />
<!-- <script src="js/jquery.min.js"></script> -->
<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="editor.md/lib/marked.min.js"></script>
<script src="editor.md/lib/prettify.min.js"></script>
<script src="editor.md/editormd.js"></script>
</head>
<body>
<div class="nav">
<img src="img/logo1.jpg" alt="">
<span class="title">我的博客系统</span>
<!-- spacer不显示内容,占位 -->
<div class="spacer"></div>
<a href="blog_list.html">主页</a>
<a href="blog_edit.html">写博客</a>
<a href="#">注销</a>
</div>
<!-- 整个编辑页的版心 -->
<div class="blog-edit-container">
<!-- 标题的编辑区 -->
<div class="title">
<!-- 输入的标题内容 -->
<input type="text" id="blog-title" placeholder="在这里输入博客标题">
<button id="submit">发布文章</button>
</div>
<!-- 正文的编辑区 -->
<div id="editor"></div>
</div>
<script>
// 初始化编辑器, 代码也是截取自 官方文档 .
var editor = editormd("editor", {
// 这里的尺寸必须在这里设置. 设置样式会被 editormd 自动覆盖掉.
width: "100%",
// 设定编辑器高度
height: "calc(100% - 52px)",
// 编辑器中的初始内容
markdown: "## hello world",
// 指定 editor.md 依赖的插件路径
path: "editor.md/lib/"
});
</script>
</body>
</html>
前后端交互
1、实现博客列表的展示功能
1.1、约定前后端交互接口
1.2、实现BlogServlet
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.util.List;
/**
* @author krystal
* @date 2022/12/2 18:06
* 博客系统
*/
@WebServlet("/blog")
public class BlogServlet extends HttpServlet {
private ObjectMapper objectMapper=new ObjectMapper();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 按照约定的接口格式返回数据
// 在博客列表页中, 已经使用了 BlogServlet.doGet 方法了.
// 博客详情页, 也想用. 就需要做出区分. 使用 query string 来区分.
// 如果请求带有 query string , 有 blogId 这个参数, 就认为是博客详情页的请求.
// 如果请求不带有 query string, 就认为是博客列表页的请求.
resp.setContentType("application/json;charset=utf8");
BlogDao blogDao=new BlogDao();
String blogId=req.getParameter("blogId");
if(blogId==null){
//博客列表页发送的请求
List<Blog> blogs=blogDao.selectAll();
resp.getWriter().write(objectMapper.writeValueAsString(blogs));
}else {
//博客详情页发送的请求
Blog blog=blogDao.selectOne(Integer.parseInt(blogId));
resp.getWriter().write(objectMapper.writeValueAsString(blog));
}
}
1.3、实现前端代码
在 blog_list.html 中 实现 ajax(注意引入依赖)
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script>
//发送ajax从服务器获取数据
function getBlogs(){
$.ajax({
type:'get',
url:'blog',
success:function(body){
//获取成功,则body就是一个js对象数组,每个元素就是一个博客
let container=document.querySelector('.container-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='date';
dateDiv.innerHTML=blog.postTime;
//构造博客的摘要
let descDiv=document.createElement('div');
descDiv.className='desc';
descDiv.innerHTML=blog.content;
//构造全文查看按钮
let a=document.createElement('a');
a.href='blog_detail.html?blogId='+blog.blogId;
a.innerHTML='查看全文>>';
//拼装最终结果
blogDiv.appendChild(titleDiv);
blogDiv.appendChild(dateDiv);
blogDiv.appendChild(descDiv);
blogDiv.appendChild(a);
container.appendChild(blogDiv);
}
}
});
}
//函数调用
getBlogs();
2、实现博客详情的展示功能
2.1、 约定前后端交互接口
2.2、实现BlogServlet
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.util.List;
/**
* @author krystal
* @date 2022/12/2 18:06
* 博客系统
*/
@WebServlet("/blog")
public class BlogServlet extends HttpServlet {
private ObjectMapper objectMapper=new ObjectMapper();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 按照约定的接口格式返回数据
// 在博客列表页中, 已经使用了 BlogServlet.doGet 方法了.
// 博客详情页, 也想用. 就需要做出区分. 使用 query string 来区分.
// 如果请求带有 query string , 有 blogId 这个参数, 就认为是博客详情页的请求.
// 如果请求不带有 query string, 就认为是博客列表页的请求.
resp.setContentType("application/json;charset=utf8");
BlogDao blogDao=new BlogDao();
String blogId=req.getParameter("blogId");
if(blogId==null){
//博客列表页发送的请求
List<Blog> blogs=blogDao.selectAll();
resp.getWriter().write(objectMapper.writeValueAsString(blogs));
}else {
//博客详情页发送的请求
Blog blog=blogDao.selectOne(Integer.parseInt(blogId));
resp.getWriter().write(objectMapper.writeValueAsString(blog));
}
}
2.3、实现前端代码
修改 blog_detail.html
,让这个页面加载的时候,能够调用到上述的接口,来从服务器获取到博客数据
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script>
function getBlog(){
$.ajax({
type:'get',
url:'blog'+location.search,
success:function(body){
let h3 = document.querySelector('.blog-detail>h3');
h3.innerHTML = body.title;
let dateDiv = document.querySelector('.blog-detail>.date');
dateDiv.innerHTML = body.postTime;
// let contentDiv = document.querySelector('#content');
// contentDiv.innerHTML = body.content;
// 此处使用 editor.md 来进行渲染
editormd.markdownToHTML('content', { markdown: body.content });
}
});
}
getBlog();
3、登录功能(暂时不实现注册)
用户有一个session,同时session有一个User属性,两者兼备才算登录状态
3.1、 约定前后端交互接口
3.2、实现LoginServlet
/**
* @author krystal
* @date 2022/12/6 9:15
* 博客系统
*/
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1、从请求中获取用户名和密码
req.setCharacterEncoding("utf-8");
String username=req.getParameter("username");
String password=req.getParameter("password");
if (username==null || username.equals("") || password==null || password.equals("")){
//用户名密码为空,直接登陆失败
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write("用户名或密码为空!登陆失败");
return;
}
//2、查询数据库,验证用户名密码是否正确
UserDao userDao=new UserDao();
User user=userDao.selectByName(username);
if (user==null || !user.getPassword().equals(password)){
//用户名不存在或者密码不相同,返回登陆失败
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write("用户名或密码为空!登陆失败");
return;
}
//3、如果正确,创建一个会话对象
HttpSession session=req.getSession(true);
//在回话中保存user
session.setAttribute("user",user);
//4、构造302响应报文
resp.sendRedirect("blog_list.html");
}
3.3、实现前端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>登录页面</title>
<link rel="stylesheet" href="css/common.css">
<link rel="stylesheet" href="css/login.css">
</head>
<body>
<div class="nav">
<img src="img/logo1.jpg" alt="">
<span class="title">我的博客系统</span>
<!-- spacer不显示内容,占位 -->
<div class="spacer"></div>
<a href="blog_list.html">主页</a>
<a href="blog_edit.html">写博客</a>
<a href="logout">注销</a>
</div>
<!-- 用这个元素作为页面的版心 -->
<div class="login-container">
<form action="login" method="post">
<!-- 登录对话框 -->
<div class="dialog">
<h3>登录</h3>
<div class="row">
<span>用户名</span>
<input type="text" id="username" name="username">
</div>
<div class="row">
<span>密码</span>
<input type="password" id="password" name="password">
</div>
<div class="row">
<input type="submit" id="login-btn" value="登陆">
</div>
</div>
</form>
</div>
</body>
</html>
4、实现登录状态判定功能
4.1、 约定前后端交互接口
4.2、在LoginServlet进行代码添加
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//使用这个方法来针对当前登录状态进行判定
//1、获取一下当前的会话
HttpSession session=req.getSession(false);
if (session==null){
//没有会话,当前是未登录状态
resp.setStatus(403);
return;
}
//判断user对象是否存在
User user=(User) session.getAttribute("user");
if (user==null){
//虽然有会话,但是没有user对象,也认为是未登录状态
resp.setStatus(403);
return;
}
//2、返回200这样的响应即可
resp.setStatus(200);
}
4.3、实现前端代码
创建app.js,在 blog_list.html
blog_detil.html
中引入 js文件,就可以执行到里面的代码,也就进行了登录状态的监测了
function getLoginStatus(){
$.ajax({
type:'get',
url:'login',
success:function(body){
//得到200,此处不做任何工作
console.log("当前已经登陆过!");
},
error:function(){
//得到403
//让页面强行转到login.html
console.log("当前还未登陆!");
location.assign('login.html');
}
});
}
5、显示用户的信息
5.1查询用户信息或者作者信息
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;
//博客系统
@WebServlet("/userInfo")
public class UserInfoServlet extends HttpServlet {
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 {
// 详情页, 获取文章作者的信息
// 查询数据库
getUserInfoFromDB(req, resp, Integer.parseInt(blogId));
}
}
private void getUserInfoFromDB(HttpServletRequest req, HttpServletResponse resp, int blogId) throws IOException {
// 1. 先根据 blogId 查询 Blog 对象, 获取到 userId (作者是谁)
BlogDao blogDao = new BlogDao();
Blog blog = blogDao.selectOne(blogId);
if (blog == null) {
// 如果参数传来的这个 blogId 是随便瞎写的. 数据库里没有.
resp.setStatus(404);
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().write("blogId 不存在");
return;
}
// 2. 根据 userId 查询对应的 User 对象即可
UserDao userDao = new UserDao();
User user = userDao.selectById(blog.getUserId());
if (user == null) {
resp.setStatus(404);
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().write("blogId 不存在");
return;
}
// 3. 把 user 对象返回给浏览器了
user.setPassword("");
resp.setContentType("application/json;charset=utf-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;charset=utf-8");
resp.getWriter().write("当前未登录");
return;
}
User user = (User) session.getAttribute("user");
if (user == null) {
resp.setStatus(403);
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().write("当前未登录");
return;
}
// user 获取到了, 把 user 中的 password 给干掉, 然后返回.
user.setPassword("");
resp.setContentType("application/json; charset=utf-8");
resp.getWriter().write(objectMapper.writeValueAsString(user));
}
}
5.2 实现前端代码
// 针对博客列表页, 获取到当前用户的登陆信息
function getUserInfo() {
$.ajax({
type: 'get',
url: 'userInfo',
success: function(body) {
// 获取成功, body 就是一个 User 对象
// 把 user 对象里的内容填写到页面上即可.
// 此处主要就是填用户名.
console.log(body);
// github 地址, 头像, 就只要改动 user 表即可.
let h3 = document.querySelector('.container-left>.card>h3');
h3.innerHTML = body.username;
}
});
}
getUserInfo();
function getUserInfo(){
$.ajax({
type:'get',
url:'userInfo'+location.search,
success:function(body){
//获取成功,body就是一个user对象
//把user对象里的内容填写到页面上即可
let h3=document.querySelector('.container-left>.card>h3');
h3.innerHTML=body.username;
}
});
}
getUserInfo();
6、实现注销(退出登录)
6.1、 约定前后端交互接口
6.2、实现LogoutServlet
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;
/**
* @author krystal
* @date 2022/12/8 17:42
* 博客系统
*/
@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;
}
//直接把session中之前的user对象删除掉
session.removeAttribute("user");
//重定向到登录页面
resp.sendRedirect("login.html");
}
}
6.3、实现前端代码
7、发布博客
7.1、 约定前后端交互接口
7.2、在BlogServlet中添加doPost方法
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//使用这个方法,来实现提交新博客
//1、先检查用户的登录状态,获取到会话和用户信息
//未登录,不能提交博客
HttpSession session = req.getSession(false);
if (session == null) {
resp.setStatus(403);
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().write("当前未登录,不能发布博客!");
return;
}
User user = (User) session.getAttribute("user");
if (user == null) {
resp.setStatus(403);
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().write("当前未登录,不能发布博客!");
return;
}
//2、获取请求中的参数(博客正文和标题)
req.setCharacterEncoding("utf-8");
String title=req.getParameter("title");
String content=req.getParameter("content");
//3、构造Blog对象,并插入到数据库中
Blog blog=new Blog();
blog.setTitle(title);
blog.setContent(content);
blog.setUserId(user.getUserId());
BlogDao blogDao=new BlogDao();
blogDao.insert(blog);
//4、构造重定向报文,回到博客列表页
resp.sendRedirect("blog_list.html");
}
7.3、 实现前端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>博客编辑</title>
<link rel="stylesheet" href="css/common.css">
<link rel="stylesheet" href="css/blog_edit.css">
<!-- 引入 editor.md 的依赖 -->
<link rel="stylesheet" href="editor.md/css/editormd.min.css" />
<!-- <script src="js/jquery.min.js"></script> -->
<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="editor.md/lib/marked.min.js"></script>
<script src="editor.md/lib/prettify.min.js"></script>
<script src="editor.md/editormd.js"></script>
</head>
<body>
<div class="nav">
<img src="img/logo1.jpg" alt="">
<span class="title">我的博客系统</span>
<!-- spacer不显示内容,占位 -->
<div class="spacer"></div>
<a href="blog_list.html">主页</a>
<a href="blog_edit.html">写博客</a>
<a href="logout">注销</a>
</div>
<!-- 整个编辑页的版心 -->
<div class="blog-edit-container">
<form action="blog" method="post" style="height: 100%">
<!-- 标题的编辑区 -->
<div class="title">
<!-- 输入的标题内容 -->
<input type="text" id="blog-title" placeholder="在这里输入博客标题" name="title">
<input id="submit" value="发布文章" type="submit">
</div>
<!-- 正文的编辑区 -->
<div id="editor">
<textarea name="content" style="display: none"></textarea>
</div>
</form>
</div>
<script src="js/app.js"></script>
<script>
// 初始化编辑器, 代码也是截取自 官方文档 .
var editor = editormd("editor", {
// 这里的尺寸必须在这里设置. 设置样式会被 editormd 自动覆盖掉.
width: "100%",
// 设定编辑器高度
height: "calc(100% - 52px)",
// 编辑器中的初始内容
markdown: "## hello world",
// 指定 editor.md 依赖的插件路径
path: "editor.md/lib/",
saveHTMLToTextarea:true,
});
getLoginStatus();
</script>
</body>
</html>
8、删除博客
8.1、 约定前后端交互接口
8.2、实现BlogDeleteServlet
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;
/**
* @author krystal
* @date 2022/12/8 18:42
* 博客系统
*/
@WebServlet("/blog_delete")
public class BlogDeleteServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1、先判定用户的登录状态
HttpSession session = req.getSession(false);
if (session == null) {
resp.setStatus(403);
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().write("您当前未登录,不能进行删除操作");
return;
}
User user = (User) session.getAttribute("user");
if (user == null) {
resp.setStatus(403);
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().write("您当前未登录,不能进行删除操作");
return;
}
//2、获取到blogId
String blogId=req.getParameter("blogId");
if (blogId==null){
//这个blogId参数不存在,无法删除
resp.setStatus(403);
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().write("您当前删除的blogId有误");
return;
}
//3、查询出这个blogId对应的blog对象
BlogDao blogDao=new BlogDao();
Blog blog=blogDao.selectOne(Integer.parseInt(blogId));
if (blog==null){
resp.setStatus(404);
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().write("您当前删除的博客不存在,blogId="+blogId);
return;
}
//4、判定登录用户是否就是文章作者
if (blog.getUserId()!= user.getUserId()){
//blog.getUserId()是文章作者id
//user.getUserId()是session里登陆的用户
resp.setStatus(403);
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().write("您不能删除别人的博客");
return;
}
//5、真正执行删除操作
blogDao.delete(Integer.parseInt(blogId));
//6、返回302重定向
resp.sendRedirect("blog_list.html");
}
}
8.3、实现前端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>博客详情</title>
<link rel="stylesheet" href="css/common.css">
<link rel="stylesheet" href="css/blog_detail.css">
<!-- 引入 editor.md 的依赖 -->
<link rel="stylesheet" href="editor.md/css/editormd.min.css" />
<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="editor.md/lib/marked.min.js"></script>
<script src="editor.md/lib/prettify.min.js"></script>
<script src="editor.md/editormd.js"></script>
</head>
<body>
<div class="nav">
<img src="img/logo1.jpg" alt="">
<span class="title">我的博客系统</span>
<!-- spacer不显示内容,占位 -->
<div class="spacer"></div>
<a href="blog_list.html">主页</a>
<a href="blog_edit.html">写博客</a>
<a href="logout">注销</a>
<a href="#" id="delete-btn">删除</a>
</div>
<!-- 这个div表示页面的主区域(版心) -->
<div class="container">
<!-- 左侧内容区域 -->
<div class="container-left">
<!-- 用这个表示用户的信息 -->
<div class="card">
<!--用户头像-->
<img src="img/logo3.jpg" alt="">
<!-- 用户名字 -->
<h3></h3>
<a href="#">github地址</a>
<div class="counter">
<span>文章</span>
<span>分类</span>
</div>
<div class="counter">
<span>2</span>
<span>1</span>
</div>
</div>
</div>
<!-- 右侧内容区域 -->
<div class="container-right">
<div class="blog-detail">
<h3></h3>
<div class="date"></div>
<div id="content" style="background-color: transparent">
</div>
</div>
</div>
</div>
<!-- <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script> -->
<script src="js/app.js"></script>
<script>
function getBlog(){
$.ajax({
type:'get',
url:'blog'+location.search,
success:function(body){
let h3 = document.querySelector('.blog-detail>h3');
h3.innerHTML = body.title;
let dateDiv = document.querySelector('.blog-detail>.date');
dateDiv.innerHTML = body.postTime;
// let contentDiv = document.querySelector('#content');
// contentDiv.innerHTML = body.content;
// 此处使用 editor.md 来进行渲染
editormd.markdownToHTML('content', { markdown: body.content });
}
});
}
getBlog();
getLoginStatus();
function getUserInfo(){
$.ajax({
type:'get',
url:'userInfo'+location.search,
success:function(body){
//获取成功,body就是一个user对象
//把user对象里的内容填写到页面上即可
let h3=document.querySelector('.container-left>.card>h3');
h3.innerHTML=body.username;
}
});
}
getUserInfo();
function updateDeleteURL(){
let deleteBtn=document.querySelector("#delete-btn");
deleteBtn.href='blog_delete'+location.search;
}
updateDeleteURL();
</script>
</body>
</html>
部署到云服务器
参考部署过程
此处是博主的博客系统