• 25 springboot文件上传


    1. 网页客户端使用表单提交文件上传

    当使用表单提交文件上传时,必须:

    • 表单<form>必须配置method="post"
    • 表单<form>必须配置enctype="multipart/form-data"

    其它部分与常规的表单开发相同。

    2. 在控制器中处理文件上传

    在处理请求的方法中,添加MultipartFile接口类型的参数,在处理过程中,调用该参数对象的void transferTo(File dest)方法即可保存客户端上传的文件到方法参数File dest对应的位置!

    此处使用到的MultipartFile,就是客户端提交的文件数据,被框架封装后的对象,所以,这个MultipartFile包含客户端提交的文件数据,也包含相关的信息。

    在保存客户端上传的文件时,可能需要考虑一些必要的问题:

    • 文件必须保存在webapp下,否则,即使上传了,也无法被下载,就没有意义了,通过HttpServletRequestHttpSession调用getServletContext().getRealPath(String name)就可以获取webpp文件夹或其子级文件夹的真实路径;
    • 文件名应该规避冲突,避免互相覆盖,例如:使用时间、随机数等组合出文件名,甚至使用UUID作为文件名,具体策略可以自行决定;
    • 应该保持与客户端上传时相同的扩展名,通过file.getOriginalFilename()可以获取文件的原始文件名,即文件在客户端时的文件名,从中就可以截取出扩展名部分,在做这种操作时,需要额外考虑:有些文件是没有扩展名,表现为整个文件全名中没有小数点,或只有第1个字符是小数点(在Linux/MacOS中,使用小数点作为第1个字符表示该文件或文件夹是隐藏的,这个小数点并不是用于分隔文件名和扩展名的)。

    3. 关于MultipartFile接口类型的API

    MultipartFile接口类型中,需要使用的API有:

    • String getOriginalFilename():获取文件的原始文件名,即文件在客户端中的文件名;
    • boolean isEmpty():判断上传的文件是否为空,当用户在上传表单中没有选择文件就直接上传,或选择的文件是0字节,则返回true,否则返回false
    • long getSize():获取客户端上传的文件的大小,以字节为单位;
    • String getContentType():获取客户端上传的文件的MIME类型,该值是根据文件的扩展名对应的;
    • InputStream getInputStream():获取客户端上传的文件的输入流,通常用于自定义接收客户端上传的文件的数据,例如客户端上传的文件较大时,可以自定义缓冲区大小等存储数据的过程,该方法不要与transferTo()方法同时使用;
    • void transferTo(File dest):将客户端上传的文件数据保存到服务器端的某个文件中,该方法不要与getInputStream()方法同时使用;

    4. 关于SpringBoot框架限制上传文件的大小

    在一些SpringBoot框架中,默认限制了上传文件的大小为1M,如果尝试上传的文件超过限制值,则出现:

    Maximum upload size exceeded; nested exception is java.lang.IllegalStateException: org.apache.tomcat.util.http.fileupload.impl.FileSizeLimitExceededException:
    The field file exceeds its maximum permitted size of 1048576 bytes.

      

    关于自定义上传文件的大小的限制值,有2种做法!

    第1种,是自定义配置上传文件大小的对象,可以在启动类中添加:

         @Bean
    	public MultipartConfigElement getMultipartConfigElement() {
    		MultipartConfigFactory factory = new MultipartConfigFactory();
    
    		// 当前项目中,无论上传的是什么,都不允许超过100M,否则直接报错,控制器根本就不执行
    		DataSize dataSize = DataSize.ofMegabytes(100);
    		//最大文件大小
    		factory.setMaxFileSize(dataSize);
    		//最大请求大小
    		factory.setMaxRequestSize(dataSize);
    		return factory.createMultipartConfig();
    	}
    

      

    第2种,是在application.properties中添加配置信息即可!SpringBoot框架的版本更新较快,早期版本和现今的主流版本的配置方式是不同的!

    在SpringBoot 2.0之后:

    spring.servlet.multipart.max-file-size=10MB  
    spring.servlet.multipart.max-request-size=100MB 
    

      

    5. 关于一次性上传多个文件

    首先,需要先确定上传的多个文件的数量是否固定,例如某些软件中,需要上传身份证的正面照片和反面照片,就属于是“数量固定”的,且每个上传的文件(照片)的定位是不相同的,则在同一个表单<form>中添加多个上传控件即可,例如:

    <form method="post" enctype="multipart/form-data" action="">
      <p>
        请选择身份证的正面照片:<input type="file" name="file1" />
      </p>
      <p>
        请选择身份证的反面照片:<input type="file" name="file2" />
      </p>
    </form>
    

      

    然后,在控制器中,处理请求的方法中,使用2个参数来表示2个不同的文件即可:

    public JsonResult<?> upload(MultipartFile file1, MultipartFile file2) {
      // 处理第1个文件file1
      // 处理第2个文件file2
    }
    

      

    如果上传的文件的数量在一定范围内不可控,例如微信朋友圈,上传的照片最多9张,但是,实际是多少张并不确定!或者网购之后发布买家秀,上传的照片的数量也是不确定的,可以采取的做法有:使用多个同名的上传控件:

    <form method="post" enctype="multipart/form-data" action="">
      <p>
        请选择第1张照片:<input type="file" name="files" />
      </p>
      <p>
        请选择第2张照片:<input type="file" name="files" />
      </p>
    </form>
    

      

    以上代码中,使用的多个上传控件的name值是相同的!在前端页面中,还可以使用JS技术动态添加更多的上传控件!

    或者,还可以只使用1个上传控件,但是,在上传控件中添加multiple="multiple"属性,则用户在浏览需要上传的文件时,可以按下键盘的Ctrl键,同时选择多个文件!例如:

    <form method="post" enctype="multipart/form-data" action="">
      <p>
        请选择需要上传的文件:<input type="file" name="files" multiple="multiple" />
      </p>
      <p>
        <b>提示:浏览文件时,按住键盘上的Ctrl键可以同时选择多个文件!</b>
      </p>
    </form>
    

      

    在服务器端的控制器中,处理这样的请求时,应该将上传文件的对象声明为数组格式,例如:

    public JsonResult<?> upload(MultipartFile[] files) {
      // 遍历数据,处理参数files中的每一个文件数据
    }
    

      

    6. 在前端页面使用$.ajax()函数实现异步上传

    在调用$.ajax()函数实现上传时,与提交普通请求的区别在于:

    • 关于data属性,必须是new FormData(表单)
    • 另外添加"contentType":false"processData":false这2个属性的配置。

    7.控制器处理单个文件demo

    @PostMapping("avatar/change")
    	public JsonResult<String> changeAvatar(MultipartFile file,HttpSession session){//不能长传超过1m大小的文件
    		if(file.isEmpty()) {
    			System.err.println("文件为空");
    			throw new FileEmptyException("头像上传失败!请选择有效的投降文件!");
    		}
    		if(file.getSize()>maxSize) {
    			throw new FileSizeException("上传头像失败!文件的大小超出"+(maxSize/1024)+"K!");
    		}
    		//判断上传的文件类型是否是允许的类型
    		if(!typeList.contains(file.getContentType())) {
    			throw new FileTypeException("上传头像失败!不支持的文件类型!支持的类型有:"+typeList.toString());
    		}
    		//确定将客户端上传的文件保存在哪里
    		//文件夹路径
    		String parent = session.getServletContext().getRealPath("avatar");
    		//文件名方案一:使用UUID生成随机文件名,缺点不便于文件排序
    		String filename = UUID.randomUUID().toString();
    		//文件名方案二:使用年月日时分秒+纳秒,精确到纳秒所以不会重复,便于排序
    		String filename2 =  sdf.format(new Date())+ System.nanoTime();//System.nanoTime()纳秒时间
    		//文件后缀
    		String suffix = "";
    		//获取原始文件名
    		String originalFilename = file.getOriginalFilename();
    		//获取后缀
    		int index = originalFilename.lastIndexOf(".");
    		suffix = originalFilename.substring(index);
    		//拼接为完整文件名
    		String child = filename2 + suffix;
    		File dest = new File(parent,child);
    		//执行保存客户端上传的文件
    			try {
    				file.transferTo(dest);
    			} catch (IllegalStateException e) {
    				throw new FileStateException("上传头像失败,请检查头像文件是否正常,并再次尝试!");
    			} catch (IOException e) {
    				throw new FileIOException("头像上传失败!传输过程出现错误,请稍后再试!");
    			}
    		//记录文件存储的位置
    		String avatar = "/avatar/" + child;
    		//存储到数据库
    		Integer uid = Integer.valueOf(session.getAttribute("uid").toString());
    	    String username = session.getAttribute("username").toString();
    		userService.changeAvater(uid, username, avatar);
    		return new JsonResult<>(OK,avatar);
    				
    	}
    

      

  • 相关阅读:
    Python类的继承(进阶5)
    面向对象编程基础(进阶4)
    Python模块(进阶3)
    Python函数式编程(进阶2)
    python多线程
    Ternary Search Tree Java实现
    Trie和Ternary Search Tree介绍
    索引时利用K-邻近算法过滤重复歌曲
    Sql排名和分组排名
    Lucene和jackson冲突
  • 原文地址:https://www.cnblogs.com/Scorpicat/p/12586230.html
Copyright © 2020-2023  润新知