前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringBoot上传文件实现

SpringBoot上传文件实现

作者头像
全栈程序员站长
发布2022-06-29 08:53:31
8110
发布2022-06-29 08:53:31
举报
文章被收录于专栏:全栈程序员必看

大家好,又见面了,我是你们的朋友全栈君。

前言

上传文件需求也是日常开发必不可少的操作,今天就稍微总结下,一般如果是上传图片操作,很多稍微大点的公司都有专门的图片服务器可直接将图片上传至那边即可,如果没有图片服务器的话,那么此处把图片也一并归为文件进行讲解。本文代码以springBoot为准

上传到哪?

这个问题想必我们在实现需求时也必定会思考,那么如果能确定该项目是一个单服务器结构,那为了方便起见,可采用上传至本地服务器的项目中,如果是分布式环境并且有些文件还挺大,这里建议使用mongo的子模块GridFS实现。下面就这两种上传剖出代码

1、上传到本地服务器

代码语言:javascript
复制
    @RequestMapping(value = "/application/file/upload", method = RequestMethod.POST)
    public Object uoloadFile(@RequestParam("file") MultipartFile file) {
        return buildMessage(ResultModel.SUCCESS, appService.uoloadFile(file));
    }

controller层主要以MultipartFile接收即可,这里返回给前端的该文件保存后的相对路径,下面看下service层upload的具体实现:

代码语言:javascript
复制
    public String uploadFile(MultipartFile file) throws NotifyException {
        // 首先校验图片格式
        List<String> imageType = Lists.newArrayList("jpg","jpeg", "png", "bmp", "gif");
        // 获取文件名,带后缀
        String originalFilename = file.getOriginalFilename();
        // 获取文件的后缀格式
        String fileSuffix = originalFilename.substring(originalFilename.lastIndexOf(".") + 1).toLowerCase();
        if (imageType.contains(fileSuffix)) {
            // 只有当满足图片格式时才进来,重新赋图片名,防止出现名称重复的情况
            String newFileName = UUIDTypeHandler.createUUID() + originalFilename;
            // 该方法返回的为当前项目的工作目录,即在哪个地方启动的java线程
            String dirPath = System.getProperty("user.dir");
            String path = File.separator + "uploadImg" + File.separator + newFileName;
            File destFile = new File(dirPath + path);
            if (!destFile.getParentFile().exists()) {
                destFile.getParentFile().mkdirs();
            }
            try {
                file.transferTo(destFile);
                // 将相对路径返回给前端
                return path;
            } catch (IOException e) {
                log.error("upload pic error");
                return null;
            }
        } else {
            // 非法文件
            log.error("the picture's suffix is illegal");
            throw new NotifyException(ExceptionConstants.FILE_UPLOAD_ERROR);
        }
    }

上述代码是以上传图片为例,上传文件同理,只要去掉图片格式验证即可

2、上传到MongoDB

这里采用它的子模块GridFS实现,对应到代码中则是采用GridFsTemplate类来实现,GridFS使用两个集合(collection)存储文件。一个集合是chunks, 用于存储文件内容的二进制数据;一个集合是files,用于存储文件的元数据及扩展数据。当把一个文件存储到GridFS时,如果文件大于chunksize (每个chunk块大小为256KB),会先将文件按照chunk的大小分割成多个chunk块,最终将chunk块的信息存储在fs.chunks集合的多个文档中。然后将文件信息存储在fs.files集合的唯一一份文档中。其中fs.chunks集合中多个文档中的files_id字段对应fs.files集中文档”_id”字段。

读文件时,先根据查询条件在files集合中找到对应的文档,同时得到“_id”字段,再根据“_id”在chunks集合中查询所有“files_id”等于“_id”的文档。最后根据“n”字段顺序读取chunk的“data”字段数据,还原文件。

整合MongoDB:

为了使本文更全面点,那么先讲springBoot如何整合mongo,由于springBoot默认是没有提供配置连接池的属性,即你在application.yaml中的连接配置是不带连接池功能,因此这里我建议采用代码方式进行配置mongo,同时代码中配置能更好的切换不同的数据库以创建不同的MongoDbFactory,先贴pom文件依赖:

代码语言:javascript
复制
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-mongodb</artifactId>
		</dependency>

然后看下代码配置mongodb与springboot整合:

代码语言:javascript
复制
@Service
public class MongoConfig extends AbstractMongoConfiguration {

    @Override
    public MongoClient mongoClient() {
        MongoClient mongoClient = getMongoClient();
        return mongoClient;
    }

    public MongoClient getMongoClient() {
        // MongoDB地址列表
        List<ServerAddress> serverAddresses = new ArrayList<>();
        serverAddresses.add(new ServerAddress("xxxx:27017"));
        // 连接认证
        MongoCredential credential = MongoCredential.createCredential("xxx", "xx", "xxx".toCharArray());
        MongoClientOptions.Builder builder = MongoClientOptions.builder();

        //最大连接数
        builder.connectionsPerHost(10);
        //最小连接数
        builder.minConnectionsPerHost(0);
        //超时时间
        builder.connectTimeout(1000*3);
        // 一个线程成功获取到一个可用数据库之前的最大等待时间
        builder.maxWaitTime(5000);
        //此参数跟connectionsPerHost的乘机为一个线程变为可用的最大阻塞数,超过此乘机数之后的所有线程将及时获取一个异常.eg.connectionsPerHost=10 and threadsAllowedToBlockForConnectionMultiplier=5,最多50个线程等级一个链接,推荐配置为5
        builder.threadsAllowedToBlockForConnectionMultiplier(5);
        //最大空闲时间
        builder.maxConnectionIdleTime(1000*10);
        //设置池连接的最大生命时间。
        builder.maxConnectionLifeTime(1000*10);
        //连接超时时间
        builder.socketTimeout(1000*10);

        MongoClientOptions myOptions = builder.build();
        MongoClient mongoClient = new MongoClient(serverAddresses, credential, myOptions);
        return mongoClient;
    }

    @Override
    protected String getDatabaseName() {
        return "xxxx";
    }

    /**
     * 获取另一个数据库
     * @return
     */
    public String getFilesDataBaseName() {
        return "xxx";
    }

    /**
     * 用于切换不同的数据库
     * @return
     */
    public MongoDbFactory getDbFactory(String dataBaseName) {
        MongoDbFactory dbFactory = null;
        try {
            dbFactory = new SimpleMongoDbFactory(getMongoClient(), dataBaseName);
        } catch (Exception e) {
            log.error("Get mongo client have an error, please check reason...", e.getMessage());
        }
        return dbFactory;
    }

    /**
     * 获取文件存储模块
     * @return
     */
    public GridFsTemplate getGridFS() {
        return new GridFsTemplate(getDbFactory(getFilesDataBaseName()), mongoTemplate.getConverter());
    }

}

为了测试方便,各参数都直接写死了,建议写到配置文件中去(例如disconf),方便更改或扩展,这里需要注意的是继承的getDatabaseName()方法中返回的数据库为mongoTemplate默认使用的库,若需切换到第二个库,请看如下代码

代码语言:javascript
复制
public String upload(MultipartFile file) {
        // 拿到本文的重点类
        GridFsTemplate gridFsTemplate = mongoConfig.getGridFS();
        try {
            InputStream in = file.getInputStream();
            String filename = file.getOriginalFilename();
            String contentType = file.getContentType();
            // 这是扩展属性,供不同的业务需求,日后可根据特地的参数进行查询
            BasicDBObject dbObject = new BasicDBObject("name", "xj");
            dbObject.put("key", "value");
            String fileId = gridFsTemplate.store(in, filename, contentType, dbObject).toString();
            return fileId;
        } catch (IOException e) {
            log.error("transfer in error .");
            return null;
        }
    }

重点即为图上的store()方法,有多个重载方法,可自行选择。

到这里其实还未结束,springboot上传文件默认支持的大小为1mb,因此当你超过这个限制是会报如下错:

SpringBoot上传文件实现
SpringBoot上传文件实现

修改文件上传的大小即可,在yaml文件下增加如下配置:

代码语言:javascript
复制
spring:
  servlet:
    multipart:
      #单个数据的大小
      max-file-size: 100MB
      #总数据的大小
      max-request-size: 100MB

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/132529.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年6月1,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 上传到哪?
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档