第2-3-4章 上傳附件的介面開發-文件存儲服務系統-nginx/fastDFS/minio/阿里雲oss/七牛雲oss
5.3 介面開發-上傳附件
第2-1-2章 傳統方式安裝FastDFS-附FastDFS常用命令
第2-1-3章 docker-compose安裝FastDFS,實現文件存儲服務
第2-1-5章 docker安裝MinIO實現文件存儲服務-springboot整合minio-minio全網最全的資料
5.3.1 介面文檔
上傳附件介面要完成的操作主要有兩個:
- 將客戶端提交的文件上傳到指定存儲位置(具體存儲位置由配置文件配置的存儲策略確定)
- 將上傳的文件資訊保存到資料庫的pd_attachment表中
介面文檔如下:
5.3.2 程式碼實現
第一步:創建AttachmentController並提供文件上傳方法
package com.itheima.pinda.file.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.pinda.base.BaseController;
import com.itheima.pinda.base.R;
import com.itheima.pinda.file.dto.AttachmentDTO;
import com.itheima.pinda.file.dto.AttachmentRemoveDTO;
import com.itheima.pinda.file.dto.AttachmentResultDTO;
import com.itheima.pinda.file.dto.FilePageReqDTO;
import com.itheima.pinda.file.entity.Attachment;
import com.itheima.pinda.file.service.AttachmentService;
import com.itheima.pinda.utils.BizAssert;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;
import static com.itheima.pinda.exception.code.ExceptionCode.BASE_VALID_PARAM;
import static java.util.stream.Collectors.groupingBy;
/**
* 附件處理控制器
*/
@RestController
@RequestMapping("/attachment")
@Slf4j
@Api(value = "附件", tags = "附件")
public class AttachmentController extends BaseController {
@Autowired
private AttachmentService attachmentService;
/**
* 上傳附件
*/
@ApiOperation(value = "附件上傳", notes = "附件上傳")
@ApiImplicitParams({
@ApiImplicitParam(name = "isSingle", value = "是否單文件", dataType = "boolean", paramType = "query"),
@ApiImplicitParam(name = "id", value = "文件id", dataType = "long", paramType = "query"),
@ApiImplicitParam(name = "bizId", value = "業務id", dataType = "long", paramType = "query"),
@ApiImplicitParam(name = "bizType", value = "業務類型", dataType = "long", paramType = "query"),
@ApiImplicitParam(name = "file", value = "附件", dataType = "MultipartFile", allowMultiple = true, required = true),
})
@PostMapping(value = "/upload")
public R<AttachmentDTO> upload(
@RequestParam(value = "file") MultipartFile file,
@RequestParam(value = "isSingle", required = false, defaultValue = "false") Boolean isSingle,
@RequestParam(value = "id", required = false) Long id,
@RequestParam(value = "bizId", required = false) String bizId,
@RequestParam(value = "bizType") String bizType) {
// 忽略路徑欄位,只處理文件類型
if (file.isEmpty()) {
return fail(BASE_VALID_PARAM.build("請求中必須至少包含一個有效文件"));
}
AttachmentDTO attachment = attachmentService.upload(file,
id,
bizType,
bizId,
isSingle);
return success(attachment);
}
}
第二步:創建AttachmentService介面
package com.itheima.pinda.file.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.itheima.pinda.file.dto.AttachmentDTO;
import com.itheima.pinda.file.dto.AttachmentResultDTO;
import com.itheima.pinda.file.dto.FilePageReqDTO;
import com.itheima.pinda.file.entity.Attachment;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* 附件業務介面
*/
public interface AttachmentService extends IService<Attachment> {
/**
* 上傳附件
*
* @param file 文件
* @param id 附件id
* @param bizType 業務類型
* @param bizId 業務id
* @param isSingle 是否單個文件
* @return
*/
AttachmentDTO upload(MultipartFile file, Long id, String bizType,
String bizId, Boolean isSingle);
}
第三步:創建AttachmentServiceImpl實現類
package com.itheima.pinda.file.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.pinda.base.id.IdGenerate;
import com.itheima.pinda.database.mybatis.conditions.Wraps;
import com.itheima.pinda.database.mybatis.conditions.query.LbqWrapper;
import com.itheima.pinda.dozer.DozerUtils;
import com.itheima.pinda.exception.BizException;
import com.itheima.pinda.file.dao.AttachmentMapper;
import com.itheima.pinda.file.domain.FileDO;
import com.itheima.pinda.file.domain.FileDeleteDO;
import com.itheima.pinda.file.dto.AttachmentDTO;
import com.itheima.pinda.file.dto.AttachmentResultDTO;
import com.itheima.pinda.file.dto.FilePageReqDTO;
import com.itheima.pinda.file.entity.Attachment;
import com.itheima.pinda.file.entity.File;
import com.itheima.pinda.file.enumeration.DataType;
import com.itheima.pinda.file.properties.FileServerProperties;
import com.itheima.pinda.file.service.AttachmentService;
import com.itheima.pinda.file.strategy.FileStrategy;
import com.itheima.pinda.utils.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* 附件業務實現類
*/
@Slf4j
@Service
public class AttachmentServiceImpl extends ServiceImpl<AttachmentMapper, Attachment> implements AttachmentService {
@Autowired
private IdGenerate<Long> idGenerate;
@Autowired
private DozerUtils dozer;
@Autowired
private FileStrategy fileStrategy;
@Autowired
private FileServerProperties fileProperties;
/**
* 上傳附件
*
* @param multipartFile 文件
* @param id 附件id
* @param bizType 業務類型
* @param bizId 業務id
* @param isSingle 是否單個文件
* @return
*/
@Override
public AttachmentDTO upload(MultipartFile multipartFile, Long id, String bizType, String bizId, Boolean isSingle) {
//根據業務類型來判斷是否生成業務id
if (StringUtils.isNotEmpty(bizType) && StringUtils.isEmpty(bizId)) {
bizId = String.valueOf(idGenerate.generate());
}
File file = fileStrategy.upload(multipartFile);
Attachment attachment = dozer.map(file, Attachment.class);
attachment.setBizId(bizId);
attachment.setBizType(bizType);
setDate(attachment);
if (isSingle) {
super.remove(Wraps.<Attachment>lbQ().eq(Attachment::getBizId, bizId).eq(Attachment::getBizType, bizType));
}
if (id != null && id > 0) {
//當前端傳遞了文件id時,修改這條記錄
attachment.setId(id);
super.updateById(attachment);
} else {
attachment.setId(idGenerate.generate());
super.save(attachment);
}
AttachmentDTO dto = dozer.map(attachment, AttachmentDTO.class);
return dto;
}
private void setDate(Attachment file) {
LocalDateTime now = LocalDateTime.now();
file.setCreateMonth(DateUtils.formatAsYearMonthEn(now));
file.setCreateWeek(DateUtils.formatAsYearWeekEn(now));
file.setCreateDay(DateUtils.formatAsDateEn(now));
}
}
5.3.3 介面測試
第一步:啟動Nacos配置中心,pd-file-server.yml配置內容如下:
pinda:
mysql:
database: pd_files
nginx:
ip: ${spring.cloud.client.ip-address} #正式環境要將該ip設置成nginx對應的公網ip
port: 10000 #正式環境需要將該ip設置成nginx對應的公網埠
swagger:
enabled: true
docket:
file:
title: 文件服務
base-package: com.itheima.pinda.file.controller
file:
type: LOCAL # LOCAL ALI MINIO FAST_DFS
local:
uriPrefix: //${pinda.nginx.ip}:${pinda.nginx.port}
bucket-name: oss-file-service
endpoint: D:\soft\nginx-1.23.0\uploadFiles
ali:
# 請填寫自己的阿里雲存儲配置
bucket-name: bladex-loan
endpoint: //oss-cn-qingdao.aliyuncs.com
access-key-id: LTAI4FhtimFAiz6iLGJSiJui
access-key-secret: SsU15qaPwpF1x5xMqwc0XzGuY92fnc
#FAST_DFS配置
fdfs:
soTimeout: 1500
connectTimeout: 600
thumb-image:
width: 150
height: 150
tracker-list:
- 111.231.76.210:22122
pool:
#從池中借出的對象的最大數目
max-total: 153
max-wait-millis: 102
jmx-name-base: 1
jmx-name-prefix: 1
server:
port: 8765
第二步:啟動Nginx服務
第三步:啟動文件服務
第四步:訪問介面文檔,地址為//localhost:8765/doc.html
可以看到上傳的文件已經保存到了本地磁碟:
同時上傳的文件資訊也已經保存到了pd_attachment表中:
可以通過Nginx提供的Http服務來訪問上傳的文件:
//192.168.137.3:10000//oss-file-service/2022/11/e76d3505-df38-4f95-a7bd-fb5de3ebe923.txt