手把手教你实现一个JavaWeb项目:创建一个自己的网页博客系统(前端+后端)(二)

        话接上文,我们讲述了实现一个项目的大体步骤和实现了项目的 view 层,也就是前端部分,从这一篇开始,我们来肝后端部分。

上篇博客地址:手把手教你实现一个JavaWeb项目:创建一个自己的网页博客系统(前端+后端)(一)_小型骷髅的博客-CSDN博客

目录:

1、具体代码实现:

        2、M——数据库部分:

        3、C——控制器,后端部分:

结语:


1、具体代码实现:

        2、M——数据库部分:

        model 层分为 sql 和jdbc ,先来创建数据库和数据表,打开mysql,输入下列 sql 语句:

-- 通过这个文件来编写建库建表的sql

-- 先建立数据库:
create database if not exists blogSystem;

-- 选中数据库:
use java102_blog;

-- 创建一个博客表:
drop table if exists blog;
create table blog(
    blogId int primary key auto_increment, -- 创建博客ID列,并作为主键约束,设置自增主键
    title varchar(1024), -- 创建标题列
    content mediumtext, -- 创建正文列,类型设为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,'我的第三篇博客','一二三四五,六六六六六',1,now());
insert into blog values(null,'我的第一篇博客','一二三四五,上山打老虎',2,now());

-- 创建一个用户表:
drop table if exists user;
create table user(
    userId int primary key auto_increment, -- 创建用户ID列,并作为自增主键
    username varchar(128) unique, -- 创建用户名列,因为后续会使用用户名登录,所以要求不能重复
    password varchar(128)
);

-- 在用户表插入两条数据:
insert into user values(null,"zhangsan","123");
insert into user values(null,"lisi","123");

        建立好数据后,在main目录下的java目录里创建一个文件夹,命名为 model :

        1)创建一个文件,命名为 Blog :

package model;

import java.sql.Timestamp;
import java.text.SimpleDateFormat;

/**
 * 描述:每个Blog对象都对应blog表中的一条记录
 * 创建类之后再根据表结构(字段)来创建类里的属性
 */
public class Blog {
    private int blogId;
    private String title;
    private String content;
    private int userId;
    private Timestamp postTime;

    public int getBlogId() {
        return blogId;
    }

    public void setBlogId(int blogId) {
        this.blogId = blogId;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public int getUserId() {
        return userId;
    }

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

//    public Timestamp getPostTime() {
//        return postTime;
//    }

    //把这里的getter方法改了,不是返回一个时间戳对象,而是一个String(已经格式好的日期)
    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;
    }
}

        2)创建一个文件,命名为 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;

/**
 * 描述:这个类用于封装 博客表 的基本操作(增删改查)
 * 这些操作中是增删查,还没有改的操作
 * JDBC 基本代码
 */
public class BlogDao {
    //1、往博客表里插入一篇博客:
    public void insert(Blog blog){
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            //1)和数据库建立连接:
            connection = DBUtil.getConnection();
            //2)构造SQl语句:
            String sql = "insert into blog values(null,?,?,?,now())";
            statement = connection.prepareStatement(sql);
            statement.setString(1,blog.getTitle());
            statement.setString(2, blog.getContent());
            statement.setInt(3,blog.getUserId());
            //3)执行SQL:
            statement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //4)释放资源,关闭连接:
            DBUtil.close(connection,statement,null);
        }
    }

    //2、能够获取到博客表里所有的博客信息(用于博客列表页,每篇博客不一定是显示全部信息)
    public List<Blog> selectAll(){
        List<Blog> blogs = new ArrayList<>();
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            //1)和数据库建立连接:
            connection = DBUtil.getConnection();
            //2)构造SQl语句:
            String sql = "select * from blog order by postTime desc";
            statement = connection.prepareStatement(sql);
            //3)执行SQL:
            resultSet = statement.executeQuery();
            //4)遍历结果集(将查询到的结果resultSet变为blog对象放到blogs数组里)
            while (resultSet.next()){
                Blog blog = new Blog();
                blog.setBlogId(resultSet.getInt("blogId"));
                blog.setTitle(resultSet.getString("title"));
                //这里针对博客列表页的“正文”content进行截取,如果其长度大于50,那么只取前50:
                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 e) {
            e.printStackTrace();
        }finally {
            //5)释放资源,关闭连接:
            DBUtil.close(connection,statement,resultSet);
        }
        return blogs;
    }

    //3、能够根据博客id获取到指定的博客内容(用于博客详情页)
    public Blog selectOne(int blogId){
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            //1)和数据库建立连接:
            connection = DBUtil.getConnection();
            //2)构造SQl语句:
            String sql = "select * from blog where blogId = ?";
            statement = connection.prepareStatement(sql);
            statement.setInt(1,blogId);
            //3)执行SQL:
            resultSet = statement.executeQuery();
            //4)遍历结果集:
            //因为此处是blogId(使用了主键约束)作为查询依据的,结果要么为1,要么为0,所以不用where,而用if
            //如果resultSet里没有数据,就不会执行if,直接返回null
            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 e) {
            e.printStackTrace();
        }finally {
            //5)释放资源,关闭连接:
            DBUtil.close(connection,statement,resultSet);
        }
        return null;
    }

    //4、从博客表中,根据博客id,删除某篇博客
    public void delete(int blogId){
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            //1)和数据库建立连接:
            connection = DBUtil.getConnection();
            //2)构造SQl语句:
            String sql = "delete from blog where blogId = ?";
            statement = connection.prepareStatement(sql);
            statement.setInt(1,blogId);
            //3)执行SQL:
            statement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //4)释放资源,关闭连接:
            DBUtil.close(connection,statement,null);
        }
    }

}

        3)创建一个文件,命名为 User :

package model;

/**
 * 描述:每个User对象都对应User表中的一条记录
* 创建类之后再根据表结构(字段)来创建类里的属性
 */
public class User {
    private int userId = 0;
    private String username = "";
    private String password = "";

    public int getUserId() {
        return userId;
    }

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

    public String getUsername() {
        return username;
    }

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

    public String getPassword() {
        return password;
    }

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

        4)创建一个文件,命名为 UserDao :

package model;

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

/**
 * 描述:这个类用于封装 用户表 的基本操作(增删改查)
 */
public class UserDao {
    //需要实现的操作:
    //针对这个类来说,简化写就行了,不考虑注册/注销 这样的功能。

    //1、根据用户名来查找用户信息(在登录逻辑中出现):
    public User selectByName(String username){
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            //1)和数据库建立连接:
            connection = DBUtil.getConnection();
            //2)构造SQl语句:
            String sql = "select * from user where username = ?";
            statement = connection.prepareStatement(sql);
            statement.setString(1,username);
            //3)执行SQL:
            resultSet = statement.executeQuery();
            //4)遍历结果集:
            //因为此处username使用的是unique约束,所以要么查到的结果为1要么为0,所以用if
            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 {
            //5)释放资源,关闭连接:
            DBUtil.close(connection,statement,resultSet);
        }
        return null;
    }

    //2、根据用户ID来查找用户信息(在博客详情页,根据用户ID查找作者名字,并显示作者名字):
    public User selectById(int userId){
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            //1)和数据库建立连接:
            connection = DBUtil.getConnection();
            //2)构造SQl语句:
            String sql = "select * from user where userId = ?";
            statement = connection.prepareStatement(sql);
            statement.setInt(1,userId);
            //3)执行SQL:
            resultSet = statement.executeQuery();
            //4)遍历结果集:
            //因为此处username使用的是unique约束,所以要么查到的结果为1要么为0,所以用if
            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 {
            //5)释放资源,关闭连接:
            DBUtil.close(connection,statement,resultSet);
        }
        return null;
    }
}

        5)创建一个文件,命名为 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;

/**
 * 描述:使用这个类,来和数据库建立连接。封装数据库
 */
public class DBUtil {
    //这是连接数据库的地址
    private static final String URL = "jdbc:mysql://127.0.0.1:3306/java102_blog?characterEncoding=utf8&useSSL=false";
    //用户名
    private static final String USERNAME = "root";
    //密码
    private static final String PASSWORD = "1234";

    //创建一个数据源对象:
    private volatile static DataSource dataSource = null;
    private static DataSource getDataSource(){
        if (dataSource == null) {
            synchronized (DBUtil.class) {
                if (dataSource == null) {
                    dataSource = new MysqlDataSource();
                    ((MysqlDataSource) dataSource).setURL(URL);
                    ((MysqlDataSource) dataSource).setUser(USERNAME);
                    ((MysqlDataSource) dataSource).setPassword(PASSWORD);
                }
            }
        }
        return dataSource;
    }

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

    //关闭资源:
    public static void close(Connection connection, PreparedStatement preparedStatement, ResultSet resultSet){
        if (resultSet != null){
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if (connection != null){
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if (preparedStatement != null){
            try {
                preparedStatement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

        3、C——控制器,后端部分:

        这一层主要包含后端服务器代码,咱们现在java目录里创建一个文件夹,命名为 controller 。

        1)创建一个文件,命名为 BlogServlet :

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;

/**
 * 描述:通过这个类,来处理 /blog 这个路径的请求
 */

@WebServlet("/blog")
public class BlogServlet extends HttpServlet {
    private ObjectMapper objectMapper = new ObjectMapper();

    //这个方法来获取数据库中的博客列表:
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("application/json; charset=utf8");
        BlogDao blogDao = new BlogDao();
        // 先尝试获取到 req 中的 blogId 参数. 如果该参数存在, 说明是要请求博客详情
        // 如果该参数不存在, 说明是要请求博客的列表.
        String param = req.getParameter("blogId");
        if (param == null) {
            // 不存在参数, 获取博客列表
            List<Blog> blogs = blogDao.selectAll();
            // 把 blogs 对象转成 JSON 格式.
            String respJson = objectMapper.writeValueAsString(blogs);
            resp.getWriter().write(respJson);
        } else {
            // 存在参数, 获取博客详情
            int blogId = Integer.parseInt(param);
            Blog blog = blogDao.selectOne(blogId);
            String respJson = objectMapper.writeValueAsString(blog);
            resp.getWriter().write(respJson);
        }
    }

    @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(作者信息)
        Blog blog = new Blog();
        blog.setTitle(title);
        blog.setContent(content);
        // 作者Id就是当前提交这个博客的用户的id
        blog.setUserId(user.getUserId());
        BlogDao blogDao = new BlogDao();
        blogDao.insert(blog);
        // 博客提交成功后,跳转(重定向)到博客列表页
        resp.sendRedirect("blog_list.html");
    }
}

        2)创建一个文件,命名为 LoginServlet :

package controller;

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

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;


@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    private ObjectMapper objectMapper = new ObjectMapper();

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf8"); //针对请求进行设置,使用utf8格式来解析请求;
        resp.setCharacterEncoding("utf8"); //针对响应进行设置,构造数据时,按照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);

        //4、返回一个重定向报文,跳转到博客列表页:
        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对象,也视为未登录
            user = new User();
            resp.getWriter().write(objectMapper.writeValueAsString(user));
            return;
        }
        //若代码运行到这,说明已经是登陆状态:
        //注意:此处不应该把密码返回到前端,不然会泄露。
        user.setPassword("");
        resp.getWriter().write(objectMapper.writeValueAsString(user));
    }
}

        3)创建一个文件,命名为 LogoutServlet :

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");
    }
}

        4)创建一个文件,命名为 BlogDeleteServlet :

package controller;

import model.Blog;
import model.BlogDao;
import model.User;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;


@WebServlet("/blogDelete")
public class BlogDeleteServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1、先检测当前用户是否登录
        HttpSession session = req.getSession(false);
        if (session == null){
            resp.setContentType("text/html;charset=utf8");
            resp.getWriter().write("当前用户未登录!不能删除!");
            return;
        }
        User user = (User) session.getAttribute("user");
        if (user == null){
            resp.setContentType("text/html;charset=utf8");
            resp.getWriter().write("当前用户未登录!不能删除!");
            return;
        }

        // 2、获取到当前参数的blogId
        String blogId = req.getParameter("blogId");
        if (blogId == null || "".equals(blogId)){
            resp.setContentType("text/html;charset=utf8");
            resp.getWriter().write("当前 blogId参数 不正确!");
            return;
        }

        // 3、获取到要删除的博客信息
        BlogDao blogDao = new BlogDao();
        Blog blog = blogDao.selectOne(Integer.parseInt(blogId));
        if (blog == null){
            resp.setContentType("text/html;charset=utf8");
            resp.getWriter().write("当前要删除的博客不存在!");
            return;
        }

        // 4、再次校验,当前用户是否为博客的作者
        if (user.getUserId() != blog.getUserId()){
            // 这一点在前端也处理过,但是再校验一次也不是坏事。
            resp.setContentType("text/html;charset=utf8");
            resp.getWriter().write("当前登录的用户不是作者,没有权限删除!");
            return;
        }

        // 5、开始删除
        blogDao.delete(Integer.parseInt(blogId));

        // 6、跳转(重定向)到博客列表页
        resp.sendRedirect("blog_list.html");
    }
}

        5)创建一个文件,命名为 AuthorServlet :

package controller;

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

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


@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));
    }
}

结语:

        项目到这呢,已经全部结束了,你可以先运行服务器,然后在浏览器输入:127.0.0.1:8080/blog_system/blog_login.html 验证一下你自己的JavaWeb项目。最后如果你觉得对自己有帮助的话不妨点个赞,谢谢!

        码云:博客系统地址​​​​​​​

猜你喜欢

转载自blog.csdn.net/weixin_56960711/article/details/125361304