文件模块初步完成
This commit is contained in:
parent
2eb5ee1207
commit
e1458e937b
|
@ -3,10 +3,12 @@ package com.greenorange.promotion.aop;
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.greenorange.promotion.annotation.SysLog;
|
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.model.entity.SysOperLog;
|
||||||
import com.greenorange.promotion.service.log.SysOperLogService;
|
import com.greenorange.promotion.service.log.SysOperLogService;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.aspectj.lang.JoinPoint;
|
import org.aspectj.lang.JoinPoint;
|
||||||
import org.aspectj.lang.annotation.*;
|
import org.aspectj.lang.annotation.*;
|
||||||
import org.aspectj.lang.reflect.MethodSignature;
|
import org.aspectj.lang.reflect.MethodSignature;
|
||||||
|
@ -30,6 +32,7 @@ import java.util.Map;
|
||||||
*/
|
*/
|
||||||
@Aspect
|
@Aspect
|
||||||
@Component
|
@Component
|
||||||
|
@Slf4j
|
||||||
public class OperateLogAspect {
|
public class OperateLogAspect {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
|
@ -170,14 +173,11 @@ public class OperateLogAspect {
|
||||||
for (Object o : paramsArray) {
|
for (Object o : paramsArray) {
|
||||||
if (o != null) {
|
if (o != null) {
|
||||||
try {
|
try {
|
||||||
// 排除掉 RequestFacade 类型的对象
|
|
||||||
if (o instanceof org.apache.catalina.connector.RequestFacade) {
|
|
||||||
continue; // 跳过该对象
|
|
||||||
}
|
|
||||||
Object jsonObj = JSON.toJSON(o);
|
Object jsonObj = JSON.toJSON(o);
|
||||||
params += jsonObj.toString() + " ";
|
params += jsonObj.toString() + " ";
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
// e.printStackTrace();
|
||||||
|
log.warn("JSON参数解析出现异常");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<String> 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -53,6 +53,8 @@ public class ProjectController {
|
||||||
*/
|
*/
|
||||||
@PostMapping("add")
|
@PostMapping("add")
|
||||||
@Operation(summary = "web端管理员添加项目", description = "参数:项目添加请求体,权限:管理员,方法名:addProject")
|
@Operation(summary = "web端管理员添加项目", description = "参数:项目添加请求体,权限:管理员,方法名:addProject")
|
||||||
|
@RequiresPermission(mustRole = UserConstant.ADMIN_ROLE)
|
||||||
|
@SysLog(title = "项目管理", content = "web端管理员添加项目")
|
||||||
public BaseResponse<Boolean> addProject(@Valid @RequestBody ProjectAddRequest projectAddRequest) {
|
public BaseResponse<Boolean> addProject(@Valid @RequestBody ProjectAddRequest projectAddRequest) {
|
||||||
Project project = commonService.copyProperties(projectAddRequest, Project.class);
|
Project project = commonService.copyProperties(projectAddRequest, Project.class);
|
||||||
projectService.save(project);
|
projectService.save(project);
|
||||||
|
|
|
@ -25,7 +25,7 @@ public class Generator {
|
||||||
private static final String ROOT_PATH = "/src/main/java";
|
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";
|
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 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";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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<FileInfo> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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<String> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -7,6 +7,9 @@ import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目状态枚举
|
||||||
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
public enum ProjectStatusEnum {
|
public enum ProjectStatusEnum {
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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<FileInfo> {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验文件
|
||||||
|
*/
|
||||||
|
void validFile(MultipartFile multipartFile);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文件保存路径
|
||||||
|
*/
|
||||||
|
String uploadFile(MultipartFile multipartFile, UploadFileRequest uploadFileRequest);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件下载
|
||||||
|
*/
|
||||||
|
void downloadFile(String filename, HttpServletResponse response) throws IOException;
|
||||||
|
}
|
|
@ -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<FileInfoMapper, FileInfo>
|
||||||
|
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<FileInfo> 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(); // 确保所有数据都已写入响应
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,6 @@ springdoc:
|
||||||
|
|
||||||
|
|
||||||
server:
|
server:
|
||||||
address: 0.0.0.0
|
|
||||||
port: 3456
|
port: 3456
|
||||||
|
|
||||||
servlet:
|
servlet:
|
||||||
|
|
26
src/main/resources/mapper/FileInfoMapper.xml
Normal file
26
src/main/resources/mapper/FileInfoMapper.xml
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<?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.greenorange.promotion.mapper.FileInfoMapper">
|
||||||
|
|
||||||
|
<resultMap id="BaseResultMap" type="com.greenorange.promotion.model.entity.FileInfo">
|
||||||
|
<id property="id" column="id" jdbcType="BIGINT"/>
|
||||||
|
<result property="name" column="name" jdbcType="VARCHAR"/>
|
||||||
|
<result property="type" column="type" jdbcType="VARCHAR"/>
|
||||||
|
<result property="path" column="path" jdbcType="VARCHAR"/>
|
||||||
|
<result property="size" column="size" jdbcType="BIGINT"/>
|
||||||
|
<result property="fileView" column="fileView" jdbcType="VARCHAR"/>
|
||||||
|
<result property="biz" column="biz" jdbcType="VARCHAR"/>
|
||||||
|
<result property="isDelete" column="isDelete" jdbcType="TINYINT"/>
|
||||||
|
<result property="createTime" column="createTime" jdbcType="TIMESTAMP"/>
|
||||||
|
<result property="updateTime" column="updateTime" jdbcType="TIMESTAMP"/>
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<sql id="Base_Column_List">
|
||||||
|
id,name,type,
|
||||||
|
path,size,fileView,
|
||||||
|
biz,isDelete,createTime,
|
||||||
|
updateTime
|
||||||
|
</sql>
|
||||||
|
</mapper>
|
|
@ -10,7 +10,7 @@ import jakarta.validation.Valid;
|
||||||
* ${entityComment} 控制器
|
* ${entityComment} 控制器
|
||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("${tableName}")
|
@RequestMapping("${entityNameLower}")
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Tag(name = "${entityComment}管理")
|
@Tag(name = "${entityComment}管理")
|
||||||
public class ${entityName}Controller {
|
public class ${entityName}Controller {
|
||||||
|
@ -28,6 +28,8 @@ public class ${entityName}Controller {
|
||||||
*/
|
*/
|
||||||
@PostMapping("add")
|
@PostMapping("add")
|
||||||
@Operation(summary = "web端管理员添加${entityComment}", description = "参数:${entityComment}添加请求体,权限:管理员,方法名:add${entityName}")
|
@Operation(summary = "web端管理员添加${entityComment}", description = "参数:${entityComment}添加请求体,权限:管理员,方法名:add${entityName}")
|
||||||
|
@RequiresPermission(mustRole = UserConstant.ADMIN_ROLE)
|
||||||
|
@SysLog(title = "${entityComment}管理", content = "web端管理员添加${entityComment}")
|
||||||
public BaseResponse<Boolean> add${entityName}(@Valid @RequestBody ${entityName}AddRequest ${entityNameLower}AddRequest) {
|
public BaseResponse<Boolean> add${entityName}(@Valid @RequestBody ${entityName}AddRequest ${entityNameLower}AddRequest) {
|
||||||
${entityName} ${entityNameLower} = commonService.copyProperties(${entityNameLower}AddRequest, ${entityName}.class);
|
${entityName} ${entityNameLower} = commonService.copyProperties(${entityNameLower}AddRequest, ${entityName}.class);
|
||||||
${entityNameLower}Service.save(${entityNameLower});
|
${entityNameLower}Service.save(${entityNameLower});
|
||||||
|
|
|
@ -16,21 +16,17 @@ import com.greenorange.promotion.common.PageRequest;
|
||||||
@Schema(description = "${entityComment}查询请求体", requiredProperties = {"current", "pageSize"})
|
@Schema(description = "${entityComment}查询请求体", requiredProperties = {"current", "pageSize"})
|
||||||
public class ${entityName}QueryRequest extends PageRequest implements Serializable {
|
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})
|
#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}
|
* ${field.comment}
|
||||||
*/
|
*/
|
||||||
#if($field.propertyType == "String")
|
#if($field.propertyType == "String")
|
||||||
@NotBlank(message = "${field.comment}不能为空")
|
@NotBlank(message = "${field.comment}不能为空")
|
||||||
#end
|
#end
|
||||||
|
#if($field.propertyType == "Long")
|
||||||
|
@Min(value = 1L, message = "${field.comment} ID不能小于1")
|
||||||
|
#end
|
||||||
@Schema(description = "${field.comment}", example = "")
|
@Schema(description = "${field.comment}", example = "")
|
||||||
private ${field.propertyType} ${field.propertyName};
|
private ${field.propertyType} ${field.propertyName};
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ import java.io.Serializable;
|
||||||
@Data
|
@Data
|
||||||
@Schema(description = "${entityComment}更新请求体", requiredProperties = {
|
@Schema(description = "${entityComment}更新请求体", requiredProperties = {
|
||||||
#foreach($field in ${table.fields})
|
#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}",
|
"${field.propertyName}",
|
||||||
#end
|
#end
|
||||||
#end
|
#end
|
||||||
|
@ -22,7 +22,7 @@ import java.io.Serializable;
|
||||||
public class ${entityName}UpdateRequest implements Serializable {
|
public class ${entityName}UpdateRequest implements Serializable {
|
||||||
|
|
||||||
#foreach($field in ${table.fields})
|
#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}
|
* ${field.comment}
|
||||||
*/
|
*/
|
||||||
|
@ -30,7 +30,7 @@ public class ${entityName}UpdateRequest implements Serializable {
|
||||||
@NotBlank(message = "${field.comment}不能为空")
|
@NotBlank(message = "${field.comment}不能为空")
|
||||||
#end
|
#end
|
||||||
#if($field.propertyType == "Long")
|
#if($field.propertyType == "Long")
|
||||||
@Min(value = 1L, message = "${field.comment} ID不能小于1")
|
@Min(value = 1L, message = "${field.comment} ID不能小于1")
|
||||||
#end
|
#end
|
||||||
@Schema(description = "${field.comment}", example = "")
|
@Schema(description = "${field.comment}", example = "")
|
||||||
private ${field.propertyType} ${field.propertyName};
|
private ${field.propertyType} ${field.propertyName};
|
||||||
|
|
|
@ -15,9 +15,9 @@ import java.math.BigDecimal;
|
||||||
public class ${entityName}VO implements Serializable {
|
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;
|
private Long id;
|
||||||
|
|
||||||
#foreach($field in ${table.fields})
|
#foreach($field in ${table.fields})
|
||||||
|
|
Loading…
Reference in New Issue
Block a user