前面我们学习了前端的博客系统,然后我们现在又学了后端的 servlet 技术,基本就可以写一个可以自己增删查改的网页了
所谓的前后端分离,通俗的说,就是这种方式下的服务器端不关注页面的内容,而只是给网页端提供数据,然后网页端通过 ajax 的方式和服务器之间交互数据,网页拿到数据之后再根据数据的内容渲染到页面上..
渲染就是相当于给你一个模板,然后里面的内容可以通过后端数据随意更改.
一. 准备工作
先准备好servlet:servlet准备工作
之前讲过的,我这里就简单点写了
1.创建Maven项目
2. 引入依赖. (servlet,jackson,mysql)
去中央仓库搜索下载(版本别搞错了):https://mvnrepository.com/
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.0</version>
</dependency>
引入后记得刷新一下:
3.创建必要的目录
web.xml 里面填写内容,直接复制下面的代码:
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
</web-app>
4. 编写代码
在 java目录里新建一个HelloServlet
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;
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("hello");
}
}
注意路径
5/6. 打包部署程序
我们下载的 smart tomcat,就不用频繁的去打包部署了
7. 在浏览器中验证
点击小三角运行:
到这里准备工作算是做完了,接下来就可以执行接下来的步骤了
二. 编写数据库的操作代码
1.创建数据库/表结构(数据库设计)
这里就要根据你的前端页面来设计了,之前搞得什么页面,需求是什么就设计什么,我们实现的博客系统,需要用户表和博客表,我们就设计这俩
建议大家现在记事本上写好了在直接拷贝到数据库上,这样不容易出错
db.sql
create database if not exists blog_system;
use blog_system;
drop table if exists blog;
create table blog (
blogId int primary key auto_increment,
title varchar(1024),
content mediumtext,
userId int,
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());
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');
2. 封装数据库操作
2.1 先创建 DBUtil 封装数据库连接的操作
我们相关都操作放到各自的包里面,这样让我们后面写起来不容易混乱!!
这里就先用之前学过的 JDBC 来连接数据库
package model;
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 final String URL = "jdbc:mysql://127.0.0.1:3306/blog_system?characterEncoding=utf8&useSSL=false";
private static final String USERNAME = "root";
private static final String PASSWORD = "root";
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(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 e) {
e.printStackTrace();
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
2.2 创建实体类
使用实体类来表示数据库中的一条记录,根据数据库创建的表,我们需要创建 Blog 类和 User 类
这样写方便我们观察:
Blog
package model;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
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;
}
public String getPostTime() {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return simpleDateFormat.format(postTime);
}
public void setPostTime(Timestamp postTime) {
this.postTime = postTime;
}
}
User
package model;
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;
}
}
2.3 封装针对数据的增删改查
我们把提供了增删改查这样的类,称为 DAO
BlogDao
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 {
public void insert(Blog blog){
Connection connection = null;
PreparedStatement statement = null;
try {
connection = DBUtil.getConnection();
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());
statement.executeUpdate();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
DBUtil.close(connection,statement,null);
}
}
public List<Blog> selectAll(){
List<Blog> 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"));
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;
}
public Blog selectOne(int blogId){
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.setUserId(resultSet.getShort("userId"));
blog.setPostTime(resultSet.getTimestamp("postTime"));
return blog;
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
DBUtil.close(connection,statement,resultSet);
}
return null;
}
public void delete(int blogId){
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);
statement.executeUpdate();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
DBUtil.close(connection,statement,null);
}
}
public void update(Blog blog) {
Connection connection = null;
PreparedStatement statement = null;
try {
connection = DBUtil.getConnection();
String sql = "update blog set content = ? ,title = ? where blogId = ?";
statement = connection.prepareStatement(sql);
statement.setString(1, blog.getContent());
statement.setString(2, blog.getTitle());
statement.setInt(3, blog.getBlogId());
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);
}
}
public static Integer selectTotal(int userId){
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
connection = DBUtil.getConnection();
String sql = "select count(userId) from blog where userId = ?";
statement = connection.prepareStatement(sql);
statement.setInt(1,userId);
resultSet = statement.executeQuery();
if(resultSet.next()){
}
return resultSet.getInt(1);
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
DBUtil.close(connection,statement,resultSet);
}
return null;
}
public static void main(String[] args) {
Integer ret1 = selectTotal(2);
System.out.println(ret1);
BlogDao blogDao = new BlogDao();
Blog blog = new Blog();
blog.setUserId(1);
blog.setBlogId(1);
blog.setTitle("hahah");
blog.setContent("fff");
blogDao.update(blog);
}
}
UserDao
package model;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class UserDao {
public void insert(User user){
Connection connection = null;
PreparedStatement statement = null;
try {
connection = DBUtil.getConnection();
String sql = "insert into user values(null,?,?)";
statement = connection.prepareStatement(sql);
statement.setString(1, user.getUsername());
statement.setString(2, user.getPassword());
statement.executeUpdate();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
DBUtil.close(connection,statement,null);
}
}
public User selectByName(String username) {
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 throwables) {
throwables.printStackTrace();
} finally {
DBUtil.close(connection, statement, resultSet);
}
return null;
}
public User selectById(int userId) {
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 throwables) {
throwables.printStackTrace();
} finally {
DBUtil.close(connection, statement, resultSet);
}
return null;
}
}
到这里 数据库操作都给准备好了 下面就是实现服务器的代码了
三. 约定前后端交互接口
我们先把之前写的前端博客系统给拷贝到 webapp 里面
博客系统:链接
1. 实现博客列表
1.1约定前后端交互接口
[请求]
GET /blog
[响应] [
{
blogId: 1,
title: "第一篇博客",
content: "博客正文",
userId: 1,
postTime: "2022-05-27 12:00:00"
},
{
blogId: 2,
title: "第二篇博客",
content: "博客正文",
userId: 1,
postTime: "2022-05-27 12:10:00"
},
...
]
我们约定, 浏览器给服务器发送一个 GET /blog 这样的 HTTP 请求, 服务器给浏览器返回了一个 JSON 格式的数据.
1.2 实现服务器代码
package controller;
import model.Blog;
import model.BlogDao;
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 java.io.IOException;
import java.util.List;
@WebServlet("/blog")
public class BlogServlet extends HttpServlet {
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
BlogDao blogDao = new BlogDao();
List<Blog> blogs = blogDao.selectAll();
String respJson = objectMapper.writeValueAsString(blogs);
resp.setContentType("application/json;charset=utf8");
resp.getWriter().write(respJson);
}
}
根据我们之前插入的数据,写完可以用 Postman 验证一下
1.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_list.css">
</head>
<body>
<!-- 这是导航栏 -->
<div class="nav">
<img src="image/head.jpg" alt="">
<span>我的博客系统</span>
<!-- 空白元素, 用来占位置 -->
<div class="spacer"></div>
<a href="blog_list.html">主页</a>
<a href="blog_edit.html">写博客</a>
<a href="logout">注销</a>
</div>
<!-- 这里的 .container 作为页面的版心 -->
<div class="container">
<!-- 左侧个人信息 -->
<div class="left">
<!-- 表示整个用户信息区域. -->
<div class="card">
<img src="image/gamegirl.jpg" alt="">
<h3></h3>
<a href="#">github 地址</a>
<div class="counter">
<span>文章</span>
<span>分类</span>
</div>
<div class="counter">
<span>999</span>
<span>999</span>
</div>
</div>
</div>
<!-- 右侧内容详情 -->
<div class="right">
<!-- .blog 就对应一个博客 -->
<!-- <div class="blog">
<div class="title">
我的第一篇博客
</div>
<div class="date">
2022-05-05 20:52:00
</div>
<div class="desc">
从今天起, 我要认真敲代码. Lorem ipsum dolor sit amet consectetur adipisicing elit. Nulla alias tenetur ut velit ex voluptatibus consequatur quam exercitationem, assumenda ea blanditiis repudiandae? Repellendus tenetur nostrum asperiores molestias doloremque cupiditate maiores.
</div>
<a href="#">查看全文 >> </a>
</div> -->
</div>
</div>
</div>
<script src="js/jquery.min.js"></script>
<script>
function getBlogList() {
$.ajax({
type: 'get',
url: 'blog',
success: function(body) {
let rightDiv = document.querySelector('.right');
rightDiv.innerHTML = '';
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_detail.html?blogId=' + blog.blogId;
blogDiv.appendChild(a);
rightDiv.appendChild(blogDiv);
}
},
error: function() {
alert("获取博客列表失败!");
}
});
}
getBlogList();
</script>
<!--<!– 在这里引入上述的 js 文件, 就可以执行到里面的代码, 也就进行了登录状态的监测了 –>-->
<!--<script src="js/common.js"></script>-->
<!--<script>-->
<!--
<!-- getUserInfo('blog_list.html');-->
<!--</script>-->
</body>
</html>
效果:
2. 实现博客详情
目前点击博客列表页的 “查看全文” , 能进入博客详情页, 但是这个博客详情页是写死的内容. 我们期望能够根据当前的 博客 id 从服务器动态获取博客内容.
2.1 约定前后端交互接口
[请求]
GET /blog?blogId=1
[响应] {
HTTP/1.1 200OK
Content-Type:application/json;
{
blogId: 1,
title: "第一篇博客",
content: "博客正文",
userId: 1,
postTime: "2022-05-27 12:00:00"
},
相比于博客列表页, 博客详情页的请求中多了一个 blogId 参数, 响应中只获取到一个博客的内容.
2.1 实现服务器代码
获取详情页跟获取列表基本相同,所以我们只需要改一下代码判断是否带参数 blogId来返回列表还是详情页
package controller;
import model.Blog;
import model.BlogDao;
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 java.io.IOException;
import java.util.List;
@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();
String param = req.getParameter("blogId");
if (param == null) {
List<Blog> blogs = blogDao.selectAll();
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);
}
}
}
当然,我们也可以分开写好理解一些:
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;
@WebServlet("/detail")
public class BlogDetailServlert 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 blogId = req.getParameter("blogId");
BlogDao blogDao = new BlogDao();
Blog blog = blogDao.selectOne(Integer.parseInt(blogId));
resp.getWriter().write(objectMapper.writeValueAsString(blog));
}
}
通过Postman 验证一下
实现客户端代码
<!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">
<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.js"></script>
</head>
<body>
<div class="nav">
<img src="image/head.jpg" 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="container">
<div class="left">
<div class="card">
<img src="image/gamegirl.jpg" alt="">
<h3></h3>
<a href="https://gitee.com/big-white-rice">github 地址</a>
<div class="counter">
<span>文章</span>
<span>分类</span>
</div>
<div class="counter">
<span>999</span>
<span>999</span>
</div>
</div>
</div>
<div class="right">
<div class="blog-content">
<h3></h3>
<div class="date"></div>
<div id="content" style="opacity: 80%">
</div>
</div>
</div>
</div>
<script>
function getBlogDetail() {
$.ajax({
type: 'get',
url: 'blog' + location.search,
success: function(body) {
let h3 = document.querySelector(".blog-content>h3");
h3.innerHTML = body.title;
let dateDiv = document.querySelector('.date');
dateDiv.innerHTML = body.postTime;
editormd.markdownToHTML('content', {
markdown: body.content
});
}
});
}
getBlogDetail();
</script>
</body>
</html>
注意:当我们在进行程序验证的时候,要牢记一件事情,浏览器的缓存可能会影响到结果,你可能修改了之后再去同一个浏览器访问的时候,他并没有发生改变,因为浏览器可能把你上次访问的页面给保存到本地了,下次在尝试访问的时候访问的就是本地的内容,所以这个时候我们要按下: Ctrl + F5 强制刷新一下…
3. 实现登录(注册)
1: 登陆页面提供一个 form 表单, 通过 form 的方式把用户名密码提交给服务器. 2: 服务器端验证用户名密码是否正确. 3: 如果密码正确, 则在服务器端创建 Session , 并把 sessionId 通过 Cookie 返回给浏览器.
3.1 约定前后端交互接口
[请求]
POST /login
Content-Type: application/x-www-form-urlencoded
username=test&password=123
[响应]
HTTP/1.1 302
Location: blog_list.html
当登录成功以后,就会自动跳转到主页(博客列表页(blog_list.html))
3.2 实现服务器代码
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("utf8");
resp.setCharacterEncoding("utf8");
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println("username="+username+",password="+password);
if(username == null || "".equals(username) || password == null || "".equals(password)){
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("当前的用户名或密码为空!!");
return;
}
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;
}
HttpSession session = req.getSession(true);
session.setAttribute("user",user);
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/blog_login.css">
</head>
<body>
<div class="nav">
<img src="image/head.jpg" alt="">
<span>我的博客系统</span>
<div class="spacer"></div>
<a href="blog_list.html">主页</a>
<a href="blog_edit.html">写博客</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">
<input type="submit" id="submit" value="提交">
</div>
</div>
</form>
</div>
</body>
</html>
先来一个错的:
是对的话(我们数据库里有这个用户)他就会直接跳回列表页
注册:
package controller;
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("/register")
public class RegisterServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf8");
resp.setCharacterEncoding("utf8");
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;
}
UserDao userDao = new UserDao();
User user1 = userDao.selectByName(username);
if(user1 != null){
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write("用户名已被占用,请更改用户名!!!");
return;
}
User user = new User();
user.setUsername(username);
user.setPassword(password);
userDao.insert(user);
HttpSession session = req.getSession(true);
session.setAttribute("user",user);
resp.sendRedirect("blog_list.html");
}
}
<!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_register.css">
</head>
<body>
<div class="nav">
<img src="image/wallhaven-72keg9.jpg" alt="">
<span>我的博客系统</span>
<div class="spacer"></div>
<a href="blog_list.html">主页</a>
<a href="blog_edit.html">写博客</a>
<a href="blog_login.html">登录</a>
</div>
<div class="login-container">
<form action="register" method="post">
<div class="login-dialog">
<h3>注册</h3>
<div class="row">
<span>用户名</span>
<input type="text" id="username" name="username" placeholder="输入用户名">
</div>
<div class="row">
<span>密码</span>
<input type="password" id="password" name="password" placeholder="输入密码">
</div>
<div class="row">
<input type="submit" id="submit" value="注册">
</div>
</div>
</form>
</div>
</body>
</html>
实现强制要求登录的 当用户访问 博客列表页 和 博客详情页 时, 如果用户当前尚未登陆, 就自动跳转到登陆页面.
这个可以在博客列表页/详情页,加载的时候,通过 ajax 访问一下服务器,获取到当前的登录状态,看看能不能获取到,如果获取到了,就说明当前雀氏是已经登陆了,此时就可以留在这个页面,如果没有获取到,说明是未登录的,就会跳转到登录页面让你登录…
约定前后端交互接口
[请求]
GET/login
[响应]
HTTP/1.1 200OK
Content-Type:application/json
{
userId: 1,
username: 'zhangsan',
}
登陆了,就直接返回当前登录的用户信息 如果未登录,则直接返回一个userId 为 0 的对象
添加后的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("utf8");
resp.setCharacterEncoding("utf8");
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println("username="+username+",password="+password);
if(username == null || "".equals(username) || password == null || "".equals(password)){
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("当前的用户名或密码为空!!");
return;
}
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;
}
HttpSession session = req.getSession(true);
session.setAttribute("user",user);
resp.sendRedirect("blog_list.html");
}
@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){
User user = new User();
resp.getWriter().write(objectMapper.writeValueAsString(user));
return;
}
User user = (User) session.getAttribute("user");
if(user == null){
user = new User();
resp.getWriter().write(objectMapper.writeValueAsString(user));
return;
}
user.setPassword("");
resp.getWriter().write(objectMapper.writeValueAsString(user));
}
}
添加后的blog_list.html
<!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="image/head.jpg" alt="">
<span>我的博客系统</span>
<!-- 空白元素, 用来占位置 -->
<div class="spacer"></div>
<a href="blog_list.html">主页</a>
<a href="blog_edit.html">写博客</a>
<a href="logout">注销</a>
</div>
<!-- 这里的 .container 作为页面的版心 -->
<div class="container">
<!-- 左侧个人信息 -->
<div class="left">
<!-- 表示整个用户信息区域. -->
<div class="card">
<img src="image/gamegirl.jpg" alt="">
<h3></h3>
<a href="#">github 地址</a>
<div class="counter">
<span>文章</span>
<span>分类</span>
</div>
<div class="counter">
<span>999</span>
<span>999</span>
</div>
</div>
</div>
<!-- 右侧内容详情 -->
<div class="right">
<!-- .blog 就对应一个博客 -->
<!-- <div class="blog">
<div class="title">
我的第一篇博客
</div>
<div class="date">
2022-05-05 20:52:00
</div>
<div class="desc">
从今天起, 我要认真敲代码. Lorem ipsum dolor sit amet consectetur adipisicing elit. Nulla alias tenetur ut velit ex voluptatibus consequatur quam exercitationem, assumenda ea blanditiis repudiandae? Repellendus tenetur nostrum asperiores molestias doloremque cupiditate maiores.
</div>
<a href="#">查看全文 >> </a>
</div> -->
</div>
</div>
</div>
<script src="js/jquery.min.js"></script>
<script>
function getBlogList() {
$.ajax({
type: 'get',
url: 'blog',
success: function(body) {
let rightDiv = document.querySelector('.right');
rightDiv.innerHTML = '';
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_detail.html?blogId=' + blog.blogId;
blogDiv.appendChild(a);
rightDiv.appendChild(blogDiv);
}
},
error: function() {
alert("获取博客列表失败!");
}
});
}
getBlogList();
function getUserInfo(pageName) {
$.ajax({
type: 'get',
url: 'login',
success: function(body) {
if (body.userId && body.userId > 0) {
console.log("当前用户登录成功! 用户名: " + body.username);
if (pageName == 'blog_list.html') {
changeUserName(body.username);
}
} else {
alert("当前您尚未登录! 请登录后再访问博客列表!");
location.assign('blog_login.html');
}
},
error: function() {
alert("当前您尚未登录! 请登录后再访问博客列表!");
location.assign('blog_login.html');
}
});
}
getUserInfo('blog_list.html');
</script>
</body>
</html>
这样我们未登录去访问列表页的时候就会出现让你登录了才行: 详情页也可以有这样的功能,就可以把这段逻辑放入公共样式,这样的可以引用了
4. 实现显示用户信息
我们期望这个信息可以随着用户登陆而发生改变.
如果当前页面是博客列表页, 则显示当前登陆用户的信息. 如果当前页面是博客详情页, 则显示该博客的作者用户信息.
4.1 约定前后端交互接口
在博客列表页,获取登录的用户的用户信息
[请求]
GET /user
[响应] {
userId: 1,
username: test
}
在博客详情页, 获取当前文章作者的用户信息
[请求]
GET /user?blogId=1
[响应] {
userId: 1,
username: test
}
注意:
针对博客详情页的时候,用户名并不能正确的显示谁是谁的,只能显示当前登录的名字,因为我们用的公共样式,所以,此处我们要进行处理一下,比如我访问的是 lisi的文章,用户名应该显示 lisi,这个时候我们就需要提供一个新的接口,这个接口可以让客户端指定 blogId ,获取指定 blogId 的作者信息!!
4.2 实现服务器代码
这里主要针对详情页的代码
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;
@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;
}
BlogDao blogDao = new BlogDao();
Blog blog = blogDao.selectOne(Integer.parseInt(param));
if(blog == null){
resp.getWriter().write("{\"ok\": false,\"reason\":\"要查询的博客不存在!!\" }");
return;
}
UserDao userDao = new UserDao();
User author = userDao.selectById(blog.getUserId());
if(author == null){
resp.getWriter().write("{\"ok\": false,\"reason\":\"要查询的用户不存在!!\" }");
return;
}
author.setPassword("");
resp.getWriter().write(objectMapper.writeValueAsString(author));
}
}
这个就是在详情页的时候,要显示作者信息,让客户端传一个博客 id 过去,服务器在里面找,在返回数据
4.3 实现客户端代码
修改上述blog_list.html和blog_detail.html代码 实现随登录过后返回的是用户名
common.js
function getUserInfo(pageName) {
$.ajax({
type: 'get',
url: 'login',
success: function(body) {
if (body.userId && body.userId > 0) {
console.log("当前用户登录成功! 用户名: " + body.username);
if (pageName == 'blog_list.html') {
changeUserName(body.username);
}
} else {
alert("当前您尚未登录! 请登录后再访问博客列表!");
location.assign('blog_login.html');
}
},
error: function() {
alert("当前您尚未登录! 请登录后再访问博客列表!");
location.assign('blog_login.html');
}
});
}
function changeUserName(username) {
let h3 = document.querySelector('.card>h3');
h3.innerHTML = username;
}
blog_list.html
**<!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="image/head.jpg" 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="container">
<div class="left">
<div class="card">
<img src="image/gamegirl.jpg" alt="">
<h3></h3>
<a href="#">github 地址</a>
<div class="counter">
<span>文章</span>
<span>分类</span>
</div>
<div class="counter">
<span>999</span>
<span>999</span>
</div>
</div>
</div>
<div class="right">
</div>
</div>
</div>
<script src="js/jquery.min.js"></script>
<script>
function getBlogList() {
$.ajax({
type: 'get',
url: 'blog',
success: function(body) {
let rightDiv = document.querySelector('.right');
rightDiv.innerHTML = '';
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_detail.html?blogId=' + blog.blogId;
blogDiv.appendChild(a);
rightDiv.appendChild(blogDiv);
}
},
error: function() {
alert("获取博客列表失败!");
}
});
}
getBlogList();
</script>
<script src="js/common.js"></script>
<script>
getUserInfo('blog_list.html');
</script>
</body>
</html>
blog_detail.html
<!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">
<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.js"></script>
</head>
<body>
<div class="nav">
<img src="image/head.jpg" 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="container">
<div class="left">
<div class="card">
<img src="image/gamegirl.jpg" alt="">
<h3></h3>
<a href="https://gitee.com/big-white-rice">github 地址</a>
<div class="counter">
<span>文章</span>
<span>分类</span>
</div>
<div class="counter">
<span>999</span>
<span>999</span>
</div>
</div>
</div>
<div class="right">
<div class="blog-content">
<h3></h3>
<div class="date"></div>
<div id="content" style="opacity: 80%">
</div>
</div>
</div>
</div>
<script>
function getBlogDetail() {
$.ajax({
type: 'get',
url: 'blog' + location.search,
success: function(body) {
let h3 = document.querySelector(".blog-content>h3");
h3.innerHTML = body.title;
let dateDiv = document.querySelector('.date');
dateDiv.innerHTML = body.postTime;
editormd.markdownToHTML('content', {
markdown: body.content
});
}
});
}
getBlogDetail();
function getUserInfo(pageName) {
$.ajax({
type: 'get',
url: 'login',
success: function(body) {
if (body.userId && body.userId > 0) {
console.log("当前用户登录成功! 用户名: " + body.username);
getAuthorInfo(body);
} else {
alert("当前您尚未登录! 请登录后再访问博客列表!");
location.assign('blog_login.html');
}
},
error: function() {
alert("当前您尚未登录! 请登录后再访问博客列表!");
location.assign('blog_login.html');
}
});
}
getUserInfo("blog_detail.html");
function getAuthorInfo(user) {
$.ajax({
type: 'get',
url: 'authorInfo' + location.search,
success: function(body) {
if (body.username) {
changeUserName(body.username);
if (body.username == user.username) {
let navDiv = document.querySelector('.nav');
let a = document.createElement('a');
a.innerHTML = '删除';
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>
</body>
</html>
总结: 1: 对于博客列表页,要显示登录用户信息,登录用户信息在检测用户是否登录的接口中,就已经拿到了,只需要把拿到的用户信息,显示到界面上即可(只需要动前端,后端不必修改) 2: 对于博客详情页,要显示出文章作者的信息,需要提供一个新的 api ,让客户端传一个博客 id 过去,然后再服务器这里查询到用户信息,查到之后,返回给页面
页面和服务器之间的交互,不一定只有一次,大概率是会有多次的 我们这里写的博客列表页涉及到两次交互: 1:从服务器拿到博客列表数据 2:从服务器拿到当前的登录用户信息 博客详情页涉及到三次交互: 1:从服务器拿到博客的详细内容 2:从服务器拿到了当前的登录用户信息 3:从服务器拿到了当前文章的作者信息 我们以后可能还会遇到不止两次三次的,有些可能复杂的十几次也是正常的…
5. 实现注销登录
就是退出登录状态 在导航栏安排一个"注销按钮",当用户点击注销之后,就会在服务器上取消登录状态,并且跳回到登录页面,希望在点击之后,能够给服务器发送一个 HTTP 请求,从而触发注销动作(其实就是把会话中的信息给删除掉)
5.1 约定前后端接口
[请求]
GET /logout
[响应]
HTTP/1.1 302
Location: login.html
5.2 实现服务器代码
从 session 中删除掉保存的 User 对象. 响应重定向到 login.html 页面.
package controller;
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.getWriter().write("当前用户尚未登录! 无法注销");
return;
}
session.removeAttribute("user");
resp.sendRedirect("blog_login.html");
}
}
5.3 实现客户端代码
只需要把注销按钮的href属性(blog_list.html,blog_detail.html,blog_edit.html)改了就行 ,注意不是 /logout
6. 实现发布博客
在博客编辑页中,当用户输入博客标题,和正文之后,点击发布,这个时候就会把博客数据提交到服务器,由服务器存储到数据中
6.1 约定前后端接口
[请求]
POST /blog
Content-Type: application/x-www-form-urlencoded
title=标题&content=正文...
[响应]
HTTP/1.1 302
Location: blog_list.html
6.2 实现服务器代码
在 BlogServlet 里面添加 一个 doPost 方法,来处理 post 请求 核心的操作就是读取请求中的标题和正文,构造 Blog 对象,并插入数据库
package controller;
import com.fasterxml.jackson.databind.ObjectMapper;
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;
import java.util.List;
@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();
String param = req.getParameter("blogId");
if (param == null) {
List<Blog> blogs = blogDao.selectAll();
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);
}
}
@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 = new Blog();
blog.setTitle(title);
blog.setContent(content);
blog.setUserId(user.getUserId());
BlogDao blogDao = new BlogDao();
blogDao.insert(blog);
resp.sendRedirect("blog_list.html");
}
}
6.3 实现客户端代码
就是需要一个form表单,把这里的内容嵌套上
<!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">
<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.js"></script>
</head>
<body>
<div class="nav">
<img src="image/head.jpg" 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" id="title">
<input type="submit" value="发布文章" id="submit">
</div>
<div id="editor">
<textarea name="content" style="display: none"></textarea>
</div>
</form>
</div>
<script>
let editor = editormd("editor",{
width: "100%",
height: "calc(100% - 50px)",
markdown: "# 在这里写下一篇博客",
path: "editor.md/lib/",
saveHTMLToTextarea: true,
});
</script>
</body>
</html>
7. 实现删除博客
界面上的处理: 进入用户详情页时, 如果当前登陆用户正是文章作者, 则在导航栏中显示 “删除” 按钮, 用户点击时则删除该文章. 不是就不显示删除按钮 服务器处理: 用户点击删除按钮,触发一个HTTP 请求,HTTP 请求就会让服务器删除指定博客,服务器收到请求后,就会把这个博客从数据库里删除掉… 需要实现两件事: 判定当前博客详情页中是否要显示 “删除” 按钮 实现删除逻辑.
7.1 约定前后端交互接口
[请求]
GET /blogDelete?blogId=1
[响应]
直接跳转到 博客列表页 即可
7.2 实现服务器代码
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 {
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;
}
String blogId = req.getParameter("blogId");
if (blogId == null || "".equals(blogId)) {
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("当前 blogId 参数不对!");
return;
}
BlogDao blogDao = new BlogDao();
Blog blog = blogDao.selectOne(Integer.parseInt(blogId));
if (blog == null) {
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("当前要删除的博客不存在!");
return;
}
if (user.getUserId() != blog.getUserId()) {
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("当前登录的用户不是作者, 没有权限删除!");
return;
}
blogDao.delete(Integer.parseInt(blogId));
resp.sendRedirect("blog_list.html");
}
}
7.3 实现客户端代码
修改 blog_detail.html
<!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">
<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.js"></script>
</head>
<body>
<div class="nav">
<img src="image/head.jpg" 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="container">
<div class="left">
<div class="card">
<img src="image/gamegirl.jpg" alt="">
<h3></h3>
<a href="https://gitee.com/big-white-rice">github 地址</a>
<div class="counter">
<span>文章</span>
<span>分类</span>
</div>
<div class="counter">
<span>999</span>
<span>999</span>
</div>
</div>
</div>
<div class="right">
<div class="blog-content">
<h3></h3>
<div class="date"></div>
<div id="content" style="opacity: 80%">
</div>
</div>
</div>
</div>
<script>
function getBlogDetail() {
$.ajax({
type: 'get',
url: 'blog' + location.search,
success: function(body) {
let h3 = document.querySelector(".blog-content>h3");
h3.innerHTML = body.title;
let dateDiv = document.querySelector('.date');
dateDiv.innerHTML = body.postTime;
editormd.markdownToHTML('content', {
markdown: body.content
});
}
});
}
getBlogDetail();
function getUserInfo(pageName) {
$.ajax({
type: 'get',
url: 'login',
success: function(body) {
if (body.userId && body.userId > 0) {
console.log("当前用户登录成功! 用户名: " + body.username);
getAuthorInfo(body);
} else {
alert("当前您尚未登录! 请登录后再访问博客列表!");
location.assign('blog_login.html');
}
},
error: function() {
alert("当前您尚未登录! 请登录后再访问博客列表!");
location.assign('blog_login.html');
}
});
}
getUserInfo("blog_detail.html");
function getAuthorInfo(user) {
$.ajax({
type: 'get',
url: 'authorInfo' + location.search,
success: function(body) {
if (body.username) {
changeUserName(body.username);
if (body.username == user.username) {
let navDiv = document.querySelector('.nav');
let a = document.createElement('a');
a.innerHTML = '删除';
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>
</body>
</html>
8. 实现用户博客总数显示
8.1 服务器端代码
package controller;
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 javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/num")
public class TotalServlet extends HttpServlet {
@Override
protected void doGet(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;
}
resp.setContentType("text/html;charset=utf8");
String blogId = req.getParameter("blogId");
BlogDao blogDao = new BlogDao();
if(blogId == null){
resp.getWriter().write(blogDao.selectTotal(user.getUserId())+"");
}else {
Blog blog = blogDao.selectOne(Integer.parseInt(blogId));
UserDao userDao = new UserDao();
User author = userDao.selectById(blog.getUserId());
resp.getWriter().write(blogDao.selectTotal(author.getUserId())+"");
}
}
}
8.2 实现客户端代码
在博客列表页和详情页加上:
<script>
$.ajax({
type: 'get',
url: 'num'+location.search,
success: function (data){
changUserNum(data);
}
});
function changUserNum(num){
let total = document.querySelector('.total');
total.innerHTML = num;
}
</script>
9. 实现修改功能
9.1 实现服务器端代码
package controller;
import com.fasterxml.jackson.databind.ObjectMapper;
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("/update")
public class BlogUpdateServlet extends HttpServlet {
private ObjectMapper objectMapper = new ObjectMapper();
private int BlogId = 0;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json;charset=utf-8");
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;
}
String blogId = req.getParameter("blogId");
if (blogId == null || "".equals(blogId)) {
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("当前 blogId 参数不对!");
return;
}
BlogDao blogDao = new BlogDao();
BlogId = Integer.parseInt(blogId);
Blog blog = blogDao.selectOne(Integer.parseInt(blogId));
if (blog == null) {
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("当前要修改的博客不存在!");
return;
}else{
resp.setContentType("application/json;charset=utf-8");
resp.getWriter().write(objectMapper.writeValueAsString(blog));
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("application/json;charset=utf8");
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;
}
String title = req.getParameter("title");
String content = req.getParameter("content");
if(title == null || "".equals(title) || content == null || "".equals(content)){
resp.getWriter().write("<script>alert('有内容为空')</script>");
return;
}
int blogId = BlogId;
BlogDao blogDao = new BlogDao();
Blog blog = new Blog();
blog.setTitle(title);
blog.setContent(content);
blog.setBlogId(blogId);
blogDao.update(blog);
resp.sendRedirect("blog_list.html");
}
}
9.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/blog_edit.css">
<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.js"></script>
</head>
<body>
<div class="nav">
<img src="image/head.jpg" 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="update" method="post" style="height: 100%">
<div class="title">
<input type="text" placeholder="在此处输入标题" name="title" id="title">
<input type="submit" value="发布文章" id="submit">
</div>
<div id="editor">
<textarea class="content" name="content" style="display: none"></textarea>
</div>
</form>
</div>
<script>
let editor = editormd("editor",{
width: "100%",
height: "calc(100% - 50px)",
path: "editor.md/lib/",
saveHTMLToTextarea: true,
});
</script>
<script>
function getEditUpdate(){
$.ajax({
type: 'get',
url: 'update' + location.search,
success: function(body){
let title = document.querySelector('.title>#title')
title.innerHTML = body.title;
let content = document.querySelector('.content')
content.innerHTML = body.content;
}
});
}
getEditUpdate();
</script>
</body>
</html>
文件地址
|