Commit 96e71469 by zhangxingmin

Merge remote-tracking branch 'origin/test' into prod

parents 48491bf2 23a33fef
......@@ -35,5 +35,6 @@ FROM base-builder
# 只拷贝jar包
COPY target/yd-oss-api-1.0-SNAPSHOT-exec.jar /home/app/yd-oss-api.jar
ENTRYPOINT ["java", "-jar", "/home/app/yd-oss-api.jar"]
# 执行命令启动jar,并设置JVM内存参数
ENTRYPOINT ["java", "-Xmx256m", "-Xms128m", "-jar", "/home/app/yd-oss-api.jar"]
EXPOSE 9106
\ No newline at end of file
......@@ -70,8 +70,8 @@ public class ApiExcelController implements ApiExcelFeignClient {
*/
@Override
public Result<ImportResult> importExcel(MultipartFile file, Integer headerRow,
Integer dataStartRow, String requiredFields) {
return apiExcelService.importExcel(file,headerRow,dataStartRow,requiredFields);
Integer dataStartRow, String requiredFields,Integer checkStartRow) {
return apiExcelService.importExcel(file,headerRow,dataStartRow,requiredFields,checkStartRow);
}
/**
......
package com.yd.oss.api.controller;
import com.yd.common.result.Result;
import com.yd.oss.api.service.ApiMaterialService;
import com.yd.oss.feign.client.ApiMaterialFeignClient;
import com.yd.oss.feign.request.ApiMaterialDownloadRequest;
import com.yd.oss.feign.request.ApiMaterialListRequest;
import com.yd.oss.feign.response.ApiMaterialDownloadResponse;
import com.yd.oss.feign.response.ApiMaterialListResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 材料基础信息
*
* @author zxm
* @since 2025-12-17
*/
@RestController
@RequestMapping("/material")
@Validated
public class ApiMaterialController implements ApiMaterialFeignClient {
@Autowired
private ApiMaterialService apiMaterialService;
/**
* 列表查询-材料基础信息
* @param request
* @return
*/
@Override
public Result<List<ApiMaterialListResponse>> list(ApiMaterialListRequest request) {
return apiMaterialService.list(request);
}
/**
* 下载-材料列表压缩包
* @param request
* @return
*/
@Override
public Result<ApiMaterialDownloadResponse> downloadCompressedFile(ApiMaterialDownloadRequest request) {
return apiMaterialService.downloadCompressedFile(request);
}
}
......@@ -3,6 +3,8 @@ package com.yd.oss.api.controller;
import com.yd.common.result.Result;
import com.yd.oss.api.service.ApiOssService;
import com.yd.oss.feign.client.ApiOssFeignClient;
import com.yd.oss.feign.request.ApiUploadFileRequest;
import com.yd.oss.feign.response.ApiBatchUploadResponse;
import com.yd.oss.feign.response.ApiFileMetadataResponse;
import com.yd.oss.feign.response.ApiUploadResponse;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -11,6 +13,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
* OSS接口信息
*
......@@ -36,6 +40,17 @@ public class ApiOssController implements ApiOssFeignClient {
}
/**
* 上传文件 - body入参方式(新,推荐)
* @param file
* @param request
* @return
*/
@Override
public Result<ApiUploadResponse> uploadFileBody(MultipartFile file, ApiUploadFileRequest request) {
return apiOssService.uploadFileBody(file,request);
}
/**
* 下载文件
* @param fileKey 文件唯一标识
* @return
......@@ -97,8 +112,14 @@ public class ApiOssController implements ApiOssFeignClient {
return apiOssService.getFileMetadata(fileKey,"","");
}
/**
* 批量上传文件 - body入参方式
* @param files 上传的文件列表
* @param request 批量上传请求参数
* @return 批量上传响应
*/
@Override
public Result uploadBatchFile() {
return apiOssService.uploadBatchFile();
public Result<ApiBatchUploadResponse> batchUploadFiles(List<MultipartFile> files, ApiUploadFileRequest request) {
return apiOssService.batchUploadFiles(files, request);
}
}
package com.yd.oss.api.controller;
import com.yd.common.result.Result;
import com.yd.oss.api.service.ApiOssFileService;
import com.yd.oss.feign.client.ApiOssFileFeignClient;
import com.yd.oss.feign.request.ApiOssFileListRequest;
import com.yd.oss.feign.response.ApiOssFileListResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.constraints.NotBlank;
import java.util.List;
/**
* 文件元数据信息
*
* @author zxm
* @since 2025-08-22
*/
@RestController
@RequestMapping("/ossFile")
@Validated
public class ApiOssFileController implements ApiOssFileFeignClient {
@Autowired
private ApiOssFileService apiOssFileService;
/**
* 列表查询-文件元数据信息
* @param request
* @return
*/
@Override
public Result<List<ApiOssFileListResponse>> list(ApiOssFileListRequest request) {
return apiOssFileService.list(request);
}
/**
* 删除-文件元数据信息
* @param fileBizId
* @return
*/
@Override
public Result del(String fileBizId) {
return apiOssFileService.del(fileBizId);
}
}
package com.yd.oss.api.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.yd.common.result.Result;
import com.yd.oss.api.service.ApiRelObjectMaterialService;
import com.yd.oss.feign.client.ApiRelObjectMaterialFeignClient;
import com.yd.oss.feign.request.ApiRelObjectMaterialListAddRequest;
import com.yd.oss.feign.request.ApiRelObjectMaterialPageRequest;
import com.yd.oss.feign.request.ApiRelObjectMaterialUploadSubmitRequest;
import com.yd.oss.feign.response.ApiRelObjectMaterialPageResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 对象材料关系表信息
*
* @author zxm
* @since 2025-12-17
*/
@RestController
@RequestMapping("/relObjectMaterial")
@Validated
public class ApiRelObjectMaterialController implements ApiRelObjectMaterialFeignClient {
@Autowired
private ApiRelObjectMaterialService apiRelObjectMaterialService;
/**
* 分页列表查询-对象材料关系表信息
* @param request
* @return
*/
@Override
public Result<IPage<ApiRelObjectMaterialPageResponse>> page(ApiRelObjectMaterialPageRequest request) {
return apiRelObjectMaterialService.page(request);
}
/**
* 删除-对象材料关系表信息
* @param relObjectMaterialBizId
* @return
*/
@Override
public Result del(String relObjectMaterialBizId) {
return apiRelObjectMaterialService.del(relObjectMaterialBizId);
}
/**
* 添加-单个对象和材料列表关系信息
* @param request
* @return
*/
@Override
public Result addRelObjectMaterialList(ApiRelObjectMaterialListAddRequest request) {
return apiRelObjectMaterialService.addRelObjectMaterialList(request);
}
/**
* 上传-提交
* @param request
* @return
*/
@Override
public Result submit(ApiRelObjectMaterialUploadSubmitRequest request) {
return apiRelObjectMaterialService.submit(request);
}
}
package com.yd.oss.api.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>
* 文件元数据表 前端控制器
* </p>
*
* @author zxm
* @since 2025-08-22
*/
@RestController
@RequestMapping("/ossFile")
public class OssFileController {
}
......@@ -21,7 +21,7 @@ public interface ApiExcelService {
Result<ExportResult> export(List<?> dataList, ExportParam exportParam, Class<?> entityClass);
Result<ImportResult> importExcel(MultipartFile file, Integer headerRow,
Integer dataStartRow, String requiredFields);
Integer dataStartRow, String requiredFields,Integer checkStartRow);
Result<ImportResult> simpleImport(MultipartFile file);
}
package com.yd.oss.api.service;
import com.yd.common.result.Result;
import com.yd.oss.feign.request.ApiMaterialDownloadRequest;
import com.yd.oss.feign.request.ApiMaterialListRequest;
import com.yd.oss.feign.response.ApiMaterialDownloadResponse;
import com.yd.oss.feign.response.ApiMaterialListResponse;
import java.util.List;
public interface ApiMaterialService {
Result<List<ApiMaterialListResponse>> list(ApiMaterialListRequest request);
Result<ApiMaterialDownloadResponse> downloadCompressedFile(ApiMaterialDownloadRequest request);
}
package com.yd.oss.api.service;
import com.yd.common.result.Result;
import com.yd.oss.feign.dto.ApiRelMaterialDto;
import com.yd.oss.feign.request.ApiOssFileListRequest;
import com.yd.oss.feign.response.ApiOssFileListResponse;
import com.yd.oss.service.model.RelObjectMaterial;
import java.util.List;
public interface ApiOssFileService {
Result<List<ApiOssFileListResponse>> list(ApiOssFileListRequest request);
Result del(String fileBizId);
Result updateByMaterial(List<RelObjectMaterial> relObjectMaterialList,
List<ApiRelMaterialDto> materialDtoList);
Result updateByMaterial(String relObjectMaterialBizId,
List<String> fileBizIdList);
}
package com.yd.oss.api.service;
import com.yd.common.result.Result;
import com.yd.oss.feign.request.ApiUploadFileRequest;
import com.yd.oss.feign.response.ApiBatchUploadResponse;
import com.yd.oss.feign.response.ApiFileMetadataResponse;
import com.yd.oss.feign.response.ApiUploadResponse;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
public interface ApiOssService {
Result<ApiUploadResponse> uploadFile(MultipartFile file, String bucket, String provider, String uploadUser);
Result<ApiUploadResponse> uploadFileBody(MultipartFile file, ApiUploadFileRequest request);
void downloadFile(String fileKey, String bucket, String provider, HttpServletResponse response);
Result<Boolean> deleteFile(String fileKey, String bucket, String provider, String operator);
......@@ -22,5 +27,12 @@ public interface ApiOssService {
Result<ApiFileMetadataResponse> getFileMetadata(String fileKey, String bucket, String provider);
Result uploadBatchFile();
/**
* 批量上传文件
* @param files 文件列表
* @param request 批量上传请求参数
* @return 批量上传响应
*/
Result<ApiBatchUploadResponse> batchUploadFiles(List<MultipartFile> files, ApiUploadFileRequest request);
}
package com.yd.oss.api.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.yd.common.result.Result;
import com.yd.oss.feign.request.ApiRelObjectMaterialListAddRequest;
import com.yd.oss.feign.request.ApiRelObjectMaterialPageRequest;
import com.yd.oss.feign.request.ApiRelObjectMaterialUploadSubmitRequest;
import com.yd.oss.feign.response.ApiRelObjectMaterialPageResponse;
public interface ApiRelObjectMaterialService {
Result<IPage<ApiRelObjectMaterialPageResponse>> page(ApiRelObjectMaterialPageRequest request);
Result del(String relObjectMaterialBizId);
Result addRelObjectMaterialList(ApiRelObjectMaterialListAddRequest request);
Result submit(ApiRelObjectMaterialUploadSubmitRequest request);
}
......@@ -107,13 +107,13 @@ public class ApiExcelServiceImpl implements ApiExcelService {
*/
@Override
public Result<ImportResult> importExcel(MultipartFile file, Integer headerRow,
Integer dataStartRow, String requiredFields) {
Integer dataStartRow, String requiredFields,Integer checkStartRow) {
List<String> requiredFieldList = null;
if (requiredFields != null && !requiredFields.isEmpty()) {
requiredFieldList = Arrays.asList(requiredFields.split(","));
}
ImportResult importResult = excelImportService.genericImport(file, headerRow, dataStartRow, requiredFieldList);
ImportResult importResult = excelImportService.genericImport(file, headerRow, dataStartRow, requiredFieldList,checkStartRow);
return Result.success(importResult);
}
......
package com.yd.oss.api.service.impl;
import com.yd.common.result.Result;
import com.yd.oss.api.service.ApiMaterialService;
import com.yd.oss.feign.dto.ApiMaterialDto;
import com.yd.oss.feign.request.ApiMaterialDownloadRequest;
import com.yd.oss.feign.request.ApiMaterialListRequest;
import com.yd.oss.feign.response.ApiMaterialDownloadResponse;
import com.yd.oss.feign.response.ApiMaterialListResponse;
import com.yd.oss.service.dto.MaterialDto;
import com.yd.oss.service.model.Material;
import com.yd.oss.service.model.RelObjectMaterial;
import com.yd.oss.service.service.CompressedFileService;
import com.yd.oss.service.service.IMaterialService;
import com.yd.oss.service.service.IRelObjectMaterialService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
@Service
public class ApiMaterialServiceImpl implements ApiMaterialService {
@Autowired
private IMaterialService iMaterialService;
@Autowired
private CompressedFileService compressedFileService;
@Autowired
private IRelObjectMaterialService iRelObjectMaterialService;
/**
* 列表查询-材料基础信息
* @param request
* @return
*/
@Override
public Result<List<ApiMaterialListResponse>> list(ApiMaterialListRequest request) {
List<Material> materialList = iMaterialService.queryList(MaterialDto.builder().objectType(request.getObjectType()).build());
if (!CollectionUtils.isEmpty(materialList)) {
List<ApiMaterialListResponse> responses = materialList.stream().map(dto -> {
ApiMaterialListResponse response = new ApiMaterialListResponse();
BeanUtils.copyProperties(dto,response);
return response;
}).collect(Collectors.toList());
return Result.success(responses);
}
return Result.success();
}
/**
* 下载-材料列表压缩包
* @param request
* @return
*/
@Override
public Result<ApiMaterialDownloadResponse> downloadCompressedFile(ApiMaterialDownloadRequest request) {
// if (StringUtils.isNotBlank(request.getObjectBizId())) {
// List<ApiMaterialDto> apiMaterialDtoList = new ArrayList<>();
// List<RelObjectMaterial> relObjectMaterialList = iRelObjectMaterialService.queryList(request.getObjectBizId());
// if (!CollectionUtils.isEmpty(relObjectMaterialList)) {
// List<String> materialBizIdList = relObjectMaterialList.stream().map(RelObjectMaterial::getMaterialBizId).collect(Collectors.toList());
//
// for (RelObjectMaterial relObjectMaterial : relObjectMaterialList) {
//
// }
// }
// }
return compressedFileService.downloadCompressedFile(request);
}
}
\ No newline at end of file
package com.yd.oss.api.service.impl;
import com.yd.common.enums.CommonEnum;
import com.yd.common.enums.ResultCode;
import com.yd.common.exception.BusinessException;
import com.yd.common.result.Result;
import com.yd.oss.api.service.ApiOssFileService;
import com.yd.oss.feign.dto.ApiRelMaterialDto;
import com.yd.oss.feign.request.ApiOssFileListRequest;
import com.yd.oss.feign.response.ApiOssFileListResponse;
import com.yd.oss.service.dto.OssFileDto;
import com.yd.oss.service.model.OssFile;
import com.yd.oss.service.model.RelObjectMaterial;
import com.yd.oss.service.service.IOssFileService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@Slf4j
@Service
public class ApiOssFileServiceImpl implements ApiOssFileService {
@Autowired
private IOssFileService iOssFileService;
/**
* 列表查询-文件元数据信息
* @param request
* @return
*/
@Override
public Result<List<ApiOssFileListResponse>> list(ApiOssFileListRequest request) {
List<ApiOssFileListResponse> list = iOssFileService.list(request.getObjectBizId(),request.getObjectBizIdList());
return Result.success(list);
}
/**
* 删除-文件元数据信息
* @param fileBizId
* @return
*/
@Override
public Result del(String fileBizId) {
Result<OssFile> result = checkOssFileIsExist(fileBizId);
OssFile ossFile = result.getData();
iOssFileService.removeById(ossFile.getId());
return Result.success();
}
/**
* 更新-材料
* @param relObjectMaterialList
* @param materialDtoList
* @return
*/
@Override
public Result updateByMaterial(List<RelObjectMaterial> relObjectMaterialList,
List<ApiRelMaterialDto> materialDtoList) {
if (!CollectionUtils.isEmpty(materialDtoList)) {
for (ApiRelMaterialDto dto : materialDtoList) {
if (!CollectionUtils.isEmpty(relObjectMaterialList)) {
List<RelObjectMaterial> materials = relObjectMaterialList.stream().filter(d -> d.getMaterialBizId().equals(dto.getMaterialBizId())).collect(Collectors.toList());
if (!CollectionUtils.isEmpty(materials)) {
RelObjectMaterial relObjectMaterial = materials.get(0);
if (!CollectionUtils.isEmpty(dto.getFileBizIdList())) {
List<OssFile> ossFileList = iOssFileService.queryList(OssFileDto.builder().fileBizIdList(dto.getFileBizIdList()).build());
if (!CollectionUtils.isEmpty(ossFileList)) {
ossFileList = ossFileList.stream().map(file -> {
file.setObjectType(CommonEnum.UID_TYPE_REL_OBJECT_MATERIAL.getCode());
file.setObjectTableName(CommonEnum.UID_TYPE_REL_OBJECT_MATERIAL.getName());
file.setObjectTableName(CommonEnum.UID_TYPE_REL_OBJECT_MATERIAL.getCode());
file.setObjectBizId(relObjectMaterial.getRelObjectMaterialBizId());
return file;
}).collect(Collectors.toList());
iOssFileService.saveOrUpdateBatch(ossFileList);
}
}
}
}
}
}
return Result.success();
}
@Override
public Result updateByMaterial(String relObjectMaterialBizId, List<String> fileBizIdList) {
//objectId查询列表,置为空字符串
List<OssFile> ossFiles = iOssFileService.queryList(OssFileDto.builder().objectBizId(relObjectMaterialBizId).build());
if (!CollectionUtils.isEmpty(ossFiles)) {
ossFiles = ossFiles.stream().map(file -> {
file.setObjectType("");
file.setObjectTableName("");
file.setObjectTableName("");
file.setObjectBizId("");
return file;
}).collect(Collectors.toList());
iOssFileService.saveOrUpdateBatch(ossFiles);
}
//再更新
List<OssFile> ossFileList = iOssFileService.queryList(OssFileDto.builder().fileBizIdList(fileBizIdList).build());
if (!CollectionUtils.isEmpty(ossFileList)) {
ossFileList = ossFileList.stream().map(file -> {
file.setObjectType(CommonEnum.UID_TYPE_REL_OBJECT_MATERIAL.getCode());
file.setObjectTableName(CommonEnum.UID_TYPE_REL_OBJECT_MATERIAL.getName());
file.setObjectTableName(CommonEnum.UID_TYPE_REL_OBJECT_MATERIAL.getCode());
file.setObjectBizId(relObjectMaterialBizId);
return file;
}).collect(Collectors.toList());
iOssFileService.saveOrUpdateBatch(ossFileList);
}
return Result.success();
}
/**
* 校验文件元数据信息是否存在
* @param fileBizId
* @return
*/
public Result<OssFile> checkOssFileIsExist(String fileBizId) {
OssFile ossFile = iOssFileService.queryOne(fileBizId);
if (Objects.isNull(ossFile)) {
//数据不存在
throw new BusinessException(ResultCode.NULL_ERROR.getCode(),ResultCode.NULL_ERROR.getMessage());
}
return Result.success(ossFile);
}
}
......@@ -3,13 +3,15 @@ package com.yd.oss.api.service.impl;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.yd.common.result.Result;
import com.yd.oss.api.service.ApiOssService;
import com.yd.oss.feign.request.ApiUploadFileRequest;
import com.yd.oss.feign.response.ApiBatchUploadResponse;
import com.yd.oss.feign.response.ApiFileMetadataResponse;
import com.yd.oss.feign.response.ApiUploadResponse;
import com.yd.oss.service.dto.FileMetadata;
import com.yd.oss.service.dto.OssUploadFileDto;
import com.yd.oss.service.dto.OssUploadFileReqDto;
import com.yd.oss.service.dto.OssUploadFileResDto;
import com.yd.oss.service.dto.UploadResult;
import com.yd.oss.service.service.OssService;
import com.yd.oss.service.service.impl.FileUploadService;
import com.yd.oss.service.utils.FileUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
......@@ -21,6 +23,8 @@ import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.time.Duration;
import java.util.List;
import java.util.Objects;
@Slf4j
@Service
......@@ -29,9 +33,6 @@ public class ApiOssServiceImpl implements ApiOssService {
@Autowired
private OssService ossService;
@Autowired
private FileUploadService fileUploadService;
/**
* 上传文件
* @param file 上传的文件
......@@ -50,7 +51,7 @@ public class ApiOssServiceImpl implements ApiOssService {
}
// 上传文件
OssUploadFileDto ossUploadFileDto = ossService.uploadFile(file.getInputStream(), file.getOriginalFilename(),
OssUploadFileResDto ossUploadFileDto = ossService.uploadFile(file.getInputStream(), file.getOriginalFilename(),
bucket, uploadUser, FileUtil.getFileType(file.getOriginalFilename()));
// 获取上传结果(包含文件信息和访问URL)
......@@ -67,6 +68,25 @@ public class ApiOssServiceImpl implements ApiOssService {
}
/**
* 上传文件 - body入参方式(新,推荐)
* @param file
* @param request
* @return
*/
@Override
public Result<ApiUploadResponse> uploadFileBody(MultipartFile file, ApiUploadFileRequest request) {
ApiUploadResponse response = null;
OssUploadFileReqDto reqDto = new OssUploadFileReqDto();
BeanUtils.copyProperties(request,reqDto);
OssUploadFileResDto fileResDto = ossService.uploadFileBody(file,reqDto);
if (!Objects.isNull(fileResDto)) {
response = new ApiUploadResponse();
BeanUtils.copyProperties(fileResDto,response);
}
return Result.success(response);
}
/**
* 下载文件
* @param fileKey 文件唯一标识
* @param bucket oss桶(不传值使用默认的oss的桶)
......@@ -218,9 +238,27 @@ public class ApiOssServiceImpl implements ApiOssService {
}
}
/**
* 批量上传文件
* @param files 文件列表
* @param request 批量上传请求参数
* @return 批量上传响应
*/
@Override
public Result uploadBatchFile() {
fileUploadService.batchProcessUrls();
return Result.success();
public Result<ApiBatchUploadResponse> batchUploadFiles(List<MultipartFile> files, ApiUploadFileRequest request) {
try {
// 转换请求参数
OssUploadFileReqDto reqDto = new OssUploadFileReqDto();
BeanUtils.copyProperties(request, reqDto);
// 调用服务层批量上传方法
ApiBatchUploadResponse response = ossService.batchUploadFiles(files, reqDto);
return Result.success(response);
} catch (Exception e) {
log.error("批量上传文件失败", e);
return Result.fail("批量上传文件失败: " + e.getMessage());
}
}
}
......@@ -27,7 +27,7 @@ public class ApiPdfServiceImpl implements ApiPdfService {
public Result<ApiGeneratePdfResponse> generatePDF(ApiGeneratePdfRequest request) {
ApiGeneratePdfResponse response = new ApiGeneratePdfResponse();
try {
String url = pdfService.generatePDF(request.getDataObject(),request.getObjectId(),request.getTemplateType());
String url = pdfService.generatePDF(request.getDataObject(),request.getObjectId(),request.getTemplateType(),request.getCustomFileName());
response.setUrl(url);
return Result.success(response);
} catch (IOException e) {
......
package com.yd.oss.api.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yd.common.enums.CommonEnum;
import com.yd.common.enums.ResultCode;
import com.yd.common.exception.BusinessException;
import com.yd.common.result.Result;
import com.yd.common.utils.RandomStringGenerator;
import com.yd.oss.api.service.ApiOssFileService;
import com.yd.oss.api.service.ApiRelObjectMaterialService;
import com.yd.oss.feign.request.ApiRelObjectMaterialListAddRequest;
import com.yd.oss.feign.request.ApiRelObjectMaterialPageRequest;
import com.yd.oss.feign.request.ApiRelObjectMaterialUploadSubmitRequest;
import com.yd.oss.feign.response.ApiRelObjectMaterialPageResponse;
import com.yd.oss.service.model.RelObjectMaterial;
import com.yd.oss.service.service.IRelObjectMaterialService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@Service
@Slf4j
public class ApiRelObjectMaterialServiceImpl implements ApiRelObjectMaterialService {
@Autowired
private IRelObjectMaterialService iRelObjectMaterialService;
@Autowired
private ApiOssFileService apiOssFileService;
/**
* 分页列表查询-对象材料关系表信息
* @param request
* @return
*/
@Override
public Result<IPage<ApiRelObjectMaterialPageResponse>> page(ApiRelObjectMaterialPageRequest request) {
Page<ApiRelObjectMaterialPageResponse> page = new Page<>(request.getPageNo(), request.getPageSize());
IPage<ApiRelObjectMaterialPageResponse> iPage = iRelObjectMaterialService.page(page, request);
return Result.success(iPage);
}
/**
* 删除-对象材料关系表信息
* @param relObjectMaterialBizId
* @return
*/
@Override
public Result del(String relObjectMaterialBizId) {
//校验对象材料关系表信息是否存在
Result<RelObjectMaterial> result = checkRelObjectMaterialIsExist(relObjectMaterialBizId);
RelObjectMaterial relObjectMaterial = result.getData();
iRelObjectMaterialService.removeById(relObjectMaterial.getId());
return Result.success();
}
/**
* 添加-单个对象和材料列表关系信息
* @param request
* @return
*/
@Override
public Result addRelObjectMaterialList(ApiRelObjectMaterialListAddRequest request) {
//先删后新增
iRelObjectMaterialService.delByObjectBizId(request.getObjectBizId());
if (!CollectionUtils.isEmpty(request.getMaterialDtoList())) {
List<RelObjectMaterial> saveList = request.getMaterialDtoList().stream().map(dto -> {
RelObjectMaterial relObjectMaterial = new RelObjectMaterial();
BeanUtils.copyProperties(request,relObjectMaterial);
relObjectMaterial.setMaterialBizId(dto.getMaterialBizId());
relObjectMaterial.setRelObjectMaterialBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_REL_OBJECT_MATERIAL.getCode()));
if (!CollectionUtils.isEmpty(dto.getFileBizIdList())) {
//附件不为空, 已上传
relObjectMaterial.setStatus("YSC");
}else {
//附件为空, 未上传
relObjectMaterial.setStatus("WSC");
}
return relObjectMaterial;
}).collect(Collectors.toList());
iRelObjectMaterialService.saveOrUpdateBatch(saveList);
//更新保存文件元数据列表
apiOssFileService.updateByMaterial(saveList,request.getMaterialDtoList());
}
return Result.success();
}
/**
* 上传-提交
* @param request
* @return
*/
@Override
public Result submit(ApiRelObjectMaterialUploadSubmitRequest request) {
Result<RelObjectMaterial> result = checkRelObjectMaterialIsExist(request.getRelObjectMaterialBizId());
RelObjectMaterial relObjectMaterial = result.getData();
if (!CollectionUtils.isEmpty(request.getFileBizIdList())) {
relObjectMaterial.setStatus("YSC");
}else {
relObjectMaterial.setStatus("WSC");
}
iRelObjectMaterialService.saveOrUpdate(relObjectMaterial);
//更新保存文件元数据列表
apiOssFileService.updateByMaterial(relObjectMaterial.getRelObjectMaterialBizId(),request.getFileBizIdList());
return Result.success();
}
/**
* 校验对象材料关系表信息是否存在
* @param relObjectMaterialBizId
* @return
*/
public Result<RelObjectMaterial> checkRelObjectMaterialIsExist(String relObjectMaterialBizId) {
RelObjectMaterial relObjectMaterial = iRelObjectMaterialService.queryOne(relObjectMaterialBizId);
if (Objects.isNull(relObjectMaterial)) {
//数据不存在
throw new BusinessException(ResultCode.NULL_ERROR.getCode(),ResultCode.NULL_ERROR.getMessage());
}
return Result.success(relObjectMaterial);
}
}
......@@ -126,6 +126,7 @@
<orderEntry type="library" name="Maven: com.ibm.icu:icu4j:73.2" level="project" />
<orderEntry type="library" name="Maven: com.yd:yd-csf-feign:1.0-SNAPSHOT" level="project" />
<orderEntry type="library" name="Maven: com.yd:yd-question-feign:1.0-SNAPSHOT" level="project" />
<orderEntry type="library" name="Maven: com.yd:yd-base-feign:1.0-SNAPSHOT" level="project" />
<orderEntry type="library" name="Maven: com.yd:yd-auth-core:1.0-SNAPSHOT" level="project" />
<orderEntry type="library" name="Maven: com.github.xiaoymin:knife4j-openapi3-spring-boot-starter:4.3.0" level="project" />
<orderEntry type="library" name="Maven: com.github.xiaoymin:knife4j-core:4.3.0" level="project" />
......
......@@ -62,7 +62,9 @@ public interface ApiExcelFeignClient {
@RequestPart("file") MultipartFile file,
@RequestParam(value = "headerRow", required = false) Integer headerRow,
@RequestParam(value = "dataStartRow", required = false) Integer dataStartRow,
@RequestParam(value = "requiredFields", required = false) String requiredFields);
@RequestParam(value = "requiredFields", required = false) String requiredFields,
@RequestParam(value = "checkStartRow", required = false) Integer checkStartRow
);
/**
* 简化导入接口
......
package com.yd.oss.feign.client;
import com.yd.common.result.Result;
import com.yd.oss.feign.fallback.ApiMaterialFeignFallbackFactory;
import com.yd.oss.feign.request.ApiMaterialDownloadRequest;
import com.yd.oss.feign.request.ApiMaterialListRequest;
import com.yd.oss.feign.response.ApiMaterialDownloadResponse;
import com.yd.oss.feign.response.ApiMaterialListResponse;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
/**
* 材料基础信息Feign客户端
*/
@FeignClient(name = "yd-oss-api",path = "/oss/api/material",fallbackFactory = ApiMaterialFeignFallbackFactory.class)
public interface ApiMaterialFeignClient {
/**
* 列表查询-材料基础信息
* @param request
* @return
*/
@PostMapping("/list")
Result<List<ApiMaterialListResponse>> list(@RequestBody ApiMaterialListRequest request);
/**
* 下载-材料列表压缩包
* @param request
* @return
*/
@PostMapping("/download/compressed/file")
Result<ApiMaterialDownloadResponse> downloadCompressedFile(@Validated @RequestBody ApiMaterialDownloadRequest request);
}
......@@ -2,15 +2,17 @@ package com.yd.oss.feign.client;
import com.yd.common.result.Result;
import com.yd.oss.feign.fallback.ApiOssFeignFallbackFactory;
import com.yd.oss.feign.request.ApiUploadFileRequest;
import com.yd.oss.feign.response.ApiBatchUploadResponse;
import com.yd.oss.feign.response.ApiFileMetadataResponse;
import com.yd.oss.feign.response.ApiUploadResponse;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
* OSS服务信息Feign客户端
*/
......@@ -26,6 +28,15 @@ public interface ApiOssFeignClient {
Result<ApiUploadResponse> uploadFile(@RequestParam("file") MultipartFile file);
/**
* 上传文件 - body入参方式(新,推荐)
* @param file
* @param request
* @return
*/
@PostMapping(value = "/upload/body", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
Result<ApiUploadResponse> uploadFileBody(@RequestPart("file") MultipartFile file, ApiUploadFileRequest request);
/**
* 下载文件
* @param fileKey 文件唯一标识
* @return
......@@ -76,9 +87,14 @@ public interface ApiOssFeignClient {
Result<ApiFileMetadataResponse> getFileMetadata(@RequestParam("fileKey") String fileKey);
/**
* 批量上传文件
* @return
* 批量上传文件 - body入参方式
* @param files 上传的文件列表
* @param request 批量上传请求参数
* @return 批量上传响应
*/
@GetMapping("/upload/batch/file")
Result uploadBatchFile();
@PostMapping(value = "/batch/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
Result<ApiBatchUploadResponse> batchUploadFiles(
@RequestPart("files") List<MultipartFile> files,
ApiUploadFileRequest request);
}
package com.yd.oss.feign.client;
import com.yd.common.result.Result;
import com.yd.oss.feign.fallback.ApiOssFileFeignFallbackFactory;
import com.yd.oss.feign.request.ApiOssFileListRequest;
import com.yd.oss.feign.response.ApiOssFileListResponse;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import javax.validation.constraints.NotBlank;
import java.util.List;
/**
* 文件元数据信息Feign客户端
*/
@FeignClient(name = "yd-oss-api",path = "/oss/api/ossFile",fallbackFactory = ApiOssFileFeignFallbackFactory.class)
public interface ApiOssFileFeignClient {
/**
* 列表查询-文件元数据信息
* @param request
* @return
*/
@PostMapping("/list")
Result<List<ApiOssFileListResponse>> list(@Validated @RequestBody ApiOssFileListRequest request);
/**
* 删除-文件元数据信息
* @param fileBizId
* @return
*/
@DeleteMapping("/del")
Result del(@NotBlank(message = "文件元数据表唯一业务ID不能为空") @RequestParam(value = "fileBizId") String fileBizId);
}
package com.yd.oss.feign.client;
import com.yd.common.result.Result;
import com.yd.oss.feign.fallback.ApiRelObjectMaterialFeignFallbackFactory;
import com.yd.oss.feign.request.ApiRelObjectMaterialListAddRequest;
import com.yd.oss.feign.request.ApiRelObjectMaterialPageRequest;
import com.yd.oss.feign.request.ApiRelObjectMaterialUploadSubmitRequest;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import javax.validation.constraints.NotBlank;
/**
* 对象材料关系表信息Feign客户端
*/
@FeignClient(name = "yd-oss-api",path = "/oss/api/relObjectMaterial",fallbackFactory = ApiRelObjectMaterialFeignFallbackFactory.class)
public interface ApiRelObjectMaterialFeignClient {
/**
* 分页列表查询-对象材料关系表信息
* @param request
* @return
*/
@PostMapping("/page")
Result page(@RequestBody ApiRelObjectMaterialPageRequest request);
/**
* 删除-对象材料关系表信息
* @param relObjectMaterialBizId
* @return
*/
@DeleteMapping("/del")
Result del(@NotBlank(message = "对象材料关系表唯一业务ID不能为空") @RequestParam(value = "relObjectMaterialBizId") String relObjectMaterialBizId);
/**
* 添加-单个对象和材料列表关系信息
* @param request
* @return
*/
@PostMapping("/add/relObjectMaterialList")
Result addRelObjectMaterialList(@Validated @RequestBody ApiRelObjectMaterialListAddRequest request);
/**
* 上传-提交
* @param request
* @return
*/
@PostMapping("/upload/submit")
Result submit(@Validated @RequestBody ApiRelObjectMaterialUploadSubmitRequest request);
}
package com.yd.oss.feign.dto;
import lombok.Data;
import java.util.List;
@Data
public class ApiMaterialDto {
/**
* 资料人(字典)
*/
private String dataPerson;
/**
* 资料类型(字典)
*/
private String dataType;
/**
* 文件URL列表
*/
private List<String> fileUrlList;
}
package com.yd.oss.feign.dto;
import lombok.Data;
import java.util.List;
@Data
public class ApiRelMaterialDto {
/**
* 材料信息表唯一业务ID
*/
private String materialBizId;
/**
* 文件元数据表唯一业务ID列表
*/
private List<String> fileBizIdList;
}
......@@ -40,8 +40,7 @@ public class ApiExcelFeignFallbackFactory implements FallbackFactory<ApiExcelFei
}
@Override
public Result<ImportResult> importExcel(MultipartFile file, Integer headerRow,
Integer dataStartRow, String requiredFields) {
public Result<ImportResult> importExcel(MultipartFile file, Integer headerRow, Integer dataStartRow, String requiredFields, Integer checkStartRow) {
return null;
}
......
package com.yd.oss.feign.fallback;
import com.yd.common.result.Result;
import com.yd.oss.feign.client.ApiMaterialFeignClient;
import com.yd.oss.feign.request.ApiMaterialDownloadRequest;
import com.yd.oss.feign.request.ApiMaterialListRequest;
import com.yd.oss.feign.response.ApiMaterialListResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* 材料基础信息Feign降级处理
*/
@Slf4j
@Component
public class ApiMaterialFeignFallbackFactory implements FallbackFactory<ApiMaterialFeignClient> {
@Override
public ApiMaterialFeignClient create(Throwable cause) {
return new ApiMaterialFeignClient() {
@Override
public Result<List<ApiMaterialListResponse>> list(ApiMaterialListRequest request) {
return null;
}
@Override
public Result downloadCompressedFile(ApiMaterialDownloadRequest request) {
return null;
}
};
}
}
......@@ -2,6 +2,8 @@ package com.yd.oss.feign.fallback;
import com.yd.common.result.Result;
import com.yd.oss.feign.client.ApiOssFeignClient;
import com.yd.oss.feign.request.ApiUploadFileRequest;
import com.yd.oss.feign.response.ApiBatchUploadResponse;
import com.yd.oss.feign.response.ApiFileMetadataResponse;
import com.yd.oss.feign.response.ApiUploadResponse;
import lombok.extern.slf4j.Slf4j;
......@@ -9,6 +11,8 @@ import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
* OSS服务信息Feign降级处理
*/
......@@ -24,6 +28,11 @@ public class ApiOssFeignFallbackFactory implements FallbackFactory<ApiOssFeignCl
}
@Override
public Result<ApiUploadResponse> uploadFileBody(MultipartFile file, ApiUploadFileRequest request) {
return null;
}
@Override
public Result downloadFile(String fileKey) {
return null;
}
......@@ -54,7 +63,7 @@ public class ApiOssFeignFallbackFactory implements FallbackFactory<ApiOssFeignCl
}
@Override
public Result uploadBatchFile() {
public Result<ApiBatchUploadResponse> batchUploadFiles(List<MultipartFile> files, ApiUploadFileRequest request) {
return null;
}
};
......
package com.yd.oss.feign.fallback;
import com.yd.common.result.Result;
import com.yd.oss.feign.client.ApiOssFileFeignClient;
import com.yd.oss.feign.request.ApiOssFileListRequest;
import com.yd.oss.feign.response.ApiOssFileListResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* 文件元数据信息Feign降级处理
*/
@Slf4j
@Component
public class ApiOssFileFeignFallbackFactory implements FallbackFactory<ApiOssFileFeignClient> {
@Override
public ApiOssFileFeignClient create(Throwable cause) {
return new ApiOssFileFeignClient() {
@Override
public Result<List<ApiOssFileListResponse>> list(ApiOssFileListRequest request) {
return null;
}
@Override
public Result del(String fileBizId) {
return null;
}
};
}
}
package com.yd.oss.feign.fallback;
import com.yd.common.result.Result;
import com.yd.oss.feign.client.ApiRelObjectMaterialFeignClient;
import com.yd.oss.feign.request.ApiRelObjectMaterialListAddRequest;
import com.yd.oss.feign.request.ApiRelObjectMaterialPageRequest;
import com.yd.oss.feign.request.ApiRelObjectMaterialUploadSubmitRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.stereotype.Component;
/**
* 对象材料关系表信息Feign降级处理
*/
@Slf4j
@Component
public class ApiRelObjectMaterialFeignFallbackFactory implements FallbackFactory<ApiRelObjectMaterialFeignClient> {
@Override
public ApiRelObjectMaterialFeignClient create(Throwable cause) {
return new ApiRelObjectMaterialFeignClient() {
@Override
public Result page(ApiRelObjectMaterialPageRequest request) {
return null;
}
@Override
public Result del(String relObjectMaterialBizId) {
return null;
}
@Override
public Result addRelObjectMaterialList(ApiRelObjectMaterialListAddRequest request) {
return null;
}
@Override
public Result submit(ApiRelObjectMaterialUploadSubmitRequest request) {
return null;
}
};
}
}
......@@ -19,4 +19,9 @@ public class ApiGeneratePdfRequest<T> {
* 生成文件的模板类型
*/
private String templateType;
/**
* 自定义文件名(有值用自定义文件名上传,无值用默认生成的规则文件名)
*/
private String customFileName;
}
package com.yd.oss.feign.request;
import com.yd.oss.feign.dto.ApiMaterialDto;
import lombok.Data;
import java.util.List;
@Data
public class ApiMaterialDownloadRequest {
/**
* 对象名(包名)
*/
private String objectName;
/**
* 对象业务ID
*/
private String objectBizId;
/**
* 材料列表
*/
private List<ApiMaterialDto> apiMaterialDtoList;
}
package com.yd.oss.feign.request;
import lombok.Data;
@Data
public class ApiMaterialListRequest {
/**
* 对象类型(字典)
*/
private String objectType;
}
package com.yd.oss.feign.request;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import java.util.List;
@Data
public class ApiOssFileListRequest {
/**
* 对象业务ID
*/
private String objectBizId;
/**
* 对象业务ID列表
*/
private List<String> objectBizIdList;
}
package com.yd.oss.feign.request;
import com.yd.oss.feign.dto.ApiRelMaterialDto;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import java.util.List;
@Data
public class ApiRelObjectMaterialListAddRequest {
/**
* 对象类型
*/
private String objectType;
/**
* 对象所属表名(预约表、新单跟进表等)
*/
private String objectTableName;
/**
* 对象名
*/
private String objectName;
/**
* 对象业务ID
*/
@NotBlank(message = "对象业务ID不能为空")
private String objectBizId;
/**
* 材料列表
*/
private List<ApiRelMaterialDto> materialDtoList;
}
package com.yd.oss.feign.request;
import com.yd.common.dto.PageDto;
import lombok.Data;
@Data
public class ApiRelObjectMaterialPageRequest extends PageDto {
/**
* 对象类型
*/
private String objectType;
/**
* 对象所属表名(预约表、新单跟进表等)
*/
private String objectTableName;
/**
* 对象名
*/
private String objectName;
/**
* 对象业务ID
*/
private String objectBizId;
}
package com.yd.oss.feign.request;
import lombok.Data;
import java.util.List;
@Data
public class ApiRelObjectMaterialUploadSubmitRequest {
/**
* 对象材料关系表唯一业务ID
*/
private String relObjectMaterialBizId;
/**
* 文件元数据表唯一业务ID列表
*/
private List<String> fileBizIdList;
}
package com.yd.oss.feign.request;
import lombok.Data;
import javax.validation.constraints.NotBlank;
@Data
public class ApiUploadFileRequest {
/**
* 对象类型
*/
private String objectType;
/**
* 对象所属表名(预约表、新单跟进表等)
*/
private String objectTableName;
/**
* 对象名
*/
private String objectName;
/**
* 对象业务ID
*/
@NotBlank(message = "对象业务ID不能为空")
private String objectBizId;
}
package com.yd.oss.feign.response;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* 批量文件上传响应
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ApiBatchUploadResponse {
/**
* 成功上传的文件列表
*/
private List<ApiUploadResponse> successFiles;
/**
* 失败的文件列表
*/
private List<FailedFile> failedFiles;
/**
* 成功数量
*/
private Integer successCount;
/**
* 失败数量
*/
private Integer failedCount;
/**
* 失败的文件信息
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class FailedFile {
/**
* 原始文件名
*/
private String fileName;
/**
* 失败原因
*/
private String reason;
}
}
package com.yd.oss.feign.response;
import lombok.Data;
@Data
public class ApiMaterialDownloadResponse {
/**
* OSS文件URL
*/
private String url;
}
package com.yd.oss.feign.response;
import lombok.Data;
@Data
public class ApiMaterialListResponse {
/**
* 材料信息表主键ID
*/
private Long id;
/**
* 材料信息表唯一业务ID
*/
private String materialBizId;
/**
* 对象类型(字典)
*/
private String objectType;
/**
* 资料人(字典)
*/
private String dataPerson;
/**
* 资料类型(字典)
*/
private String dataType;
/**
* 注意事项
*/
private String precautions;
/**
* 状态:0-禁用,1-启用
*/
private Integer status;
}
package com.yd.oss.feign.response;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class ApiOssFileListResponse {
/**
* 文件元数据表主键ID
*/
private Long id;
/**
* 对象类型
*/
private String objectType;
/**
* 对象所属表名(预约表、新单跟进表等)
*/
private String objectTableName;
/**
* 对象名
*/
private String objectName;
/**
* 对象业务ID
*/
private String objectBizId;
/**
* 文件元数据表唯一业务ID
*/
private String fileBizId;
/**
* 文件唯一标识
*/
private String fileKey;
/**
* 原始文件名
*/
private String originalName;
/**
* 文件大小(字节)
*/
private Long fileSize;
/**
* 文件类型
*/
private String fileType;
/**
* 完整文件路径
*/
private String fileUrl;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 创建人ID
*/
private String creatorId;
/**
* 创建人名
*/
private String creatorName;
}
package com.yd.oss.feign.response;
import lombok.Data;
import java.util.List;
@Data
public class ApiRelObjectMaterialPageResponse {
/**
* 对象材料关系表主键ID
*/
private Long id;
/**
* 对象材料关系表唯一业务ID
*/
private String relObjectMaterialBizId;
/**
* 材料信息表唯一业务ID
*/
private String materialBizId;
/**
* 状态: YSC-已上传 WSC-未上传 DSC-待上传
*/
private String status;
/**
* 资料人(字典)
*/
private String dataPerson;
/**
* 资料类型(字典)
*/
private String dataType;
/**
* 注意事项
*/
private String precautions;
/**
* 文件URL列表(完整路径)
*/
private List<String> fileUrlList;
}
......@@ -109,5 +109,6 @@
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.13.2" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.13.2" level="project" />
<orderEntry type="library" name="Maven: com.yd:yd-user-feign:1.0-SNAPSHOT" level="project" />
<orderEntry type="library" name="Maven: com.yd:yd-base-feign:1.0-SNAPSHOT" level="project" />
</component>
</module>
\ No newline at end of file
package com.yd.oss.service.dao;
import com.yd.oss.service.model.Material;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yd.oss.service.model.ProductFile;
/**
* <p>
* 产品文件关系表 Mapper 接口
* 材料基础信息 Mapper 接口
* </p>
*
* @author zxm
* @since 2025-10-17
* @since 2025-12-17
*/
public interface ProductFileMapper extends BaseMapper<ProductFile> {
public interface MaterialMapper extends BaseMapper<Material> {
}
package com.yd.oss.service.dao;
import com.yd.oss.feign.response.ApiOssFileListResponse;
import com.yd.oss.service.model.OssFile;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
......@@ -37,4 +38,7 @@ public interface OssFileMapper extends BaseMapper<OssFile> {
// 标记文件为已删除
@Update("UPDATE oss_file SET is_deleted = true, deleted_time = NOW() WHERE file_key = #{fileKey}")
int markAsDeleted(@Param("fileKey") String fileKey);
List<ApiOssFileListResponse> list(@Param("objectBizId") String objectBizId,
@Param("objectBizIdList") List<String> objectBizIdList);
}
package com.yd.oss.service.dao;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yd.oss.feign.request.ApiRelObjectMaterialPageRequest;
import com.yd.oss.feign.response.ApiRelObjectMaterialPageResponse;
import com.yd.oss.service.model.RelObjectMaterial;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
/**
* <p>
* 对象材料关系表 Mapper 接口
* </p>
*
* @author zxm
* @since 2025-12-17
*/
public interface RelObjectMaterialMapper extends BaseMapper<RelObjectMaterial> {
IPage<ApiRelObjectMaterialPageResponse> page(@Param("page") Page<ApiRelObjectMaterialPageResponse> page,
@Param("request") ApiRelObjectMaterialPageRequest request);
}
package com.yd.oss.service.dto;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class MaterialDto {
/**
* 对象类型(字典)
*/
private String objectType;
}
package com.yd.oss.service.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class OssFileDto {
/**
* 对象业务ID
*/
private String objectBizId;
/**
* 文件元数据表唯一业务ID列表
*/
private List<String> fileBizIdList;
}
package com.yd.oss.service.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 提供OSS上传文件请求的DTO
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class OssUploadFileReqDto {
/**
* 对象类型
*/
private String objectType;
/**
* 对象所属表名(预约表、新单跟进表等)
*/
private String objectTableName;
/**
* 对象名
*/
private String objectName;
/**
* 对象业务ID
*/
private String objectBizId;
/**
* 上传用户业务id
*/
private String uploadUser;
}
......@@ -2,11 +2,13 @@ package com.yd.oss.service.dto;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 提供OSS上传文件返回的DTO
*/
@Data
public class OssUploadFileDto {
public class OssUploadFileResDto {
/**
* 文件元数据表业务ID唯一标识
......@@ -28,4 +30,23 @@ public class OssUploadFileDto {
*/
private String url;
/**
* 访问URL(带过期时间签名URL)
*/
private String accessUrl;
/**
* 文件大小
*/
private Long fileSize;
/**
* 文件类型
*/
private String fileType;
/**
* 上传时间
*/
private LocalDateTime uploadTime;
}
package com.yd.oss.service.handler;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedTypes;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@MappedTypes(List.class)
public class StringToListTypeHandler extends BaseTypeHandler<List<String>> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, List<String> parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, String.join(";", parameter));
}
@Override
public List<String> getNullableResult(ResultSet rs, String columnName) throws SQLException {
String value = rs.getString(columnName);
return convertStringToList(value);
}
@Override
public List<String> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String value = rs.getString(columnIndex);
return convertStringToList(value);
}
@Override
public List<String> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String value = cs.getString(columnIndex);
return convertStringToList(value);
}
private List<String> convertStringToList(String value) {
if (value == null || value.trim().isEmpty()) {
return Collections.emptyList();
}
return Arrays.stream(value.split(";"))
.map(String::trim)
.filter(s -> !s.isEmpty())
.collect(Collectors.toList());
}
}
\ No newline at end of file
......@@ -4,62 +4,64 @@ 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 lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
import java.time.LocalDateTime;
import lombok.Getter;
import lombok.Setter;
/**
* <p>
* 产品文件关系表
* 材料基础信息
* </p>
*
* @author zxm
* @since 2025-10-17
* @since 2025-12-17
*/
@Getter
@Setter
@TableName("product_file")
public class ProductFile implements Serializable {
@TableName("material")
public class Material implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 未知ID
* 材料信息表唯一业务ID
*/
@TableField("material_biz_id")
private String materialBizId;
/**
* 对象类型(字典)
*/
@TableField("biz_id")
private String bizId;
@TableField("object_type")
private String objectType;
/**
* 产品业务ID
* 资料人(字典)
*/
@TableField("product_biz_id")
private String productBizId;
@TableField("data_person")
private String dataPerson;
/**
* 文件名称
* 资料类型(字典)
*/
@TableField("file_name")
private String fileName;
@TableField("data_type")
private String dataType;
/**
* 原文件URL
* 注意事项
*/
@TableField("old_file_url")
private String oldFileUrl;
@TableField("precautions")
private String precautions;
/**
* 新文件URL
* 状态:0-禁用,1-启用
*/
@TableField("new_file_url")
private String newFileUrl;
@TableField("status")
private Integer status;
/**
* 通用备注
......@@ -71,7 +73,7 @@ public class ProductFile implements Serializable {
* 删除标识: 0-正常, 1-删除
*/
@TableField("is_deleted")
private Boolean isDeleted;
private Integer isDeleted;
/**
* 创建人ID
......
......@@ -28,7 +28,31 @@ public class OssFile implements Serializable {
private Long id;
/**
* 业务ID唯一标识
* 对象类型
*/
@TableField("object_type")
private String objectType;
/**
* 对象所属表名(对象材料关系表、预约表、新单跟进表等)
*/
@TableField("object_table_name")
private String objectTableName;
/**
* 对象名
*/
@TableField("object_name")
private String objectName;
/**
* 对象业务ID
*/
@TableField("object_biz_id")
private String objectBizId;
/**
* 文件元数据表唯一业务ID
*/
@TableField("file_biz_id")
private String fileBizId;
......@@ -100,6 +124,12 @@ public class OssFile implements Serializable {
private String creatorId;
/**
* 创建人名
*/
@TableField("creator_name")
private String creatorName;
/**
* 更新人ID
*/
@TableField("updater_id")
......
package com.yd.oss.service.model;
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.time.LocalDateTime;
import lombok.Getter;
import lombok.Setter;
/**
* <p>
* 对象材料关系表
* </p>
*
* @author zxm
* @since 2025-12-17
*/
@Getter
@Setter
@TableName("rel_object_material")
public class RelObjectMaterial implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 对象材料关系表唯一业务ID
*/
@TableField("rel_object_material_biz_id")
private String relObjectMaterialBizId;
/**
* 对象类型
*/
@TableField("object_type")
private String objectType;
/**
* 对象所属表名(预约表、新单跟进表等)
*/
@TableField("object_table_name")
private String objectTableName;
/**
* 对象名
*/
@TableField("object_name")
private String objectName;
/**
* 对象业务ID
*/
@TableField("object_biz_id")
private String objectBizId;
/**
* 材料信息表唯一业务ID
*/
@TableField("material_biz_id")
private String materialBizId;
/**
* 状态: YSC-已上传 WSC-未上传 DSC-待上传
*/
@TableField("status")
private String status;
/**
* 通用备注
*/
@TableField("remark")
private String remark;
/**
* 删除标识: 0-正常, 1-删除
*/
@TableField("is_deleted")
private Integer isDeleted;
/**
* 创建人ID
*/
@TableField("creator_id")
private String creatorId;
/**
* 更新人ID
*/
@TableField("updater_id")
private String updaterId;
/**
* 创建时间
*/
@TableField("create_time")
private LocalDateTime createTime;
/**
* 更新时间
*/
@TableField("update_time")
private LocalDateTime updateTime;
}
package com.yd.oss.service.service;
import com.yd.common.result.Result;
import com.yd.oss.feign.request.ApiMaterialDownloadRequest;
import com.yd.oss.feign.response.ApiMaterialDownloadResponse;
public interface CompressedFileService {
Result<ApiMaterialDownloadResponse> downloadCompressedFile(ApiMaterialDownloadRequest request);
}
......@@ -12,7 +12,7 @@ public interface ExcelImportService {
MultipartFile file,
Integer headerRow,
Integer dataStartRow,
List<String> requiredFields);
List<String> requiredFields,Integer checkStartRow);
ImportResult simpleImport(MultipartFile file);
}
package com.yd.oss.service.service;
import com.yd.oss.service.dto.MaterialDto;
import com.yd.oss.service.model.Material;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* <p>
* 材料基础信息 服务类
* </p>
*
* @author zxm
* @since 2025-12-17
*/
public interface IMaterialService extends IService<Material> {
List<Material> queryList(MaterialDto dto);
}
package com.yd.oss.service.service;
import com.yd.oss.feign.response.ApiOssFileListResponse;
import com.yd.oss.service.dto.OssFileDto;
import com.yd.oss.service.model.OssFile;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yd.oss.service.model.OssOperationLog;
......@@ -31,4 +33,10 @@ public interface IOssFileService extends IService<OssFile> {
List<OssFile> getProviderFiles(Long providerId);
List<OssOperationLog> getOperationLogsByFileId(Long fileId);
List<OssFile> queryList(OssFileDto dto);
OssFile queryOne(String fileBizId);
List<ApiOssFileListResponse> list(String objectBizId,List<String> objectBizIdList);
}
package com.yd.oss.service.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yd.oss.feign.request.ApiRelObjectMaterialPageRequest;
import com.yd.oss.feign.response.ApiRelObjectMaterialPageResponse;
import com.yd.oss.service.model.RelObjectMaterial;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* <p>
* 对象材料关系表 服务类
* </p>
*
* @author zxm
* @since 2025-12-17
*/
public interface IRelObjectMaterialService extends IService<RelObjectMaterial> {
IPage<ApiRelObjectMaterialPageResponse> page(Page<ApiRelObjectMaterialPageResponse> page,
ApiRelObjectMaterialPageRequest request);
RelObjectMaterial queryOne(String relObjectMaterialBizId);
Boolean delByObjectBizId(String objectBizId);
List<RelObjectMaterial> queryList(String objectBizId);
}
package com.yd.oss.service.service;
import com.yd.oss.feign.request.ApiUploadFileRequest;
import com.yd.oss.service.dto.FileMetadata;
import com.yd.oss.service.dto.OssUploadFileDto;
import com.yd.oss.service.dto.OssUploadFileReqDto;
import com.yd.oss.service.dto.OssUploadFileResDto;
import com.yd.oss.service.dto.UploadResult;
import com.yd.oss.service.model.OssProvider;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
import java.time.Duration;
......@@ -13,7 +16,9 @@ import java.time.Duration;
public interface OssService {
// 上传文件
OssUploadFileDto uploadFile(InputStream inputStream, String fileName, String bucketName, String uploadUser,String type);
OssUploadFileResDto uploadFile(InputStream inputStream, String fileName, String bucketName, String uploadUser, String type);
OssUploadFileResDto uploadFileBody(MultipartFile file, OssUploadFileReqDto reqDto);
// 上传文件(使用默认存储桶)
String uploadFile(InputStream inputStream, String fileName, String uploadUser);
......@@ -69,5 +74,10 @@ public interface OssService {
String upload(byte[] content, String fileName);
String upload(InputStream inputStream, String fileName);
// 批量上传文件
com.yd.oss.feign.response.ApiBatchUploadResponse batchUploadFiles(
java.util.List<org.springframework.web.multipart.MultipartFile> files,
com.yd.oss.service.dto.OssUploadFileReqDto reqDto);
}
......@@ -4,5 +4,5 @@ import java.io.IOException;
public interface PdfService<T> {
String generatePDF(T dataObject,String objectId, String templateType) throws IOException;
String generatePDF(T dataObject,String objectId, String templateType,String customFileName) throws IOException;
}
......@@ -6,11 +6,16 @@ import com.aliyun.oss.model.CannedAccessControlList;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import com.yd.auth.core.dto.AuthUserDto;
import com.yd.auth.core.utils.SecurityUtil;
import com.yd.common.enums.CommonEnum;
import com.yd.common.exception.BusinessException;
import com.yd.common.utils.IpUtil;
import com.yd.common.utils.RandomStringGenerator;
import com.yd.oss.feign.request.ApiUploadFileRequest;
import com.yd.oss.service.dto.FileMetadata;
import com.yd.oss.service.dto.OssUploadFileDto;
import com.yd.oss.service.dto.OssUploadFileReqDto;
import com.yd.oss.service.dto.OssUploadFileResDto;
import com.yd.oss.service.dto.UploadResult;
import com.yd.oss.service.model.OssFile;
import com.yd.oss.service.model.OssOperationLog;
......@@ -24,14 +29,11 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.net.URL;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.UUID;
......@@ -68,9 +70,11 @@ public class AliYunOssServiceImpl implements OssService {
* @return
*/
@Override
public OssUploadFileDto uploadFile(InputStream inputStream, String fileName,
String bucketName, String uploadUser,String type) {
OssUploadFileDto ossUploadFileDto = new OssUploadFileDto();
public OssUploadFileResDto uploadFile(InputStream inputStream, String fileName,
String bucketName, String uploadUser, String type) {
//获取Security上下文当前用户的登录信息
AuthUserDto authUserDto = SecurityUtil.getCurrentLoginUser();
OssUploadFileResDto ossUploadFileDto = new OssUploadFileResDto();
long startTime = System.currentTimeMillis(); // 记录开始时间
String operationResult = "success"; // 操作结果
String errorMessage = null; // 错误信息
......@@ -110,6 +114,8 @@ public class AliYunOssServiceImpl implements OssService {
ossFile.setProviderBizId(currentProvider.getProviderBizId());
ossFile.setBucketName(actualBucket);
ossFile.setUploadUser(uploadUser);
ossFile.setCreatorId(authUserDto.getUserBizId());
ossFile.setCreatorName(authUserDto.getUsername());
// 保存文件元数据到数据库
ossFileService.saveFileMetadata(ossFile);
......@@ -166,6 +172,142 @@ public class AliYunOssServiceImpl implements OssService {
}
/**
* 上传文件 - body入参方式(新,推荐)
* @param file
* @param reqDto
* @return
*/
@Override
public OssUploadFileResDto uploadFileBody(MultipartFile file, OssUploadFileReqDto reqDto) {
//获取Security上下文当前用户的登录信息
AuthUserDto authUserDto = SecurityUtil.getCurrentLoginUser();
OssUploadFileResDto ossUploadFileDto = new OssUploadFileResDto();
// 记录开始时间
long startTime = System.currentTimeMillis();
// 操作结果
String operationResult = "success";
// 错误信息
String errorMessage = null;
// 文件记录
OssFile ossFile = null;
//文件输入流
InputStream inputStream = null;
//原始文件名
String fileName = file.getOriginalFilename();
//文件扩展名
String type = FileUtil.getFileType(file.getOriginalFilename());
try {
inputStream = file.getInputStream();
} catch (IOException e) {
e.printStackTrace();
throw new BusinessException("文件输入流解析异常:{}");
}
try {
// 读取输入流到字节数组
byte[] fileData = FileUtil.readInputStreamToBytes(inputStream);
long fileSize = fileData.length;
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(fileData);
// 生成文件key
String fileKey = FileUtil.generateFileKey(fileName,type);
//默认阿里云的桶名
String actualBucket = defaultBucket;
//获取文件扩展名
String fileType = FileUtil.getFileType(fileName);
// 创建上传请求
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(fileSize);
metadata.setContentType(FileUtil.getContentType(fileType));
// 设置公共读权限(如果需要)
// metadata.setObjectAcl(CannedAccessControlList.PublicRead);
PutObjectRequest putObjectRequest = new PutObjectRequest(
actualBucket, fileKey, byteArrayInputStream, metadata);
// 上传文件
ossClient.putObject(putObjectRequest);
// 创建文件记录
ossFile = new OssFile();
ossFile.setFileBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_OSS_FILE.getCode()));
ossFile.setFileKey(fileKey);
ossFile.setOriginalName(fileName);
ossFile.setFileSize(fileSize);
ossFile.setFileType(fileType);
ossFile.setProviderBizId(currentProvider.getProviderBizId());
ossFile.setBucketName(actualBucket);
ossFile.setUploadUser(reqDto.getUploadUser());
//存储对象信息
ossFile.setObjectBizId(reqDto.getObjectBizId());
ossFile.setObjectName(reqDto.getObjectName());
ossFile.setObjectTableName(reqDto.getObjectTableName());
ossFile.setObjectType(reqDto.getObjectType());
ossFile.setCreatorId(authUserDto.getUserBizId());
ossFile.setCreatorName(authUserDto.getUsername());
// 保存文件元数据到数据库
ossFileService.saveFileMetadata(ossFile);
// 创建操作日志
OssOperationLog operationLog = new OssOperationLog();
operationLog.setFileBizId(ossFile.getFileBizId());
operationLog.setOperationType("upload");
operationLog.setOperationUser(reqDto.getUploadUser());
operationLog.setOperationResult(operationResult);
operationLog.setErrorMessage(errorMessage);
operationLog.setClientIp(IpUtil.getClientIp());
operationLog.setCostTime(System.currentTimeMillis() - startTime);
// 保存操作日志到数据库
ossFileService.saveOperationLog(operationLog);
log.info("文件上传成功: {} -> {}/{}", fileName, actualBucket, fileKey);
ossUploadFileDto.setFileBizId(ossFile.getFileBizId());
ossUploadFileDto.setFileKey(fileKey);
ossUploadFileDto.setOriginalName(fileName);
// 如果设置了公共读,可以直接拼接URL
String publicUrl = "https://" + actualBucket + "." + defaultEndpoint + "/" + fileKey;
ossUploadFileDto.setUrl(publicUrl);
ossUploadFileDto.setFileSize(fileSize);
ossUploadFileDto.setFileType(fileType);
return ossUploadFileDto;
} catch (Exception e) {
// 标记操作失败
operationResult = "failure";
// 记录错误信息
errorMessage = e.getMessage();
log.error("阿里云OSS上传文件失败: {}", fileName, e);
throw new RuntimeException("阿里云OSS上传文件失败: " + fileName, e);
} finally {
// 关闭资源
FileUtil.closeQuietly(inputStream);
// 记录失败日志
if ("failure".equals(operationResult)) {
OssOperationLog operationLog = new OssOperationLog();
if (ossFile != null) {
operationLog.setFileBizId(ossFile.getFileBizId());
} else {
// 使用无效文件ID
operationLog.setFileBizId("-1");
}
operationLog.setOperationType("upload");
operationLog.setOperationUser(reqDto.getUploadUser());
operationLog.setOperationResult(operationResult);
operationLog.setErrorMessage(errorMessage);
operationLog.setClientIp(IpUtil.getClientIp());
operationLog.setCostTime(System.currentTimeMillis() - startTime);
// 保存操作日志到数据库
ossFileService.saveOperationLog(operationLog);
}
}
}
/**
* 上传文件(使用默认存储桶)
* @param inputStream
* @param fileName
......@@ -645,4 +787,60 @@ public class AliYunOssServiceImpl implements OssService {
}
}
/**
* 批量上传文件
* @param files 文件列表
* @param reqDto 上传请求参数
* @return 批量上传响应
*/
@Override
public com.yd.oss.feign.response.ApiBatchUploadResponse batchUploadFiles(
java.util.List<MultipartFile> files, OssUploadFileReqDto reqDto) {
com.yd.oss.feign.response.ApiBatchUploadResponse response = new com.yd.oss.feign.response.ApiBatchUploadResponse();
java.util.List<com.yd.oss.feign.response.ApiUploadResponse> successFiles = new java.util.ArrayList<>();
java.util.List<com.yd.oss.feign.response.ApiBatchUploadResponse.FailedFile> failedFiles = new java.util.ArrayList<>();
if (files == null || files.isEmpty()) {
response.setSuccessFiles(successFiles);
response.setFailedFiles(failedFiles);
response.setSuccessCount(0);
response.setFailedCount(0);
return response;
}
for (MultipartFile file : files) {
try {
// 调用单文件上传方法
OssUploadFileResDto uploadResult = uploadFileBody(file, reqDto);
// 转换为ApiUploadResponse
com.yd.oss.feign.response.ApiUploadResponse uploadResponse = new com.yd.oss.feign.response.ApiUploadResponse();
uploadResponse.setFileBizId(uploadResult.getFileBizId());
uploadResponse.setFileKey(uploadResult.getFileKey());
uploadResponse.setOriginalName(uploadResult.getOriginalName());
uploadResponse.setUrl(uploadResult.getUrl());
uploadResponse.setFileSize(uploadResult.getFileSize());
uploadResponse.setFileType(uploadResult.getFileType());
successFiles.add(uploadResponse);
} catch (Exception e) {
log.error("批量上传文件失败: {}", file.getOriginalFilename(), e);
com.yd.oss.feign.response.ApiBatchUploadResponse.FailedFile failedFile =
new com.yd.oss.feign.response.ApiBatchUploadResponse.FailedFile();
failedFile.setFileName(file.getOriginalFilename());
failedFile.setReason(e.getMessage());
failedFiles.add(failedFile);
}
}
response.setSuccessFiles(successFiles);
response.setFailedFiles(failedFiles);
response.setSuccessCount(successFiles.size());
response.setFailedCount(failedFiles.size());
log.info("批量上传完成: 成功{}个, 失败{}个", successFiles.size(), failedFiles.size());
return response;
}
}
package com.yd.oss.service.service.impl;
import com.yd.common.result.Result;
import com.yd.oss.feign.dto.ApiMaterialDto;
import com.yd.oss.feign.request.ApiMaterialDownloadRequest;
import com.yd.oss.feign.response.ApiMaterialDownloadResponse;
import com.yd.oss.service.service.CompressedFileService;
import com.yd.oss.service.service.OssService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* 压缩包服务
*/
@Slf4j
@Service
public class CompressedFileServiceImpl implements CompressedFileService {
@Autowired
private OssService ossService;
@Autowired
private String defaultBucket; // 注入默认存储桶
@Autowired
private String defaultEndpoint; // 注入默认服务端点
/**
* 下载-材料列表压缩包
* @param request
* @return
*/
@Override
public Result<ApiMaterialDownloadResponse> downloadCompressedFile(ApiMaterialDownloadRequest request) {
try {
// 验证请求参数
if (request == null || CollectionUtils.isEmpty(request.getApiMaterialDtoList())) {
return Result.fail("材料列表不能为空");
}
if (!StringUtils.hasText(request.getObjectName())) {
return Result.fail("对象名(包名)不能为空");
}
// 创建临时压缩文件
File tempZipFile = createTempZipFile();
int successFileCount = 0; // 成功添加的文件计数
try (FileOutputStream fos = new FileOutputStream(tempZipFile);
ZipOutputStream zos = new ZipOutputStream(fos, StandardCharsets.UTF_8)) {
// 处理每个材料
for (ApiMaterialDto materialDto : request.getApiMaterialDtoList()) {
String folderName = buildFolderName(materialDto);
// 处理每个文件的URL
if (!CollectionUtils.isEmpty(materialDto.getFileUrlList())) {
for (int i = 0; i < materialDto.getFileUrlList().size(); i++) {
String fileUrl = materialDto.getFileUrlList().get(i);
try {
// 下载文件并添加到压缩包
boolean success = addFileToZip(zos, fileUrl, folderName, i + 1);
if (success) {
successFileCount++;
}
} catch (Exception e) {
log.warn("文件下载失败,URL: {}", fileUrl, e);
// 继续处理其他文件
}
}
}
}
// 刷新并关闭流
zos.flush();
zos.finish();
// 如果没有成功添加任何文件,返回错误
if (successFileCount == 0) {
return Result.fail("没有有效的文件可下载");
}
log.info("成功添加 {} 个文件到压缩包,压缩包大小: {} 字节",
successFileCount, tempZipFile.length());
// 上传压缩包到OSS
String ossUrl = uploadZipToOss(tempZipFile, request.getObjectName());
// 构建响应
ApiMaterialDownloadResponse response = new ApiMaterialDownloadResponse();
response.setUrl(ossUrl);
return Result.success(response);
} catch (Exception e) {
log.error("创建压缩包失败", e);
return Result.fail("创建压缩包失败: " + e.getMessage());
} finally {
// 清理临时文件
if (tempZipFile.exists()) {
try {
tempZipFile.delete();
} catch (Exception e) {
log.warn("清理临时文件失败", e);
}
}
}
} catch (Exception e) {
log.error("下载材料压缩包失败", e);
return Result.fail("下载材料压缩包失败: " + e.getMessage());
}
}
/**
* 创建临时压缩文件
*/
private File createTempZipFile() throws IOException {
String tempDir = System.getProperty("java.io.tmpdir");
String fileName = "material_zip_" + System.currentTimeMillis() + "_" + UUID.randomUUID() + ".zip";
File tempFile = new File(tempDir, fileName);
log.debug("创建临时压缩文件: {}", tempFile.getAbsolutePath());
return tempFile;
}
/**
* 构建文件夹名称:资料人-资料类型
*/
private String buildFolderName(ApiMaterialDto materialDto) {
String dataPerson = StringUtils.hasText(materialDto.getDataPerson()) ?
materialDto.getDataPerson() : "未知资料人";
String dataType = StringUtils.hasText(materialDto.getDataType()) ?
materialDto.getDataType() : "未知类型";
// 清理非法文件名字符
String folderName = dataPerson + "-" + dataType;
folderName = folderName.replaceAll("[\\\\/:*?\"<>|]", "_");
return folderName;
}
/**
* 下载文件并添加到压缩包
*/
private boolean addFileToZip(ZipOutputStream zos, String fileUrl, String folderName, int fileIndex) throws Exception {
// 从URL中提取文件名
String fileName = extractFileNameFromUrl(fileUrl, fileIndex);
// 构建zip中的完整路径
String zipEntryName = folderName + "/" + fileName;
// 从OSS下载文件
InputStream fileInputStream = downloadFileFromUrl(fileUrl);
if (fileInputStream == null) {
throw new IOException("无法下载文件: " + fileUrl);
}
try {
// 创建zip entry
ZipEntry zipEntry = new ZipEntry(zipEntryName);
zos.putNextEntry(zipEntry);
// 将文件内容写入zip
byte[] buffer = new byte[8192];
int length;
int totalBytes = 0;
while ((length = fileInputStream.read(buffer)) > 0) {
zos.write(buffer, 0, length);
totalBytes += length;
}
zos.closeEntry();
log.debug("成功添加文件到压缩包: {} ({} 字节)", zipEntryName, totalBytes);
return true;
} finally {
try {
fileInputStream.close();
} catch (IOException e) {
log.warn("关闭文件流失败", e);
}
}
}
/**
* 从URL中提取文件名
*/
private String extractFileNameFromUrl(String fileUrl, int fileIndex) {
if (!StringUtils.hasText(fileUrl)) {
return "file_" + fileIndex;
}
try {
// 尝试从URL中提取文件名
int lastSlashIndex = fileUrl.lastIndexOf('/');
if (lastSlashIndex >= 0 && lastSlashIndex < fileUrl.length() - 1) {
String fileName = fileUrl.substring(lastSlashIndex + 1);
// 清理文件名
int queryIndex = fileName.indexOf('?');
if (queryIndex > 0) {
fileName = fileName.substring(0, queryIndex);
}
if (StringUtils.hasText(fileName) && fileName.length() < 255) {
return fileName;
}
}
} catch (Exception e) {
log.warn("从URL提取文件名失败: {}", fileUrl, e);
}
// 默认文件名
return "file_" + fileIndex + getFileExtensionFromUrl(fileUrl);
}
/**
* 从URL获取文件扩展名
*/
private String getFileExtensionFromUrl(String fileUrl) {
if (!StringUtils.hasText(fileUrl)) {
return "";
}
try {
// 获取扩展名
int dotIndex = fileUrl.lastIndexOf('.');
if (dotIndex > 0 && dotIndex < fileUrl.length() - 1) {
String ext = fileUrl.substring(dotIndex);
int queryIndex = ext.indexOf('?');
if (queryIndex > 0) {
ext = ext.substring(0, queryIndex);
}
// 只保留常见的文件扩展名
if (ext.length() <= 5 && ext.matches("\\.[a-zA-Z0-9]{1,4}")) {
return ext;
}
}
} catch (Exception e) {
log.warn("获取文件扩展名失败", e);
}
return "";
}
/**
* 从URL下载文件
*/
private InputStream downloadFileFromUrl(String fileUrl) {
try {
// 方法1: 尝试从OSS下载(如果URL是我们OSS的)
String fileKey = extractFileKeyFromUrl(fileUrl);
if (StringUtils.hasText(fileKey)) {
log.debug("从OSS下载文件,fileKey: {}", fileKey);
return ossService.downloadFile(fileKey);
}
// 方法2: 尝试HTTP下载
log.debug("尝试HTTP下载文件: {}", fileUrl);
return downloadFileByHttp(fileUrl);
} catch (Exception e) {
log.error("下载文件失败: {}", fileUrl, e);
return null;
}
}
/**
* 从完整URL中提取OSS文件key
*/
private String extractFileKeyFromUrl(String fileUrl) {
if (!StringUtils.hasText(fileUrl)) {
return null;
}
try {
// 你提供的URL格式: https://yd-ali-oss.oss-cn-shanghai-finance-1-pub.aliyuncs.com/docx/2026/01/06/166b192397f84055aaec968d20e57977.docx
// 移除协议前缀
String url = fileUrl;
if (url.startsWith("https://")) {
url = url.substring(8);
} else if (url.startsWith("http://")) {
url = url.substring(7);
}
// 从配置获取endpoint
String endpoint = defaultEndpoint;
// 查找bucket.endpoint组合
String bucketEndpoint = defaultBucket + "." + endpoint;
int bucketEndpointIndex = url.indexOf(bucketEndpoint);
if (bucketEndpointIndex >= 0) {
// 提取bucket.endpoint之后的部分
int startIndex = bucketEndpointIndex + bucketEndpoint.length();
if (url.charAt(startIndex) == '/') {
startIndex++;
}
String fileKey = url.substring(startIndex);
// 移除查询参数
int queryIndex = fileKey.indexOf('?');
if (queryIndex > 0) {
fileKey = fileKey.substring(0, queryIndex);
}
log.debug("从URL提取fileKey: {} -> {}", fileUrl, fileKey);
return fileKey;
}
// 尝试其他可能的格式
int firstSlashIndex = url.indexOf('/');
if (firstSlashIndex > 0) {
String fileKey = url.substring(firstSlashIndex + 1);
// 移除查询参数
int queryIndex = fileKey.indexOf('?');
if (queryIndex > 0) {
fileKey = fileKey.substring(0, queryIndex);
}
log.debug("从URL提取fileKey(备选): {} -> {}", fileUrl, fileKey);
return fileKey;
}
} catch (Exception e) {
log.warn("从URL提取文件key失败: {}", fileUrl, e);
}
return null;
}
/**
* HTTP下载文件
*/
private InputStream downloadFileByHttp(String fileUrl) {
try {
URL url = new URL(fileUrl);
URLConnection connection = url.openConnection();
connection.setConnectTimeout(10000); // 10秒连接超时
connection.setReadTimeout(30000); // 30秒读取超时
// 设置User-Agent,避免被某些服务器拒绝
connection.setRequestProperty("User-Agent",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
return connection.getInputStream();
} catch (Exception e) {
log.error("HTTP下载文件失败: {}", fileUrl, e);
return null;
}
}
/**
* 上传压缩包到OSS
*/
private String uploadZipToOss(File zipFile, String objectName) throws Exception {
if (!zipFile.exists() || zipFile.length() == 0) {
throw new IOException("压缩文件不存在或为空");
}
try (FileInputStream fis = new FileInputStream(zipFile)) {
// 生成压缩包文件名
String zipFileName = generateZipFileName(objectName);
log.info("上传压缩包到OSS,文件大小: {} 字节,文件名: {}",
zipFile.length(), zipFileName);
// 检查是否使用阿里云OSS实现
if (ossService instanceof AliYunOssServiceImpl) {
AliYunOssServiceImpl aliYunOssService = (AliYunOssServiceImpl) ossService;
// 使用反射调用upload方法(兼容性更好)
try {
// 方法1: 直接调用public方法
java.lang.reflect.Method uploadMethod = AliYunOssServiceImpl.class
.getMethod("upload", InputStream.class, String.class);
String ossUrl = (String) uploadMethod.invoke(aliYunOssService, fis, zipFileName);
log.info("压缩包上传成功,URL: {}", ossUrl);
return ossUrl;
} catch (NoSuchMethodException e) {
// 方法2: 尝试其他可能的upload方法
log.warn("未找到upload(InputStream, String)方法,尝试其他方法");
// 转换为字节数组上传
byte[] zipBytes = readFileToBytes(zipFile);
try {
java.lang.reflect.Method uploadMethod2 = AliYunOssServiceImpl.class
.getMethod("upload", byte[].class, String.class);
String ossUrl = (String) uploadMethod2.invoke(aliYunOssService, zipBytes, zipFileName);
log.info("压缩包上传成功,URL: {}", ossUrl);
return ossUrl;
} catch (NoSuchMethodException e2) {
// 最后尝试:使用现有的uploadFile方法
log.info("尝试使用现有的uploadFile方法");
return uploadUsingExistingMethod(fis, zipFileName, "system");
}
}
} else {
throw new UnsupportedOperationException("不支持的OSS服务类型");
}
}
}
/**
* 使用现有的uploadFile方法上传
*/
private String uploadUsingExistingMethod(InputStream inputStream, String fileName, String uploadUser) throws Exception {
// 这里需要根据你的OssService接口的具体方法进行调整
// 假设有uploadFile(InputStream, String, String)方法
try {
// 读取整个文件到字节数组
byte[] fileData = readInputStreamToBytes(inputStream);
// 使用反射调用upload(byte[], String)方法
java.lang.reflect.Method uploadMethod = AliYunOssServiceImpl.class
.getMethod("upload", byte[].class, String.class);
AliYunOssServiceImpl aliYunOssService = (AliYunOssServiceImpl) ossService;
return (String) uploadMethod.invoke(aliYunOssService, fileData, fileName);
} catch (Exception e) {
log.error("使用现有方法上传失败", e);
throw e;
}
}
/**
* 读取文件到字节数组
*/
private byte[] readFileToBytes(File file) throws IOException {
try (FileInputStream fis = new FileInputStream(file);
ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
byte[] buffer = new byte[8192];
int length;
while ((length = fis.read(buffer)) > 0) {
bos.write(buffer, 0, length);
}
return bos.toByteArray();
}
}
/**
* 读取输入流到字节数组
*/
private byte[] readInputStreamToBytes(InputStream inputStream) throws IOException {
try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
byte[] buffer = new byte[8192];
int length;
while ((length = inputStream.read(buffer)) > 0) {
bos.write(buffer, 0, length);
}
return bos.toByteArray();
}
}
/**
* 生成压缩包文件名
*/
private String generateZipFileName(String objectName) {
// 清理非法字符
String safeObjectName = objectName.replaceAll("[\\\\/:*?\"<>|]", "_");
// 添加时间戳和扩展名
String fileName = safeObjectName + "_" +
new java.text.SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()) +
".zip";
log.debug("生成的压缩包文件名: {}", fileName);
return fileName;
}
}
\ No newline at end of file
......@@ -6,7 +6,7 @@ import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import com.yd.oss.feign.dto.ExportParam;
import com.yd.oss.feign.dto.ExportResult;
import com.yd.oss.service.dto.OssUploadFileDto;
import com.yd.oss.service.dto.OssUploadFileResDto;
import com.yd.oss.service.service.ExcelExportService;
import com.yd.oss.service.service.OssService;
import lombok.extern.slf4j.Slf4j;
......@@ -110,7 +110,7 @@ public class ExcelExportServiceImpl implements ExcelExportService {
String fileName = generateExcelFileName(exportParam.getFileName());
// 调用OSS服务上传文件到云端存储
OssUploadFileDto uploadResult = ossService.uploadFile(
OssUploadFileResDto uploadResult = ossService.uploadFile(
inputStream, // Excel文件输入流
fileName, // 生成的文件名
"", // 存储桶名称(空字符串表示使用默认存储桶)
......
......@@ -33,34 +33,40 @@ public class ExcelImportServiceImpl implements ExcelImportService {
public ImportResult genericImport(MultipartFile file,
Integer headerRow,
Integer dataStartRow,
List<String> requiredFields) {
List<String> requiredFields,Integer checkStartRow) {
ImportResult result = new ImportResult();
log.info("开始导入Excel,文件名:{},headerRow:{},dataStartRow:{}",
file.getOriginalFilename(), headerRow, dataStartRow);
try {
// 参数默认值处理
int headerRowNum = headerRow != null ? headerRow : 0;
int dataStartRowNum = dataStartRow != null ? dataStartRow : 1;
log.info("实际参数:headerRowNum={}, dataStartRowNum={}", headerRowNum, dataStartRowNum);
// 1. 获取表头信息
List<String> headers = getExcelHeaders(file, headerRowNum);
log.info("获取到表头:{}", headers);
result.setHeaders(headers);
// 2. 导入Excel数据
ExcelImportResult<Map<String, Object>> importResult =
importExcel(file, headerRowNum, dataStartRowNum);
System.out.println(JSON.toJSONString(importResult.getList()));
// 3. 处理导入结果
List<Map<String, Object>> data =
processImportResult(importResult, headers);
log.info("处理后数据行数:{}", data.size());
result.setData(data);
result.setTotalCount(data.size());
// 4. 数据验证
if (requiredFields != null && !requiredFields.isEmpty()) {
ValidationResult validationResult =
validateData(data, requiredFields);
validateData(data, requiredFields, dataStartRowNum,checkStartRow); // 传入dataStartRowNum
result.setValid(validationResult.isValid());
result.setErrorMessages(validationResult.getErrors());
} else {
......@@ -71,8 +77,13 @@ public class ExcelImportServiceImpl implements ExcelImportService {
result.setMessage("导入成功,共导入" + data.size() + "条数据");
} catch (Exception e) {
log.error("Excel导入失败", e);
result.setSuccess(false);
result.setMessage("导入失败:" + e.getMessage());
String errorMsg = e.getMessage();
if (errorMsg == null || errorMsg.isEmpty()) {
errorMsg = e.getClass().getSimpleName();
}
result.setMessage("导入失败:" + errorMsg);
}
return result;
......@@ -85,7 +96,7 @@ public class ExcelImportServiceImpl implements ExcelImportService {
*/
@Override
public ImportResult simpleImport(MultipartFile file) {
return genericImport(file, 0, 1, null);
return genericImport(file, 0, 1, null,null);
}
/**
......@@ -100,22 +111,35 @@ public class ExcelImportServiceImpl implements ExcelImportService {
int headerRowNum,
int dataStartRowNum) throws Exception {
ImportParams params = new ImportParams();
params.setHeadRows(headerRowNum + 1); // 表头行数(从1开始计数)
// 检查文件是否为空
if (file == null || file.isEmpty()) {
throw new IllegalArgumentException("文件不能为空");
}
// EasyPOI的startRows是从0开始计数,但表示的是跳过多少行
// 如果要从第2行开始(索引1),需要设置为1,但这样会跳过第2行
// 正确的做法:如果要读取从dataStartRowNum开始的行,应该设置为dataStartRowNum
params.setStartRows(dataStartRowNum);
// 检查文件格式
String originalFilename = file.getOriginalFilename();
if (originalFilename == null ||
(!originalFilename.endsWith(".xlsx") && !originalFilename.endsWith(".xls"))) {
throw new IllegalArgumentException("仅支持Excel文件(.xlsx, .xls)");
}
params.setNeedVerify(true);
ImportParams params = new ImportParams();
params.setHeadRows(headerRowNum + 1); // 表头行数
params.setStartRows(0); // 数据开始行
params.setNeedVerify(true); // 需要校验
try {
// 使用Map接收数据
return ExcelImportUtil.importExcelMore(
file.getInputStream(),
Map.class,
params
);
} catch (Exception e) {
log.error("Excel导入失败,文件:{},headerRow:{},dataStartRow:{}",
originalFilename, headerRowNum, dataStartRowNum, e);
throw new RuntimeException("Excel解析失败:" + e.getMessage(), e);
}
}
/**
......@@ -202,37 +226,48 @@ public class ExcelImportServiceImpl implements ExcelImportService {
}
/**
* 判断一行数据是否为空行
* @param rowData 行数据
* @param headers 表头列表
* @return true-空行, false-非空行
* 判断一行数据是否为空行(更严格的条件)
*/
private static boolean isEmptyRow(Map<String, Object> rowData, List<String> headers) {
if (rowData == null || rowData.isEmpty()) {
return true;
}
// 检查所有业务字段是否都为空(排除excelRowNum等系统字段)
// 方法1:检查所有业务字段是否都为空
for (String header : headers) {
Object value = rowData.get(header);
if (value != null && !value.toString().trim().isEmpty()) {
return false; // 发现非空值,不是空行
if (value != null) {
String strValue = value.toString().trim();
// 排除常见的空值表示
if (!strValue.isEmpty() &&
!strValue.equals("-") &&
!strValue.equals("null") &&
!strValue.equals("NULL")) {
return false;
}
}
}
// 方法2:检查所有键值对(包括系统字段)
int validCount = 0;
for (Map.Entry<String, Object> entry : rowData.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
// 额外检查:如果只有系统字段有值,也算空行
boolean hasOnlySystemFields = true;
for (String key : rowData.keySet()) {
if (!key.equals("excelRowNum") && !key.startsWith("_")) {
Object value = rowData.get(key);
if (value != null && !value.toString().trim().isEmpty()) {
hasOnlySystemFields = false;
break;
// 跳过系统字段
if (key.equals("excelRowNum") || key.startsWith("_")) {
continue;
}
if (value != null) {
String strValue = value.toString().trim();
if (!strValue.isEmpty()) {
validCount++;
}
}
}
return hasOnlySystemFields;
return validCount == 0;
}
/**
......@@ -241,25 +276,25 @@ public class ExcelImportServiceImpl implements ExcelImportService {
* @param requiredFields 必填字段
* @return 验证结果
*/
public static ValidationResult validateData(List<Map<String, Object>> data, List<String> requiredFields) {
public static ValidationResult validateData(List<Map<String, Object>> data,
List<String> requiredFields,
int dataStartRow,Integer checkStartRow) { // 新增参数
ValidationResult result = new ValidationResult();
result.setValid(true);
for (int i = 0; i < data.size(); i++) {
Map<String, Object> row = data.get(i);
int rowNum = i + 1; // 实际行号(从1开始)
// int excelRowNum = dataStartRow + i + 1; // 计算Excel中的实际行号
Integer excelRowNum = checkStartRow + i - 1; // 计算Excel中的实际行号
// 检查必填字段
for (String field : requiredFields) {
Object value = row.get(field);
if (value == null || value.toString().trim().isEmpty()) {
result.setValid(false);
result.getErrors().add("第" + rowNum + "行,字段[" + field + "]不能为空");
result.getErrors().add("第" + excelRowNum + "行,字段[" + field + "]不能为空");
}
}
// 这里可以添加更多的验证规则
// 例如:数据类型验证、格式验证等
}
return result;
}
......
package com.yd.oss.service.service.impl;
import com.aliyun.oss.OSS;
import com.aliyun.oss.model.PutObjectRequest;
import com.yd.oss.service.dao.ProductFileMapper;
import com.yd.oss.service.model.ProductFile;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.List;
import java.util.UUID;
@Service
@Slf4j
public class FileUploadService {
@Autowired
private OSS ossClient;
@Autowired
private ProductFileMapper productFileMapper;
@Autowired
private String defaultBucket; // 从配置注入默认存储桶
@Autowired
private String defaultEndpoint; // 注入默认服务端点
/**
* 批量处理URL上传
*/
public void batchProcessUrls() {
List<ProductFile> productFileList = productFileMapper.selectList(null);
for (ProductFile productFile : productFileList) {
try {
// 处理单个URL
processSingleUrl(productFile);
} catch (Exception e) {
log.error("处理URL失败: {}, 错误: {}", productFile.getOldFileUrl(), e.getMessage());
}
}
}
/**
* 处理单个URL
*/
private void processSingleUrl(ProductFile productFile) throws Exception {
// 1. 下载文件
byte[] fileContent = downloadFile(productFile.getOldFileUrl());
// 2. 生成OSS文件名(使用原始URL路径)
String ossFileName = generateOssFileName(productFile.getOldFileUrl(), "");
// 3. 上传到阿里云OSS
String ossUrl = uploadToAliOss(fileContent, ossFileName);
// 4. 更新数据库
productFile.setNewFileUrl(ossUrl);
productFileMapper.updateById(productFile);
log.info("文件上传成功: {} -> {}", productFile.getFileName(), ossUrl);
}
/**
* 下载文件
*/
private byte[] downloadFile(String fileUrl) throws Exception {
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet(fileUrl);
try (CloseableHttpResponse response = httpClient.execute(httpGet);
InputStream inputStream = response.getEntity().getContent()) {
return IOUtils.toByteArray(inputStream);
} finally {
httpClient.close();
}
}
/**
* 生成OSS文件名 - 保留原始URL路径结构
*/
private String generateOssFileName(String originalUrl, String originalFileName) {
try {
// 解析原始URL,提取路径部分
URL url = new URL(originalUrl);
String path = url.getPath(); // 得到类似:/wslucky/product/2024/12/27/9ba093ee-be9a-4291-aa86-d6a1995e16f9.pdf
// 移除开头的斜杠(如果有)
if (path.startsWith("/")) {
path = path.substring(1);
}
// 如果路径为空,使用备选方案
if (path.isEmpty()) {
return generateFallbackFileName(originalFileName);
}
return path;
} catch (Exception e) {
log.warn("解析URL路径失败: {}, 使用备选方案", originalUrl, e);
return generateFallbackFileName(originalFileName);
}
}
/**
* 备选文件名生成方案
*/
private String generateFallbackFileName(String originalFileName) {
String fileExtension = originalFileName.substring(originalFileName.lastIndexOf("."));
String timestamp = String.valueOf(System.currentTimeMillis());
String randomStr = UUID.randomUUID().toString().replace("-", "").substring(0, 8);
return "insurance/" + timestamp + "_" + randomStr + fileExtension;
}
/**
* 上传到阿里云OSS
*/
private String uploadToAliOss(byte[] fileContent, String ossFileName) {
// 创建上传请求
PutObjectRequest putObjectRequest = new PutObjectRequest(defaultBucket, ossFileName,
new ByteArrayInputStream(fileContent));
// 上传文件
ossClient.putObject(putObjectRequest);
// 生成访问URL
return String.format("https://%s.%s/%s", defaultBucket,
defaultEndpoint, ossFileName);
}
}
\ No newline at end of file
package com.yd.oss.service.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yd.oss.service.dto.MaterialDto;
import com.yd.oss.service.model.Material;
import com.yd.oss.service.dao.MaterialMapper;
import com.yd.oss.service.service.IMaterialService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* <p>
* 材料基础信息 服务实现类
* </p>
*
* @author zxm
* @since 2025-12-17
*/
@Service
public class MaterialServiceImpl extends ServiceImpl<MaterialMapper, Material> implements IMaterialService {
@Override
public List<Material> queryList(MaterialDto dto) {
return this.baseMapper.selectList(new LambdaQueryWrapper<Material>()
.eq(Material::getObjectType,dto.getObjectType()));
}
}
package com.yd.oss.service.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yd.common.exception.BusinessException;
import com.yd.oss.feign.response.ApiOssFileListResponse;
import com.yd.oss.service.dao.OssOperationLogMapper;
import com.yd.oss.service.dto.OssFileDto;
import com.yd.oss.service.model.OssFile;
import com.yd.oss.service.dao.OssFileMapper;
import com.yd.oss.service.model.OssOperationLog;
import com.yd.oss.service.service.IOssFileService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
......@@ -30,10 +36,10 @@ import java.util.List;
@Service
public class OssFileServiceImpl extends ServiceImpl<OssFileMapper, OssFile> implements IOssFileService {
@Autowired
@Resource
private OssFileMapper ossFileMapper;
@Autowired
@Resource
private OssOperationLogMapper ossOperationLogMapper;
/**
......@@ -128,5 +134,29 @@ public class OssFileServiceImpl extends ServiceImpl<OssFileMapper, OssFile> impl
return ossOperationLogMapper.selectByFileId(fileId);
}
/**
* 查询列表
* @param dto
* @return
*/
@Override
public List<OssFile> queryList(OssFileDto dto) {
List<OssFile> list = baseMapper.selectList(new LambdaQueryWrapper<OssFile>()
.eq(StringUtils.isNotBlank(dto.getObjectBizId()),OssFile::getObjectBizId,dto.getObjectBizId())
.in(!CollectionUtils.isEmpty(dto.getFileBizIdList()),OssFile::getFileBizId,dto.getFileBizIdList())
);
return list;
}
@Override
public OssFile queryOne(String fileBizId) {
return this.getOne(new LambdaQueryWrapper<OssFile>().eq(OssFile::getFileBizId,fileBizId));
}
@Override
public List<ApiOssFileListResponse> list(String objectBizId,List<String> objectBizIdList) {
return this.baseMapper.list(objectBizId,objectBizIdList);
}
}
......@@ -9,6 +9,7 @@ import com.yd.oss.service.dto.FileProdDto;
import com.yd.oss.service.service.*;
import com.yd.oss.service.utils.PdfUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xwpf.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
......@@ -45,10 +46,11 @@ public class PdfServiceImpl<T> implements PdfService<T> {
* @param dataObject
* @param objectId
* @param templateType
* @param customFileName 自定义文件名
* @return
* @throws IOException
*/
public String generatePDF(T dataObject, String objectId, String templateType) throws IOException {
public String generatePDF(T dataObject, String objectId, String templateType,String customFileName) throws IOException {
// 获取模板信息
FileProdDto fileProdDto = iFileTemplateService.getFileProd("", templateType);
......@@ -68,7 +70,13 @@ public class PdfServiceImpl<T> implements PdfService<T> {
convertWordToPdf(tempInputFile, tempPdfFile, dataObject, fileProdDto);
// 上传到OSS
String objectName = "insurance_schedules/" + objectId + "_" + System.currentTimeMillis() + ".pdf";
String objectName = "";
if (StringUtils.isNotBlank(customFileName)) {
objectName = "insurance_schedules/" + System.currentTimeMillis() + "/" + customFileName + ".pdf";
}else {
objectName = "insurance_schedules/" + objectId + "_" + System.currentTimeMillis() + ".pdf";
}
uploadToOSS(tempPdfFile, fileProdDto.getBucketName(), objectName);
// 生成访问URL
......
package com.yd.oss.service.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yd.oss.feign.request.ApiRelObjectMaterialPageRequest;
import com.yd.oss.feign.response.ApiRelObjectMaterialPageResponse;
import com.yd.oss.service.model.RelObjectMaterial;
import com.yd.oss.service.dao.RelObjectMaterialMapper;
import com.yd.oss.service.service.IRelObjectMaterialService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* <p>
* 对象材料关系表 服务实现类
* </p>
*
* @author zxm
* @since 2025-12-17
*/
@Service
public class RelObjectMaterialServiceImpl extends ServiceImpl<RelObjectMaterialMapper, RelObjectMaterial> implements IRelObjectMaterialService {
@Override
public IPage<ApiRelObjectMaterialPageResponse> page(Page<ApiRelObjectMaterialPageResponse> page,
ApiRelObjectMaterialPageRequest request) {
return baseMapper.page(page,request);
}
@Override
public RelObjectMaterial queryOne(String relObjectMaterialBizId) {
return this.getOne(new LambdaQueryWrapper<RelObjectMaterial>()
.eq(RelObjectMaterial::getRelObjectMaterialBizId,relObjectMaterialBizId));
}
@Override
public Boolean delByObjectBizId(String objectBizId) {
return this.remove(new LambdaQueryWrapper<RelObjectMaterial>().eq(RelObjectMaterial::getObjectBizId,objectBizId));
}
@Override
public List<RelObjectMaterial> queryList(String objectBizId) {
return this.baseMapper.selectList(new LambdaQueryWrapper<RelObjectMaterial>().eq(RelObjectMaterial::getObjectBizId,objectBizId));
}
}
......@@ -5,11 +5,11 @@ import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
public class MyBatisPlusCodeGenerator {
public static void main(String[] args) {
FastAutoGenerator.create("jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8", "root", "123456")
FastAutoGenerator.create("jdbc:mysql://139.224.145.34:3308/yd_oss?serverTimezone=GMT%2B8", "root", "Zxm7320017")
.globalConfig(builder -> {
builder.author("zxm")
.outputDir("src/main/java/com/yd/oss/service");
// .outputDir("D:/soft/ideaproject/v2/yd-oss/yd-oss-service/src/main/java");
// .outputDir("src/main/java/com/yd/oss/service");
.outputDir("D:/soft/ideaproject/v2/yd-oss/yd-oss-service/src/main/java");
})
.packageConfig(builder -> {
builder.parent("com.yd.oss.service")
......@@ -21,7 +21,7 @@ public class MyBatisPlusCodeGenerator {
})
.strategyConfig(builder -> {
builder.addInclude(
"product_file"
"material","rel_object_material"
)
.entityBuilder()
.enableLombok()
......
<?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.yd.oss.service.dao.MaterialMapper">
</mapper>
......@@ -2,4 +2,22 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yd.oss.service.dao.OssFileMapper">
<select id="list" resultType="com.yd.oss.feign.response.ApiOssFileListResponse">
select o.*,
concat('https://', op.bucket_name, '.', op.endpoint, '/', o.file_key) as fileUrl
from oss_file o
left join oss_provider op on op.provider_biz_id = o.provider_biz_id and op.is_deleted = 0
<where>
<if test="objectBizId != null and objectBizId != ''">
and o.object_biz_id = #{objectBizId}
</if>
<if test="objectBizIdList != null and objectBizIdList.size > 0">
and o.object_biz_id in
<foreach collection="objectBizIdList" item="item" index="index" open="(" separator="," close=")">
#{item}
</foreach>
</if>
and o.is_deleted = 0
</where>
</select>
</mapper>
<?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.yd.oss.service.dao.RelObjectMaterialMapper">
<!-- 结果映射 -->
<resultMap id="RelObjectMaterialResponseMap" type="com.yd.oss.feign.response.ApiRelObjectMaterialPageResponse">
<id property="id" column="id"/>
<result property="relObjectMaterialBizId" column="rel_object_material_biz_id"/>
<result property="materialBizId" column="material_biz_id"/>
<result property="status" column="status"/>
<result property="dataPerson" column="data_person"/>
<result property="dataType" column="data_type"/>
<result property="precautions" column="precautions"/>
<!-- 使用类型处理器将分号分隔的字符串转换为List -->
<result property="fileUrlList" column="file_urls"
typeHandler="com.yd.oss.service.handler.StringToListTypeHandler"/>
</resultMap>
<select id="page" resultMap="RelObjectMaterialResponseMap">
SELECT
rom.id,
rom.rel_object_material_biz_id,
rom.material_biz_id,
rom.status,
m.data_person,
m.data_type,
m.precautions,
GROUP_CONCAT(
CONCAT('https://', f.bucket_name, '.', p.endpoint, '/', f.file_key)
SEPARATOR ';'
) as file_urls
FROM rel_object_material rom
LEFT JOIN material m ON m.material_biz_id = rom.material_biz_id AND m.is_deleted = 0
LEFT JOIN oss_file f ON f.object_biz_id = rom.rel_object_material_biz_id
AND f.object_table_name = 'rel_object_material'
AND f.is_deleted = 0
LEFT JOIN oss_provider p ON p.provider_biz_id = f.provider_biz_id
AND p.is_active = 1
AND p.is_deleted = 0
<where>
<if test="request.objectBizId != null and request.objectBizId != ''">
AND rom.object_biz_id = #{request.objectBizId}
</if>
AND rom.is_deleted = 0
</where>
GROUP BY rom.id
</select>
</mapper>
......@@ -68,6 +68,7 @@
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.13.2" level="project" />
<orderEntry type="library" name="Maven: com.yd:yd-csf-feign:1.0-SNAPSHOT" level="project" />
<orderEntry type="library" name="Maven: com.yd:yd-question-feign:1.0-SNAPSHOT" level="project" />
<orderEntry type="library" name="Maven: com.yd:yd-base-feign:1.0-SNAPSHOT" level="project" />
<orderEntry type="library" name="Maven: com.yd:yd-auth-core:1.0-SNAPSHOT" level="project" />
<orderEntry type="library" name="Maven: com.github.xiaoymin:knife4j-openapi3-spring-boot-starter:4.3.0" level="project" />
<orderEntry type="library" name="Maven: com.github.xiaoymin:knife4j-core:4.3.0" level="project" />
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment