基于Spring前后端分离版本的论坛

news2024/11/24 15:55:47

基于Spring前后端分离版本的论坛系统

  • PP论坛地址
  • 系统设计
    • 逻辑交互图
    • 数据库设计
    • 工程结构概述
    • 注册功能实现展示
      • 注册交互图
      • 参数要求
      • 接口规范
      • 后端具体实现
      • 前端数据集成
  • 接口拦截器实现
  • mybatis生成类与映射文件
  • 改造session存储到 redis
  • 加盐算法实现
  • 部分Bug调试记录
  • 项目测试记录
    • Postman 接口测试
    • Jmeter 接口压测
  • 项目配置问题记录

PP论坛地址

http://211.159.172.237:58080/sign-in.html

系统设计

在这里插入图片描述

  • PP论坛 项目基于B/S架构

B/S架构全称是浏览器/服务器(Browser/Server)结构,分为Web浏览器、服务器程序、数据库服务三部分,可以理解为是对C/S架构一种改进。
由于所有的业务逻辑都由服务器程序处理,所以客户端仅使用浏览器就可以完成所有操作,大大降低了客户端的维护成本。

在这里插入图片描述

逻辑交互图

在这里插入图片描述

数据库设计

create database forum_db character set utf8mb4 collate utf8mb4_general_ci;

--  选择数据库
use forum_db;

-- SET NAMES utf8mb4;
-- SET FOREIGN_KEY_CHECKS = 0;

--  创建用户表
drop table if exists t_user;
create table t_user (
	id bigint primary key auto_increment comment '编号,主键自增',
	username varchar(20) not null unique comment '用户名,唯一的',
	password varchar(32) not null comment '加密后的密码',
	nickname varchar(50) not null comment '昵称',
	phoneNum varchar(20) comment '手机号',
	email varchar (50) comment '电子邮箱',
	gender tinyint not null default 2 comment '性别:0女1男2保密',
	salt varchar(32) not null comment '密码加盐',
	avatarUrl varchar(255) comment '用户头像路径',
	articleCount int not null default 0 comment '发帖数量',
	isAdmin tinyint not null default 0 comment ' 管理员:0否1是',
	remark varchar(1000) comment '备注:自我介绍',
	state tinyint not null default 0 comment '状态:0正常1禁言',
	deleteState tinyint not null default 0 comment '是否删除:0否1是',
	createTime datetime not null comment '创建时间',
	updateTime datetime not null comment '更新时间'
	);

-- 创建板块表
drop table if exists t_board;
create table t_board (
	id bigint primary key auto_increment comment '编号,主键自增',
	name varchar(20) not null unique comment '板块名',
	articleCount int not null default 0 comment '帖子数量',
	sort int not null default 0 comment '升序排序',
	state tinyint not null default 0 comment '状态:0正常1禁言',
	deleteState tinyint not null default 0 comment '是否删除:0否1是',
	createTime datetime not null comment '创建时间',
	updateTime datetime not null comment '更新时间'
	);

-- 创建帖子表
drop table if exists t_article;
create table t_article (
	id bigint primary key auto_increment comment '编号,主键自增',
	boardId bigint not null comment '关联板块编号',
	userId bigint not null comment '关联用户编号',
	title varchar(100) not null comment '帖子标题',
	content text not null comment '帖子正文',
	visitCount int not null default 0 comment '访问量',
	likeCount int not null default 0 comment '点赞数',
	replyCount int not null default 0 comment '回复数',
	state tinyint not null default 0 comment '状态:0正常1禁言',
	deleteState tinyint not null default 0 comment '是否删除:0否1是',
	createTime datetime not null comment '创建时间',
	updateTime datetime not null comment '更新时间'
	);

-- 创建帖子回复表
drop table if exists t_article_reply;
create table t_article_reply (
	id bigint primary key auto_increment comment '编号,主键自增',
	articleId bigint not null comment '关联帖子编号',
	postUserId bigint not null comment '关联楼主用户编号',
	replyId bigint not null comment '关联回复编号,支持楼中楼',
	replyUserId bigint not null comment '楼下回复用户编号,支持楼中楼',
	content varchar(500) not null comment '回帖内容',
	likeCount int not null comment '回帖点赞数',
	state tinyint not null default 0 comment '状态:0正常1禁言',
	deleteState tinyint not null default 0 comment '是否删除:0否1是',
	createTime datetime not null comment '创建时间',
	updateTime datetime not null comment '更新时间'
	);


-- 创建私信表
drop table if exists t_message;
create table t_message (
	id bigint primary key auto_increment comment '编号,主键自增',
	postUserId bigint not null comment '发送者:关联用户编号',
	receiveUserId bigint not null comment '接收者:关联用户编号',
	content varchar(500) not null comment '私信内容',
	state tinyint not null default 0 comment '状态:0正常1禁言',
	deleteState tinyint not null default 0 comment '是否删除:0否1是',
	createTime datetime not null comment '创建时间',
	updateTime datetime not null comment '更新时间'
	);

工程结构概述

  • common:系统通用定义 (返回结果、状态码)
  • config : 系统配置层 (session、Mybatis扫描路径)
  • controller:接收用户请求 对参数做校验(调用service 返回执行结果)
  • dao:数据库交互(调用mapper中定义的sql语句)
  • exception : 异常处理 (自定义、全局)
  • Interceptor : 拦截器使用
  • model:实体对象 (根据数据库生成 )
  • services:处理业务逻辑 ,定义接口(处理事务若遇异常向外抛)
  • utill : 通用工具 (加密、非空校验)
  • mapper:定义SQL语句(查数据库)

注册功能实现展示

注册交互图

在这里插入图片描述

参数要求

  • 用户注册时需要提交的参数列表
    在这里插入图片描述

确认密码:在Controller层对密码和确认密码进行校验,不通过直接返回错误

接口规范

在这里插入图片描述

后端具体实现

  1. 定义SQL,按用户名查询用户信息
    在这里插入图片描述
  2. dao层中对应的类,添加SQL中定义的方法
    在这里插入图片描述
  3. 创建接口,以及接口的实现类
    在这里插入图片描述
  4. 进行service实现类中业务方法的编写
    在这里插入图片描述
    在这里插入图片描述
  5. 对所写的类进行单元测试
    在这里插入图片描述
  6. 编写Controller层
    在这里插入图片描述
  7. 接口测试
    在这里插入图片描述

前端数据集成

使用JQuery完成AJAX请求,并处理HTML页面标签

在这里插入图片描述

    // 构造数据
    let postData = {
      username : $('#username').val(),
      nickname : $('#nickname').val(),
      password : $('#password').val(),
      passwordRepeat : $('#passwordRepeat').val()
    };

    // 发送AJAX请求 
    // contentType = application/x-www-form-urlencoded
    // 成功后跳转到 sign-in.html
    $.ajax ({
      type : 'post',
      url  : 'user/register',
      contentType : 'application/x-www-form-urlencoded',
      data : postData,
      // 回调方法
      success: function(respData){
        // 判断返回的状态码
        if (respData.code == 0) {
          // 跳转到登录页面
          location.assign('/sign-in.html');
        } else {
          // 提示信息
          $.toast({
              heading: '警告',
              text: respData.message,
              icon: 'warning'
          });
        }
      }, 
      error : function() {
        // 提示信息
        $.toast({
              heading: '错误',
              text: '访问出现问题,请与管理员联系.',
              icon: 'error'
          });
      }
    });

在这里插入图片描述

接口拦截器实现

在这里插入图片描述

  • 在application.yml 中引入项目自定义相关配置
# 项目自定义相关配置
project-forum:
  login:
    url: /sign-in.html  # 未登录状况下强制跳转页面
  • 确定要拦截的目标
    在这里插入图片描述

mybatis生成类与映射文件

  1. 在pom.xml 中引入依赖
<mybatis-generator-plugin-version>1.4.1</mybatis-generator-plugin-version>
  • 引入mybatis生成器插件:
			<plugin>
				<groupId>org.mybatis.generator</groupId>
				<artifactId>mybatis-generator-maven-plugin</artifactId>
				<version>${mybatis-generator-plugin-version}</version>
				<executions>
				<execution>
				<id>Generate MyBatis Artifacts</id>
					<phase>deploy</phase>
					<goals>
						<goal>generate</goal>
					</goals>
				</execution>
				</executions>
				<!-- 相关配置 -->
				<configuration>
					<!-- 打开⽇志 -->
					<verbose>true</verbose>
					<!-- 允许覆盖 -->
					<overwrite>true</overwrite>
					<!-- 配置⽂件路径 -->
					<configurationFile>
						src/main/resources/mybatis/generatorConfig.xml
					</configurationFile>
				</configuration>
			</plugin>
  1. 配置文件(src/main/resources/mybatis/generatorConfig.xml)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <!-- 驱动包路径,location中路径替换成自己本地路径 -->
    <classPathEntry location="C:\Users\lenovo\.m2\repository\mysql\mysql-connector-java\5.1.49\mysql-connector-java-5.1.49.jar"/>

    <context id="DB2Tables" targetRuntime="MyBatis3">
        <!-- 禁用自动生成的注释 -->
        <commentGenerator>
            <property name="suppressAllComments" value="true"/>
            <property name="suppressDate" value="true"/>
        </commentGenerator>

        <!-- 连接配置 -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://127.0.0.1:3306/forum_db?characterEncoding=utf8&amp;useSSL=false"
                        userId="root"
                        password="123456">
        </jdbcConnection>

        <javaTypeResolver>
            <!-- 小数统一转为BigDecimal -->
            <property name="forceBigDecimals" value="false"/>
        </javaTypeResolver>

        <!-- 实体类生成位置 -->
        <javaModelGenerator targetPackage="com.project.forum.model" targetProject="src/main/java">
            <property name="enableSubPackages" value="true"/>
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>

        <!-- mapper.xml生成位置 -->
        <sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources">
            <property name="enableSubPackages" value="true"/>
        </sqlMapGenerator>

        <!-- DAO类生成位置 -->
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.project.forum.dao" targetProject="src/main/java">
            <property name="enableSubPackages" value="true"/>
        </javaClientGenerator>

        <!-- 配置生成表与实例, 只需要修改表名tableName, 与对应类名domainObjectName 即可-->
        <table tableName="t_article" domainObjectName="Article" enableSelectByExample="false"
               enableDeleteByExample="false" enableDeleteByPrimaryKey="false" enableCountByExample="false"
               enableUpdateByExample="false">
            <!-- 类的属性用数据库中的真实字段名做为属性名, 不指定这个属性会自动转换 _ 为驼峰命名规则-->
            <property name="useActualColumnNames" value="true"/>
        </table>
        <table tableName="t_article_reply" domainObjectName="ArticleReply" enableSelectByExample="false"
               enableDeleteByExample="false" enableDeleteByPrimaryKey="false" enableCountByExample="false"
               enableUpdateByExample="false">
            <property name="useActualColumnNames" value="true"/>
        </table>
        <table tableName="t_board" domainObjectName="Board" enableSelectByExample="false" enableDeleteByExample="false"
               enableDeleteByPrimaryKey="false" enableCountByExample="false" enableUpdateByExample="false">
            <property name="useActualColumnNames" value="true"/>
        </table>
        <table tableName="t_message" domainObjectName="Message" enableSelectByExample="false"
               enableDeleteByExample="false" enableDeleteByPrimaryKey="false" enableCountByExample="false"
               enableUpdateByExample="false">
            <property name="useActualColumnNames" value="true"/>
        </table>
        <table tableName="t_user" domainObjectName="User" enableSelectByExample="false" enableDeleteByExample="false"
               enableDeleteByPrimaryKey="false" enableCountByExample="false" enableUpdateByExample="false">
            <property name="useActualColumnNames" value="true"/>
        </table>

    </context>
</generatorConfiguration>
  1. 创建好对应包,设置好数据表
    在这里插入图片描述

  2. 在Insert 标签中添加获取主键值的选项
    在这里插入图片描述

  3. 在dao层每个类中加入@Mapper注解;在model层下加入@Data,删掉get、set方法

  4. 配置Mybatis的扫描路径
    在这里插入图片描述
    在这里插入图片描述

# mybatis 相关配置,单独配置,顶格写
mybatis:
  mapper-locations: classpath:mapper/**/*.xml # 指定 xxxMapper.xml的扫描路径

改造session存储到 redis

  • 在 pom . xml 添加依赖框架
<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.session</groupId>
			<artifactId>spring-session-data-redis</artifactId>
		</dependency>
  • 在 application.properties 中添加配置
# redis 配置
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=
spring.redis.database=2
spring.session.store-type=redis
# session 过期时间
server.servlet.session.timeout=1800
spring.session.redis.flush-mode=on_save
spring.session.redis.namespace=spring:session

加盐算法实现

在这里插入图片描述

/**
 * Description: 校验密码
 */
public class CheckUtil {
    public static boolean check(String password , String DBSalt ,String DBPassword) {
        String encryptPassword = MD5Util.md5Salt(password,DBSalt);
        if (!encryptPassword.equalsIgnoreCase(DBPassword)) {
            return false;
        }
        return true;

    }
}

/**
 * Description:密码加密方法
 */
public class MD5Util {

    public static String md5 (String str) {
        return DigestUtils.md5Hex(str);
    }

    public static String md5Salt (String str , String salt) {
        return md5(md5(str)+salt);
    }

}

/**
 * Description: 密码的 salt
 * 随机生成的uuid是36位(其中包含4个 “-”),去掉正好32位
 */
public class UUIDUtil {
    public static String UUID_36() {
        return UUID.randomUUID().toString();
    }

    public static String UUID_32() {
        return UUID.randomUUID().toString().replace("-","");
    }
}

部分Bug调试记录

  • 编写完后端的获取用户信息接口后,又完成了前端的ajax编写,在测试成功时发现前端并未展示出用户信息,首先我抓包确定后端返回了需要的数据。
  • 在这里插入图片描述
    在这里插入图片描述
  • 我认为是前端参数获取的问题,于是我调试起了前端代码,发现报错
    TypeError: Cannot read properties of undefined (reading 'avatarUrl')
    得出结果是:在尝试访问 respData.data 的属性之前,确定 respData.data 是否已经定义。
  • 于是我重新检查后端代码,发现定义的返回结果data写成了date,导致undefined 报错

在这里插入图片描述

  • 在修改了后端代码之后,数据正常显示出来
    在这里插入图片描述

项目测试记录

Postman 接口测试

在这里插入图片描述

Jmeter 接口压测

在这里插入图片描述

项目配置问题记录

  1. 解决SpringBoot3整合Druid的兼容性问题
  2. java.lang.ClassNotFoundException: org.h2.Driver
  3. Spring Boot 3 集成 MyBatis
  4. VM warning

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1983493.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

关于正点原子imx6ull-mini在写触摸驱动时,一直挂载不上驱动,就是没有一些信息反馈

/** 设备树匹配表 */ const struct of_device_id gt9147_of_match_table[] {{.compatible "goodix,gt9147" },{ /* sentinel */ } };const struct of_device_id gt9147_of_match_table[] {{.compatible "goodix&#xff0c;gt9147"},{} }; 找了俩小时…

高频面试题全攻略:从算法到解题技巧

干货分享&#xff0c;感谢您的阅读&#xff01; &#xff08;暂存篇---后续会删除&#xff0c;完整版和持续更新见高频面试题基本总结回顾&#xff08;含笔试高频算法整理&#xff09;&#xff09; 备注&#xff1a;引用请标注出处&#xff0c;同时存在的问题请在相关博客留言…

基于宝塔面板稳定快速安装 ssl 证书脚本

背景 我通过AI制作了不少关于签发ssl证书的脚本&#xff0c;目的是方便无脑安装&#xff0c;不需要懂代码。 但全都是基于acme.sh这个工具来设计的脚本&#xff0c;而且证书申请有点慢&#xff0c;有时还会申请失败。 然后我发现了certbot, 安装证书可谓神速&#xff01; c…

[米联客-安路飞龙DR1-FPSOC] UDP通信篇连载-04 IP层程序设计

软件版本&#xff1a;Anlogic -TD5.9.1-DR1_ES1.1 操作系统&#xff1a;WIN10 64bit 硬件平台&#xff1a;适用安路(Anlogic)FPGA 实验平台&#xff1a;米联客-MLK-L1-CZ06-DR1M90G开发板 板卡获取平台&#xff1a;https://milianke.tmall.com/ 登录“米联客”FPGA社区 ht…

全面解析PHP反序列化漏洞:原理、复现与防御

文章目录 概念序列化数据的含义魔术方法魔术方法的使用construct&#xff0c;destructtoStringcallgetsetsleepwakeupissetunsetinvoke 原生态反序列化漏洞概念种类复现 wakeup长度绕过产生原因条件复现 基本题型源码解读 在Web应用安全领域&#xff0c;PHP反序列化漏洞常常被视…

Tomcat 使用和配置文件(详解)

一.tomcat 介绍 1. tomcat 概述 自从JSP发布之后&#xff0c;推出了各式各样的JSP引擎。Apache Group在完成GNUJSP1.0的开发以后&#xff0c;开始考虑在SUN的JSWDK基础上开发一个可以直接提供Web服务的JSP服务器&#xff0c;当然同时也支持 Servlet&#xff0c;这样Tomcat就诞…

MySQL数据库误删恢复--超详细

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…

Tensorflow——第三讲神经网络八股

前两讲我们学习了使用tensorflow原生代码搭建神经网络&#xff0c;本讲主要学习使用Tensorflow API&#xff1a;tf.keras搭建神经网络 一、搭建网络八股Sequential 六步法&#xff1a; 1.import&#xff1a;import 相关模块&#xff0c;如 import tensorflow as tf 2.train…

2024年7月30日~2024年8月5日周报

一、前言 上周继续修改论文&#xff0c;并阅读了两篇论文。 本周主要修改论文、完成实验、参加一些组会与论文讨论会&#xff0c;并配置了torch环境。 二、完成情况 2.1 论文符号系统注意事项 数学符号应该有唯一性&#xff0c;不能与其他符号造成误解&#xff1b;W_{\mathr…

c++初阶-----适配器---priority_queue

作者前言 &#x1f382; ✨✨✨✨✨✨&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f382; ​&#x1f382; 作者介绍&#xff1a; &#x1f382;&#x1f382; &#x1f382; &#x1f389;&#x1f389;&#x1f389…

极狐GitLab CICD Catalog Beta 功能介绍

极狐GitLab 是 GitLab 在中国的发行版&#xff0c;专门面向中国程序员和企业提供企业级一体化 DevOps 平台&#xff0c;用来帮助用户实现需求管理、源代码托管、CI/CD、安全合规&#xff0c;而且所有的操作都是在一个平台上进行&#xff0c;省事省心省钱。可以一键安装极狐GitL…

【Python】数据类型之列表(下)

&#xff08;6&#xff09;清空列表 功能&#xff1a;clear() 代码示例&#xff1a; &#xff08;7&#xff09;根据值获取索引&#xff08;从左到右找到第一个返回索引&#xff09;【慎用&#xff0c;找不到报错】 功能&#xff1a;index(xyz)&#xff0c;xyz为数据类型。 …

OpenAI gym player mode

题意&#xff1a;OpenAI gym 的自定义模式 问题背景&#xff1a; Does anyone know how to run one of the OpenAI gym environments as a player. As in letting a human player play a round of cart pole? I have seen that there is env.mode human but I have not been…

波兰表达式求值

from operator import add, sub, muldef div(x, y):# 使用整数除法的向零取整方式return int(x / y) if x * y > 0 else -(abs(x) // abs(y))class Solution(object):op_map {: add, -: sub, *: mul, /: div}def evalRPN(self, tokens: List[str]) -> int:stack []for …

【C基础-按要求找数】一个整数,它加上100后是一个完全平方数,再加上168又是一个完全平方数,请问该数是多少

一个整数&#xff0c;它加上100后是一个完全平方数&#xff0c;再加上168又是一个完全平方数&#xff0c;请问该数是多少 完全平方数是指一个整数能够表示为某个整数的平方。换句话说&#xff0c;如果存在一个整数 n&#xff0c;使得 n^2m,那么 m 就是一个完全平方数。 使用C…

第二十一天培训笔记

上午 1 、环境准备 2 、安装 mysql 绿包 3 、配置 mysql 工作环境 mysql -hip 地址 -p3306 -uroot -p &#xff08;远程连接使用&#xff09; 4 、 mysql 基础命令 &#xff08; 1 &#xff09;修改密码 &#xff08; 2 &#xff09;授权远程登录 &#xff08; 3 &#x…

程序员短视频上瘾综合症

一、是你疯了还是面试官疯了&#xff1f; ​ 最近有两个学员咨询问题&#xff0c;把我给整得苦笑不得。大家来看看&#xff0c;你有没有同样的症状。 ​ 第一个学员说去一家公司面试&#xff0c;第一轮面试聊得挺好的。第二轮面试自我感觉良好&#xff0c;但是被面试官给Diss…

模型优化学习笔记—对比各种梯度下降算法

import mathimport numpy as np from opt_utils import * import matplotlib.pyplot as plt# 标准梯度下降 def update_parameters_with_gd(parameters, grads, learning_rate):L len(parameters) // 2for l in range(1, L 1):parameters[f"W{l}"] parameters[f&q…

【uniapp】聊天记录列表长按消息计算弹出菜单方向

1. 效果图 1.1 消息靠上接近导航栏&#xff0c;菜单显在消息体下方弹出&#xff0c;箭头向上 1.2 消息体没有贴近上方导航栏&#xff0c;菜单在消息体上方弹出&#xff0c;箭头向下 1.3 长消息&#xff0c;菜单在手指按下的位置弹出&#xff0c;无箭头 2. 代码实现 <view …

sqli 1- 10

sql靶场 第一关 首先我们需要判断是否存在sql注入点&#xff0c;前端界面提示我使用ID作为参数,在url地址栏输入?id1 通过输入不同的id值查询数据库相对应的内容&#xff0c;之后判断为数字型还是字符型 根据查询内容判断为字符型且有注入点&#xff0c;再通过联合查询&…