博客系统(Servlet)

我们的目标是实现一个带有服务器版本的博客系统(重点关注后端开发)

1.准备工作

1)创建web项目

2)创建相应的目录结构、

博客系统(Servlet)_第1张图片

 3)配置pom.xml



    4.0.0

    org.example
    blog_system
    1.0-SNAPSHOT

    
        8
        8
    

    
        
        
            javax.servlet
            javax.servlet-api
            3.1.0
            provided
        

        
        
            com.fasterxml.jackson.core
            jackson-databind
            2.15.0
        

        
        
            mysql
            mysql-connector-java
            5.1.49
        
    

    
    war
    
        
        BlogSystem
    

2.前端代码

2.1创建相关的目录

博客系统(Servlet)_第2张图片

2.2每个目录或文件的内容

我们查看我的博客根据相关路径创建相应的文件,复制相应的内容即可,所需要复制的内容只有上述标记的即可。

2.3editor

editor存放的是markdown编辑器的内容,主要用于编写相应的博客。这个我们下载相应的代码即可。

  • Editor.md - 开源在线 Markdown 编辑器 (pandao.github.io) 打开相应的网址
  • 点击下载安装,然后点击使用giteehub下载

博客系统(Servlet)_第3张图片

  •  安装好后,我们有相应的压缩包,然后解压缩,把总文件夹相应的名字修改成一下,把他放到相应的目录下面即可

2.4页面效果预览

登录页面

博客列表页】

博客编辑页面】

博客详情页】

3.数据库设计

3.1表的设计

博客系统主要有两个重要数据,一个博客数据,一个是用户数据。所以我们需要设计两张表,一张是文章表,一张是用户表

文章表】文章表所需要的元素有 博客id博客标题博客正文博客作者id发布时间

用户表】用户表所需要的内容有 用户id用户名用户密码

【完整的SQL语句】

我们可以在src/main目录下,创建一个db.sql,用于记录创建数据库时的语句,这样在部署到不同的服务器时,我们只需要复制一下即可

博客系统(Servlet)_第4张图片

-- 一班对于建表的 sql 都会单独搞一个文件, .sql文件来保存
-- 后续程序可能需要在不同的主机上进行部署,部署的时候就需要在对应的主机上把数据库也创建好。
-- 把建表 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(20),
    content varchar(4096),
    userId int,
    postTime datetime);

-- 默认先删除一下残留的数据
drop table if exists user;
-- 创建用户表
create table user(
    userId int primary key auto_increment,
    username varchar(50) unique,
    password varchar(50));




-- 用于测试使用的些许数据
-- 用户数据
insert into user values(null, 'zhangsan', '123'), (null, 'lisi', '123');
-- 博客数据
insert into blog values(null, '我的第一篇博客', '这是第一篇博客的内容。', 1, '2023-06-04 12:00:00');
insert into blog values(null, '我的第二篇博客', '这是第二篇博客的内容。', 1, '2023-06-05 12:00:00');

 4.封装数据库操作代码

我们发现使用JDBC进行数据库操作的时候,很多步骤都是固定的,如设置URL,设置用户,设置密码,建立连接,关闭资源等操作,我们将这些步骤提取出来以简化代码

4.1创建DBUtil

通过一个单例模式来获取数据库连接。

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;

/**
 * Describe:封装数据库操作代码
 * User:lenovo
 * Date:2023-07-03
 * Time:15:29
 */
public class DBUtil {
    //使用单例模式
    private static volatile DataSource dataSource= null;

    private static DataSource getDataSource() {
        //这里使用一个if会每次都要加锁,使用两个if不用每次都加锁,同时用能判断dataSource == null
        if(dataSource == null) {
            synchronized(DBUtil.class) {
                if(dataSource == null) {
                    dataSource = new MysqlDataSource();
                    ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/blog_system?characterEncoding=utf8&useSSL=false");
                    ((MysqlDataSource)dataSource).setUser("root");
                    ((MysqlDataSource)dataSource).setPassword("1020118096");
                }
            }
        }
        return dataSource;
    }

    public static Connection getConnection() throws SQLException {
        return getDataSource().getConnection();
    }

    public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet) throws SQLException {
        if(connection != null) {
            connection.close();
        }
        if(statement != null) {
            statement.close();
        }
        if(resultSet != null) {
            resultSet.close();
        }
    }
}

4.2创建Blog类和User类

【Blog】

package model;

import java.sql.Timestamp;

/**
 * Describe:表示一篇博客的类
 * User:lenovo
 * Date:2023-07-03
 * Time:15:47
 */
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() {
        //我们可以打印一下原来的类型,看看到Java中是什么样子
        System.out.println(postTime);
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        return format.format(postTime);
    }

    public void setPostTime(Timestamp postTime) {
        this.postTime = postTime;
    }
}

 【User】

package model;

/**
 * Describe:表示用户相关信息的类
 * User:lenovo
 * Date:2023-07-03
 * Time:15:51
 */
public class User {
    private int userId;
    private String username;
    private String password;
    
    //自动生成相应的get和set方法

    public int getUserId() {
        return userId;
    }

    public void setUserId(int userId) {
        this.userId = userId;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

4.3创建BlogDao类和UserDao类

什么是"DAO"?

DAO的全程是“data access object"(数据访问对象),主要功能就是对某个数据库表进行增删查改。一般每张数据库表会对应一个DAO类。这是一种给类命名的习惯做法,并不是强制要求的。

创建BlogDao类,针对博客表进行操作

  • insert:插入一个Blog对象到blog表种
  • selectAll:从blog表中查找所有的Blog对象
  • selectOne:从blog表中查找指定的Blog对象
  • delete:从blog表中删除指定的Blog对象
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;

/**
 * Describe:对一个博客进行操作
 * User:lenovo
 * Date:2023-07-03
 * Time:16:09
 */
public class BlogDao {
    //把一个Blog对象插入到数据库中
    public void insert(Blog blog) throws SQLException {
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            //1.建立连接
            connection = DBUtil.getConnection();
            //2.构造SQL语句
            String sql = "insert into blog values(null, ?, ?, ?, ?)";
            statement = connection.prepareStatement(sql);
            statement.setString(1, blog.getTitle());
            statement.setString(2, blog.getContent());
            statement.setInt(3, blog.getUserId());
            statement.setString(4, blog.getPostTime());
            //执行sql语句
            statement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(connection, statement, null);
        }
    }

    //查询 blog 表中所有博客数据
    public List selectAll() throws SQLException {
        List 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() > 100) {
                    content = content.substring(0, 100) +"...";
                }
                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;
    }

    //指定博客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();

            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();
        }
        return null;
    }

    //指定 博客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();
        }
    }
}

创建UserDao类,实现对用户表的增删查改。

package model;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * Describe:对用户进行操作
 * User:lenovo
 * Date:2023-07-04
 * Time:10:18
 */
public class UserDao {
    //通过ID查询
    public User selectUserById(int userId) throws SQLException {
        User user = null;
        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 = new User();
                user.setUserId(resultSet.getInt("userId"));
                user.setUsername(resultSet.getString("username"));
                user.setPassword(resultSet.getString("password"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(connection, statement, resultSet);
        }
        return user;
    }

    //通过名字查询
    public User selectUserByName(String name) throws SQLException {
        User user = null;
        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, name);
            resultSet = statement.executeQuery();

            if(resultSet.next()) {
                user = new User();
                user.setUserId(resultSet.getInt("userId"));
                user.setUsername(resultSet.getString("username"));
                user.setPassword(resultSet.getString("password"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(connection, statement, resultSet);
        }
        return user;
    }
}

5.创建相应的API

5.1创建BlogServlet.java

这个主要用于查看博客列表,查看博客详情,以及提交博客使用

package api;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import model.Blog;
import model.BlogDao;
import model.User;

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.io.UnsupportedEncodingException;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.List;

/**
 * Describe:通过这个类实现一些后端接口,这个主要用于查看博客列表,查看博客详情,以及提交博客使用
 * User:lenovo
 * Date:2023-07-08
 * Time:10:58
 */
@WebServlet("/blog")
public class BlogServlet extends HttpServlet {
    private ObjectMapper objectMapper = new ObjectMapper();

     @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 从query string 中查询是否有 blogId,如果有就认为是查询指定的博客;如果没有就是查询所有博客
        BlogDao blogDao = new BlogDao();
        String blogId = req.getParameter("blogId");
        System.out.println("这里在查看参数");
        if(blogId == null) {
            System.out.println("URL后面没有参数,表示查找全部博客");
            List blogs = null;
            try {
                blogs = blogDao.selectAll();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            String respString = objectMapper.writeValueAsString(blogs);
                resp.setContentType("application/json;charset=utf8");
                resp.getWriter().write(respString);
        }else {
            Blog blog = blogDao.selectOne(Integer.parseInt(blogId));
            String respString = objectMapper.writeValueAsString(blog);
            resp.setContentType("application/json; charset=utf8");
            resp.getWriter().write(respString);
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        req.setCharacterEncoding("utf8");
        // 1.先从请求中拿到标题和正文
        String title = req.getParameter("title");
        String content = req.getParameter("content");
        if (title == null || title.equals("") || content == null || content.equals("")) {
            String html = "

title 或者 content 为空!新增博客失败!

"; resp.setContentType("text/html; charset=utf8"); resp.getWriter().write(html); return; } // 2.从会话中拿到作者的id HttpSession session = req.getSession(false); if(session == null) { String html = "

当前用户为登录!新增博客博客失败!

"; resp.setContentType("text/html; charset=utf8"); resp.getWriter().write(html); return; } User user = (User)session.getAttribute("user"); if(user == null) { String html = "

当前用户未登录!新增博客失败!

"; resp.setContentType("text/html; charset=utf8"); resp.getWriter().write(html); return; } // 3.构造blog对象 Blog blog = new Blog(); blog.setUserId(user.getUserId()); blog.setTitle(content); blog.setContent(content); blog.setPostTime(new Timestamp(System.currentTimeMillis())); // 4.插入blog对象到数据库中 BlogDao blogDao = new BlogDao(); try { blogDao.insert(blog); } catch (SQLException e) { e.printStackTrace(); } // 5.跳转到博客列表页 resp.sendRedirect("blog_list.html"); } }

5.2创建LoginServlet.java

这个类主要用于匹配登录,并验证是否登录的,如果没有登录却在访问其他选项,会跳转到登录页面。

package api;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import model.User;
import model.UserDao;

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.io.UnsupportedEncodingException;
import java.sql.SQLException;

/**
 * Describe:登录的一些接口
 * User:lenovo
 * Date:2023-07-09
 * Time:19:08
 */
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    private ObjectMapper objectMapper = new ObjectMapper();

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException{
        req.setCharacterEncoding("utf8");
        // 1.从请求中,获取到用户名和密码
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        if(username == null || username.equals("") || password == null || password.equals("")) {
            // 用户名或密码残缺
            String html = "

登录失败!缺少用户名或者密码!

"; resp.setContentType("text/html; charset=uft8"); resp.getWriter().write(html); return; } // 2.从数据库中读数据,看看用户名和密码是否匹配 UserDao userDao = new UserDao(); User user = null; try { user = userDao.selectUserByName(username); } catch (SQLException e) { e.printStackTrace(); } if(user == null) { // 用户不存在 String html = "

用户名或密码错误!

"; resp.setContentType("text/html; charset=utf8"); resp.getWriter().write(html); return; } if(!password.equals(user.getPassword())) { // 密码错误 String html = "

用户名或密码错误!

"; resp.setContentType("text/html; charset=utf8"); resp.getWriter().write(html); return; } // 3.用户名和密码都正确,登录成功,需要设置会话 HttpSession session = req.getSession(true); // 此处就把用户对象储存到session中了,下次用户访问其他页面,就可以直接拿到会话 session.setAttribute("user", user); // 4.返回一个重定向相应,能够跳转到博客列表页 resp.sendRedirect("blog_list.html"); } //通过这个方法,判断用户的登录状态,已登录,返回200,未登录返回403 @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { //查询会话是否存在 HttpSession session = req.getSession(false); if(session == null) { //会话不存在,未登录状态 resp.setStatus(403); return; } User user = (User)session.getAttribute("user"); if(user == null) { //会话虽然存在,但是用户对象没有,未登录状态 resp.setStatus(403); return; } //已经登录了 //200是默认的状态码,此处不写200也是可以的 resp.setStatus(200); resp.setContentType("application/json;charset=utf8"); user.setPassword("");//避免密码被返回,我们设置未空 String respJson = objectMapper.writeValueAsString(user); resp.getWriter().write(respJson); } }

5.3创建UserServlet.java

这个类主要用于博客详情页,用于查询指定的博客对应的作者

package api;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import model.Blog;
import model.BlogDao;
import model.User;
import model.UserDao;

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.sql.SQLException;

/**
 * Describe:
 * User:lenovo
 * Date:2023-07-10
 * Time:10:26
 */
@WebServlet("/user")
public class UserServlet extends HttpServlet {
    private ObjectMapper objectMapper = new ObjectMapper();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // 1.先读取出blogId
        String blogId = req.getParameter("blogId");
        if(blogId == null || blogId.equals("")) {
            // 直接返回一个 userId 为0的对象,因为最终返回的是一个 json 数据
            // 此处返回 json 格式的对象,如果返回一个html,前端处理会很麻烦
            String respJson = objectMapper.writer().writeValueAsString(new User());
            resp.setContentType("application/json; charset=utf8");
            System.out.println("参数给定的blogId为空");
            return;
        }
        // 2.查询数据库,查询对应的 Blog 对象
        BlogDao blogDao = new BlogDao();
        Blog blog = blogDao.selectOne(Integer.parseInt(blogId));
        if(blog == null) {
            String respJson = objectMapper.writeValueAsString(new User());
            resp.setContentType("application/json; charset=utf8");
            resp.getWriter().write(respJson);
            System.out.println("阐述给定的blogId不存在!");
            return;
        }
        // 3.根据 blog 中 userId,查询作者的信息
        UserDao userDao = new UserDao();
        User user = null;
        try {
            user = userDao.selectUserById(blog.getUserId());
            if(user == null) {
                String respJson = objectMapper.writeValueAsString(new User());
                resp.setContentType("application/json; charset=utf8");
                resp.getWriter().write(respJson);
                System.out.println("该博客对应的作者不存在!");
                return;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        // 4.把user对象返回给页面
        String respJson = objectMapper.writeValueAsString(user);
        resp.setContentType("application/json; charset=utf8");
        resp.getWriter().write(respJson);
    }
}

5.4创建LogoutServlet.java

用于注销账号

package api;

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;

/**
 * Describe:用于注销功能
 * User:lenovo
 * Date:2023-07-10
 * Time:10:56
 */
@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        HttpSession session = req.getSession(false);
        if(session == null) {
            //本身就没有登陆
            resp.sendRedirect("login.html");
            return;
        }
        //如果user存在
        session.removeAttribute("user");
        resp.sendRedirect("login.html");
    }
}

6.总结

这是一个简单的博客系统,我们完成了博客登录页,博客详情页,博客列表页,博客编辑页,注销功能。

这个对于初学者先对比较难,也会发生很多的问题。我们可以通过在控制台打印的方式来确定问题的位置,如

博客系统(Servlet)_第5张图片

 当然在我们上线服务器的时候,只要进行注释即可

你可能感兴趣的:(笔记,Tomcat,java-ee)