(十二)springMvc 处理图片,视频等文件的上传
导包
需要导入如下的包
commons-fileupload-1.3.3.jar
commons-io-2.6.jar
修改表单类型
想要上传图片、文本、电影、音乐等资源的时候,需要将 form
的类型改为 multipart/form-data
<form enctype="multipart/form-data">
配置解析器
在 springMvc.xml
文件中进行配置 ;
<!--配置图片、音乐等文件的解析器-->
<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--限制上文最大为5M 1024*1024*5-->
<property name="maxInMemorySize">
<value>5242880 </value>
</property>
</bean>
处理上传的图片
springMvc
对这类型的数据,也支持 参数绑定 ,使用 MultipartFile
接收 ,注意页面上的 name
属性的值和形参名一致,老生常谈的事了;
MultipartFile
的一些基本操作 :
// 获取上传的文件名
String oldFile = multipartFile.getOriginalFilename() ;
// 将上传的文件,从内存中写到硬盘上
multipartFile.transferTo(path);
补充一个自己写的工具类
之前写的过于简单,补充下一个实例;
-
上传文件
先判断
HttpServletRequest
是否是MultipartHttpServletRequest
的实例,如果不是,则表示HttpServletRequest
只是一个普通的request
,并没有带文件过来,当然网上还有其他好几种判断方法,这是我常用的一种;public String upLoadExcel(HttpServletRequest request) { JSONObject jsonObject = new JSONObject(); if (!(request instanceof MultipartHttpServletRequest)) { jsonObject.put("result", "0"); jsonObject.put("resultInfo", "没有选中任何文件"); return jsonObject.toJSONString(); } ... }
如果
HttpServletRequest
是MultipartHttpServletRequest
的实例,则进行强转,将HttpServletRequest
转成MultipartHttpServletRequest
的实例;然后获取上传的文件:首先说明下,上传的文件的情况,它是一个
Map
中套List
的情况。因此,获取文件,需要先获取外层的
Map
,MultipartHttpServletRequest
提供了获取其迭代器的方法:Iterator<String> iterator = request.getFileNames();
这样就获取了所有的文件名,注意下
Map
里面套的是List
因此,这些名字就是Map
的键,一个键对应一个值List
,就是说一个文件名可以对应多个文件。根据文件名获取其对应的
List
:List<MultipartFile> files = request.getFiles(fileName);
这样就获取到了一个文件对应的
Lsit
集合,再迭代这个List
就可以获取其对应的文件。
下面是一个实例:
/** * 文件上传 * <p> * 先遍历名字,在根据名字遍历对应的文件,两层循环,ok! * * @param request 接受提交文件的 request * @return 返回上传的文件的保存路径 */ public static List<String> fileUpload(MultipartHttpServletRequest request) throws IOException { List<String> paths = new ArrayList<>(); // String path = FileUpDownloadUtils.class.getClassLoader().getResource("UpDownLoad" + File.separator + "readme.txt").getPath(); // 当前web应用的绝对路径 // String path = request.getSession().getServletContext().getRealPath("/") + "UpDownLoad"; // 获取系统的路径 String path = File.separator + "UpDownLoad"; Iterator<String> iterator = request.getFileNames(); while (iterator.hasNext()) { String fileName = iterator.next(); List<MultipartFile> files = request.getFiles(fileName); if (files.size() > 0) { ListIterator<MultipartFile> multipartFileListIterator = files.listIterator(); while (multipartFileListIterator.hasNext()) { String uuid = UUID.randomUUID().toString(); String path_in = getPathByHashcode(path, uuid); MultipartFile multipartFile = multipartFileListIterator.next(); StringBuilder builder = new StringBuilder(); builder.append(path_in + File.separator); builder.append(uuid + "_"); builder.append(multipartFile.getOriginalFilename()); File file = new File(builder.toString()); paths.add(file.getAbsolutePath()); multipartFile.transferTo(file); } } } return paths; }
再附送下代码中,我写的文件随机分配算法,这是其中的一种实现,只适合代码去读文件,人工找某个文件比较费劲,还有一种实现是按照日期分配;
日期分配,方便人工去拿文件,但是存在弱点,如果一天之内,有人暴力上传文件,文件夹就会被撑爆。各有各的优缺点。
/** * 文件分配算法,根据UUid的值 算出文件保存的地址 ; * <p> * UUID 的长度是固定的,然后根据其长度,保证其生成的 hascode 的长度也是一样长的(32位) ; * <p> * 每四位取为一个int 值 ,最多可以取 8 层 ; * <p> * 可以保存 16 * 16 * 16 * 16 * 1000 = 4 096 000(四百万份合同) ; * * @param path * @param uuid * @return */ private static String getPathByHashcode(String path, String uuid) { int hashcode = uuid.hashCode(); int one = hashcode & 0xf; int two = (hashcode >> 4) & 0xf; int three = (hashcode >> 4 >> 4) & 0xf; int four = (hashcode >> 4 >> 4 >> 4) & 0xf; File file = new File(path + File.separator + one + File.separator + two + File.separator + three + File.separator + four); if (!file.exists()) { file.mkdirs(); } return file.getPath(); }
-
下载文件
导包都是导入
spring
框架下面的,不要导错了。做了下载文件的时候,对文件名的兼容性,可以有空格。/** * springMvc 的下载,原始的response的outputStream 怎么用的,都要忘记了 见鬼的框架,真香的封装 * * @param imgPaths 封装需要下载的文件的路径 * @return */ public static ResponseEntity<Resource> fileDownload(String imgPaths, int blag) throws UnsupportedEncodingException { File file = new File(imgPaths); String simpleName = imgPaths.substring(imgPaths.indexOf("_") + 1); Resource body = new FileSystemResource(file); HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder .getRequestAttributes()).getRequest(); HttpStatus status = HttpStatus.CREATED; /** * 对文件名进行处理下 */ // 浏览器分为 火狐 和 非火狐 if (request.getHeader("USER-AGENT").toLowerCase().indexOf("firefox") >= 0) { // 火狐头大,需要独特设置一下 simpleName = new String(simpleName.getBytes("UTF-8"), "iso-8859-1"); } else { simpleName = URLEncoder.encode(simpleName, "UTF-8"); // IE 文件名有空格会被加号代替。需要自己替换回去 simpleName = simpleName.replaceAll("\\+", "%20"); } String suffix = simpleName.substring(simpleName.lastIndexOf(".") + 1); HttpHeaders headers = new HttpHeaders(); switch (blag) { /** * 内嵌显示,针对IE浏览器:TEXT_PLAIN * 文件名有空格。火狐则会截断文件名,需要将文件名用字符串包起来.使用 springMvc 不再需要这样做,并且你做了,还会在文件名前后各加一个 _ ; * * 预览需要自己判断下文件类型。 * */ case SHOW: MediaType mediaType; switch (suffix.toLowerCase()) { case "png": case "jpg": case "gif": mediaType = MediaType.TEXT_PLAIN; break; // case "html": // case "xml": // case "markdown": // mediaType = MediaType.valueOf("text/" + suffix); // break; default: mediaType = MediaType.valueOf("application/" + suffix); } headers.setContentType(mediaType); break; /** * 下载,下载设置内容格式为二进制数据:MediaType.APPLICATION_OCTET_STREAM */ case DOWNLOAD: headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); headers.setContentDispositionFormData("attachment", simpleName); break; } headers.setContentLength(file.length()); return new ResponseEntity<>(body, headers, status); }
其中的常量是:
传入
0
,就只是显示在浏览器上,不下载,这个只显示功能还有点问题,图片、pdf等格式会显示,一些其他格式无论怎么调试都是会下载。。。 ;1
是下载。public static final int SHOW = 0; public static final int DOWNLOAD = 1;