第2-3-4章 上传附件的接口开发-文件存储服务系统-nginx/fastDFS/minio/阿里云oss/七牛云oss


目录
  • 第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 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 {
        /**
         * 上传附件
         *
         * @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 implements AttachmentService {
        @Autowired
        private IdGenerate 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.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: http://${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: http://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服务

    第三步:启动文件服务

    第四步:访问接口文档,地址为http://localhost:8765/doc.html

    在这里插入图片描述

    可以看到上传的文件已经保存到了本地磁盘:
    在这里插入图片描述
    同时上传的文件信息也已经保存到了pd_attachment表中:
    在这里插入图片描述

    可以通过Nginx提供的Http服务来访问上传的文件:

    http://192.168.137.3:10000//oss-file-service/2022/11/e76d3505-df38-4f95-a7bd-fb5de3ebe923.txt

    全套代码及资料全部完整提供,点此处下载