refactor(file): 优化文件上传和下载功能
- 修改了文件上传接口,支持 InputStream 参数 - 优化了文件下载逻辑,使用临时文件和 ZipOutputStream - 更新了相关实体类和控制器的方法- 新增了 RemindUserRequest 和 ZipDownloadRequest 类
This commit is contained in:
parent
cd1775a297
commit
1a1f86c5ff
|
|
@ -3,8 +3,8 @@ package com.nflg.mobilebroken.admin.controller;
|
|||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.nflg.mobilebroken.admin.annotation.ApiMark;
|
||||
|
|
@ -23,6 +23,7 @@ import com.nflg.mobilebroken.common.util.*;
|
|||
import com.nflg.mobilebroken.repository.entity.*;
|
||||
import com.nflg.mobilebroken.repository.service.*;
|
||||
import com.nflg.mobilebroken.starter.annotation.MethodInfoMark;
|
||||
import com.nflg.mobilebroken.starter.service.FileUploadService;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
|
|
@ -36,9 +37,10 @@ import javax.annotation.Resource;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.file.Paths;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
|
@ -76,6 +78,9 @@ public class DeviceController extends ControllerBase {
|
|||
@Resource
|
||||
private IDeviceComponentService deviceComponentService;
|
||||
|
||||
@Resource
|
||||
private FileUploadService fileUploadService;
|
||||
|
||||
|
||||
/**
|
||||
* 获取设备列表
|
||||
|
|
@ -258,10 +263,10 @@ public class DeviceController extends ControllerBase {
|
|||
public void downTemplateForAdd(HttpServletResponse response) throws Exception {
|
||||
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
|
||||
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + URLEncoder.encode("设备新增导入模板.xlsx", "UTF-8"));
|
||||
ClassPathResource resource = new ClassPathResource("templates/设备新增导入模板.xlsx");
|
||||
ClassPathResource resource = new ClassPathResource("templates/deviceForAdd.xlsx");
|
||||
List<DeviceAddImportDTO> datas = new ArrayList<>();
|
||||
new Workbook()
|
||||
.addSheet(new TemplateSheet(Paths.get(resource.getURI()))
|
||||
.addSheet(new TemplateSheet(resource.getInputStream())
|
||||
.setData(datas)
|
||||
.setData("@list:deviceStateDesc", dictionaryItemService.getListByDictionaryCode(Constant.DICTIONARY_DEVICE_STATE)
|
||||
.stream().map(DictionaryItem::getName).collect(Collectors.toList())))
|
||||
|
|
@ -275,24 +280,28 @@ public class DeviceController extends ControllerBase {
|
|||
@Transactional
|
||||
@PostMapping("importForAdd")
|
||||
@ApiMark(moduleName = "设备管理", apiName = "新增导入")
|
||||
public void importForAdd(HttpServletResponse response, @RequestParam(value = "file") MultipartFile file) throws IOException {
|
||||
public ApiResult importForAdd(HttpServletResponse response, @RequestParam(value = "file") MultipartFile file) throws IOException {
|
||||
List<DeviceAddImportDTO> data = EecExcelUtil.getExcelContext(file.getInputStream(), DeviceAddImportDTO.class);
|
||||
VUtils.trueThrowBusinessError(CollectionUtil.isEmpty(data)).throwMessage("导入文件内容为空");
|
||||
if (addCheckAndImport(data)) {
|
||||
response.setContentType("application/json");
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
byte[] datas = StrUtil.bytes(JSONUtil.toJsonStr(ApiResult.success()));
|
||||
response.getOutputStream().write(datas, 0, datas.length);
|
||||
return ApiResult.success();
|
||||
} else {
|
||||
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
|
||||
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + URLEncoder.encode("设备新增.xlsx", "UTF-8"));
|
||||
ClassPathResource resource = new ClassPathResource("templates/设备新增导入模板.xlsx");
|
||||
ClassPathResource resource = new ClassPathResource("templates/deviceForAdd.xlsx");
|
||||
try(ByteArrayOutputStream osOut = new ByteArrayOutputStream()) {
|
||||
new Workbook()
|
||||
.addSheet(new TemplateSheet(Paths.get(resource.getURI()))
|
||||
.addSheet(new TemplateSheet(resource.getInputStream())
|
||||
.setData(data)
|
||||
.setData("@list:deviceStateDesc", dictionaryItemService.getListByDictionaryCode(Constant.DICTIONARY_DEVICE_STATE)
|
||||
.stream().map(DictionaryItem::getName).collect(Collectors.toList())))
|
||||
.writeTo(response.getOutputStream());
|
||||
.writeTo(osOut);
|
||||
try(ByteArrayInputStream isIn = new ByteArrayInputStream(osOut.toByteArray())) {
|
||||
return ApiResult.error(STATE.BusinessError, "导入文件失败",fileUploadService.upload("temp/" +DateTimeUtil.format(LocalDate.now(),"yyyyMMdd")+"/"+ IdUtil.fastUUID() + ".xlsx", isIn));
|
||||
}
|
||||
}catch (Exception e){
|
||||
return ApiResult.error(STATE.BusinessError, "保存文件出错");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -446,7 +455,7 @@ public class DeviceController extends ControllerBase {
|
|||
*/
|
||||
@PostMapping("exportSelect")
|
||||
@ApiMark(moduleName = "设备管理", apiName = "导出选中的设备")
|
||||
public void exportSelect(HttpServletResponse response,@Valid @RequestBody @NotEmpty List<Integer> ids) throws IOException {
|
||||
public void exportSelect(HttpServletResponse response,@Valid @RequestBody @NotEmpty List<Integer> ids) throws Exception {
|
||||
List<Device> devices=deviceService.listByIds(ids);
|
||||
List<DictionaryItem> states = dictionaryItemService.getListByDictionaryCode(Constant.DICTIONARY_DEVICE_STATE);
|
||||
List<DeviceUpdateImportDTO> datas=devices.stream().map(d->{
|
||||
|
|
@ -470,9 +479,9 @@ public class DeviceController extends ControllerBase {
|
|||
}).collect(Collectors.toList());
|
||||
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
|
||||
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + URLEncoder.encode("设备更新.xlsx", "UTF-8"));
|
||||
ClassPathResource resource = new ClassPathResource("templates/设备更新导入模板.xlsx");
|
||||
ClassPathResource resource = new ClassPathResource("templates/deviceForUpdate.xlsx");
|
||||
new Workbook()
|
||||
.addSheet(new TemplateSheet(Paths.get(resource.getURI()))
|
||||
.addSheet(new TemplateSheet(resource.getInputStream())
|
||||
.setData(datas)
|
||||
.setData("@list:deviceStateDesc", dictionaryItemService.getListByDictionaryCode(Constant.DICTIONARY_DEVICE_STATE)
|
||||
.stream().map(DictionaryItem::getName).collect(Collectors.toList())))
|
||||
|
|
@ -486,24 +495,26 @@ public class DeviceController extends ControllerBase {
|
|||
@Transactional
|
||||
@PostMapping("importForUpdate")
|
||||
@ApiMark(moduleName = "设备管理", apiName = "更新导入")
|
||||
public void importForUpdate(HttpServletResponse response, @RequestParam(value = "file") MultipartFile file) throws IOException {
|
||||
public ApiResult importForUpdate(@RequestParam(value = "file") MultipartFile file) throws IOException {
|
||||
List<DeviceUpdateImportDTO> data = EecExcelUtil.getExcelContext(file.getInputStream(), DeviceUpdateImportDTO.class);
|
||||
VUtils.trueThrowBusinessError(CollectionUtil.isEmpty(data)).throwMessage("导入文件内容为空");
|
||||
if (updateCheckAndImport(data)) {
|
||||
response.setContentType("application/json");
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
byte[] datas = StrUtil.bytes(JSONUtil.toJsonStr(ApiResult.success()));
|
||||
response.getOutputStream().write(datas, 0, datas.length);
|
||||
return ApiResult.success();
|
||||
} else {
|
||||
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
|
||||
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + URLEncoder.encode("设备更新.xlsx", "UTF-8"));
|
||||
ClassPathResource resource = new ClassPathResource("templates/设备更新导入模板.xlsx");
|
||||
ClassPathResource resource = new ClassPathResource("templates/deviceForUpdate.xlsx");
|
||||
try(ByteArrayOutputStream osOut = new ByteArrayOutputStream()) {
|
||||
new Workbook()
|
||||
.addSheet(new TemplateSheet(Paths.get(resource.getURI()))
|
||||
.addSheet(new TemplateSheet(resource.getInputStream())
|
||||
.setData(data)
|
||||
.setData("@list:deviceStateDesc", dictionaryItemService.getListByDictionaryCode(Constant.DICTIONARY_DEVICE_STATE)
|
||||
.stream().map(DictionaryItem::getName).collect(Collectors.toList())))
|
||||
.writeTo(response.getOutputStream());
|
||||
.writeTo(osOut);
|
||||
try(ByteArrayInputStream isIn = new ByteArrayInputStream(osOut.toByteArray())) {
|
||||
return ApiResult.error(STATE.BusinessError, "导入文件失败",fileUploadService.upload("temp/" +DateTimeUtil.format(LocalDate.now(),"yyyyMMdd")+"/"+ IdUtil.fastUUID() + ".xlsx", isIn));
|
||||
}
|
||||
}catch (Exception e){
|
||||
return ApiResult.error(STATE.BusinessError, "保存文件出错");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import com.nflg.mobilebroken.common.exception.NflgException;
|
|||
import com.nflg.mobilebroken.common.pojo.ApiResult;
|
||||
import com.nflg.mobilebroken.common.pojo.PageData;
|
||||
import com.nflg.mobilebroken.common.pojo.request.FileSearchRequest;
|
||||
import com.nflg.mobilebroken.common.pojo.request.ZipDownloadRequest;
|
||||
import com.nflg.mobilebroken.common.pojo.vo.FileUploadVO;
|
||||
import com.nflg.mobilebroken.common.pojo.vo.FileVO;
|
||||
import com.nflg.mobilebroken.common.util.AdminUserUtil;
|
||||
|
|
@ -191,18 +192,18 @@ public class FileController extends ControllerBase {
|
|||
/**
|
||||
* 文件压缩下载
|
||||
*
|
||||
* @param fileIds 文件id列表
|
||||
* @param request 请求参数
|
||||
*/
|
||||
@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());
|
||||
public ResponseEntity<byte[]> zipDownload(@Valid @RequestBody ZipDownloadRequest request) throws IOException {
|
||||
List<String> urls = fileUploadRecordService.listByIds(request.getFileIds()).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()) {
|
||||
Request r = new Request.Builder().url(fileUrl).build();
|
||||
try (Response response = client.newCall(r).execute()) {
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
String fileName = fileUrl.substring(fileUrl.lastIndexOf('/') + 1);
|
||||
ZipEntry zipEntry = new ZipEntry(fileName);
|
||||
|
|
|
|||
|
|
@ -726,7 +726,7 @@ public class TicketController extends ControllerBase {
|
|||
.setCreateTime(Instant.now())
|
||||
.setAttachments(request.getAttachments())
|
||||
.setImages(request.getImages())
|
||||
.setRemindUserIds(request.getRemindUserIds());
|
||||
.setRemindUsers(request.getRemindUsers());
|
||||
if(Objects.nonNull(request.getQuoteId())){
|
||||
ChatMessageDTO quoteMessage = ticketChatService.getMessage(request.getTicketId(), request.getQuoteId());
|
||||
message.setQuote(quoteMessage);
|
||||
|
|
|
|||
|
|
@ -323,7 +323,7 @@ public class TiketController extends ControllerBase {
|
|||
.setCreateTime(Instant.now())
|
||||
.setAttachments(request.getAttachments())
|
||||
.setImages(request.getImages())
|
||||
.setRemindUserIds(request.getRemindUserIds());
|
||||
.setRemindUsers(request.getRemindUsers());
|
||||
if(Objects.nonNull(request.getQuoteId())){
|
||||
ChatMessageDTO quoteMessage = ticketChatService.getMessage(request.getTicketId(), request.getQuoteId());
|
||||
message.setQuote(quoteMessage);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.nflg.mobilebroken.common.pojo.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.nflg.mobilebroken.common.pojo.request.RemindUserRequest;
|
||||
import com.nflg.mobilebroken.common.pojo.vo.FileUploadVO;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
|
@ -45,6 +46,6 @@ public class ChatMessageDTO {
|
|||
// 引用的消息
|
||||
private ChatMessageDTO quote;
|
||||
|
||||
//被艾特的用户id列表
|
||||
private List<Integer> remindUserIds;
|
||||
//被艾特的用户列表
|
||||
private List<RemindUserRequest> remindUsers;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,6 @@ public class AddChatMessageRequest {
|
|||
// 引用的消息
|
||||
private String quoteId;
|
||||
|
||||
//被艾特的用户id列表
|
||||
private List<Integer> remindUserIds;
|
||||
//被艾特的用户列表
|
||||
private List<RemindUserRequest> remindUsers;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
package com.nflg.mobilebroken.common.pojo.request;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class RemindUserRequest {
|
||||
|
||||
/**
|
||||
* 用户id
|
||||
*/
|
||||
private Integer id;
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
private String name;
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.nflg.mobilebroken.common.pojo.request;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.util.List;
|
||||
|
||||
@Valid
|
||||
@Data
|
||||
public class ZipDownloadRequest {
|
||||
|
||||
/**
|
||||
* 文件id列表
|
||||
*/
|
||||
@NotEmpty
|
||||
private List<Integer> fileIds;
|
||||
}
|
||||
|
|
@ -2,11 +2,13 @@ package com.nflg.mobilebroken.common.pojo.vo;
|
|||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class FileUploadVO {
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.nflg.mobilebroken.starter.service;
|
|||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public interface FileUploadService {
|
||||
|
||||
|
|
@ -14,4 +15,13 @@ public interface FileUploadService {
|
|||
* @throws IOException
|
||||
*/
|
||||
String upload(String filePath,MultipartFile file) throws IOException;
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
* @param filePath 文件完整路径,如: /cfs/xxx.jpg
|
||||
* @param stream 文件流
|
||||
* @return 可访问的url
|
||||
* @throws IOException
|
||||
*/
|
||||
String upload(String filePath, InputStream stream) throws IOException;
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ import org.springframework.web.multipart.MultipartFile;
|
|||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
@Service
|
||||
@ConditionalOnProperty(name = "file.upload.type", havingValue = "oss")
|
||||
|
|
@ -30,8 +31,13 @@ public class OSSFileUploadService implements FileUploadService {
|
|||
|
||||
@Override
|
||||
public String upload(String filePath, MultipartFile file) throws IOException {
|
||||
return upload(filePath, file.getInputStream());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String upload(String filePath, InputStream stream) {
|
||||
// 上传文件到OSS
|
||||
PutObjectResult result = ossClient.putObject(new PutObjectRequest(bucketName, filePath, file.getInputStream()));
|
||||
PutObjectResult result = ossClient.putObject(new PutObjectRequest(bucketName, filePath, stream));
|
||||
//log.debug("上传文件结果: " + result);
|
||||
return StrUtil.format("{}/{}",domain, filePath);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue