客户照片上传功能
This commit is contained in:
@@ -1,10 +1,21 @@
|
||||
package com.rj.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.rj.config.MinIOConfig;
|
||||
import com.rj.dto.CustomerPhotoPreviewResult;
|
||||
import com.rj.dto.CustomerPhotoUploadResult;
|
||||
import com.rj.entity.CustomerManagement;
|
||||
import com.rj.mapper.CustomerManagementMapper;
|
||||
import com.rj.service.ICustomerManagementService;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.rj.service.MinIOService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -14,7 +25,190 @@ import org.springframework.stereotype.Service;
|
||||
* @author 李中华 ,spllzh
|
||||
* @since 2025-08-07
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class CustomerManagementServiceImpl extends ServiceImpl<CustomerManagementMapper, CustomerManagement> implements ICustomerManagementService {
|
||||
public class CustomerManagementServiceImpl extends ServiceImpl<CustomerManagementMapper, CustomerManagement>
|
||||
implements ICustomerManagementService {
|
||||
|
||||
@Autowired
|
||||
private MinIOService minIOService;
|
||||
|
||||
@Autowired
|
||||
private MinIOConfig minioConfig;
|
||||
|
||||
@Override
|
||||
public CustomerPhotoUploadResult uploadCustomerPhoto(String id, MultipartFile file) {
|
||||
try {
|
||||
if (id == null || id.trim().isEmpty()) {
|
||||
return CustomerPhotoUploadResult.badRequest("客户ID不能为空");
|
||||
}
|
||||
if (file == null || file.isEmpty()) {
|
||||
return CustomerPhotoUploadResult.badRequest("请选择要上传的文件");
|
||||
}
|
||||
CustomerManagement customer = getById(id.trim());
|
||||
if (customer == null) {
|
||||
return CustomerPhotoUploadResult.badRequest("客户不存在");
|
||||
}
|
||||
String original = file.getOriginalFilename();
|
||||
String ext = "";
|
||||
if (original != null && original.contains(".")) {
|
||||
ext = original.substring(original.lastIndexOf("."));
|
||||
}
|
||||
String objectName = "customer-management/photo/" + id.trim() + "/"
|
||||
+ UUID.randomUUID().toString().replace("-", "") + ext;
|
||||
String url = minIOService.uploadFileWithName(file, objectName);
|
||||
log.info("客户照片已上传 MinIO,customerId={}, url={}", id, url);
|
||||
return CustomerPhotoUploadResult.ok(url);
|
||||
} catch (Exception e) {
|
||||
log.error("客户照片上传失败: {}", e.getMessage(), e);
|
||||
return CustomerPhotoUploadResult.serverError("上传失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomerPhotoPreviewResult openCustomerPhotoPreview(String url, String id, String photoType) {
|
||||
String photoUrl = null;
|
||||
if (url != null && !url.trim().isEmpty()) {
|
||||
photoUrl = url.trim();
|
||||
} else if (id != null && !id.trim().isEmpty() && photoType != null && !photoType.trim().isEmpty()) {
|
||||
CustomerManagement customer = getById(id.trim());
|
||||
if (customer == null) {
|
||||
return CustomerPhotoPreviewResult.notFound();
|
||||
}
|
||||
String type = photoType.trim().toLowerCase();
|
||||
switch (type) {
|
||||
case "front":
|
||||
photoUrl = customer.getFrontPhotoUrl();
|
||||
break;
|
||||
case "side":
|
||||
photoUrl = customer.getSidePhotoUrl();
|
||||
break;
|
||||
case "life":
|
||||
photoUrl = customer.getLifePhotoUrl();
|
||||
break;
|
||||
default:
|
||||
return CustomerPhotoPreviewResult.badRequest();
|
||||
}
|
||||
} else {
|
||||
return CustomerPhotoPreviewResult.badRequest();
|
||||
}
|
||||
if (photoUrl == null || photoUrl.trim().isEmpty()) {
|
||||
return CustomerPhotoPreviewResult.notFound();
|
||||
}
|
||||
String loc = photoUrl.trim();
|
||||
String nameProbe = lastPathSegmentForPreview(loc);
|
||||
if (!isImageFile(nameProbe)) {
|
||||
log.warn("预览拒绝非图片扩展名: {}", nameProbe);
|
||||
return CustomerPhotoPreviewResult.badRequest();
|
||||
}
|
||||
String objectName = resolveMinioObjectNameForPreview(loc);
|
||||
if (objectName == null || objectName.isEmpty()) {
|
||||
log.warn("无法从 URL 解析 MinIO 对象名: {}", loc);
|
||||
return CustomerPhotoPreviewResult.badRequest();
|
||||
}
|
||||
try {
|
||||
InputStream inputStream = minIOService.downloadFile(objectName);
|
||||
String contentType = imageContentType(nameProbe);
|
||||
return CustomerPhotoPreviewResult.ok(inputStream, contentType);
|
||||
} catch (Exception e) {
|
||||
log.error("从 MinIO 读取客户照片失败, objectName={}", objectName, e);
|
||||
return CustomerPhotoPreviewResult.notFound();
|
||||
}
|
||||
}
|
||||
|
||||
private static String lastPathSegmentForPreview(String urlOrPath) {
|
||||
if (urlOrPath == null) {
|
||||
return "";
|
||||
}
|
||||
String s = urlOrPath.trim();
|
||||
int q = s.indexOf('?');
|
||||
if (q >= 0) {
|
||||
s = s.substring(0, q);
|
||||
}
|
||||
int slash = Math.max(s.lastIndexOf('/'), s.lastIndexOf('\\'));
|
||||
return slash >= 0 ? s.substring(slash + 1) : s;
|
||||
}
|
||||
|
||||
private static boolean isImageFile(String fileName) {
|
||||
if (fileName == null || fileName.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
String ext = getFileExtension(fileName).toLowerCase();
|
||||
switch (ext) {
|
||||
case "jpg":
|
||||
case "jpeg":
|
||||
case "png":
|
||||
case "gif":
|
||||
case "webp":
|
||||
case "bmp":
|
||||
case "ico":
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static String getFileExtension(String fileName) {
|
||||
if (fileName == null) {
|
||||
return "";
|
||||
}
|
||||
int i = fileName.lastIndexOf('.');
|
||||
return i >= 0 ? fileName.substring(i + 1) : "";
|
||||
}
|
||||
|
||||
private static String imageContentType(String fileName) {
|
||||
String ext = getFileExtension(fileName).toLowerCase();
|
||||
switch (ext) {
|
||||
case "jpg":
|
||||
case "jpeg":
|
||||
return MediaType.IMAGE_JPEG_VALUE;
|
||||
case "png":
|
||||
return MediaType.IMAGE_PNG_VALUE;
|
||||
case "gif":
|
||||
return MediaType.IMAGE_GIF_VALUE;
|
||||
case "webp":
|
||||
return "image/webp";
|
||||
case "bmp":
|
||||
return "image/bmp";
|
||||
case "ico":
|
||||
return "image/x-icon";
|
||||
default:
|
||||
return MediaType.APPLICATION_OCTET_STREAM_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
private String resolveMinioObjectNameForPreview(String fileUrl) {
|
||||
if (fileUrl == null || fileUrl.trim().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
String trimmed = fileUrl.trim();
|
||||
String withoutQuery = trimmed;
|
||||
int q = trimmed.indexOf('?');
|
||||
if (q >= 0) {
|
||||
withoutQuery = trimmed.substring(0, q);
|
||||
}
|
||||
String prefix = minioConfig.getFileUrlPrefix();
|
||||
if (prefix != null && !prefix.isEmpty() && withoutQuery.startsWith(prefix)) {
|
||||
return withoutQuery.substring(prefix.length());
|
||||
}
|
||||
return extractObjectNameFromUrlFallback(trimmed);
|
||||
}
|
||||
|
||||
private static String extractObjectNameFromUrlFallback(String url) {
|
||||
if (url == null || url.trim().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
String urlWithoutParams = url.contains("?") ? url.substring(0, url.indexOf('?')) : url;
|
||||
String[] parts = urlWithoutParams.split("/");
|
||||
for (int i = parts.length - 1; i >= 0; i--) {
|
||||
if (parts[i] != null && !parts[i].trim().isEmpty()) {
|
||||
return parts[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user