Files
dating/src/main/java/com/bao/dating/service/impl/UserServiceImpl.java

376 lines
12 KiB
Java

package com.bao.dating.service.impl;
import com.bao.dating.common.Result;
import com.bao.dating.common.ResultCode;
import com.bao.dating.common.aliyun.AliOssUtil;
import com.bao.dating.common.aliyun.GreenImageScan;
import com.bao.dating.common.aliyun.GreenTextScan;
import com.bao.dating.common.result.AliOssResult;
import com.bao.dating.common.result.GreenAuditResult;
import com.bao.dating.config.RedisConfig;
import com.bao.dating.context.UserContext;
import com.bao.dating.mapper.UserMapper;
import com.bao.dating.pojo.dto.UserInfoUpdateDTO;
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.service.VerificationCodeService;
import com.bao.dating.util.FileUtil;
import com.bao.dating.util.JwtUtil;
import com.bao.dating.util.MD5Util;
import io.jsonwebtoken.Claims;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* 用户服务实现类
*
* @author KilLze
*/
@Service
public class UserServiceImpl implements UserService {
@Autowired
private AliOssUtil ossUtil;
@Autowired
private GreenTextScan greenTextScan;
@Autowired
private GreenImageScan greenImageScan;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private UserMapper userMapper;
@Autowired
private VerificationCodeService verificationCodeService;
/**
* 用户登录
*
* @param userLoginDTO 登录参数
* @return 登录信息
*/
@Override
public UserLoginVO userLogin(UserLoginDTO userLoginDTO) {
// 参数校验
if (userLoginDTO == null || userLoginDTO.getUsername() == null || userLoginDTO.getPassword() == null) {
throw new RuntimeException("用户名或密码不能为空");
}
// 查询用户
User user = userMapper.getByUsername(userLoginDTO.getUsername());
if (user == null) {
throw new RuntimeException("用户不存在");
}
// 密码校验
boolean match = MD5Util.verifyWithSalt(
userLoginDTO.getPassword(),
user.getSalt(),
user.getPasswordHash()
);
if (!match) {
throw new RuntimeException("密码错误");
}
// 生成token
String token = JwtUtil.generateToken(String.valueOf(user.getUserId()));
String redisKey = "login:token:" + user.getUserId();
redisTemplate.opsForValue().set(
redisKey,
token,
7,
TimeUnit.DAYS
);
// 封装返回
UserLoginVO userLoginVO = new UserLoginVO();
userLoginVO.setUserId(user.getUserId());
userLoginVO.setNickname(user.getNickname());
userLoginVO.setToken(token);
return userLoginVO;
}
/**
* 退出登录
* @param token 登录凭证
*/
@Override
public void logout(String token) {
Claims claims = JwtUtil.getClaimsFromToken(token);
Date expiration = claims.getExpiration();
// 判断 token 是否已过期
long ttl = expiration.getTime() - System.currentTimeMillis();
// 如果 token 已过期,则不用处理
if (ttl <= 0) {
return;
}
String logoutKey = "jwt:blacklist:" + token;
redisTemplate.opsForValue().set(
logoutKey,
"logout",
ttl,
TimeUnit.MILLISECONDS);
}
/**
* 获取用户信息
*
* @param userId 用户ID
* @return 用户信息
*/
@Override
public UserInfoVO getUserInfo(Long userId) {
User user = userMapper.selectByUserId(userId);
if (user == null) {
throw new RuntimeException("用户不存在");
}
UserInfoVO userInfoVO = new UserInfoVO();
BeanUtils.copyProperties(user, userInfoVO);
return userInfoVO;
}
/**
* 上传头像接口
*
* @param file 头像文件
* @return 上传后的文件URL
*/
@Override
public String uploadAvatar(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 (!AliOssResult.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 + "/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);
}
}
/**
* 上传背景图片
*
* @param file 背景图片文件
* @return 上传后的文件URL
*/
@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 (!AliOssResult.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);
}
}
/**
* 更新用户信息
*
* @param userInfoUpdateDTO 用户信息更新参数
*/
@Override
public UserInfoVO updateUserInfo(UserInfoUpdateDTO userInfoUpdateDTO) {
Long userId = userInfoUpdateDTO.getUserId();
User user = userMapper.selectByUserId(userId);
if (user == null) {
throw new RuntimeException("用户不存在");
}
// 将需要审核的内容合并成一个文本,用于减少调用次数
StringBuilder textBuilder = new StringBuilder();
if (userInfoUpdateDTO.getNickname() != null && !userInfoUpdateDTO.getNickname().isEmpty()) {
textBuilder.append(userInfoUpdateDTO.getNickname()).append(" ");
}
if (userInfoUpdateDTO.getHobbies() != null && !userInfoUpdateDTO.getHobbies().isEmpty()) {
// 将爱好列表转换为字符串,用空格分隔
String hobbiesStr = String.join(" ", userInfoUpdateDTO.getHobbies());
textBuilder.append(hobbiesStr).append(" ");
}
if (userInfoUpdateDTO.getSignature() != null && !userInfoUpdateDTO.getSignature().isEmpty()) {
textBuilder.append(userInfoUpdateDTO.getSignature()).append(" ");
}
// 文本审核
if (textBuilder.length() > 0) {
Map textResult;
try {
textResult = greenTextScan.greeTextScan(textBuilder.toString());
} catch (Exception e) {
throw new RuntimeException("用户信息文本审核失败");
}
String suggestion = (String) textResult.get("suggestion");
if (GreenAuditResult.BLOCK.equals(suggestion)) {
throw new RuntimeException("用户信息包含违规内容,修改失败");
}
if (GreenAuditResult.REVIEW.equals(suggestion)) {
throw new RuntimeException("用户信息需要人工审核,暂无法修改");
}
}
// 图片审核
List<String> imageKeys = new ArrayList<>();
if (userInfoUpdateDTO.getAvatarUrl() != null && !userInfoUpdateDTO.getAvatarUrl().isEmpty()) {
imageKeys.add(userInfoUpdateDTO.getAvatarUrl());
}
if (userInfoUpdateDTO.getBackgroundUrl() != null && !userInfoUpdateDTO.getBackgroundUrl().isEmpty()) {
imageKeys.add(userInfoUpdateDTO.getBackgroundUrl());
}
if (!imageKeys.isEmpty()) {
Map imageResult;
try {
imageResult = greenImageScan.imageScan(imageKeys);
} catch (Exception e) {
throw new RuntimeException("用户图片审核失败");
}
String suggestion = (String) imageResult.get("suggestion");
if (GreenAuditResult.BLOCK.equals(suggestion)) {
throw new RuntimeException("头像或背景图不合规,修改失败");
}
if (GreenAuditResult.REVIEW.equals(suggestion)) {
throw new RuntimeException("头像或背景图需要人工审核,暂无法修改");
}
}
// 默认昵称兜底
if (userInfoUpdateDTO.getNickname() == null || userInfoUpdateDTO.getNickname().trim().isEmpty()) {
userInfoUpdateDTO.setNickname(user.getUserName());
}
userInfoUpdateDTO.setUpdatedAt(LocalDateTime.now());
// 更新数据库
userMapper.updateUserInfoByUserId(userInfoUpdateDTO);
// 封装返回结果
User updatedUser = userMapper.selectByUserId(userInfoUpdateDTO.getUserId());
UserInfoVO userInfoVO = new UserInfoVO();
BeanUtils.copyProperties(updatedUser, userInfoVO);
return userInfoVO;
}
/**
* 查询用户
* @param userName 用户民称
* @return
*/
@Override
public Boolean registerUser(String userName,String userPassword) {
//校验参数是否为空
if (userName.isEmpty() || userPassword.isEmpty()){
return false;
}
//产看数据库是否存在已注册用户
User user = userMapper.getByUsername(userName);
if (user != null){
return false;
}
//将用户数据存入苏数据库
String salt = "lyy123";
String passwordHash = MD5Util.encryptWithSalt(userPassword, salt);
//查询最大用户id
Long maxId = userMapper.selectMaxId();
User saveUser = new User();
saveUser.setUserId(maxId+1);
saveUser.setUserName(userName);
saveUser.setPasswordHash(passwordHash);
saveUser.setSalt(salt);
saveUser.setUpdatedAt(LocalDateTime.now());
saveUser.setCreatedAt(LocalDateTime.now());
int count = userMapper.saveUser(saveUser);
return count > 0;
}
/**
* 邮箱登录
* @param email 邮箱
* @param code 验证码
* @return 脱敏用户信息
*/
@Override
public UserLoginVO emailLogin(String email, String code) {
User user = userMapper.selectByUserEmailUser(email);
if (user == null)
return null;
boolean flag = verificationCodeService.verifyEmailCode(email, code);
if (!flag)
return null;
// 生成token
String token = JwtUtil.generateToken(String.valueOf(user.getUserId()));
UserLoginVO userLoginVO = new UserLoginVO();
userLoginVO.setUserId(user.getUserId());
userLoginVO.setNickname(user.getNickname());
userLoginVO.setToken(token);
return userLoginVO;
}
}