- 准备工作
- 1.创建maven项目
- 2. 引入依赖(servlet,jackson,mysql)
- 3.创建必要的目录
- 4. 编写代码
- 5/6. 打包部署程序——直接基于smart Tomcat
- 如何下载tomcat
- 如何下载smart Tomcat
- 7. 在浏览器中验证
- 编写数据库的操作代码
- 1.创建数据库/表结构—数据库设计
- 2. 封装数据库操作
- 2.1 先创建 DBUtil 封装数据库连接的操作
- 2.2 创建实体类(使用实体类来表示数据库中的一条记录)
- 2.3 封装针对数据的增删改查
- 约定前后端交互接口
- 1. 实现博客列表
- 1.1约定前后端交互接口
- 1.2 实现服务器代码
- 1.3 编写客户端代码
- 2. 实现博客详情
- 2.1 约定前后端交互接口
- 2.2 实现服务器代码
- 2.3 实现客户端代码
- 3. 实现登录
- 3.1 约定前后端交互接口
- 3.2 实现服务器代码
- 3.3 实现客户端代码
- 实现强制要求登录
- 约定前后端交互接口
- 实现服务器代码
- 实现客户端代码
- 4. 实现显示用户信息
- 4.1 约定前后端交互接口
- 4.2 实现服务器代码
- 4.3 实现客户端代码
- 5. 实现注销登录
- 5.1 约定前后端接口
- 5.2 实现服务器代码
- 5.3 实现客户端代码
- 6. 实现发布博客
- 6.1 约定前后端接口
- 6.2 实现服务器代码
- 6.3 实现客户端代码
- 7. 实现删除博客
- 7.1 约定前后端交互接口
- 7.2 实现服务器代码
- 7.3 实现客户端代码
引言:
准备工作 1.创建maven项目tomcat版本:8.5
开发工具:IDEA
jdk版本:jdk1.8.0_161
此项目是对本博主之前编写的一个纯HTML页面的博客系统进行的一个改进
依次点击File→New→Project,选择左侧的Maven项目,点击Next,然后填写项目名称,点击Finish,至此一个maven项目就创建好了。
2. 引入依赖(servlet,jackson,mysql)去中央仓库搜索下载即可,地址传送门(一般搜索关键字后第一个就是我们所需要的,注意版本)
//这个需要手动敲上去 javax.servlet javax.servlet-api 3.1.0 provided mysql mysql-connector-java 5.1.47 com.fasterxml.jackson.core jackson-databind 2.12.6.1
引入依赖后记得手动刷新一下,以防万一。(第一次引入的时候时间可能会长一些,要耐心等待,有的时候可能因为网络问题导致引入失败,这时候不要慌,多刷新几次试试)
web.xml新建的时候选择File选项
web.xml里面填写的内容,直接复制下面的代码即可:
4. 编写代码Archetype Created Web Application
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
如何下载tomcat
tomcat直接在官网下载即可:官网下载
下载完解压即可,解压的时候最好不要解压到带中文的文件夹里。
然后就按照下面的步骤进行部署⬇️⬇️⬇️
点击上方小绿三角运行,然后在浏览器中输入:http://localhost(也可以是127.0.0.1):8080/blog_system/hello
到这里准备工作算是做完了,接下来就可以执行接下来的步骤了⬇️
设计数据库,需要根据当前的需求来进行设计,而我们这个博客页面,一共需要以下几个页面:
- 博客列表页,显示博客的列表
- 博客详情页,点击博客列表页,上面列出的博客条目,跳转到的页面,显示博客的完整内容
- 登录页面
- 博客编辑页,基于editor.md搞一个markdown编辑器,基于这个页面来发布博客
我们需要以下需求:
- 存储博客:当点击发布的时候,博客被发布到服务器上,就要被存起来
- 存取博客:在博客列表页和博客详情页,能够拿到博客的内容
- 能够进行登录校验
我们设计表,就需要抓住需求中的实体(关键性的名词)
- 博客表:用来存储所有的博客数据
- 用户表:用户登录时需要用到
-- 编写建库建表的 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, -- 文章作者的 id
postTime datetime -- 发布时间
);
-- 给博客插点数据,后面方便我们进行测试
insert into blog values(null,'第一篇博客','好好学习',1,now());
insert into blog values(null,'第二篇博客','天天向上',1,now());
insert into blog values(null,'第三篇博客','明天开始学Java',1,now());
insert into blog values(null,'第四篇博客','努力去见易烊千玺',2,now());
insert into blog values(null,'第五篇博客','累死自己,卷死同学',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,'panpan','123');
insert into user values(null,'ajiao','123456');
2. 封装数据库操作
2.1 先创建 DBUtil 封装数据库连接的操作
package util;
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 bean;
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 Timestamp getPostTime() {
// return postTime;
// }
//把这里的getter方法给改了,不是返回一个时间戳对象,而是返回一个String(格式化好的时间)
public String getPostTime(){
//使用SimpleDateFormat来完成时间戳到格式化日期时间的转换
//这个转换过程,需要在构造方法中指定要转换的格式,然后调用format来进行转换
SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return simpleDateFormat.format(postTime);
}
public void setPostTime(Timestamp postTime) {
this.postTime = postTime;
}
}
User类
package bean;
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 封装针对数据的增删改查
BlogDao类我们把提供了增删改查这样的类,称为 DAO,所以我们可以把实现这类功能的类统一放在一个dao包里面。
package dao;
import bean.Blog;
import util.DBUtil;
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();
//4.关闭连接,释放资源
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtil.close(connection,statement,null);
}
}
//2.能够获取到博客表中的所有博客的信息(用于在博客列表页,此处每篇博客不一定会获取到完整的正文)
public ListselectAll(){
Connection connection=null;
PreparedStatement statement=null;
ResultSet resultSet=null;
Listblogs=new ArrayList<>();
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.getInt("userId"));
blog.setPostTime(resultSet.getTimestamp("postTime"));
blogs.add(blog);
}
} catch (SQLException e) {
e.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 {
connection=DBUtil.getConnection();
String sql="select * from blog where blogId=?";
statement= connection.prepareStatement(sql);
statement.setInt(1,blogId);
resultSet=statement.executeQuery();
//此处我们是使用主键来作为查询条件的,查询结果要么是1要么是0,所以用if即可
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.getInt("userId"));
blog.setPostTime(resultSet.getTimestamp("postTime"));
return blog;
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtil.close(connection,statement,resultSet);
}
return null;
}
//4.从博客表中,根据博客id删除博客
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 e) {
e.printStackTrace();
}finally {
DBUtil.close(connection,statement,null);
}
}
}
UserDao类
package dao;
import bean.User;
import util.DBUtil;
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 {
connection= DBUtil.getConnection();
String sql="select * from user where username=?";
statement= connection.prepareStatement(sql);
statement.setString(1,username);
resultSet=statement.executeQuery();
if(resultSet.next()){
User user=new User();
user.setUserId(resultSet.getInt("userId"));
user.setUsername(resultSet.getString("username"));
user.setPassword(resultSet.getString("password"));
return user;
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtil.close(connection,statement,resultSet);
}
return null;
}
//2.根据用户id来找用户信息
//博客详情页,就可以根据用户id来查询作者的名字,把作者名字显示出来
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();
//此处username使用unique约束,要么能查到一个,要么一个都查不到
if(resultSet.next()){
User user=new User();
user.setUserId(resultSet.getInt("userId"));
user.setUsername(resultSet.getString("username"));
user.setPassword(resultSet.getString("password"));
return user;
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtil.close(connection,statement,resultSet);
}
return null;
}
}
到此数据库操作都给准备好了,下面就开始编写前后端的代码了
约定前后端交互接口在编写前后端代码之前,先把之前纯页面的博客系统全部拷贝到webapp里面
博客系统:码云地址
[请求] GET/blog
[响应] [
{
blogId: 1,
title: "第一篇博客",
content: "博客正文",
userId: 1,
postTime: "2022-06-08 18:08:05"
},
{
blogId: 2,
title: "第二篇博客",
content: "博客正文",
userId: 2,
postTime: "2022-06-08 18:08:05"
},
...
]
1.2 实现服务器代码约定浏览器给服务器发送一个 GET /blog 这样的 HTTP 请求, 服务器给浏览器返回了一个 JSON 格式的数据
package servlet;
import bean.Blog;
import com.fasterxml.jackson.databind.ObjectMapper;
import dao.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();
Listblogs=blogDao.selectAll();
//把blog对象转成JSON格式
String respJson= objectMapper.writeValueAsString(blogs);
resp.setContentType("application/json;charset=utf8");
resp.getWriter().write(respJson);
}
}
1.3 编写客户端代码
博客列表
效果图如下:
2. 实现博客详情图中的用户名显示的是panpan,而上面的客户端代码中用户名给的是同学潘,这是因为后面我们要实现登录的是哪个用户就显示哪个用户名,因此这里有点差异。
2.1 约定前后端交互接口由于目前点击博客列表页的 “查看全文” , 进入博客详情页后是写死的内容,所以 我们期望能够根据当前的 博客 id 从服务器动态获取博客内容。
[请求]
GET /blog?blogId=1
[响应] {
HTTP/1.1 200OK
Content-Type:application/json;
{
blogId: 2,
title: "第二篇博客",
content: "博客正文",
userId: 1,
postTime: "2022-06-08 18:08:05"
},
2.2 实现服务器代码
获取详情页跟获取列表基本相同,所以我们只需要更改一下代码判断是否带参数 blogId,以此来返回是列表页还是详情页。
package servlet;
import bean.Blog;
import com.fasterxml.jackson.databind.ObjectMapper;
import dao.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 javax.servlet.http.HttpSession;
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格式,然后直接返回即可
//先尝试获取到rep中的blogId参数,如果参数存在,说明是要请求博客详情
//如果该参数不存在,说明是要请求博客的列表
BlogDao blogDao=new BlogDao();
resp.setContentType("application/json;charset=utf8");
String param=req.getParameter("blogId");
if(param==null){
//不存在参数,获取博客列表
Listblogs=blogDao.selectAll();
//把blog对象转成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);
}
}
}
2.3 实现客户端代码
博客详情页
效果图如下:
3. 实现登录注意:当我们在进行程序验证的时候,要牢记一件事情,浏览器的缓存可能会影响到结果,你可能修改了之后再去同一个浏览器访问的时候,他并没有发生改变,因为浏览器可能把你上次访问的页面给保存到本地了,下次在尝试访问的时候访问的就是本地的内容,所以这个时候我们要按下: Ctrl + F5强制刷新一下
- 登陆页面提供一个 form 表单,通过 form 的方式把用户名密码提交给服务器
- 服务器端验证用户名密码是否正确
- 如果密码正确, 则在服务器端创建 Session,并把 sessionId 通过 Cookie 返回给浏览器
[请求] POST /login Content-Type: application/x-www-form-urlencoded username=panpan&password=123 [响应] HTTP/1.1 302 Location: https://blog.csdn.net/m0_46468731/article/details/blog_list.html//登录成功以后,自动跳转到主页(博客列表页https://blog.csdn.net/m0_46468731/article/details/blog_list.html)3.2 实现服务器代码
package servlet;
import bean.User;
import com.fasterxml.jackson.databind.ObjectMapper;
import dao.UserDao;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
private ObjectMapper objectMapper=new ObjectMapper();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf8");
resp.setCharacterEncoding("utf8");
//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);
//返回一个重定向报文,跳转到博客列表页
resp.sendRedirect("https://blog.csdn.net/m0_46468731/article/details/blog_list.html");
}
}
3.3 实现客户端代码
登录页面
实现强制要求登录
当用户访问 博客列表页 和 博客详情页 时, 如果用户当前尚未登陆, 就自动跳转到登陆页面
约定前后端交互接口这个可以在博客列表页/详情页加载的时候,通过 ajax 访问一下服务器,获取当前的登录状态,看看能不能获取到,如果获取到了,就说明当前确实是已经登陆了,此时就可以留在这个页面;如果没有获取到,说明是未登录的,就会跳转到登录页面让你登录。
[请求]
GET/login
[响应]
HTTP/1.1 200OK
Content-Type:application/json
{
userId: 1,
username: 'panpan',
}
登陆了,就直接返回当前登录的用户信息;如果未登录,则直接返回一个userId 为 0 的对象
实现服务器代码在LoginServlet中加入以下代码即可:
//这个方法用来让前端检测当前的登陆状态
@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对象,也视为未登录
user=new User();
resp.getWriter().write(objectMapper.writeValueAsString(user));
return;
}
//已经登录的状态
//注意,此处不要把密码给返回到前端
user.setPassword("");
resp.getWriter().write(objectMapper.writeValueAsString(user));
}
实现客户端代码
在https://blog.csdn.net/m0_46468731/article/details/blog_list.html中加入以下代码即可:
//加上一个逻辑,通过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{
//登录失败,让前端页面跳转到blog_login.html
alert("当前您尚未登录!请登录后再访问博客列表!");
location.assign('blog_login.html');
}
},
error:function(){
alert("当前您尚未登录!请登录后再访问博客列表!");
location.assign('blog_login.html');
}
});
}
getUserInfo();
博客详情页也可以有这样的功能,把这段代码添加到https://blog.csdn.net/m0_46468731/article/details/blog_detail.html中即可
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{
//登录失败,让前端页面跳转到blog_login.html
alert("当前您尚未登录!请登录后再访问博客详情!");
location.assign('blog_login.html');
}
},
error:function(){
alert("当前您尚未登录!请登录后再访问博客列表详情!");
location.assign('blog_login.html');
}
});
}
getUserInfo();
效果图如下:
4.1 约定前后端交互接口我们期望用户信息可以随着用户的登陆而发生改变,如果当前页面是博客列表页,则显示当前登陆用户的信息;如果当前页面是博客详情页,则显示该博客的作者用户信息。
在博客列表页,获取登录用户的用户信息:
[请求]
GET /user
[响应] {
userId: 1,
username: test
}
在博客详情页,获取当前文章作者的用户信息:
[请求]
GET /user?blogId=1
[响应] {
userId: 1,
username: test
}
4.2 实现服务器代码
主要针对博客详情页:
package servlet;
import bean.Blog;
import bean.User;
import com.fasterxml.jackson.databind.ObjectMapper;
import dao.BlogDao;
import dao.UserDao;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import 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;
}
//根据当前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));
}
}
4.3 实现客户端代码
https://blog.csdn.net/m0_46468731/article/details/blog_list.html对上述https://blog.csdn.net/m0_46468731/article/details/blog_list.html和https://blog.csdn.net/m0_46468731/article/details/blog_detail.html代码进行修改,实现登录成功过后显示相应的用户名
//加上一个逻辑,通过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);
//根据当前用户登录的情况,把当前用户名设置到界面上
ChangeUserName(body.username);
}else{
//登录失败,让前端页面跳转到blog_login.html
alert("当前您尚未登录!请登录后再访问博客列表!");
location.assign('blog_login.html');
}
},
error:function(){
alert("当前您尚未登录!请登录后再访问博客列表!");
location.assign('blog_login.html');
}
});
}
getUserInfo();
function ChangeUserName(username){
let h3=document.querySelector('.card>h3');
h3.innerHTML=username;
}
https://blog.csdn.net/m0_46468731/article/details/blog_detail.html
function ChangeUserName(username){
let h3=document.querySelector('.card>h3');
h3.innerHTML=username;
}
//从服务器获取一下当前博客的作者信息,并显示到界面上
//参数user就是刚才从服务器拿到的当前登陆用户的信息
function getAuthorInfo(user){
$.ajax({
type:'get',
url:'authorInfo'+location.search,
success:function(body){
//此处的body,就是服务器返回的User对象,是文章的作者信息
if(body.username){
//如果响应中的username存在,就把这个值设置到页面上
ChangeUserName(body.username);
}else{
console.log("获取作者信息失败!"+body.reason);
}
}
});
}
效果图如下:
总结:
- 对于博客列表页,要显示登录用户信息,由于登录用户信息在检测用户是否登录的接口中,就已经拿到了,所以只需要把拿到的用户信息,显示到界面上即可(只需要动前端,后端不必修改)
- 对于博客详情页,要显示出文章作者的信息,需要提供一个新的 api ,让客户端传一个博客 id 过去,然后在服务器这里查询到用户信息,查到之后返回给页面
页面和服务器之间的交互,不一定只有一次,大概率是会有多次的。
我们这里写的博客列表页涉及到两次交互:
- 从服务器拿到博客列表数据
- 从服务器拿到当前的登录用户信息
博客详情页涉及到三次交互:
- 从服务器拿到博客的详细内容
- 从服务器拿到了当前的登录用户信息
- 从服务器拿到了当前文章的作者信息
我们以后可能还会遇到不止两次三次的,有些可能复杂的十几次也是正常的
5. 实现注销登录5.1 约定前后端接口就是退出登录状态,在导航栏安排一个"注销"按钮,当用户点击注销之后,就会在服务器上取消登录状态,并且跳回到登录页面,希望在点击之后,能够给服务器发送一个 HTTP 请求,从而触发注销动作(其实就是把会话中的信息给删除掉)
[请求] GET /https://blog.csdn.net/m0_46468731/article/details/logout [响应] HTTP/1.1 302 Location: login.html5.2 实现服务器代码
从 session 中删除掉保存的 User 对象,响应重定向到 login.html 页面
package servlet;
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("/https://blog.csdn.net/m0_46468731/article/details/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 实现客户端代码
只需要把https://blog.csdn.net/m0_46468731/article/details/blog_list.html,https://blog.csdn.net/m0_46468731/article/details/blog_detail.html,https://blog.csdn.net/m0_46468731/article/details/blog_edit.html中a标签中的href属性改为https://blog.csdn.net/m0_46468731/article/details/logout即可❗❗
注销6. 实现发布博客
6.1 约定前后端接口在博客编辑页中,当用户输入博客标题和正文之后,点击发布,这个时候就会把博客数据提交到服务器,由服务器存储到数据库中。
[请求] POST /blog Content-Type: application/x-www-form-urlencoded title=标题&content=正文... [响应] HTTP/1.1 302 Location: https://blog.csdn.net/m0_46468731/article/details/blog_list.html6.2 实现服务器代码
在 BlogServlet 里面添加 一个 doPost 方法来处理 post 请求,核心的操作就是读取请求中的标题和正文,构造 Blog 对象,并插入数据库
@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("https://blog.csdn.net/m0_46468731/article/details/blog_list.html");
}
6.3 实现客户端代码
需要一个form表单,把这里的内容嵌套上:
博客编辑页
效果图如下:
删除博客,肯定不是可以随便删除的,约定只有自己能删除自己的博客,不能删除别人的博客❗❗ (此处咱们暂时不考虑管理员)
界面上的处理: 在博客详情页这里,就去进行判定,判定看当前这个博客的作者,是否就是登录的用户。如果是,就在导航栏里显示一个“删除按钮";如果不是,就不显示删除按钮
服务器处理: 用户点击删除按钮,触发一个HTTP请求, HTTP请求就会让服务器删除指定的博客,服务器收到请求之后,就会把这个博客从数据库里给删除掉
[请求] GET /blogDelete?blogId=1 [响应] 直接跳转到 博客列表页 即可7.2 实现服务器代码
package servlet;
import bean.Blog;
import bean.User;
import dao.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 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("https://blog.csdn.net/m0_46468731/article/details/blog_list.html");
}
}
7.3 实现客户端代码
博客详情页
效果图如下:
目前实现的功能只有这么多,具体其他功能以后随缘实现❗❗❗




