0


前端+后端项目 - 论坛信息管理系统(Web+servlet+MySQL+JDBC)

【大家好,我是爱干饭的猿,如果喜欢这篇文章,点个赞👍,关注一下吧,后续会持续分享其他项目的相关操作和Linux相关知识

上一篇文章:《前端项目 - 论坛信息管理系统(纯页面)》

本篇文章介绍的《论坛信息管理系统》源码链接放在文章末尾了,感兴趣的朋友可以看看。


上一篇文章中我们完成了论坛信息管理系统的前端页面,现在我们可以基于模板的方式,通过服务器把数据渲染到页面中,然后直接返回完整的页面给浏览器。

目前比较主流的开发方式是“前后端分离”的方式,在这种方式下服务端不关注页面的内容,而是网页提供的数据。

网页可以通过ajax的方式和服务器之间交互数据,网页拿到数据之后再根据数据的内容渲染到页面上。

此篇文章仅展示重要代码思路过程,项目源码在 gitee 中

链接:
《论坛信息管理系统》

效果展示

论坛列表页:

论坛主贴页:

论坛回帖页:

用户写帖子页:

用户个人信息页:

论坛登录页:

论坛注册页:


一. 准备工作

1) 创建 web 项目

2) 创建目录结构

3) 配置 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>forum-inforation-management-system</artifactId>
    <version>1.0-SNAPSHOT</version>
    
    <!-- 指定最终 war 包的名称 -->
    <packaging>war</packaging>

    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <!-- 加入 servlet 依赖 -->
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.12.4</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
            <scope>compile</scope>
        </dependency>

    </dependencies>

</project>

二. 数据库操作代码

1. 数据库设计

1.1 ER图

1.2 ER图转化为关系****模型并优化

  1. 管理员信息表(管理员编号,管理员名称,管理员密码)
  2. 用户信息表(用户编号,用户名称,用户密码,用户生日,用户性别,用户性别,用户生日,用户职业,用户爱好,用户帖子数,用户等级,用户注册日期)
  3. 版块信息表(版块编号,版主编号,版块名称,版块说明,版块点击次数,版块主题数)
  4. 主贴信息表(主贴编号,主贴板块编号,主贴用户编号,主贴回复次数,主贴标题,主贴内容,主贴时间,主贴回复次数,主贴点击次数)
  5. 回复贴信息表(回帖编号,回帖主题帖子编号,回帖的用户编号,回帖标题,回帖内容,回帖时间,回帖点击次数)

1.3 创建数据库/表结构

根据在ER图中的实体,创建库表结构

db.sql

-- 创建数据库
if exit forum_management_information_system1 drop database `forum_management_information_system1`;
CREATE SCHEMA `forum_management_information_system1` DEFAULT CHARACTER SET utf8 ;

-- 创建管理员信息表
CREATE TABLE `admin` (
  `adminID` int NOT NULL AUTO_INCREMENT COMMENT '管理员编号',
  `adminName` varchar(20) NOT NULL COMMENT '管理员名称',
  `adminPassword` varchar(20) NOT NULL COMMENT '管理员密码',
  PRIMARY KEY (`adminID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COMMENT='管理员信息表';

-- 创建用户信息表
CREATE TABLE `user` (
  `uID` int NOT NULL AUTO_INCREMENT COMMENT '用户编号',
  `userName` varchar(20) NOT NULL COMMENT '用户昵称',
  `userPassword` varchar(20) NOT NULL COMMENT '用户密码',
  `userSex` varchar(20) NOT NULL COMMENT '用户性别',
  `userAge` int NOT NULL COMMENT '用户生日',
  `userOccupation` varchar(20) NOT NULL COMMENT '用户职业',
  `userHobby` varchar(20) NOT NULL COMMENT '用户爱好',
  `userPoint` int NOT NULL DEFAULT '0' COMMENT '用户积分',
  `userClass` int NOT NULL DEFAULT '0' COMMENT '用户等级',
  `userRegister` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '用户注册时间',
  PRIMARY KEY (`uID`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb3 COMMENT='用户信息表';

-- 板块信息表
CREATE TABLE `section` (
  `sID` int NOT NULL AUTO_INCREMENT COMMENT '板块编号',
  `uID` int NOT NULL COMMENT '版主编号(用户编号)',
  `sName` varchar(50) NOT NULL COMMENT '板块名称',
  `sStatement` text NOT NULL COMMENT '板块说明',
  `sClickCount` int NOT NULL DEFAULT '0' COMMENT '板块点击次数',
  `sTopicCount` int NOT NULL DEFAULT '0' COMMENT '板块主题数',
  PRIMARY KEY (`sID`),
  KEY `s_uID_idx` (`uID`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb3 COMMENT='板块信息表';

-- 主贴信息表
CREATE TABLE `topic` (
  `tID` int NOT NULL AUTO_INCREMENT COMMENT '主贴编号',
  `sID` int NOT NULL COMMENT '主贴板块编号',
  `uID` int NOT NULL COMMENT '主贴用户编号',
  `tTopic` varchar(20) NOT NULL COMMENT '主贴标题',
  `tContent` text NOT NULL COMMENT '主贴内容',
  `tTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '主贴时间',
  `tReplyCount` int NOT NULL DEFAULT '0' COMMENT '主贴回复次数',
  `tClickCount` int NOT NULL DEFAULT '0' COMMENT '主贴点击次数',
  PRIMARY KEY (`tID`),
  KEY `t_uID_idx` (`uID`),
  KEY `t_sID_idx` (`sID`),
  CONSTRAINT `t_sID` FOREIGN KEY (`sID`) REFERENCES `section` (`sID`),
  CONSTRAINT `t_uID` FOREIGN KEY (`uID`) REFERENCES `user` (`uID`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb3 COMMENT='主贴信息表';

-- 回复贴信息表
CREATE TABLE `reply` (
  `rID` int NOT NULL AUTO_INCREMENT COMMENT '回帖编号',
  `tID` int NOT NULL COMMENT '回帖主题帖子编号(主贴信息表)',
  `uID` int NOT NULL COMMENT '回帖的用户编号',
  `rTopic` varchar(20) NOT NULL DEFAULT '回帖' COMMENT '回帖标题',
  `rContent` text NOT NULL COMMENT '回帖内容',
  `rTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '回帖时间',
  `rClickCount` int NOT NULL DEFAULT '0' COMMENT '回帖点击次数',
  PRIMARY KEY (`rID`)
) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8mb3 COMMENT='回复贴信息表';

-- 初始数据 (增加一个用户)
INSERT INTO `forum_management_information_system1`.`user` (`userName`, `userPassword`, `userSex`, `userAge`, `userOccupation`, `userHobby`) VALUES ('管理员', '123456', '男', '18', '管理员', '你猜');

-- 初始化板块数据
INSERT INTO `forum_management_information_system1`.`section` (`uID`, `sName`, `sStatement`) VALUES ('1', '网易云', '小时候枕头上全是口水,长大后枕头上全是泪水;小时候微笑是一个心情,长大后微笑是一种表情;小时候哭着哭着就笑了,长大后笑着笑着就哭了。我们终于到了小时候最羡慕的年龄,但却没有成为小时候最想成为的人。——网易云音乐热评《当我已不再那么年轻》');
INSERT INTO `forum_management_information_system1`.`section` (`uID`, `sName`, `sStatement`) VALUES ('1', '码农', '码农Coding Peasant(s):可以指在程序设计某个专业领域中的专业人士,或是从事软体撰写,程序开发、维护的专业人员。但一般Coder特指进行编写代码的编码员。');
INSERT INTO `forum_management_information_system1`.`section` (`uID`, `sName`, `sStatement`) VALUES ('1', '电影', '电影,也被称为运动画面或动态画面,即“映画”,是作品视觉艺术形式,通过使用移动图像来表达沟通思想,故事,认知,情感,价值观,或各类大气模拟体验。这些图像通常伴随着声音,很少有其他感官刺激。 “电影”一词是电影摄影的缩写,通常用于指代电影制作和电影业,以及由此产生的艺术形式。');
INSERT INTO `forum_management_information_system1`.`section` (`uID`, `sName`, `sStatement`) VALUES ('1', '体育', '( physical education ,缩写 PE 或 P.E. ),是一种复杂的社会文化现象,它是一种以身体与智力活动为基本手段,根据人体生长发育、技能形成和机能提高等规律,达到促进全面发育、提高身体素质与全面教育水平、增强体质与提高运动能力、改善生活方式与提高生活质量的一种有意识、有目的、有组织的社会活动。');
INSERT INTO `forum_management_information_system1`.`section` (`uID`, `sName`, `sStatement`) VALUES ('1', '游戏', '游戏(英文: Game)是所有哺乳类动物,特别是灵长类动物学习生存的第一步。它是一种基于物质需求满足之上的,在一些特定时间、空间范围内遵循某种特定规则的,追求精神世界需求满足的社会行为方式,但同时这种行为方式也是哺乳类动物或者灵长类动物所需的一种降压减排的方式,不管是在出生幼年期,或者发育期,成熟期都会需要的一种行为方式。');
INSERT INTO `forum_management_information_system1`.`section` (`uID`, `sName`, `sStatement`) VALUES ('1', '旅行', '“旅”是旅行,外出,即为了实现某一目的而在空间上从甲地到乙地的行进过程;“游”是外出游览、观光、娱乐,即为达到这些目的所作的旅行。二者合起来即旅游。所以,旅行偏重于行,旅游不但有“行”,且有观光、娱乐含义。');
INSERT INTO `forum_management_information_system1`.`section` (`uID`, `sName`, `sStatement`) VALUES ('1', '明星', ' (拼音míng xīng,注音ㄇㄧㄥˊ ㄒㄧㄥ)汉语 词语 ,古书上指金星;旧时指 交际 场中有名的女子;现指在某个领域内有一定影响力的人物。 泛指有名的 演员 、 歌手 、 艺人 、 运动员 等。');

2. 封装数据库

1. DBUtil 类(JDBC连接数据库)

package forum.util;

import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import lombok.SneakyThrows;

import javax.sql.DataSource;
import java.sql.Connection;

/**
 * @author haomin
 * @date 2022/06/29 17:23
 **/
public class DBUtil {
    private static final DataSource dataSource;

    static {
        MysqlDataSource mysqlDataSource = new MysqlDataSource();
        // 数据库路径要正确
        mysqlDataSource.setUrl("jdbc:mysql:///forum_management_information_system1?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai");
        mysqlDataSource.setUser("root");
        mysqlDataSource.setPassword("123456");
        dataSource = mysqlDataSource;
    }

    @SneakyThrows
    public static Connection connection() {
        return dataSource.getConnection();
    }

}

2. 创建实体类

一般放对象的目录命名为model,根据model目录,其中存放的都是各种对象,例如 User 类、Topic 类、Reply 类。

使用@Data注解在类上时,不用再手动添加get/set等方法了,简化代码

2.1 User

package forum.model;

import lombok.Data;

// 使用@Data注解在类上时,不用再手动添加get/set等方法了,简化代码
@Data
public class User {
    public Integer uID;
    public String username;
    public String password;
    public String userSex;
    public Integer userAge;
    public String userOccupation;
    public String userHobby;
    public Integer userPoint;
    public Integer userClass;
    public String userRegister;
}

2.2 Section

package forum.model;

import lombok.Data;

@Data
public class Section {
    public Integer sID;
    public Integer uID;
    public String sName;
    public String sStatement;
    public Integer sClickCount;
    public Integer sTopicCount;
}

2.3 Topic

package forum.model;

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;

import java.util.Date;

@Data
public class Topic {
    public Integer tID;
    public Integer sID;
    public Integer uID;
    public String username;
    public String tTopic;
    public String tContent;
    //@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    public String tTime;
    public Integer tReplyCount;
    public Integer tClickCount;
}

2.4 Reply

package forum.model;

import com.fasterxml.jackson.annotation.JsonFormat;

import java.util.Date;

public class Reply {
    public Integer rID;
    public Integer tID;
    public Integer uID;
    public String username;
    public String rTopic;
    public String rContent;
    public String rTime;
    public Integer rClickCount;
}

2.5 Key

为实现一个搜索功能,新建了一个Keyword实体

package forum.model;

import lombok.Data;

@Data
public class Keyword {
    public String keyword;
}

3. 封装对数据库的增删查改类

一般放数据库增删查改的目录命名为dao,根据dao目录,其中存放的都是各种数据库增删查改方法类,例如 UserDao 类, SectionDao 类。

3.1 UserDao

package forum.dao;

import forum.model.User;
import forum.util.DBUtil;
import lombok.SneakyThrows;

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

/**
 * @author haomin
 * @date 2022/06/29 17:22
 **/

// 从数据库查找user数据的方法类
public class UserDao {

    // 用户帖子数
    @SneakyThrows
    public int selectPointCountByUid(int uid){
        String sql = "select count(*) from topic where uID = ?";
        try (Connection c = DBUtil.connection()){
            try (PreparedStatement ps = c.prepareStatement(sql)){
                ps.setInt(1,uid);
                try (ResultSet rs = ps.executeQuery()){
                    rs.next();
                    int count = rs.getInt("count(*)");
                    updatePointCountByUid(uid,count);
                    return count;
                }
            }
        }
    }

    // 更新主贴回复数
    @SneakyThrows
    public void updatePointCountByUid(int uID, int count) {
        String sql = "update user set userPoint = ? where uID = ?";
        try (Connection c = DBUtil.connection()) {
            try (PreparedStatement ps = c.prepareStatement(sql)) {
                ps.setInt(1,count);
                ps.setInt(2,uID);

                ps.executeUpdate();
            }
        }
    }

    // 用户等级
    public int selectClassCountByUid(int uid){
        int point = new UserDao().selectPointCountByUid(uid);
        int classCount = 0;
        if(point == 0){
            classCount = 0;
        }else if(point < 5){
            classCount = 1;
        }else if(point < 15){
            classCount = 2;
        }else if(point < 30){
            classCount = 3;
        }else {
            classCount = 4;
        }
        updateClassCountByUid(uid,classCount);
        return classCount;
    }

    @SneakyThrows
    private void updateClassCountByUid(int uID, int classCount) {
        String sql = "update user set userClass = ? where uID = ?";
        try (Connection c = DBUtil.connection()) {
            try (PreparedStatement ps = c.prepareStatement(sql)) {
                ps.setInt(1,classCount);
                ps.setInt(2,uID);

                ps.executeUpdate();
            }
        }

    }

    // 查询用户ByUsernameAndPassword
    @SneakyThrows
    public User selectOneByUsernameAndPassword(String username,String password){
        String sql = "select uID, userSex, userAge,userOccupation, userHobby, userPoint, userClass, userRegister from user where userName = ? and userPassword = ?";
        try (Connection c = DBUtil.connection()){
            try (PreparedStatement ps = c.prepareStatement(sql)){
                ps.setString(1,username);
                ps.setString(2,password);

                System.out.println("DEBUG: " + ps);
                try (ResultSet rs = ps.executeQuery()){
                    if(!rs.next()){
                        return null;
                    }

                    User user = new User();
                    user.uID = rs.getInt("uID");
                    user.username = username;
                    user.password = password;
                    user.userSex = rs.getString("userSex");
                    user.userAge = rs.getInt("userAge");
                    user.userOccupation = rs.getString("userOccupation");
                    user.userHobby = rs.getString("userHobby");
                    user.userPoint = rs.getInt("userPoint");
                    user.userClass = rs.getInt("userClass");
                    String Time = rs.getString("userRegister");
                    user.userRegister = Time.substring(0,Time.length()-5);

                    return user;
                }
            }
        }
    }

    // 查询用户名ByUid
    @SneakyThrows
    public String selectUserNameByUid(int uid){
        String sql = "select username from user where uID = ?";
        try (Connection c = DBUtil.connection()){
            try (PreparedStatement ps = c.prepareStatement(sql)){
                ps.setInt(1,uid);
                try (ResultSet rs = ps.executeQuery()){
                    if(!rs.next()){
                        return null;
                    }
                    String username = rs.getString("username");

                    return username;
                }
            }
        }
    }

    // 新建用户
    @SneakyThrows
    public User insert(String username, String password, String sex, int age, String occupation, String hobby) {
        String sql = "insert into user (username,userPassword,userSex,userAge,userOccupation,userHobby) values (?, ?, ?, ?, ?, ?)";
        try (Connection c = DBUtil.connection()){
            try (PreparedStatement ps = c.prepareStatement(sql)){
                ps.setString(1,username);
                ps.setString(2,password);
                ps.setString(3,sex);
                ps.setInt(4,age);
                ps.setString(5,occupation);
                ps.setString(6,hobby);

                ps.executeUpdate();
                System.out.println("新建用户完成");
                return new UserDao().selectOneByUsernameAndPassword(username,password);
            }
        }
    }
}

3.2 SectionDao

package forum.dao;

import forum.model.Section;
import forum.util.DBUtil;
import lombok.SneakyThrows;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

/**
 * @author haomin
 * @date 2022/06/30 11:32
 **/
public class SectionDao {

    // 得到板块集合ByUid
    @SneakyThrows
    public List<Section> selectListByUid(){
        List<Section> list = new ArrayList<>();
        String sql = "select sID, uID, sName, sStatement, sClickCount, sTopicCount from section;";
        try (Connection c = DBUtil.connection()) {
            try (PreparedStatement ps = c.prepareStatement(sql)){
                System.out.println("DEBUG: " + ps);
                try (ResultSet rs = ps.executeQuery()){
                    while (rs.next()){
                        Section section = new Section();
                        section.sID = rs.getInt("sID");
                        section.uID = rs.getInt("uID");
                        section.sName = rs.getString("sName");
                        section.sStatement = rs.getString("sStatement");
                        section.sClickCount = rs.getInt("sClickCount");
                        section.sTopicCount = new TopicDao().sTopicCount(section.sID);

                        list.add(section);
                    }
                }
            }
        }
        return list;
    }

    // 得到板块集合ByKeyWord
    @SneakyThrows
    public List<Section> selectSectionListByKeyword(String keyword) {
        List<Section> list = new ArrayList<>();
        String sql = "select * from section where sName like ?;";

        System.out.println(sql);
        try (Connection c = DBUtil.connection()) {
            System.out.println(sql);

            try (PreparedStatement ps = c.prepareStatement(sql)){
                System.out.println(sql);
                String key = "%"+keyword+"%";
                ps.setString(1,key);
                System.out.println(sql);

                try (ResultSet rs = ps.executeQuery()){
                    while (rs.next()){
                        Section section = new Section();
                        section.sID = rs.getInt("sID");
                        section.uID = rs.getInt("uID");
                        section.sName = rs.getString("sName");
                        section.sStatement = rs.getString("sStatement");
                        section.sClickCount = rs.getInt("sClickCount");
                        section.sTopicCount = new TopicDao().sTopicCount(section.sID);

                        list.add(section);
                    }
                }
            }
        }
        return list;
    }

    // 更新浏览次数
    @SneakyThrows
    public void update(int sid) {
        String sql = "update section set sClickCount = sClickCount+1 where sid = ?";
        try (Connection c = DBUtil.connection()) {
            try (PreparedStatement ps = c.prepareStatement(sql)) {
                ps.setInt(1,sid);

                ps.executeUpdate();
            }
        }
    }
}

3.3 TopicDao

package forum.dao;

import forum.model.Section;
import forum.model.Topic;
import forum.model.User;
import forum.util.DBUtil;
import lombok.SneakyThrows;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

/**
 * @author haomin
 * @date 2022/06/30 16:38
 **/
public class TopicDao {

    // 查询板块帖子数
    @SneakyThrows
    public int sTopicCount(Integer sID) {
        String sql = "select count(*) from topic where sID = ?";
        try (Connection c = DBUtil.connection()){
            try (PreparedStatement ps = c.prepareStatement(sql)){
                ps.setInt(1,sID);
                try (ResultSet rs = ps.executeQuery()){
                    rs.next();
                    int count = rs.getInt("count(*)");

                    updateSTopicCount(sID, count);
                    return count;
                }
            }
        }
    }

    // 更新板块帖子数
    @SneakyThrows
    public void updateSTopicCount(int sID, int count) {
        String sql = "update section set sTopicCount = ? where sID = ?";
        try (Connection c = DBUtil.connection()) {
            try (PreparedStatement ps = c.prepareStatement(sql)) {
                ps.setInt(1,count);
                ps.setInt(2,sID);

                ps.executeUpdate();
            }
        }
    }

    // 得到主贴集合BySid
    @SneakyThrows
    public List<Topic> selectListByUid(int sid){
        List<Topic> list = new ArrayList<>();
        String sql = "select tID, uID, tTopic, tContent, tTime, tReplyCount, tClickCount from topic where sID = ? order by tTime desc";
        try(Connection c = DBUtil.connection()){
            try (PreparedStatement ps = c.prepareStatement(sql)){
                ps.setInt(1,sid);
                System.out.println("DEBUG: " + ps);
                try (ResultSet rs = ps.executeQuery()){
                    while (rs.next()){
                        Topic topic = new Topic();
                        topic.tID = rs.getInt("tID");
                        topic.sID = sid;
                        topic.uID = rs.getInt("uID");
                        topic.username = new UserDao().selectUserNameByUid(topic.uID);
                        topic.tTopic = rs.getString("tTopic");
                        topic.tContent = rs.getString("tContent");
                        String Time = rs.getString("tTime");
                        topic.tTime = Time.substring(0,Time.length()-5);

                        topic.tReplyCount = new ReplyDao().tReplyCount(topic.tID);
                        topic.tClickCount = rs.getInt("tClickCount");

                        list.add(topic);
                    }
                }
            }
        }
        return list;
    }

    // 得到主贴集合ByKeyword
    @SneakyThrows
    public List<Topic> selectTopicListByKeyword(String keyword) {
        List<Topic> list = new ArrayList<>();
        String sql = "select * from topic where tTopic like ?;";

        System.out.println(sql);
        try (Connection c = DBUtil.connection()) {
            System.out.println(sql);

            try (PreparedStatement ps = c.prepareStatement(sql)){
                System.out.println(sql);
                String key = "%"+keyword+"%";
                ps.setString(1,key);
                System.out.println(sql);

                try (ResultSet rs = ps.executeQuery()){
                    while (rs.next()){
                        Topic topic = new Topic();
                        topic.tID = rs.getInt("tID");
                        topic.sID = rs.getInt("sId");
                        topic.uID = rs.getInt("uID");
                        topic.username = new UserDao().selectUserNameByUid(topic.uID);
                        topic.tTopic = rs.getString("tTopic");
                        topic.tContent = rs.getString("tContent");
                        String Time = rs.getString("tTime");
                        topic.tTime = Time.substring(0,Time.length()-5);

                        topic.tReplyCount = new ReplyDao().tReplyCount(topic.tID);
                        topic.tClickCount = rs.getInt("tClickCount");

                        list.add(topic);
                    }
                }
            }
        }

        return list;
    }

    // 查询一个主贴ByTid
    @SneakyThrows
    public Topic selectTopicByTid(int tid) {
        String sql = "select sID, uID, tTopic, tContent, tTime, tReplyCount, tClickCount from topic where tID = ?";
        try(Connection c = DBUtil.connection()){
            try (PreparedStatement ps = c.prepareStatement(sql)){
                ps.setInt(1,tid);

                System.out.println("DEBUG: " + ps);
                try (ResultSet rs = ps.executeQuery()){
                    rs.next();

                    Topic topic = new Topic();
                    topic.tID = tid;
                    topic.sID = rs.getInt("sID");
                    topic.uID = rs.getInt("uID");
                    topic.username = new UserDao().selectUserNameByUid(topic.uID);
                    topic.tTopic = rs.getString("tTopic");
                    topic.tContent = rs.getString("tContent");
                    String Time = rs.getString("tTime");
                    topic.tTime = Time.substring(0,Time.length()-5);

                    topic.tReplyCount = new ReplyDao().tReplyCount(topic.tID);
                    topic.tClickCount = rs.getInt("tClickCount");

                    return topic;
                }
            }
        }
    }

    // 插入主贴
    @SneakyThrows
    public void insert(int sid, Integer uID, String title, String content) {
        String sql = "insert into topic (sID, uID, tTopic, tContent) values (?, ?, ?, ?)";
        try (Connection c = DBUtil.connection()){
            try (PreparedStatement ps = c.prepareStatement(sql)){
                ps.setInt(1,sid);
                ps.setInt(2,uID);
                ps.setString(3,title);
                ps.setString(4,content);

                ps.executeUpdate();
                System.out.println("插入完成");
            }
        }
    }

    // 更新主贴浏览次数
    @SneakyThrows
    public void update(int tid) {
        String sql = "update topic set tClickCount = tClickCount+1 where tid = ?";
        try (Connection c = DBUtil.connection()) {
            try (PreparedStatement ps = c.prepareStatement(sql)) {
                ps.setInt(1,tid);

                ps.executeUpdate();
            }
        }
    }

}

3.4 ReplyDao

package forum.dao;

import forum.model.Reply;
import forum.util.DBUtil;
import lombok.SneakyThrows;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

/**
 * @author haomin
 * @date 2022/06/30 16:38
 **/
public class ReplyDao {

    // 查询主贴回复数
    @SneakyThrows
    public int tReplyCount(int tid){
        try (Connection c = DBUtil.connection()){
            String sql = "select count(*) from reply where tID = ?;";
            try (PreparedStatement ps = c.prepareStatement(sql)){
                ps.setInt(1,tid);
                try (ResultSet rs = ps.executeQuery()){
                    rs.next();
                    int count = rs.getInt("count(*)");
                    updateTReplyCount(tid,count);
                    return count;
                }
            }
        }
    }

    // 更新主贴回复数
    @SneakyThrows
    public void updateTReplyCount(int tID, int count) {
        String sql = "update topic set tReplyCount = ? where tID = ?";
        try (Connection c = DBUtil.connection()) {
            try (PreparedStatement ps = c.prepareStatement(sql)) {
                ps.setInt(1,count);
                ps.setInt(2,tID);

                ps.executeUpdate();
            }
        }
    }

    // 根据tid查询所有回复
    @SneakyThrows
    public List<Reply> selectListByTid(int tid){
        List<Reply> list = new ArrayList<>();
        String sql = "select rID, uID, rTopic, rContent, rTime, rClickCount from reply where tid = ? order by rTime desc";
        try (Connection c = DBUtil.connection()){
            try (PreparedStatement ps = c.prepareStatement(sql)){
                ps.setInt(1,tid);
                System.out.println("DEBUG: " + ps);

                try (ResultSet rs = ps.executeQuery()){
                    while (rs.next()){
                        Reply reply = new Reply();
                        reply.rID = rs.getInt("rID");
                        reply.tID = tid;
                        reply.uID = rs.getInt("uID");
                        reply.username = new UserDao().selectUserNameByUid(reply.uID);
                        reply.rTopic = rs.getString("rTopic");
                        reply.rContent = rs.getString("rContent");
                        String Time = rs.getString("rTime");
                        reply.rTime = Time.substring(0,Time.length()-5);
                        reply.rClickCount = rs.getInt("rClickCount");

                        list.add(reply);
                    }
                }

            }
        }
        return list;
    }

    // 插入主贴
    @SneakyThrows
    public void insert(int tid, Integer uID, String content) {
        try (Connection c = DBUtil.connection()){
            String sql = "insert into reply (tID,uID,rContent) values (?,?,?)";
            try (PreparedStatement ps = c.prepareStatement(sql)){
                ps.setInt(1,tid);
                ps.setInt(2,uID);
                ps.setString(3,content);

                ps.executeUpdate();
                System.out.println("插入完成");
            }
        }
    }
}

3.5 KeyDao

package forum.dao;

import forum.model.Keyword;
import forum.util.DBUtil;
import lombok.SneakyThrows;

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

/**
 * @author haomin
 * @date 2022/07/04 10:11
 **/

public class KeyDao {

    // 插入查询的关键字
    @SneakyThrows
    public void insertKey (String keyword){
        String sql = "INSERT INTO `forum_management_information_system`.`key` (`keyword`) VALUES (?);";
        try (Connection c = DBUtil.connection()){
            try (PreparedStatement ps = c.prepareStatement(sql)){
                ps.setString(1,keyword);

                ps.executeUpdate();
                System.out.println("插入完成");
            }
        }
    }

    // 更新主贴回复数
    @SneakyThrows
    public void updateTReplyCount(int tID, int count) {
        String sql = "update topic set tReplyCount = ? where tID = ?";
        try (Connection c = DBUtil.connection()) {
            try (PreparedStatement ps = c.prepareStatement(sql)) {
                ps.setInt(1,count);
                ps.setInt(2,tID);

                ps.executeUpdate();
            }
        }
    }

    // 查询是否存在关键字
    @SneakyThrows
    public String selectKey () {
        String sql = "select keyword from forum_management_information_system.key;";
        try (Connection c = DBUtil.connection()){
            try (PreparedStatement ps = c.prepareStatement(sql)){
                try (ResultSet rs = ps.executeQuery()){
                    if(rs.next()){
                        String keyword = rs.getString("keyword");
                        return keyword;
                    }else {
                        return null;
                    }

                }
            }
        }
    }

    // 删除关键字
    @SneakyThrows
    public void deleteKey () {
        String sql = "DELETE FROM `forum_management_information_system`.`key` WHERE (1 = 1);";
        try (Connection c = DBUtil.connection()){
            try (PreparedStatement ps = c.prepareStatement(sql)){
                ps.executeUpdate();
            }
        }
    }
}

三. 约定前后端交互接口

0. 前端页面

先把前端页面拷贝到当前项目

前端页面可见于上一篇博客:《前端项目 - 论坛信息管理系统(纯页面)》

1. 实现论坛列表页

1.1约定前后端交互接口

{
  "currentUser" : {
    "uID" : 17,
    "username" : "张三",
    "password" : "123",
    "userSex" : "男",
    "userAge" : 18,
    "userOccupation" : "大数据开发工程师",
    "userHobby" : "敲代码",
    "userPoint" : 1,
    "userClass" : 1,
    "userRegister" : "2022-07-08 15:01",
    "uid" : 17
  },
  "pointCount" : 1,
  "classCount" : 1,
  "sectionList" : [ {
    "sID" : 12,
    "uID" : 1,
    "sName" : "网易云",
    "sStatement" : "小时候枕头上全是口水,长大后枕头上全是泪水;小时候微笑是一个心情,长大后微笑是一种表情;小时候哭着哭着就笑了,长大后笑着笑着就哭了。我们终于到了小时候最羡慕的年龄,但却没有成为小时候最想成为的人。——网易云音乐热评《当我已不再那么年轻》",
    "sClickCount" : 2,
    "sTopicCount" : 3,
    "uid" : 1,
    "sname" : "网易云",
    "sclickCount" : 2,
    "sstatement" : "小时候枕头上全是口水,长大后枕头上全是泪水;小时候微笑是一个心情,长大后微笑是一种表情;小时候哭着哭着就笑了,长大后笑着笑着就哭了。我们终于到了小时候最羡慕的年龄,但却没有成为小时候最想成为的人。——网易云音乐热评《当我已不再那么年轻》"
    "sid" : 12,
    "stopicCount" : 3
  }, ...]
  "topicList" : null
}

1.2 实现服务器代码

package forum.servlet;

import com.fasterxml.jackson.databind.ObjectMapper;
import forum.dao.KeyDao;
import forum.model.Keyword;
import forum.model.SectionListResult;
import forum.model.User;
import forum.service.SectionService;

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;

/**
 * @author haomin
 * @date 2022/06/30 11:21
 **/

@WebServlet("/section-list.json")
public class SectionListJsonServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        User currentUser = null;
        Keyword key = null;
        System.out.println("开始");

        HttpSession session = req.getSession(false);
        if(session != null){
            currentUser = (User) session.getAttribute("currentUser");
        }
        String keyword = new KeyDao().selectKey();

        SectionService sectionService = new SectionService();
        SectionListResult result = null;
        if(keyword == null) {
            result = sectionService.sectionListResult(currentUser);
            System.out.println("执行第一个");
        }else {
            System.out.println(keyword);
            result = sectionService.sectionListResult(currentUser,keyword);
            System.out.println("执行第二个");

        }

        ObjectMapper objectMapper = new ObjectMapper();
        String jsonString = objectMapper.writeValueAsString(result);

        resp.setCharacterEncoding("utf-8");
        resp.setContentType("application/json");
        resp.getWriter().printf(jsonString);
    }
}

1.3 编写客户端代码

// 1. request /json/article_list.json
// 2. update dom tree
function renderAuthor(currentUser) {
    document.querySelector('.author-username').textContent = currentUser.username
    document.querySelector('.author-userSex').textContent = currentUser.userSex
    document.querySelector('.author-userAge').textContent = currentUser.userAge
    document.querySelector('.author-userOccupation').textContent = currentUser.userOccupation
    document.querySelector('.author-userHobby').textContent = "爱好:" + currentUser.userHobby
}

function renderCount(pointCount, classCount) {
    document.querySelector('.author-userPoint').textContent = pointCount
    document.querySelector('.author-userClass').textContent = classCount
}

function renderSectionList(sectionList, topicList) {
    console.log(sectionList)
    var container = document.querySelector('.section')
    console.log(container)

    for (var i in sectionList) {
        var section = sectionList[i]
        console.log(section)

        var html = `<li>` +
             `<div class="板块信息">` +
                ` <h3 class="板块名称">${section.sName}</h3>` +
                 `<div class="版主">版块ID: <span class="版主名称">${section.sID}</span></div>` +
                `<p class="板块说明">${section.sStatement}</p>` +

                ` <div class="点击">` +
                     `<div class="数量">` +
                        ` <div>浏览量</div>` +
                        ` <div>${section.sClickCount}</div>` +
                     `</div>` +
                     `<div>` +
                         `<div>主贴数</div>` +
                         `<div>${section.sTopicCount}</div>` +
                     `</div>` +
                 `</div>` +

                 `<div class="查看详情">` +
                     `<a href="detail.html?sid=${section.sID}" target="_self">查看详情>></a>` +
                 `</div>` +

             `</div></li>`

        container.innerHTML += html
    }
}

function renderTopicList(topicList) {
    console.log(topicList)
    var container = document.querySelector('.topic')
    console.log(container)

    for (var i in topicList) {
        var topic = topicList[i]
        console.log(topic)

        var html = `<li>` +
             `<div class="板块信息">` +
                 `<h3 class="板块名称">${topic.tTopic}</h3>` +
                ` <p class="主贴时间">${topic.tTime}</p>` +

                ` <div class="版主">贴主: <span class="版主名称">${topic.username}</span></div>` +

                ` <p class="板块说明">${topic.tContent}</p>` +

                ` <div class="点击">` +
                   `  <div class="数量">` +
                         `<div>浏览量</div>` +
                        ` <div>${topic.tClickCount}</div>` +
                     `</div>` +
                     `<div>` +
                         `<div>回复</div>` +
                         `<div>${topic.tReplyCount}</div>` +
                     `</div>` +
                ` </div>` +

                `<div class="查看回复" style="display: block; margin: 10px auto 0 auto; align-items: center;
                text-align: center;color: black;user-select: none;cursor: pointer;">` +
                  `<a href="reply.html?tid=${topic.tID}" target="_self" style="color: black;text-decoration:
                  none;font-size: 13px;">查看回复>></a>` +
                `</div>` +
             `</div></li>`

        container.innerHTML += html
    }
}

var xhr = new XMLHttpRequest()
xhr.open('get', '/section-list.json')
xhr.onload = function() {
    //alert(this.responseText);
    var data = JSON.parse(this.responseText)
    if(!data.currentUser){
        // 重定向
        // location = '/login.html'
        location.assign('/login.html')
        return
    }

    renderAuthor(data.currentUser)
    renderCount(data.pointCount, data.classCount)
    renderSectionList(data.sectionList)
    renderTopicList(data.topicList)
}
xhr.send()

实现效果:

2. 实现论坛主贴页

2.1约定前后端交互接口

{
  "currentUser" : {
    "uID" : 17,
    "username" : "张三",
    "password" : "123",
    "userSex" : "男",
    "userAge" : 18,
    "userOccupation" : "大数据开发工程师",
    "userHobby" : "敲代码",
    "userPoint" : 1,
    "userClass" : 1,
    "userRegister" : "2022-07-08 15:01",
    "uid" : 17
  },
  "pointCount" : 1,
  "classCount" : 1,
  "topicList" : [ {
    "tID" : 16,
    "sID" : 12,
    "uID" : 11,
    "username" : "管理员",
    "tTopic" : "窃取天上三分景",
    "tContent" : "小狐狸想去人间很久了,临行之前,她的姥姥赠她了一件宝物芙蓉面。 小狐狸得了这芙蓉面,欢喜极了,她摸了摸芙蓉面道:“姥姥,我得了芙蓉面也能行走人世吗?” “是啊,只要你戴上芙蓉面,这世上任何人的脸,都可以幻化,可你是妖,就算有了芙蓉面,也得学世人的姿态。” 小狐狸拿着芙蓉面思索半天,",
    "tTime" : "2022-07-08 13:50",
    "tReplyCount" : 4,
    "tClickCount" : 4,
    "uid" : 11,
    "treplyCount" : 4,
    "tclickCount" : 4,
    "ttime" : "2022-07-08 13:50",
    "tid" : 16,
    "tcontent" : "小狐狸想去人间很久了,临行之前,她的姥姥赠她了一件宝物芙蓉面。 小狐狸得了这芙蓉面,欢喜极了,她摸了摸芙蓉面道:“姥姥,我得了芙蓉面也能行走人世吗?” “是啊,只要你戴上芙蓉面,这世上任何人的脸,都可以幻化,可你是妖,就算有了芙蓉面,也得学世人的姿态。” 小狐狸拿着芙蓉面思索半天,",
    "ttopic" : "窃取天上三分景",
    "sid" : 12
  },...]
}

2.2 实现服务器代码

package forum.servlet;

import com.fasterxml.jackson.databind.ObjectMapper;
import forum.dao.KeyDao;
import forum.model.Keyword;
import forum.model.SectionListResult;
import forum.model.User;
import forum.service.SectionService;

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;

/**
 * @author haomin
 * @date 2022/06/30 11:21
 **/

@WebServlet("/section-list.json")
public class SectionListJsonServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        User currentUser = null;
        Keyword key = null;
        System.out.println("开始");

        HttpSession session = req.getSession(false);
        if(session != null){
            currentUser = (User) session.getAttribute("currentUser");
        }
        String keyword = new KeyDao().selectKey();

        SectionService sectionService = new SectionService();
        SectionListResult result = null;
        if(keyword == null) {
            result = sectionService.sectionListResult(currentUser);
            System.out.println("执行第一个");
        }else {
            System.out.println(keyword);
            result = sectionService.sectionListResult(currentUser,keyword);
            System.out.println("执行第二个");

        }

        ObjectMapper objectMapper = new ObjectMapper();
        String jsonString = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(result);

        resp.setCharacterEncoding("utf-8");
        resp.setContentType("application/json");
        resp.getWriter().printf(jsonString);
    }
}

2.3 编写客户端代码

// 1. request /json/article_list.json
// 2. update dom tree
function renderAuthor(currentUser) {
    document.querySelector('.author-username').textContent = currentUser.username
    document.querySelector('.author-userSex').textContent = currentUser.userSex
    document.querySelector('.author-userAge').textContent = currentUser.userAge
    document.querySelector('.author-userOccupation').textContent = currentUser.userOccupation
    document.querySelector('.author-userHobby').textContent = "爱好:" + currentUser.userHobby
}

function renderCount(pointCount, classCount) {
    document.querySelector('.author-userPoint').textContent = pointCount
    document.querySelector('.author-userClass').textContent = classCount
}

function renderTopicList(topicList) {
    console.log(topicList)
    var container = document.querySelector('.topic')
    console.log(container)

    for (var i in topicList) {
        var topic = topicList[i]
        console.log(topic)

        var html = `<li>` +
             `<div class="板块信息">` +
                 `<h3 class="板块名称">${topic.tTopic}</h3>` +
                ` <p class="主贴时间">${topic.tTime}</p>` +

                ` <div class="版主">贴主: <span class="版主名称">${topic.username}</span></div>` +

                ` <p class="板块说明">${topic.tContent}</p>` +

                ` <div class="点击">` +
                   `  <div class="数量">` +
                         `<div>浏览量</div>` +
                        ` <div>${topic.tClickCount}</div>` +
                     `</div>` +
                     `<div>` +
                         `<div>回复</div>` +
                         `<div>${topic.tReplyCount}</div>` +
                     `</div>` +
                ` </div>` +

                `<div class="查看回复" style="display: block; margin: 10px auto 0 auto; align-items: center;
                text-align: center;color: black;user-select: none;cursor: pointer;">` +
                  `<a href="reply.html?tid=${topic.tID}" target="_self" style="color: black;text-decoration:
                  none;font-size: 13px;">查看回复>></a>` +
                `</div>` +
             `</div></li>`

        container.innerHTML += html
    }
}

var xhr = new XMLHttpRequest()
xhr.open('get', '/topic-list.json' + location.search)

xhr.onload = function() {
    // 打印 json内容
    alert(this.responseText);
    console.log(this.responseText)
    var data = JSON.parse(this.responseText)
    if(!data.currentUser){
        // 重定向
        // location = '/login.html'
        location.assign('/login.html')
        return
    }

    renderAuthor(data.currentUser)
    renderCount(data.pointCount, data.classCount)
    renderTopicList(data.topicList)

}
xhr.send()

实现效果:

3. 实现论坛回复页

3.1约定前后端交互接口

{
  "currentUser" : {
    "uID" : 17,
    "username" : "张三",
    "password" : "123",
    "userSex" : "男",
    "userAge" : 18,
    "userOccupation" : "大数据开发工程师",
    "userHobby" : "敲代码",
    "userPoint" : 1,
    "userClass" : 1,
    "userRegister" : "2022-07-08 15:01",
    "uid" : 17
  },
  "pointCount" : 1,
  "classCount" : 1,
  "replyList" : [ {
    "rID" : 39,
    "tID" : 16,
    "uID" : 17,
    "username" : "张三",
    "rTopic" : "回帖",
    "rContent" : "hello word",
    "rTime" : "2022-07-08 15:04",
    "rClickCount" : 0
  }, {
    "rID" : 32,
    "tID" : 16,
    "uID" : 11,
    "username" : "管理员",
    "rTopic" : "回帖",
    "rContent" : "有些人为了上前排连尊严都不要了,您怎么看呢?父亲?",
    "rTime" : "2022-07-08 13:54",
    "rClickCount" : 0
  }],
  "tid" : 16,
  "topic" : {
    "tID" : 16,
    "sID" : 12,
    "uID" : 11,
    "username" : "管理员",
    "tTopic" : "窃取天上三分景",
    "tContent" : "小狐狸想去人间很久了,临行之前,她的姥姥赠她了一件宝物芙蓉面。 小狐狸得了这芙蓉面,欢喜极了,她摸了摸芙蓉面道:“姥姥,我得了芙蓉面也能行走人世吗?” “是啊,只要你戴上芙蓉面,这世上任何人的脸,都可以幻化,可你是妖,就算有了芙蓉面,也得学世人的姿态。” 小狐狸拿着芙蓉面思索半天,",
    "tTime" : "2022-07-08 13:50",
    "tReplyCount" : 4,
    "tClickCount" : 6,
    "uid" : 11,
    "treplyCount" : 4,
    "tclickCount" : 6,
    "ttime" : "2022-07-08 13:50",
    "tid" : 16,
    "tcontent" : "小狐狸想去人间很久了,临行之前,她的姥姥赠她了一件宝物芙蓉面。 小狐狸得了这芙蓉面,欢喜极了,她摸了摸芙蓉面道:“姥姥,我得了芙蓉面也能行走人世吗?” “是啊,只要你戴上芙蓉面,这世上任何人的脸,都可以幻化,可你是妖,就算有了芙蓉面,也得学世人的姿态。” 小狐狸拿着芙蓉面思索半天,",
    "ttopic" : "窃取天上三分景",
    "sid" : 12
  }
}

3.2 实现服务器代码

package forum.servlet;

import com.fasterxml.jackson.databind.ObjectMapper;
import forum.dao.TopicDao;
import forum.model.ReplyListResult;
import forum.model.User;
import forum.service.ReplyService;

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;

/**
 * @author haomin
 * @date 2022/07/01 17:05
 **/

@WebServlet("/reply-list.json")
public class ReplyListServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        String tidString = req.getParameter("tid");
        int tid = Integer.parseInt(tidString);

        User currentUser = null;
        HttpSession session = req.getSession(false);
        if(session != null){
            currentUser = (User)session.getAttribute("currentUser");
        }

        // 浏览一次回帖页面,浏览次数加1
        new TopicDao().update(tid);

        ReplyService replyService = new ReplyService();
        ReplyListResult result = replyService.replyListResult(currentUser,tid);
        result.tid = tid;

        ObjectMapper objectMapper = new ObjectMapper();
        String jsonString = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(result);

        resp.setCharacterEncoding("utf-8");
        resp.setContentType("application/json");
        resp.getWriter().println(jsonString);
    }
}

3.3 编写客户端代码

function renderAuthor(currentUser) {
    document.querySelector('.author-username').textContent = currentUser.username
    document.querySelector('.author-userSex').textContent = currentUser.userSex
    document.querySelector('.author-userAge').textContent = currentUser.userAge
    document.querySelector('.author-userOccupation').textContent = currentUser.userOccupation
    document.querySelector('.author-userHobby').textContent = "爱好:" + currentUser.userHobby
}

function renderCount(pointCount, classCount) {
    document.querySelector('.author-userPoint').textContent = pointCount
    document.querySelector('.author-userClass').textContent = classCount
}

function renderDefineTid(tid){
    document.querySelector('.tid').value = tid;
}

function renderReplyList(topic,replyList){
    console.log(replyList)
    var container = document.querySelector('.reply')
    console.log(container)

    // 主贴
    var html = `<li>` +
         `<div class="板块信息1">` +

             `<h3 class="板块名称">${topic.tTopic}</h3>` +
            ` <p class="主贴时间">${topic.tTime}</p>` +

            ` <div class="版主">贴主: <span class="版主名称">${topic.username}</span></div>` +

            ` <p class="板块说明">${topic.tContent}</p>` +

                ` <div class="点击">` +
                   `  <div class="数量">` +
                         `<div>浏览量</div>` +
                        ` <div>${topic.tClickCount}</div>` +
                     `</div>` +
                ` </div>` +

         `</div></li>`

    container.innerHTML += html

    //回帖
    for(var i in replyList){
        var reply = replyList[i]
        console.log(reply)

        var html = `<li>` +
                     `<div class="板块信息">` +
                         `<h3 class="板块名称">${reply.rTopic}</h3>` +
                        ` <p class="主贴时间">${reply.rTime}</p>` +

                        ` <div class="版主"><span class="版主名称">${reply.username}</span></div>` +
                        ` <p class="板块说明">${reply.rContent}</p>` +

                        /*` <div class="点击">` +
                           `  <div class="数量">` +
                                 `<div>点击次数</div>` +
                                ` <div>100</div>` +
                             `</div>` +
                        ` </div>` +*/
                     `</div></li>`

                container.innerHTML += html
    }
}

var xhr = new XMLHttpRequest()
xhr.open('get','/reply-list.json' + location.search)

xhr.onload = function() {
    //alert(this.responseText);
    console.log(this.responseText)
    var data = JSON.parse(this.responseText)
    if(!data.currentUser){
        location.assign('/login.html')
        return
    }

    renderAuthor(data.currentUser)
    renderCount(data.pointCount, data.classCount)
    renderReplyList(data.topic,data.replyList)
    renderDefineTid(data.tid)
}
xhr.send()

实现效果:

4. 实现论坛个人中心页

4.1约定前后端交互接口

个人中心的json数据来自于/section-list.json

{
  "currentUser" : {
    "uID" : 17,
    "username" : "张三",
    "password" : "123",
    "userSex" : "男",
    "userAge" : 18,
    "userOccupation" : "大数据开发工程师",
    "userHobby" : "敲代码",
    "userPoint" : 1,
    "userClass" : 1,
    "userRegister" : "2022-07-08 15:01",
    "uid" : 17
  }
}

4.2 实现服务器代码

个人中心的服务器代码来自于/section-list.json,和列表页服务器代码相同,再次不在赘述。

4.3 编写客户端代码

function renderAuthor(currentUser) {
    document.querySelector('.author-username').value = currentUser.username
    document.querySelector('.author-userSex').value = currentUser.userSex
    document.querySelector('.author-userAge').value = currentUser.userAge
    document.querySelector('.author-userOccupation').value = currentUser.userOccupation
    document.querySelector('.author-userHobby').value = currentUser.userHobby
    document.querySelector('.author-userPoint').value = currentUser.userPoint
    document.querySelector('.author-userClass').value = currentUser.userClass
    document.querySelector('.author-userRegister').value = currentUser.userRegister
}

var xhr = new XMLHttpRequest()
xhr.open('get', '/section-list.json')
xhr.onload = function() {
    //alert(this.responseText);
    var data = JSON.parse(this.responseText)
    if(!data.currentUser){
        // 重定向
        // location = '/login.html'
        location.assign('/login.html')
        return
    }

    renderAuthor(data.currentUser)
}
xhr.send()

实现效果:

5. 实现论坛发布帖子页

5.1约定前后端交互接口

[请求] post /editor.do

5.2 实现服务器代码

package forum.servlet;

import forum.dao.TopicDao;
import forum.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;

/**
 * @author haomin
 * @date 2022/07/01 19:30
 **/

@WebServlet("/editor.do")
public class EditorDoServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        String title = req.getParameter("title");
        String sidString = req.getParameter("type");
        int sid = Integer.parseInt(sidString);
        String content = req.getParameter("editor-markdown-doc");

        User currentUser = null;
        HttpSession session = req.getSession(false);
        if (session != null) {
            currentUser = (User) session.getAttribute("currentUser");
        }

        if (currentUser == null) {
            // 说明没有登录
            resp.sendRedirect("/login.html");
            return;
        }

        TopicDao topicDao = new TopicDao();
        topicDao.insert(sid,currentUser.uID,title,content);

        // 重定向到文章详情页
        resp.sendRedirect("/detail.html?sid=" + sid);
    }
}

5.3 编写客户端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>写帖子</title>
    <link rel="stylesheet" href="css/navigation bar.css">
    <link rel="stylesheet" href="css/editor.css">
</head>
<body>
    <div class="导航栏">
        <div class="left-logo">
            <div class="logo"><img src="img/系统图标.png" width="45"></div>
            <p>论坛管理信息系统</p>
        </div>

        <div class="占位"></div>

        <div class="right-function">
            <a href="center.html">个人中心</a>
            <a href="list.html">主页</a>
            <a href="editor.html">写帖子</a>
            <a href="logout" target="_self">注销</a>
        </div>
    </div>

    <div class="blog-edit-container">
        <form method="post" action="/editor.do">
            <div class="title">
                <input type="text" placeholder="在这里写下主贴标题" id="title" name="title">
                <input type="text" placeholder="板块编号" id="type" name="type" style="    height: 40px;
    width: 80px;

    text-indent: 10px;
    border-radius: 10px;
    outline: none;
    border: none;
    background-color:rgba(255, 255, 255, 0.8);">

                <button id="submit">发布帖子</button>
            </div>

        <div id="editor" class="编辑器"></div>
        <link rel="stylesheet" href="editor.md/css/editormd.min.css" />
        <script src="js/jquery.min.js"></script>
        <script src="editor.md/lib/marked.min.js"></script>
        <script src="editor.md/lib/prettify.min.js"></script>
        <script src="editor.md/editormd.js"></script>

        </form>
    </div>

    <script>
        var content = '# 在这里写下一篇帖子 ##';
        var config = {
            // 这里的尺寸必须在这里设置. 设置样式会被 editormd 自动覆盖掉.
            width: "100%",
            // 高度 100% 意思是和父元素一样高. 要在父元素的基础上去掉标题编辑区的高度
            height: "100vh",
            // 编辑器中的初始内容
            markdown: content,
            // 指定 editor.md 依赖的插件路径
            path: "editor.md/lib/"
        };
        editormd("editor", config);

    </script>
</body>
</html>

实现效果:

6. 实现论坛登录页

6.1约定前后端交互接口

[请求] post /login.do

6.2 实现服务器代码

package forum.servlet;

import forum.dao.UserDao;
import forum.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;

/**
 * @author haomin
 * @date 2022/06/29 17:18
 **/

@WebServlet("/login.do")
public class LoginDoServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        System.out.println("DEBUG: username = " + username);
        System.out.println("DEBUG: password = " + password);

        UserDao userDao = new UserDao();
        User user = userDao.selectOneByUsernameAndPassword(username,password);
        if(user == null){
            resp.sendRedirect("/login.html");
            return;
        }

        System.out.println(user);

        HttpSession session = req.getSession();
        session.setAttribute("currentUser",user);

        resp.sendRedirect("/");
    }
}

6.3 编写客户端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
    <link rel="stylesheet" href="css/navigation bar.css">
    <link rel="stylesheet" href="css/login.css">
</head>
<body>

    <div class="导航栏">
        <div class="left-logo">
            <div class="logo"><img src="img/系统图标.png" width="45"></div>
            <p>论坛管理信息系统</p>
        </div>

        <div class="占位"></div>

        <div class="right-function">
            <span class="center"></span>
            <a href="list.html">主页</a>
            <a href="editor.html" target="_blank">写帖子</a>
            <a href="logon.html">注册</a>
        </div>
    </div>

    <div class="主体区">
        <div class="登录框">
            <form action="/login.do" method="post">
                <h2>登录</h2>
                <div>
                    <span>用户名</span>
                    <input type="text" class="text" name="username" placeholder="请输入用户名">
                </div>
                <div>
                    <span>密码</span>
                    <input type="password" class="text" name="password" placeholder="请输入密码">
                </div>
                <div>
                    <button class="提交">登录</button>
                </div>
            </form>
        </div>
    </div>

</body>
</html>

实现效果:

7. 实现论坛注册页

7.1约定前后端交互接口

[请求] post /logon.do

7.2 实现服务器代码

package forum.servlet;

import forum.dao.UserDao;
import forum.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;

/**
 * @author haomin
 * @date 2022/07/03 08:34
 **/
@WebServlet("/logon.do")
public class LogonDoServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        String username = req.getParameter("username");
        String sex = req.getParameter("sex");
        String age = req.getParameter("age");
        String occupation = req.getParameter("occupation");
        String hobby = req.getParameter("hobby");
        String password1 = req.getParameter("password1");
        String password2 = req.getParameter("password2");

        UserDao userDao = new UserDao();
        User user = userDao.insert(username,password1,sex,Integer.parseInt(password1),occupation,hobby);

        HttpSession session = req.getSession();
        session.setAttribute("currentUser",user);

        resp.sendRedirect("/");

    }
}

7.3 编写客户端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册</title>
    <link rel="stylesheet" href="css/navigation bar.css">
    <link rel="stylesheet" href="css/logon.css">
</head>
<body>

    <div class="导航栏">
        <div class="left-logo">
            <div class="logo"><img src="img/系统图标.png" width="45"></div>
            <p>论坛管理信息系统</p>
        </div>

        <div class="占位"></div>

        <div class="right-function">
            <span class="center"></span>
            <a href="list.html">主页</a>
            <a href="editor.html" target="_blank">写帖子</a>
            <a href="login.html">登录</a>
        </div>
    </div>

    <div class="主体区">
        <div class="注册框">
            <form action="/logon.do" method="post">
                <h2>注册</h2>
                <div>
                    <span>昵称</span>
                    <input type="text" class="text" placeholder="请输入昵称" name="username">
                </div>
                <div>
                    <span>年龄</span>
                    <input type="text" class="text" placeholder="请输入年龄" name="age">
                </div>
                <div>
                    <span>性别</span>
                    <input type="text" class="text" placeholder="请输入性别  男|女" name="sex">

                </div>
                <div>
                    <span>爱好</span>
                    <input type="text" class="text" placeholder="请输入爱好" name="hobby">
                </div>
                <div>
                    <span>职业</span>
                    <input type="text" class="text" placeholder="请输入职业" name="occupation">
                </div>
<!--                <div>-->
<!--                    <span>Email</span>-->
<!--                    <input type="text" class="text" placeholder="请输入Email" name="email">-->
<!--                </div>-->
                <div>
                    <span>密码</span>
                    <input type="password" class="text" placeholder="请输入密码" name="password1">
                </div>
                <div>
                    <span>再次确认密码</span>
                    <input type="password" class="text" placeholder="请再次确认密码" name="password2">
                </div>
                <div>
                    <button class="提交">注册</button>
                </div>
            </form>
        </div>
    </div>

</body>
</html>

实现效果:

8. 实现论坛注销

8.1实现服务器代码

package forum.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("/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) {
            session.removeAttribute("currentUser");
        }

        resp.sendRedirect("/");
    }
}
package forum.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 java.io.IOException;

/**
 * @author haomin
 * @date 2022/06/30 08:43
 **/

@WebServlet("")
public class IndexServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.sendRedirect("/list.html");
    }
}

重定向到论坛主页,但是服务器发现没有用户登录,继而重定向到用户登录页。

实现效果:

论坛信息管理系统主要重点就介绍到这里了,如果想看看项目源码,可以点击这里:《论坛信息管理系统》

如果你喜欢这篇文章,请点赞加关注吧,或者如果你对与文章有什么困惑,可以私信我。

🏓🏓🏓


本文转载自: https://blog.csdn.net/m0_62218217/article/details/125810816
版权归原作者 爱干饭的猿 所有, 如有侵权,请联系我们删除。

“前端+后端项目 - 论坛信息管理系统(Web+servlet+MySQL+JDBC)”的评论:

还没有评论