feat: 增加附件表结构与本地上传接口
This commit is contained in:
45
script/sql/attachment.sql
Normal file
45
script/sql/attachment.sql
Normal file
@@ -0,0 +1,45 @@
|
||||
DROP TABLE IF EXISTS sys_attachment;
|
||||
|
||||
CREATE TABLE sys_attachment (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
source_type VARCHAR(100) NOT NULL,
|
||||
source_id BIGINT,
|
||||
original_name VARCHAR(255) NOT NULL,
|
||||
file_name VARCHAR(255) NOT NULL,
|
||||
file_suffix VARCHAR(50),
|
||||
content_type VARCHAR(100),
|
||||
file_size BIGINT NOT NULL DEFAULT 0,
|
||||
storage_type VARCHAR(50) NOT NULL,
|
||||
file_path VARCHAR(500) NOT NULL,
|
||||
file_url VARCHAR(500),
|
||||
version INTEGER NOT NULL DEFAULT 1,
|
||||
create_time TIMESTAMP,
|
||||
update_time TIMESTAMP,
|
||||
remark VARCHAR(500) DEFAULT '',
|
||||
create_by VARCHAR(64),
|
||||
update_by VARCHAR(64)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_sys_attachment_source_type ON sys_attachment (source_type);
|
||||
CREATE INDEX idx_sys_attachment_source_id ON sys_attachment (source_id);
|
||||
CREATE INDEX idx_sys_attachment_storage_type ON sys_attachment (storage_type);
|
||||
CREATE INDEX idx_sys_attachment_create_time ON sys_attachment (create_time);
|
||||
|
||||
COMMENT ON TABLE sys_attachment IS '系统附件表';
|
||||
COMMENT ON COLUMN sys_attachment.id IS 'ID';
|
||||
COMMENT ON COLUMN sys_attachment.source_type IS '来源业务类型';
|
||||
COMMENT ON COLUMN sys_attachment.source_id IS '来源业务ID';
|
||||
COMMENT ON COLUMN sys_attachment.original_name IS '原始文件名';
|
||||
COMMENT ON COLUMN sys_attachment.file_name IS '存储文件名';
|
||||
COMMENT ON COLUMN sys_attachment.file_suffix IS '文件后缀';
|
||||
COMMENT ON COLUMN sys_attachment.content_type IS '文件MIME类型';
|
||||
COMMENT ON COLUMN sys_attachment.file_size IS '文件大小(字节)';
|
||||
COMMENT ON COLUMN sys_attachment.storage_type IS '存储类型';
|
||||
COMMENT ON COLUMN sys_attachment.file_path IS '文件存储路径';
|
||||
COMMENT ON COLUMN sys_attachment.file_url IS '文件访问地址';
|
||||
COMMENT ON COLUMN sys_attachment.version IS '版本';
|
||||
COMMENT ON COLUMN sys_attachment.create_time IS '创建时间';
|
||||
COMMENT ON COLUMN sys_attachment.update_time IS '更新时间';
|
||||
COMMENT ON COLUMN sys_attachment.remark IS '备注';
|
||||
COMMENT ON COLUMN sys_attachment.create_by IS '创建者';
|
||||
COMMENT ON COLUMN sys_attachment.update_by IS '更新者';
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.bruce.common.config;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "common.attachment")
|
||||
public class AttachmentProperties {
|
||||
|
||||
private String basePath = "data/attachments";
|
||||
|
||||
public String getBasePath() {
|
||||
return basePath;
|
||||
}
|
||||
|
||||
public void setBasePath(String basePath) {
|
||||
this.basePath = basePath;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.bruce.common.controller;
|
||||
|
||||
import com.bruce.common.entity.SysAttachment;
|
||||
import com.bruce.common.service.ISysAttachmentService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
@Tag(name = "系统附件管理")
|
||||
@RestController
|
||||
@RequestMapping("/api/attachments")
|
||||
public class SysAttachmentController {
|
||||
|
||||
private final ISysAttachmentService sysAttachmentService;
|
||||
|
||||
public SysAttachmentController(ISysAttachmentService sysAttachmentService) {
|
||||
this.sysAttachmentService = sysAttachmentService;
|
||||
}
|
||||
|
||||
@Operation(summary = "上传附件")
|
||||
@PostMapping("/upload")
|
||||
public SysAttachment upload(@RequestParam("file") MultipartFile file,
|
||||
@RequestParam String sourceType,
|
||||
@RequestParam(required = false) Long sourceId) {
|
||||
return sysAttachmentService.upload(file, sourceType, sourceId);
|
||||
}
|
||||
}
|
||||
59
src/main/java/com/bruce/common/entity/SysAttachment.java
Normal file
59
src/main/java/com/bruce/common/entity/SysAttachment.java
Normal file
@@ -0,0 +1,59 @@
|
||||
package com.bruce.common.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("sys_attachment")
|
||||
@Schema(description = "系统附件")
|
||||
public class SysAttachment extends BaseEntity {
|
||||
|
||||
@Schema(description = "来源业务类型")
|
||||
@TableField("source_type")
|
||||
private String sourceType;
|
||||
|
||||
@Schema(description = "来源业务ID")
|
||||
@TableField("source_id")
|
||||
private Long sourceId;
|
||||
|
||||
@Schema(description = "原始文件名")
|
||||
@TableField("original_name")
|
||||
private String originalName;
|
||||
|
||||
@Schema(description = "存储文件名")
|
||||
@TableField("file_name")
|
||||
private String fileName;
|
||||
|
||||
@Schema(description = "文件后缀")
|
||||
@TableField("file_suffix")
|
||||
private String fileSuffix;
|
||||
|
||||
@Schema(description = "文件MIME类型")
|
||||
@TableField("content_type")
|
||||
private String contentType;
|
||||
|
||||
@Schema(description = "文件大小(字节)")
|
||||
@TableField("file_size")
|
||||
private Long fileSize;
|
||||
|
||||
@Schema(description = "存储类型")
|
||||
@TableField("storage_type")
|
||||
private String storageType;
|
||||
|
||||
@Schema(description = "文件存储路径")
|
||||
@TableField("file_path")
|
||||
private String filePath;
|
||||
|
||||
@Schema(description = "文件访问地址")
|
||||
@TableField("file_url")
|
||||
private String fileUrl;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.bruce.common.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.bruce.common.entity.SysAttachment;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface SysAttachmentMapper extends BaseMapper<SysAttachment> {
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.bruce.common.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.bruce.common.entity.SysAttachment;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
public interface ISysAttachmentService extends IService<SysAttachment> {
|
||||
|
||||
SysAttachment upload(MultipartFile file, String sourceType, Long sourceId);
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.bruce.common.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.bruce.common.config.AttachmentProperties;
|
||||
import com.bruce.common.entity.SysAttachment;
|
||||
import com.bruce.common.mapper.SysAttachmentMapper;
|
||||
import com.bruce.common.service.ISysAttachmentService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.UUID;
|
||||
|
||||
@Service
|
||||
public class SysAttachmentServiceImpl extends ServiceImpl<SysAttachmentMapper, SysAttachment> implements ISysAttachmentService {
|
||||
|
||||
private static final String STORAGE_TYPE_LOCAL = "LOCAL";
|
||||
|
||||
private final AttachmentProperties attachmentProperties;
|
||||
|
||||
public SysAttachmentServiceImpl(AttachmentProperties attachmentProperties) {
|
||||
this.attachmentProperties = attachmentProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SysAttachment upload(MultipartFile file, String sourceType, Long sourceId) {
|
||||
if (file == null || file.isEmpty()) {
|
||||
throw new IllegalArgumentException("上传文件不能为空");
|
||||
}
|
||||
if (!StringUtils.hasText(sourceType)) {
|
||||
throw new IllegalArgumentException("sourceType不能为空");
|
||||
}
|
||||
|
||||
String originalName = file.getOriginalFilename();
|
||||
String suffix = StringUtils.getFilenameExtension(originalName);
|
||||
String storedFileName = UUID.randomUUID() + (StringUtils.hasText(suffix) ? "." + suffix : "");
|
||||
String dateDirectory = LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
|
||||
Path rootPath = Paths.get(attachmentProperties.getBasePath()).toAbsolutePath().normalize();
|
||||
Path targetDirectory = rootPath.resolve(dateDirectory);
|
||||
Path targetPath = targetDirectory.resolve(storedFileName);
|
||||
|
||||
try {
|
||||
Files.createDirectories(targetDirectory);
|
||||
file.transferTo(targetPath);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("文件上传失败", e);
|
||||
}
|
||||
|
||||
SysAttachment attachment = new SysAttachment();
|
||||
attachment.setSourceType(sourceType);
|
||||
attachment.setSourceId(sourceId);
|
||||
attachment.setOriginalName(originalName);
|
||||
attachment.setFileName(storedFileName);
|
||||
attachment.setFileSuffix(suffix);
|
||||
attachment.setContentType(file.getContentType());
|
||||
attachment.setFileSize(file.getSize());
|
||||
attachment.setStorageType(STORAGE_TYPE_LOCAL);
|
||||
attachment.setFilePath(dateDirectory + "/" + storedFileName);
|
||||
attachment.setFileUrl(null);
|
||||
attachment.setVersion(1);
|
||||
save(attachment);
|
||||
return attachment;
|
||||
}
|
||||
}
|
||||
@@ -11,3 +11,7 @@ mybatis-plus:
|
||||
mapper-locations: classpath*:/mapper/**/*.xml
|
||||
configuration:
|
||||
map-underscore-to-camel-case: true
|
||||
|
||||
common:
|
||||
attachment:
|
||||
base-path: /data/common-agent/attachments
|
||||
|
||||
@@ -4,3 +4,6 @@ spring:
|
||||
profiles:
|
||||
active: dev
|
||||
|
||||
common:
|
||||
attachment:
|
||||
base-path: data/attachments
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.bruce.common.attachment;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.bruce.common.controller.SysAttachmentController;
|
||||
import com.bruce.common.entity.SysAttachment;
|
||||
import com.bruce.common.mapper.SysAttachmentMapper;
|
||||
import com.bruce.common.service.ISysAttachmentService;
|
||||
import com.bruce.common.service.impl.SysAttachmentServiceImpl;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class SysAttachmentComponentStructureTests {
|
||||
|
||||
@Test
|
||||
void sysAttachmentComponentsShouldReuseMybatisPlusBaseTypes() {
|
||||
assertTrue(BaseMapper.class.isAssignableFrom(SysAttachmentMapper.class));
|
||||
assertTrue(IService.class.isAssignableFrom(ISysAttachmentService.class));
|
||||
assertTrue(ServiceImpl.class.isAssignableFrom(SysAttachmentServiceImpl.class));
|
||||
assertTrue(ISysAttachmentService.class.isAssignableFrom(SysAttachmentServiceImpl.class));
|
||||
assertTrue(SysAttachment.class.isAssignableFrom(SysAttachment.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sysAttachmentShouldExposeUploadMethods() throws NoSuchMethodException {
|
||||
Method serviceMethod = ISysAttachmentService.class.getMethod(
|
||||
"upload",
|
||||
MultipartFile.class,
|
||||
String.class,
|
||||
Long.class
|
||||
);
|
||||
Method controllerMethod = SysAttachmentController.class.getMethod(
|
||||
"upload",
|
||||
MultipartFile.class,
|
||||
String.class,
|
||||
Long.class
|
||||
);
|
||||
|
||||
assertNotNull(serviceMethod);
|
||||
assertNotNull(controllerMethod);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user