From 34c73d2e2662be27a3aa2d2dd978af1c6a64105b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A1=BE=E5=90=9B=E7=A6=B9?= <2673609096@qq.com> Date: Sat, 16 Aug 2025 16:39:21 +0800 Subject: [PATCH 1/3] =?UTF-8?q?farm=E6=A8=A1=E5=9D=97-=E6=89=B9=E9=87=8F?= =?UTF-8?q?=E4=B8=8A=E4=BC=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/admin/file/FileController.java | 6 +++ .../infra/service/file/FileService.java | 11 +++++ .../infra/service/file/FileServiceImpl.java | 45 +++++++++++++++++++ 3 files changed, 62 insertions(+) diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java index afcf7162..1f5f0f93 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java @@ -50,6 +50,12 @@ public class FileController { uploadReqVO.getDirectory(), file.getContentType())); } + @PostMapping("/upload-multi") + @Operation(summary = "多文件上传", description = "批量上传多个文件") + public CommonResult uploadMultiFiles(@Valid FileMultiUploadReqVO uploadReqVO) throws Exception { + return success(fileService.createFiles(uploadReqVO.getFiles(), uploadReqVO.getDirectory())); + } + @GetMapping("/presigned-url") @Operation(summary = "获取文件预签名地址", description = "模式二:前端上传文件:用于前端直接上传七牛、阿里云 OSS 等文件存储器") @Parameters({ diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileService.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileService.java index 5b15ad87..13e36bb8 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileService.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileService.java @@ -4,8 +4,10 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FileCreateReqVO; import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePageReqVO; import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePresignedUrlRespVO; +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FileMultiUploadRespVO; import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO; import jakarta.validation.constraints.NotEmpty; +import org.springframework.web.multipart.MultipartFile; import java.util.List; @@ -36,6 +38,15 @@ public interface FileService { String createFile(@NotEmpty(message = "文件内容不能为空") byte[] content, String name, String directory, String type); + /** + * 批量上传文件 + * + * @param files 文件列表 + * @param directory 目录,允许空 + * @return 多文件上传结果 + */ + FileMultiUploadRespVO createFiles(List files, String directory); + /** * 生成文件预签名地址信息 * diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java index 98447fb3..65bf90bd 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java @@ -2,14 +2,19 @@ package cn.iocoder.yudao.module.infra.service.file; import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.io.FileUtil; +import cn.hutool.core.io.IoUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.digest.DigestUtil; +import org.springframework.web.multipart.MultipartFile; + +import java.util.ArrayList; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FileCreateReqVO; import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePageReqVO; import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePresignedUrlRespVO; +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FileMultiUploadRespVO; import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO; import cn.iocoder.yudao.module.infra.dal.mysql.file.FileMapper; import cn.iocoder.yudao.module.infra.framework.file.core.client.FileClient; @@ -92,6 +97,46 @@ public class FileServiceImpl implements FileService { return url; } + @Override + @SneakyThrows + public FileMultiUploadRespVO createFiles(List files, String directory) { + FileMultiUploadRespVO result = new FileMultiUploadRespVO(); + List successFiles = new ArrayList<>(); + List failedFiles = new ArrayList<>(); + + for (MultipartFile file : files) { + FileMultiUploadRespVO.FileUploadResult fileResult = new FileMultiUploadRespVO.FileUploadResult(); + fileResult.setOriginalName(file.getOriginalFilename()); + fileResult.setSize(file.getSize()); + fileResult.setType(file.getContentType()); + + try { + // 上传文件 + byte[] content = IoUtil.readBytes(file.getInputStream()); + String url = createFile(content, file.getOriginalFilename(), directory, file.getContentType()); + + // 设置成功结果 + fileResult.setUrl(url); + fileResult.setSuccess(true); + successFiles.add(fileResult); + } catch (Exception e) { + // 设置失败结果 + fileResult.setSuccess(false); + fileResult.setErrorMessage(e.getMessage()); + failedFiles.add(fileResult); + } + } + + // 设置统计信息 + result.setSuccessFiles(successFiles); + result.setFailedFiles(failedFiles); + result.setTotalCount(files.size()); + result.setSuccessCount(successFiles.size()); + result.setFailedCount(failedFiles.size()); + + return result; + } + @VisibleForTesting String generateUploadPath(String name, String directory) { // 1. 生成前缀、后缀 From c34abc4a03d9c82e3caffc7d6609d6943afc9486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A1=BE=E5=90=9B=E7=A6=B9?= <2673609096@qq.com> Date: Sat, 16 Aug 2025 17:31:46 +0800 Subject: [PATCH 2/3] =?UTF-8?q?farm=E6=A8=A1=E5=9D=97-=E6=89=B9=E9=87=8F?= =?UTF-8?q?=E4=B8=8A=E4=BC=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/admin/home/HomeController.java | 2 +- .../dataobject/deviceinfo/DeviceInfoDO.java | 112 +++++++++++- .../PestDiseaseWeedLibraryDO.java | 29 ++- .../ProductManagementDO.java | 57 +++++- .../specieslibrary/SpeciesLibraryDO.java | 29 ++- .../WeatherDisasterLibraryDO.java | 29 ++- .../framework/util/ImageCollectionUtil.java | 170 ++++++++++++++++++ .../controller/admin/file/FileController.java | 2 + .../infra/service/file/FileServiceImpl.java | 12 +- 9 files changed, 428 insertions(+), 14 deletions(-) create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/framework/util/ImageCollectionUtil.java diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/home/HomeController.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/home/HomeController.java index 432aab32..ce8dab7c 100644 --- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/home/HomeController.java +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/home/HomeController.java @@ -19,7 +19,7 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; * @author: binda * @date: 2025/8/14 19:43 */ -@Tag(name = "弄成首页") +@Tag(name = "农场首页") @RestController @RequestMapping("/farm/home") @Validated diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/dataobject/deviceinfo/DeviceInfoDO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/dataobject/deviceinfo/DeviceInfoDO.java index a52ae33c..1e3ff71b 100644 --- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/dataobject/deviceinfo/DeviceInfoDO.java +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/dataobject/deviceinfo/DeviceInfoDO.java @@ -6,9 +6,11 @@ import java.time.LocalDateTime; import java.time.LocalDateTime; import java.time.LocalDateTime; import java.time.LocalDateTime; +import java.util.List; import com.baomidou.mybatisplus.annotation.*; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.farm.framework.util.ImageCollectionUtil; /** * 设备信息 DO @@ -100,17 +102,40 @@ public class DeviceInfoDO extends BaseDO { */ private LocalDateTime updatedAt; /** - * 设备图片 + * 设备图片(数据库存储为逗号分隔的字符串) */ + @TableField(value = "image") private String image; + /** - * 告警状态图片 + * 设备图片集合(业务层使用) */ + @TableField(exist = false) + private List imageList; + + /** + * 告警状态图片(数据库存储为逗号分隔的字符串) + */ + @TableField(value = "alarm_image") private String alarmImage; + /** - * 离线状态图片 + * 告警状态图片集合(业务层使用) */ + @TableField(exist = false) + private List alarmImageList; + + /** + * 离线状态图片(数据库存储为逗号分隔的字符串) + */ + @TableField(value = "offline_image") private String offlineImage; + + /** + * 离线状态图片集合(业务层使用) + */ + @TableField(exist = false) + private List offlineImageList; /** * 分类图标 */ @@ -136,9 +161,16 @@ public class DeviceInfoDO extends BaseDO { */ private String edgeInstanceUniqueId; /** - * 数据快照 + * 数据快照(数据库存储为逗号分隔的字符串) */ + @TableField(value = "data_image") private String dataImage; + + /** + * 数据快照集合(业务层使用) + */ + @TableField(exist = false) + private List dataImageList; /** * 基地id */ @@ -157,4 +189,76 @@ public class DeviceInfoDO extends BaseDO { private String plotName; private String tenantId; + + /** + * 获取设备图片集合 + */ + public List getImageList() { + if (imageList == null) { + imageList = ImageCollectionUtil.toImageList(this.image); + } + return imageList; + } + + /** + * 设置设备图片集合 + */ + public void setImageList(List imageList) { + this.imageList = imageList; + this.image = ImageCollectionUtil.toDatabaseString(imageList); + } + + /** + * 获取告警状态图片集合 + */ + public List getAlarmImageList() { + if (alarmImageList == null) { + alarmImageList = ImageCollectionUtil.toImageList(this.alarmImage); + } + return alarmImageList; + } + + /** + * 设置告警状态图片集合 + */ + public void setAlarmImageList(List alarmImageList) { + this.alarmImageList = alarmImageList; + this.alarmImage = ImageCollectionUtil.toDatabaseString(alarmImageList); + } + + /** + * 获取离线状态图片集合 + */ + public List getOfflineImageList() { + if (offlineImageList == null) { + offlineImageList = ImageCollectionUtil.toImageList(this.offlineImage); + } + return offlineImageList; + } + + /** + * 设置离线状态图片集合 + */ + public void setOfflineImageList(List offlineImageList) { + this.offlineImageList = offlineImageList; + this.offlineImage = ImageCollectionUtil.toDatabaseString(offlineImageList); + } + + /** + * 获取数据快照集合 + */ + public List getDataImageList() { + if (dataImageList == null) { + dataImageList = ImageCollectionUtil.toImageList(this.dataImage); + } + return dataImageList; + } + + /** + * 设置数据快照集合 + */ + public void setDataImageList(List dataImageList) { + this.dataImageList = dataImageList; + this.dataImage = ImageCollectionUtil.toDatabaseString(dataImageList); + } } diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/dataobject/pestdiseaseweedlibrary/PestDiseaseWeedLibraryDO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/dataobject/pestdiseaseweedlibrary/PestDiseaseWeedLibraryDO.java index 2741c789..b3ce5e87 100644 --- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/dataobject/pestdiseaseweedlibrary/PestDiseaseWeedLibraryDO.java +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/dataobject/pestdiseaseweedlibrary/PestDiseaseWeedLibraryDO.java @@ -4,8 +4,10 @@ import lombok.*; import java.time.LocalDateTime; import java.time.LocalDateTime; +import java.util.List; import com.baomidou.mybatisplus.annotation.*; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.farm.framework.util.ImageCollectionUtil; /** * 病虫草害库维护 DO @@ -44,9 +46,16 @@ public class PestDiseaseWeedLibraryDO extends BaseDO { */ private String propose; /** - * 图片 + * 图片(数据库存储为逗号分隔的字符串) */ + @TableField(value = "images") private String images; + + /** + * 图片集合(业务层使用) + */ + @TableField(exist = false) + private List imageList; /** * 0=启用,1=停用 */ @@ -69,4 +78,22 @@ public class PestDiseaseWeedLibraryDO extends BaseDO { private String plotName; private String tenantId; + + /** + * 获取图片集合 + */ + public List getImageList() { + if (imageList == null) { + imageList = ImageCollectionUtil.toImageList(this.images); + } + return imageList; + } + + /** + * 设置图片集合 + */ + public void setImageList(List imageList) { + this.imageList = imageList; + this.images = ImageCollectionUtil.toDatabaseString(imageList); + } } \ No newline at end of file diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/dataobject/productmanagement/ProductManagementDO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/dataobject/productmanagement/ProductManagementDO.java index 3871410e..2a243ad9 100644 --- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/dataobject/productmanagement/ProductManagementDO.java +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/dataobject/productmanagement/ProductManagementDO.java @@ -4,8 +4,10 @@ import lombok.*; import java.time.LocalDateTime; import java.time.LocalDateTime; +import java.util.List; import com.baomidou.mybatisplus.annotation.*; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.farm.framework.util.ImageCollectionUtil; /** * 商品管理 DO @@ -44,9 +46,17 @@ public class ProductManagementDO extends BaseDO { */ private String packingUnit; /** - * 商品图片 + * 商品图片(数据库存储为逗号分隔的字符串) */ + @TableField(value = "image") private String image; + + /** + * 商品图片集合(业务层使用) + */ + @TableField(exist = false) + private List imageList; + /** * 商品介绍 */ @@ -64,9 +74,16 @@ public class ProductManagementDO extends BaseDO { */ private String brandName; /** - * 商标图片 + * 商标图片(数据库存储为逗号分隔的字符串) */ + @TableField(value = "brand_image") private String brandImage; + + /** + * 商标图片集合(业务层使用) + */ + @TableField(exist = false) + private List brandImageList; /** * 商品认证 */ @@ -89,4 +106,40 @@ public class ProductManagementDO extends BaseDO { private String plotName; private String tenantId; + + /** + * 获取商品图片集合 + */ + public List getImageList() { + if (imageList == null) { + imageList = ImageCollectionUtil.toImageList(this.image); + } + return imageList; + } + + /** + * 设置商品图片集合 + */ + public void setImageList(List imageList) { + this.imageList = imageList; + this.image = ImageCollectionUtil.toDatabaseString(imageList); + } + + /** + * 获取商标图片集合 + */ + public List getBrandImageList() { + if (brandImageList == null) { + brandImageList = ImageCollectionUtil.toImageList(this.brandImage); + } + return brandImageList; + } + + /** + * 设置商标图片集合 + */ + public void setBrandImageList(List brandImageList) { + this.brandImageList = brandImageList; + this.brandImage = ImageCollectionUtil.toDatabaseString(brandImageList); + } } diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/dataobject/specieslibrary/SpeciesLibraryDO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/dataobject/specieslibrary/SpeciesLibraryDO.java index 8cdb28ee..c3bed5e0 100644 --- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/dataobject/specieslibrary/SpeciesLibraryDO.java +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/dataobject/specieslibrary/SpeciesLibraryDO.java @@ -4,8 +4,10 @@ import lombok.*; import java.time.LocalDateTime; import java.time.LocalDateTime; +import java.util.List; import com.baomidou.mybatisplus.annotation.*; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.farm.framework.util.ImageCollectionUtil; /** * 物种库维护 DO @@ -48,9 +50,34 @@ public class SpeciesLibraryDO extends BaseDO { */ private Integer lifeCycle; /** - * 图片 + * 图片集合(数据库存储为逗号分隔的字符串) */ + @TableField(value = "image") private String image; + + /** + * 图片集合(业务层使用) + */ + @TableField(exist = false) + private List imageList; + + /** + * 获取图片集合 + */ + public List getImageList() { + if (imageList == null) { + imageList = ImageCollectionUtil.toImageList(this.image); + } + return imageList; + } + + /** + * 设置图片集合 + */ + public void setImageList(List imageList) { + this.imageList = imageList; + this.image = ImageCollectionUtil.toDatabaseString(imageList); + } /** * 0=启用,1=停用 */ diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/dataobject/weatherdisasterlibrary/WeatherDisasterLibraryDO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/dataobject/weatherdisasterlibrary/WeatherDisasterLibraryDO.java index d49fdadf..92f3ad01 100644 --- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/dataobject/weatherdisasterlibrary/WeatherDisasterLibraryDO.java +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/dataobject/weatherdisasterlibrary/WeatherDisasterLibraryDO.java @@ -4,9 +4,11 @@ import lombok.*; import java.time.LocalDateTime; import java.time.LocalDateTime; +import java.util.List; import com.baomidou.mybatisplus.annotation.*; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.farm.framework.util.ImageCollectionUtil; /** * 气象灾害库维护 DO @@ -41,9 +43,16 @@ public class WeatherDisasterLibraryDO extends BaseDO { */ private String propose; /** - * 图片 + * 图片(数据库存储为逗号分隔的字符串) */ + @TableField(value = "images") private String images; + + /** + * 图片集合(业务层使用) + */ + @TableField(exist = false) + private List imageList; /** * 0=启用,1=停用 */ @@ -66,4 +75,22 @@ public class WeatherDisasterLibraryDO extends BaseDO { private String plotName; private String tenantId; + + /** + * 获取图片集合 + */ + public List getImageList() { + if (imageList == null) { + imageList = ImageCollectionUtil.toImageList(this.images); + } + return imageList; + } + + /** + * 设置图片集合 + */ + public void setImageList(List imageList) { + this.imageList = imageList; + this.images = ImageCollectionUtil.toDatabaseString(imageList); + } } \ No newline at end of file diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/framework/util/ImageCollectionUtil.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/framework/util/ImageCollectionUtil.java new file mode 100644 index 00000000..60c6f794 --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/framework/util/ImageCollectionUtil.java @@ -0,0 +1,170 @@ +package cn.iocoder.yudao.module.farm.framework.util; + +import cn.hutool.core.util.StrUtil; +import lombok.extern.slf4j.Slf4j; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 图片集合转换工具类 + * 用于在数据库字符串(逗号分隔)和Java集合之间转换 + * + * @author 芋道源码 + */ +@Slf4j +public class ImageCollectionUtil { + + /** + * 分隔符 + */ + private static final String SEPARATOR = ","; + + /** + * 将图片集合转换为数据库存储的字符串 + * + * @param imageList 图片集合 + * @return 逗号分隔的字符串,如果集合为空则返回null + */ + public static String toDatabaseString(List imageList) { + if (imageList == null || imageList.isEmpty()) { + return null; + } + // 过滤空字符串并去重 + List filteredList = imageList.stream() + .filter(StrUtil::isNotBlank) + .distinct() + .collect(Collectors.toList()); + + if (filteredList.isEmpty()) { + return null; + } + + return String.join(SEPARATOR, filteredList); + } + + /** + * 将数据库字符串转换为图片集合 + * + * @param databaseString 数据库中的字符串 + * @return 图片集合,如果字符串为空则返回空集合 + */ + public static List toImageList(String databaseString) { + if (StrUtil.isBlank(databaseString)) { + return new ArrayList<>(); + } + + try { + return Arrays.stream(databaseString.split(SEPARATOR)) + .map(String::trim) + .filter(StrUtil::isNotBlank) + .distinct() + .collect(Collectors.toList()); + } catch (Exception e) { + log.error("转换图片集合失败,原始字符串: {}", databaseString, e); + return new ArrayList<>(); + } + } + + /** + * 将单个图片URL转换为集合(兼容旧数据) + * + * @param singleImage 单个图片URL + * @return 图片集合 + */ + public static List singleToImageList(String singleImage) { + if (StrUtil.isBlank(singleImage)) { + return new ArrayList<>(); + } + + // 如果已经是逗号分隔的格式,直接转换 + if (singleImage.contains(SEPARATOR)) { + return toImageList(singleImage); + } + + // 单个图片,包装成集合 + List imageList = new ArrayList<>(); + imageList.add(singleImage); + return imageList; + } + + /** + * 将图片集合转换为单个图片URL(兼容旧接口) + * 取第一个图片,如果没有则返回null + * + * @param imageList 图片集合 + * @return 第一个图片URL或null + */ + public static String imageListToSingle(List imageList) { + if (imageList == null || imageList.isEmpty()) { + return null; + } + return imageList.get(0); + } + + /** + * 验证图片集合是否有效 + * + * @param imageList 图片集合 + * @return 是否有效 + */ + public static boolean isValidImageList(List imageList) { + if (imageList == null) { + return false; + } + + // 检查是否有空字符串 + return imageList.stream().allMatch(StrUtil::isNotBlank); + } + + /** + * 获取图片集合的大小 + * + * @param imageList 图片集合 + * @return 图片数量 + */ + public static int getImageCount(List imageList) { + if (imageList == null) { + return 0; + } + return imageList.size(); + } + + /** + * 添加图片到集合 + * + * @param imageList 原图片集合 + * @param newImage 新图片URL + * @return 新的图片集合 + */ + public static List addImage(List imageList, String newImage) { + if (StrUtil.isBlank(newImage)) { + return imageList != null ? new ArrayList<>(imageList) : new ArrayList<>(); + } + + List result = imageList != null ? new ArrayList<>(imageList) : new ArrayList<>(); + if (!result.contains(newImage)) { + result.add(newImage); + } + return result; + } + + /** + * 从集合中移除图片 + * + * @param imageList 原图片集合 + * @param imageToRemove 要移除的图片URL + * @return 新的图片集合 + */ + public static List removeImage(List imageList, String imageToRemove) { + if (imageList == null || StrUtil.isBlank(imageToRemove)) { + return imageList != null ? new ArrayList<>(imageList) : new ArrayList<>(); + } + + List result = new ArrayList<>(imageList); + result.remove(imageToRemove); + return result; + } +} diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java index 1f5f0f93..8a076d8c 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java @@ -8,6 +8,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.*; +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FileMultiUploadReqVO; +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FileMultiUploadRespVO; import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO; import cn.iocoder.yudao.module.infra.service.file.FileService; import io.swagger.v3.oas.annotations.Operation; diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java index 65bf90bd..ad8eb218 100644 --- a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java @@ -9,6 +9,7 @@ import cn.hutool.crypto.digest.DigestUtil; import org.springframework.web.multipart.MultipartFile; import java.util.ArrayList; + import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FileCreateReqVO; @@ -41,13 +42,13 @@ public class FileServiceImpl implements FileService { /** * 上传文件的前缀,是否包含日期(yyyyMMdd) - * + *

* 目的:按照日期,进行分目录 */ static boolean PATH_PREFIX_DATE_ENABLE = true; /** * 上传文件的后缀,是否包含时间戳 - * + *

* 目的:保证文件的唯一性,避免覆盖 * 定制:可按需调整成 UUID、或者其他方式 */ @@ -109,16 +110,19 @@ public class FileServiceImpl implements FileService { fileResult.setOriginalName(file.getOriginalFilename()); fileResult.setSize(file.getSize()); fileResult.setType(file.getContentType()); - try { // 上传文件 byte[] content = IoUtil.readBytes(file.getInputStream()); String url = createFile(content, file.getOriginalFilename(), directory, file.getContentType()); - + // 设置成功结果 fileResult.setUrl(url); fileResult.setSuccess(true); successFiles.add(fileResult); + FileClient client = fileConfigService.getMasterFileClient(); + fileMapper.insert(new FileDO().setConfigId(client.getId()) + .setName(fileResult.getOriginalName()).setUrl(url) + .setType(fileResult.getType()).setSize((int) file.getSize())); } catch (Exception e) { // 设置失败结果 fileResult.setSuccess(false); From 626560d6e2d7a8dc86a7ab03039a66c9f80c4ff6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A1=BE=E5=90=9B=E7=A6=B9?= <2673609096@qq.com> Date: Sun, 17 Aug 2025 10:21:58 +0800 Subject: [PATCH 3/3] =?UTF-8?q?farm=E6=A8=A1=E5=9D=97-=E6=89=B9=E9=87=8F?= =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E5=AE=9E=E4=BD=93=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../file/vo/file/FileMultiUploadReqVO.java | 32 ++++++++++++ .../file/vo/file/FileMultiUploadRespVO.java | 51 +++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileMultiUploadReqVO.java create mode 100644 yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileMultiUploadRespVO.java diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileMultiUploadReqVO.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileMultiUploadReqVO.java new file mode 100644 index 00000000..b109b4e4 --- /dev/null +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileMultiUploadReqVO.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.infra.controller.admin.file.vo.file; + +import cn.hutool.core.util.StrUtil; +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.AssertTrue; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.Size; +import lombok.Data; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +@Schema(description = "管理后台 - 多文件上传 Request VO") +@Data +public class FileMultiUploadReqVO { + + @Schema(description = "文件附件列表", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "文件附件列表不能为空") + @Size(max = 10, message = "最多只能上传10个文件") + private List files; + + @Schema(description = "文件目录", example = "XXX/YYY") + private String directory; + + @AssertTrue(message = "文件目录不正确") + @JsonIgnore + public boolean isDirectoryValid() { + return !StrUtil.containsAny(directory, "..", "/", "\\"); + } + +} diff --git a/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileMultiUploadRespVO.java b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileMultiUploadRespVO.java new file mode 100644 index 00000000..3de93260 --- /dev/null +++ b/yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/file/FileMultiUploadRespVO.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.infra.controller.admin.file.vo.file; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Schema(description = "管理后台 - 多文件上传 Response VO") +@Data +public class FileMultiUploadRespVO { + + @Schema(description = "上传成功的文件列表") + private List successFiles; + + @Schema(description = "上传失败的文件列表") + private List failedFiles; + + @Schema(description = "总文件数") + private Integer totalCount; + + @Schema(description = "成功数量") + private Integer successCount; + + @Schema(description = "失败数量") + private Integer failedCount; + + @Schema(description = "管理后台 - 文件上传结果") + @Data + public static class FileUploadResult { + + @Schema(description = "原始文件名") + private String originalName; + + @Schema(description = "文件访问路径") + private String url; + + @Schema(description = "文件大小(字节)") + private Long size; + + @Schema(description = "文件类型") + private String type; + + @Schema(description = "错误信息") + private String errorMessage; + + @Schema(description = "是否上传成功") + private Boolean success; + + } + +}