根据公司的底层做文件上传功能

Posted 杀手不太冷!

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了根据公司的底层做文件上传功能相关的知识,希望对你有一定的参考价值。

根据公司的底层做文件上传功能

引入公司依赖

首先我们做文件上传功能的时候,我们使用到的底层是我们公司为我们做的,所以我们一定要引入公司的依赖,如下图:

<dependency>
            <groupId>com.timevale.crm.sdk</groupId>
            <artifactId>crm-sdk-common-core</artifactId>
            <version>1.0.8-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.timevale.footstone-base</groupId>
            <artifactId>footstone-base-model</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.timevale.epeius</groupId>
            <artifactId>epeius-facade</artifactId>
            <version>1.0.0-SNAPSHOT</version>
            <exclusions>
                <exclusion>
                    <groupId>com.timevale</groupId>
                    <artifactId>mandarin-common</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>io.springfox</groupId>
                    <artifactId>springfox-swagger2</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>io.springfox</groupId>
                    <artifactId>springfox-swagger-ui</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

但是需要注意的是,这些依赖都是我们公司自己写的底层,所以我们的idea一定要引用我们公司自己的私服仓库,也就是说,maven设置时用到的setting.xml配置文件一定要是公司提供的maven的配置文件setting.xml。

写bean实体类

package org.eqianbao.localtest.entity;

import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.util.Date;

/**
 * @Date 2021/10/18 14:40
 * @Author 望轩
 */
@Data
@ApiModel(value = "文件对象")
public class FileResult {
    @ApiModelProperty(value = "文件名")
    private String fileName;

    @ApiModelProperty(value = "文件id")
    private String fileId;

    @ApiModelProperty(value = "文件下载地址")
    private String downloadUrl;

    @ApiModelProperty(value = "上传人")
    private String uploader;

    @ApiModelProperty(value = "上传人id")
    private String uploaderId;

    @ApiModelProperty(value = "上传时间")
    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
    private Date uploadTime;
}

Controller控制器

我们的本地文件首先会通过这个接口,上传到我们公司自己提供的文件系统(怎么上传的,就是通过我们引入的依赖传递的,我们引入的依赖是公司封装的底层),然后会生成文件系统中已经上传了的文件的下载地址和文件的ID等一系列信息,这些信息我们都可以通过接口的返回值得到。

package org.eqianbao.localtest.controller;

import com.timevale.crm.sdk.common.constant.enums.EnvEnum;
import com.timevale.crm.sdk.common.entity.integration.dto.FileDownloadDTO;
import com.timevale.crm.sdk.common.utils.file.FileUtil;
import com.timevale.epeius.service.enums.EpeiusResultEnum;
import com.timevale.footstone.base.model.response.BaseResult;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.eqianbao.localtest.entity.FileResult;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;

/**
 * @Date 2021/10/18 13:40
 * @Author 望轩
 * 文件管理
 */
@Controller
@ResponseBody
@RequestMapping(value="/file")
@Slf4j
public class FileSystemController {
    private EnvEnum envEnum = null;

    @Value("${spring.profiles.active}")
    private String activeProfile;

    @PostConstruct
    public void init(){
        if (activeProfile.toLowerCase().contains("prod")) {
            envEnum = EnvEnum.PROD;
        } else if (activeProfile.toLowerCase().contains("pre")) {
            envEnum = EnvEnum.PRE;
        }else {
            envEnum = EnvEnum.TEST;
        }
    }


    //上传文件
    @PostMapping(path = "/dock/uploadFile")
    public BaseResult<FileResult> uploadFile(@RequestParam(value = "file",required = false) MultipartFile file) {
        FileResult fileResponse ;
        try {
            FileDownloadDTO fileDownloadDTO = FileUtil.uploadFileToOSS(file, envEnum);
            if (fileDownloadDTO == null){
                log.warn("文件上传失败!");
                return BaseResult.fail(EpeiusResultEnum.FILE_UPLOAD_FAIL);
            }
            fileResponse = new FileResult();
            fileResponse.setFileName(fileDownloadDTO.getFileName());
            fileResponse.setFileId(fileDownloadDTO.getFileId());
            fileResponse.setDownloadUrl(fileDownloadDTO.getDownloadUrl());
        } catch (Exception e) {
            log.error("文件上传失败:"+e);
            return BaseResult.fail(EpeiusResultEnum.FILE_UPLOAD_FAIL);
        }
        return BaseResult.success(fileResponse);
    }

    @ApiOperation(value ="上传多个文件",notes = "望轩")
    @PostMapping(path = "/uploadMultiFile")
    public BaseResult<List<FileResult>> uploadMultiFile(@RequestParam(value = "files",required = false)MultipartFile[] files) {
        List<FileResult> fileResponseList = new ArrayList<FileResult>();
        if (files.length <= 0){
            return BaseResult.success();
        }
        try {
            for (MultipartFile file : files){
                if (file == null){
                    continue;
                }
                FileDownloadDTO fileDownloadDTO = FileUtil.uploadFileToOSS(file, envEnum);
                if (fileDownloadDTO == null){
                    return BaseResult.fail(EpeiusResultEnum.FILE_UPLOAD_FAIL);
                }
                FileResult fileResponse = new FileResult();
                fileResponse.setFileName(fileDownloadDTO.getFileName());
                fileResponse.setFileId(fileDownloadDTO.getFileId());
                fileResponse.setDownloadUrl(fileDownloadDTO.getDownloadUrl());
                fileResponseList.add(fileResponse);
            }
        } catch (Exception e) {
            log.error("文件上传失败:"+e);
            return BaseResult.fail(EpeiusResultEnum.FILE_UPLOAD_FAIL);
        }
        return BaseResult.success(fileResponseList);
    }


    @ApiOperation(value ="根据文件id获取下载地址",notes = "望轩")
    @GetMapping(path = "/downloadFile")
    public BaseResult<String> downloadFile(@RequestParam("fileId") String fileId) {
        FileDownloadDTO fileDownloadDTO ;
        try {
            fileDownloadDTO = FileUtil.getFileDownloadInfo(fileId,envEnum);
        } catch (Exception e) {
            log.error("文件下载失败 fileId = {} msg = {}",fileId,e.getMessage());
            return BaseResult.fail(EpeiusResultEnum.FILE_DOWNLOAD_FAIL);
        }
        return BaseResult.success(fileDownloadDTO.getDownloadUrl());
    }
}

写文件管理相关的配置类

package org.eqianbao.localtest.config;

import org.springframework.boot.web.servlet.MultipartConfigFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.MultipartConfigElement;
import java.io.File;

/**
 * @Date 2021/10/18 16:47
 * @Author 望轩
 */
@Configuration
public class MultipartConfig {

    private static final String locationTempDir = "D:\\\\文件上传存放文件夹";

    @Bean
    public MultipartConfigElement multipartConfigElement() {
        File tmpFile = new File(locationTempDir);
        if (!tmpFile.exists()) {
            tmpFile.mkdirs();
        }

        MultipartConfigFactory factory = new MultipartConfigFactory();
        factory.setLocation(locationTempDir);

        return factory.createMultipartConfig();
    }

}

这个配置类可以写也可以不写,如果你想要在测试的时候,让文件可以指定的上传的本地,那么你可以把这个配置类写上。但是我们在调用上传文件的接口之后,可以得到下载我们已经上传的文件的地址,可以通过这个地址把文件下载到指定的目录,这里我们上传的所有文件都会上传到"D:\\文件上传存放文件夹"目录中一份,但是格式可能和我们上传的文件的格式不一致,但是我们通过接口返回值里面的下载地址这个链接下载到的我们公司的文件系统中已经上传的文件的格式都是一致的。

测试

启动报错

错误消失,如下图:

IOC容器里面找不到bean报错

错误消失。

IOC容器中找不到RestTemplate模板报错

上面加上扫描包之后,又重新出现了新的bug,如下图:

上图中的错误是因为在IOC容器中找不到RestTemplate模板,我们需要把RestTemplate模板注入到IOC容器中,我们两步,第一步需要写一个RestTemplate的配置类,第二步需要在主启动类上还要扫描一下RestTemplate配置类所在的包,首先创建一个RestTemplate配置类如下图:

然后在主启动类上扫描这个配置类所在的包,如下图:

上面的几个错误的总结

遇到的最多的一个错误,就是在主启动类上没有扫描对应的类所在的包,最后导致这些类没办法注入到IOC容器中。比如之前有一个错误就是,我们在swagger里面看不到我们写的接口,显示不出来,而且项目启动也没有异常,完全正确,这是为什么呢?原因就是我们没有在启动类上面扫描Controller控制器所在的包,扫描这个包之后就可以在swagger中显示出来我们的接口地址了。

localtest项目工程的断点也进不去,而且在swagger中根本显示不出来对应的接口,这是什么原因呢?这个得具体原因就是我的控制器所在的包没有扫描,所以在swagger中加加载不出来我的控制器中对应的接口。在主启动类上加上一个扫描控制器的包就可以了,如下图:

所以以后如果发现那个类在IOC容器中找不到,首先要看一下这个类所在的包,有没有在启动类的上面被扫描。如果你发现你写的控制器的接口也不能用,那么你一定要检查一下控制器所在的包有没有在启动类上被扫描。

postman发送上传文件的请求

首先请求一定要用POST请求的方式,然后在Body->form-data中设置上传文件的KEY-VALUE键值对,其中KEY是我们的接口中参数对应的名字,而VALUE是我们要上传的本机文件,如下图:

然后设置上传文件的时候的Headers格式,其实也就是设置格式对应的KEY-VALUE键值对,如下图:

如果是上传文件,它的Headers所对应的键值对是有规定的,KEY=Content-Type,VALUE=multipart/form-data。

都设置好之后就可以发送请求了。

成功上传请求之后,我们返回值中就包含了“我们把文件上传到公司的文件系统之后,公司的文件系统所给我们返回的文件的下载地址和文件ID等信息”,如下图:

怎样根据外部引入的jar包找到对应的依赖

比如我们这里想要仿照别人已经写好的crm-dock工程,然后拷贝拷贝里面的代码自己写一个文件上传功能,但是中间肯定会用到一些依赖的,那么现在问题来了,我们怎么才能找到jar包所对应的依赖坐标呢?

如下图:

上图中可以在每一个maven模块里面去搜索jar包的名字。然后找到这个jar包是在哪个模块里面,最后去具体的模块的pom.xml文件里面去寻找对应的依赖坐标,如下图:

删除非必要的依赖,让项目达到最简化

因为如果项目的依赖太多的话会太占内存,所以我们在开发的时候一定要删除不必要的依赖包,至于我们要删除哪些包呢?怎么找呢?就看最上面导入的依赖,如果导入的这个依赖包就导入一次,那么就表示就使用了这个依赖中的一个类,所以我们只要把这个依赖包中的类复制到本地中一份就行了,如下图:

以上是关于根据公司的底层做文件上传功能的主要内容,如果未能解决你的问题,请参考以下文章

基于Java的一个简单的文件上传下载功能

蓝桥杯——根据手册写底层

layui上传文件组件(前后端代码实现)

thinkphp 使用插件异步上传图片或者文件

java Ftp上传创建多层文件的代码片段

java用上传一个文件测试网速怎么写代码