4. 项目1 —— 实现一个简易博客系统

Java
238
0
0
2022-11-29

1. 需求分析

本项目需要实现一个简易的博客系统,其中功能包括: 1)注册新用户 2)登陆已有用户 3)显示博客列表,包括文章的作者和文章的内容 4)点击文章就会跳转到文章详情 5)发布新博客 6)删除自己的博客

2. 数据库设计

设计当前代码中需要用到数据库的几张表,每张表上都有哪些字段,每个表之间有什么关联关系

1)提取出需求中的“实体”有哪些 【用户】【文章】 确定了有两张表:User表 和 Article表

2)确定实体需要的属性 用户:【名字,密码】 文章:【标题,内容】

3)确定实体和实体之间的关系 用户和文章应该是【一对多】的关系,在“多”的表中加上外键 (需要在user表中加入userId字段,表示身份标识 在Article表中加入一个userId字段,表示该文章是由哪个用户发的)

drop database if exists blogdemo;
create database blogdemo;

use blogdemo;

drop table if exists article;
create table user(
 userId int primary key auto_increment,
    name varchar(50) unique,
    password varchar(50)
);

drop table if exists article;
create table article(
    articleId int primary key auto_increment,
    title varchar(255),
    content text,
    userId int ,
    foreign key(userId) references user(userId)
);

创建完成的数据库如下:

img

3. 开始写代码

a)创建一个类来管理数据库的连接(JDBC)

img

package model;

//管理数据库连接
//1.建立连接
//2.断开连接
//JDBC使用DataSourcr来管理连接
//DBUtil相当于是对DataSource再稍微包装一层
//因为 DataSource 应该是每个应用程序只应该有一个实例
//DBUtil本质上就是实现了一个单例模式,管理了一个唯一的DataSource实例

//单例模式的实现,有两种风格
//1.饿汉模式
//2.懒汉模式(在这里实现的)_______主要问题:线程不安全

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 volatile DataSource dataSource = null;
    private static final String URL = "jdbc:mysql://127.0.0.1:3306/blogdome?characterEncoding=utf-8&useSSL=true";
    private static final String USERNAME = "root";
    private static final String PASSWORD = "09050797";

    public static DataSource getDataSource(){
        if (dataSource == null) {
            synchronized (DBUtil.class) {
                if (dataSource == null){
                    dataSource = new MysqlDataSource();
                    //需要给DataSource设置一些属性
                    ((MysqlDataSource)dataSource).setURL(URL);
                    ((MysqlDataSource)dataSource).setUser(USERNAME);
                    ((MysqlDataSource)dataSource).setPassword(PASSWORD);
                }
            }
        }
        return dataSource;
    }

    //通过这个方法来获取连接 
    public static Connection getConnection(){
        try {
            return getDataSource().getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    //通过这个方法断开连接 
    public static void close(Connection connection, PreparedStatement statement,
                             ResultSet resultSet){
        try {
            if (resultSet != null){
                resultSet.close();
            }
            if (statement != null){
                statement.close();
            }
            if (connection != null){
                connection.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

b)创建实体类 创建一个user类和article类,这俩类的属性要和数据库结构是相关联的

img

package model;

public class User {
    private int userId;
    private String name;
    private String password;

    public int getUserId() {
        return userId;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

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

}
package model;

public class Article {
    private int articleId;
    private String title;
    private String content;
    private int userId;

    public int getArticleId() {
        return articleId;
    }

    public void setArticleId(int articleId) {
        this.articleId = articleId;
    }

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

c)实现数据库的增删改查

img

package model;

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

//Dao表示数据访问层
public class UserDao {
    //1.新增用户(注册) 
    //  把一个User对象插入到数据库中 
    void add(User user){
        //1.获取带数据库连接 
        Connection connection = DBUtil.getConnection();
        //2.拼装sql语句 
        String sql = "insert into user values (null,?,?)";
        PreparedStatement statement = null;
        try {
            statement = connection.prepareStatement(sql);
            statement.setString(1,user.getName());
            statement.setString(2,user.getPassword());
            //3.执行sql语句 
            int ret = statement.executeUpdate();
            if(ret != 1){
                //插入失败
                System.out.println("插入新用户失败!");
                return;
            }
            System.out.println("插入新用户成功!");
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //4.释放数据库连接
            DBUtil.close(connection,statement,null);
        }
    }

    //2.按照名字查找(登录) 
    public User selectByName(String name){
        //1.和数据库建立连接 
        Connection connection = DBUtil.getConnection();
        //2.拼装SQL 
        String sql = "select * from user where name = ?";
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            statement = connection.prepareStatement(sql);
            statement.setString(1,name);
            //3.执行SQL
            resultSet = statement.executeQuery();
            //4.遍历结果集合 
            if (resultSet.next()){
                User user = new User();
                user.setUserId(resultSet.getInt("userId"));
                user.setName(resultSet.getString("name"));
                user.setPassword(resultSet.getString("password"));
                return user;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //5.释放数据库连接
            DBUtil.close(connection,statement,resultSet);
        }
        return null;
    }
}
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 ArticleDao {
    //1.新增文章(发布博客) 
    public void add(Article article){
        //1.获取数据库连接 
        Connection connection = DBUtil.getConnection();
        //2.构造sql 
        String sql = "insert into article value (null,?,?,?)";
        PreparedStatement statement = null;
        try {
            statement = connection.prepareStatement(sql);
            statement.setString(1,article.getTitle());
            statement.setString(2,article.getContent());
            statement.setInt(3,article.getUserId());
            //3.执行sql 
            int ret = statement.executeUpdate();
            if (ret != 1){
                System.out.println("插入文章操作失败!");
                return;
            }
            System.out.println("插入文章操作成功!");
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //4.释放连接
            DBUtil.close(connection,statement,null);
        }
    }


    //2.查看文章(把所有的文章信息都查出来) 
    public List<Article> selectAll(){
        List<Article> articles = new ArrayList<>();
        Connection connection = DBUtil.getConnection();
        String sql = "select article,title,userId from article";
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            statement = connection.prepareStatement(sql);
            resultSet = statement.executeQuery();
            while (resultSet.next()){
                Article article = new Article();
                article.setArticleId(resultSet.getInt("articleId"));
                article.setTitle(resultSet.getString("title"));
                article.setUserId(resultSet.getInt("userId"));
                articles.add(article);
            }
            return articles;
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DBUtil.close(connection,statement,resultSet);
        }
        return null;
    }

    //3.查看指定的文章详情 
    public Article selectById(int articleId){
        Connection connection = DBUtil.getConnection();
        String sql = "select * from where articleId = ?";
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            statement = connection.prepareStatement(sql);
            statement.setInt(1,articleId);
            resultSet = statement.executeQuery();
            if (resultSet.next()){
                Article article = new Article();
                article.setArticleId(resultSet.getInt("articleId"));
                article.setTitle(resultSet.getString("title"));
                article.setContent(resultSet.getString("content"));
                article.setUserId(resultSet.getInt("userId"));
                return article;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DBUtil.close(connection,statement,resultSet);
        }
        return null;
    }

    //4.删除指定文章 
    public void delete(int articleId){
        Connection connection = DBUtil.getConnection();
        String sql = "delete from article where articleId = ?";
        PreparedStatement statement = null;
        try {
            statement = connection.prepareStatement(sql);
            statement.setInt(1,articleId);
            int ret = statement.executeUpdate();
            if (ret != 1){
                System.out.println("删除文章失败!");
                return;
            }
            System.out.println("删除文章成功!");
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DBUtil.close(connection,statement,null);
        }
    }
}

4. 前后端接口设计

img

5. 开始实现接口

1) 实现注册页面

img

register.html

<!doctype html>
<html lang="en">
<head> 
    <meta charset="UTF-8"> 
    <meta name="viewport" 
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> 
    <meta http-equiv="X-UA-Compatible" content="ie=edge"> 
    <title>注册</title>
</head>
<body>
<form action="register" method="post"> 
    <input type="text" name="name" placeholder="请输入密码"> 
    <br/> 
    <input type="text" name="password" placeholder="请输入密码"> 
    <br/> 
    <input type="submit" value="注册">

</form>

</body>
</html>

RegisterServlet

package api;

import model.User;
import model.UserDao;
import view.HtmlGenerator;

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

public class RegisterServlet extends HttpServlet {
    //浏览器是通过POST方法来提交数据的 
    @Override 
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html; charset=utf-8");
        //1.获取到前端提交的数据(用户名,密码)校验是否合法 
        String name = req.getParameter("name");
        String password = req.getParameter("password");
        if(name == null || "".equals(name)||password==null||"".equals(password)){
            String html = HtmlGenerator.getMessagePage("用户名或者密码为空","register.html");
            resp.getWriter().write(html);
            return;
        }
        //2.拿着用户名在数据库中查一下,看看当前用户是否已经存在,如果存在,认为注册失败 
        UserDao userDao = new UserDao();
        User existUser = userDao.selectByName(name);
        if (existUser != null){
            //说明已经存在,提示用户注册失败,用户名重复 
            String html = HtmlGenerator.getMessagePage("用户名重复!请换个名字!","register.html");
            resp.getWriter().write(html);
            return;
        }
        //3.根据前端提交的数据构造user对象,并插入到数据库中 
        User user = new User();
        user.setName(name);
        user.setPassword(password);
        userDao.add(user);
        //4.返回一个结果页面,提示当前注册成功 
        String html = HtmlGenerator.getMessagePage("注册成功!点击这里跳转到登陆页面!","login.html");
        resp.getWriter().write(html);
        
    }
}

HtmlGenerator

package view;

public class HtmlGenerator {
    //通过字符串拼接的形式,构造出来HTML格式出来 
    public static String getMessagePage(String message, String nextUrl) {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("<html>");
        stringBuilder.append("<head>");
        stringBuilder.append("<meta charset=\"utf-8\">");
        stringBuilder.append("<title>提示页面</title>");
        stringBuilder.append("</head>");
        stringBuilder.append("<body>");

        stringBuilder.append("<h3>");
        stringBuilder.append(message);
        stringBuilder.append("</h3>");

        stringBuilder.append(String.format("<a href=\"%s\"> 点击这里跳转 </a>",nextUrl));

        stringBuilder.append("</body>");
        stringBuilder.append("</html>");

        return stringBuilder.toString();

    }
}

配置web.xml文件

img

2) 实现登录功能

img

login.html

<!doctype html>
<html lang="en">
<head> 
    <meta charset="UTF-8"> 
    <meta name="viewport" 
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> 
    <meta http-equiv="X-UA-Compatible" content="ie=edge"> 
    <title>登录</title>
</head>
<body>
<form action="login" method="post"> 
    <input type="text" name="name" placeholder="请输入用户名"> 
    <br/> 
    <input type="password" name="password" placeholder="请输入密码"> 
    <br/> 
    <input type="submit" value="登录">

</form>

</body>
</html>

loginServlet

package api;

import model.User;
import model.UserDao;
import view.HtmlGenerator;

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

public class loginServlet extends HttpServlet {
    @Override 
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html; charset=utf-8");
        //1.获取到用户名和密码,并进行简单的校验 
        String name = req.getParameter("name");
        String password = req.getParameter("password");
        if (name == null || "".equals(name) || password==null || "".equals(password)){
            String html = HtmlGenerator.getMessagePage("用户名或密码为空","login.html");
            resp.getWriter().write(html);
            return;
        }
        //2.数据库中查找,看看用户是否存在 
        //3.对比密码是否匹配 
        UserDao userDao = new UserDao();
        User user = userDao.selectByName(name);
        if (user==null || !password.equals(user.getPassword())){
            //用户名不存在 
            String html = HtmlGenerator.getMessagePage("用户名或密码错误","login.html");
            resp.getWriter().write(html);
            return;
        }

        //4.匹配成功则认为登陆成功,创建一个session 
        HttpSession httpSession = req.getSession(true);
        httpSession.setAttribute("user",user);

        //5.返回一个登陆成功的页面 
        String html = HtmlGenerator.getMessagePage("登陆成功","article");
        resp.getWriter().write(html);
    }
}

3) 实现文章功能

img

ArticleServlet

package api;

import model.Article;
import model.ArticleDao;
import model.User;
import model.UserDao;
import view.HtmlGenerator;

import javax.servlet.ServletException;
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;

public class ArticleServlet extends HttpServlet {
    @Override 
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html; charset=utf-8");
        //1.验证用户是否已经登陆了,如果尚未登陆提示用户登录 
        HttpSession httpSession = req.getSession(false);
        if (httpSession == null){
            //当前是未登录状态 
            String html = HtmlGenerator.getMessagePage("请先登录","login.html");
            resp.getWriter().write(html);
            return;
        }
        User user = (User)httpSession.getAttribute("user");
        //2.判断请求中是否存在articleId参数 
        String articleIdStr = req.getParameter("articleId");
        if (articleIdStr == null){
            //a)没有这个参数就去执行获取文章列表的操作
            getAllArticle(user, resp);
        }else {
            //b)有这个参数就去执行获取文章详情的操作
            getOneArticle(Integer.parseInt(articleIdStr),user,resp);
        }

    }

    private void getOneArticle(int articleId, User user, HttpServletResponse resp) throws IOException {
        //1.查找数据库 
        ArticleDao articleDao = new ArticleDao();
        Article article = articleDao.selectById(articleId);
        if (article == null){
            //文章未找到 
            String html = HtmlGenerator.getMessagePage("文章不存在","article");
            resp.getWriter().write(html);
            return;
        }
        //根据作者ID。找到作者信息,进一步得到作者姓名 
        UserDao userDao = new UserDao();
        User author = userDao.selectById(article.getUserId());
        //2.构造页面 
        String html = HtmlGenerator.getArticleDetailPage(article,user,author);
        resp.getWriter().write(html);
    }


    private void getAllArticle(User user, HttpServletResponse resp) throws IOException {
        //1.查找数据库 
        ArticleDao articleDao = new ArticleDao();
        List<Article> articles = articleDao.selectAll();
        //2.构造页面 
        String html = HtmlGenerator.getArticleListPage(articles, user);
        resp.getWriter().write(html);
    }
}

HtmlGenerator

package view;

import model.Article;
import model.User;

import java.util.List;

public class HtmlGenerator {
    //通过字符串拼接的形式,构造出来HTML格式出来 
    public static String getMessagePage(String message, String nextUrl) {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("<html>");
        stringBuilder.append("<head>");
        stringBuilder.append("<meta charset=\"utf-8\">");
        stringBuilder.append("<title>提示页面</title>");
        stringBuilder.append("</head>");
        stringBuilder.append("<body>");

        stringBuilder.append("<h3>");
        stringBuilder.append(message);
        stringBuilder.append("</h3>");

        stringBuilder.append(String.format("<a href=\"%s\"> 点击这里跳转 </a>",nextUrl));

        stringBuilder.append("</body>");
        stringBuilder.append("</html>");

        return stringBuilder.toString();

    }

    public static String getArticleListPage(List<Article> articles, User user) {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("<html>");
        stringBuilder.append("<head>");
        stringBuilder.append("<meta charset=\"utf-8\">");
        stringBuilder.append("<title>提示页面</title>");
        stringBuilder.append("<style>");
        stringBuilder.append("a{"+
                "color: #333;"+
                "text-decoration: none;"+
                "}");
        stringBuilder.append("a{"+
                "color: white"+
                "background-color: orange;"+
                "}");
        stringBuilder.append("</style>");
        stringBuilder.append("</head>");
        stringBuilder.append("<body>");

        stringBuilder.append("<h3> 欢迎您!"+ user.getName()+"</h3>");
        stringBuilder.append("<hr>");
        //要有一个文章列表,显示每个文章的标题 
        for (Article article : articles){
           stringBuilder.append(String.format("<div style=\"width: 200px;height: 50px\"><a href=\"article?articleId=%d\"> %s </div>",
           article.getArticleId(),article.getTitle()));
        }
        stringBuilder.append("<hr>");
        stringBuilder.append(String.format("<div>当前共有博客 %d 篇 </div>",articles.size()));

        stringBuilder.append("</body>");
        stringBuilder.append("</html>");

        return stringBuilder.toString();
    }


    public static String getArticleDetailPage(Article article, User user, User author) {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("<html>");
        stringBuilder.append("<head>");
        stringBuilder.append("<meta charset=\"utf-8\">");
        stringBuilder.append("<title>提示页面</title>");
        stringBuilder.append("<style>");
        stringBuilder.append("a{"+
                "color: #333;"+
                "text-decoration: none;"+
                "}");
        stringBuilder.append("a{"+
                "color: white"+
                "background-color: orange;"+
                "}");
        stringBuilder.append("</style>");
        stringBuilder.append("</head>");
        stringBuilder.append("<body>");

        stringBuilder.append("<h3> 欢迎您!"+ user.getName()+"</h3>");
        stringBuilder.append("<hr>");

        stringBuilder.append(String.format("<h1>%s</h1>",article.getTitle()));
        stringBuilder.append(String.format("<h4>作者:%s</h4>",author.getName()));
        stringBuilder.append(String.format("<div>%s</div>",article.getContent()));

        stringBuilder.append("</body>");
        stringBuilder.append("</html>");
        return stringBuilder.toString();

    }
}

3) 实现删除文章

package api;


import model.Article;
import model.ArticleDao;
import model.User;
import view.HtmlGenerator;

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

public class DeleteArticleServlet extends HttpServlet {
    @Override 
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html; charset=utf-8");
        // 1. 验证用户的登陆状态, 如果未登陆, 肯定不能删除. 
        HttpSession httpSession = req.getSession(false);
        if (httpSession == null) {
            String html = HtmlGenerator.getMessagePage("您尚未登陆!",
                    "login.html");
            resp.getWriter().write(html);
            return;
        }
        User user = (User) httpSession.getAttribute("user");
        // 2. 读取请求内容, 获取到要删除的文章 id 
        String articleIdStr = req.getParameter("articleId");
        if (articleIdStr == null || "".equals(articleIdStr)) {
            String html = HtmlGenerator.getMessagePage("要删除的文章 id 有误",
                    "article");
            resp.getWriter().write(html);
            return;
        }
        // 3. 根据文章 id 查找到该文章的作者. 当前用户如果就是作者, 才能删除, 否则删除失败. 
        ArticleDao articleDao = new ArticleDao();
        Article article = articleDao.selectById(Integer.parseInt(articleIdStr));
        if (article.getUserId() != user.getUserId()) {
            String html = HtmlGenerator.getMessagePage("您只能删除自己的文章!",
                    "article");
            resp.getWriter().write(html);
            return;
        }
        // 4. 真正执行数据库删除操作
        articleDao.delete(Integer.parseInt(articleIdStr));
        // 5. 返回一个 "删除成功" 的页面. 
        String html = HtmlGenerator.getMessagePage("删除成功!",
                "article");
        resp.getWriter().write(html);
    }
}