feat(material): 通过base64字符串支持图片上传

- 在FileUploadService接口中新增支持base64字符串上传的方法
- 在OSSFileUploadServiceImpl和RustFSServiceImpl实现类中添加base64上传实现
- 在MaterialController新增base64图片上传功能,自动转换并上传图片
- 生成图片文件路径,支持动态日期、随机字符串及UUID组合
- 在ShipmentMaterialSyncSaveQO中新增imageBase64字段支持传递base64图片数据
- 添加日志记录上传失败的异常信息,保证上传错误可追踪
This commit is contained in:
曹鹏飞 2026-05-11 15:06:03 +08:00
parent 99ce826d1c
commit f330ca4117
5 changed files with 80 additions and 4 deletions

View File

@ -35,6 +35,11 @@ public class ShipmentMaterialSyncSaveQO {
*/ */
private String image; private String image;
/**
* base64格式的图片
*/
private String imageBase64;
/** /**
* 重量 * 重量
*/ */

View File

@ -2,6 +2,8 @@ package com.nflg.wms.shipment.controller;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@ -12,6 +14,7 @@ import com.nflg.wms.common.pojo.qo.ShipmentMaterialAddQO;
import com.nflg.wms.common.pojo.qo.ShipmentMaterialSearchQO; import com.nflg.wms.common.pojo.qo.ShipmentMaterialSearchQO;
import com.nflg.wms.common.pojo.qo.ShipmentMaterialSyncSaveQO; import com.nflg.wms.common.pojo.qo.ShipmentMaterialSyncSaveQO;
import com.nflg.wms.common.pojo.qo.ShipmentMaterialUpdateQO; import com.nflg.wms.common.pojo.qo.ShipmentMaterialUpdateQO;
import com.nflg.wms.common.util.DateTimeUtil;
import com.nflg.wms.common.util.UserUtil; import com.nflg.wms.common.util.UserUtil;
import com.nflg.wms.common.util.VUtil; import com.nflg.wms.common.util.VUtil;
import com.nflg.wms.repository.entity.WmsShipmentMaterial; import com.nflg.wms.repository.entity.WmsShipmentMaterial;
@ -19,11 +22,13 @@ import com.nflg.wms.repository.service.IWmsShipmentMaterialService;
import com.nflg.wms.shipment.service.ShipmentMaterialControllerService; import com.nflg.wms.shipment.service.ShipmentMaterialControllerService;
import com.nflg.wms.starter.BaseController; import com.nflg.wms.starter.BaseController;
import com.nflg.wms.starter.service.BomMaterialService; import com.nflg.wms.starter.service.BomMaterialService;
import com.nflg.wms.starter.service.FileUploadService;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
@ -33,6 +38,7 @@ import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import java.io.IOException; import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -41,6 +47,7 @@ import java.util.stream.Collectors;
/** /**
* 图纸管理 * 图纸管理
*/ */
@Slf4j
@RestController @RestController
@RequestMapping("material") @RequestMapping("material")
public class MaterialController extends BaseController { public class MaterialController extends BaseController {
@ -54,6 +61,9 @@ public class MaterialController extends BaseController {
@Resource @Resource
private ShipmentMaterialControllerService shipmentMaterialControllerService; private ShipmentMaterialControllerService shipmentMaterialControllerService;
@Resource
private FileUploadService fileUploadService;
/** /**
* 新增图纸 * 新增图纸
*/ */
@ -164,7 +174,11 @@ public class MaterialController extends BaseController {
dbMaterial.setDescribe(data.getDescribe()); dbMaterial.setDescribe(data.getDescribe());
dbMaterial.setDescribeEn(data.getDescribeEn()); dbMaterial.setDescribeEn(data.getDescribeEn());
dbMaterial.setDrawingNo(data.getDrawingNo()); dbMaterial.setDrawingNo(data.getDrawingNo());
dbMaterial.setImage(data.getImage()); if (StrUtil.isNotBlank(data.getImageBase64())) {
dbMaterial.setImage(uploadBase64(data.getImageBase64()));
}else {
dbMaterial.setImage(data.getImage());
}
dbMaterial.setWeight(data.getWeight()); dbMaterial.setWeight(data.getWeight());
dbMaterial.setLength(data.getLength()); dbMaterial.setLength(data.getLength());
dbMaterial.setWidth(data.getWidth()); dbMaterial.setWidth(data.getWidth());
@ -173,7 +187,7 @@ public class MaterialController extends BaseController {
dbMaterial.setUpdateTime(LocalDateTime.now()); dbMaterial.setUpdateTime(LocalDateTime.now());
shipmentMaterialService.updateById(dbMaterial); shipmentMaterialService.updateById(dbMaterial);
}); });
if (CollectionUtil.isNotEmpty(dbMaterials)){ if (CollectionUtil.isNotEmpty(dbMaterials)) {
shipmentMaterialService.updateBatchById(dbMaterials); shipmentMaterialService.updateBatchById(dbMaterials);
} }
datas.removeIf(data -> dbMaterials.stream().anyMatch(dbMaterial -> dbMaterial.getNo().equals(data.getNo()))); datas.removeIf(data -> dbMaterials.stream().anyMatch(dbMaterial -> dbMaterial.getNo().equals(data.getNo())));
@ -188,6 +202,24 @@ public class MaterialController extends BaseController {
return ApiResult.success(); return ApiResult.success();
} }
private String uploadBase64(String base64) {
try {
return fileUploadService.upload(buildFilePath(base64), base64);
} catch (Exception e) {
log.error("上传图片失败", e);
return null;
}
}
private String buildFilePath(String base64) {
return StrUtil.format("admin/{}/{}/{}{}", DateTimeUtil.format(LocalDate.now())
, RandomUtil.randomString(4), IdUtil.fastUUID(), getFileType(base64));
}
private String getFileType(String base64) {
return "."+base64.substring(base64.indexOf("/") + 1, base64.indexOf(";"));
}
/** /**
* 同步-删除 * 同步-删除
* @param nos 物料编号列表 * @param nos 物料编号列表

View File

@ -9,7 +9,6 @@ public interface FileUploadService {
/** /**
* 上传文件 * 上传文件
*
* @param filePath 文件完整路径: /cfs/xxx.jpg * @param filePath 文件完整路径: /cfs/xxx.jpg
* @param file 文件 * @param file 文件
* @return 可访问的url * @return 可访问的url
@ -19,7 +18,6 @@ public interface FileUploadService {
/** /**
* 上传文件 * 上传文件
*
* @param filePath 文件完整路径: /cfs/xxx.jpg * @param filePath 文件完整路径: /cfs/xxx.jpg
* @param stream 文件流 * @param stream 文件流
* @return 可访问的url * @return 可访问的url
@ -27,4 +25,13 @@ public interface FileUploadService {
*/ */
String upload(String filePath, InputStream stream, String contentType) throws Exception; String upload(String filePath, InputStream stream, String contentType) throws Exception;
/**
* 上传文件
* @param filePath 文件完整路径: /cfs/xxx.jpg
* @param base64 base64字符串
* @return 可访问的url
* @throws IOException
*/
String upload(String filePath, String base64) throws Exception;
} }

View File

@ -12,8 +12,10 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Base64;
@Service @Service
@ConditionalOnProperty(name = "file.upload.type", havingValue = "oss") @ConditionalOnProperty(name = "file.upload.type", havingValue = "oss")
@ -41,4 +43,18 @@ public class OSSFileUploadServiceImpl implements FileUploadService {
//log.debug("上传文件结果: " + result); //log.debug("上传文件结果: " + result);
return StrUtil.format("{}/{}", domain, filePath); return StrUtil.format("{}/{}", domain, filePath);
} }
@Override
public String upload(String filePath, String base64) throws Exception {
String contentType = "";
// 去掉前缀
if (base64.contains(",")) {
String header = base64.substring(0, base64.indexOf(","));
if (header.startsWith("data:") && header.contains(";")) {
contentType = header.substring(5, header.indexOf(";"));
}
base64 = base64.substring(base64.indexOf(",") + 1);
}
return upload(filePath, new ByteArrayInputStream(Base64.getDecoder().decode(base64)), contentType);
}
} }

View File

@ -15,7 +15,9 @@ import software.amazon.awssdk.services.s3.model.HeadBucketRequest;
import software.amazon.awssdk.services.s3.model.NoSuchBucketException; import software.amazon.awssdk.services.s3.model.NoSuchBucketException;
import software.amazon.awssdk.services.s3.model.PutObjectRequest; import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import java.io.ByteArrayInputStream;
import java.io.InputStream; import java.io.InputStream;
import java.util.Base64;
@Slf4j @Slf4j
@Service @Service
@ -50,6 +52,20 @@ public class RustFSServiceImpl implements FileUploadService {
return StrUtil.format("{}/{}/{}", domain, bucketName, filePath); return StrUtil.format("{}/{}/{}", domain, bucketName, filePath);
} }
@Override
public String upload(String filePath, String base64) throws Exception {
String contentType = "";
// 去掉前缀
if (base64.contains(",")) {
String header = base64.substring(0, base64.indexOf(","));
if (header.startsWith("data:") && header.contains(";")) {
contentType = header.substring(5, header.indexOf(";"));
}
base64 = base64.substring(base64.indexOf(",") + 1);
}
return upload(filePath, new ByteArrayInputStream(Base64.getDecoder().decode(base64)), contentType);
}
private void ensureBucketExists() { private void ensureBucketExists() {
try { try {
s3Client.headBucket(HeadBucketRequest.builder().bucket(bucketName).build()); s3Client.headBucket(HeadBucketRequest.builder().bucket(bucketName).build());