论坛系统(4)

news2025/6/4 2:05:01

用户详情

获取用户信息

实现逻辑

⽤⼾提交请求,服务器根据是否传⼊Id参数决定返回哪个⽤⼾的详情

1. 不传⽤⼾Id,返回当前登录⽤⼾的详情(从session获取)

2. 传⼊⽤⼾Id,返回指定Id的⽤⼾详情(根据用户id去查)

俩种方式获得用户信息

参数要求

参数名描述类型默认值条件
id⽤⼾Idlong可以为空

接口规范

// 请求
GET /user/info HTTP/1.1
GET /user/info?id=1 HTTP/1.1
// 响应
HTTP/1.1 200
Content-type: applicatin/json
{
"code": 0,
"message": "成功",
"data": {
"id": 25,
"username": "user223",
"nickname": "user223",
"phoneNum": null,
"email": null,
"gender": 1,
"avatarUrl": null,
"articleCount": 0,
"isAdmin": 0,
"state": 0,
"createTime": "2023-04-08 15:06:10",
"updateTime": "2023-04-08 15:06:10"}}

用户帖子列表

实现逻辑

对应版块中显⽰的帖⼦列表以发布时间降序排列不传⼊版块Id返回所有帖⼦

1. ⽤⼾点击某个版块或⾸⻚时,将版块Id做为参数向服务器发送请求

2. 服务器接收请求,并获取版块Id,查询对应版块下的所有帖⼦

3. 返回查询结果

参数要求

参数名描述类型默认值条件
boardId版块IdLong可为空

接口规范

// 请求
// 返回指定版块下的帖⼦列表
GET http://127.0.0.1:58080/article/getAllByBoardId?boardId=1 HTTP/1.1(以传入的id为准)
// 返回所有的帖⼦列表
GET http://127.0.0.1:58080/article/getAllByBoardId HTTP/1.1 (从session中获取当前登录用户的Id)
// 响应
HTTP/1.1 200
Content-Type: application/json
{
"code": 0,
"message": "成功",
"data": [
{
"id": 17,
"boardId": 1,
"userId": 1,
"title": "测试删除",
"visitCount": 8,
"replyCount": 1,
"likeCount": 1,
"state": 0,
"createTime": "2023-07-05 04:10:46",
"updateTime": "2023-07-05 11:22:43",
"board": {
"id": 1,
"name": "Java"
},
"user": {
"id": 1,
"nickname": "bitboy",
"phoneNum": null,
"email": null,
"gender": 1,
"avatarUrl": null
},
"own": false
}}]

后端代码实现

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

需要定义一个根据用户Id查询的SQL


2. 在Mapper.java中定义方法

在ArticleMapper里面定义selectByUserId方法


3. 定义Service接口

在IArticleService里面定义selectByUserId接口


4. 实现Service接口

实现步骤

1> 对用户id进行非空校验

2> 调用service, 根据userId校验用户是否存在

3> 调用DAO根据用户id查询用户的帖子

具体代码

   @Override
    public List<Article> selectByUserId(Long userId) {
        // 对userId进行非空校验
        if (userId == null || userId <= 0) {
            // 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 校验用户是否存在
        User user = userService.selectById(userId);
        if (user == null) {
            // 打印日志
            log.warn(ResultCode.FAILED_USER_NOT_EXISTS.toString() + ", user id = " + userId);
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_NOT_EXISTS));
        }
        // 调用DAO
        List<Article> articles = articleMapper.selectByUserId(userId);
        // 返回结果
        return articles;
    }

5. 单元测试

返回帖子列表


6. Controller实现方法并对外提供API接口

实现步骤

1> 判断userId是否为空, 是空的就去获取登录用户的userId

2> 调用Service,通过userId查询对应的作者的帖子

具体代码

    @Operation(summary = "获取用户的帖子列表")
    @GetMapping("/getAllByUserId")
    public AppResult<List<Article>> getAllByUserId(HttpServletRequest request,
                                                   @Parameter(description = "用户Id") @RequestParam(value = "userId",required = false) Long userId){
        // 如果UserId为空, 那么就从sessionId获取当前登录的用户Id
        if(userId == null){
            // 获取Session
            HttpSession session = request.getSession(false);
            // 获取User对象
            User user = (User) session.getAttribute(AppConfig.USER_SESSION);
            userId = user.getId();
        }
        // 调用Service
        List<Article> articles = articleService.selectByUserId(userId);
        // 返回结果
        return AppResult.success(articles);

    }

7. 测试API接口

不管传不传userId都能查询帖子信息

前端代码实现

构造ajax请求

实现结果

个人中心

修改个人信息

实现逻辑

只对⽤⼾的基本信息做修改,不包括密码与头像,修改密码与修改头像提供单独的修改接⼝

1. ⽤⼾打开找修改个⼈信息⻚⾯

2. 填⼊要修改的内容并提交服务器

3. 服务器获取登录⽤⼾的Id(从session中获取),并根据提交的内容修改数据

4. 返回成功或失败,如果成功返回更新后的个⼈信息

5. 浏览器刷新个⼈信息

参数要求

后端可以提供一个统一的接口, 更具用户提供参数来封装要修改的对象

参数名描述类型默认值条件
username⽤⼾名(⽤于登录)String可选,唯⼀,校验是否存在
nickname昵称String可选,
gender性别Byte可选,0⼥, 1男,2保密
email邮箱String可选
phoneNum电话String可选
remark个⼈简介String可选

接口规范

// 请求
POST http://127.0.0.1:58080/user/modifyInfo HTTP/1.1
Content-Type: application/x-www-form-urlencoded
id=1&nickname=bitboy&gender=1&email=bitboy%40bit.com&phoneNum=18888888888&remar
k=%E6%88%91%E6%98%AF%E4%B8%80%E4%B8%AA%E4%BC%98%E7%A7%80%E7%9A%84%E5%A5%BD%E9%9
D%92%E5%B9%B4
// 响应
HTTP/1.1 200
Content-Type: application/json
{
"code": 0,
"message": "成功",
"data": {
"id": 1,
"username": "bitboy",
"nickname": "bitboy",
"phoneNum": "18888888888",
"email": "bitboy@bit.com",
"gender": 1,
"avatarUrl": null,
"articleCount": 1,
"isAdmin": 1,
"remark": "我是⼀个优秀的好⻘年",
"state": 0,
"createTime": "2023-06-24 11:59:15",
"updateTime": "2023-07-09 03:05:23"
}
}

后端代码编写

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

2. 在Mapper.java中定义方法

直接使用动态SQL,已经生成


3. 定义Service接口

IUserService定义modifyInfo接口


4. 实现Service接口

实现modifyInfo

实现步骤

1> 对用户进行非空校验

2> 根据用户id查询用户是否存在(不存在直接抛异常)

3> 定义一个标志位

4> 设置一个对象,用来动态更新sql的时候对修改的属性进行操作

5> 对用户名进行校验是否要更改(必须验证时唯一值)

6> 对其他参数校验是否要更改

7> geng'ju

具体代码

    @Override
    public void modifyInfo(User user) {
        // 1. 非空校验
        if (user == null || user.getId() == null || user.getId() <= 0) {
            // 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 2. 根据用户id查询校验用户是否存在
        User existsUser = userMapper.selectByPrimaryKey(user.getId());
        // 如果查不到, 就直接抛异常
        if (existsUser == null) {
            // 打印日志
            log.warn(ResultCode.FAILED_USER_NOT_EXISTS.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_NOT_EXISTS));
        }
        // 3. 定义一个标志位
        boolean checkAttr = false;// false表示没有校验通过
        // 4. 定义一个专门用来更新的对象, 防止用户传入的User对象设置了其他属性
        // 当使用动态SQL进行更新的时候, 覆盖了没有经过校验的字段
        User updateUser = new User();
        // 5. 设置用户Id
        updateUser.setId(user.getId());
        // 6. 对每一个参数进行校验并赋值
        if (!StringUtil.isEmpty(user.getUsername())
                && !user.getUsername().equals(existsUser.getUsername())) {// 用户名不为空并且修改后的用户名和原先用户名不一样
            // 更新用户名之前, 需要进行唯一性校验, 去表里面找有没有修改后的用户
            User checkUser = userMapper.selectByUserName(user.getUsername());
            if (checkUser != null) {
                // 用户已存在
                log.warn(ResultCode.FAILED_USER_EXISTS.toString());
                // 抛出异常
                throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_EXISTS));
            }
            // 数据库中没有找到相应的用户, 表示可以修改用户名
            updateUser.setUsername(user.getUsername());
            // 更新标志位
            checkAttr = true;
        }
        // 7. 校验昵称
        if (!StringUtil.isEmpty(user.getNickname())
                && !user.getNickname().equals(existsUser.getNickname())) {
            // 设置昵称
            updateUser.setNickname(user.getNickname());
            // 更新标志位
            checkAttr = true;
        }
        // 8. 校验性别
        if (user.getGender() != null && user.getGender() != existsUser.getGender()) {
            // 设置性别
            updateUser.setGender(user.getGender());
            // 合法性校验
            if (updateUser.getGender() > 2 || updateUser.getGender() < 0) {
                updateUser.setGender((byte) 2);
            }
            // 更新标志位
            checkAttr = true;
        }
        // 9. 校验邮箱
        if (!StringUtil.isEmpty(user.getEmail())
                && !user.getEmail().equals(existsUser.getEmail())) {
            // 设置邮箱
            updateUser.setEmail(user.getEmail());
            // 更新标志位
            checkAttr = true;
        }
        // 9. 校验电话号码
        if (!StringUtil.isEmpty(user.getPhoneNum())
                && !user.getPhoneNum().equals(existsUser.getPhoneNum())) {
            // 设置电话号码
            updateUser.setPhoneNum(user.getPhoneNum());
            // 更新标志位
            checkAttr = true;
        }
        // 10. 校验个人简介
        if (!StringUtil.isEmpty(user.getRemark())
                && !user.getRemark().equals(existsUser.getRemark())) {
            // 设置电话号码
            updateUser.setRemark(user.getRemark());
            // 更新标志位
            checkAttr = true;
        }
        // 11. 根据标志位来决定是否可以执行更新
        if (checkAttr == false) {
            // 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 12. 调用DAO
        int row = userMapper.updateByPrimaryKeySelective(updateUser);
        if (row != 1) {
            log.warn(ResultCode.FAILED.toString() + ", 受影响的行数不等于 1 .");
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED));
        }
    }

5. 单元测试

修改成功


6. Controller实现方法并对外提供API接口

实现步骤

1> 接受参数, 对参数进行非空校验

2> 从session中获取要修改的用户Id

3> 封装更新的User对象

4> 调用Service中的方法

5> 查询最新的用户信息

6> 把最新的用户信息设置到session中

7> 返回结果

具体代码


    // 修改个人信息
    @Operation(summary = "修改个人信息")
    @GetMapping("/modifyInfo")
    public AppResult modifyInfo(HttpServletRequest request,
                                @Parameter(description = "用户名") @RequestParam(value = "username", required = false) String username,
                                @Parameter(description = "昵称") @RequestParam(value = "nickname", required = false) String nickname,
                                @Parameter(description = "性别") @RequestParam(value = "gender", required = false) Byte gender,
                                @Parameter(description = "邮箱") @RequestParam(value = "email", required = false) String email,
                                @Parameter(description = "电话号") @RequestParam(value = "phoneNum", required = false) String phoneNum,
                                @Parameter(description = "个人简介") @RequestParam(value = "remark", required = false) String remark) {

        // 1. 接受参数
        // 2. 对参数做非空校验(全部都为空,就返回错误信息)
        if (StringUtil.isEmpty(username) && StringUtil.isEmpty(nickname)
                && StringUtil.isEmpty(email) && StringUtil.isEmpty(phoneNum)
                && StringUtil.isEmpty(remark) && gender == null) {
            // 返回错误信息
            return AppResult.failed("请输入要修改的内容");
        }
        // 3. 从session中获取用户Id
        HttpSession session = request.getSession(false);
        User user = (User) session.getAttribute(AppConfig.USER_SESSION);
        // 4. 封装更新的User对象
        User updateUser = new User();
        updateUser.setId(user.getId()); // 用户Id
        updateUser.setUsername(username); // 用户名
        updateUser.setNickname(nickname); // 昵称
        updateUser.setGender(gender); // 性别
        updateUser.setEmail(email); // 邮箱
        updateUser.setPhoneNum(phoneNum); // 电话
        updateUser.setRemark(remark); // 个人简介
        // 5. 调用Service中的方法
        userService.modifyInfo(updateUser);
        // 6. 查询最新的用户信息
        user = userService.selectById(user.getId());
        // 7. 把最新的用户信息设置到session中
        session.setAttribute(AppConfig.USER_SESSION,user);
        // 8. 返回结果
        return AppResult.success(user);
    }

7. 测试API接口

前端代码编写

编写ajax请求

最终的结果

修改密码

实现逻辑

• 为修改密码提供⼀个单独的接⼝及操作⻚⾯
1. ⽤⼾打开修改密码⻚⾯

2. 输⼊原密码、新密码、重复新密码并提交服务器

3. 服务器校验原密码是否正确

4. 原密码校验通过更新密码

5. 返回成功或失败

参数要求

参数名描述类型默认值条件
oldPassword原密码String必须
newPassword新密码String必须
passwordRepea t确认新密码String必须,与新密码相同

接口规范

// 请求
POST http://127.0.0.1:58080/user/modifyPwd HTTP/1.1
Content-Type: application/x-www-form-urlencoded
id=1&oldPassword=123456&newPassword=123456&passwordRepeat=123456
// 响应
HTTP/1.1 200
Content-Type: application/json
{
"code": 0,
"message": "成功",
"data": null
}

后端代码实现

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

2. 在Mapper.java中定义方法

1.2实现过


3. 定义Service接口

4. 实现Service接口

实现步骤

1> 对id进行非空校验

2> 根据id去数据库查询用户的信息, 并校验用户是否存在

3> 校验老密码是否正确(取出老盐, 然后和老密码进行md5加密)

4> 然后老密码和用户密码进行比对

5> 构造新的盐和新密码

6> 构造要更新的对象

7> 调用DAO

具体代码

 /**
     * 修改密码
     * @param id 用户Id
     * @param newPassword 新密码
     * @param oldPassword 老密码
     */
    @Override
    public void modifyPassword(Long id, String newPassword, String oldPassword) {
        // 对id进行非空校验
        if (id == null || id <= 0 || StringUtil.isEmpty(newPassword) || StringUtil.isEmpty(oldPassword)) {
            // 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 查询用户的信息
        User user = userMapper.selectByPrimaryKey(id);
        // 校验用户是否存在
        if (user == null || user.getDeleteState() == 1) {
            // 打印日志
            log.warn(ResultCode.FAILED_USER_NOT_EXISTS.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_NOT_EXISTS));
        }
        // 校验老密码是否正确
        // 对老密码进行加密, 获取密文: 获取旧的盐, 然后让旧的盐和旧的密码拼接, 然后用md5进行加密
        String oldEncryptPassword = MD5Util.md5Salt(oldPassword,user.getSalt());
        // 和用户当前的密码进行比较
        if(!oldEncryptPassword.equalsIgnoreCase(user.getPassword())){
            // 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 生成一个新的盐
        String salt = UUIDUtil.UUID_32();
        // 生成新密码的密文 ((明文)md5加密+扰动字符)md5加密
        String encryptPassword = MD5Util.md5Salt(newPassword,salt);
        // 构造要更新的对象
        User updateUser = new User();
        updateUser.setId(user.getId()); // 用户id
        updateUser.setSalt(salt);// 新生成的盐
        updateUser.setPassword(encryptPassword); // 新密码对应的密文
        Date date = new Date();
        updateUser.setUpdateTime(date); // 更新时间

        // 调用DAO
        int row = userMapper.updateByPrimaryKeySelective(updateUser);
        if (row != 1) {
            log.warn(ResultCode.FAILED.toString() + ", 受影响的行数不等于 1 .");
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED));
        }

    }


5. 单元测试


6. Controller实现方法并对外提供API接口

实现逻辑

1> 校验新密码和确认密码是否相同

2> 获取当前登录的用户信息

3> 调用Service

4> 销毁session 回到登录页面重新登录

5> 返回结果

具体代码

    @Operation(summary = "修改密码")
    @PostMapping("/modifyPwd")
    public AppResult modifyPassword(HttpServletRequest request,
                                    @Parameter(description = "原密码") @RequestParam("oldPassword")@NonNull String oldPassword,
                                    @Parameter(description = "新密码") @RequestParam("newPassword")@NonNull String newPassword,
                                    @Parameter(description = "确认密码") @RequestParam("passwordRepeat")@NonNull String repeatPassword){
        // 1. 校验新密码和确认密码是否相同
        if(!newPassword.equalsIgnoreCase(repeatPassword)){
            // 返回错误描述
            return AppResult.failed(ResultCode.FAILED_TWO_PWD_NOT_SAME);
        }
        // 2. 获取当前登录的用户信息
        HttpSession session = request.getSession(false);
        User user =(User) session.getAttribute(AppConfig.USER_SESSION);
        // 3. 调用Service
        userService.modifyPassword(user.getId(),newPassword,oldPassword);
        // 4. 销毁session 回到登录页面重新登录
        if (session != null) {
            session.invalidate();
        }
        // 5. 返回结果
        return AppResult.success();
    }

7. 测试API接口

站内信

发送

实现逻辑

1. 在⽬录⽤⼾详情界⾯,点击发送站内信接钮,进⼊编辑⻚⾯

2. 编写站内信内容,点击发送按钮

3. 提⽰发送结果

参数要求

参数名描述类型条件默认值
receiveUserId接收⽤⼾IdLong必须
content站内信内容String必须

接口规范

// 请求
POST http://127.0.0.1:58080/message/send HTTP/1.1
Content-Type: application/x-www-form-urlencoded
receiveUserId=2&content=%E4%BD%A0%E5%A5%BD%E5%95%8A
// 响应
HTTP/1.1 200
Content-Type: application/json
{
"code": 0,
"message": "成功",
"data": null
}

后端代码实现

1. 在Mapper.xml中编写SQL语句
2. 在Mapper.java中定义方法

实现过了


3. 定义Service接口


4. 实现Service接口

实现逻辑

1> 对Message进行非空校验

2> 根据message的id查询接收者是否存在

3> 设置默认值

4> 设置创建时间和更新时间

5> 调用DAO,插入message

具体代码

package org.xiaobai.forum.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.xiaobai.forum.common.AppResult;
import org.xiaobai.forum.common.ResultCode;
import org.xiaobai.forum.dao.MessageMapper;
import org.xiaobai.forum.exception.ApplicationException;
import org.xiaobai.forum.model.Message;
import org.xiaobai.forum.model.User;
import org.xiaobai.forum.service.IMessageService;
import org.xiaobai.forum.service.IUserService;
import org.xiaobai.forum.utils.StringUtil;

import javax.annotation.Resource;
import java.util.Date;

@Service
@Slf4j
public class MessageServiceImpl implements IMessageService {
    @Resource
    private MessageMapper messageMapper;
    @Resource
    private IUserService userService;

    @Override
    public void create(Message message) {
        // 非空校验
        if (message == null || message.getPostUserId() == null || message.getReceiveUserId() == null
                || StringUtil.isEmpty(message.getContent())) {
            // 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 校验接收者是否存在
        User user = userService.selectById(message.getReceiveUserId());
        if (user == null || user.getDeleteState() == 1) {
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 设置默认值
        message.setState((byte) 0);
        message.setDeleteState((byte) 0);
        // 设置创建与更新时间
        Date date = new Date();
        message.setCreateTime(date);
        message.setUpdateTime(date);
        // 调用DAO
        int row = messageMapper.insertSelective(message);
        if (row != 1) {
            log.warn(ResultCode.FAILED_CREATE.toString());
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_CREATE));
        }

    }
}

5. 单元测试

6. Controller实现方法并对外提供API接口

实现逻辑

1> 获取当前登录的用户信息

2> 判断当前登录用户的状态, 如果是禁言是不能发送站内信

3> 判断发送人是不是作者(不能自己给自己发送站内信)

4> 根据接收者id校验接收者是否存在

5> 封装发送对象

6> 调用Service, 把message传进去

7> 返回结果

具体代码

package org.xiaobai.forum.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.xiaobai.forum.common.AppResult;
import org.xiaobai.forum.common.ResultCode;
import org.xiaobai.forum.config.AppConfig;
import org.xiaobai.forum.model.Message;
import org.xiaobai.forum.model.User;
import org.xiaobai.forum.service.IMessageService;
import org.xiaobai.forum.service.IUserService;

import javax.annotation.Resource;

@Tag(name ="站内信接口",description = "给其他用户发送信息")
@RestController
@RequestMapping("/message")
@Slf4j
public class MessageController {
    @Resource
    private IMessageService messageService;
    @Resource
    private IUserService userService;
    @Operation(summary = "发送站内信")
    @PostMapping("/send")
    public AppResult send(HttpServletRequest request,
                          @Parameter(description = "接收者Id")@RequestParam("receiveUserId") @NonNull Long receiveUserId,
                          @Parameter(description = "内容")@RequestParam("content")@NonNull String content){
        // 获取当前登录的用户信息
        HttpSession session = request.getSession(false);
        User user = (User) session.getAttribute(AppConfig.USER_SESSION);
        // 1. 当前登录用户的状态, 如果是禁言状态是不能发送站内信
        if(user.getState() == 1){
            // 返回用户状态异常
            return AppResult.failed(ResultCode.FAILED_USER_BANNED);
        }
        // 2. 不能给自己发送站内信
        if(user.getId() == receiveUserId){
            return AppResult.failed("不能给自己发送站内信");
        }
        // 3. 校验接收者是否存在
        User receiveUser = userService.selectById(receiveUserId);
        // 判断接收者状态是否正常
        if (receiveUser == null || receiveUser.getDeleteState() == 1) {
            // 返回接收者状态不正常
            return AppResult.failed("接收者状态异常");
        }
        // 4. 封装发送对象
        Message message = new Message();
        message.setPostUserId(user.getId());// 发送者Id
        message.setReceiveUserId(receiveUserId);// 接收者Id
        message.setContent(content);// 站内信内容
        // 5.调用Service
        messageService.create(message);
        // 6. 返回结果
        return AppResult.success("发送成功");

    }
}

7. 测试API接口

未读数

实现逻辑

查询当前登录⽤⼾的未读站内信数量(直接从session中获取用户的Id)

接口规范

// 请求
GET http://127.0.0.1.41:58080/message/getUnreadCount HTTP/1.1
// 响应
HTTP/1.1 200
Content-Type: application/json
{"code":0,"message":"成功","data":1}

后端代码实现

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

根据用户Id查询该用户的未读数量 state = 0(0表示未读)


2. 在Mapper.java中定义方法

3. 定义Service接口

4. 实现Service接口

实现逻辑

1> 对receiverUserId进行参数非空校验

2> 直接调用DAO,通过receiverUserId查询该用户未读的信息数

3> 检查count

具体代码

    /**
     * 根据用户Id查询该用户的未读数
     * @param receiveUserId 用户id
     * @return 未读数
     */
    @Override
    public Integer selectUnreadCount(Long receiveUserId) {
        // 参数非空校验
        if(receiveUserId == null || receiveUserId <=0){
            // 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 直接调用DAO
        Integer count = messageMapper.selectUnreadCount(receiveUserId);
        // 检查count
        if (count == null) {
            log.warn(ResultCode.ERROR_SERVICES.toString());
            throw new ApplicationException(AppResult.failed(ResultCode.ERROR_SERVICES));
        }
        // 返回结果
        return count;
    }

5. 单元测试

6. Controller实现方法并对外提供API接口

实现逻辑

1> 根据session获取当前登录的用户

2> 调用Service, 根据用户Id获取用户站内信未读数

3> 返回结果集

具体代码

    @Operation(summary = "获取未读数")
    @GetMapping("/getUnreadCount")
    public  AppResult<Integer> getUnreadCount(HttpServletRequest request){
        // 1. 获取当前登录的用户
        HttpSession session = request.getSession(false);
        User user = (User) session.getAttribute(AppConfig.USER_SESSION);
        // 2. 调用Service
        Integer count = messageService.selectUnreadCount(user.getId());// 当前登录的id就是接收者id
        // 3. 返回结果
        return AppResult.success(count);

    }


7. 测试API接口

列表

实现逻辑

⽤⼾访问API,服务器响应当前登录⽤⼾的站内信

接口规范

// 请求
GET http://127.0.0.1:58080/message/getAll HTTP/1.1
// 响应
HTTP/1.1 200
Content-Type: application/json
{
"code": 0,
"message": "成功",
"data": [{
"id": 11,
"postUserId": 32, 
"receiveUserId": 3,
"content": "真的可以发出去吗\n",
"state": 2,
"createTime": "2023-06-20 11:21:09",
"updateTime": "2023-06-25 11:24:38",
"postUser": {
"id": 32,
"nickname": "ljl",
"phoneNum": null,
"email": null,
"gender": 2,
"avatarUrl": null
}
}]}

后端代码实现

1. 在Mapper.xml中编写SQL语句
 
2. 在Mapper.java中定义方法

3. 定义Service接口

4. 实现Service接口

实现逻辑

1> 参数非空校验

2> 调用DAO

3> 返回结果

具体代码

    @Override
    public List<Message> selectByReceiveUserId(Long receiveUserId) {
        // 参数非空校验
        if(receiveUserId == null || receiveUserId <=0){
            // 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 调用DAO
        List<Message> messages = messageMapper.selectByReceiveUserId(receiveUserId);
        // 返回结果
        return messages;
    }

5. 单元测试

6. Controller实现方法并对外提供API接口

具体逻辑

1> 获取当前登录的用户

2> 根据用户的id获取用户的站内信列表

3> 返回结果

代码编写

    @Operation(summary = "查询用户的所有站内信")
    @GetMapping("/getAll")
    public AppResult<List<Message>> getAll(HttpServletRequest request){
        // 1. 获取当前登录的用户
        HttpSession session = request.getSession(false);
        User user = (User) session.getAttribute(AppConfig.USER_SESSION);
        // 2. 调用Service
        List<Message> messages = messageService.selectByReceiveUserId(user.getId());
        // 3. 返回结果
        return AppResult.success(messages);
    }

7. 测试API接口

更新状态

实现逻辑

1. ⽤⼾点击站内信,显⽰详情⻚⾯

2. 更新未读状态的站内信为已读

参数要求

参数名描述类型条件默认值
id站内信Idlong必须

接口规范

// 请求
POST http://127.0.0.1:58080/message/markRead HTTP/1.1
Content-Type: application/x-www-form-urlencoAded
id=1
// 响应
HTTP/1.1 200
Content-Type: application/json
{"code": 0,
"message": "成功",
"data": null
}

后端代码实现

1. 在Mapper.xml中编写SQL语句
2. 在Mapper.java中定义方法

之前写了


3. 定义Service接口

4. 实现Service接口

实现逻辑

1> 对id, state进行校验

2> 动态更新, 构造更新对象

3> 调用DAO,更新是否已读

具体代码

@Override
    public void updateStateById(Long id, Byte state) {
        // 对id进行非空校验, state: 0 未读 1 已读 2 已回复
        if (id == null || id <= 0 || state < 0 || state > 2) {
            // 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());// 更新帖子数失败
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 构造更新对象
        Message updateMessage = new Message();
        updateMessage.setId(id);
        updateMessage.setState(state);
        Date date = new Date();
        updateMessage.setUpdateTime(date);
        // 调用DAO
        int row = messageMapper.updateByPrimaryKeySelective(updateMessage);
        if(row !=1){
            log.warn(ResultCode.ERROR_SERVICES.toString());
            throw  new ApplicationException(AppResult.failed(ResultCode.ERROR_SERVICES));
        }
    }


5. 单元测试


6. Controller实现方法并对外提供API接口

实现逻辑

1> 根据Id查询站内信,并且查询站内信是否存在

2> 判断站内信是不是自己

3> 调用Service把id所对应的Message更新为已读状态

具体代码

    @Operation(summary = "更新为已读")
    @PostMapping("/markedRead")
    public AppResult markedRead(HttpServletRequest request,
                                @Parameter(description = "站内信Id") @RequestParam("id") @NonNull Long id) {
        //1. 根据Id查询站内信
        Message message = messageService.selectById(id);
        //2. 站内信是否存在
        if (message == null || message.getDeleteState() == 1) {
            // 返回错误信息
            return AppResult.failed(ResultCode.FAILED_MESSAGE_NOT_EXISTS);
        }
        //3. 站内信是不是自己的
        HttpSession session = request.getSession(false);
        User user = (User) session.getAttribute(AppConfig.USER_SESSION);
        // 判断站内信的收件人是不是当前的登录
        if (user.getId() != message.getReceiveUserId()) {
            // 返回错误信息
            return AppResult.failed(ResultCode.FAILED_FORBIDDEN);
        }
        // 调用Service, 把状态更新为已读
        messageService.updateStateById(id,(byte)1);
        // 返回结果
        return AppResult.success();
    }

7. 测试API接口

回复

实现逻辑

1. ⽤⼾在站内信详情⻚⾯点击回复按钮,显⽰回复区

2. 填写回复内容并提交到服务器

3. ⽤⼾不能回复接收者不是⾃⼰的站内信

4. 站内信状态置为已回复(并且要在数据库中新增一条站内信记录, 俩个数据的修改操作在一个业务逻辑中, 因此要用事务进行管理)

参数要求

参数名描述类型条件默认值
repliedId(要回复的站内信id)站内信IdLong必须
content内容String必须

接口规范

// 请求
POST http://127.0.0.1:58080/message/reply HTTP/1.1
Content-Type: application/x-www-form-urlencoded
repliedId=1&receiveUserId=2&content=%E4%BD%A0%E5%A5%BD%E5%95%8A
// 响应
HTTP/1.1 200
Content-Type: application/json
{
"code": 0,
"message": "成功",
"data": null
}

后端代码实现

1. 在Mapper.xml中编写SQL语句
2. 在Mapper.java中定义方法
3. 定义Service接口

4. 实现Service接口

实现步骤

1> 对repliedId进行非空校验

2> 校验repliedId是不是存在

3> 更新状态为已读

4> 回复的内容写入数据库

具体代码

    /**
     * 回复站内信
     * @param repliedId 要回复的站内信Id
     * @param message 回复的对象
     */
    @Override
    public void reply(Long repliedId, Message message) {
        // 对repliedId进行非空校验
        if (repliedId == null || repliedId <= 0) {
            // 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 校验repliedId是不是存在
        Message existsMessage  = messageMapper.selectByPrimaryKey(repliedId);
        // 信息是否存在
        if (existsMessage == null || existsMessage.getDeleteState() == 1) {
            // 打印日志
            log.warn(ResultCode.FAILED_MESSAGE_NOT_EXISTS.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_MESSAGE_NOT_EXISTS));
        }
        // 更新状态为已回复
        updateStateById(repliedId,(byte)2);
        // 回复的内容写入数据库
        create(message);
    }


5. 单元测试


6. Controller实现方法并对外提供API接口

实现步骤

1> 校验当前登录用户的状态(是否禁言)

2> 校验要恢复的站内信状态(是否有站内信)

3> 校验是不是给自己回复

4> 构造回复对象

5> 调用Service

6> 返回结果

具体代码

    @Operation(summary = "回复站内信")
    @PostMapping("/reply")
    public AppResult reply(HttpServletRequest request,
                           @Parameter(description = "要回复的站内信Id") @RequestParam("repliedId") @NonNull Long repliedId,
                           @Parameter(description = "站内信的内容") @RequestParam("content")@NonNull String content){
        // 校验当前登录用户的状态
        HttpSession session = request.getSession(false);
        User user = (User) session.getAttribute(AppConfig.USER_SESSION);
        if (user.getState() == 1) {
            // 返回错误描述
            return AppResult.failed(ResultCode.FAILED_USER_BANNED);
        }

        // 校验要回复的站内信状态
        Message existsMessage = messageService.selectById(repliedId);
        if (existsMessage == null || existsMessage.getDeleteState() == 1) {
            // 返回错误描述
            return AppResult.failed(ResultCode.FAILED_MESSAGE_NOT_EXISTS);
        }
        // 不能给自己回复
        if (user.getId() == existsMessage.getPostUserId()) {
            // 返回错误描述
            return AppResult.failed("不能回复自己的站内信");
        }
        // 构造对象
        Message message = new Message();
        message.setPostUserId(user.getId()); // 发送者
        message.setReceiveUserId(existsMessage.getPostUserId()); // 接收者
        message.setContent(content); // 内容
        // 调用Service
        messageService.reply(repliedId, message);
        // 返回结果
        return AppResult.success();
    }

7. 测试API接口

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

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

相关文章

力扣面试150题--二叉树的层平均值

Day 54 题目描述 思路 初次做法&#xff08;笨&#xff09;&#xff1a;使用两个队列&#xff0c;一个队列存放树的节点&#xff0c;一个队列存放对应节点的高度&#xff0c;使用x存放上一个节点&#xff0c;highb存放上一个节点的高度&#xff0c;sum存放当前层的节点值之和…

【Doris入门】Doris初识:分布式分析型数据库的核心价值与架构解析

目录 1 Doris简介与核心价值 2 Doris架构深度解析 2.1 Frontend&#xff08;FE&#xff09;架构 2.2 Backend&#xff08;BE&#xff09;架构 3 Doris核心概念详解 3.1 数据分布模型 3.2 Tablet与Replica 3.3 数据模型 4 Doris关键技术解析 4.1 存储引擎 4.2 查询执…

数据结构与算法学习笔记(Acwing 提高课)----动态规划·区间DP

数据结构与算法学习笔记----动态规划区间DP author: 明月清了个风 first publish time: 2025.5.26 ps⭐️区间DP的特征在于子结构一般是一个子区间上的问题&#xff0c;涉及到的问题也非常多&#xff0c;如环形区间&#xff0c;记录方案数&#xff0c;高精度&#xff0c;二维…

从0到1搭建AI绘画模型:Stable Diffusion微调全流程避坑指南

从0到1搭建AI绘画模型&#xff1a;Stable Diffusion微调全流程避坑指南 系统化学习人工智能网站&#xff08;收藏&#xff09;&#xff1a;https://www.captainbed.cn/flu 文章目录 从0到1搭建AI绘画模型&#xff1a;Stable Diffusion微调全流程避坑指南摘要引言一、数据集构…

从一到无穷大 #46:探讨时序数据库Deduplicate与Compaction的设计权衡

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。 本作品 (李兆龙 博文, 由 李兆龙 创作)&#xff0c;由 李兆龙 确认&#xff0c;转载请注明版权。 文章目录 引言Compaction AlgorithmsCompact Execution Flow Based On VeloxLocalMergeSource的…

vue3 导出excel

需求&#xff1a;导出自带格式的excel表格 1.自定义二维数组格式 导出 全部代码&#xff1a; <el-button click"exportExcel">导出</el-button> const exportExcel () > {const data [[商品, 单价, 数量, 总价],[A, 100, 1.55, { t: n, f: B2*C2…

day024-网络基础-TCP与UDP、DNS

文章目录 1. 李导推荐书籍2. OSI七层模型2.1 传输层2.2 网络层2.2.1 问&#xff1a;两端处于不同局域网的设备怎么网络通信&#xff1f; 2.3 数据链路层2.4 物理层2.5 图解OSI七层模型 3. 数据传输模式3.1 全双工3.2 半双工3.3 单工 4. TCP 3次握手4.1 抓包 5. TCP 4次挥手5.1 …

专场回顾 | 重新定义交互,智能硬件的未来设计

自2022年起&#xff0c;中国智能硬件行业呈现出蓬勃发展的态势&#xff0c;市场规模不断扩大。一个多月前&#xff0c;“小智AI”在短视频平台的爆火将智能硬件带向了大众视野&#xff0c;也意味着智能硬件已不再仅仅停留在概念和技术层面&#xff0c;而是加速迈向实际落地应用…

WPS 免登录解锁编辑

遇到 WPS 需要登录才能启用编辑功能&#xff1f; 如何免登录使用编辑功能&#xff1f; 方法一 解锁方法 1、关闭 WPS&#xff1b; 2、桌面右键→ “新建”→“文本文档”&#xff0c;粘贴以下内容&#xff08;见最下面&#xff09;&#xff1b;编码保持默认&#xff08;ANSI …

技术分享 | Oracle SQL优化案例一则

本文为墨天轮数据库管理服务团队第70期技术分享&#xff0c;内容原创&#xff0c;作者为技术顾问马奕璇&#xff0c;如需转载请联系小墨&#xff08;VX&#xff1a;modb666&#xff09;并注明来源。 一、问题概述 开发人员反映有条跑批语句在测试环境执行了很久都没结束&…

华为手机用的时间长了,提示手机电池性能下降,需要去换电池吗?平时要怎么用能让电池寿命长久一些?

华为手机提示电池性能下降时&#xff0c;是否需要更换电池以及如何延长电池寿命&#xff0c;取决于电池老化程度和使用习惯。以下是具体分析和建议&#xff1a; 一、是否需要更换电池&#xff1f; 电池健康度低于80% 如果手机提示“电池性能下降”&#xff0c;通常意味着电池…

BERT***

​​1.预训练&#xff08;Pre-training&#xff09;​​ 是深度学习中的一种训练策略&#xff0c;指在大规模无标注数据上预先训练模型&#xff0c;使其学习通用的特征表示&#xff0c;再通过​​微调&#xff08;Fine-tuning&#xff09;​​ 适配到具体任务 2.sentence-lev…

超级对话2:大跨界且大综合的学问融智学应用场景述评(不同第三方的回应)之二

摘要&#xff1a;《人机协同文明升维行动框架》提出以HIAICI/W公式推动认知革命&#xff0c;构建三大落地场景&#xff1a;1&#xff09;低成本认知增强神经接口实现300%学习效率提升&#xff1b;2&#xff09;全球学科活动化闪电战快速转化知识体系&#xff1b;3&#xff09;人…

深度学习常见实验问题与实验技巧

深度学习常见实验问题与实验技巧 有一定的先后顺序的 还在迷茫深度学习中的改进实验应该从哪里开始改起的同学&#xff0c;一定要进来看看了&#xff01;用自身经验给你推荐实验顺序&#xff01; YOLOV8-硬塞注意力机制&#xff1f;这样做没创新&#xff01;想知道注意力怎么…

一张Billing项目的流程图

流程图 工作记录 2016-11-11 序号 工作 相关人员 1 修改Payment Posted的导出。 Claim List的页面加了导出。 Historical Job 加了Applied的显示和详细。 郝 识别引擎监控 Ps (iCDA LOG :剔除了160篇ASG_BLANK之后的结果): LOG_File 20161110.txt BLANK_CDA/ALL 45/10…

理想树图书:以科技赋能教育,开启AI时代自主学习新范式

深耕教育沃土 构建全场景教辅产品矩阵 自2013年创立以来&#xff0c;理想树始终以教育匠心回应时代命题。在教辅行业这片竞争激烈的领域&#xff0c;由专业教育工作者组成的理想树图书始终秉持“知识互映”理念&#xff0c;经过十余年的精耕细作&#xff0c;精心打造了小学同步…

【大模型02】Deepseek使用和prompt工程

文章目录 DeepSeekDeepseek 的创新MLA &#xff08;低秩近似&#xff09; MOE 混合专家混合精度框架总结DeepSeek-V3 与 DeepSeek R1 DeepSeek 私有化部署算例市场&#xff1a; autoDLVllM 使用Ollma复习 API 调用deepseek-r1Prompt 提示词工程Prompt 实战设置API Keycot 示例p…

大学大模型教学:基于NC数据的全球气象可视化解决方案

引言 气象数据通常以NetCDF(Network Common Data Form)格式存储,这是一种广泛应用于科学数据存储的二进制文件格式。在大学气象学及相关专业的教学中,掌握如何读取、处理和可视化NC数据是一项重要技能。本文将详细介绍基于Python的NC数据处理与可视化解决方案,包含完整的代…

MediaMtx开源项目学习

这个博客主要记录MediaMtx开源项目学习记录,主要包括下载、推流(摄像头,MP4)、MediaMtx如何使用api去添加推流,最后自定义播放器,播放推流后的视频流,自定义Video播放器博客地址 1 下载 MediaMTX MediaMTX 提供了预编译的二进制文件,您可以从其 GitHub 页面下载: Gi…

Linux安装EFK日志分析系统

目标&#xff1a;能够实现采集指定路径日志到es&#xff0c;用kibana实现日志分析 单es节点集群规划&#xff1a; 主机名IP 地址组件a1192.168.1.111Kibana elasticsearcha2192.168.1.112Fluentda3192.168.1.103Fluentd 1、安装Elasticsearch 1.1添加 Elastic 仓库并安装 E…