feat(file): 优化文件上传功能并添加批量下载支持
- 修改文件上传接口,返回 FileUploadVO 对象包含文件信息 - 添加文件批量下载功能,支持压缩包下载 - 更新相关实体类和控制器以适应新的文件上传逻辑- 优化文件名处理,使用 UUID 生成唯一后缀
This commit is contained in:
parent
4fa4e8cdf5
commit
63a587f39e
|
|
@ -1,5 +1,7 @@
|
||||||
package com.nflg.mobilebroken.admin.controller;
|
package com.nflg.mobilebroken.admin.controller;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
|
import cn.hutool.core.util.IdUtil;
|
||||||
import cn.hutool.core.util.RandomUtil;
|
import cn.hutool.core.util.RandomUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.nflg.mobilebroken.admin.annotation.ApiMark;
|
import com.nflg.mobilebroken.admin.annotation.ApiMark;
|
||||||
|
|
@ -8,11 +10,22 @@ import com.nflg.mobilebroken.common.exception.NflgException;
|
||||||
import com.nflg.mobilebroken.common.pojo.ApiResult;
|
import com.nflg.mobilebroken.common.pojo.ApiResult;
|
||||||
import com.nflg.mobilebroken.common.pojo.PageData;
|
import com.nflg.mobilebroken.common.pojo.PageData;
|
||||||
import com.nflg.mobilebroken.common.pojo.request.FileSearchRequest;
|
import com.nflg.mobilebroken.common.pojo.request.FileSearchRequest;
|
||||||
|
import com.nflg.mobilebroken.common.pojo.vo.FileUploadVO;
|
||||||
import com.nflg.mobilebroken.common.pojo.vo.FileVO;
|
import com.nflg.mobilebroken.common.pojo.vo.FileVO;
|
||||||
import com.nflg.mobilebroken.common.util.AdminUserUtil;
|
import com.nflg.mobilebroken.common.util.AdminUserUtil;
|
||||||
|
import com.nflg.mobilebroken.common.util.DateTimeUtil;
|
||||||
|
import com.nflg.mobilebroken.common.util.VUtils;
|
||||||
import com.nflg.mobilebroken.repository.entity.FileUploadRecord;
|
import com.nflg.mobilebroken.repository.entity.FileUploadRecord;
|
||||||
import com.nflg.mobilebroken.repository.service.IFileUploadRecordService;
|
import com.nflg.mobilebroken.repository.service.IFileUploadRecordService;
|
||||||
import com.nflg.mobilebroken.starter.service.FileUploadService;
|
import com.nflg.mobilebroken.starter.service.FileUploadService;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
import org.apache.commons.io.FilenameUtils;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
|
@ -20,10 +33,18 @@ import javax.annotation.Resource;
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
import javax.validation.constraints.NotEmpty;
|
import javax.validation.constraints.NotEmpty;
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件管理相关接口
|
* 文件管理相关接口
|
||||||
|
|
@ -34,6 +55,8 @@ import java.util.List;
|
||||||
@RequestMapping("/file")
|
@RequestMapping("/file")
|
||||||
public class FileController extends ControllerBase {
|
public class FileController extends ControllerBase {
|
||||||
|
|
||||||
|
private final OkHttpClient client = new OkHttpClient();
|
||||||
|
|
||||||
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
|
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
|
|
@ -51,23 +74,24 @@ public class FileController extends ControllerBase {
|
||||||
*/
|
*/
|
||||||
@PostMapping("uploadSingleFile")
|
@PostMapping("uploadSingleFile")
|
||||||
@ApiMark(moduleName = "文件管理", apiName = "上传单个文件")
|
@ApiMark(moduleName = "文件管理", apiName = "上传单个文件")
|
||||||
public ApiResult<String> uploadSingleFile(@Valid @NotNull @RequestParam("file") MultipartFile file
|
public ApiResult<FileUploadVO> uploadSingleFile(@Valid @NotNull @RequestParam("file") MultipartFile file
|
||||||
,@Valid @NotNull @RequestParam("source") Byte source
|
,@Valid @NotNull @RequestParam("source") Byte source
|
||||||
,@Valid @NotNull @RequestParam("sourceId") Integer sourceId) {
|
,@Valid @NotNull @RequestParam("sourceId") Integer sourceId) {
|
||||||
try {
|
try {
|
||||||
String fileName=file.getOriginalFilename().substring(0,file.getOriginalFilename().lastIndexOf("."));
|
String fileName=file.getOriginalFilename();
|
||||||
String fileType=file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
|
String fileType=getFileType(fileName);
|
||||||
String url=fileUploadService.upload(buildFilePath(fileName,fileType), file);
|
String url=fileUploadService.upload(buildFilePath(fileType), file);
|
||||||
fileUploadRecordService.save(buildFileUploadRecord(source,sourceId,fileName,fileType,url));
|
FileUploadRecord record=buildFileUploadRecord(source,sourceId,fileName,fileType,url);
|
||||||
return ApiResult.success(url);
|
fileUploadRecordService.save(record);
|
||||||
|
return ApiResult.success(new FileUploadVO(record.getId(),fileName,url));
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
throw new NflgException(STATE.BusinessError, "上传文件失败:" + ex.getMessage());
|
throw new NflgException(STATE.BusinessError, "上传文件失败:" + ex.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String buildFilePath(String fileName, String fileType) {
|
private String buildFilePath(String fileType) {
|
||||||
return StrUtil.format("admin/{}/{}/{}/{}{}", LocalDateTime.now().format(FORMATTER), AdminUserUtil.getUserId()
|
return StrUtil.format("admin/{}/{}/{}/{}{}", LocalDateTime.now().format(FORMATTER), AdminUserUtil.getUserId()
|
||||||
, RandomUtil.randomString(4), fileName, fileType);
|
, RandomUtil.randomString(4), IdUtil.fastUUID(), fileType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -77,22 +101,22 @@ public class FileController extends ControllerBase {
|
||||||
* @param sourceId 文件来源id 对应来源的数据id,比如工单id,代理商id,管理端账户id
|
* @param sourceId 文件来源id 对应来源的数据id,比如工单id,代理商id,管理端账户id
|
||||||
* @return 可访问的文件url列表
|
* @return 可访问的文件url列表
|
||||||
*/
|
*/
|
||||||
|
@Transactional
|
||||||
@PostMapping("uploadMultipleFiles")
|
@PostMapping("uploadMultipleFiles")
|
||||||
@ApiMark(moduleName = "文件管理", apiName = "上传多个文件")
|
@ApiMark(moduleName = "文件管理", apiName = "上传多个文件")
|
||||||
public ApiResult<List<String>> uploadMultipleFiles(@Valid @RequestParam("files") @NotEmpty List<MultipartFile> files
|
public ApiResult<List<FileUploadVO>> uploadMultipleFiles(@Valid @RequestParam("files") @NotEmpty List<MultipartFile> files
|
||||||
,@Valid @NotNull @RequestParam("source") Byte source
|
,@Valid @NotNull @RequestParam("source") Byte source
|
||||||
,@Valid @NotNull @RequestParam("sourceId") Integer sourceId) {
|
,@Valid @NotNull @RequestParam("sourceId") Integer sourceId) {
|
||||||
try {
|
try {
|
||||||
List<String> list = new ArrayList<>();
|
List<FileUploadVO> list = new ArrayList<>();
|
||||||
List<FileUploadRecord> records = new ArrayList<>();
|
|
||||||
for (MultipartFile file : files) {
|
for (MultipartFile file : files) {
|
||||||
String fileName=file.getOriginalFilename().substring(0,file.getOriginalFilename().lastIndexOf("."));
|
String fileName=file.getOriginalFilename();
|
||||||
String fileType=file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
|
String fileType=getFileType(fileName);
|
||||||
String url=fileUploadService.upload(buildFilePath(fileName,fileType), file);
|
String url=fileUploadService.upload(buildFilePath(fileType), file);
|
||||||
list.add(url);
|
FileUploadRecord record=buildFileUploadRecord(source,sourceId,fileName,fileType,url);
|
||||||
records.add(buildFileUploadRecord(source,sourceId,fileName,fileType,url));
|
fileUploadRecordService.save(record);
|
||||||
|
list.add(new FileUploadVO(record.getId(),fileName,url));
|
||||||
}
|
}
|
||||||
fileUploadRecordService.saveBatch(records);
|
|
||||||
return ApiResult.success(list);
|
return ApiResult.success(list);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
throw new NflgException(STATE.BusinessError, "上传文件失败:" + ex.getMessage());
|
throw new NflgException(STATE.BusinessError, "上传文件失败:" + ex.getMessage());
|
||||||
|
|
@ -105,21 +129,24 @@ public class FileController extends ControllerBase {
|
||||||
* @return 可访问的文件url
|
* @return 可访问的文件url
|
||||||
*/
|
*/
|
||||||
@PostMapping("uploadSingleFile1")
|
@PostMapping("uploadSingleFile1")
|
||||||
public ApiResult<String> uploadSingleFile1(@Valid @NotNull @RequestParam("file") MultipartFile file) {
|
public ApiResult<FileUploadVO> uploadSingleFile1(@Valid @NotNull @RequestParam("file") MultipartFile file) {
|
||||||
try {
|
try {
|
||||||
String fileName=file.getOriginalFilename().substring(0,file.getOriginalFilename().lastIndexOf("."));
|
String fileName=file.getOriginalFilename();
|
||||||
String fileType=file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
|
String fileType=getFileType(fileName);
|
||||||
String url=fileUploadService.upload(buildFilePath(fileName,fileType), file);
|
String url=fileUploadService.upload(buildFilePath(fileType), file);
|
||||||
return ApiResult.success(url);
|
return ApiResult.success(new FileUploadVO(0,fileName,url));
|
||||||
}catch (Exception ex){
|
}catch (Exception ex){
|
||||||
throw new NflgException(STATE.BusinessError,"上传文件失败:"+ex.getMessage());
|
throw new NflgException(STATE.BusinessError,"上传文件失败:"+ex.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getFileType(String fileName){
|
||||||
|
return "."+FilenameUtils.getExtension(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
private FileUploadRecord buildFileUploadRecord(Byte source,Integer sourceId,String fileName,String fileType, String url){
|
private FileUploadRecord buildFileUploadRecord(Byte source,Integer sourceId,String fileName,String fileType, String url){
|
||||||
return new FileUploadRecord()
|
return new FileUploadRecord()
|
||||||
.setFileName(fileName)
|
.setFileName(FilenameUtils.getBaseName(fileName))
|
||||||
.setFileType(fileType)
|
.setFileType(fileType)
|
||||||
.setFrom("admin")
|
.setFrom("admin")
|
||||||
.setCreateTime(LocalDateTime.now())
|
.setCreateTime(LocalDateTime.now())
|
||||||
|
|
@ -160,4 +187,45 @@ public class FileController extends ControllerBase {
|
||||||
public ApiResult<List<String>> getFileTypes(){
|
public ApiResult<List<String>> getFileTypes(){
|
||||||
return ApiResult.success(fileUploadRecordService.getFileTypes());
|
return ApiResult.success(fileUploadRecordService.getFileTypes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件压缩下载
|
||||||
|
*
|
||||||
|
* @param fileIds 文件id列表
|
||||||
|
*/
|
||||||
|
@PostMapping("zipDownload")
|
||||||
|
public ResponseEntity<byte[]> zipDownload(@Valid @RequestParam @NotNull List<Integer> fileIds) throws IOException {
|
||||||
|
List<String> urls = fileUploadRecordService.listByIds(fileIds).stream().map(FileUploadRecord::getUrl).collect(Collectors.toList());
|
||||||
|
VUtils.trueThrowBusinessError(CollectionUtil.isEmpty(urls)).throwMessage("没有需要下载的文件");
|
||||||
|
Path tempZipFile = Files.createTempFile("files", ".zip");
|
||||||
|
try (FileOutputStream fos = new FileOutputStream(tempZipFile.toFile());
|
||||||
|
ZipOutputStream zos = new ZipOutputStream(fos)) {
|
||||||
|
for (String fileUrl : urls) {
|
||||||
|
Request request = new Request.Builder().url(fileUrl).build();
|
||||||
|
try (Response response = client.newCall(request).execute()) {
|
||||||
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
|
String fileName = fileUrl.substring(fileUrl.lastIndexOf('/') + 1);
|
||||||
|
ZipEntry zipEntry = new ZipEntry(fileName);
|
||||||
|
zos.putNextEntry(zipEntry);
|
||||||
|
// 使用流式处理将文件内容写入 ZIP 输出流
|
||||||
|
InputStream inputStream = response.body().byteStream();
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
int length;
|
||||||
|
while ((length = inputStream.read(buffer)) >= 0) {
|
||||||
|
zos.write(buffer, 0, length);
|
||||||
|
}
|
||||||
|
zos.closeEntry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
byte[] zipContent = Files.readAllBytes(tempZipFile);
|
||||||
|
Files.deleteIfExists(tempZipFile);
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename="+ DateTimeUtil.format(LocalDateTime.now(),"yyyyMMddHHmmss")+".zip");
|
||||||
|
return ResponseEntity.ok()
|
||||||
|
.headers(headers)
|
||||||
|
.contentType(MediaType.APPLICATION_OCTET_STREAM)
|
||||||
|
.body(zipContent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,17 @@
|
||||||
package com.nflg.mobilebroken.cfs.controller;
|
package com.nflg.mobilebroken.cfs.controller;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.IdUtil;
|
||||||
import cn.hutool.core.util.RandomUtil;
|
import cn.hutool.core.util.RandomUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.nflg.mobilebroken.common.constant.STATE;
|
import com.nflg.mobilebroken.common.constant.STATE;
|
||||||
import com.nflg.mobilebroken.common.exception.NflgException;
|
import com.nflg.mobilebroken.common.exception.NflgException;
|
||||||
import com.nflg.mobilebroken.common.pojo.ApiResult;
|
import com.nflg.mobilebroken.common.pojo.ApiResult;
|
||||||
|
import com.nflg.mobilebroken.common.pojo.vo.FileUploadVO;
|
||||||
import com.nflg.mobilebroken.common.util.AppUserUtil;
|
import com.nflg.mobilebroken.common.util.AppUserUtil;
|
||||||
import com.nflg.mobilebroken.repository.entity.FileUploadRecord;
|
import com.nflg.mobilebroken.repository.entity.FileUploadRecord;
|
||||||
import com.nflg.mobilebroken.repository.service.IFileUploadRecordService;
|
import com.nflg.mobilebroken.repository.service.IFileUploadRecordService;
|
||||||
import com.nflg.mobilebroken.starter.service.FileUploadService;
|
import com.nflg.mobilebroken.starter.service.FileUploadService;
|
||||||
|
import org.apache.commons.io.FilenameUtils;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
|
@ -49,23 +52,24 @@ public class FileController extends ControllerBase {
|
||||||
* @return 可访问的文件url
|
* @return 可访问的文件url
|
||||||
*/
|
*/
|
||||||
@PostMapping("uploadSingleFile")
|
@PostMapping("uploadSingleFile")
|
||||||
public ApiResult<String> uploadSingleFile(@Valid @NotNull @RequestParam("file") MultipartFile file
|
public ApiResult<FileUploadVO> uploadSingleFile(@Valid @NotNull @RequestParam("file") MultipartFile file
|
||||||
,@Valid @NotNull @RequestParam("source") Byte source
|
,@Valid @NotNull @RequestParam("source") Byte source
|
||||||
,@Valid @NotNull @RequestParam("sourceId") Integer sourceId) {
|
,@Valid @NotNull @RequestParam("sourceId") Integer sourceId) {
|
||||||
try {
|
try {
|
||||||
String fileName=file.getOriginalFilename().substring(0,file.getOriginalFilename().lastIndexOf("."));
|
String fileName=file.getOriginalFilename();
|
||||||
String fileType=file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
|
String fileType=getFileType(fileName);
|
||||||
String url=fileUploadService.upload(buildFilePath(fileName,fileType), file);
|
String url=fileUploadService.upload(buildFilePath(fileType), file);
|
||||||
fileUploadRecordService.save(buildFileUploadRecord(source,sourceId,fileName,fileType,url));
|
FileUploadRecord record=buildFileUploadRecord(source,sourceId,fileName,fileType,url);
|
||||||
return ApiResult.success(url);
|
fileUploadRecordService.save(record);
|
||||||
|
return ApiResult.success(new FileUploadVO(record.getId(),fileName,url));
|
||||||
}catch (Exception ex){
|
}catch (Exception ex){
|
||||||
throw new NflgException(STATE.BusinessError,"上传文件失败:"+ex.getMessage());
|
throw new NflgException(STATE.BusinessError,"上传文件失败:"+ex.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String buildFilePath(String fileName,String fileType) {
|
private String buildFilePath(String fileType) {
|
||||||
return StrUtil.format("cfs/{}/{}/{}/{}{}", LocalDateTime.now().format(FORMATTER), AppUserUtil.getUserId()
|
return StrUtil.format("cfs/{}/{}/{}/{}{}", LocalDateTime.now().format(FORMATTER), AppUserUtil.getUserId()
|
||||||
, RandomUtil.randomString(4), fileName,fileType);
|
, RandomUtil.randomString(4), IdUtil.fastUUID(),fileType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -76,20 +80,19 @@ public class FileController extends ControllerBase {
|
||||||
* @return 可访问的文件url列表
|
* @return 可访问的文件url列表
|
||||||
*/
|
*/
|
||||||
@PostMapping("uploadMultipleFiles")
|
@PostMapping("uploadMultipleFiles")
|
||||||
public ApiResult<List<String>> uploadMultipleFiles(@Valid @RequestParam("files") @NotEmpty List<MultipartFile> files
|
public ApiResult<List<FileUploadVO>> uploadMultipleFiles(@Valid @RequestParam("files") @NotEmpty List<MultipartFile> files
|
||||||
,@Valid @NotNull @RequestParam("source") Byte source
|
,@Valid @NotNull @RequestParam("source") Byte source
|
||||||
,@Valid @NotNull @RequestParam("sourceId") Integer sourceId) {
|
,@Valid @NotNull @RequestParam("sourceId") Integer sourceId) {
|
||||||
try {
|
try {
|
||||||
List<String> list = new ArrayList<>();
|
List<FileUploadVO> list = new ArrayList<>();
|
||||||
List<FileUploadRecord> records = new ArrayList<>();
|
|
||||||
for (MultipartFile file : files) {
|
for (MultipartFile file : files) {
|
||||||
String fileName=file.getOriginalFilename().substring(0,file.getOriginalFilename().lastIndexOf("."));
|
String fileName=file.getOriginalFilename();
|
||||||
String fileType=file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
|
String fileType=getFileType(fileName);
|
||||||
String url=fileUploadService.upload(buildFilePath(fileName,fileType), file);
|
String url=fileUploadService.upload(buildFilePath(fileType), file);
|
||||||
list.add(url);
|
FileUploadRecord record=buildFileUploadRecord(source,sourceId,fileName,fileType,url);
|
||||||
records.add(buildFileUploadRecord(source,sourceId,fileName,fileType,url));
|
fileUploadRecordService.save(record);
|
||||||
|
list.add(new FileUploadVO(record.getId(),fileName,url));
|
||||||
}
|
}
|
||||||
fileUploadRecordService.saveBatch(records);
|
|
||||||
return ApiResult.success(list);
|
return ApiResult.success(list);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
throw new NflgException(STATE.BusinessError, "上传文件失败:" + ex.getMessage());
|
throw new NflgException(STATE.BusinessError, "上传文件失败:" + ex.getMessage());
|
||||||
|
|
@ -102,17 +105,21 @@ public class FileController extends ControllerBase {
|
||||||
* @return 可访问的文件url
|
* @return 可访问的文件url
|
||||||
*/
|
*/
|
||||||
@PostMapping("uploadSingleFile1")
|
@PostMapping("uploadSingleFile1")
|
||||||
public ApiResult<String> uploadSingleFile1(@Valid @NotNull @RequestParam("file") MultipartFile file) {
|
public ApiResult<FileUploadVO> uploadSingleFile1(@Valid @NotNull @RequestParam("file") MultipartFile file) {
|
||||||
try {
|
try {
|
||||||
String fileName=file.getOriginalFilename().substring(0,file.getOriginalFilename().lastIndexOf("."));
|
String fileName=file.getOriginalFilename();
|
||||||
String fileType=file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
|
String fileType=getFileType(fileName);
|
||||||
String url=fileUploadService.upload(buildFilePath(fileName,fileType), file);
|
String url=fileUploadService.upload(buildFilePath(fileType), file);
|
||||||
return ApiResult.success(url);
|
return ApiResult.success(new FileUploadVO(0,fileName,url));
|
||||||
}catch (Exception ex){
|
}catch (Exception ex){
|
||||||
throw new NflgException(STATE.BusinessError,"上传文件失败:"+ex.getMessage());
|
throw new NflgException(STATE.BusinessError,"上传文件失败:"+ex.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getFileType(String fileName){
|
||||||
|
return "."+FilenameUtils.getExtension(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
private FileUploadRecord buildFileUploadRecord(Byte source,Integer sourceId,String fileName,String fileType,String url){
|
private FileUploadRecord buildFileUploadRecord(Byte source,Integer sourceId,String fileName,String fileType,String url){
|
||||||
return new FileUploadRecord()
|
return new FileUploadRecord()
|
||||||
.setFileName(fileName)
|
.setFileName(fileName)
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import cn.hutool.core.util.StrUtil;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.nflg.mobilebroken.cfs.publisher.TicketEventPublisher;
|
import com.nflg.mobilebroken.cfs.publisher.TicketEventPublisher;
|
||||||
import com.nflg.mobilebroken.cfs.service.SsePushService;
|
import com.nflg.mobilebroken.cfs.service.SsePushService;
|
||||||
import com.nflg.mobilebroken.common.constant.Constant;
|
|
||||||
import com.nflg.mobilebroken.common.constant.TicketState;
|
import com.nflg.mobilebroken.common.constant.TicketState;
|
||||||
import com.nflg.mobilebroken.common.pojo.ApiResult;
|
import com.nflg.mobilebroken.common.pojo.ApiResult;
|
||||||
import com.nflg.mobilebroken.common.pojo.PageData;
|
import com.nflg.mobilebroken.common.pojo.PageData;
|
||||||
|
|
@ -84,6 +83,9 @@ public class TiketController extends ControllerBase {
|
||||||
@Resource
|
@Resource
|
||||||
private RedisTemplate<String, String> redisTemplate;
|
private RedisTemplate<String, String> redisTemplate;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ITBasePartService partService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 搜索设备
|
* 搜索设备
|
||||||
* @param request 搜索条件
|
* @param request 搜索条件
|
||||||
|
|
@ -110,12 +112,7 @@ public class TiketController extends ControllerBase {
|
||||||
**/
|
**/
|
||||||
@GetMapping("getAllDeviceComponents")
|
@GetMapping("getAllDeviceComponents")
|
||||||
public ApiResult<List<String>> getAllDeviceComponents() {
|
public ApiResult<List<String>> getAllDeviceComponents() {
|
||||||
return ApiResult.success(
|
return ApiResult.success(partService.lambdaQuery().select(TBasePart::getPartName).eq(TBasePart::getEnable, true).list().stream().map(TBasePart::getPartName).collect(Collectors.toList()));
|
||||||
dictionaryItemTranslateService.getAllByDictionaryCode(Constant.DICTIONARY_ITEM_DEVICECOMPONENT, MultilingualUtil.getLanguage())
|
|
||||||
.stream()
|
|
||||||
.map(DictionaryItemTranslateVO::getValue)
|
|
||||||
.collect(Collectors.toList())
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,6 @@ public class Constant {
|
||||||
|
|
||||||
public static final String DICTIONARY_TYPE_TITLE_CQM = "YDP-007";
|
public static final String DICTIONARY_TYPE_TITLE_CQM = "YDP-007";
|
||||||
|
|
||||||
public static final String DICTIONARY_ITEM_DEVICECOMPONENT = "modelComponents";
|
|
||||||
|
|
||||||
public static final String REDIS_KEY_USER_UPDATE_KAPTCHA_APP = "app:kaptcha:user:update:{}";
|
public static final String REDIS_KEY_USER_UPDATE_KAPTCHA_APP = "app:kaptcha:user:update:{}";
|
||||||
|
|
||||||
public static final String REDIS_KEY_USER_UPDATE_KAPTCHA_ADMIN = "admin:kaptcha:user:update:{}";
|
public static final String REDIS_KEY_USER_UPDATE_KAPTCHA_ADMIN = "admin:kaptcha:user:update:{}";
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package com.nflg.mobilebroken.common.pojo.dto;
|
package com.nflg.mobilebroken.common.pojo.dto;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import com.nflg.mobilebroken.common.pojo.vo.FileUploadVO;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
|
@ -29,10 +30,10 @@ public class ChatMessageDTO {
|
||||||
private String content;
|
private String content;
|
||||||
|
|
||||||
// 附件列表
|
// 附件列表
|
||||||
private List<String> attachments;
|
private List<FileUploadVO> attachments;
|
||||||
|
|
||||||
//图片列表
|
//图片列表
|
||||||
private List<String> images;
|
private List<FileUploadVO> images;
|
||||||
|
|
||||||
// 创建时间
|
// 创建时间
|
||||||
private Instant createTime;
|
private Instant createTime;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package com.nflg.mobilebroken.common.pojo.request;
|
package com.nflg.mobilebroken.common.pojo.request;
|
||||||
|
|
||||||
|
import com.nflg.mobilebroken.common.pojo.vo.FileUploadVO;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
@ -16,10 +17,10 @@ public class AddChatMessageRequest {
|
||||||
private String content;
|
private String content;
|
||||||
|
|
||||||
//附件列表
|
//附件列表
|
||||||
private List<String> attachments;
|
private List<FileUploadVO> attachments;
|
||||||
|
|
||||||
//图片列表
|
//图片列表
|
||||||
private List<String> images;
|
private List<FileUploadVO> images;
|
||||||
|
|
||||||
// 引用的消息
|
// 引用的消息
|
||||||
private String quoteId;
|
private String quoteId;
|
||||||
|
|
|
||||||
|
|
@ -29,10 +29,10 @@ public class TicketAddRequest {
|
||||||
@Size(max = 500, message = "描述长度不能超过500")
|
@Size(max = 500, message = "描述长度不能超过500")
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
//图片
|
//图片列表
|
||||||
private List<String> images;
|
private List<String> images;
|
||||||
|
|
||||||
//附件
|
//附件列表
|
||||||
private List<String> attachments;
|
private List<String> attachments;
|
||||||
|
|
||||||
//设备地址
|
//设备地址
|
||||||
|
|
|
||||||
|
|
@ -205,7 +205,7 @@ public class AdminTicketVO {
|
||||||
return ChronoUnit.DAYS.between(createTime.toLocalDate(), LocalDateTime.now().toLocalDate()) + 1;
|
return ChronoUnit.DAYS.between(createTime.toLocalDate(), LocalDateTime.now().toLocalDate()) + 1;
|
||||||
}
|
}
|
||||||
if (TicketState.Closed.getState().compareTo(state) >= 0) {
|
if (TicketState.Closed.getState().compareTo(state) >= 0) {
|
||||||
return ChronoUnit.DAYS.between(completeTime, LocalDateTime.now()) + 1;
|
return ChronoUnit.DAYS.between(createTime.toLocalDate(), completeTime.toLocalDate()) + 1;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,10 +27,10 @@ public class ChatMessageVO {
|
||||||
private String content;
|
private String content;
|
||||||
|
|
||||||
// 附件列表
|
// 附件列表
|
||||||
private List<String> attachments;
|
private List<FileUploadVO> attachments;
|
||||||
|
|
||||||
//图片列表
|
//图片列表
|
||||||
private List<String> images;
|
private List<FileUploadVO> images;
|
||||||
|
|
||||||
// 创建时间
|
// 创建时间
|
||||||
private String createTime;
|
private String createTime;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
package com.nflg.mobilebroken.common.pojo.vo;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class FileUploadVO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件id
|
||||||
|
*/
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示名称
|
||||||
|
*/
|
||||||
|
private String fileName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* url路径
|
||||||
|
*/
|
||||||
|
private String url;
|
||||||
|
}
|
||||||
|
|
@ -20,6 +20,13 @@ public class DateTimeUtil {
|
||||||
return dateTime.format(FORMATTER);
|
return dateTime.format(FORMATTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String format(LocalDateTime dateTime,String pattern){
|
||||||
|
if (Objects.isNull(dateTime)){
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return dateTime.format(DateTimeFormatter.ofPattern(pattern));
|
||||||
|
}
|
||||||
|
|
||||||
public static LocalDate asSystemDate(LocalDate date){
|
public static LocalDate asSystemDate(LocalDate date){
|
||||||
if (Objects.isNull(date)){
|
if (Objects.isNull(date)){
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -336,6 +336,7 @@ public class AppUserServiceImpl extends ServiceImpl<AppUserMapper, AppUser> impl
|
||||||
String areaName=StrUtil.join(",",customers.stream().map(TBaseCustomer::getAreaName).flatMap(name->StrUtil.split(name, ",").stream()).collect(Collectors.toSet()));
|
String areaName=StrUtil.join(",",customers.stream().map(TBaseCustomer::getAreaName).flatMap(name->StrUtil.split(name, ",").stream()).collect(Collectors.toSet()));
|
||||||
primary=new AppUserForAdminVO()
|
primary=new AppUserForAdminVO()
|
||||||
.setPrimary(true)
|
.setPrimary(true)
|
||||||
|
.setLoginName(appUser.getLoginName())
|
||||||
.setUserName(appUser.getName())
|
.setUserName(appUser.getName())
|
||||||
.setAvatar(appUser.getAvatar())
|
.setAvatar(appUser.getAvatar())
|
||||||
.setUserState(appUser.getState())
|
.setUserState(appUser.getState())
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,14 @@ import com.nflg.mobilebroken.repository.entity.*;
|
||||||
import com.nflg.mobilebroken.repository.mapper.TicketMapper;
|
import com.nflg.mobilebroken.repository.mapper.TicketMapper;
|
||||||
import com.nflg.mobilebroken.repository.service.*;
|
import com.nflg.mobilebroken.repository.service.*;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -55,6 +59,7 @@ public class TicketServiceImpl extends ServiceImpl<TicketMapper, Ticket> impleme
|
||||||
@Resource
|
@Resource
|
||||||
private ITicketSolutionService ticketSolutionService;
|
private ITicketSolutionService ticketSolutionService;
|
||||||
|
|
||||||
|
@Transactional
|
||||||
@Override
|
@Override
|
||||||
public Ticket add(TicketAddRequest request, Integer userId) {
|
public Ticket add(TicketAddRequest request, Integer userId) {
|
||||||
Ticket lastTicket=lambdaQuery()
|
Ticket lastTicket=lambdaQuery()
|
||||||
|
|
@ -77,26 +82,40 @@ public class TicketServiceImpl extends ServiceImpl<TicketMapper, Ticket> impleme
|
||||||
.setUserId(userId)
|
.setUserId(userId)
|
||||||
.setCreateTime(LocalDateTime.now());
|
.setCreateTime(LocalDateTime.now());
|
||||||
save(ticket);
|
save(ticket);
|
||||||
Collection<String> files=CollectionUtil.addAll(request.getImages(),request.getAttachments());
|
// Collection<String> files=CollectionUtil.addAll(request.getImages(),request.getAttachments());
|
||||||
if (CollectionUtil.isNotEmpty(files)){
|
List<FileUploadRecord> imagesRecords = new ArrayList<>();
|
||||||
List<FileUploadRecord> fileUploadRecords=new ArrayList<>();
|
if (CollectionUtil.isNotEmpty(request.getImages())) {
|
||||||
for (String url : files) {
|
for (String url : request.getImages()) {
|
||||||
String fileName=url.substring(url.lastIndexOf("/")+1);
|
FileUploadRecord record = fileUploadRecordService.lambdaQuery()
|
||||||
String pre=fileName.substring(0,fileName.lastIndexOf("."));
|
.eq(FileUploadRecord::getSource, (byte) 0)
|
||||||
String end=fileName.substring(fileName.lastIndexOf("."));
|
.eq(FileUploadRecord::getSourceId, 0)
|
||||||
FileUploadRecord fileUploadRecord = new FileUploadRecord()
|
.eq(FileUploadRecord::getUrl, url)
|
||||||
.setFrom("app")
|
.one();
|
||||||
.setUrl(url)
|
VUtils.trueThrowBusinessError(Objects.isNull(record)).throwMessage("未找到图片上传记录:" + url);
|
||||||
.setFileName(pre)
|
record.setSourceId(ticket.getId());
|
||||||
.setFileType(end)
|
imagesRecords.add(record);
|
||||||
.setSource((byte) 0)
|
|
||||||
.setSourceId(ticket.getId())
|
|
||||||
.setCreateBy(AppUserUtil.getUserName())
|
|
||||||
.setCreateTime(LocalDateTime.now());
|
|
||||||
fileUploadRecords.add(fileUploadRecord);
|
|
||||||
}
|
}
|
||||||
fileUploadRecordService.saveBatch(fileUploadRecords);
|
fileUploadRecordService.updateBatchById(imagesRecords);
|
||||||
}
|
}
|
||||||
|
List<FileUploadRecord> attachmentsRecords = new ArrayList<>();
|
||||||
|
if (CollectionUtil.isNotEmpty(request.getAttachments())) {
|
||||||
|
for (String url : request.getAttachments()) {
|
||||||
|
FileUploadRecord record = fileUploadRecordService.lambdaQuery()
|
||||||
|
.eq(FileUploadRecord::getSource, (byte) 0)
|
||||||
|
.eq(FileUploadRecord::getSourceId, 0)
|
||||||
|
.eq(FileUploadRecord::getUrl, url)
|
||||||
|
.one();
|
||||||
|
VUtils.trueThrowBusinessError(Objects.isNull(record)).throwMessage("未找到附件上传记录:" + url);
|
||||||
|
record.setSourceId(ticket.getId());
|
||||||
|
attachmentsRecords.add(record);
|
||||||
|
}
|
||||||
|
fileUploadRecordService.updateBatchById(attachmentsRecords);
|
||||||
|
}
|
||||||
|
lambdaUpdate()
|
||||||
|
.set(CollectionUtil.isNotEmpty(imagesRecords),Ticket::getImages, imagesRecords.stream().map(FileUploadRecord::getId).collect(Collectors.toList()))
|
||||||
|
.set(CollectionUtil.isNotEmpty(attachmentsRecords),Ticket::getAttachments, attachmentsRecords.stream().map(FileUploadRecord::getId).collect(Collectors.toList()))
|
||||||
|
.eq(Ticket::getId, ticket.getId())
|
||||||
|
.update();
|
||||||
return ticket;
|
return ticket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -295,6 +314,7 @@ public class TicketServiceImpl extends ServiceImpl<TicketMapper, Ticket> impleme
|
||||||
VUtils.trueThrowBusinessError(Byte.compare(ticket.getState(), TicketState.ProcessingCompleted.getState())>0)
|
VUtils.trueThrowBusinessError(Byte.compare(ticket.getState(), TicketState.ProcessingCompleted.getState())>0)
|
||||||
.throwMessage("当前工单状态不允许重新打开");
|
.throwMessage("当前工单状态不允许重新打开");
|
||||||
ticket.setState(TicketState.Processing.getState());
|
ticket.setState(TicketState.Processing.getState());
|
||||||
|
ticket.setSolveTime(null);
|
||||||
ticket.setUpdateTime(LocalDateTime.now());
|
ticket.setUpdateTime(LocalDateTime.now());
|
||||||
updateById(ticket);
|
updateById(ticket);
|
||||||
return ticket;
|
return ticket;
|
||||||
|
|
@ -350,6 +370,7 @@ public class TicketServiceImpl extends ServiceImpl<TicketMapper, Ticket> impleme
|
||||||
VUtils.trueThrowBusinessError(tickerMangagers.stream().noneMatch(uid -> Objects.equals(uid, AdminUserUtil.getUserId())))
|
VUtils.trueThrowBusinessError(tickerMangagers.stream().noneMatch(uid -> Objects.equals(uid, AdminUserUtil.getUserId())))
|
||||||
.throwMessage("你无权驳回工单");
|
.throwMessage("你无权驳回工单");
|
||||||
ticket.setState(TicketState.Processing.getState());
|
ticket.setState(TicketState.Processing.getState());
|
||||||
|
ticket.setSolveTime(null);
|
||||||
ticket.setUpdateTime(LocalDateTime.now());
|
ticket.setUpdateTime(LocalDateTime.now());
|
||||||
updateById(ticket);
|
updateById(ticket);
|
||||||
return ticket;
|
return ticket;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue