JavaWeb项目—— 博客系统
文章目录效果展示1. 创建 maven 项目2. 设计数据库3. 封装数据库的操作代码3.1 创建 DBUtil 类3.2 创建 Blog(代表一篇博客)3.3 创建 User(代表一个用户)3.4 创建类 BlogDao(对博客表进行操作)3.5 创建类 UserDao (对用户表进行操作)4. 导入之前已经写好的前端代码5. 实现博客主页界面5.1 约定好前后端交互接口5.2 实现 BlogS
文章目录
效果展示
1. 创建 maven 项目
创建必要的目录,引入需要的依赖
2. 设计数据库
本系统要存入博客文章的信息和用户的信息
创建博客表:
博客的 id,博客的标题,博客的内容,博客的日期,博文的博主 id
创建用户表:
用户 id 用户名 用户密码
-- 创建一个数据库
create database if not exists java102_blog;
use java102_blog;
-- 创建一个博客表.
drop table if exists blog;
create table blog (
blogId int primary key auto_increment,
title varchar(1024),
content mediumtext,
userId int, -- 文章作者的 id
postTime datetime -- 发布时间
);
---- 给博客表中插入点数据, 方便测试.
insert into blog values(null, '这是第一篇博客', '从今天开始, 我要认真学 Java', 1, now());
insert into blog values(null, '这是第二篇博客', '从昨天开始, 我要认真学 Java', 1, now());
insert into blog values(null, '这是第三篇博客', '从前天开始, 我要认真学 Java', 1, now());
insert into blog values(null, '这是第一篇博客', '从今天开始, 我要认真学 C++', 2, now());
insert into blog values(null, '这是第二篇博客', '从昨天开始, 我要认真学 C++', 2, now());
insert into blog values(null, '这是第三篇博客', '# 一级标题\n ### 三级标题\n > 这是引用内容', 2, now());
-- 创建一个用户表
drop table if exists user;
create table user (
userId int primary key auto_increment,
username varchar(128) unique, -- 后续会使用用户名进行登录, 一般用于登录的用户名都是不能重复的.
password varchar(128)
);
insert into user values(null, 'zhangsan', '123');
insert into user values(null, 'lisi', '123');
insert into user values(null, 'ling', '123');
3. 封装数据库的操作代码
创建包 model 用来存放数据库的代码
3.1 创建 DBUtil 类
用于和数据库建立连接
package model;
import com.mysql.cj.jdbc.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 final String URL = "jdbc:mysql://127.0.0.1:3306/java102_blog?characterEncoding=utf8&useSSL=false";
private static final String USERNAME = "root";
private static final String PASSWORD = "707703";
private volatile static DataSource dataSource = null;
private static DataSource getDataSource() {
if(dataSource == null) {
synchronized (DBUtil.class) {
if(dataSource == null) {
dataSource = new MysqlDataSource();
((MysqlDataSource)dataSource).setUrl(URL);
((MysqlDataSource)dataSource).setUser(USERNAME);
((MysqlDataSource)dataSource).setPassword(PASSWORD);
}
}
}
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 throwables) {
throwables.printStackTrace();
}
}
if(statement != null) {
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(connection != null) {
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
3.2 创建 Blog(代表一篇博客)
package model;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
// 每个 blog对象 ,对应 blog 表里的一条记录
public class Blog {
private int blogId;
private String title;
private String content;
private int userId;
private Timestamp postTime;
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 int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
// 把这里 的 getter 方法给改了,不是返回一个 时间搓对象,而是返回一个 string(格式化的时间)
public String getPostTime() {
// 使用这个类 来完成时间戳到格式化日期的转换
// 这个 转换过程,需要构造方法中制定要转换的格式,然后调用 format 来进行转换
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return simpleDateFormat.format(postTime);
}
public void setPostTime(Timestamp postTime) {
this.postTime = postTime;
}
}
3.3 创建 User(代表一个用户)
package model;
// 每个 model.User 对象, 期望能够表示 user 表中的一条记录.
public class User {
private int userId = 0;
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;
}
}
3.4 创建类 BlogDao(对博客表进行操作)
注意:
对数据进行插入删除操作时,执行 sql:
其他操作:
插入顺序:
package model;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* 这个类用于去封装博客表的 基本操作
*/
public class BlogDao {
// 1.往博客表里,插入一个博客
public void insert(Blog blog) {
// JDBC 代码
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 throwables) {
throwables.printStackTrace();
}finally {
// 4. 关闭连接,释放资源
DBUtil.close(connection,statement,null);
}
}
// 2. 获取博客列表中的所有博客信息
public List<Blog> selectAll() {
List<Blog> blogs = new ArrayList<>();
// JDBC 代码
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();
// 把查询到的数据 存储到 blogs 当中
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() > 50) {
content = content.substring(0,50) + "..点进来吧我的宝";
}
blog.setContent(content);
blog.setUserId(resultSet.getShort("userId"));
blog.setPostTime(resultSet.getTimestamp("postTime"));
blogs.add(blog);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
DBUtil.close(connection,statement,resultSet);
}
return blogs;
}
// 3. 能够根据博客 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();
// 此处我们是使用 主键 来作为 查询条件,查询结果,要么是 1,要么是 0
if(resultSet.next()) {
Blog blog = new Blog();
blog.setBlogId(resultSet.getInt("blogId"));
blog.setTitle(resultSet.getString("title"));
blog.setContent(resultSet.getString("content"));
blog.setUserId(resultSet.getShort("userId"));
blog.setPostTime(resultSet.getTimestamp("postTime"));
return blog;
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
// 4. 关闭连接 释放资源
DBUtil.close(connection,statement,resultSet);
}
return null;
}
// 4. 从博客列表中,根据博客 id 删除博客
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
statement.executeUpdate();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
DBUtil.close(connection,statement,null);
}
}
}
3.5 创建类 UserDao (对用户表进行操作)
package model;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* 这个类用于 封装 用户表的 基本操作
*/
public class UserDao {
// 1. 根据用户名 查找用户信息
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();
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 throwables) {
throwables.printStackTrace();
}finally {
// 4. 关闭连接 释放资源
DBUtil.close(connection,statement,resultSet);
}
return null;
}
// 2. 根据 用户 id 来找 用户信息
// 博客详情页 就可以根据用户 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();
// 此处的 username 使用 unique 约束,要么能查到一个,要么一个都查不到
// 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 throwables) {
throwables.printStackTrace();
}finally {
DBUtil.close(connection,statement,resultSet);
}
return null;
}
}
4. 导入之前已经写好的前端代码
5. 实现博客主页界面
5.1 约定好前后端交互接口
5.2 实现 BlogServlet
import model.BlogDao;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
// 通过这个类, 来处理 /blog 路径对应的请求
@WebServlet("/blog")
public class BlogServlet extends HttpServlet {
private ObjectMapper objectMapper = new ObjectMapper();
// 这个方法用来获取到数据库中的博客列表.
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 从数据库中查询到博客列表, 转成 JSON 格式, 然后直接返回即可.
BlogDao blogDao = new BlogDao();
List<Blog> blogs = blogDao.selectAll();
//把 blogs 对象转成 JSON 格式.
String respJson = objectMapper.writeValueAsString(blogs);
resp.setContentType("application/json; charset=utf8");
resp.getWriter().write(respJson);
}
}
5.3 实现 前端代码
在 blog_list.html 中 实现 ajax
注意:引入依赖
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script>
// 在页面加载的时候, 通过 ajax 给服务器发送数据, 获取到博客列表信息, 并且显示在界面上.
function getBlogList() {
$.ajax({
type: 'get',
url: 'blog',
success: function(body) {
// 获取到的 body 就是一个 js 对象数组, 每个元素就是一个 js 对象, 根据这个对象构造 div
// 1. 先把 .right 里原有的内容给清空
let rightDiv = document.querySelector('.right');
rightDiv.innerHTML = '';
// 2. 遍历 body, 构造出一个个的 blogDiv
for (let blog of body) {
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.innerHTML = '查看全文 >>';
// 此处希望点击之后能够跳转到 博客详情页 !!
// 这个跳转过程需要告知服务器要访问的是哪个博客的详情页.
a.href = 'blog_detil.html?blogId=' + blog.blogId;
blogDiv.appendChild(a);
// 把 blogDiv 挂到 dom 树上!
rightDiv.appendChild(blogDiv);
}
},
error: function() {
alert("获取博客列表失败!");
}
});
}
getBlogList();
</script>
6. 实现博客详情界面
6.1 约定好前后端交互接口
6.2 实现BlogServlet
这里后端代码和博客列表页的获取,基本相同,就直接放到一个方法中,来实现!使用blogId参数来区别是获取博客列表还是详情
这里注意:博客列表页在也在BlogServlet中实现的,我们如何去区别呢?:
package controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import model.Blog;
import model.BlogDao;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
/**
* // doGet 获取博客列表页
*/
@WebServlet("/blog")
public class BlogServlet extends HttpServlet {
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json; charset=utf8");
BlogDao blogDao = new BlogDao();
// 先尝试获取到 req 中的 blogId 参数. 如果该参数存在, 说明是要请求博客详情
// 如果该参数不存在, 说明是要请求博客的列表.
String param = req.getParameter("blogId");
if (param == null) {
// 不存在参数, 获取博客列表
List<Blog> blogs = blogDao.selectAll();
// 把 blogs 对象转成 JSON 格式.
String respJson = objectMapper.writeValueAsString(blogs);
resp.getWriter().write(respJson);
} else {
// 存在参数, 获取博客详情
int blogId = Integer.parseInt(param);
Blog blog = blogDao.selectOne(blogId);
String respJson = objectMapper.writeValueAsString(blog);
resp.getWriter().write(respJson);
}
}
}
6.3 实现前端代码
修改 blog_detail.html
,让这个页面加载的时候,能够调用到上述的接口,来从服务器获取到博客数据
注意:
在博客详情页中引入 editor
<script>
function getBlogDetail() {
$.ajax({
type: 'get',
// location.search 拿到了形如 '?blogId=5' 这样的一段内容
url: 'blog2' + location.search,
success: function(body) {
// 根据 body 中的内容来构造页面
// 1. 构造博客标题S
let h3 = document.querySelector(".blog-content>h3");
h3.innerHTML = body.title;
// 2. 构造博客发布时间
let dateDiv = document.querySelector('.date');
dateDiv.innerHTML = body.postTime;
// 3. 构造博客正文
// 如果直接把 content 设为 innerHTML, 此时展示在界面上的内容, 是原始的 markdown 字符串
// 咱们需要的是渲染后的, 带有格式的效果
// let content = document.querySelector('#content');
// content.innerHTML = body.content;
// 第一个参数对应 id=content 的 html 标签. 渲染后得到的 html 片段就会被放到这个 标签下.
editormd.markdownToHTML('content', {
markdown: body.content
});
}
});
}
getBlogDetail();
</script>
7. 实现登录界面
这里需要注意:啥样才算是已经登录
用户有一个 session,同时 session 有一个 user 属性 ~
两者同时具备,才叫登录状态
这里先给注销做铺垫:理解一下注销是如何操作的:
注销只要破坏掉上面的任意一个条件就行了
7.1 约定好前后端交互接口
7.2 实现 LoginServlet
package controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import model.User;
import model.UserDao;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
// 实现登录页面
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
// 1. 获取到请求中的参数
String username = req.getParameter("username");
String password = req.getParameter("password");
if(username == null || "".equals(username) || password == null || "".equals(password)) {
// 请求内容缺失,登录失败
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);
// 把刚才的用户信息,存储到会话中
session.setAttribute("user",user);
// 4. 返回一个重定向报文,跳转到博客列表页
resp.sendRedirect("blog_list.html");
}
}
7.3 实现前端代码
修改blog_login.html
这里只需要在原来登录操作上套上一层 form 标签就可以了
因为这里在原有的基础上填上了 form表单,我们在 css 中也会有一些改动
<!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_login.css">
</head>
<body>
<!--这是导航栏 nav-->
<div class = "nav">
<img src="imge/ph.png" alt="">
<!--标题 span-->
<span>我的博客系统</span>
<!--这是一个空白元素用来占位置-->
<div class="spacer"></div>
<!--链接标签<a>-->
<a href="blog_list.html">主页</a>
<a href="blog_edit.html">写博客</a>
<!--# 空链接--> <!--注销没必要显示在登录页面-->>
<!-- <a href="#">注销</a> -->
</div>
<div class="login-container">
<form action="login" method="post">
<!--空白页-->
<div class="login-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">
<!-- <button>提交</button> -->
<input type="submit" id="submit" value="提交">
</div>
</div>
</form>
</div>
</div>
</body>
</html>
8. 实现登录状态判定功能
8.1 约定前后端交互接口
8.2 在 LoginServlet 进行代码添加
package controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import model.User;
import model.UserDao;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
// 实现登录页面
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
// 1. 获取到请求中的参数
String username = req.getParameter("username");
String password = req.getParameter("password");
if(username == null || "".equals(username) || password == null || "".equals(password)) {
// 请求内容缺失,登录失败
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);
// 把刚才的用户信息,存储到会话中
session.setAttribute("user",user);
// 4. 返回一个重定向报文,跳转到博客列表页
resp.sendRedirect("blog_list.html");
}
// // 这个方法用来让前端检测当前的登录状态~~~~~~~~~~~~~~~~~~~~~~
// 1)检测有无会话 2)检测有无属性
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json;charset=utf8");
HttpSession session = req.getSession(false);
if(session == null) {
// 1) 检测有无会话,无说明未登录
// 创建对象--> 里面为空
User user = new User();
resp.getWriter().write(objectMapper.writeValueAsString(user));
return;
}
User user = (User) session.getAttribute("user");
if(user == null) {
// 2)虽然有会话,但是会话里如果没有 user 对象,也视为未登录
user = new User();
resp.getWriter().write(objectMapper.writeValueAsString(user));
return;
}
// 已经登录的状态!
// 注意,此处不要把密码返回到前端
user.setPassword("");
resp.getWriter().write(objectMapper.writeValueAsString(user));
}
}
8.3 在前端代码中创建 common.js
// 这个文件里放一些 页面公共的代码
// 加上一个逻辑,通过 GET/login 这个接口来获取下当前的登录状态
function getUserInfo() {
$.ajax({
type: 'get',
url: 'login',
success: function(body) {
// 判定此处的 body 是不是一个有效的 user 对象(userId 是否非 0)
if(body.userId && body.userId >0) {
// 登录成功
// 不做处理
console.log("当前用户登录成功!用户名:" + body.username);
}else{
// 登录失败
// 让前端页面,跳转到 login.html
alert("当前你尚未登录!请登录后再访问博客列表!");
location.assign('blog_login.html');
}
},
error: function() {
alert("当前你尚未登录!请登录后再访问博客列表!");
location.assign('blog_login.html');
}
});
}
getUserInfo();
8.4 修改前端代码
在
blog_list.html
blog_detil.html
中引入 js文件,就可以执行到里面的代码,也就进行了登录状态的监测了
<script src="js/commom.js"></script>
9. 实现显示用户信息功能
9.1 约定好前后端交互接口
9.2 实现 AuthorServlet 代码
package controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import model.Blog;
import model.BlogDao;
import model.User;
import model.UserDao;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 根据博客 id 查 博客信息
* 根据 博客信息里的 作者 id 查 作者信息
*/
@WebServlet("/authorInfo")
public class AuthorServlet extends HttpServlet {
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json; charset=utf8");
// 通过这个方法, 来获取到指定的博客的作者信息.
String param = req.getParameter("blogId");
if (param == null || "".equals(param)) {
// 参数缺少了.
resp.getWriter().write("{ \"ok\": false, \"reason\": \"参数缺失!\" }");
return;
}
// 根据当前 blogId 在数据库中进行查找, 找到对应的 Blog 对象, 再进一步的根据 blog 对象, 找到作者信息.
BlogDao blogDao = new BlogDao();
Blog blog = blogDao.selectOne(Integer.parseInt(param));
if (blog == null) {
resp.getWriter().write("{ \"ok\": false, \"reason\": \"要查询的博客不存在!\" }");
return;
}
// 根据 blog 对象, 查询到用户对象
UserDao userDao = new UserDao();
User author = userDao.selectById(blog.getUserId());
if (author == null) {
resp.getWriter().write("{ \"ok\": false, \"reason\": \"要查询的用户不存在!\" }");
return;
}
// 把 author 返回到浏览器这边
// 注意要把密码给干掉!
author.setPassword("");
resp.getWriter().write(objectMapper.writeValueAsString(author));
}
}
9.3 实现前端代码
针对博客列表页进行修改
在 common.js 中 修改代码
针对博客详情页
10. 实现注销功能
在导航栏中安排一个“注销”按钮,当用户点击注销之后,就会在服务器上取消登录状态,并且能够跳转到登录页面
10.1 约定好前后端交互接口
10.2 实现 LogouServlet
package controller;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
import java.util.Enumeration;
@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.getWriter().write("当前用户尚未登录! 无法注销!");
return;
}
// 然后把这个用户的会话中的信息给删掉就行了!!
session.removeAttribute("user");
resp.sendRedirect("blog_login.html");
}
}
10.3 实现前端代码
将 blog_detail.html blog_list.html bloh_edit.htm中的注销标签进行修改
11. 实现发布博客功能
在博客编辑页
中,当用户输入博客标题
,和正文
之后,点击发布
此时就会把博客数据提交到服务器,由服务器存储到数据中
11.1 约定好前后端交互的接口
11.2 在BlogServlet中添加doPost方法
@Override
protected 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("当前用户未登录, 不能提交博客!");
return;
}
User user = (User) session.getAttribute("user");
if (user == null) {
// 当前用户未登录, 不能提交博客!
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write("当前用户未登录, 不能提交博客!");
return;
}
// 一定要先指定好请求按照哪种编码来解析
req.setCharacterEncoding("utf8");
// 先从请求中, 取出参数(博客的标题和正文)
String title = req.getParameter("title");
String content = req.getParameter("content");
if (title == null || "".equals(title) || content == null || "".equals(content)) {
// 直接告诉客户端, 请求参数不对
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write("提交博客失败! 缺少必要的参数!");
return;
}
// 构造 Blog 对象, 把当前的信息填进去, 并插入数据库中
// 此处要给 Blog 设置的属性, 主要是 title, content, userId (作者信息)
// postTime 和 blogId 都不需要手动指定, 都是插入数据库的时候自动生成的.
Blog blog = new Blog();
blog.setTitle(title);
blog.setContent(content);
// 作者 id 就是当前提交这个博客的用户的身份信息!!
blog.setUserId(user.getUserId());
BlogDao blogDao = new BlogDao();
blogDao.insert(blog);
// 重定向到, 博客列表页!
resp.sendRedirect("blog_list.html");
}
11.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="editor.md/lib/marked.min.js"></script>
<script src="editor.md/lib/prettify.min.js"></script>
<script src="editor.md/editormd.min.js"></script>
</head>
<body>
<!-- 这是导航栏 -->
<div class="nav">
<img src="imge/ph.png" alt="">
<span>我的博客系统</span>
<!-- 空白元素, 用来占位置 -->
<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" placeholder="在此处输入标题" name="title">
<!-- <button>发布文章</button> -->
<input type="submit" value="发布文章" id="submit">
</div>
<!-- 放置 md 编辑器 -->
<div id="editor">
<!-- 为了进行 form的提交,此处搞一下 textarea 多行编辑框,借助这个编辑框来实现表单的提交-->
<textarea name="content" style="display: none"></textarea>
</div>
</form>
</div>
<script>
// 初始化编辑器
let editor = editormd("editor", {
// 这里的尺寸必须在这里设置. 设置样式会被 editormd 自动覆盖掉.
width: "100%",
// 设定编辑器高度
height: "calc(100% - 50px)",
// 编辑器中的初始内容
markdown: "# 在这里写下一篇博客",
// 指定 editor.md 依赖的插件路径
path: "editor.md/lib/",
// 此处要加上一个重要的选项,然后 editr.md 就会自动把用户在编辑器输入的内容同步保存到 隐藏的 textarea中
saveHTMLToTextarea:true,
});
</script>
</body>
</html>
12. 删除博客
12.1 约定号前后端交互接口
12.1 实现前端代码
<script>
function getBlogDetail() {
$.ajax({
type: 'get',
// location.search 拿到了形如 '?blogId=5' 这样的一段内容
url: 'blog' + location.search,
success: function(body) {
// 根据 body 中的内容来构造页面
// 1. 构造博客标题
let h3 = document.querySelector(".blog-content>h3");
h3.innerHTML = body.title;
// 2. 构造博客发布时间
let dateDiv = document.querySelector('.date');
dateDiv.innerHTML = body.postTime;
// 3. 构造博客正文
// 如果直接把 content 设为 innerHTML, 此时展示在界面上的内容, 是原始的 markdown 字符串
// 咱们需要的是渲染后的, 带有格式的效果
// let content = document.querySelector('#content');
// content.innerHTML = body.content;
// 第一个参数对应 id=content 的 html 标签. 渲染后得到的 html 片段就会被放到这个 标签下.
editormd.markdownToHTML('content', {
markdown: body.content
});
}
});
}
// 加上一个逻辑,通过 GET /login 这个接口来获取下当前的登录状态
function getUserInfo(pageName) {
$.ajax({
type:'get',
url: 'login',
success: function(body) {
// 判断此处的 body 是不是一个有效的user 对象(userId 是否为0)
if(body.userId && body.userId > 0) {
// 登录成功
// 不做处理
console.log("当前用户登录成功!用户名:" + body.username);
// 在getUserInfo 的回调函数中,来调用获取用户信息
getAuthorInfo(body);
}else {
// 登录失败
// 让前端页面,跳转到 login.html
alert("当前您尚未登录!请登录后再访问博客列表");
location.assign('blog_login.html');
}
},
error: function() {
alert("当前您尚未登录!请登录后再访问博客列表");
location.assign('blog_login.html');
}
});
}
// 判定用户的登录状态
getUserInfo('blog_detail.html');
// 从服务器获取一下当前博客的作者信息, 并显示到界面上.
// 参数 user 就是刚才从服务器拿到的当前登录用户的信息
function getAuthorInfo(user) {
$.ajax({
type: 'get',
url: 'authorInfo' + location.search,
success: function(body) {
// 此处的body,就是服务器返回的User对象,是文章作者信息
if(body.username) {
getBlogDetail();
changeUserName(body.username);
if(body.username == user.username ) {
// 作业和登录的用户是一个人,则显示 删除按钮
let navDiv = document.querySelector('.nav');
let a = document.createElement('a');
a.innerHTML = '删除';
// 点击删除,构造一个 形如 blogDelete?blogId = 6 这样的请求
a.href = 'blogDelete' + location.search;
navDiv.appendChild(a);
}
}else{
console.log("获取信息失败" + body.reason);
}
}
});
}
function changeUserName(username) {
let h3 = document.querySelector('.card>h3');
h3.innerHTML = username;
}
</script>
12.2 实现BlogDeleteServlet
package controller;
import model.Blog;
import model.BlogDao;
import model.User;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* 实现删除功能
*/
@WebServlet("/blogDelete")
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.setContentType("text/html; charset=utf8");
resp.getWriter().write("当前尚未登录, 不能删除!");
return;
}
User user = (User) session.getAttribute("user");
if (user == null) {
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("当前尚未登录, 不能删除!");
return;
}
// 2. 获取到参数中的 blogId
String blogId = req.getParameter("blogId");
if (blogId == null || "".equals(blogId)) {
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("当前 blogId 参数不对!");
return;
}
// 3. 获取要删除的博客信息.
BlogDao blogDao = new BlogDao();
Blog blog = blogDao.selectOne(Integer.parseInt(blogId));
if (blog == null) {
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("当前要删除的博客不存在!");
return;
}
// 4. 再次校验, 当前的用户是否就是博客的作者
if (user.getUserId() != blog.getUserId()) {
// 这一点在前端这里其实也处理过~~ 但是此处还是再校验一次, 不是坏事!!!
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("当前登录的用户不是作者, 没有权限删除!");
return;
}
// 5. 确认无误, 开始删除
blogDao.delete(Integer.parseInt(blogId));
// 6. 重定向到博客列表页
resp.sendRedirect("blog_list.html");
}
}
更多推荐
所有评论(0)