论坛项目知识回顾

目录

一. 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;
    }

    @Override
    public 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
     */
    @Override
    public 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 {

    // 注入自定义的登录拦截器
    @Resource
    private LoginInterceptor loginInterceptor;

    @Override
    public 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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值