图片上传

This commit is contained in:
huangge1199 2025-07-26 14:42:04 +08:00
parent f1e438327a
commit 9c0c536f57
15 changed files with 671 additions and 0 deletions

View File

@ -0,0 +1,50 @@
package com.huangge1199.picture.controller;
import com.huangge1199.picture.annotation.AuthCheck;
import com.huangge1199.picture.common.R;
import com.huangge1199.picture.constant.UserConstant;
import com.huangge1199.picture.model.dto.picture.PictureUploadRequest;
import com.huangge1199.picture.model.entity.User;
import com.huangge1199.picture.model.vo.PictureVO;
import com.huangge1199.picture.service.PictureService;
import com.huangge1199.picture.service.UserService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
/**
* 图片
*
* @author huangge1199
* @since 2025/7/26 14:36:52
*/
@RestController
@RequestMapping("/pic")
public class PictureController {
@Resource
private UserService userService;
@Resource
private PictureService pictureService;
/**
* 上传图片可重新上传
*/
@PostMapping("/upload")
@AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
public R<PictureVO> uploadPicture(
@RequestPart("file") MultipartFile multipartFile,
PictureUploadRequest pictureUploadRequest,
HttpServletRequest request) throws Exception {
User loginUser = userService.getLoginUser(request);
PictureVO pictureVO = pictureService.uploadPicture(multipartFile, pictureUploadRequest, loginUser);
return R.ok(pictureVO);
}
}

View File

@ -0,0 +1,18 @@
package com.huangge1199.picture.mapper;
import com.huangge1199.picture.model.Picture;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @author hyy
* @description 针对表picture(图片)的数据库操作Mapper
* @createDate 2025-07-26 11:04:44
* @Entity com.huangge1199.picture.model.Picture
*/
public interface PictureMapper extends BaseMapper<Picture> {
}

View File

@ -0,0 +1,97 @@
package com.huangge1199.picture.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.util.Date;
import lombok.Data;
/**
* 图片
* @author hyy
* @TableName picture
*/
@TableName(value ="picture")
@Data
public class Picture {
/**
* id
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
* 图片 url
*/
private String url;
/**
* 图片名称
*/
private String name;
/**
* 简介
*/
private String introduction;
/**
* 分类
*/
private String category;
/**
* 标签JSON 数组
*/
private String tags;
/**
* 图片体积
*/
private Long picSize;
/**
* 图片宽度
*/
private Integer picWidth;
/**
* 图片高度
*/
private Integer picHeight;
/**
* 图片宽高比例
*/
private Double picScale;
/**
* 图片格式
*/
private String picFormat;
/**
* 创建用户 id
*/
private Long userId;
/**
* 创建时间
*/
private Date createTime;
/**
* 编辑时间
*/
private Date editTime;
/**
* 更新时间
*/
private Date updateTime;
/**
* 是否删除
*/
private Integer isDelete;
}

View File

@ -0,0 +1,57 @@
package com.huangge1199.picture.model.dto.file;
import lombok.Data;
/**
* UploadPictureResult
*
* @author huangge1199
* @since 2025/7/26 13:24:59
*/
@Data
public class UploadPictureResult {
/**
* 图片地址
*/
private String url;
/**
* 缩略图 url
*/
private String thumbnailUrl;
/**
* 图片名称
*/
private String picName;
/**
* 文件体积
*/
private Long picSize;
/**
* 图片宽度
*/
private int picWidth;
/**
* 图片高度
*/
private int picHeight;
/**
* 图片宽高比
*/
private Double picScale;
/**
* 图片格式
*/
private String picFormat;
/**
* 图片主色调
*/
private String picColor;
}

View File

@ -0,0 +1,22 @@
package com.huangge1199.picture.model.dto.picture;
import lombok.Data;
import java.io.Serializable;
/**
* PictureUpdateRequest
*
* @author huangge1199
* @since 2025/7/26 11:18:05
*/
@Data
public class PictureUpdateRequest implements Serializable {
/**
* id
*/
private Long id;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,32 @@
package com.huangge1199.picture.model.dto.picture;
import lombok.Data;
import java.io.Serializable;
/**
* PictureUploadByBatchRequest
*
* @author huangge1199
* @since 2025/7/26 13:36:20
*/
@Data
public class PictureUploadByBatchRequest implements Serializable {
/**
* 搜索词
*/
private String searchText;
/**
* 抓取数量
*/
private Integer count = 10;
/**
* 图片名称前缀
*/
private String namePrefix;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,32 @@
package com.huangge1199.picture.model.dto.picture;
import lombok.Data;
import java.io.Serializable;
/**
* PictureUploadRequest
*
* @author huangge1199
* @since 2025/7/26 13:37:11
*/
@Data
public class PictureUploadRequest implements Serializable {
/**
* 图片 id用于修改
*/
private Long id;
/**
* 文件地址
*/
private String fileUrl;
/**
* 图片名称
*/
private String picName;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,151 @@
package com.huangge1199.picture.model.vo;
import cn.hutool.json.JSONUtil;
import com.huangge1199.picture.model.Picture;
import lombok.Data;
import org.springframework.beans.BeanUtils;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* PictureVO
*
* @author huangge1199
* @since 2025/7/26 13:23:02
*/
@Data
public class PictureVO implements Serializable {
/**
* id
*/
private Long id;
/**
* 图片 url
*/
private String url;
/**
* 缩略图 url
*/
private String thumbnailUrl;
/**
* 图片名称
*/
private String name;
/**
* 简介
*/
private String introduction;
/**
* 标签
*/
private List<String> tags;
/**
* 分类
*/
private String category;
/**
* 文件体积
*/
private Long picSize;
/**
* 图片宽度
*/
private Integer picWidth;
/**
* 图片高度
*/
private Integer picHeight;
/**
* 图片比例
*/
private Double picScale;
/**
* 图片格式
*/
private String picFormat;
/**
* 图片主色调
*/
private String picColor;
/**
* 用户 id
*/
private Long userId;
/**
* 空间 id
*/
private Long spaceId;
/**
* 创建时间
*/
private Date createTime;
/**
* 编辑时间
*/
private Date editTime;
/**
* 更新时间
*/
private Date updateTime;
/**
* 创建用户信息
*/
private UserVO user;
/**
* 权限列表
*/
private List<String> permissionList = new ArrayList<>();
private static final long serialVersionUID = 1L;
/**
* 封装类转对象
*/
public static Picture voToObj(PictureVO pictureVO) {
if (pictureVO == null) {
return null;
}
Picture picture = new Picture();
BeanUtils.copyProperties(pictureVO, picture);
// 类型不同需要转换
picture.setTags(JSONUtil.toJsonStr(pictureVO.getTags()));
return picture;
}
/**
* 对象转封装类
*/
public static PictureVO objToVo(Picture picture) {
if (picture == null) {
return null;
}
PictureVO pictureVO = new PictureVO();
BeanUtils.copyProperties(picture, pictureVO);
// 类型不同需要转换
pictureVO.setTags(JSONUtil.toList(picture.getTags(), String.class));
return pictureVO;
}
}

View File

@ -0,0 +1,30 @@
package com.huangge1199.picture.service;
import com.huangge1199.picture.model.Picture;
import com.baomidou.mybatisplus.extension.service.IService;
import com.huangge1199.picture.model.dto.picture.PictureUploadRequest;
import com.huangge1199.picture.model.entity.User;
import com.huangge1199.picture.model.vo.PictureVO;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
/**
* @author hyy
* @description 针对表picture(图片)的数据库操作Service
* @createDate 2025-07-26 11:04:44
*/
public interface PictureService extends IService<Picture> {
/**
* 上传图片
*
* @param multipartFile
* @param pictureUploadRequest
* @param loginUser
* @return
*/
PictureVO uploadPicture(MultipartFile multipartFile,
PictureUploadRequest pictureUploadRequest,
User loginUser) throws Exception;
}

View File

@ -0,0 +1,27 @@
package com.huangge1199.picture.service;
import com.huangge1199.picture.model.dto.picture.PictureUploadRequest;
import com.huangge1199.picture.model.entity.User;
import com.huangge1199.picture.model.vo.PictureVO;
import org.springframework.web.multipart.MultipartFile;
/**
* PictureSevice
*
* @author huangge1199
* @since 2025/7/26 13:34:02
*/
public interface PictureSevice {
/**
* 上传图片
*
* @param multipartFile
* @param pictureUploadRequest
* @param loginUser
* @return
*/
PictureVO uploadPicture(MultipartFile multipartFile,
PictureUploadRequest pictureUploadRequest,
User loginUser);
}

View File

@ -0,0 +1,90 @@
package com.huangge1199.picture.service.impl;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huangge1199.picture.exception.ErrorCode;
import com.huangge1199.picture.exception.ThrowUtils;
import com.huangge1199.picture.model.Picture;
import com.huangge1199.picture.model.dto.file.UploadPictureResult;
import com.huangge1199.picture.model.dto.picture.PictureUploadRequest;
import com.huangge1199.picture.model.entity.User;
import com.huangge1199.picture.model.vo.PictureVO;
import com.huangge1199.picture.service.PictureService;
import com.huangge1199.picture.mapper.PictureMapper;
import com.huangge1199.picture.utils.MinioUtil;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Date;
/**
* @author hyy
* @description 针对表picture(图片)的数据库操作Service实现
* @createDate 2025-07-26 11:04:44
*/
@Service
public class PictureServiceImpl extends ServiceImpl<PictureMapper, Picture>
implements PictureService {
@Resource
private MinioUtil minioUtil;
@Override
public PictureVO uploadPicture(MultipartFile multipartFile, PictureUploadRequest pictureUploadRequest, User loginUser) throws Exception {
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 originalFilename = multipartFile.getOriginalFilename();
String fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));
String url = minioUtil.upload(multipartFile.getInputStream(), fileExtension, multipartFile.getContentType());
String fileName = url.substring(url.lastIndexOf("/") + 1, url.lastIndexOf("."));
// 构造要入库的图片信息
Picture picture = new Picture();
picture.setUrl(url);
picture.setName(fileName);
BufferedImage image = ImageIO.read(multipartFile.getInputStream());
int width = image.getWidth();
int height = image.getHeight();
double scale = NumberUtil.round(width * 1.0 / height, 2).doubleValue();
picture.setPicSize(multipartFile.getSize());
picture.setPicWidth(width);
picture.setPicHeight(height);
picture.setPicScale(scale);
picture.setPicFormat(url.substring(url.lastIndexOf(".") + 1));
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);
}
}

View File

@ -0,0 +1,30 @@
package com.huangge1199.picture.utils;
import com.huangge1199.picture.exception.ErrorCode;
import com.huangge1199.picture.exception.ThrowUtils;
import com.huangge1199.picture.model.dto.file.UploadPictureResult;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.InputStream;
/**
* FileUtil
*
* @author huangge1199
* @since 2025/7/26 13:28:09
*/
@Component
public class FileUtil {
@Resource
private MinioUtil minioUtil;
public void validPicture(MultipartFile multipartFile) throws Exception {
ThrowUtils.throwIf(multipartFile == null, ErrorCode.PARAMS_ERROR, "文件不能为空!");
long fileSize = multipartFile.getSize();
final long ONE_M = 1024 * 1024L;
ThrowUtils.throwIf(fileSize > 2 * ONE_M, ErrorCode.PARAMS_ERROR, "文件大小不能超过2M");
}
}

View File

@ -2,6 +2,7 @@ package com.huangge1199.picture.utils;
import io.minio.*;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

View File

@ -13,6 +13,9 @@ spring:
password: 数据库密码
profiles:
active: local
servlet:
multipart:
max-file-size: 10MB
mybatis-plus:
configuration:
map-underscore-to-camel-case: false

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.huangge1199.picture.mapper.PictureMapper">
<resultMap id="BaseResultMap" type="com.huangge1199.picture.model.Picture">
<id property="id" column="id" />
<result property="url" column="url" />
<result property="name" column="name" />
<result property="introduction" column="introduction" />
<result property="category" column="category" />
<result property="tags" column="tags" />
<result property="picSize" column="picSize" />
<result property="picWidth" column="picWidth" />
<result property="picHeight" column="picHeight" />
<result property="picScale" column="picScale" />
<result property="picFormat" column="picFormat" />
<result property="userId" column="userId" />
<result property="createTime" column="createTime" />
<result property="editTime" column="editTime" />
<result property="updateTime" column="updateTime" />
<result property="isDelete" column="isDelete" />
</resultMap>
<sql id="Base_Column_List">
id,url,name,introduction,category,tags,
picSize,picWidth,picHeight,picScale,picFormat,
userId,createTime,editTime,updateTime,isDelete
</sql>
</mapper>