论坛项目知识回顾

目录

一. MySQL 建表

二. MyBatis

三. dao层

四. service层

五. controller层

六 component层

七. configuration层

八. utils 包

九. common 包

十. Exception

十一. interceptor包

十二. 代码有使用什么SpringBoot注解


一. MySQL 建表

首先使用 MySQL 进行表的创建, 有以下几个表:

t_user: 用户信息表, 用来存储用户的姓名, 密码,昵称,电话号码,邮件,个人简介

t_board: 板块表, 存储每个板块的名字, 板块中的文章数

 t_article: 帖子表, 存储帖子标题, 文章, 点击数, 评论数和喜欢数. 使用 userId 和 boardId 将帖子和发帖用户,板块关联起来

 t_article_reply: 评论表, 存储评论, 使用 articleId, replyId 将评论和帖子,评论用户联系起来

 t_message: 站内信表, 存储消息, 使用 postUserId 和 receivedUserId 将信息和发生用户,接受用户联系起来 

二. MyBatis

使用 MyBatis 和数据库建立联系

1. 创建 model 到, 按照数据库的表来创建类

2. 创建 mybatisConfig.xml, 将对应的依赖写入

3. 创建 mapper 目录, 按照固定格式, 写入 SQL 语句

4. 创建 dao 包, 里面装接口类, 类中写调用 SQL 的方法

mapper

常用标签: insert select update

标签属性:

id: dao 中对应的方法名

parameterType:   导入参数类型

resultMap: 返回参数类型

useGenerateKeys: 是否自己创建主键

keyProperty: 主键是谁(和useGenerateKeys一起用)

常用标签: trim if

标签属性:

prefix: 前面添加字符串

suffix: 后面添加字符串

prefixOverrides: 省略最前面对应字符

suffixOverrides: 省略最后面对应字符

test: test 的条件为 true 就将 if 中的字符串添加进 SQL 语句

常用标签: set

会自动删除最后一个,

三. dao层

public interface UserMapper {int insert(User row);int insertSelective(User row);User selectByPrimaryKey(Long id);int updateByPrimaryKeySelective(User row);int updateByPrimaryKey(User row);User selectByUserName (@Param("username") String username);
}
public interface BoardMapper {int insert(Board row);int insertSelective(Board row);Board selectByPrimaryKey(Long id);int updateByPrimaryKeySelective(Board row);int updateByPrimaryKey(Board row);List<Board> selectByNum (@Param("num") Integer num);
}
public interface ArticleMapper {int insert(Article row);int insertSelective(Article row);Article selectByPrimaryKey(Long id);int updateByPrimaryKeySelective(Article row);int updateByPrimaryKeyWithBLOBs(Article row);int updateByPrimaryKey(Article row);/*** 查询所有帖子列表* @return*/List<Article> selectAll ();List<Article> selectAllByBoardId(Long boardId);Article selectDetailById(Long articleId);List<Article> selectByUserId(Long userId);}
public interface ArticleReplyMapper {int insert(ArticleReply row);int insertSelective(ArticleReply row);ArticleReply selectByPrimaryKey(Long id);int updateByPrimaryKeySelective(ArticleReply row);int updateByPrimaryKey(ArticleReply row);List<ArticleReply> selectByArticleId(Long articleId);
}
public interface MessageMapper {int insert(Message row);int insertSelective(Message row);Message selectByPrimaryKey(Long id);int updateByPrimaryKeySelective(Message row);int updateByPrimaryKey(Message row);Integer selectUnreadCount(Long receiveUserId);List<Message> selectByReceiveUserId(Long id);
}

四. service层

service 层主要通过这些方法来和 dao层进行一个交互, 增删查改数据库中的数据

使用到的类:

用户板块文章评论消息
IUserServiceIBoardServiceIArticleServiceArticleReplyServiceIMessageService

UserService

创建用户按用户名查询登录按 ID 查询
createNormalUser
selectByUserName

 login

selectById
会进行 user 的非空校验, 然后查询该用户是否已经存在,  不存在则创建用户对用户名非空校验,  然后返回查询结果

对用户名和密码进行非空校验, 然后查询该用户是否存在, 存在则校验密码

对 id 进行非空校验, 根据 id 查询用户
增加用户发帖数减少用户发帖数修改个人信息修改密码
addOneArticleCountById
subOneArticleCountById
modifyInfo
modifyPassword
对 ID 进行非空校验, 根据 ID 查询用户, 然后将发帖数 +1, 更新用户 对 ID 进行非空校验, 根据 ID 查询用户, 将发帖数 -1, 更新用户user和ID非空校验, 定义一个标志位, 如果有修改信息标志位为 true, 否则为 false, 修改不通过对id, 老密码和新密码进行非空校验, 校验老密码, 比较新老密码是否相同, 进行修改

BoardService

拿到前num个板块增加一个板块帖子数通过id拿到板块减少一个板块帖子数
selectByNum
addOneArticleCountById
selectById
subOneArticleCountById
对 num 非空校验, 拿出前 num 个板块非空校验 id, 将 对应板块帖子数 +1, 修改数据库非空校验 id, 拿到对应板块非空校验 id, 减少对应板块一个帖子数, 修改数据库

ArticleService

发布帖子拿到全部帖子通过板块 id 拿到所有帖子
createselectAllselectAllByBoardId

非空校验article, userId, boardId, title, content.

将 article 写入数据库, 更新用户发帖数, 板块帖子数

拿到全部帖子非空校验 boardId, 校验板块是否存在, 拿到所有对应的帖子
访问帖子通过userId拿到所有帖子拿到帖子
selectDetailById
selectByUserId
selectById
非空校验id, 拿到帖子, 将帖子访问数 +1, 更新数据库, 返回帖子非空校验userId, 拿到该用户写的帖子, 返回所有帖子非空校验id, 通过帖子id拿到帖子, 返回帖子
修改帖子点赞帖子删除帖子增加一个评论数
modify
thumbsUpById
deleteById
addOneReplyCountById

非空校验id, title, content.

修改帖子

非空校验id, 将对应帖子点赞非空校验id, 删除对应帖子非空校验id, 将对应帖子评论数+1

ArticleReplyService

创建评论读取某文章的全部评论
create
selectByArticleId
非空校验评论, id.将 articleReply 写入数据库, 将帖子的回复数+1对 articleId 非空校验, 拿出所有 articleId 的评论

MessageService

构建一个消息通过id拿到消息没有被阅读的消息数
create
selectById
selectUnreadCount
非空校验消息本体, 发送用户id, 接收用户id, 查看接收用户是否存在, 将消息写入数据库非空校验id, 将对应消息拿出非空校验用户id, 返回没有被阅读数
通过接收用户id拿到消息更改消息状态回复消息
selectByReceiveUserId
updateStateById
reply
非空校验用户id, 返回所有接受的消息非空校验id、state, state 分为 0未读、1已读、2已回复

非空校验接受到的消息id、要发送消息, 如果接受到的消息为空, 则抛出异常.

不为空就发送消息, 将接收消息的状态改为 2已回复.

五. controller层

Controller层通过 http 来和客户端接受和发送请求, 然后调用 service层 的方法来对数据库进行增删查改

UserController

用户注册用户登录获取用户信息
registerlogingetUserInfo
客户端传来username, nickname, password, passwordRepeat. 校验密码和重复密码是否相同, 调用service层 createNormalUser客户端传来用户名和密码, 调用service层 login方法, 如果登录成功将 user 作为 session 设到 redis 中客户端传id, 非空校验id, 如果 id 为 null, 则从 session 中取出 user, 如果不为 null, 则返回 userId 的 user
退出登录修改个人信息修改密码
logoutmodifyInfomodifyPassword
如果 session 不为 null, 就销毁 session将客户端传来的不为 null 的数据对数据库进行修改, 调用 service 层的 modifyInfo 方法客户端传来原密码、新密码、确认密码, 校验新密码和确认密码是否相同, 调用 service层 modifyPassword 方法进行修改

BoardController

获取首页版块列表
通过 id 获取版块信息
topList
getById
调用 service 层 selectByNum, 将 前 num 个板块获取调用 service层的 selectById, 获取 id 对应的板块信息

ArticleController

发布新帖获取帖子列表根据帖子Id获取详情
create
getAllByBoardId
getDetails
客户端传来 boardId, title, content.  封装文章对象, 调用 service 层的 create 方法, 添加文章客户端传来 boardId, 如果为 null 则返回所有文章, 不为 null 则返回对应对应板块的索引文章客户端传来 id, 判断 id 是否为登录用户 id, 如果是将文章标记, 返回 id 对应文章
修改帖子
点赞
删除帖子
获取用户的帖子列表
modify
thumbsUp
deleteById
getAllByUserId
客户端传来 id, title, content. 根据 id 获取帖子, 校验是否为当前用户的帖子, 如果是调用 service 层 modify, 修改帖子客户端传来 id, 判定用户是否被禁言, 没有则调用 service层 thumbUpById, 点赞数+1客户端传来 id, 判断是否被禁言, 对应帖子是否被删除, 当前登录用户是否为作者, 都通过调用 service层 deleteById 删除帖子
客户端传来 userId, 传来 null则从 session 中获取 userId, 调用 service层 selectByUserId 获取所有该用户帖子

ArticleReplyController

评论
获取回复列表
ArticleReplyController
getRepliesByArticleId
客户端传来 id, content. 判定要回复帖子是否存在, 从 session 中拿到user, 构建评论, 调用 service层 create 方法, 返回结果客户端传来 articleId, 判断该文章是否存在, 调用 service层 selectByArticleId 获取该文章所有评论 

MessageController

发送站内信查询用户所有站内信
MessageController
getAll
客户端传来 receivedUserId, content. 从 session 拿到 postUser, 校验用户是否被禁言, 是不是给自己发站内信, receiver 是否存在, 封装 message, 调用 Messageservice的create方法将 message 写入数据库, 返回结果从 session 获取 user, 调用 meesageService 的 selectReceiverUserId 获取 该用户所有站内信, 返回站内信
更新为已读回复站内信
markRead
reply
客户端传来 id, 根据 id 获取站内信, 校验站内信是否存在, 站内信是不是自己的, 调用 messageService层的 updateStateById, 将站内信 state 改为 1, 返回结果客户端传来 repliedId, content.  校验当前登录用户状态, 要回复的站内信状态, 是否给自己回复, 构造 message 对象, 调用 messageService层 reply, 返回结果

六 component层

@Component
public class BinaryTool implements Serializable {public static byte[] toBinary(User user){ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();try (ObjectOutputStream outputStream = new ObjectOutputStream(byteArrayOutputStream)){outputStream.writeObject(user);} catch (IOException e) {e.printStackTrace();}return byteArrayOutputStream.toByteArray();}public static User fromBinary(byte[] data){User user = null;try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data)){try (ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream)){user = (User) objectInputStream.readObject();} catch (ClassNotFoundException e) {e.printStackTrace();}} catch (IOException e) {e.printStackTrace();}return user;}
}

使用 toBinary 对传进来的对象进行序列化, 返回序列化后的对象

使用 fromBinary 对传进来的二进制数据反序列化, 返回 Object 对象

使用这两个方法实现序列化和反序列化.

用处:

将 java 对象存储进 redis 中无法直接存储, 需要进行序列化后再存储.

需要从 redis 中拿取对象时, 再进行反序列化.

注: 被序列化的对象也要实现 Serializable 接口

七. configuration层

这里面放一些我们会使用到的字符串常量.

1. AppConfig

public class AppConfig {/*** 用户Session中的Key值*/public static final String USER_SESSION = "USER_SESSION";
}

用作 session 中的 Key 值

2. MyBatisConfig

@Configuration
// 具体的配置
@MapperScan("com.example.forum.dao")
public class MybatisConfig {}

配置 Mybatis 的扫描路径

八. utils 包

这里面是放一些我们要使用到的工具方法, 来完成某个特定的任务

UUIDUtil

public class UUIDUtil {/*** 生成一个标准的UUID** @return*/public static String UUID_36 () {return UUID.randomUUID().toString();}/*** 生成一个32位的UUID* @return*/public static String UUID_32 () {return UUID.randomUUID().toString().replace("-", "");}
}

第一个方法是生成一个标准的UUID, 36 位大小, 第二个方法是将 UUID 的 "-" 去掉变成 32 位.

MD5Util

public class MD5Util {/*** 对字符串进行MD5加密* @param str 明文* @return 密文*/public static String md5 (String str) {return DigestUtils.md5Hex(str);}/*** 对用户密码进行加密* @param str 密码明文* @param salt 扰动字符* @return 密文*/public static String md5Salt (String str, String salt) {return md5(md5(str) + salt);}
}

使用这个类来对对密码进行加密后再放进数据库, 这样能有效防止数据库泄漏后密码被知晓.

第一个方法是使用 DigestUtils 类的静态方法 md5Hex, 来对数据进行 md5 加密, 但这样的加密很容易被破解.

第二个方法时先将密码进行 md5 加密, 然后往密码后加上一个 salt, 再对整个字符串进行 md5 加密

salt 是由 UUIDUtil 的 UUID_32 生成.

九. common 包

这里面放我们要返回给前端的自定义状态码

采用枚举

public enum ResultCode {SUCCESS                     (0, "操作成功"),FAILED                      (1000, "操作失败"),FAILED_UNAUTHORIZED         (1001, "未授权"),FAILED_PARAMS_VALIDATE      (1002, "参数校验失败"),FAILED_FORBIDDEN            (1003, "禁止访问"),FAILED_CREATE               (1004, "新增失败"),FAILED_NOT_EXISTS           (1005, "资源不存在"),// 关于用户的错误描述FAILED_USER_EXISTS          (1101, "用户已存在"),FAILED_USER_NOT_EXISTS      (1102, "用户不存在"),FAILED_LOGIN                (1103, "用户名或密码错误"),FAILED_USER_BANNED          (1104, "您已被禁言, 请联系管理员, 并重新登录."),FAILED_USER_ARTICLE_COUNT   (1105, "更新帖子数量失败"),FAILED_TWO_PWD_NOT_SAME     (1106, "两次输入的密码不一致"),// 关于版块的错误描述FAILED_BOARD_ARTICLE_COUNT  (1201, "更新帖子数量失败"),FAILED_BOARD_BANNED         (1202, "版块状况异常"),FAILED_BOARD_NOT_EXISTS     (1203, "版块不存在"),FAILED_ARTICLE_NOT_EXISTS   (1301, "帖子不存在"),FAILED_ARTICLE_BANNED       (1302, "帖子状况异常"),FAILED_MESSAGE_NOT_EXISTS   (1401, "站内信不存在"),ERROR_SERVICES              (2000, "服务器内部错误"),ERROR_IS_NULL               (2001, "IS NULL.");// 状态码int code;// 描述信息String message;ResultCode(int code, String message){this.code = code;this.message = message;}@Overridepublic String toString() {return "code=" + code +", message='" + message + '.';}public int getCode() {return code;}public String getMessage() {return message;}
}

然后我们调用 AppResult 类来将数据返回给前端, 这里采用 Json 的格式返回

public class AppResult<T> {// 状态码@JsonInclude(JsonInclude.Include.ALWAYS) // 不论任何情况都参与JSON序列化private int code;// 描述信息@JsonInclude(JsonInclude.Include.ALWAYS)private String message;// 具体的数据@JsonInclude(JsonInclude.Include.ALWAYS)private T data;/*** 构造方法* @param code* @param message*/public AppResult(int code, String message) {this(code, message, null);}public AppResult(int code, String message, T data) {this.code = code;this.message = message;this.data = data;}/*** 成功* @return*/public static AppResult success () {return new AppResult(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage());}public static AppResult success (String message) {return new AppResult(ResultCode.SUCCESS.getCode(), message);}public static <T> AppResult<T> success (T data) {return new AppResult<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage(), data);}public static <T> AppResult<T> success (String message, T data) {return new AppResult<>(ResultCode.SUCCESS.getCode(), message, data);}/*** 失败* @return*/public static AppResult failed () {return new AppResult(ResultCode.FAILED.getCode(), ResultCode.FAILED.getMessage());}public static AppResult failed (String message) {return new AppResult(ResultCode.FAILED.getCode(), message);}public static AppResult failed (ResultCode resultCode) {return new AppResult(resultCode.getCode(), resultCode.getMessage());}public int getCode() {return code;}public void setCode(int code) {this.code = code;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}public T getData() {return data;}public void setData(T data) {this.data = data;}
}

十. Exception

自定义异常

public class ApplicationException extends RuntimeException{// 在异常中持有一个错误信息对象protected AppResult errorResult;public ApplicationException(AppResult errorResult) {super(errorResult.getMessage());this.errorResult = errorResult;}public ApplicationException(String message) {super(message);}public ApplicationException(String message, Throwable cause) {super(message, cause);}public ApplicationException(Throwable cause) {super(cause);}public AppResult getErrorResult() {return errorResult;}
}

十一. interceptor包

这里面用来实现拦截器

@Component
public class LoginInterceptor implements HandlerInterceptor {@Value("${bit-forum.login.url}")private String defaultURL;/*** 前置处理(对请求的预处理)* @return true : 继续流程 <br/> false : 流程中断* @throws Exception*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 获取session 对象HttpSession session = request.getSession(false);// 判断session是否有效if (session != null && session.getAttribute(AppConfig.USER_SESSION) != null) {// 用户为已登录状,校验通过return true;}// 校验URL是否正确if (!defaultURL.startsWith("/")) {defaultURL = "/" + defaultURL;}// 校验不通过, 跳转到登录页面response.sendRedirect(defaultURL);// 中断流程return false;}
}
@Configuration
public class AppInterceptorConfigure implements WebMvcConfigurer {// 注入自定义的登录拦截器@Resourceprivate LoginInterceptor loginInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 添加登录拦截器registry.addInterceptor(loginInterceptor)       // 添加用户登录拦截器.addPathPatterns("/**")                 // 拦截所有请求.excludePathPatterns("/sign-in.html")   // 排除登录HTML.excludePathPatterns("/sign-up.html")   // 排除注册HTML.excludePathPatterns("/user/login")     // 排除登录api接口.excludePathPatterns("/user/register")  // 排除注册api接口.excludePathPatterns("/user/logout")    // 排除退出api接口.excludePathPatterns("/swagger*/**")    // 排除登录swagger下所有.excludePathPatterns("/v3*/**")         // 排除登录v3下所有,与swagger相关.excludePathPatterns("/dist/**")        // 排除所有静态文件.excludePathPatterns("/image/**").excludePathPatterns("/js/**").excludePathPatterns("/**.ico");}
}

十二. 代码有使用什么SpringBoot注解

bean:

@Service @Controller @Component @Configuration @Resource

日志:

@Slf4j

访问路径:

@RestMapping @PostMapping @GetMapping

返回 Json:

@ResponseBody @RestController 

注: @RestController = @Controller + @ResponseBody

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【iptables 实战】06 iptables网络防火墙实验

一、现状说明 在上一节中&#xff0c;我们将两个网段的机器&#xff0c;通过中间机器的网络转发&#xff0c;能达到互通。再来回顾一下这个网络连接的图 这一节&#xff0c;我们将通过设置机器B的iptables规则&#xff0c;来做一些防火墙实验 机器A模拟公网的一台服务器&#…

【生命周期】

生命周期 1 引出生命周期2 分析生命周期3 总结生命周期 1 引出生命周期 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta …

微服务技术栈-认识微服务和第一个微服务Demo

文章目录 前言一、认识微服务二、微服务技术栈三、Eureka注册中心四、微服务DEMO1、搭建eureka-server2、服务注册和服务发现 总结 前言 随着业务的不断复杂&#xff0c;对服务的要求也越来越高&#xff0c;服务架构也从单体架构逐渐演变为现在流行的微服务架构。 本章就从微服…

【JVM】垃圾回收(GC)详解

垃圾回收&#xff08;GC&#xff09;详解 一. 死亡对象的判断算法1. 引用计数算法2. 可达性分析算法 二. 垃圾回收算法1. 标记-清除算法2. 复制算法3. 标记-整理算法4. 分代算法 三. STW1. 为什么要 STW2. 什么情况下 STW 四. 垃圾收集器1. CMS收集器&#xff08;老年代收集器&…

算法-动态规划/trie树-单词拆分

算法-动态规划/trie树-单词拆分 1 题目概述 1.1 题目出处 https://leetcode.cn/problems/word-break/description/?envTypestudy-plan-v2&envIdtop-interview-150 1.2 题目描述 2 动态规划 2.1 解题思路 dp[i]表示[0, i)字符串可否构建那么dp[i]可构建的条件是&…

【计算机网络黑皮书】应用层

【事先声明】 这是对于中科大的计算机网络的网课的学习笔记&#xff0c;感谢郑烇老师的无偿分享 书籍是《计算机网络&#xff08;自顶向下方法 第6版&#xff09;》 需要的可以私信我&#xff0c;无偿分享&#xff0c;课程简介下也有 课程连接 目录 应用层网络应用的原理应用架…

Linux使用之xshell、xftp保姆教学(含安装包,详细使用方法,连接失败解决方法)

前言 链接: FTP&#xff0c;SSH服务器介绍 这是我之前写的一篇博客&#xff0c;其中介绍了Ubuntu操作系统的一些常用命令以及服务器介绍&#xff0c;这篇文章就向大家详细介绍如何安装及应用这些服务器&#xff0c;我以xshell、xftp为例。 安装包&#xff0c;使用方法&#xf…

快速上手Apache POI

哈喽~大家好&#xff0c;这篇我们来看看快速上手Apache POI。 &#x1f947;个人主页&#xff1a;个人主页​​​​​ &#x1f948; 系列专栏&#xff1a;【日常学习上的分享】 &#x1f949;与这篇相关的文章&#xff1a; Red…

认识柔性数组

在C99中&#xff0c;结构中的最后一个元素允许是未知大小的数组&#xff0c;这就叫做柔性数组成员 限制条件是&#xff1a; 结构体中最后一个成员未知大小的数组 1.柔性数组的形式 那么我们怎样写一个柔性数组呢 typedef struct st_type {int i;int a[0];//柔性数组成员 }ty…

Moonbeam Ignite强势回归

参与Moonbeam上最新的流动性计划 还记得新一轮的流动性激励计划吗&#xff1f;Moonbeam Ignite社区活动带着超过300万枚GLMR奖励来啦&#xff01;体验新项目&#xff0c;顺便薅一把GLMR羊毛。 本次Moonbeam Ignite活动的参与项目均为第二批Moonbeam生态系统Grant资助提案中获…

北京开发APP需要多少钱

北京开发一个移动应用&#xff08;APP&#xff09;的费用因多种因素而异&#xff0c;包括项目的规模、复杂性、所需功能、设计要求、技术选择、开发团队的经验和地理位置等。一般来说&#xff0c;北京的APP开发费用通常较高&#xff0c;因为这是中国的主要技术和创新中心之一&a…

堆优化迪氏最短单源路径原理及C++实现

时间复杂度 O(ElogE)&#xff0c;E是边数。适用与稀疏图。 使用前提 边的权为正。可以非连通&#xff0c;非连通的距离为-1。 原理 优选队列&#xff08;小根堆&#xff09;记录两个数据&#xff1a;当前点到源点距离&#xff0c;当前点。先处理距离小的点&#xff1b;如果…