284 lines
10 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package edu.whut.smilepicturebackend.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import edu.whut.smilepicturebackend.annotation.AuthCheck;
import edu.whut.smilepicturebackend.common.BaseResponse;
import edu.whut.smilepicturebackend.common.ResultUtils;
import edu.whut.smilepicturebackend.constant.UserConstant;
import edu.whut.smilepicturebackend.exception.BusinessException;
import edu.whut.smilepicturebackend.exception.ErrorCode;
import edu.whut.smilepicturebackend.exception.ThrowUtils;
import edu.whut.smilepicturebackend.manager.auth.StpKit;
import edu.whut.smilepicturebackend.model.dto.user.UserAddRequest;
import edu.whut.smilepicturebackend.model.dto.user.UserQueryRequest;
import edu.whut.smilepicturebackend.model.entity.User;
import edu.whut.smilepicturebackend.model.enums.UserRoleEnum;
import edu.whut.smilepicturebackend.model.vo.LoginUserVO;
import edu.whut.smilepicturebackend.model.vo.UserVO;
import edu.whut.smilepicturebackend.service.UserService;
import edu.whut.smilepicturebackend.mapper.UserMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author 张三
* @description 针对表【user(用户)】的数据库操作Service实现
*/
@Service
@Slf4j
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
implements UserService{
private final BCryptPasswordEncoder passwordEncoder;
/**
* 用户注册
*
* @param userAccount 用户账户
* @param userPassword 用户密码
* @param checkPassword 校验密码
* @return
*/
@Override
public long userRegister(String userAccount, String userPassword, String checkPassword) {
// 1. 校验参数
if (StrUtil.hasBlank(userAccount, userPassword, checkPassword)) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");
}
if (userAccount.length() < 4) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户账号过短");
}
if (userPassword.length() < 8 || checkPassword.length() < 8) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户密码过短");
}
if (!userPassword.equals(checkPassword)) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "两次输入的密码不一致");
}
// 2. 检查用户账号是否和数据库中已有的重复
LambdaQueryWrapper<User> lambda = Wrappers.lambdaQuery();
lambda.eq(User::getUserAccount, userAccount);
long count = this.baseMapper.selectCount(lambda);
if (count > 0) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号重复");
}
// 3. 密码一定要加密
String encryptPassword = getEncryptPassword(userPassword);
// 4. 插入数据到数据库中
User user = new User();
user.setUserAccount(userAccount);
user.setUserPassword(encryptPassword);
user.setUserName("无名");
user.setUserRole(UserRoleEnum.USER.getValue());
boolean saveResult = this.save(user);
if (!saveResult) {
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "注册失败,数据库错误");
}
return user.getId();
}
/**
* 获取加密后的密码
*
* @param userPassword 用户密码
* @return 加密后的密码
*/
@Override
public String getEncryptPassword(String userPassword) {
return passwordEncoder.encode(userPassword);
// // 加盐,混淆密码
// final String SALT = "smile12306";
// return DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes());
}
@Override
public LoginUserVO userLogin(String userAccount, String userPassword, HttpServletRequest request) {
// 1. 校验
if (StrUtil.hasBlank(userAccount, userPassword)) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");
}
if (userAccount.length() < 4) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户账号错误");
}
if (userPassword.length() < 8) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户密码错误");
}
// 2. 根据账号查询用户(不带密码)
LambdaQueryWrapper<User> lambda = Wrappers.lambdaQuery();
lambda.eq(User::getUserAccount, userAccount);
User user = this.baseMapper.selectOne(lambda);
if (user == null) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户不存在或者密码错误");
}
// 3. 用 BCryptPasswordEncoder 去校验明文密码 vs 数据库里存的加密密码
if (!passwordEncoder.matches(userPassword, user.getUserPassword())) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户不存在或者密码错误");
}
// 4. 保存用户的登录态
request.getSession().setAttribute(UserConstant.USER_LOGIN_STATE, user);
// 记录用户登录态到 Sa-token便于空间鉴权时使用注意保证该用户信息与 SpringSession 中的信息过期时间一致
StpKit.SPACE.login(user.getId());
StpKit.SPACE.getSession().set(UserConstant.USER_LOGIN_STATE, user);
return this.getLoginUserVO(user);
}
/**
* 获取脱敏后的用户信息(无密码)
*
* @param user 用户
* @return 脱敏后的用户信息
*/
@Override
public LoginUserVO getLoginUserVO(User user) {
if (user == null) {
return null;
}
LoginUserVO loginUserVO = new LoginUserVO();
BeanUtil.copyProperties(user, loginUserVO);
return loginUserVO;
}
/**
* 获得脱敏后的用户信息(无密码、更新、编辑时间)
*
* @param user
* @return
*/
@Override
public UserVO getUserVO(User user) {
if (user == null) {
return null;
}
UserVO userVO = new UserVO();
BeanUtil.copyProperties(user, userVO);
return userVO;
}
/**
* 获取脱敏后的用户列表
*
* @param userList
* @return
*/
@Override
public List<UserVO> getUserVOList(List<User> userList) {
if (CollUtil.isEmpty(userList)) {
return new ArrayList<>();
}
return userList.stream()
.map(this::getUserVO)
.collect(Collectors.toList());
}
/**
* 获取当前登录用户
* @param request
* @return
*/
@Override
public User getLoginUser(HttpServletRequest request) {
// 判断是否已经登录
Object userObj = request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE);
User currentUser = (User) userObj;
if (currentUser == null || currentUser.getId() == null) {
throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
}
// // 从数据库中查询(追求性能的话可以注释,直接返回上述结果)
// Long userId = currentUser.getId();
// currentUser = this.getById(userId);
// if (currentUser == null) {
// throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
// }
return currentUser;
}
/**
* 退出登录
*
* @param request
* @return
*/
@Override
public boolean userLogout(HttpServletRequest request) {
// 判断是否已经登录
Object userObj = request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE);
if (userObj == null) {
throw new BusinessException(ErrorCode.OPERATION_ERROR, "未登录");
}
// 移除登录态
request.getSession().removeAttribute(UserConstant.USER_LOGIN_STATE);
return true;
}
/**
* 查询条件
* @param req
* @return
*/
@Override
public LambdaQueryWrapper<User> getQueryWrapper(UserQueryRequest req) {
if (req == null) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "请求参数为空");
}
LambdaQueryWrapper<User> qw = Wrappers.lambdaQuery(User.class);
// 基本等值和模糊匹配
qw.eq(ObjUtil.isNotNull(req.getId()), User::getId, req.getId())
.eq(StrUtil.isNotBlank(req.getUserRole()), User::getUserRole, req.getUserRole())
.like(StrUtil.isNotBlank(req.getUserAccount()), User::getUserAccount, req.getUserAccount())
.like(StrUtil.isNotBlank(req.getUserName()), User::getUserName, req.getUserName())
.like(StrUtil.isNotBlank(req.getUserProfile()), User::getUserProfile, req.getUserProfile());
// 动态排序
if (StrUtil.isNotBlank(req.getSortField())) {
String column = StrUtil.toUnderlineCase(req.getSortField());
boolean asc = "ascend".equalsIgnoreCase(req.getSortOrder());
qw.last("ORDER BY " + column + (asc ? " ASC" : " DESC"));
}
return qw;
}
@Override
public boolean isAdmin(User user) {
return user != null && UserRoleEnum.ADMIN.getValue().equals(user.getUserRole());
}
/**
* 创建用户
*/
@Override
public long createUser(UserAddRequest req) {
// 1. DTO -> entity
User user = new User();
BeanUtil.copyProperties(req, user);
// 2. 设定默认密码并加密
String encoded = passwordEncoder.encode(UserConstant.USER_DEFAULT);
user.setUserPassword(encoded);
// 3.插入数据库
boolean result = this.save(user);
ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
return user.getId();
}
}