• 云笔记项目- 文件的上传与下载学习


    在云笔记项目学习中,提到了如何下载和上传文件,使用web的方式完成上传和下载都需要参考规范协议,代码的书写,以及web的配置,都是参考规范协议来编写的。本文将重新建立一个新Maven项目,进行简单演示,在服务端生成图片和Excel文件,发送到网页显示或实现下载,从本地上传图片或者文件到服务器,然后写出到目标文件夹。

    文件上传与下载相关参考协议

    (1)文件上传参考协议:Form-based File Upload in HTML RFC1867

    (2)文件下载参考协议:Hypertext Transfer Protocol HTTP/1.1 RFC2616

    (3)Spring-framework参考文档:https://docs.spring.io/spring/docs/4.3.23.RELEASE/spring-framework-reference/htmlsingle/

      其他协议:

    (1)UDP协议:User Datagram Protocol(UDP) RFC768 ,以前学习的UDP编程基于此

    (2)TCP协议:Transmission Control Protocol(TCP) RFC793,以前学习的socket就是基于此文章

    (3)HTTP/1.0版本协议:Hypertext Transfer Protocol HTTP/1.0 RFC1945,是HTTP/1.1以前的版本

    (4)HTTP状态管理协议:HTTP State Management Mechanism RFC6265,其中Cookie就在里面说明

    本项目参考的协议只有上传和下载协议,以及Spring-framework参考文档。

    项目搭建

    Step1 导包,项目需要导入Spring-MVC包、poi包、Commons-fileupload包、jackson核心包、pom.xml中进行配置

     1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     2   <modelVersion>4.0.0</modelVersion>
     3   <groupId>com.boe</groupId>
     4   <artifactId>FileUploadAndDownLoad</artifactId>
     5   <version>0.0.1-SNAPSHOT</version>
     6   <packaging>war</packaging>
     7   
     8   <dependencies>
     9    <!-- 导入spring-MVC -->
    10     <dependency>
    11      <groupId>org.springframework</groupId>
    12      <artifactId>spring-webmvc</artifactId>
    13      <version>4.2.3.RELEASE</version>
    14     </dependency>
    15   
    16     <dependency>
    17      <groupId>org.springframework</groupId>
    18      <artifactId>spring-webmvc</artifactId>
    19      <version>4.2.3.RELEASE</version>
    20      <classifier>sources</classifier>
    21     </dependency>
    22   
    23     <dependency>
    24      <groupId>org.springframework</groupId>
    25      <artifactId>spring-webmvc</artifactId>
    26      <version>4.2.3.RELEASE</version>
    27      <classifier>javadoc</classifier>
    28     </dependency>    
    29     
    30     <!-- 导入poi包,创建excel用 -->
    31     <dependency>
    32      <groupId>org.apache.poi</groupId>
    33      <artifactId>poi</artifactId>
    34      <version>3.17</version>
    35     </dependency>
    36     
    37     <dependency>
    38      <groupId>org.apache.poi</groupId>
    39      <artifactId>poi-ooxml</artifactId>
    40      <version>3.17</version>
    41     </dependency>
    42     
    43     <!-- 导入commons-fileupload包,用于文件上载 -->
    44     <dependency>
    45      <groupId>commons-fileupload</groupId>
    46      <artifactId>commons-fileupload</artifactId>
    47      <version>1.3</version>
    48     </dependency>   
    49     
    50     <!-- 导入json和java对象转换的jackson包 -->
    51     <!-- 导入jackson-core -->
    52     <dependency>
    53      <groupId>com.fasterxml.jackson.core</groupId>
    54      <artifactId>jackson-core</artifactId>
    55      <version>2.2.3</version>
    56     </dependency>
    57     
    58    <!-- 导入jackson-databind -->
    59     <dependency>
    60      <groupId>com.fasterxml.jackson.core</groupId>
    61      <artifactId>jackson-databind</artifactId>
    62      <version>2.2.3</version>
    63     </dependency>
    64     
    65     <!-- 导入jackson-annotations -->
    66      <dependency>
    67       <groupId>com.fasterxml.jackson.core</groupId>
    68       <artifactId>jackson-annotations</artifactId>
    69       <version>2.2.3</version>
    70     </dependency>      
    71     
    72 </dependencies>
    73   
    74 </project>

    step2 配置Spring-mvc.xml,除了配置组件扫描和注解驱动,由于项目上传文件需要用到Spring的解析器MultipartResolver,因此还需要进行上传解析器配置,里面设置上传的最大文件大小,以及文件名编码方式和最大文件内存保存大小等属性,后面将有用。

     1         <!-- 配置组件扫描 -->
     2         <context:component-scan base-package="Web"></context:component-scan>
     3         <!-- 添加注解驱动 -->
     4         <mvc:annotation-driven></mvc:annotation-driven>
     5         
     6         <!-- 配置文件上载解析器MultipartResolver -->
     7         <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
     8         <!-- one of the properties available; the maximum file size in bytes -->
     9         <!-- 通过set方法设置以下两个父类属性,父类为CommonsFileUploadSupport.class -->
    10         <property name="maxUploadSize" value="10000000"/>  <!--10M大小 -->
    11         <property name="defaultEncoding" value="UTF-8" /> <!-- 文件名编码,可以适用于中文名 -->
    12 
    13         <property name="maxInMemorySize" value="10000000" />
    14         <!-- 上传文件大小默认小于10kib时,会将文件写入硬盘前保存在内存中,否则就不会保存在内存中 -->
    15         </bean>

    step3 配置Servlet,其中使用部署描述文件来自动配置,DispatcherServelet会自动启动Spring-MVC,因此不需要新建一个类,直接使用存在的Spring下的DispatcherServelet即可,并设置参数,和路径请求条件。

    配置完成后的web.xml文件内容,就包含部署描述文件自动生成的部分。

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
     3   <display-name>FileUploadAndDownLoad</display-name>
     4   <welcome-file-list>
     5     <welcome-file>index.html</welcome-file>
     6     <welcome-file>index.htm</welcome-file>
     7     <welcome-file>index.jsp</welcome-file>
     8     <welcome-file>default.html</welcome-file>
     9     <welcome-file>default.htm</welcome-file>
    10     <welcome-file>default.jsp</welcome-file>
    11   </welcome-file-list>
    12   <!-- 手动配置的servlet -->
    13   <servlet>
    14     <description></description>
    15     <display-name>ImageServlet</display-name>
    16     <servlet-name>ImageServlet</servlet-name>
    17     <servlet-class>Web.ImageServlet</servlet-class>
    18   </servlet>
    19   <servlet-mapping>
    20     <servlet-name>ImageServlet</servlet-name>
    21     <url-pattern>/demoImg</url-pattern>
    22   </servlet-mapping>
    23   <!-- 使用部署描述文件生成,不用新建一个专门的servlet,而是勾选"选择已经存在的servlet或JSP来配置" -->
    24   <!-- 使用DispatcherServlet来帮忙加载配置文件,启动Spring容器 -->
    25   <servlet>
    26     <description></description>
    27     <display-name>DispatcherServlet</display-name>
    28     <servlet-name>DispatcherServlet</servlet-name>
    29     <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    30     <init-param>
    31       <description></description>
    32       <param-name>contextConfigLocation</param-name>
    33       <param-value>classpath:config/spring-*.xml</param-value>
    34     </init-param>
    35     <load-on-startup>1</load-on-startup>
    36   </servlet>
    37   <servlet-mapping>
    38     <servlet-name>DispatcherServlet</servlet-name>
    39     <url-pattern>*.do</url-pattern>
    40   </servlet-mapping>
    41 </web-app>

    完成以上配置后,就可以写控制器,以及网页来进行测试,最后测试完成后项目结构如下图:

    RFC2616协议参考

    服务器给浏览器发送数据时,先发送状态行,再发送响应头和消息body,可以参考RFC2616超文本传输协议内容。

    例子:如果发送一个网页给Client,简单的将包含如下几部分
    HTTP/1.1 200 OK
    ContentType:text/html charset=utf-8
    ContentLength:203
    空一行
    <html>内容</html>

    状态行(Status-Line)
    Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
    状态行包括HTTP版本号,状态码,和状态码的建议描述等信息,其中状态码是三位的数字,第一位数字用于分类,其他没有分类功能。此外Client端只检查状态码,不会检查状态码的描述,描述主要是给人看的。关于状态码,有如下几类:
    1XX: Informational,请求接受继续执行
    2XX: Success,请求被成功接受,解释,以及被接收
    3XX: Redirection,为了完成当前请求,需要进行进一步的请求
    4XX: Client Error,请求包含错误语法或者不能被实现
    5XX: Server Error,服务端不能处理包含正确语法的请求

    响应头(Entity Header Fields)
    响应头里的ContentType定义了消息Body里的数据类型,根据RFC2616介绍,Content-Encoding也可以定义消息Body数据类型,消息头里的ContentLength定义了消息Body在编码前的长度

    消息body(Entity Header Fields)
    任何HTTP/1.1版本的消息body,都必须在前面有ContentType对媒体信息的定义。

    使用Servlet发送图片到网页

    在进行文件下载前,先演示如何动态生成图片,并通过Servlet发送图片到网页显示,其中图片生成有一套固定的写法,最后返回一个byte数组,然后通过Servlet将这个字节数组发送到网页,完成图片显示。在服务器发送图片数据给浏览器时,需要发送包含状态行,响应头和消息Body的一条消息给浏览器,并且要发送正确的消息,网页才能正常显示图片。其中需要设置ContentType为image/png,告诉浏览器这是一张图片,并设置ContentLength,告诉浏览器图片的字节长度是多少。Servlet代码如下:

     1 package Web;
     2 
     3 import java.awt.image.BufferedImage;
     4 import java.io.ByteArrayOutputStream;
     5 import java.io.IOException;
     6 
     7 import javax.imageio.ImageIO;
     8 import javax.servlet.ServletException;
     9 import javax.servlet.http.HttpServlet;
    10 import javax.servlet.http.HttpServletRequest;
    11 import javax.servlet.http.HttpServletResponse;
    12 
    13 public class ImageServlet extends HttpServlet {
    14     private static final long serialVersionUID = 1L;
    15 
    16     public ImageServlet() {
    17         // TODO Auto-generated constructor stub
    18     }
    19 
    20     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    21         //response.getWriter().append("Served at: ").append(request.getContextPath());
    22         
    23         //在doGet方法里将资源发送
    24         byte[] image=createImage();
    25         //设置消息发送的消息头
    26         response.setContentType("image/png");
    27         response.setContentLength(image.length);
    28         //发送数据
    29         response.getOutputStream().write(image);
    30         
    31     }
    32     /**
    33      * 绘制一张图片,返回图片编码后的byte数组
    34      * @return
    35      * @throws IOException 
    36      */
    37     public byte[] createImage() throws IOException {
    38         //使用BufferedImage绘图
    39         //第一个参数图片宽度
    40         //第二个参数图片高度
    41         //第三个参数图片像素颜色表示方式,为3位的byte,一个byte调节一种颜色,分别为BGR,一个byte为8位,可以代表0-255的亮度
    42         BufferedImage buffImage=new BufferedImage(100,100,BufferedImage.TYPE_3BYTE_BGR);
    43         //设置图片某个像素点的颜色
    44         buffImage.setRGB(50, 50, 0x00ff00);//使用16进制表示
    45         ByteArrayOutputStream os=new ByteArrayOutputStream();
    46         //图片编码为png
    47         ImageIO.write(buffImage, "png", os);
    48         //关闭流
    49         os.close();
    50         byte[] image=os.toByteArray();
    51         return image;
    52     }
    53 
    54 }

    直接使用doGet请求来发送响应,服务端在获取请求后,刚开始会先调用service方法,随后会分发给doGet来执行,具体里面原理这里不深究,后续单独学习。浏览器端访问后图片显示结果如下图:

    使用Spring-MVC发送图片内容到网页,并实现文件下载

    使用Spring-MVC来实现Servlet能实现的功能,代码将更加简单,如发送图片到网页显示,只需要配置控制器即可,并且使用@ResponseBody注解,可实现向浏览器发送数据,这次发送的数据不一定是JSON,可能是图片字节数组,也可能是Excel的字节数组。如下代码实现了图片发送和文件下载。主要参考协议RFC2616来完成。

      1 package Web;
      2 
      3 import java.awt.image.BufferedImage;
      4 import java.io.ByteArrayOutputStream;
      5 import java.io.IOException;
      6 
      7 import javax.imageio.ImageIO;
      8 import javax.servlet.http.HttpServletResponse;
      9 
     10 import org.apache.poi.hssf.usermodel.HSSFCell;
     11 import org.apache.poi.hssf.usermodel.HSSFRow;
     12 import org.apache.poi.hssf.usermodel.HSSFSheet;
     13 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
     14 import org.springframework.stereotype.Controller;
     15 import org.springframework.web.bind.annotation.RequestMapping;
     16 import org.springframework.web.bind.annotation.ResponseBody;
     17 
     18 /**
     19  * 发送图片的控制器
     20  * @author yangchaolin
     21  *
     22  */
     23 @Controller
     24 @RequestMapping("/demo")
     25 public class ImageController {
     26     /**
     27      * @ResponseBody 注解会自动处理控制返回值
     28      * 1 当返回的类型为JavaBean(数组,集合),返回的数据为JSON
     29      * 2 当返回的类型为byte数组,直接将byte数组装入响应消息的body
     30      * 3 produces的配置相当如设置消息头Content-Type为image/png
     31      */
     32     @RequestMapping(value="/imgController.do",produces="image/png")
     33     @ResponseBody
     34     public byte[] sendImageToWeb() throws IOException {
     35         byte[] image=createImage();
     36         return image;        
     37     }
     38     
     39     /**
     40      * 下载图片需参考RFC2616 19.5.1 Content-Disposition
     41      * 如果想下载图片,需要将Content-Type设置为application/octet-stream
     42      * 另外还需要在响应消息头设置Content-Disposition
     43      */
     44     @RequestMapping(value="/downloadImage.do",produces="application/octet-stream")
     45     @ResponseBody
     46     public byte[] downloadImageForWeb(HttpServletResponse response) throws IOException {
     47         //example写法: Content-Disposition: attachment; filename="fname.ext"
     48         response.setHeader("Content-Disposition", "attachment; filename="text.png"");// " 转义 "
     49         return createImage();        
     50     }
     51     
     52     /**
     53      * 生成excel,浏览器可以下载,类似图片下载
     54      */
     55     @RequestMapping(value="/downloadExcel.do",produces="application/octet-stream")
     56     @ResponseBody
     57     public byte[] downloadExcelForWeb(HttpServletResponse response) throws IOException {
     58         //example写法: Content-Disposition: attachment; filename="fname.ext"
     59         response.setHeader("Content-Disposition", "attachment; filename="text.xls"");// " 转义 "
     60         return createExcel();        
     61     }
     62     
     63     /**
     64      * 生成一个简单excel,并返回byte数组
     65      */
     66     private byte[] createExcel() throws IOException {
     67         //生成工作簿
     68         HSSFWorkbook workbook=new HSSFWorkbook();
     69         //生成工作表
     70         HSSFSheet sheet=workbook.createSheet("information");
     71         //创建一行
     72         HSSFRow row=sheet.createRow(0);//第一行
     73         //行中创建一个Cell
     74         HSSFCell cell=row.createCell(0);//第一列
     75         //Cell中写入数据
     76         cell.setCellValue("hello excel with poi");
     77         //将Excel数据写入到输出流
     78         ByteArrayOutputStream os=new ByteArrayOutputStream();
     79         workbook.write(os);
     80         os.close();
     81         //使用输出流API,转换成byte数组并返回
     82         byte[] excel=os.toByteArray();        
     83         return excel;
     84     }
     85 
     86     /**
     87      * 绘制一张图片,返回图片编码后的byte数组
     88      */
     89     public byte[] createImage() throws IOException {
     90         //使用BufferedImage绘图
     91         //第一个参数图片宽度
     92         //第二个参数图片高度
     93         //第三个参数图片像素颜色表示方式,为3位的byte,一个byte调节一种颜色,分别为BGR,一个byte为8位,可以代表0-255的亮度
     94         BufferedImage buffImage=new BufferedImage(100,100,BufferedImage.TYPE_3BYTE_BGR);
     95         //设置图片某个像素点的颜色
     96         buffImage.setRGB(50, 50, 0x00ff00);//使用16进制表示
     97         ByteArrayOutputStream os=new ByteArrayOutputStream();
     98         //图片编码为png
     99         ImageIO.write(buffImage, "png", os);
    100         //关闭流
    101         os.close();
    102         byte[] image=os.toByteArray();
    103         return image;
    104     }
    105 
    106 }

    网页部分:

     1 <!DOCTYPE html>
     2 <html>
     3 <head>
     4 <meta charset="UTF-8">
     5 <title>web发送请求到服务端得到图片</title>
     6 </head>
     7 <body style="font-family:'微软雅黑'">
     8 
     9   <h1>以下为使用servlet从服务端得到的图片</h1>
    10   <p>
    11     <img alt="" src="demoImg"> <!-- demoImg为web.xml中配置好的访问路径 -->
    12   </p>
    13 
    14   <h1>以下为使用Spring MVC从服务端得到的图片</h1>
    15   <p>
    16     <img alt="" src="demo/imgController.do"> <!-- src里就是get请求地址 -->
    17   </p>
    18   
    19   <h1>以下为使用Spring MVC从服务器下载图片</h1> <!-- 下载图片,需参考RFC2616 19.5.1里的要求 -->
    20   <a href="demo/downloadImage.do">下载图片</a>
    21   
    22   <h1>以下为使用Spring MVC从服务器下载Excel</h1> <!-- 下载Excel,需参考RFC2616 19.5.1里的要求,类似图片下载,最后都是返回byte数组 -->
    23   <a href="demo/downloadExcel.do">下载Excel</a>
    24
    33 </body>
    34 </html>

    网页显示:

    下载的图片和Excel在文件夹中:

    RFC1867协议参考

    文件的上传,参考文档 Form-based File Upload in HTML RFC1867,字面意思为基于Form表单的文件上传,其中在文档目录 2.HTML forms with file submission 里有一个example,示例用户如何通过表单上传文件。

    <FORM ENCTYPE="multipart/form-data" ACTION="_URL_" METHOD=POST>

     File to process: <INPUT NAME="userfile1" TYPE="file">

     <INPUT TYPE="submit" VALUE="Send File">

    </FORM>

    发送的请求,必须为POST请求,此外还需要完成以下两步才能正常上载文件:

    1 导入一个commons-fileupload包

    2 在web.xml中进行解析器MultipartResolver的配置

    解析器的配置方法参考spring-framework的文档目录 22.10.2 Using a MultipartResolver with Commons FileUpload,本文档使用版本4

    使用Spring-MVC实现文件上传

    使用Spring-MVC实现文件的上传,网页端除了使用传统Form表单提交方式,还可以使用AJAX的FormData来提交,前者是上传后会刷新页面,后者是不刷新页面。本项目中上传文件成功后,服务器将给浏览器发送一个Map,里面包含上传成功的信息,不再采用云笔记的JasonResult来返回数据,代码如下。

      1 package Web;
      2 
      3 import java.io.File;
      4 import java.io.FileOutputStream;
      5 import java.io.IOException;
      6 import java.io.InputStream;
      7 import java.util.HashMap;
      8 import java.util.Map;
      9 
     10 import org.springframework.stereotype.Controller;
     11 import org.springframework.web.bind.annotation.RequestMapping;
     12 import org.springframework.web.bind.annotation.ResponseBody;
     13 import org.springframework.web.multipart.MultipartFile;
     14 
     15 /**
     16  * 上传文件的控制器
     17  * @author yangchaolin
     18  *
     19  */
     20 @Controller
     21 @RequestMapping("/file")
     22 public class UploadController {
     23     
     24     @RequestMapping("/uploadFile.do")
     25     @ResponseBody
     26     public Object uploadFile(MultipartFile userfile1,MultipartFile userfile2) throws IllegalStateException, IOException{
     27         /**
     28          * Spring MVC中可以使用MultipartFile接受上载的文件,文件中的一切数据都可以从此对象中获取
     29          * 比如可以获取文件原始名,文件类型等
     30          */
     31         
     32         //比如获取上载文件的原始文件名,就是文件系统中的文件名
     33         String filename1=userfile1.getOriginalFilename();
     34         String filename2=userfile2.getOriginalFilename();
     35         System.out.println("文件1原始文件名为:"+filename1);
     36         System.out.println("文件2原始文件名为:"+filename2);
     37         
     38         Map<String,String> map=new HashMap<String,String>();
     39         
     40         /**
     41          * 保存上传的文件有三种方法:
     42          * 1 MultipartFile接口的transferTo(File dest)方法
     43          * 将文件直接保存到目标文件,适用于大文件
     44          * 2 MultipartFile接口的getBytes()方法
     45          * 将文件全部读取,返回byte数组,保存在内存,适用于小文件,大文件有爆内存风险
     46          * 3 MultipartFile接口的getInputStream()方法,将文件读取后返回一个InputStream
     47          * 获取上载文件的流,适用于大文件  
     48          */
     49             
     50         //mac中保存文件地址 /Users/yangchaolin
     51         //window中保存地址 D:/yangchaolin
     52         //linux中保存地址 /home/soft01/yangchaolin
     53         
     54         //1 使用transferTo(File dest)            
     55         // 创建目标文件夹
     56         File dir=new File("F:/FileUploadAndDownload");
     57         boolean makeDirectoryResult=dir.mkdirs();
     58         System.out.println("文件夹路径是否建立:"+makeDirectoryResult);
     59         //往文件夹放第一个文件
     60         File file=new File(dir,filename1);    
     61         userfile1.transferTo(file);
     62         
     63         /**
     64          * transferTo方法如果不注释掉,后面执行第二种方法写入文件到硬盘会报错
     65          * 报错内容:java.lang.IllegalStateException: File has been moved - cannot be read again
     66          * 原因为transferTo方法底层在执行时,会检查需要写入到OutputStream的文件字节数是否超过MultipartResolver配置的大小,
     67          * 默认设置为10kib,如果超过了,执行完这个方法后会从内存中删除上传的文件,后面再想读取就会报错
     68          */
     69         
     70         //2 使用getInputStream()方法
     71         File file1=new File(dir,filename1);
     72         InputStream isWithoutBuff=userfile1.getInputStream();
     73         //使用FileoutputStream写出到文件
     74         FileOutputStream fosWithoutbuff=new FileOutputStream(file1);
     75         //InputStream一个字节一个字节的读取,将读取到的结果写入到FileOutputStream
     76         int b;//读取一个byte后,以int类型显示数值,范围0~255        
     77         while((b=isWithoutBuff.read())!=-1) {
     78             //read()方法每次只读取文件的一个byte
     79             fosWithoutbuff.write(b);
     80         }
     81         isWithoutBuff.close();
     82         fosWithoutbuff.close();
     83         
     84         //同样使用InputStream读取,将读取到的结果写入到FileOutputStream,但使用了缓冲字节数组
     85         File file2=new File(dir,filename2);
     86         InputStream isWithBuff=userfile2.getInputStream();
     87         FileOutputStream fosWithBuff=new FileOutputStream(file2);
     88         int n;//保存返回读取到的字节数, 一次8192个字节,当不够时就是实际读取到的字节数
     89         byte[] buff=new byte[8*1024];//8kib的缓冲字节数组
     90         while((n=isWithBuff.read(buff))!=-1) {
     91             System.out.println("读取后的字节数:"+n);
     92             fosWithBuff.write(buff, 0, n);
     93         }
     94         isWithBuff.close();
     95         fosWithBuff.close();
     96         
     97         //3 使用getBytes()方法
     98         byte[] data=userfile2.getBytes();
     99         //写出byte数组到文件
    100         File file3=new File(dir,filename2);
    101         FileOutputStream fosWithByte=new FileOutputStream(file3);
    102         fosWithByte.write(data,0,data.length);
    103         fosWithByte.close();
    104         
    105         map.put("Result", "upload Success");        
    106 
    107         return map;//需要导入jackson的三个核心包,否则无法正常转换成JSON
    108         
    109     }
    110 
    111 }

    传统Form表单提交:

    1   <h1>以下为使用Spring MVC上载图片</h1>
    2   <form method="post" action="file/uploadFile.do" enctype="multipart/form-data">
    3     file to process:<br>
    4     <input type="file" name="userfile1"/> <!-- name用于提交到服务器的表单数据进行标识 -->
    5     <input type="file" name="userfile2"/>
    6     <input type="submit" value="upload文件"/>
    7   </form>

    网页显示:

    文件上传结果:

    AJAX提交的方式,服务端无需修改,只需要修改浏览器端代码即可:

    AJAX文件上载,参考项目FileUploadAndDownLoad ,AJAX上传适用于最新的浏览器版本,老版本的可能不兼容,使用FormData()来上传文件,FormData类似于Form,对于前面Spring MVC上传文件的方式:

    1 不使用AJAX,客户端需使用form来实现文件上传,form表单里有input元素,通过input元素的name属性来标识上传文件的资源,利用commons-fileupload包,客户端上传的文件会保存在MultipartFile对象中,然后可再通过三种方式,将上传的文件写入到硬盘。

    2 使用AJAX,客户端不需要写form表单,文件资源将直接保存到FormData里面,然后传入服务器,服务端的处理跟前面第一种没有区别,只是保存到FormData里的标识符,需要跟服务端方法里的参数名字一样。

     1 <!DOCTYPE html>
     2 <html>
     3 <head>
     4 <meta charset="UTF-8">
     5 <title>使用AJAX上传文件</title>
     6 <script type="text/javascript" src="scripts/jquery.min.js"></script>
     7 <script type="text/javascript">
     8  <!--使用AJAX来上传数据-->
     9  $(function(){
    10      $("#uploadFile").bind("click",uploadFileWithAJAX);     
    11  });
    12  function uploadFileWithAJAX(){
    13      //获取文件,将文件保存到FormData里
    14      var file1=$("#file1")[0].files[0];//jQuery对象转换成DOM对象,然后使用DOM对象的files属性,获取文件
    15      var file2=$("#file2")[0].files[0];
    16      //创建内存中的表单对象
    17      var formdata=new FormData();
    18      //第一个参数,必须和服务端MultipartFile的参数名一样
    19      formdata.append("userfile1",file1);
    20      formdata.append("userfile2",file2);
    21      
    22      //发送ajax请求
    23      $.ajax({
    24          url:"file/uploadFile.do",
    25          type:"POST",
    26          data:formdata,
    27          dataType:"JSON",
    28          cache:false,
    29          processData:false,
    30          contentType:false,
    31          success:function(resultData){
    32              console.log(resultData);
    33              if(resultData.Result=="upload Success"){
    34                  $("#result").text("upload Success");
    35              }
    36          },
    37          error:function(e){
    38              console.log("网络错误");
    39          }         
    40      });
    41      
    42  }
    43 </script>
    44 </head>
    45 <body>
    46 
    47   <h1>以下为使用AJAX上传文件,服务端代码不用变</h1>
    48   <input type="file" id="file1"><br>
    49   <input type="file" id="file2"><br>
    50   <input type="submit" value="上传图片" id="uploadFile"><br>
    51   <div id="result"></div>
    52   
    53 </body>
    54 </html>

    网页显示:

    文件上传结果:

    总结

    (1)无论是文件的上传,下载还是显示,都需要参考协议,其中上传参考RFC1867,下载参考RFC2616,此外还需要参考Spring-Framework的文档

    (2)使用Spring注解@ResponseBody不仅仅可以返回JSON,还可以返回byte数组

    (3)文件的上传可以使用AJAX,并使用FormData完成文件上传

  • 相关阅读:
    【leetcode刷题笔记】Best Time to Buy and Sell Stock II
    【leetcode刷题笔记】Reverse Integer
    JAVA中的NIO(二)
    标准I/O
    margin的理解
    JAVA中的NIO(一)
    IO模型
    linux网络命令
    linux用户管理命令
    linux中的帮助命令
  • 原文地址:https://www.cnblogs.com/youngchaolin/p/10700640.html
Copyright © 2020-2023  润新知