package edu.whut.smilepicturebackend.service.impl; 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.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import edu.whut.smilepicturebackend.exception.ErrorCode; import edu.whut.smilepicturebackend.exception.ThrowUtils; import edu.whut.smilepicturebackend.manager.FileManager; import edu.whut.smilepicturebackend.mapper.PictureMapper; import edu.whut.smilepicturebackend.model.dto.picture.PictureQueryRequest; import edu.whut.smilepicturebackend.model.dto.picture.PictureUploadRequest; import edu.whut.smilepicturebackend.model.entity.Picture; import edu.whut.smilepicturebackend.model.entity.User; import edu.whut.smilepicturebackend.model.file.UploadPictureResult; import edu.whut.smilepicturebackend.model.vo.PictureVO; import edu.whut.smilepicturebackend.model.vo.UserVO; import edu.whut.smilepicturebackend.service.PictureService; import edu.whut.smilepicturebackend.service.UserService; import lombok.RequiredArgsConstructor; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; /** * @author 张三 * @description 针对表【picture(图片)】的数据库操作Service实现 * @createDate 2025-06-11 11:23:11 */ @Service @RequiredArgsConstructor public class PictureServiceImpl extends ServiceImpl implements PictureService { private final FileManager fileManager; private final UserService userService; @Override public void validPicture(Picture picture) { ThrowUtils.throwIf(picture == null, ErrorCode.PARAMS_ERROR); // 从对象中取值 Long id = picture.getId(); String url = picture.getUrl(); String introduction = picture.getIntroduction(); // 修改数据时,id 不能为空,有参数则校验 ThrowUtils.throwIf(ObjUtil.isNull(id), ErrorCode.PARAMS_ERROR, "id 不能为空"); // 如果传递了 url,才校验 if (StrUtil.isNotBlank(url)) { ThrowUtils.throwIf(url.length() > 1024, ErrorCode.PARAMS_ERROR, "url 过长"); } if (StrUtil.isNotBlank(introduction)) { ThrowUtils.throwIf(introduction.length() > 800, ErrorCode.PARAMS_ERROR, "简介过长"); } } @Override public PictureVO uploadPicture(MultipartFile multipartFile, PictureUploadRequest pictureUploadRequest, User loginUser) { // 校验参数 ThrowUtils.throwIf(loginUser == null, ErrorCode.NO_AUTH_ERROR); // 判断是新增还是删除 Long pictureId = null; if (pictureUploadRequest != null) { pictureId = pictureUploadRequest.getId(); } // 如果是更新,判断图片是否存在 if (pictureId != null) { boolean exists=this.lambdaQuery() .eq(Picture::getId,pictureId) .exists(); ThrowUtils.throwIf(!exists, ErrorCode.NOT_FOUND_ERROR, "图片不存在"); } // 上传图片,得到图片信息 String uploadPathPrefix; //公共图库下,每个用户有自己的userid管理的文件夹。 uploadPathPrefix = String.format("public/%s", loginUser.getId()); UploadPictureResult uploadPictureResult = fileManager.uploadPicture(multipartFile, uploadPathPrefix); // 构造要入库的图片信息 Picture picture = new Picture(); // 复制同名属性(url、name、picSize、picWidth、picHeight、picScale、picFormat) BeanUtils.copyProperties(uploadPictureResult, picture); picture.setUserId(loginUser.getId()); // 操作数据库 // 如果 pictureId 不为空,表示更新,否则是新增 if (pictureId != null) { // 如果是更新,需要补充 id 和编辑时间 picture.setId(pictureId); picture.setEditTime(new Date()); } boolean result = this.saveOrUpdate(picture); ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR, "图片上传失败,数据库操作失败"); return PictureVO.objToVo(picture); } @Override public LambdaQueryWrapper getQueryWrapper(PictureQueryRequest req) { LambdaQueryWrapper qw = Wrappers.lambdaQuery(Picture.class); if (req == null) { return qw; } // 精简版条件构造 qw.eq(ObjUtil.isNotEmpty(req.getId()), Picture::getId, req.getId()) .eq(ObjUtil.isNotEmpty(req.getUserId()), Picture::getUserId, req.getUserId()) .like(StrUtil.isNotBlank(req.getName()), Picture::getName, req.getName()) .like(StrUtil.isNotBlank(req.getIntroduction()), Picture::getIntroduction, req.getIntroduction()) .like(StrUtil.isNotBlank(req.getPicFormat()), Picture::getPicFormat, req.getPicFormat()) .eq(StrUtil.isNotBlank(req.getCategory()), Picture::getCategory, req.getCategory()) .eq(ObjUtil.isNotEmpty(req.getPicWidth()), Picture::getPicWidth, req.getPicWidth()) .eq(ObjUtil.isNotEmpty(req.getPicHeight()), Picture::getPicHeight, req.getPicHeight()) .eq(ObjUtil.isNotEmpty(req.getPicSize()), Picture::getPicSize, req.getPicSize()) .eq(ObjUtil.isNotEmpty(req.getPicScale()), Picture::getPicScale, req.getPicScale()) .ge(ObjUtil.isNotEmpty(req.getStartEditTime()), Picture::getEditTime, req.getStartEditTime()) .lt(ObjUtil.isNotEmpty(req.getEndEditTime()), Picture::getEditTime, req.getEndEditTime()); // 全字段模糊搜索 if (StrUtil.isNotBlank(req.getSearchText())) { qw.and(w -> w .like(Picture::getName, req.getSearchText()) .or() .like(Picture::getIntroduction, req.getSearchText()) ); } // JSON 数组 tags 查询 if (CollUtil.isNotEmpty(req.getTags())) { req.getTags().forEach(tag -> qw.like(Picture::getTags, "\"" + tag + "\"") ); } // 动态排序:转下划线字段名并手工拼接 if (StrUtil.isNotBlank(req.getSortField())) { String column = StrUtil.toUnderlineCase(req.getSortField()); String direction = "ascend".equalsIgnoreCase(req.getSortOrder()) ? "ASC" : "DESC"; qw.last("ORDER BY " + column + " " + direction); } return qw; } @Override public PictureVO getPictureVO(Picture picture, HttpServletRequest request) { // 对象转封装类 PictureVO pictureVO = PictureVO.objToVo(picture); // 关联查询用户信息 Long userId = picture.getUserId(); if (userId != null && userId > 0) { User user = userService.getById(userId); UserVO userVO = userService.getUserVO(user); pictureVO.setUser(userVO); } return pictureVO; } @Override public Page getPictureVOPage(Page picturePage, HttpServletRequest request) { List pictureList = picturePage.getRecords(); Page pictureVOPage = new Page<>(picturePage.getCurrent(), picturePage.getSize(), picturePage.getTotal()); if (CollUtil.isEmpty(pictureList)) { return pictureVOPage; } // 对象列表 => 封装对象列表 List pictureVOList = pictureList.stream() .map(PictureVO::objToVo) .collect(Collectors.toList()); // 1. 关联查询用户信息 // 1,2,3,4 Set userIdSet = pictureList.stream().map(Picture::getUserId).collect(Collectors.toSet()); // 1 => user1, 2 => user2 Map> userIdUserListMap = userService.listByIds(userIdSet).stream() .collect(Collectors.groupingBy(User::getId)); // 2. 填充信息 pictureVOList.forEach(pictureVO -> { Long userId = pictureVO.getUserId(); User user = null; if (userIdUserListMap.containsKey(userId)) { user = userIdUserListMap.get(userId).get(0); } pictureVO.setUser(userService.getUserVO(user)); }); pictureVOPage.setRecords(pictureVOList); return pictureVOPage; } }