SpringMVC--实现文件上传下载

学习一个框架少不了学习文件上传和下载,原理来说上传和下载都是基本二进制流的转换,所以搞清楚了这一点就很容易理解上传和下载了


在使用springmvc进行系统实现时,springmvc默认的解析器里面是没有加入对文件上传的解析的,这可以方便我们实现自己的文件上传。但如果你想使用springmvc对文件上传的解析器来处理文件上传的时候就需要在spring的applicationContext里面加上springMVC提供的MultipartResolver的声明。这样之后,客户端每次进行请求的时候,springMVC都会检查request里面是否包含多媒体信息,如果包含了就会使用MultipartResolver进行解析,springMVC会使用一个支持文件处理的MultipartHttpServletRequest来包裹当前的HttpServletRequest,然后使用MultipartHttpServletRequest就可以进行文件处理了。


一.文件上传


1.引入依赖包

文件上传需要额外引入包分别是:

commons-filrupload-1.3.1.jar

commons-io-2.4.jar

2.配置jsp页面

<%@ page contentType="text/html;charset=utf-8" language="java"%>
<%@ taglib prefix="sf" url="http://www.springframework.org/tags/form"%>
<html>
<head>
    <meta charset="utf-8">
    <title>用户登入<title>
</head>
<body>
    <%--文件上传的话需要enctype="multipart/form-data"--%>
    <sf:form modelAttribute="user" method="post" enctype="multipart/form-data">
    用户名:<sf:input path="username"/><sf:errors path="username"/>
    <br>
    密码:<sf:input path="password"/><sf:errors path="password"/>
    <br>
    昵称:<sf:input path="nickname"/><sf:errors path="nickname"/>
    <br>
    <%--这里设置文件上传--%>
    文件:<input type="file" name="file">
    <input type="submit" value="提交">
</sf:form>
</body>
</html>

3.配置相应的控制器

@RequestMapping(value="/login",method=RequestMethod.POST)
public String login(@Validated User user,BindingResult br,Model model,@RequestParam("file") MultipartFile file)
{
    if(br.hasErrors()){
        return "user/login"; //校验User,报错就会br有错误集合.@Validated和BindingResult是成对出现的
    }
    //分别获取的变量名file--文件类型--文件名
    System.out.println(file.getName()+"---"+file.getContentType()+"---"+file.getOriginalFilename());//getOriginalFilename()获取上传文件的原名,getName()获取表单中文件组件的名称
    try{
        if(!file.isEmpty())
        {
            //使用StreamsApi方式拷贝文件
            Streams.copy(file.getInputStream(),new FileOutputStream("E:/"+file.getOriginalFilename()));
            
        }catch(IOException e)
        {
            System.out.println("文件上传失败");
            e.printStackTrace();
        }
        System.out.println(user.toString());
        return "user/login";
    }
    

}

至此单个文件上传完成。

4.多个文件上传

多个文件上传很简单,只需要把参数改为数组就可以

 @RequestMapping(value = "/login",method = RequestMethod.POST)
    public String login(@Validated User user, BindingResult br, Model model,@RequestParam("file") MultipartFile[] file){
        if (br.hasErrors()){
            return "user/login";
        }
        //这里对文件进行遍历
        for (MultipartFile mul:file){
        //分别获取的是变量名file---文件类型---文件名
            System.out.println(mul.getName()+"---"+mul.getContentType()+"---"+mul.getOriginalFilename());
            try {
                if (!mul.isEmpty()){
                    Streams.copy(mul.getInputStream(),new FileOutputStream("E:/temp/"+mul.getOriginalFilename()),true);
                }
            } catch (IOException e) {
                System.out.println("文件上传失败");
                e.printStackTrace();
            }
        }
        System.out.println(user.toString());
        return "user/login";
    }

二.文件下载

下载需要把文件转化为二进制流,然后让客户端读取这个二进制流写入到本机,这样就实现了下载功能。那么现在就要想两个问题:1.问么巴文件写成二进制流?2.怎么把让客户端应答,开始下载?

其实:

1.写成二进制流可以用之前导入的文件上传组件提供的方法:FileUtils.readFileToByteArray(file)

2.让浏览器响应,则需要设置相应的httpHeader了,并且利用spring提供的ResponseEntity把返回值设置文header和响应内容

1.创建控制器代码

@RequestMapping(value="/downloda",produces="application/octet-stream;charset=UTF-8")
public ResponseEntity<byte[]> download() throws IOException {
//                指定文件,必须是绝对路径
            File file = new File("E:/temp/me-bg.jpg");
//                下载浏览器响应的那个文件名
            String dfileName = "1.jpg";
//                下面开始设置HttpHeaders,使得浏览器响应下载
            HttpHeaders headers = new HttpHeaders();
//                设置响应方式
            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
//                设置响应文件
            headers.setContentDispositionFormData("attachment", dfileName);
//                把文件以二进制形式写回
            return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file), headers, HttpStatus.CREATED);
        }

3.补充

有时候下载下来的文件会出现被压缩现象,也就是之前的格式都不存在了。解决办法为配置springMvc的messageConverter如下:

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">  
    <property name="messageConverters">  
        <list>  
            <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>  
        </list>  
    </property>  
</bean>  

在springboot中和fastjson一起使用可以如下:

本质上和xml配置是一样的,注入的时候有些转换器都有默认处理类型,所以没必要再次配置

@Bean
    public HttpMessageConverters customConverters() {

        //fastjson处理消息转换
        FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(SerializerFeature.WriteMapNullValue);
        /*
          List<MediaType> fastMediaTypes = new ArrayList<>();
          fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
          fastConverter.setSupportedMediaTypes(fastMediaTypes);
        */
        fastConverter.setFastJsonConfig(fastJsonConfig);

        //文件下载使用ByteArrayHttpMessageConverter处理
        ByteArrayHttpMessageConverter byteArrayHttpMessageConverter = new ByteArrayHttpMessageConverter();
        byteArrayHttpMessageConverter.setDefaultCharset(Charset.forName("UTF-8"));
        /*
         //ByteArrayHttpMessageConverter默认处理请求类型就是APPLICATION_OCTET_STREAM
         List<MediaType> byteMediaTypes = new ArrayList<>();
         byteMediaTypes.add(MediaType.APPLICATION_OCTET_STREAM);
         byteArrayHttpMessageConverter.setSupportedMediaTypes(byteMediaTypes);
         */
        List<HttpMessageConverter<?>> converters = new ArrayList<>();
        converters.add(fastConverter);
        converters.add(byteArrayHttpMessageConverter);

        return new HttpMessageConverters(converters);
    }

文件软码问题,可以使用URLEncoder转换下解决:

String filename = URLEncoder.encode(file.getName(),"UTF-8");

猜你喜欢

转载自blog.csdn.net/weixin_39573518/article/details/83043308