迷你论坛项目实现

博客简介

开发环境:idea 2019.03
数据库:MySQL

主要内容:实现一个迷你博客论坛项目
具体包括:项目背景、项目介绍、具体流程实现代码、结果分析

项目实现

一、立项

项目名称: 迷你论坛
项目背景: 为了验证学习成果、印证知识点的掌握程度,模仿 “CSDN” 实现一个迷你博客论坛,实现其部分功能。主要模仿用户对博客类论坛的基础功能需求,目的是实现用户的注册、登录、对文章的查看、点赞、评论等操作,基于Java语言的特性和组件开发的特点,预留了其他的功能实现接口留待日后补充。

二、需求分析

核心需求: 查看文章、发布文章、评论文章、点赞文章
核心功能: 文章的管理
必要辅助功能: 用户管理(注册、登录、注销等)

三、可行性评估

需要完成的主要功能有:
1、用户注册
2、用户登录
3、查看文章列表(只给出Id,按照发表时间倒序显示)
4、发表文章(要求用户必须登录)
5、查看指定文章内容
6、发表评论(要求用户必须登录)
7、对指定文章进行点赞(要求用户必须登录)

四、数据建模

需要的数据模型:用户users、文章articles、评论表comment、点赞关系表like_relations

各模型属性:
Users: id(用户id )、nickname(显示用户名称)、username(登录用户昵称)、password(用户密码)
articles: author_id(发表文章作者的id)、title (文章题目)、published_at(发表时间)、content(文章内容)
like_relations: user_id(点赞者id)、article_id(文章id)
comments: id(自增id)、user_id(评论者id)、article_id(文章id)、published_at(发表时间)、content(评论内容)

五、代码实现

1、建库建表

--建库
create database shuju_boke charset utf8mb4;
use shuju_boke;

--建表
--用户表
create table users (
  id int primary key auto_increment comment '自增id',
  username varchar(200) not null unique comment '唯一的用户名',
  nickname varchar(200) not null comment '显示名称',
  password varchar(200) not null comment '登录密码'
);

--文章表
create table articles (
  id int primary key auto_increment comment '自增id',
  author_id int not null comment '作者id',
  title varchar(200) not null comment '文章标题',
  published_at datetime not null comment '文章发表时间',
  content text  not null comment '文章正题'
);

--评论表
create table comments (
  id int primary key auto_increment comment '自增 id',
  user_id int not null comment '评论者id',
  article_id int not null comment '文章id',
  published_at datetime not null comment '评论时间',
  content varchar(200) not null comment '评论正文'
);

-- 点赞关系表
-- 使用成复合主键的形式
create table like_relations (
  user_id int not null comment '评论者id',
  article_id int not null comment '文章id',
  primary key (user_id, article_id)
);

2、UI设计——菜单->用户选择的循环
3、Action(interface)抽象一个功能void run();
4、Main类的职责:

  • 1.打印菜单
  • 2.打印提示
  • 3.获取用户输入
  • 4.根据用户不同的输入,分发给不同的Action对象去处理用户的请求
package blog;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Main {
    // 当前的登录用户信息
    // 没有登录 user == null
    // 否则,指向具体的用户对象
    //private static User user = null;

    private static List<String> featureList = new ArrayList<>();//featureList功能的名称
    private static List<Action> actionList = new ArrayList<>();//actionList功能对应的动作

    private static void initFeatureList() {//功能
        featureList.add("用户注册");
        featureList.add("用户登录");
        featureList.add("查看文章列表-按照发表时间倒序给出");
        featureList.add("发表文章-要求先登录");
        featureList.add("查看指定文章内容");
        featureList.add("评论指定文章-要求先登录");
        featureList.add("点赞指定文章-要求先登录");
    }


    private static void initActionList() {
        actionList.add(new UserRegisterAction());//用户注册
        actionList.add(new UserLoginAction());//用户登录
        actionList.add(new ArticlelishAction());//文章列表
        actionList.add(new ArticlePublishAction());//发表文章
        actionList.add(new ArticleDetailAction());//
    }

    public static void main(String[] args) {//先初始化
        initFeatureList();//功能名称
        initActionList();//功能背后对应的动作

        Scanner scanner = new Scanner(System.in);
        while (true) {
            showMenu();//打印菜单
            showPrompt();//打印提示符
            int select = scanner.nextInt();//获取用户输入
            doAction(select);//根据用户不同的输入,分发给不同的Action对象去处理用户的请求(Dispatch分发)
        }
    }

    private static void doAction(int select) {
        if (select == 0) {
            System.out.println("欢迎下次再来!");
            System.exit(0);
        }

        System.out.println("您的选择是: " + featureList.get(select - 1));
        if (select - 1 < actionList.size()) {
            Action action = actionList.get(select - 1);
            action.run();
        } else {
            System.out.println("该功能尚未支持,敬请期待...");
        }
    }

    private static void showPrompt() {//提示
        System.out.print("请输入功能的序号> ");
    }

    private static void showMenu() {//菜单
        System.out.println("欢迎使用《迷你论坛》,支持以下功能");
        for (int i = 0; i < featureList.size(); i++) {
            System.out.printf("  %d. %s%n", i + 1, featureList.get(i));
        }
        System.out.println("  0. 退出");
    }

    private static void userRegister() {//注册
        System.out.println("开始用户注册");
    }
}

菜单实现
在这里插入图片描述

功能1:用户注册

package blog;

import java.sql.*;
import java.util.Scanner;

//完整实现用户注册的功能
public class UserRegisterAction implements Action{
    @Override
    public void run() {
        //1.提示用户输入需要的信息,并使用jdbc执行sql;

        System.out.print("开始用户注册");
        System.out.println();

        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入用户名称");
        String username = scanner.nextLine();
        System.out.print("请输入用户昵称");
        String nickname = scanner.nextLine();
        System.out.print("请输入用户密码");
        String password = scanner.nextLine();

        try(Connection connection = DBUtil.getConnection()) {

            String sql = "insert into users(username,nickname,password) values(?,?,?)";
            try (PreparedStatement statement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
                statement.setString(1,username);
                statement.setString(2,nickname);
                statement.setString(3,password);

                statement.executeUpdate();

                int id;
                try(ResultSet r = statement.getGeneratedKeys()) {
                    r.next();
                    id = r.getInt(1);
                }
                System.out.println("注册成功,欢迎您的加入"+nickname);

                //是否应该让刚注册的这个用户自动登录成功呢?好说让该用户重新登陆?
                //两种方法都可以接受,我们选择自动登录成功
                User user = new User();
                user.id = id;//用户表中的id来自自增主键
                user.nickname = nickname;
                user.username = username;
                User.login(user);
            }
        }catch (SQLException e) {
            System.out.println("错误:" + e.getMessage());
        }
    }
}

运行代码,测试注册功能。经测试,注册功能成功实现
在这里插入图片描述

功能2:用户登录

package blog;

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

//负责用户登录
public class UserLoginAction implements Action{
    public void run() {
        System.out.println("开始用户登录...");
        System.out.println();

        //读取用户输入的信息
        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入用户名");
        String username = scanner.nextLine();
        System.out.print("请输入密码");
        String password = scanner.nextLine();

        try(Connection c = DBUtil.getConnection()) {
            //执行SQL,后面的??可以执行替换
            String sql = "select id,nickname from users where username =? and password = ?";
            try (PreparedStatement s = c.prepareStatement(sql)) {
                s.setString(1,username);
                s.setString(2,password);

                try(ResultSet rs = s.executeQuery()) {
                    //因为username是unique
                    //所以查找的过程,要不返回1行数据,要不返回0 行数据
                    //不可能多个
                    if(rs.next()) {
                        int id = rs.getInt(1);
                        String nickname = rs.getString(2);
                        User user = new User();
                        user.id = id;
                        user.nickname = nickname;
                        user.username = username;

                        //进行登录
                        User.login(user);
                    }else {
                        System.out.println("用户名或者密码错误,请重新输入!!");
                    }
                }
            }
        }catch (SQLException e) {
            System.out.println("错误:"+e.getMessage());
        }

        //搞定用户登录的过程
        //根据username+password判断用户是否登录成功
        //select id,username,nickname from users where username = ? and password = ?


    }
}

运行代码,测试登录功能。经测试,登录功能成功实现

在这里插入图片描述
功能3:发表文章

package blog;

import javax.naming.CompositeName;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;

public class ArticlePublishAction implements Action {
    //发表文章-要求先登录

    @Override
    public void run() {
        if (!User.isLogined()) {
            System.out.println("需要先登录,才能操作该功能!!");
            return;
        }
        //和注册用户基本一致
        //获取用户的输入(标题,正文)
        //根据当前登录用户,获取作者id
        //通过调用API,获取当前时间

        System.out.println("发表文章中...");
        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入文章标题");
        String title = scanner.nextLine();
        System.out.print("请输入文章正文");
        String content = scanner.nextLine();

        int authorId = User.getCurrentUser().id;
        Date publishedAt = new Date();//new完的对象,本来就是当前时间
        //published现在是Date对象,我们把Date对象format成String格式
        DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String publishedAtStr = format.format(publishedAt);

        //现在信息已经获取完全,通过JDBC执行insert操作
        try {
            Connection c = DBUtil.getConnection();
            Throwable var9 = null;

            try {
                String sql = "insert into articles (author_id, title, published_at, content) values (?, ?, ?, ?)";
                PreparedStatement s = c.prepareStatement(sql);
                Throwable var12 = null;

                try {
                    s.setInt(1, authorId);
                    s.setString(2, title);
                    s.setString(3, publishedAtStr);
                    s.setString(4, content);
                    s.executeUpdate();
                    System.out.println("《" + title + "》 文章发表成功!");
                } catch (Throwable var37) {
                    var12 = var37;
                    throw var37;
                } finally {
                    if (s != null) {
                        if (var12 != null) {
                            try {
                                s.close();
                            } catch (Throwable var36) {
                                var12.addSuppressed(var36);
                            }
                        } else {
                            s.close();
                        }
                    }

                }
            } catch (Throwable var39) {
                var9 = var39;
                throw var39;
            } finally {
                if (c != null) {
                    if (var9 != null) {
                        try {
                            c.close();
                        } catch (Throwable var35) {
                            var9.addSuppressed(var35);
                        }
                    } else {
                        c.close();
                    }
                }

            }
        } catch (SQLException var41) {
            System.out.println("错误:" + var41.getMessage());
        }

    }
}

运行代码,测试发表功能。经测试,发表文章功能成功实现
在这里插入图片描述
查看mysql中的文章表,是否有新文章《下雨了》
在这里插入图片描述

功能4:查看文章列表

package blog;

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

public class ArticlelishAction implements Action {
    //查看文章列表-按照发表时间倒序给出
    @Override
    public void run() {
        try(Connection c = DBUtil.getConnection()) {
            List<String[]> articleList = new ArrayList<>();
            List<String[]> authorIdList = new ArrayList<>();
            String sql = "select id,author_id,title,published_at from articles order by published_at desc";
            try(PreparedStatement s = c.prepareStatement(sql)) {
                try(ResultSet rs = s.executeQuery()) {
                    while(rs.next()) {
                        String[] article = new String[5];
                        String id = rs.getString("id");
                        String authorId = rs.getString("author_id");
                        String title = rs.getString("title");
                        String publishedAt = rs.getString("published_at");
                        article[0] = id;
                        article[1] = authorId;
                        article[2] = title;
                        article[3] = publishedAt;

                        articleList.add(article);
                    }
                }
            }

            //TODO打印作者的昵称而不是Id
            //需要根据作者id,再次去users表中查询出 用户的昵称信息
            Set<String> authorIdSet = new HashSet<>();
            for (String[] article : articleList) {
                String authorId = article[1];
                authorIdSet.add(authorId);
            }

            String querySql = "select id,nickname from users where id in (";;
            for(int i = 0; i < authorIdSet.size(); i++) {
                querySql +="?,";
            }
            querySql += "?)";
            System.out.println("DEBUG:"+ querySql.toString());


            Map<String,String> userIdToNicknameMap = new HashMap<>();
            try(PreparedStatement s = c.prepareStatement(querySql.toString())) {
                int i = 1;
                for(String id : authorIdSet) {
                    s.setString(i++,id);
                }

                try(ResultSet rs = s.executeQuery()) {
                    while(rs.next()) {
                    String id = rs.getString("id");
                    String nickname = rs.getString("nickname");
                    userIdToNicknameMap.put(id,nickname);
                    }
                }
            }



            System.out.printf("#ID | 标题 | 作者 | 发表时间%n");
            for(String[]article:articleList) {
                String id = article[0];
                String authorId = article[1];
                String authorNickname = userIdToNicknameMap.get(authorId);
                String title = article[2];
                String publishedAt = article[3];
                System.out.printf("%-4s | %-40s | %-10s | %s%n ",id,title,authorNickname,publishedAt);
            }

        } catch (SQLException e) {
            System.out.println("错误:"+ e.getMessage());
        }
    }
}

运行代码,测试查看功能。经测试,查看功能成功实现
在这里插入图片描述
功能5/6:点赞文章、评论文章

package blog;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;

public class ArticleDetailAction implements Action {
    public ArticleDetailAction() {
    }

    public void run() {
        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入要查看的文章的id :");
        String id = scanner.nextLine();

        String authorId = null;
        String title = null;
        String content = null;
        String publishedAt = null;
        int likeCount = 0;

        try (Connection c = DBUtil.getConnection()) {
            //1.查找文章信息
            String queryArticleSql = "select id,author_id,title,content,published_at from articles where id = ?";
            try(PreparedStatement s = c.prepareStatement(queryArticleSql)) {
                s.setString(1,id);
                try(ResultSet rs = s.executeQuery()) {
                    if(!rs.next()) {
                        System.out.println("没有这篇文章!!");
                        return;
                    }

                    authorId = rs.getString("author_id");
                    title = rs.getString("title");
                    content = rs.getString("content");
                    publishedAt = rs.getString("published_at");
                    }
                }

            //2.查询点赞的情况
            String likeCountSql = "select count(*) from like_relations where article_id = ?";
            try(PreparedStatement s = c.prepareStatement(likeCountSql)) {
                s.setString(1,id);
                try(ResultSet rs = s.executeQuery()) {
                    rs.next();
                    likeCount = rs.getInt(1);
                }
            }

            //3.查询评论信息
            List<String[]>commentList = new ArrayList<>();
            String queryCommentSql = "select user_id,content,published_at from comments where article_id = ?";
            try(PreparedStatement s = c.prepareStatement(queryCommentSql)) {
                s.setString(1,id);
                try(ResultSet rs = s.executeQuery()) {
                    while (rs.next()) {
                        String[] comment = new String[3];
                        comment[0] = rs.getString("user_id");
                        comment[1] = rs.getString("content");
                        comment[2] = rs.getString("published_at");

                        commentList.add(comment);
                    }
                }
            }

            //4.根据用户id,查询用户昵称
            //作者id和评论者id
            Set<String>userIdSet = new HashSet<>();
            userIdSet.add(authorId);
            for(String[] comment : commentList) {
                userIdSet.add(comment[0]);
            }

            StringBuilder queryNicknameSql = new StringBuilder("select id,nickname from users where id in (");
            for(int i = 1;i<userIdSet.size();i++) {
               queryNicknameSql.append("?, ");
            }
            queryNicknameSql.append("?)");

            Map<String,String> userIdNicknameMap = new HashMap<>();
            try(PreparedStatement s = c.prepareStatement(queryNicknameSql.toString())) {
                int i = 1;
                for(String userId : userIdSet) {
                    s.setString(i++,userId);
                }
                try(ResultSet rs = s.executeQuery()) {
                    while (rs.next()) {
                        userIdNicknameMap.put(rs.getString("id"),rs.getString("nickname"));
                    }
                }
            }

            //5.根据所有的信息,进行打印
            System.out.println(title);
            System.out.println(userIdNicknameMap.get(authorId));
            System.out.println(publishedAt);
            System.out.println("点赞人数:" + likeCount);
            System.out.println("=========================================");
            System.out.println(content);
            System.out.println("=========================================");
            for(String[] comment : commentList) {
                System.out.println(userIdNicknameMap.get(comment[0] + "|" + comment[1] + "|" + comment[2]));

            }

        } catch (SQLException e) {
            System.out.println("错误:"+ e.getMessage());
        }
    }
}


运行代码,测试点赞和评论功能。经测试,点赞和评论功能成功实现
在这里插入图片描述在这里插入图片描述

六概述

目前这个项目1.0已经完成实现,它还有许多可以进一步优化的地方,功能也可以再大幅增强,目前只实现基础功能,主要部分已经完成,基于语言的特性,以后可以进一步细化各种功能,尽可能打造一个完整的项目,作为自己学习的巩固和学习成果的检验。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值