11 Commits

Author SHA1 Message Date
KilLze
96b256d46e 加注释 2025-12-28 21:14:30 +08:00
KilLze
fca54a6f97 完成头像和背景上传,优化动态文件上传,修bug 2025-12-28 21:10:55 +08:00
KilLze
0f8f47de8e 用户查询个人信息功能 2025-12-28 19:57:05 +08:00
KilLze
2cb8ae5c3c 修bug,顺便修改接口名 2025-12-28 18:05:47 +08:00
KilLze
7abd6fe27d 修bug,顺便修改接口名 2025-12-28 17:53:16 +08:00
KilLze
dfc9508827 修bug,顺便修改接口名 2025-12-28 16:59:51 +08:00
KilLze
4c70bd3c6f 完成jwt拦截器和从token中获取当前登录的用户id
目前除登录以外的所有操作都会经过拦截器,可以在WebConfig中设置拦截器忽略的接口
获取用户id不需要手动输入了,直接通过UserContext获取当前登录的用户id
为动态删除,动态修改等我负责的功能添加身份验证,用户id不匹配则会跳出异常
增加token过期验证
2025-12-28 02:17:09 +08:00
KilLze
d3c069967e 完成jwt拦截器和从token中获取当前登录的用户id
目前除登录以外的所有操作都会经过拦截器,可以在WebConfig中设置拦截器忽略的接口
获取用户id不需要手动输入了,直接通过UserContext获取当前登录的用户id
为动态删除,动态修改等我负责的功能添加身份验证,用户id不匹配则会跳出异常
2025-12-28 02:04:25 +08:00
bao
4a2aff888a 配置redis
(cherry picked from commit ae0cca5437)
2025-12-27 19:37:01 +08:00
bao
0b0959fa80 增加User项目结构
(cherry picked from commit c329eaef79)
2025-12-27 19:28:19 +08:00
KilLze
4401a8a44a 用户密码登录功能完成 2025-12-27 19:25:03 +08:00
16 changed files with 295 additions and 122 deletions

View File

@@ -1,14 +1,26 @@
package com.bao.dating.common;
/**
* 响应状态码枚举
*/
public enum ResultCode {
/** 成功 */
SUCCESS(200, "成功"),
/** 请求已成功处理 */
SUCCESS_REVIEW(201, "请求已成功处理"),
/** 删除成功 */
SUCCESS_DELETE(204, "删除成功"),
/** 参数错误 */
PARAM_ERROR(400, "参数错误"),
/** 未登录或 Token 失效 */
UNAUTHORIZED(401, "未登录或 Token 失效"),
/** 无权限 */
FORBIDDEN(403, "无权限"),
/** 数据不存在 */
NOT_FOUND(404, "数据不存在"),
/** 系统异常 */
SYSTEM_ERROR(500, "系统异常"),
/** 操作失败 */
FAIL(500, "操作失败");
private final int code;
@@ -26,4 +38,4 @@ public enum ResultCode {
public String msg() {
return msg;
}
}
}

View File

@@ -25,9 +25,7 @@ public class WebConfig implements WebMvcConfigurer {
.addPathPatterns("/**")
// 忽略的接口
.excludePathPatterns(
"/user/login",
"/user/userRegister"
"/user/login"
);
}
}

View File

@@ -36,7 +36,7 @@ public class PostController {
* @param postDTO 动态信息
* @return 发布的动态对象
*/
@PostMapping(consumes = "application/json")
@PostMapping( "/createPost")
public Result<Post> createPostJson(@RequestBody PostRequestDTO postDTO) {
// 调用 Service 层处理发布动态业务逻辑
Post result = postService.createPost(postDTO);
@@ -49,8 +49,8 @@ public class PostController {
* @param postIds 动态ID
* @return 删除结果
*/
@DeleteMapping
public Result<String> deleteById(@RequestParam List<Long> postIds){
@PostMapping("/deletePost")
public Result<String> deleteById(@RequestBody List<Long> postIds){
int deletedCount = postService.deletePostById(postIds);
return Result.success(ResultCode.SUCCESS_DELETE, deletedCount > 0 ? "成功删除" : "删除失败,该动态不存在", null);
}
@@ -60,7 +60,7 @@ public class PostController {
* @param postId 动态ID
* @return 动态对象
*/
@GetMapping("/{postId}")
@PostMapping("/{postId}")
public Result<PostEditVO> getPostById(@PathVariable Long postId) {
PostEditVO postEditVO = postService.getPostForEdit(postId);
return Result.success(ResultCode.SUCCESS,"查询成功", postEditVO);
@@ -72,7 +72,7 @@ public class PostController {
* @param postRequestDTO 动态信息
* @return 更新后的动态对象
*/
@PutMapping("/{postId}")
@PostMapping("/{postId}/updatePost")
public Result<PostEditVO> updatePost(@PathVariable Long postId, @RequestBody PostRequestDTO postRequestDTO) {
PostEditVO result = postService.updatePost(postId, postRequestDTO);
return Result.success(ResultCode.SUCCESS_REVIEW, "动态更新成功", result);

View File

@@ -2,15 +2,12 @@ package com.bao.dating.controller;
import com.bao.dating.common.Result;
import com.bao.dating.common.ResultCode;
import com.bao.dating.pojo.entity.Post;
import com.bao.dating.pojo.entity.PostFavorite;
import com.bao.dating.pojo.entity.User;
import com.bao.dating.service.PostFavoriteService;
import com.bao.dating.service.PostService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
@RestController
@@ -34,11 +31,4 @@ public class PostFavoriteController {
Long userId = user.getUserId();
return postFavoriteService.deletePostFavorite(userId, postId);
}
@GetMapping("/{user_id}/favorites")
public Result<List<Post>> getFavorites(@PathVariable("user_id")Long postId){
if (postId == null){
return Result.error(ResultCode.PARAM_ERROR);
}
return postFavoriteService.getAllFavoritePost(postId);
}
}

View File

@@ -2,11 +2,17 @@ package com.bao.dating.controller;
import com.bao.dating.common.Result;
import com.bao.dating.common.ResultCode;
import com.bao.dating.context.UserContext;
import com.bao.dating.pojo.dto.UserLoginDTO;
import com.bao.dating.pojo.entity.User;
import com.bao.dating.pojo.vo.UserInfoVO;
import com.bao.dating.pojo.vo.UserLoginVO;
import com.bao.dating.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@RestController
@RequestMapping("/user")
@@ -26,23 +32,35 @@ public class UserController {
}
/**
* 用户注册
* @param userAccount 用户名称
* @param userPassword 用户密码
* @return 用户id
* 获取用户信息
* @return 用户信息
*/
@PostMapping("/userRegister")
public Result userRegister(String userAccount, String userPassword){
long result = userService.userRegister(userAccount, userPassword);
if (result == -1){
return Result.error(ResultCode.SYSTEM_ERROR);
}
if (result==-2){
return Result.error(ResultCode.PARAM_ERROR);
}
if (result == -3){
return Result.error(ResultCode.FAIL,"用户名称相同");
}
return Result.success(ResultCode.SUCCESS,"注册成功",result);
@GetMapping("/info")
public Result<UserInfoVO> getUserInfo() {
Long userId = UserContext.getUserId();
UserInfoVO userInfoVO = userService.getUserInfo(userId);
return Result.success(ResultCode.SUCCESS, "获取用户信息成功", userInfoVO);
}
/**
* 上传头像接口
* @param file 头像文件
* @return 上传后的文件URL列表
*/
@PostMapping(value = "/info/uploadAvatar", consumes = "multipart/form-data")
public Result<String> uploadAvatar(@RequestParam("file") MultipartFile file) {
String fileUrl = userService.uploadAvatar(file);
return Result.success(ResultCode.SUCCESS_REVIEW, "头像上传成功", fileUrl);
}
/**
* 上传背景接口
* @param file 背景文件
* @return 上传后的文件URL列表
*/
@PostMapping(value = "/info/uploadBackground", consumes = "multipart/form-data")
public Result<String> uploadBackground(@RequestParam("file") MultipartFile file) {
String fileUrl = userService.uploadBackground(file);
return Result.success(ResultCode.SUCCESS_REVIEW, "背景上传成功", fileUrl);
}
}

View File

@@ -1,6 +1,5 @@
package com.bao.dating.mapper;
import com.bao.dating.pojo.entity.Post;
import com.bao.dating.pojo.entity.PostFavorite;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@@ -13,5 +12,4 @@ public interface PostFavoriteMapper {
List<Long> selectUserIDByPostID(@Param("postId") Long postId);
int addPostFavorite(PostFavorite postFavorite);
int deletePostFavorite(@Param("postId") Long postId);
List<Post> getAllPost(@Param("userId") Long userId);
}

View File

@@ -20,7 +20,7 @@ public interface PostMapper {
*
* @param postIds 动态ID
*/
int deletePostByIds(@Param("postIds") List<Long> postIds);
int deletePostByIds(List<Long> postIds);
/**
* 根据ID查询动态
@@ -28,7 +28,7 @@ public interface PostMapper {
* @param postId
* @return
*/
Post selectById(@Param("postId") Long postId);
Post selectById(Long postId);
/**
* 根据ID更新动态

View File

@@ -2,6 +2,7 @@ package com.bao.dating.mapper;
import com.bao.dating.pojo.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface UserMapper {
@@ -15,10 +16,10 @@ public interface UserMapper {
User getByUsername(String username);
/**
* 添加用户
* @param user 用户对象
* @return 受影响行数
* 根据用户id查询用户信息
*
* @param userid 用户id
* @return 用户
*/
Long insertUser(User user);
long getMaxUserId();
User selectByUserId(Long userid);
}

View File

@@ -0,0 +1,24 @@
package com.bao.dating.pojo.vo;
import lombok.Data;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
/**
* 用户信息VO
*/
@Data
public class UserInfoVO {
private Long userId;
private String nickname;
private String avatarUrl;
private String backgroundUrl;
private Integer gender;
private LocalDate birthday;
private List<String> hobbies;
private String signature;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}

View File

@@ -1,13 +1,10 @@
package com.bao.dating.service;
import com.bao.dating.common.Result;
import com.bao.dating.pojo.entity.Post;
import java.util.List;
import java.util.Map;
public interface PostFavoriteService {
Result<Map<String,Long>> postFavorite(Long userid,Long postId);
Result<?> deletePostFavorite(Long userid,Long postId);
Result<List<Post>> getAllFavoritePost(Long userId);
}

View File

@@ -1,7 +1,12 @@
package com.bao.dating.service;
import com.bao.dating.pojo.dto.UserLoginDTO;
import com.bao.dating.pojo.vo.PostEditVO;
import com.bao.dating.pojo.vo.UserInfoVO;
import com.bao.dating.pojo.vo.UserLoginVO;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
public interface UserService {
/**
@@ -10,5 +15,24 @@ public interface UserService {
* @return 登录结果
*/
UserLoginVO userLogin(UserLoginDTO userLoginDTO);
long userRegister(String userAccount, String userPassword);
/**
* 查询个人信息
* @param userId 动态ID
*/
UserInfoVO getUserInfo(Long userId);
/**
* 上传头像
* @param file 头像文件
* @return 上传后的文件URL列表
*/
String uploadAvatar(MultipartFile file);
/**
* 上传背景
* @param file 背景文件
* @return 上传后的文件URL列表
*/
String uploadBackground(MultipartFile file);
}

View File

@@ -4,7 +4,6 @@ import com.bao.dating.common.Result;
import com.bao.dating.common.ResultCode;
import com.bao.dating.mapper.PostFavoriteMapper;
import com.bao.dating.mapper.PostMapper;
import com.bao.dating.pojo.entity.Post;
import com.bao.dating.pojo.entity.PostFavorite;
import com.bao.dating.service.PostFavoriteService;
import org.springframework.beans.factory.annotation.Autowired;
@@ -59,10 +58,4 @@ public class PostFavoriteServiceImpl implements PostFavoriteService {
postMapper.decreaseFavoriteCount(postId);
return null;
}
@Override
public Result<List<Post>> getAllFavoritePost(Long userId) {
List<Post> result = postFavoriteMapper.getAllPost(userId);
return Result.success(ResultCode.SUCCESS,"查询成功",result);
}
}

View File

@@ -20,10 +20,7 @@ import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.*;
/**
* 动态服务实现类
@@ -52,34 +49,55 @@ public class PostServiceImpl implements PostService {
*/
@Override
public List<String> uploadMedia(MultipartFile[] files) {
// 如果没有文件,则返回空列表
if (files == null || files.length == 0) {
return Collections.emptyList();
}
// 创建媒体文件列表
List<String> mediaUrls = new ArrayList<>();
if (files != null && files.length > 0) {
for (MultipartFile file : files) {
if (!file.isEmpty()) {
// 跳过空文件
if (file == null || file.isEmpty()) {
continue;
}
// 获取文件名并跳过空文件
String originalFilename = file.getOriginalFilename();
if (originalFilename == null) {
continue;
}
// 校验文件类型
String fileType = FileUtil.getFileType(originalFilename);
if (!"image".equals(fileType) && !"video".equals(fileType)) {
throw new RuntimeException("不支持的文件类型:" + originalFilename);
}
// 创建目录
String dir = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM"));
// 获取文件扩展名
String extension = FileUtil.getFileExtension(originalFilename);
// 生成唯一文件名
String newFileName = UUID.randomUUID().toString().replace("-", "") + "." + extension;
// 获取用户ID
Long userId = UserContext.getUserId();
// 创建文件名
String fileName = "post/" + userId + "/" + dir + "/" + newFileName;
try {
// 根据文件扩展名判断文件类型
String fileType = FileUtil.getFileType(file.getOriginalFilename());
// 创建目录
String dir = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM"));
// 生成唯一文件名
String newFileName = UUID.randomUUID().toString() + "." + FileUtil.getFileExtension(file.getOriginalFilename());
String fileName = "post/" + dir + "/" + newFileName;
// 获取文件字节数据
byte[] fileBytes = file.getBytes();
// 根据文件类型处理
String ossUrl = "";
if ("image".equals(fileType) || "video".equals(fileType)) {
// 上传图片或视频
ossUrl = ossUtil.upload(fileBytes, fileName);
// 上传图片或视频
String ossUrl = ossUtil.upload(fileBytes, fileName);
if (ossUrl == null || ossUrl.isEmpty()) {
throw new RuntimeException("文件上传失败:" + originalFilename);
}
// 添加上传后的 URL
mediaUrls.add(ossUrl);
} catch (IOException e) {
e.printStackTrace();
// 统一异常处理
throw new RuntimeException("上传媒体文件失败:" + originalFilename, e);
}
}
}
}
return mediaUrls;
}
@@ -188,7 +206,7 @@ public class PostServiceImpl implements PostService {
* 查询动态详情(用于编辑)
*
* @param postId 动态ID
* @return
* @return 动态详情
*/
@Override
public PostEditVO getPostForEdit(Long postId) {
@@ -210,7 +228,7 @@ public class PostServiceImpl implements PostService {
* 修改动态
* @param postId 动态ID
* @param postRequestDTO 修改的动态数据传输对象
* @return
* @return 修改的动态对象
*/
@Override
public PostEditVO updatePost(Long postId, PostRequestDTO postRequestDTO) {
@@ -225,9 +243,8 @@ public class PostServiceImpl implements PostService {
throw new RuntimeException("无权限修改此动态");
}
post.setContent(postRequestDTO.getContent());
if (postRequestDTO.getMediaOssKeys() != null && !postRequestDTO.getMediaOssKeys().isEmpty()) {
post.setMediaOssKeys(postRequestDTO.getMediaOssKeys());
}
// 如果请求中的mediaOssKeys不为null即使是空列表则更新为新值
post.setMediaOssKeys(postRequestDTO.getMediaOssKeys());
// 1. 文本内容审核
Map textResult;
@@ -239,11 +256,11 @@ public class PostServiceImpl implements PostService {
// 文本审核结果
String textSuggestion = (String) textResult.get("suggestion");
// 2. 图片审核(如果有)
if (postRequestDTO.getMediaOssKeys() != null && !postRequestDTO.getMediaOssKeys().isEmpty()) {
// 2. 图片审核(如果有媒体文件
if (post.getMediaOssKeys() != null && !post.getMediaOssKeys().isEmpty()) {
Map imageResult;
try {
imageResult = greenImageScan.imageScan(postRequestDTO.getMediaOssKeys());
imageResult = greenImageScan.imageScan(post.getMediaOssKeys());
} catch (Exception e) {
throw new RuntimeException(e);
}

View File

@@ -1,23 +1,40 @@
package com.bao.dating.service.impl;
import com.bao.dating.common.aliyun.AliOssUtil;
import com.bao.dating.context.UserContext;
import com.bao.dating.mapper.UserMapper;
import com.bao.dating.pojo.dto.UserLoginDTO;
import com.bao.dating.pojo.entity.User;
import com.bao.dating.pojo.vo.UserInfoVO;
import com.bao.dating.pojo.vo.UserLoginVO;
import com.bao.dating.service.UserService;
import com.bao.dating.util.FileUtil;
import com.bao.dating.util.JwtUtil;
import com.bao.dating.util.MD5Util;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.time.LocalDateTime;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.UUID;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private AliOssUtil ossUtil;
@Autowired
private UserMapper userMapper;
/**
* 用户登录
* @param userLoginDTO
* @return 登录信息
*/
@Override
public UserLoginVO userLogin(UserLoginDTO userLoginDTO) {
// 参数校验
@@ -49,36 +66,95 @@ public class UserServiceImpl implements UserService {
}
/**
* 用户注册
* @param userAccount 账户名称
* @param userPassword 密码
* @return 用户id
* 获取用户信息
* @param userId
* @return 用户信息
*/
@Override
public long userRegister(String userAccount, String userPassword) {
//验证非空
if (userAccount.isEmpty() ||userPassword.isEmpty()){
return -2;
public UserInfoVO getUserInfo(Long userId) {
User user = userMapper.selectByUserId(userId);
if (user == null){
throw new RuntimeException("用户不存在");
}
//校验账户不能重复
User resultUser = userMapper.getByUsername(userAccount);
if (resultUser!=null){
return -3;
UserInfoVO userInfoVO = new UserInfoVO();
BeanUtils.copyProperties(user, userInfoVO);
return userInfoVO;
}
@Override
public String uploadAvatar(MultipartFile file) {
// 参数校验
if (file == null || file.isEmpty()) {
throw new RuntimeException("图片不存在");
}
//对密码进行加密
String encryptPassword = MD5Util.encryptWithSalt(userPassword, "yujian");
long maxUserId = userMapper.getMaxUserId();
User user = new User();
user.setUserId(maxUserId+1);
user.setUserName(userAccount);
user.setSalt("yujian");
user.setPasswordHash(encryptPassword);
user.setCreatedAt(LocalDateTime.now());
user.setUpdatedAt(LocalDateTime.now());
Long result = userMapper.insertUser(user);
if (result < 0){
return -1;
String originalFilename = file.getOriginalFilename();
if (originalFilename == null) {
throw new RuntimeException("文件名非法");
}
String fileType = FileUtil.getFileType(originalFilename);
if (!"image".equals(fileType)) {
throw new RuntimeException("仅支持图片上传");
}
//生成 OSS 路径
String dir = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM"));
String extension = FileUtil.getFileExtension(originalFilename);
String fileName = UUID.randomUUID().toString().replace("-", "") + "." + extension;
Long userId = UserContext.getUserId();
String objectKey = "user/" + userId + "/avatar/" + fileName;
try {
byte[] fileBytes = file.getBytes();
String ossUrl = ossUtil.upload(fileBytes, objectKey);
if (ossUrl == null || ossUrl.isEmpty()) {
throw new RuntimeException("图片上传失败");
}
return ossUrl;
} catch (Exception e) {
throw new RuntimeException("上传图片失败", e);
}
}
@Override
public String uploadBackground(MultipartFile file) {
// 参数校验
if (file == null || file.isEmpty()) {
throw new RuntimeException("图片不存在");
}
String originalFilename = file.getOriginalFilename();
if (originalFilename == null) {
throw new RuntimeException("文件名非法");
}
String fileType = FileUtil.getFileType(originalFilename);
if (!"image".equals(fileType)) {
throw new RuntimeException("仅支持图片上传");
}
//生成 OSS 路径
String extension = FileUtil.getFileExtension(originalFilename);
String fileName = UUID.randomUUID().toString().replace("-", "") + "." + extension;
Long userId = UserContext.getUserId();
String objectKey = "user/" + userId + "/background/" + fileName;
try {
byte[] fileBytes = file.getBytes();
String ossUrl = ossUtil.upload(fileBytes, objectKey);
if (ossUrl == null || ossUrl.isEmpty()) {
throw new RuntimeException("图片上传失败");
}
return ossUrl;
} catch (Exception e) {
throw new RuntimeException("上传图片失败", e);
}
return user.getUserId();
}
}

View File

@@ -14,8 +14,4 @@
<select id="selectUserIDByPostID" resultType="java.lang.Long">
SELECT user_id FROM post_favorite WHERE post_id = #{postId}
</select>
<!--查询用户收藏的所有动态-->
<select id="getAllPost" resultType="com.bao.dating.pojo.entity.Post">
select * from post where post_id in (select post_id from post_favorite where user_id=#{userId})
</select>
</mapper>

View File

@@ -3,15 +3,44 @@
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bao.dating.mapper.UserMapper">
<insert id="insertUser" useGeneratedKeys="true" parameterType="com.bao.dating.pojo.entity.User">
insert into user(user_id,user_name,salt,password_hash,created_at,updated_at) values (#{userId},#{userName},#{salt},#{passwordHash},#{createdAt},#{updatedAt})
</insert>
<!--根据用户名查询用户-->
<select id="getByUsername" resultType="com.bao.dating.pojo.entity.User">
SELECT * FROM user WHERE user_name = #{userName}
SELECT
user_id,
user_name,
password_hash,
salt,
nickname
FROM user WHERE user_name = #{userName}
</select>
<select id="getMaxUserId" resultType="java.lang.Long">
SELECT IFNULL(MAX(user_id), 0) AS max_id FROM user;
<!--根据用户id查询用户信息-->
<resultMap id="UserResultMap" type="com.bao.dating.pojo.entity.User">
<id property="userId" column="user_id"/>
<result property="nickname" column="nickname"/>
<result property="avatarUrl" column="avatar_url"/>
<result property="backgroundUrl" column="background_url"/>
<result property="gender" column="gender"/>
<result property="birthday" column="birthday"/>
<result property="hobbies" column="hobbies" typeHandler="com.bao.dating.handler.ListToVarcharTypeHandler"/>
<result property="signature" column="signature"/>
<result property="createdAt" column="created_at"/>
<result property="updatedAt" column="updated_at"/>
</resultMap>
<select id="selectByUserId" resultMap="UserResultMap">
SELECT
user_id,
nickname,
avatar_url,
background_url,
gender,
birthday,
hobbies,
signature,
created_at,
updated_at
FROM user WHERE user_id = #{userId}
</select>
</mapper>