1. 任务标题自动生成 - 根据SPU信息+平台+品牌+任务子类型+需求类型自动组合生成标题 - 添加watch监听相关字段变化自动更新标题 2. 预览图上传功能 - 添加S3预览图上传API(自动压缩到200px宽度) - Task实体增加previewImage字段 - 前端添加预览图上传组件 - 任务卡片显示65x65像素预览图 3. 接单大厅按部门显示 - 根据用户所属部门筛选可接单的任务类型 - 只显示用户部门对应的任务类型的任务
230 lines
8.9 KiB
Java
230 lines
8.9 KiB
Java
package com.designhub.service;
|
||
|
||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||
import com.designhub.entity.FileUpload;
|
||
import com.designhub.entity.S3Config;
|
||
import com.designhub.mapper.FileUploadMapper;
|
||
import com.designhub.mapper.S3ConfigMapper;
|
||
import org.slf4j.Logger;
|
||
import org.slf4j.LoggerFactory;
|
||
import org.springframework.beans.factory.annotation.Autowired;
|
||
import org.springframework.stereotype.Service;
|
||
import org.springframework.web.multipart.MultipartFile;
|
||
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
|
||
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
|
||
import software.amazon.awssdk.core.sync.RequestBody;
|
||
import software.amazon.awssdk.regions.Region;
|
||
import software.amazon.awssdk.services.s3.S3Client;
|
||
import software.amazon.awssdk.services.s3.S3Configuration;
|
||
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
|
||
|
||
import java.io.ByteArrayInputStream;
|
||
import java.io.ByteArrayOutputStream;
|
||
import java.io.IOException;
|
||
import java.net.URI;
|
||
import java.time.LocalDateTime;
|
||
import java.time.format.DateTimeFormatter;
|
||
import java.util.UUID;
|
||
import net.coobird.thumbnailator.Thumbnails;
|
||
|
||
/**
|
||
* S3文件存储服务
|
||
*/
|
||
@Service
|
||
public class S3Service {
|
||
|
||
private static final Logger log = LoggerFactory.getLogger(S3Service.class);
|
||
|
||
@Autowired
|
||
private S3ConfigMapper s3ConfigMapper;
|
||
|
||
@Autowired
|
||
private FileUploadMapper fileUploadMapper;
|
||
|
||
/**
|
||
* 上传文件到S3
|
||
*
|
||
* @param file 文件
|
||
* @param uploaderId 上传者ID
|
||
* @param uploaderName 上传者姓名
|
||
* @param relatedType 关联类型
|
||
* @param relatedId 关联ID
|
||
* @return 文件URL
|
||
*/
|
||
public String uploadFile(MultipartFile file, Long uploaderId, String uploaderName,
|
||
String relatedType, Long relatedId) throws IOException {
|
||
// 获取激活的S3配置
|
||
S3Config config = s3ConfigMapper.getActiveConfig();
|
||
if (config == null) {
|
||
throw new RuntimeException("S3配置未激活,请先配置S3存储");
|
||
}
|
||
|
||
// 生成唯一文件名
|
||
String originalFilename = file.getOriginalFilename();
|
||
String fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));
|
||
String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
|
||
String uuid = UUID.randomUUID().toString().replace("-", "").substring(0, 8);
|
||
String storedName = timestamp + "_" + uuid + fileExtension;
|
||
|
||
// 构建文件路径
|
||
String filePath = config.getFilePath() + storedName;
|
||
|
||
try {
|
||
// 创建S3客户端
|
||
S3Client s3Client = createS3Client(config);
|
||
|
||
// 上传文件
|
||
PutObjectRequest putObjectRequest = PutObjectRequest.builder()
|
||
.bucket(config.getBucket())
|
||
.key(filePath)
|
||
.contentType(file.getContentType())
|
||
.build();
|
||
|
||
s3Client.putObject(putObjectRequest, RequestBody.fromInputStream(file.getInputStream(), file.getSize()));
|
||
|
||
// 生成文件URL
|
||
String fileUrl = config.getPublicDomain() + "/" + filePath;
|
||
|
||
// 保存文件上传记录
|
||
FileUpload fileUpload = new FileUpload();
|
||
fileUpload.setOriginalName(originalFilename);
|
||
fileUpload.setStoredName(storedName);
|
||
fileUpload.setFilePath(filePath);
|
||
fileUpload.setFileUrl(fileUrl);
|
||
fileUpload.setFileSize(file.getSize());
|
||
fileUpload.setFileType(file.getContentType());
|
||
fileUpload.setUploaderId(uploaderId);
|
||
fileUpload.setUploaderName(uploaderName);
|
||
fileUpload.setRelatedType(relatedType);
|
||
fileUpload.setRelatedId(relatedId);
|
||
fileUploadMapper.insert(fileUpload);
|
||
|
||
log.info("文件上传成功: {} -> {}", originalFilename, fileUrl);
|
||
return fileUrl;
|
||
|
||
} catch (Exception e) {
|
||
log.error("文件上传失败: {}", originalFilename, e);
|
||
throw new RuntimeException("文件上传失败: " + e.getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 创建S3客户端
|
||
*/
|
||
private S3Client createS3Client(S3Config config) {
|
||
AwsBasicCredentials credentials = AwsBasicCredentials.create(
|
||
config.getAccessKeyId(),
|
||
config.getSecretAccessKey()
|
||
);
|
||
|
||
S3Configuration s3Config = S3Configuration.builder()
|
||
.pathStyleAccessEnabled(config.getEnablePathStyle())
|
||
.build();
|
||
|
||
return S3Client.builder()
|
||
.region(Region.of(config.getRegion()))
|
||
.credentialsProvider(StaticCredentialsProvider.create(credentials))
|
||
.endpointOverride(URI.create(config.getEndpoint()))
|
||
.serviceConfiguration(s3Config)
|
||
.build();
|
||
}
|
||
|
||
/**
|
||
* 获取文件上传记录
|
||
*/
|
||
public FileUpload getFileUploadById(Long id) {
|
||
return fileUploadMapper.selectById(id);
|
||
}
|
||
|
||
/**
|
||
* 根据关联信息获取文件列表
|
||
*/
|
||
public java.util.List<FileUpload> getFilesByRelated(String relatedType, Long relatedId) {
|
||
LambdaQueryWrapper<FileUpload> wrapper = new LambdaQueryWrapper<>();
|
||
wrapper.eq(FileUpload::getRelatedType, relatedType)
|
||
.eq(FileUpload::getRelatedId, relatedId)
|
||
.orderByDesc(FileUpload::getCreateTime);
|
||
return fileUploadMapper.selectList(wrapper);
|
||
}
|
||
|
||
/**
|
||
* 上传预览图(压缩到最大宽度200px,保持比例)
|
||
*
|
||
* @param file 图片文件
|
||
* @param uploaderId 上传者ID
|
||
* @param uploaderName 上传者姓名
|
||
* @return 压缩后图片的URL
|
||
*/
|
||
public String uploadPreviewImage(MultipartFile file, Long uploaderId, String uploaderName) throws IOException {
|
||
// 获取激活的S3配置
|
||
S3Config config = s3ConfigMapper.getActiveConfig();
|
||
if (config == null) {
|
||
throw new RuntimeException("S3配置未激活,请先配置S3存储");
|
||
}
|
||
|
||
// 验证是否为图片
|
||
String contentType = file.getContentType();
|
||
if (contentType == null || !contentType.startsWith("image/")) {
|
||
throw new RuntimeException("只能上传图片文件");
|
||
}
|
||
|
||
// 生成唯一文件名
|
||
String originalFilename = file.getOriginalFilename();
|
||
String fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));
|
||
String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
|
||
String uuid = UUID.randomUUID().toString().replace("-", "").substring(0, 8);
|
||
String storedName = "preview_" + timestamp + "_" + uuid + fileExtension;
|
||
|
||
// 构建文件路径(预览图专用目录)
|
||
String filePath = config.getFilePath() + "previews/" + storedName;
|
||
|
||
try {
|
||
// 压缩图片到最大宽度200px,保持比例
|
||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||
Thumbnails.of(file.getInputStream())
|
||
.width(200) // 最大宽度200像素
|
||
.keepAspectRatio(true) // 保持比例
|
||
.outputQuality(0.85) // 图片质量
|
||
.toOutputStream(outputStream);
|
||
|
||
byte[] compressedBytes = outputStream.toByteArray();
|
||
|
||
// 创建S3客户端
|
||
S3Client s3Client = createS3Client(config);
|
||
|
||
// 上传压缩后的图片
|
||
PutObjectRequest putObjectRequest = PutObjectRequest.builder()
|
||
.bucket(config.getBucket())
|
||
.key(filePath)
|
||
.contentType(contentType)
|
||
.build();
|
||
|
||
s3Client.putObject(putObjectRequest,
|
||
RequestBody.fromInputStream(new ByteArrayInputStream(compressedBytes), compressedBytes.length));
|
||
|
||
// 生成文件URL
|
||
String fileUrl = config.getPublicDomain() + "/" + filePath;
|
||
|
||
// 保存文件上传记录
|
||
FileUpload fileUpload = new FileUpload();
|
||
fileUpload.setOriginalName(originalFilename);
|
||
fileUpload.setStoredName(storedName);
|
||
fileUpload.setFilePath(filePath);
|
||
fileUpload.setFileUrl(fileUrl);
|
||
fileUpload.setFileSize((long) compressedBytes.length);
|
||
fileUpload.setFileType(contentType);
|
||
fileUpload.setUploaderId(uploaderId);
|
||
fileUpload.setUploaderName(uploaderName);
|
||
fileUpload.setRelatedType("preview_image");
|
||
fileUploadMapper.insert(fileUpload);
|
||
|
||
log.info("预览图上传成功: {} -> {} (压缩后大小: {} bytes)", originalFilename, fileUrl, compressedBytes.length);
|
||
return fileUrl;
|
||
|
||
} catch (Exception e) {
|
||
log.error("预览图上传失败: {}", originalFilename, e);
|
||
throw new RuntimeException("预览图上传失败: " + e.getMessage());
|
||
}
|
||
}
|
||
}
|