“智汇论坛“——基于 Spring 前后端分离版本的论坛系统

2024-08-26 10:28

本文主要是介绍“智汇论坛“——基于 Spring 前后端分离版本的论坛系统,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一.项目背景

1.项目简介

智汇论坛是一个集高科技与高效交流于一体的在线社区平台,旨在为用户提供一个便捷、智能的讨论空间。通过集成先进的服务器端技术和丰富的浏览器端技术,智汇论坛不仅支持用户之间的实时互动与信息共享,还确保了平台的高可用性和良好的用户体验。项目采用Spring Boot作为核心框架,结合Spring MVC和MyBatis实现快速开发与高效数据访问,同时利用HTML、CSS、JavaScript等前端技术打造响应式界面,提升用户交互的流畅性和视觉美感。

2.项目技术

服务器端技术

  • Spring
  • Spring Boot
  • Spring MVC
  • MyBatis

浏览器端技术

  • HTML, CSS, JavaScript
  • jQuery
  • Bootstrap

数据库

  • MySQL

项目构建工具

  • Maven

版本控制工具

  • Git + GITEE

二.环境搭建

1.项目创建

2.热部署

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency>

3.pom文件

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.14</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.javastudy</groupId><artifactId>forum</artifactId><version>0.0.1-SNAPSHOT</version><name>forum</name><description>forum</description><properties><java.version>1.8</java.version><mybatis-starter.version>2.3.0</mybatis-starter.version><druid-starter.version>1.2.16</druid-starter.version><mysql-connector.version>5.1.49</mysql-connector.version></properties><dependencies><!--        spring web--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--        mybatis--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>${mybatis-starter.version}</version></dependency><!--        热部署--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><!--        lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!--        spring boot test--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--   mysql连接--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql-connector.version}</version><scope>runtime</scope></dependency><!-- 阿里巴巴druid数据源,如果使用SpringBoot默认的数据源,删除或注释这个依赖即可 --><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>${druid-starter.version}</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build></project>

4.application.yml文件

#配置数据源
spring:application:name: "forum" # 项目名output:ansi:enabled: always # 控制台输出彩色日志datasource:url: jdbc:mysql://127.0.0.1:13306/forum_db?characterEncoding=utf8&useSSL=false    # 数据库连接串username: root # 数据库用户名字\password: woaini520 # 数据库密码driver-class-name: com.mysql.jdbc.Driver # 数据库连接驱动
# 服务器配置
server:port: 8082 # 指定端口号# mybatis 相关配置,单独配置,顶格写
mybatis:mapper-locations: classpath:mapper/**/*.xml # 指定 xxxMapper.xml的扫描路径configuration: # 配置打印 MyBatis 执行的 SQLlog-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 日志信息
logging:pattern:dateformat: yyyy-MM-dd HH:mm:ss # 日期格式file:path: logs/level:root: info

三.数据库设计

1.创建数据库
-- ----------------------------
-- 创建数据库,并指定字符集
-- ----------------------------
drop database if exists forum_db;
create database forum_db character set utf8mb4 collate utf8mb4_general_ci;

2.创建数据表

-- 选择数据库
use forum_db;set names utf8mb4;
set foreign_key_checks = 0;
(1)用户表
-- ----------------------------
-- 创建用户表 for t_user
-- ----------------------------
drop table if exists `t_user`;
create table `t_user`  (`id` bigint(20) not null auto_increment comment '用户编号,主键,自增',`username` varchar(20) character set utf8mb4 collate utf8mb4_general_ci not null comment '用户名,非空,唯一',`password` varchar(32) character set utf8mb4 collate utf8mb4_general_ci not null comment '加密后的密码',`nickname` varchar(50) character set utf8mb4 collate utf8mb4_general_ci not null comment '昵称,非空',`phonenum` varchar(20) character set utf8mb4 collate utf8mb4_general_ci null default null comment '手机号',`email` varchar(50) character set utf8mb4 collate utf8mb4_general_ci null default null comment '邮箱地址',`gender` tinyint(4) not null default 2 comment '0女 1男 2保密,非空,默认2',`salt` varchar(32) character set utf8mb4 collate utf8mb4_general_ci not null comment '为密码加盐,非空',`avatarurl` varchar(255) character set utf8mb4 collate utf8mb4_general_ci null default null comment '用户头像url,默认系统图片',`articlecount` int(11) not null default 0 comment '发帖数量,非空,默认0',`isadmin` tinyint(4) not null default 0 comment '是否管理员,0否 1是,默认0',`remark` varchar(1000) character set utf8mb4 collate utf8mb4_general_ci null default null comment '备注,自我介绍',`state` tinyint(4) not null default 0 comment '状态 0 正常,1 禁言,默认0',`deletestate` tinyint(4) not null default 0 comment '是否删除 0否 1是,默认0',`createtime` datetime not null comment '创建时间,精确到秒',`updatetime` datetime not null comment '更新时间,精确到秒',primary key (`id`) using btree,unique index `user_username_uindex`(`username`) using btree
) engine = innodb auto_increment = 2 character set = utf8mb4 collate = utf8mb4_general_ci comment = '用户表' row_format = dynamic;set foreign_key_checks = 1;
(2) 文章表
-- ----------------------------
-- 创建帖子表 t_article
-- ----------------------------
drop table if exists `t_article`;
create table `t_article`  (`id` bigint(20) not null auto_increment comment '帖子编号,主键,自增',`boardid` bigint(20) not null comment '关联板块编号,非空',`userid` bigint(20) not null comment '发帖人,非空,关联用户编号',`title` varchar(100) character set utf8mb4 collate utf8mb4_general_ci not null comment '标题,非空,最大长度100个字符',`content` text character set utf8mb4 collate utf8mb4_general_ci not null comment '帖子正文,非空',`visitcount` int(11) not null default 0 comment '访问量,默认0',`replycount` int(11) not null default 0 comment '回复数据,默认0',`likecount` int(11) not null default 0 comment '点赞数,默认0',`state` tinyint(4) not null default 0 comment '状态 0正常 1 禁用,默认0',`deletestate` tinyint(4) not null default 0 comment '是否删除 0 否 1 是,默认0',`createtime` datetime not null comment '创建时间,精确到秒,非空',`updatetime` datetime not null comment '修改时间,精确到秒,非空',primary key (`id`) using btree
) engine = innodb auto_increment = 1 character set = utf8mb4 collate = utf8mb4_general_ci comment = '帖子表' row_format = dynamic;
(3)文章回复表
-- ----------------------------
-- 创建帖子回复表 t_article_reply
-- ----------------------------
drop table if exists `t_article_reply`;
create table `t_article_reply`  (`id` bigint(20) not null auto_increment comment '编号,主键,自增',`articleid` bigint(20) not null comment '关联帖子编号,非空',`postuserid` bigint(20) not null comment '楼主用户,关联用户编号,非空',`replyid` bigint(20) null default null comment '关联回复编号,支持楼中楼',`replyuserid` bigint(20) null default null comment '楼主下的回复用户编号,支持楼中楼',`content` varchar(500) character set utf8mb4 collate utf8mb4_general_ci not null comment '回贴内容,长度500个字符,非空',`likecount` int(11) not null default 0 comment '点赞数,默认0',`state` tinyint(4) not null default 0 comment '状态 0 正常,1禁用,默认0',`deletestate` tinyint(4) not null default 0 comment '是否删除 0否 1是,默认0',`createtime` datetime not null comment '创建时间,精确到秒,非空',`updatetime` datetime not null comment '更新时间,精确到秒,非空',primary key (`id`) using btree
) engine = innodb auto_increment = 1 character set = utf8mb4 collate = utf8mb4_general_ci comment = '帖子回复表' row_format = dynamic;
(4)版块表
-- ----------------------------
-- 创建版块表 t_board
-- ----------------------------
drop table if exists `t_board`;
create table `t_board`  (`id` bigint(20) not null auto_increment comment '版块编号,主键,自增',`name` varchar(50) character set utf8mb4 collate utf8mb4_general_ci not null comment '版块名,非空',`articlecount` int(11) not null default 0 comment '帖子数量,默认0',`sort` int(11) not null default 0 comment '排序优先级,升序,默认0,',`state` tinyint(4) not null default 0 comment '状态,0 正常,1禁用,默认0',`deletestate` tinyint(4) not null default 0 comment '是否删除 0否,1是,默认0',`createtime` datetime not null comment '创建时间,精确到秒,非空',`updatetime` datetime not null comment '更新时间,精确到秒,非空',primary key (`id`) using btree
) engine = innodb auto_increment = 1 character set = utf8mb4 collate = utf8mb4_general_ci comment = '版块表' row_format = dynamic;
(5)站内信表
-- ----------------------------
-- 创建站内信表 for t_message
-- ----------------------------
drop table if exists `t_message`;
create table `t_message`  (`id` bigint(20) not null auto_increment comment '站内信编号,主键,自增',`postuserid` bigint(20) not null comment '发送者,并联用户编号',`receiveuserid` bigint(20) not null comment '接收者,并联用户编号',`content` varchar(255) character set utf8mb4 collate utf8mb4_general_ci not null comment '内容,非空,长度255个字符',`state` tinyint(4) not null default 0 comment '状态 0未读 1已读,默认0',`deletestate` tinyint(4) not null default 0 comment '是否删除 0否,1是,默认0',`createtime` datetime not null comment '创建时间,精确到秒,非空',`updatetime` datetime not null comment '更新时间,精确到秒,非空',primary key (`id`) using btree
) engine = innodb auto_increment = 1 character set = utf8mb4 collate = utf8mb4_general_ci comment = '站内信表' row_format = dynamic;

 四.工程配置

1.生成类的映射文件

版本统一管理 

        <mybatis-generator-plugin-version>1.4.1</mybatis-generator-plugin-version>

 在 build --> plugins 标签中加入如下配置 

    <build><plugins><!-- 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></plugins></build>

generatorConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfigurationPUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN""http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"><generatorConfiguration><!-- 驱动包路径,location中路径替换成自己本地路径 --><classPathEntry location="D:\java cave\Maven\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:13306/forum_db?characterEncoding=utf8&amp;useSSL=false"userId="root"password="woaini520"></jdbcConnection><javaTypeResolver><!-- 小数统一转为BigDecimal --><property name="forceBigDecimals" value="false"/></javaTypeResolver><!-- 实体类生成位置 --><javaModelGenerator targetPackage="com.javastudy.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.javastudy.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>

2.配置扫描配置

@Configuration
//指定mybatis的扫描路径
@MapperScan("com.javastudy.forum.dao")
public class MybatisConfig {
}

3.测试

输入一数据

    INSERT INTO `forum_db`.`t_user` (`id`, `username`, `password`, `nickname`,`gender`, `salt`, `avatarurl`, `articlecount`, `isadmin`, `state`,`deletestate`, `createtime`, `updatetime`) VALUES (1, 'joyboy', '123456', '路飞', 2, '123', 'avatar.png',0, 1, 0, 0, '2022-12-13 22:30:10', '2022-12-13 22:30:13');

 测试代码

@SpringBootTest
@Slf4j
class UserMapperTest {@ResourceUserMapper userMapper;@ResourceObjectMapper objectMapper;@Testvoid insert() {}@Testvoid insertSelective() {}@Testvoid selectByPrimaryKey() throws JsonProcessingException {User user = userMapper.selectByPrimaryKey(1L);log.info(objectMapper.writeValueAsString(user));}@Testvoid updateByPrimaryKeySelective() {}@Testvoid updateByPrimaryKey() {}
}

 五.编写代码

1.公共代码

(1)定义状态码

(2)Swagger自动生成

引入版本号

<springfox-boot-starter.version>3.0.0</springfox-boot-starter.version>

引入相关依赖

        <!-- API⽂档⽣成,基于swagger2 --><dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter</artifactId><version>${springfox-boot-starter.version}</version></dependency><!-- SpringBoot健康监控 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency>

编写配置类

package com.javastudy.forum.config;import org.springframework.boot.actuate.autoconfigure.endpoint.web.CorsEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;
import org.springframework.boot.actuate.endpoint.ExposableEndpoint;
import org.springframework.boot.actuate.endpoint.web.*;
import org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointsSupplier;
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier;
import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;import java.util.ArrayList;
import java.util.Collection;
import java.util.List;/*** @author Chooker* @create 2023-08-09 12:45*/
// 配置类
@Configuration
// 开启Springfox-Swagger
@EnableOpenApi
public class SwaggerConfig {/*** Springfox-Swagger基本配置** @return*/@Beanpublic Docket createApi() {Docket docket = new Docket(DocumentationType.OAS_30).apiInfo(apiInfo()).select().apis(RequestHandlerSelectors.basePackage("com.javastudy.forum.controller")).paths(PathSelectors.any()).build();return docket;}// 配置API基本信息private ApiInfo apiInfo() {ApiInfo apiInfo = new ApiInfoBuilder().title("论坛系统API").description("论坛系统前后端分离API测试").contact(new Contact("Chooker", "https://blog.csdn.net/qq_64580912", "ak1474502128@gmail.com")).version("1.0").build();return apiInfo;}/*** 解决SpringBoot 6.0以上与Swagger 3.0.0 不兼容的问题* 复制即可**/@Beanpublic WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(WebEndpointsSupplier webEndpointsSupplier,ServletEndpointsSupplier servletEndpointsSupplier,ControllerEndpointsSupplier controllerEndpointsSupplier,EndpointMediaTypes endpointMediaTypes, CorsEndpointProperties corsProperties,WebEndpointProperties webEndpointProperties, Environment environment) {List<ExposableEndpoint<?>> allEndpoints = new ArrayList();Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();allEndpoints.addAll(webEndpoints);allEndpoints.addAll(servletEndpointsSupplier.getEndpoints());allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints());String basePath = webEndpointProperties.getBasePath();EndpointMapping endpointMapping = new EndpointMapping(basePath);boolean shouldRegisterLinksMapping = this.shouldRegisterLinksMapping(webEndpointProperties, environment,basePath);return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, endpointMediaTypes,corsProperties.toCorsConfiguration(), new EndpointLinksResolver(allEndpoints, basePath),shouldRegisterLinksMapping, null);}private boolean shouldRegisterLinksMapping(WebEndpointProperties webEndpointProperties, Environment environment,String basePath) {return webEndpointProperties.getDiscovery().isEnabled() && (StringUtils.hasText(basePath)|| ManagementPortType.get(environment).equals(ManagementPortType.DIFFERENT));}
}

application.yml 中添加配置 

spring:  mvc:pathmatch:matching-strategy: ANT_PATH_MATCHER #Springfox-Swagger兼容性配置

具体API

API常用注解

@Api: 作用在Controller上,对控制器类的说明
     tags="说明该类的作用,可以在前台界面上看到的注解
@ApiModel: 作用在响应的类上,对返回响应数据的说明
@ApiModelProerty:作用在类的属性上,对属性的说明
@ApiOperation: 作用在具体方法上,对API接口的说明
@ApiParam: 作用在方法中的每⼀个参数上,对参数的属性进行说明 

六.具体功能实现

1.注册功能实现

(1)在Mapper.xml中编写SQL语句

写入操作

  <insert id="insertSelective" parameterType="com.javastudy.forum.model.User">insert into t_user<trim prefix="(" suffix=")" suffixOverrides=","><if test="id != null">id,</if><if test="username != null">username,</if><if test="password != null">password,</if><if test="nickname != null">nickname,</if><if test="phonenum != null">phonenum,</if><if test="email != null">email,</if><if test="gender != null">gender,</if><if test="salt != null">salt,</if><if test="avatarurl != null">avatarurl,</if><if test="articlecount != null">articlecount,</if><if test="isadmin != null">isadmin,</if><if test="remark != null">remark,</if><if test="state != null">state,</if><if test="deletestate != null">deletestate,</if><if test="createtime != null">createtime,</if><if test="updatetime != null">updatetime,</if></trim><trim prefix="values (" suffix=")" suffixOverrides=","><if test="id != null">#{id,jdbcType=BIGINT},</if><if test="username != null">#{username,jdbcType=VARCHAR},</if><if test="password != null">#{password,jdbcType=VARCHAR},</if><if test="nickname != null">#{nickname,jdbcType=VARCHAR},</if><if test="phonenum != null">#{phonenum,jdbcType=VARCHAR},</if><if test="email != null">#{email,jdbcType=VARCHAR},</if><if test="gender != null">#{gender,jdbcType=TINYINT},</if><if test="salt != null">#{salt,jdbcType=VARCHAR},</if><if test="avatarurl != null">#{avatarurl,jdbcType=VARCHAR},</if><if test="articlecount != null">#{articlecount,jdbcType=INTEGER},</if><if test="isadmin != null">#{isadmin,jdbcType=TINYINT},</if><if test="remark != null">#{remark,jdbcType=VARCHAR},</if><if test="state != null">#{state,jdbcType=TINYINT},</if><if test="deletestate != null">#{deletestate,jdbcType=TINYINT},</if><if test="createtime != null">#{createtime,jdbcType=TIMESTAMP},</if><if test="updatetime != null">#{updatetime,jdbcType=TIMESTAMP},</if></trim></insert>

根据用户名查询用户信息

创建如图的目录结构,并在extension目录下创建UserExtMapper.xml文件,里面编写自动生成以外的代码. 

可以看出 UserExtMapper.xml与UserMapper.xml是共用resultMap和Base_Column_List的

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.javastudy.forum.dao.UserMapper"><!--1. 注意namespace表示命名空间,要与 UserMapper.xml中的namespace相同2. 统一用com.javastudy.forum.dao.UserMapper, 也就是UserMapper的完全限定名(包名+类名)3. 不同的映射文件指定了相同的namespace后,定义的所有用id或name标识的结果集映射都可以在不同的文件中共享
--><!--    根据用户名查询用户信息--><select id="selectByUsername" parameterType="java.lang.String" resultMap="BaseResultMap">select<include refid="Base_Column_List" />from t_user where username=#{username,jdbcType=VARCHAR};</select></mapper>
(2)在Mapper.java中定义方法
@Mapper
public interface UserMapper {int insert(User row);int insertSelective(User row);User selectByPrimaryKey(Long id);int updateByPrimaryKeySelective(User row);int updateByPrimaryKey(User row);/*** 根据用户名查询用户信息* @param username* @return*/User selectByUsername(String username);
}
 (3)定义Service接口
public interface IUserService {User selectByUsername(String username);int createNormalUser(User user);
}
(4)实现Serivce接口
@Slf4j //日志
@Service
public class UserServiceImpl implements IUserService {@ResourceUserMapper userMapper;@Overridepublic User selectByUsername(String username) {//非空校验if (StringUtils.isEmpty(username)) {//打印日志log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());//抛出异常throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));}//根据用户名查询用户信息User user = userMapper.selectByUsername(username);return user;}@Overridepublic int createNormalUser(User user) {//非空校验if (user == null || StringUtils.isEmpty(user.getUsername()) || StringUtils.isEmpty(user.getNickname()) ||StringUtils.isEmpty(user.getPassword()) || StringUtils.isEmpty(user.getSalt())) {//打印日志log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());//抛出异常throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));}//校验用户名是否存在User exitsUser = userMapper.selectByUsername(user.getUsername());if (exitsUser != null) {//打印日志log.warn(ResultCode.FAILED_USER_EXISTS.toString());//抛出异常throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_EXISTS));}//为性別设置默认值if (user.getGender() != null) {if (user.getGender() < 0 || user.getGender() > 2) {user.setGender((byte) 2);}} else {user.setGender((byte) 2);}//为发帖数设置默认值user.setArticlecount(0);//设置是否管理员user.setIsadmin((byte) 0);//设置状态user.setState((byte) 0);//设置是否删除user.setDeletestate((byte) 0);//设置时间Date date = new Date();user.setCreatetime(date);user.setUpdatetime(date);//写入数据库int row = userMapper.insertSelective(user);if (row != 1) {//打印日志log.warn(ResultCode.FAILED_CREATE.toString() + "  注册用户失败,username:" + user.getUsername());//抛出异常throw new ApplicationException(AppResult.failed(ResultCode.FAILED_CREATE));}return row;}
}
(5)单元测试

(6)Controller实现方法外提供API接口
@RestController
@Slf4j
@RequestMapping("/user")
@Api(tags = "用户接口")
public class UserController {@ResourceIUserService userService;@ApiOperation("用户注册")@PostMapping("/register")public AppResult register(@ApiParam("用户名") @RequestParam("username") @NonNull String username,@ApiParam("昵称") @RequestParam("nickname") @NonNull String nickname,@ApiParam("密码") @RequestParam("password") @NonNull String password,@ApiParam("确定密码") @RequestParam("passwordRepeat") @NonNull String passwordRepeat) {if (!password.equals(passwordRepeat)) {return AppResult.failed(ResultCode.FAILED_TWO_PWD_NOT_SAME);}User user = new User();user.setUsername(username);user.setNickname(nickname);//对密码进行处理String salt = UUIDUtils.UUID_32();password = MD5Utils.md5Salt(password, salt);user.setPassword(password);user.setSalt(salt);userService.createNormalUser(user);return AppResult.success("注册成功");}}
(7)测试API接口

(8)实现前端逻辑,完成前后端交互
      // 构造数据var 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'});}},//http请求的失败error: function () {$.toast({heading: '错误',text: '访问出现问题,请联系管理员',icon: 'error'});}});});

2.登录功能实现

与上述功能类似,这里不再演示

3.退出功能实现

退出功能直接在session中删除用户信息即可,因此不需要前面的五步

4.获取用户信息实现

(1)Controller实现方法外提供API接口
    @ApiOperation("获取用户信息")@GetMapping("/info")public AppResult<User> getInfo(HttpServletRequest httpServletRequest) {//获取Session对象HttpSession session = httpServletRequest.getSession(false);if (session == null || session.getAttribute(AppConfig.SESSION_USER_KEY) == null) {return AppResult.failed("用户未登录");}User user = (User) session.getAttribute(AppConfig.SESSION_USER_KEY);return AppResult.success(user);}
(2)测试API接口

 此时我们进行测试可以得到以上的数据,但是此时还是有一定的弊端的

  • 密码和盐不能在网络上进行传输,会有安全隐患
  • 有些为空的数据没有必要传输
  • 日期信息的传输格式不是常规的

接下来一一来解决以上的问题.

1. 解决密码和盐传输的问题

在实体类属性上面加入@JsonIgnore注解 

    @ApiModelProperty("密码")@JsonIgnoreprivate String password;@ApiModelProperty("性别")private Byte gender;@ApiModelProperty("盐")@JsonIgnoreprivate String salt;@ApiModelProperty("删除状态")@JsonIgnoreprivate Byte deletestate;
2.解决空数据传输的问题和解决日期格式的问题
  # JSON序列化配置jackson:date-format: yyyy-MM-dd HH:mm:ss # 日期格式default-property-inclusion: NON_NULL # 不为null时序列化

登录的时候,发现data信息不见了,因为data信息为null,所以没有进行序列化,但是实际上code,message,data信息就算是null也是要进行传输的.

加入以下注解可以解决这个问题.

    @ApiModelProperty("状态码")@JsonInclude(JsonInclude.Include.ALWAYS) // 任何情况下都参与JSON序列化private Long code;@ApiModelProperty("错误信息")@JsonInclude(JsonInclude.Include.ALWAYS) // 任何情况下都参与JSON序列化private String message;@ApiModelProperty("返回的数据")@JsonInclude(JsonInclude.Include.ALWAYS) // 任何情况下都参与JSON序列化private T data;

头像同样也是需要的

    @ApiModelProperty("头像地址")@JsonInclude(JsonInclude.Include.ALWAYS)private String avatarurl;

5.拦截器的实现

论坛中的大部分接口都需要在登录的情况下进行访问,因此我们需要一个拦截器对访问页面的时候对未登录进行校验

6.获取用户信息实现2 

当我们进入一个帖子的时候,我们点击发帖的用户,可以看到用户的信息,此时前端给我们一个id,我们需要从数据库中根据id插叙到用户的信息.

7.获取版块信息实现

先向数据库中插入一些板块的信息.

-- 写入版块信息数据
INSERT INTO `t_board` (`id`, `name`, `articleCount`, `sort`, `state`, `deleteState`, `createTime`, `updateTime`) VALUES (1, 'Java', 0, 1, 0, 0, '2023-01-14 19:02:18', '2023-01-14 19:02:18');
INSERT INTO `t_board` (`id`, `name`, `articleCount`, `sort`, `state`, `deleteState`, `createTime`, `updateTime`) VALUES (2, 'C++', 0, 2, 0, 0, '2023-01-14 19:02:41', '2023-01-14 19:02:41');
INSERT INTO `t_board` (`id`, `name`, `articleCount`, `sort`, `state`, `deleteState`, `createTime`, `updateTime`) VALUES (3, '前端技术', 0, 3, 0, 0, '2023-01-14 19:02:52', '2023-01-14 19:02:52');
INSERT INTO `t_board` (`id`, `name`, `articleCount`, `sort`, `state`, `deleteState`, `createTime`, `updateTime`) VALUES (4, 'MySQL', 0, 4, 0, 0, '2023-01-14 19:03:02', '2023-01-14 19:03:02');
INSERT INTO `t_board` (`id`, `name`, `articleCount`, `sort`, `state`, `deleteState`, `createTime`, `updateTime`) VALUES (5, '面试宝典', 0, 5, 0, 0, '2023-01-14 19:03:24', '2023-01-14 19:03:24');
INSERT INTO `t_board` (`id`, `name`, `articleCount`, `sort`, `state`, `deleteState`, `createTime`, `updateTime`) VALUES (6, '经验分享', 0, 6, 0, 0, '2023-01-14 19:03:48', '2023-01-14 19:03:48');
INSERT INTO `t_board` (`id`, `name`, `articleCount`, `sort`, `state`, `deleteState`, `createTime`, `updateTime`) VALUES (7, '招聘信息', 0, 7, 0, 0, '2023-01-25 21:25:33', '2023-01-25 21:25:33');
INSERT INTO `t_board` (`id`, `name`, `articleCount`, `sort`, `state`, `deleteState`, `createTime`, `updateTime`) VALUES (8, '福利待遇', 0, 8, 0, 0, '2023-01-25 21:25:58', '2023-01-25 21:25:58');
INSERT INTO `t_board` (`id`, `name`, `articleCount`, `sort`, `state`, `deleteState`, `createTime`, `updateTime`) VALUES (9, '灌水区', 0, 9, 0, 0, '2023-01-25 21:26:12', '2023-01-25 21:26:12');

8.获得帖子信息实现

9.获得指定帖子信息实现  

10.根据Id获取板块信息

11.发布新帖操作

发布帖子涉及到的是文章表(article),其次需要更新用户的文章数,涉及用户表(user),最后需要更新板块的帖子数,涉及到板块表(board),并且这三个操作要么都成功,要么都失败,因此我们需要给这三个操作加上事务.

12.获取文章详情

获取文章详情的时候也需要获取相关用户的信息,板块的信息

13.文章访问数量的增加

14..编辑文章

在编辑文章之前,我们需要在文章中增加一个属性,来表示这篇文章是不是属于作者的,前端进行判断来选择展示修改和删除文章的按钮

15.删除文章

删除文章的时候需要做以下三个操作

1.需要将删除文章的deleteState置为1(article表)

2.需要将相应板块的文章数减一(board表)

3.需要将相应用户的文章数减一(user表)

16.点赞文章

17.根据文章Id查询回复列表

进行插入数据

-- 写入回复表数据
INSERT INTO t_article_reply VALUES (NULL, 1, 1, NULL, NULL, '回复内容111', 0, 0, 0, '2023-08-14 16:52:00', '2023-08-14 16:52:00');
INSERT INTO t_article_reply VALUES (NULL, 1, 1, NULL, NULL, '回复内容222', 0, 0, 0, '2023-08-14 16:53:00', '2023-08-14 16:53:00');
INSERT INTO t_article_reply VALUES (NULL, 1, 1, NULL, NULL, '回复内容333', 0, 0, 0, '2023-08-14 16:54:00', '2023-08-14 16:54:00');
INSERT INTO t_article_reply VALUES (NULL, 1, 2, NULL, NULL, '回复内容444', 0, 0, 0, '2023-08-14 16:55:00', '2023-08-14 16:55:00');
INSERT INTO t_article_reply VALUES (NULL, 1, 2, NULL, NULL, '回复内容555', 0, 0, 0, '2023-08-14 16:56:00', '2023-08-14 16:56:00');

18.回复文章

回复文章需要进行如下两个操作

1.插入一个回复(ArticleReply表)

2.增加文章的回复数(Article表)

因为涉及到多次更新的操作,因此也需要事务操作

19.用户个人信息和文章展示

已经有根据id获取用户信息的方法,现在我们只需要根据userId获取所有文章信息的接口即可

20.修改用户信息

修改用户信息,首先需要获取用户的信息,前面的接口已经实现,我们只需要在前端根据接口获取信息展示到页面上即可

21.修改密码

22.站内信功能

这个功能涉及到的是message表

23.查看未读数

24.获取消息列表 

在获取消息的时候,我们也需要发送者的用户信息,因此在message实体类中加上一个属性

25.站内信已读状态更新

26.站内信回复功能 

七.项目的部署与发布

1.部署linux服务器 

1.创建数据库

可以将sql语句变成一个文件,然后执行下面的代码

source /root/java78/table.sql
2.打包代码

打包完成之后,将jar包拖拽到linux服务器上

3.运行代码 

 后台启动项目

nohup java -jar Blog_Spring-0.0.1-SNAPSHOT.jar &

 

 查看日志

cd logs/tail -f spring.log

终止当前的服务

ps -ef | grep [ ] kill -9 pid

注意:如果开启多个服务,需要开端口,给防火墙添加端口号

查看防火墙状态(如果没开启,建议开启,不开启可以直接访问,开启了需要进行已下的操作访问)

systemctl status firewalld

 启动防火墙和关闭防火墙

systemctl start firewalldsystemctl stop firewalld

查看开放的端口号

firewall-cmd --list-ports

开启8080端口

firewall-cmd --permanent --add-port=8080/tcp

重启防火墙

firewall-cmd --reload

设置开机启动

systemctl enable firewalld

添加安全组

2.访问测试

八.项目描述

  1. 使用统一返回格式+全局错误信息定义处理前后端交互时的返回结果
  2. 使用@ControllerAdvice+@ExceptionHandler实现全局异常处理
  3. 使用拦截器实现用户登录校验
  4. 使用MybatisGeneratorConfig生成常的增删改查方法
  5. 集成Swagger实现自动生成API测试接口
  6. 使用jQuery完成AJAX请求,并处理HTML页面标签
  7. 对数据库中常用的查询字段建立索引,并使用查询计划分析索引是否生效

九.代码获取

代码链接:智汇论坛

这篇关于“智汇论坛“——基于 Spring 前后端分离版本的论坛系统的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1108297

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

基于人工智能的图像分类系统

目录 引言项目背景环境准备 硬件要求软件安装与配置系统设计 系统架构关键技术代码示例 数据预处理模型训练模型预测应用场景结论 1. 引言 图像分类是计算机视觉中的一个重要任务,目标是自动识别图像中的对象类别。通过卷积神经网络(CNN)等深度学习技术,我们可以构建高效的图像分类系统,广泛应用于自动驾驶、医疗影像诊断、监控分析等领域。本文将介绍如何构建一个基于人工智能的图像分类系统,包括环境

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,