SpringBoot上传文件实现

SpringBoot上传文件实现前言上传文件需求也是日常开发必不可少的操作,今天就稍微总结下,一般如果是上传图片操作,很多稍微大点的公司都有专门的图片服务器可直接将图片上传至那边即可,如果没有图片服务器的话,那么此处把图片也一并归为文件进行讲解。本文代码以springBoot为准上传到哪?这个问题想必我们在实现需求时也必定会思考,那么如果能确定该项目是一个单服务器结构,那为了方便起见,可采用上传至本地服务器的项…

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

前言

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

 

上传到哪?

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

1、上传到本地服务器

    @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的具体实现:

    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文件依赖:

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-mongodb</artifactId>
		</dependency>

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

@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默认使用的库,若需切换到第二个库,请看如下代码

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上传文件实现

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

spring:
  servlet:
    multipart:
      #单个数据的大小
      max-file-size: 100MB
      #总数据的大小
      max-request-size: 100MB

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

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

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Java程序设计(高级及专题)- 类的加载和反射[通俗易懂]

    Java程序设计(高级及专题)- 类的加载和反射[通俗易懂]Java程序设计(高级及专题)- 类的加载和反射

    2022年4月22日
    49
  • MyEclipse SVN插件的安装及使用

    MyEclipse SVN插件的安装及使用MyEclipseSVN插件安装有两种,在线安装和手动安装一、(一)、在线安装1.打开Myeclipse,在菜单栏中选择Help→SoftwareUpdates→FindandInstall;2.选择Searchfornewfeaturesto

    2022年7月20日
    13
  • Java后台接收参数出现java.lang.Integer cannot be cast to java.lang.Double错误(已解决)[通俗易懂]

    Java后台接收参数出现java.lang.Integer cannot be cast to java.lang.Double错误(已解决)[通俗易懂]在Java接受前端传过来的数据信息的时候,使用List<List<double>>进行接收结果出现这个错误java.lang.Integercannotbecasttojava.lang.Double是类型转换出现的错误,当是这个数据在前端明明处理过,使用parseFloat转为了浮点数后端使用List<List>进行接收,此时也没有报错于是打开debug进行调试检查问题,发现传过来的数值如果是整数则为Integer类型,有小数的才是double类型

    2022年7月16日
    14
  • mapminmax 用法

    mapminmax 用法mapminmax是MATLAB实现归一化的工具包,默认:(1)将矩阵的每行分别进行归一化;(2)每行的最大值最小值作为每行归一化的xmin和xmax;(3)将数据归一化到[-1,1].若要将数据归一化到0到1之间,即y∈[0,1],使用b=mapminmax(a,0,1);若给与确定的最大值和最小值作为每行的xmin和xmax,使用:b= mapminmax(a,0,1);PS.xmin…

    2022年6月30日
    19
  • 设计手机APP界面的感想

    设计手机APP界面的感想设计手机APP界面的感想设计三个界面,花费了大概七八个小时。看老师讲解的时候,感觉就是那么回事,挺简单的,其实不然,当亲自操作后发现了诸多问题。首先是对已知工具运用上的不熟练,有些昨天刚刚使用过的工具,在今天的设计中就发生了一些错误,导致返工修改的时候浪费了好多时间。还有就是不能很好地将几个软件的功能结合起来,不如最近学了PS和UI,在今天的设计中主要使用的是UI,在设计过程中发现界面的一些板

    2022年6月21日
    22
  • Hook技术看这篇就够了[通俗易懂]

    Hook技术看这篇就够了[通俗易懂]   相信很多搞机的朋友都玩过Xposed,它实现了很多不可思议的功能。它是怎么实现的呢?这里就得提到我们的Hook技术了。    关于Android中的Hook机制,大致有两个方式: 要root权限,直接Hook系统,可以干掉所有的App。 免root权限,但是只能Hook自身,对系统其它App无能为力。   时间所限,这里不展开了。   知识点: …

    2022年5月9日
    154

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号