From e1458e937ba69362c78f05b641c5f3a1e8b43798 Mon Sep 17 00:00:00 2001 From: chen-xin-zhi <3588068430@qq.com> Date: Tue, 6 May 2025 19:15:01 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=87=E4=BB=B6=E6=A8=A1=E5=9D=97=E5=88=9D?= =?UTF-8?q?=E6=AD=A5=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../promotion/aop/OperateLogAspect.java | 10 +- .../fileInfo/FileInfoController.java | 89 ++++++++++ .../controller/project/ProjectController.java | 2 + .../promotion/generator/Generator.java | 8 +- .../promotion/mapper/FileInfoMapper.java | 18 ++ .../dto/fileInfo/FileInfoAddRequest.java | 78 +++++++++ .../dto/fileInfo/FileInfoQueryRequest.java | 40 +++++ .../dto/fileInfo/FileInfoUpdateRequest.java | 80 +++++++++ .../model/dto/fileInfo/UploadFileRequest.java | 25 +++ .../promotion/model/entity/FileInfo.java | 71 ++++++++ .../model/enums/FileUploadBizEnum.java | 51 ++++++ .../model/enums/ProjectStatusEnum.java | 3 + .../model/vo/fileInfo/FileInfoVO.java | 62 +++++++ .../service/file/FileInfoService.java | 35 ++++ .../file/impl/FileInfoServiceImpl.java | 162 ++++++++++++++++++ src/main/resources/application.yml | 1 - src/main/resources/mapper/FileInfoMapper.xml | 26 +++ .../resources/templates/controller.java.vm | 4 +- .../templates/dto/QueryRequest.java.vm | 12 +- .../templates/dto/UpdateRequest.java.vm | 6 +- src/main/resources/templates/vo/VO.java.vm | 4 +- 21 files changed, 763 insertions(+), 24 deletions(-) create mode 100644 src/main/java/com/greenorange/promotion/controller/fileInfo/FileInfoController.java create mode 100644 src/main/java/com/greenorange/promotion/mapper/FileInfoMapper.java create mode 100644 src/main/java/com/greenorange/promotion/model/dto/fileInfo/FileInfoAddRequest.java create mode 100644 src/main/java/com/greenorange/promotion/model/dto/fileInfo/FileInfoQueryRequest.java create mode 100644 src/main/java/com/greenorange/promotion/model/dto/fileInfo/FileInfoUpdateRequest.java create mode 100644 src/main/java/com/greenorange/promotion/model/dto/fileInfo/UploadFileRequest.java create mode 100644 src/main/java/com/greenorange/promotion/model/entity/FileInfo.java create mode 100644 src/main/java/com/greenorange/promotion/model/enums/FileUploadBizEnum.java create mode 100644 src/main/java/com/greenorange/promotion/model/vo/fileInfo/FileInfoVO.java create mode 100644 src/main/java/com/greenorange/promotion/service/file/FileInfoService.java create mode 100644 src/main/java/com/greenorange/promotion/service/file/impl/FileInfoServiceImpl.java create mode 100644 src/main/resources/mapper/FileInfoMapper.xml diff --git a/src/main/java/com/greenorange/promotion/aop/OperateLogAspect.java b/src/main/java/com/greenorange/promotion/aop/OperateLogAspect.java index d11a4a3..2573fa8 100644 --- a/src/main/java/com/greenorange/promotion/aop/OperateLogAspect.java +++ b/src/main/java/com/greenorange/promotion/aop/OperateLogAspect.java @@ -3,10 +3,12 @@ package com.greenorange.promotion.aop; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.greenorange.promotion.annotation.SysLog; +import com.greenorange.promotion.model.dto.fileInfo.UploadFileRequest; import com.greenorange.promotion.model.entity.SysOperLog; import com.greenorange.promotion.service.log.SysOperLogService; import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.*; import org.aspectj.lang.reflect.MethodSignature; @@ -30,6 +32,7 @@ import java.util.Map; */ @Aspect @Component +@Slf4j public class OperateLogAspect { @Resource @@ -170,14 +173,11 @@ public class OperateLogAspect { for (Object o : paramsArray) { if (o != null) { try { - // 排除掉 RequestFacade 类型的对象 - if (o instanceof org.apache.catalina.connector.RequestFacade) { - continue; // 跳过该对象 - } Object jsonObj = JSON.toJSON(o); params += jsonObj.toString() + " "; } catch (Exception e) { - e.printStackTrace(); +// e.printStackTrace(); + log.warn("JSON参数解析出现异常"); } } } diff --git a/src/main/java/com/greenorange/promotion/controller/fileInfo/FileInfoController.java b/src/main/java/com/greenorange/promotion/controller/fileInfo/FileInfoController.java new file mode 100644 index 0000000..ed3bf48 --- /dev/null +++ b/src/main/java/com/greenorange/promotion/controller/fileInfo/FileInfoController.java @@ -0,0 +1,89 @@ +package com.greenorange.promotion.controller.fileInfo; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.greenorange.promotion.annotation.RequiresPermission; +import com.greenorange.promotion.annotation.SysLog; +import com.greenorange.promotion.common.BaseResponse; +import com.greenorange.promotion.common.ErrorCode; +import com.greenorange.promotion.common.ResultUtils; +import com.greenorange.promotion.constant.UserConstant; +import com.greenorange.promotion.exception.BusinessException; +import com.greenorange.promotion.exception.ThrowUtils; +import com.greenorange.promotion.model.dto.CommonBatchRequest; +import com.greenorange.promotion.model.dto.fileInfo.FileInfoAddRequest; +import com.greenorange.promotion.model.dto.fileInfo.FileInfoQueryRequest; +import com.greenorange.promotion.model.dto.fileInfo.FileInfoUpdateRequest; +import com.greenorange.promotion.model.dto.fileInfo.UploadFileRequest; +import com.greenorange.promotion.model.entity.FileInfo; +import com.greenorange.promotion.model.vo.fileInfo.FileInfoVO; +import com.greenorange.promotion.service.common.CommonService; +import com.greenorange.promotion.service.file.FileInfoService; +import com.greenorange.promotion.utils.RegexUtils; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotBlank; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.greenorange.promotion.model.dto.CommonRequest; +import jakarta.validation.Valid; +import org.springframework.web.multipart.MultipartFile; + +import java.io.*; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.List; + + +/** + * 文件 控制器 + */ +@RestController +@RequestMapping("fileInfo") +@Slf4j +@Tag(name = "文件管理") +public class FileInfoController { + + + @Resource + private FileInfoService fileInfoService; + + + + + /** + * Web端文件上传(服务器) + * @param uploadFileRequest 业务请求 + * @param multipartFile 上传的文件 + * @return 上传文件的路径 + */ + @PostMapping("upload") + @Operation(summary = "Web端文件上传(服务器)", description = "参数:文件添加请求体,权限:管理员,方法名:addFileInfo") + @SysLog(title = "文件管理", content = "Web端文件上传(服务器)") + public BaseResponse uploadFile(@RequestPart("file") MultipartFile multipartFile, UploadFileRequest uploadFileRequest) { + // 校验文件 + fileInfoService.validFile(multipartFile); + // 文件上传 + String view = fileInfoService.uploadFile(multipartFile, uploadFileRequest); + return ResultUtils.success(view, "上传成功"); + } + + + + + + /** + * 文件下载(服务器) + * @param filename 文件名 + * @throws IOException + */ + @GetMapping("/download") + @Operation(summary = "文件下载(服务器)", description = "参数:文件名,权限:所有人,方法名:downloadFile") + public void downloadFile(@RequestParam @NotBlank String filename, HttpServletResponse response) throws IOException { + fileInfoService.downloadFile(filename, response); + } + +} \ No newline at end of file diff --git a/src/main/java/com/greenorange/promotion/controller/project/ProjectController.java b/src/main/java/com/greenorange/promotion/controller/project/ProjectController.java index 4f1f3ec..64aae15 100644 --- a/src/main/java/com/greenorange/promotion/controller/project/ProjectController.java +++ b/src/main/java/com/greenorange/promotion/controller/project/ProjectController.java @@ -53,6 +53,8 @@ public class ProjectController { */ @PostMapping("add") @Operation(summary = "web端管理员添加项目", description = "参数:项目添加请求体,权限:管理员,方法名:addProject") + @RequiresPermission(mustRole = UserConstant.ADMIN_ROLE) + @SysLog(title = "项目管理", content = "web端管理员添加项目") public BaseResponse addProject(@Valid @RequestBody ProjectAddRequest projectAddRequest) { Project project = commonService.copyProperties(projectAddRequest, Project.class); projectService.save(project); diff --git a/src/main/java/com/greenorange/promotion/generator/Generator.java b/src/main/java/com/greenorange/promotion/generator/Generator.java index 70bb36b..ec755c6 100644 --- a/src/main/java/com/greenorange/promotion/generator/Generator.java +++ b/src/main/java/com/greenorange/promotion/generator/Generator.java @@ -25,7 +25,7 @@ public class Generator { private static final String ROOT_PATH = "/src/main/java"; // 实体类属性名 - private static final String ENTITY_NAME_LOWER = "project"; + private static final String ENTITY_NAME_LOWER = "fileInfo"; // 父包名 private static final String PARENT_PATH = "com.greenorange.promotion"; @@ -51,11 +51,11 @@ public class Generator { // 作者 private static final String AUTHOR = "chenxinzhi"; // 表注释 - private static final String TABLE_COMMENT = "项目"; + private static final String TABLE_COMMENT = "文件"; // 实体类名 - private static final String ENTITY_NAME = "Project"; + private static final String ENTITY_NAME = "FileInfo"; // 表名 - private static final String TABLE_NAME = "project"; + private static final String TABLE_NAME = "file_info"; diff --git a/src/main/java/com/greenorange/promotion/mapper/FileInfoMapper.java b/src/main/java/com/greenorange/promotion/mapper/FileInfoMapper.java new file mode 100644 index 0000000..bd5bf64 --- /dev/null +++ b/src/main/java/com/greenorange/promotion/mapper/FileInfoMapper.java @@ -0,0 +1,18 @@ +package com.greenorange.promotion.mapper; + +import com.greenorange.promotion.model.entity.FileInfo; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** +* @author 35880 +* @description 针对表【file_info(文件上传列表)】的数据库操作Mapper +* @createDate 2025-05-06 17:02:05 +* @Entity com.greenorange.promotion.model.entity.FileInfo +*/ +public interface FileInfoMapper extends BaseMapper { + +} + + + + diff --git a/src/main/java/com/greenorange/promotion/model/dto/fileInfo/FileInfoAddRequest.java b/src/main/java/com/greenorange/promotion/model/dto/fileInfo/FileInfoAddRequest.java new file mode 100644 index 0000000..aa1f314 --- /dev/null +++ b/src/main/java/com/greenorange/promotion/model/dto/fileInfo/FileInfoAddRequest.java @@ -0,0 +1,78 @@ +package com.greenorange.promotion.model.dto.fileInfo; + +import com.greenorange.promotion.annotation.EnumValue; +import com.greenorange.promotion.model.enums.FileUploadBizEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Min; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 文件添加请求体 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Schema(description = "文件添加请求体", requiredProperties = { + "name", + "type", + "path", + "size", + "fileView", + "biz", +}) +public class FileInfoAddRequest implements Serializable { + + /** + * 文件名 + */ + @NotBlank(message = "文件名不能为空") + @Schema(description = "文件名", example = "file.png") + private String name; + + /** + * 文件类型 + */ + @NotBlank(message = "文件类型不能为空") + @Schema(description = "文件类型", example = "png") + private String type; + + /** + * 文件路径 + */ + @NotBlank(message = "文件路径不能为空") + @Schema(description = "文件路径", example = "user_avatar/file.png") + private String path; + + /** + * 文件大小(KB) + */ + @Schema(description = "文件大小", example = "3000") + private Double size; + + /** + * 文件view值 + */ + @NotBlank(message = "文件view值不能为空") + @Schema(description = "文件view值", example = "3E8U2AM8") + private String fileView; + + /** + * 文件业务类型(头像,项目,富文本,默认) + */ + @EnumValue(enumClass = FileUploadBizEnum.class) + @Schema(description = "文件业务类型(头像,项目,富文本,默认)", example = "avatar") + private String biz; + + + @Serial + private static final long serialVersionUID = 1L; +} + diff --git a/src/main/java/com/greenorange/promotion/model/dto/fileInfo/FileInfoQueryRequest.java b/src/main/java/com/greenorange/promotion/model/dto/fileInfo/FileInfoQueryRequest.java new file mode 100644 index 0000000..51ec52d --- /dev/null +++ b/src/main/java/com/greenorange/promotion/model/dto/fileInfo/FileInfoQueryRequest.java @@ -0,0 +1,40 @@ +package com.greenorange.promotion.model.dto.fileInfo; + +import com.greenorange.promotion.annotation.EnumValue; +import com.greenorange.promotion.model.enums.FileUploadBizEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Min; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import com.greenorange.promotion.common.PageRequest; + +/** + * 文件查询请求体,继承自分页请求 PageRequest + */ +@Data +@Schema(description = "文件查询请求体", requiredProperties = {"current", "pageSize"}) +public class FileInfoQueryRequest extends PageRequest implements Serializable { + + /** + * 文件ID + */ + @Min(value = 1L, message = "文件ID ID不能小于1") + @Schema(description = "文件ID", example = "1") + private Long id; + + + /** + * 文件view值 + */ + @EnumValue(enumClass = FileUploadBizEnum.class) + @Schema(description = "文件view值", example = "3E8U2AM8") + private String fileView; + + + @Serial + private static final long serialVersionUID = 1L; +} + diff --git a/src/main/java/com/greenorange/promotion/model/dto/fileInfo/FileInfoUpdateRequest.java b/src/main/java/com/greenorange/promotion/model/dto/fileInfo/FileInfoUpdateRequest.java new file mode 100644 index 0000000..79d78df --- /dev/null +++ b/src/main/java/com/greenorange/promotion/model/dto/fileInfo/FileInfoUpdateRequest.java @@ -0,0 +1,80 @@ +package com.greenorange.promotion.model.dto.fileInfo; + +import com.greenorange.promotion.annotation.EnumValue; +import com.greenorange.promotion.model.enums.FileUploadBizEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Min; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 文件更新请求体 + */ +@Data +@Schema(description = "文件更新请求体", requiredProperties = { + "id", + "name", + "type", + "path", + "size", + "fileView", + "biz", +}) +public class FileInfoUpdateRequest implements Serializable { + + /** + * 文件ID + */ + @Min(value = 1L, message = "文件ID ID不能小于1") + @Schema(description = "文件ID", example = "1") + private Long id; + + /** + * 文件名 + */ + @NotBlank(message = "文件名不能为空") + @Schema(description = "文件名", example = "file.png") + private String name; + + /** + * 文件类型 + */ + @NotBlank(message = "文件类型不能为空") + @Schema(description = "文件类型", example = "png") + private String type; + + /** + * 文件路径 + */ + @NotBlank(message = "文件路径不能为空") + @Schema(description = "文件路径", example = "user_avatar/file.png") + private String path; + + /** + * 文件大小(KB) + */ + @Min(value = 1L, message = "文件大小 ID不能小于1") + @Schema(description = "文件大小", example = "3000") + private Double size; + + /** + * 文件view值 + */ + @NotBlank(message = "文件view值不能为空") + @Schema(description = "文件view值", example = "3E8U2AM8") + private String fileView; + + /** + * 文件业务类型(头像,项目,富文本,默认) + */ + @EnumValue(enumClass = FileUploadBizEnum.class) + @Schema(description = "文件业务类型(头像,项目,富文本,默认)", example = "avatar") + private String biz; + + + @Serial + private static final long serialVersionUID = 1L; +} \ No newline at end of file diff --git a/src/main/java/com/greenorange/promotion/model/dto/fileInfo/UploadFileRequest.java b/src/main/java/com/greenorange/promotion/model/dto/fileInfo/UploadFileRequest.java new file mode 100644 index 0000000..06bc1db --- /dev/null +++ b/src/main/java/com/greenorange/promotion/model/dto/fileInfo/UploadFileRequest.java @@ -0,0 +1,25 @@ +package com.greenorange.promotion.model.dto.fileInfo; + +import com.greenorange.promotion.annotation.EnumValue; +import com.greenorange.promotion.model.enums.FileUploadBizEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +@Data +@Schema(description = "文件上传请求体", requiredProperties = {"biz"}) +public class UploadFileRequest implements Serializable { + + /** + * 文件业务类型(头像,项目,富文本,默认) + */ + @EnumValue(enumClass = FileUploadBizEnum.class) + @Schema(description = "文件业务类型(头像,项目,富文本,默认)", example = "avatar") + private String biz; + + + @Serial + private static final long serialVersionUID = 1L; +} diff --git a/src/main/java/com/greenorange/promotion/model/entity/FileInfo.java b/src/main/java/com/greenorange/promotion/model/entity/FileInfo.java new file mode 100644 index 0000000..5819e6c --- /dev/null +++ b/src/main/java/com/greenorange/promotion/model/entity/FileInfo.java @@ -0,0 +1,71 @@ +package com.greenorange.promotion.model.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.io.Serializable; +import java.util.Date; +import lombok.Data; + +/** + * 文件上传列表 + * @TableName file_info + */ +@TableName(value ="file_info") +@Data +public class FileInfo implements Serializable { + /** + * 文件ID + */ + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 文件名 + */ + private String name; + + /** + * 文件类型 + */ + private String type; + + /** + * 文件路径 + */ + private String path; + + /** + * 文件大小(KB) + */ + private Double size; + + /** + * 文件view值 + */ + private String fileView; + + /** + * 文件业务类型(头像,项目,富文本,默认) + */ + private String biz; + + /** + * 是否删除 + */ + private Integer isDelete; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + + @TableField(exist = false) + private static final long serialVersionUID = 1L; +} \ No newline at end of file diff --git a/src/main/java/com/greenorange/promotion/model/enums/FileUploadBizEnum.java b/src/main/java/com/greenorange/promotion/model/enums/FileUploadBizEnum.java new file mode 100644 index 0000000..083ad18 --- /dev/null +++ b/src/main/java/com/greenorange/promotion/model/enums/FileUploadBizEnum.java @@ -0,0 +1,51 @@ +package com.greenorange.promotion.model.enums; + +import lombok.Getter; +import org.apache.commons.lang3.StringUtils; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + + +/** + * 文件上传业务类型枚举 + */ +@Getter +public enum FileUploadBizEnum { + + AVATAR("用户头像", "avatar"), + PROJECT("项目", "project"), + RICH_TEXT("富文本", "richText"); + + private final String text; + private final String value; + + FileUploadBizEnum(String text, String value) { + this.text = text; + this.value = value; + } + + /** + * 获取值列表 + */ + public static List getValues() { + return Arrays.stream(values()).map(item -> item.value).collect(Collectors.toList()); + } + + /** + * 根据值获取对应的枚举对象 + */ + public static FileUploadBizEnum getEnumByValue(String value) { + if (StringUtils.isBlank(value)) { + return null; + } + for (FileUploadBizEnum anEnum : FileUploadBizEnum.values()) { + if (anEnum.value.equals(value)) { + return anEnum; + } + } + return null; + } +} + diff --git a/src/main/java/com/greenorange/promotion/model/enums/ProjectStatusEnum.java b/src/main/java/com/greenorange/promotion/model/enums/ProjectStatusEnum.java index 2a01da3..e74b991 100644 --- a/src/main/java/com/greenorange/promotion/model/enums/ProjectStatusEnum.java +++ b/src/main/java/com/greenorange/promotion/model/enums/ProjectStatusEnum.java @@ -7,6 +7,9 @@ import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; +/** + * 项目状态枚举 + */ @Getter public enum ProjectStatusEnum { diff --git a/src/main/java/com/greenorange/promotion/model/vo/fileInfo/FileInfoVO.java b/src/main/java/com/greenorange/promotion/model/vo/fileInfo/FileInfoVO.java new file mode 100644 index 0000000..f2ec4a6 --- /dev/null +++ b/src/main/java/com/greenorange/promotion/model/vo/fileInfo/FileInfoVO.java @@ -0,0 +1,62 @@ +package com.greenorange.promotion.model.vo.fileInfo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; + +/** + * 文件 视图对象 + */ +@Data +@Schema(description = "文件 视图对象") +public class FileInfoVO implements Serializable { + + /** + * 文件ID + */ + @Schema(description = "文件ID", example = "1") + private Long id; + + /** + * 文件名 + */ + @Schema(description = "文件名", example = "file.png") + private String name; + + /** + * 文件类型 + */ + @Schema(description = "文件类型", example = "png") + private String type; + + /** + * 文件路径 + */ + @Schema(description = "文件路径", example = "user_avatar/file.png") + private String path; + + /** + * 文件大小(KB) + */ + @Schema(description = "文件大小", example = "3000") + private Double size; + + /** + * 文件view值 + */ + @Schema(description = "文件view值", example = "3E8U3A") + private String fileView; + + /** + * 文件业务类型(头像,项目,富文本,默认) + */ + @Schema(description = "文件业务类型(头像,项目,富文本,默认)", example = "user_avatar") + private String biz; + + + @Serial + private static final long serialVersionUID = 1L; +} diff --git a/src/main/java/com/greenorange/promotion/service/file/FileInfoService.java b/src/main/java/com/greenorange/promotion/service/file/FileInfoService.java new file mode 100644 index 0000000..f345267 --- /dev/null +++ b/src/main/java/com/greenorange/promotion/service/file/FileInfoService.java @@ -0,0 +1,35 @@ +package com.greenorange.promotion.service.file; + +import com.greenorange.promotion.model.dto.fileInfo.UploadFileRequest; +import com.greenorange.promotion.model.entity.FileInfo; +import com.baomidou.mybatisplus.extension.service.IService; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; + +/** +* @author 35880 +* @description 针对表【file_info(文件上传列表)】的数据库操作Service +* @createDate 2025-05-06 17:02:05 +*/ +public interface FileInfoService extends IService { + + + /** + * 校验文件 + */ + void validFile(MultipartFile multipartFile); + + + /** + * 获取文件保存路径 + */ + String uploadFile(MultipartFile multipartFile, UploadFileRequest uploadFileRequest); + + + /** + * 文件下载 + */ + void downloadFile(String filename, HttpServletResponse response) throws IOException; +} diff --git a/src/main/java/com/greenorange/promotion/service/file/impl/FileInfoServiceImpl.java b/src/main/java/com/greenorange/promotion/service/file/impl/FileInfoServiceImpl.java new file mode 100644 index 0000000..f2292cf --- /dev/null +++ b/src/main/java/com/greenorange/promotion/service/file/impl/FileInfoServiceImpl.java @@ -0,0 +1,162 @@ +package com.greenorange.promotion.service.file.impl; + +import cn.hutool.core.io.FileUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.greenorange.promotion.common.ErrorCode; +import com.greenorange.promotion.exception.BusinessException; +import com.greenorange.promotion.exception.ThrowUtils; +import com.greenorange.promotion.model.dto.fileInfo.FileInfoAddRequest; +import com.greenorange.promotion.model.dto.fileInfo.UploadFileRequest; +import com.greenorange.promotion.model.entity.FileInfo; +import com.greenorange.promotion.model.enums.FileUploadBizEnum; +import com.greenorange.promotion.service.common.CommonService; +import com.greenorange.promotion.service.file.FileInfoService; +import com.greenorange.promotion.mapper.FileInfoMapper; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import org.apache.commons.lang3.RandomStringUtils; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.*; +import java.lang.reflect.Field; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + +/** +* @author 35880 +* @description 针对表【file_info(文件上传列表)】的数据库操作Service实现 +* @createDate 2025-05-06 17:02:05 +*/ +@Service +public class FileInfoServiceImpl extends ServiceImpl + implements FileInfoService{ + + @Resource + private CommonService commonService; + + + // 上传文件的服务器存储目录 + private static final String UPLOAD_DIR = "D:/qingcheng/image/"; + + + // 优化:设置一个合理的缓冲区大小 + private static final int BUFFER_SIZE = 8192; // 8 KB + + + /** + * 校验文件 + */ + @Override + public void validFile(MultipartFile multipartFile) { + // 文件大小 + long fileSize = multipartFile.getSize(); + // 文件后缀 + String fileSuffix = FileUtil.getSuffix(multipartFile.getOriginalFilename()); + final long LIMIT = 20 * 1024 * 1024L; + ThrowUtils.throwIf(fileSize > LIMIT, ErrorCode.PARAMS_ERROR, "文件大小不能超过20MB"); + ThrowUtils.throwIf(!Arrays.asList("jpeg", "jpg", "svg", "png", "webp", "JPG").contains(fileSuffix),ErrorCode.PARAMS_ERROR, "文件类型错误"); + } + + + + /** + * 获取文件保存路径 + */ + @Override + public String uploadFile(MultipartFile multipartFile, UploadFileRequest uploadFileRequest) { + // 获取业务名称 + String biz = uploadFileRequest.getBiz(); + // 获取文件名 + String fileName = multipartFile.getOriginalFilename(); + // 获取文件类型 + String fileType = FileUtil.getSuffix(fileName); + // 获取文件路径 + // 获取view值 + String view = RandomStringUtils.random(8); + // 获取文件路径 + String filePath = String.format("%s/%s", biz, fileName); + // 获取文件大小 + Double fileSize = multipartFile.getSize() / 1024.0; + // 保存文件 + FileInfoAddRequest fileInfoAddRequest = FileInfoAddRequest.builder() + .name(fileName) + .type(fileType) + .path(filePath) + .size(fileSize) + .fileView(view) + .biz(biz) + .build(); + FileInfo fileInfo = commonService.copyProperties(fileInfoAddRequest, FileInfo.class); + this.save(fileInfo); + // 创建上传目录,如果不存在 + File file = new File(UPLOAD_DIR + filePath); + if (!file.getParentFile().exists()) { + file.getParentFile().mkdirs();// 如果路径不存在则创建 + } + // 将文件上传到目标位置 + try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file), BUFFER_SIZE)) { + bos.write(multipartFile.getBytes()); + } catch (IOException e) { + throw new BusinessException(ErrorCode.OPERATION_ERROR, "文件上传失败,失败原因:" + e.getMessage()); + } + return view; + } + + + /** + * 文件下载 + * @param filename 业务名称/view值 + * @param response + */ + @Override + public void downloadFile(String filename, HttpServletResponse response) throws IOException{ + ThrowUtils.throwIf(!filename.contains("/"), ErrorCode.PARAMS_ERROR); + String[] split = filename.split("/"); + FileUploadBizEnum fileUploadBizEnum = FileUploadBizEnum.getEnumByValue(split[0]); + ThrowUtils.throwIf(fileUploadBizEnum == null, ErrorCode.PARAMS_ERROR, "业务类型错误"); + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + lambdaQueryWrapper.eq(FileInfo::getFileView, split[1]); + FileInfo fileInfo = this.getOne(lambdaQueryWrapper); + ThrowUtils.throwIf(fileInfo == null, ErrorCode.NOT_FOUND_ERROR, "文件不存在"); + + File file = new File(UPLOAD_DIR + fileInfo.getPath()); +// // 设置response的Header + response.setContentType("application/octet-stream"); + response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(file.getName(), StandardCharsets.UTF_8)); + response.setContentLengthLong(file.length()); // 使用 setContentLengthLong 适应大文件 + + // 设置缓存相关的 HTTP 头 + long lastModified = file.lastModified(); + response.setDateHeader("Last-Modified", lastModified); // 文件最后修改时间 + response.setHeader("Cache-Control", "public, max-age=86400"); // 缓存一天(24小时) + response.setHeader("ETag", String.valueOf(lastModified)); // 使用文件最后修改时间作为 ETag + + // 检查浏览器缓存是否有效 + String ifNoneMatch = response.getHeader("If-None-Match"); + if (ifNoneMatch != null && ifNoneMatch.equals(String.valueOf(lastModified))) { + // 如果 ETag 匹配,表示文件没有变化,返回 304 Not Modified + response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); + return; + } + // 使用 BufferedInputStream 和 BufferedOutputStream 提高性能 + try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file), BUFFER_SIZE); + BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream(), BUFFER_SIZE)) { + byte[] buffer = new byte[BUFFER_SIZE]; + int bytesRead; + // 从文件中读取数据并写入响应输出流 + while ((bytesRead = bis.read(buffer)) != -1) { + bos.write(buffer, 0, bytesRead); + } + bos.flush(); // 确保所有数据都已写入响应 + } + } + +} + + + + diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 3e0177b..be5d1ab 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -30,7 +30,6 @@ springdoc: server: - address: 0.0.0.0 port: 3456 servlet: diff --git a/src/main/resources/mapper/FileInfoMapper.xml b/src/main/resources/mapper/FileInfoMapper.xml new file mode 100644 index 0000000..6b1fa22 --- /dev/null +++ b/src/main/resources/mapper/FileInfoMapper.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + id,name,type, + path,size,fileView, + biz,isDelete,createTime, + updateTime + + diff --git a/src/main/resources/templates/controller.java.vm b/src/main/resources/templates/controller.java.vm index ed8e28a..6594c19 100644 --- a/src/main/resources/templates/controller.java.vm +++ b/src/main/resources/templates/controller.java.vm @@ -10,7 +10,7 @@ import jakarta.validation.Valid; * ${entityComment} 控制器 */ @RestController -@RequestMapping("${tableName}") +@RequestMapping("${entityNameLower}") @Slf4j @Tag(name = "${entityComment}管理") public class ${entityName}Controller { @@ -28,6 +28,8 @@ public class ${entityName}Controller { */ @PostMapping("add") @Operation(summary = "web端管理员添加${entityComment}", description = "参数:${entityComment}添加请求体,权限:管理员,方法名:add${entityName}") + @RequiresPermission(mustRole = UserConstant.ADMIN_ROLE) + @SysLog(title = "${entityComment}管理", content = "web端管理员添加${entityComment}") public BaseResponse add${entityName}(@Valid @RequestBody ${entityName}AddRequest ${entityNameLower}AddRequest) { ${entityName} ${entityNameLower} = commonService.copyProperties(${entityNameLower}AddRequest, ${entityName}.class); ${entityNameLower}Service.save(${entityNameLower}); diff --git a/src/main/resources/templates/dto/QueryRequest.java.vm b/src/main/resources/templates/dto/QueryRequest.java.vm index 1f47253..5f1c202 100644 --- a/src/main/resources/templates/dto/QueryRequest.java.vm +++ b/src/main/resources/templates/dto/QueryRequest.java.vm @@ -16,21 +16,17 @@ import com.greenorange.promotion.common.PageRequest; @Schema(description = "${entityComment}查询请求体", requiredProperties = {"current", "pageSize"}) public class ${entityName}QueryRequest extends PageRequest implements Serializable { - /** - * ${entityComment} ID - */ - @Schema(description = "${entityComment} ID", example = "1") - @Min(value = 1L, message = "${entityComment} ID不能小于1") - private Long id; - #foreach($field in ${table.fields}) -#if(!$field.keyFlag && $field.propertyName != "createTime" && $field.propertyName != "updateTime" && $field.propertyName != "isDelete") +#if($field.propertyName != "createTime" && $field.propertyName != "updateTime" && $field.propertyName != "isDelete") /** * ${field.comment} */ #if($field.propertyType == "String") @NotBlank(message = "${field.comment}不能为空") #end + #if($field.propertyType == "Long") + @Min(value = 1L, message = "${field.comment} ID不能小于1") + #end @Schema(description = "${field.comment}", example = "") private ${field.propertyType} ${field.propertyName}; diff --git a/src/main/resources/templates/dto/UpdateRequest.java.vm b/src/main/resources/templates/dto/UpdateRequest.java.vm index 883cdc6..006a164 100644 --- a/src/main/resources/templates/dto/UpdateRequest.java.vm +++ b/src/main/resources/templates/dto/UpdateRequest.java.vm @@ -14,7 +14,7 @@ import java.io.Serializable; @Data @Schema(description = "${entityComment}更新请求体", requiredProperties = { #foreach($field in ${table.fields}) - #if(!$field.keyFlag && $field.propertyName != "createTime" && $field.propertyName != "updateTime" && $field.propertyName != "isDelete") + #if($field.propertyName != "createTime" && $field.propertyName != "updateTime" && $field.propertyName != "isDelete") "${field.propertyName}", #end #end @@ -22,7 +22,7 @@ import java.io.Serializable; public class ${entityName}UpdateRequest implements Serializable { #foreach($field in ${table.fields}) -#if(!$field.keyFlag && $field.propertyName != "createTime" && $field.propertyName != "updateTime" && $field.propertyName != "isDelete") +#if($field.propertyName != "createTime" && $field.propertyName != "updateTime" && $field.propertyName != "isDelete") /** * ${field.comment} */ @@ -30,7 +30,7 @@ public class ${entityName}UpdateRequest implements Serializable { @NotBlank(message = "${field.comment}不能为空") #end #if($field.propertyType == "Long") - @Min(value = 1L, message = "${field.comment} ID不能小于1") + @Min(value = 1L, message = "${field.comment} ID不能小于1") #end @Schema(description = "${field.comment}", example = "") private ${field.propertyType} ${field.propertyName}; diff --git a/src/main/resources/templates/vo/VO.java.vm b/src/main/resources/templates/vo/VO.java.vm index 6eb5d9f..65ffb8e 100644 --- a/src/main/resources/templates/vo/VO.java.vm +++ b/src/main/resources/templates/vo/VO.java.vm @@ -15,9 +15,9 @@ import java.math.BigDecimal; public class ${entityName}VO implements Serializable { /** - * ${entityComment} ID + * ${entityComment}ID */ - @Schema(description = "${entityComment} ID", example = "1") + @Schema(description = "${entityComment}ID", example = "1") private Long id; #foreach($field in ${table.fields})