上传文件的表单要求html
Spring MVC实现上传文件java
须要导入的jar包web
配置MultipartResolver解析器spring
编写接收上传文件的控制器apache
编写文件下载的控制器浏览器
配置异常页面的介绍服务器
对于普通表单来讲,有几个注意点:
一、action:表示要提交到哪里;
二、method:表单提交的方式,经常使用的有post和get两种,不写的话,默认是get;提交文件是只能使用post方式。
三、enctype:编码类型,表示提交的数据是什么格式。有三个值,
1)不显式设置enctype时,默认是application/x-www-form-urlencoded,表示提交的是普通的数据;
2)text/plain,表示提交的是文本数据,数据量稍大一点。
3)multipart/form-data,这种方式能够提交二进制数据(音频、图像等文件)
综上,若是要上传文件,必需要将method设置为post,而后将enctype设置multipart/form-data。另外,上传文件的input标签的type属性设置为file。
<form action="upload" method="post" enctype="multipart/form-data"> <input type="file" name="myfile" /> <input type="submit" name="submit" value="upload" /> </form>
在看Spring MVC是怎么实现文件上传以前,能够先看一下不是框架,使用原生的servlet开发是怎么实现文件上传的:Servlet 实现文件上传与下载
在Servlet 3.0以后,Spring MVC实现文件上传主要是使用一个叫MultipartResolver的解析器,该解析器依赖于apache的commons-io和commons-fileupload。MultipartResolver会自动解析文件,以后咱们在handlerMethod中,能够很方便的操做上传的文件。
必不可少的commons-io.jar和commons-fileupload.jar这两个包,缺一不可。
MultipartResolver是一个interface,咱们只须要配置他的一个实现类,好比CommonsMultipartResolver这个实现类,配置的方法也很简单,只须要配置一个id为multipartResolver的<bean>便可。
在Spring MVC的配置文件中增长下面配置:
<!-- 建立MultipartResolver解析器 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 配置属性,能够省略不配置,设置上传的文件maxSize,单位为B(字节) --> <property name="maxUploadSize" value="1000000"></property> </bean>
package cn.ganlixin.controller; import java.io.File; import java.io.IOException; import java.util.UUID; import org.apache.commons.io.FileUtils; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.multipart.MultipartFile; @Controller public class UploadController { @RequestMapping("upload") // 注意表单中文件input的name要和这里的参数名相同。 public String upload(MultipartFile myfile) throws IOException { // 上传一张图片 C:\Users\Administrator\Desktop\code.png // 获取文件的原始名称 String originalFileName = myfile.getOriginalFilename(); // code.png // 获取上传文件的表单中,input的name值,其实就是myfile(就是接收时的名称) String fileName = myfile.getName(); // myfile // 获取上传的文件大小,单位为字节 long fileSize = myfile.getSize(); // 5823(字节) String extensionName = originalFileName.substring(originalFileName.lastIndexOf(".")); /* 进行一些过滤判断操做 */ // 利用apache的commons-io和commons-fileupload,将文件保存到硬盘中,文件名能够根据本身的规则来定,这里使用UUID String newFileName = UUID.randomUUID().toString(); FileUtils.copyInputStreamToFile( myfile.getInputStream(), new File("E:/uploads/" + newFileName + extensionName) ); return "/success.jsp"; } }
在原生servlet实现文件下载主要有两步:
一、使用HttpServletRequest对象接收请求,获取客户端想要下载的文件名;
二、读取须要下载的文件,而后使用HttpServletResponse对象向客户端输出文件的字节流。
其实Spring MVC实现文件下载和使用原生servlet实现文件下载的方式并无太大区别,甚至能够说没有任何区别。惟一的区别就是Spring MVC的控制器没有继承HttpServlet,可是却能够为HandlerMethod注入HttpServletRequest和HttpServletResponse对象,以后就能够进行和原生servlet相同的操做了。
先看一下提供下载文件的资源连接:
<a href="download?fileName=info.txt">点击下载info.txt</a> <a href="download?fileName=data.rar">点击下载data.rar</a>
若是仍旧按照之前的设置:Content-Type=text/html; charset=utf-8; 那么当客户端点击下载连接时,发生的事情可能超乎预料。上面这两个资源连接的文件的扩展名,扩展名指明了该文件的格式。若是没有设置文件以附件形式下载,那么对于不一样的浏览器,对于文件的处理方式是不一样的:
一、若是浏览器可以打开或者可以解析该类型文件,那么,文件就会直接被浏览器打开(注意,不是下载,不会保存到用户的本地磁盘);
二、若是浏览器不能打开或者不能解析该类型的文件,那么,浏览器才会将文件下载下来(保存到用户磁盘)。
好比,当服务器响应info.txt以后,浏览器接收到info.txt,info.txt是文本文件,浏览器能够打开,因而就会将info.txt的内容显示在浏览器的页面中,而没有下载下来。而对于data.rar来讲,浏览器没法直接打开,因此会下载到本地。
为了让用户请求下载的文件都能保存到用户磁盘(即便浏览器可以打开文件,也不要让他打开,而只是让他进行下载),能够设置Content-Disposition属性为attachment(通知浏览器以附件形式下载)。
package cn.ganlixin.controller; import java.io.File; import java.io.IOException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.FileUtils; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class DownloadController { @RequestMapping("/download") // 注入fileName、request、response public void download(String fileName, HttpServletRequest request, HttpServletResponse response) throws IOException { // 设置响应是以附件形式,不用设置Content-Type了 response.setHeader("Content-Disposition", "attachment; filename=" + fileName); // 获取文件的真实路径(可供下载的文件都放在/project/WebContext/files/路径下,可是部署到服务器后,files文件夹的路径都会发生改变。 // 因此须要从新得到该文件从根目录开始的路径,而后读取文件,并响应给客户端。 String path = request.getServletContext().getRealPath("files"); // 文件下载时,是使用字节流格式,因此不能使用response.getWriter()-->返回PrintWriter是字符流 // 获取输出字节流恶意使用response. ServletOutputStream out = response.getOutputStream(); File downloadFile = new File(path, fileName); // 判断文件是否存在 if (! downloadFile.exists()) { request.setAttribute("msg", "文件不存在"); response.sendError(404); return; } // 利用FileUtils将文件读入字节数组,而后返回给客户端。 out.write(FileUtils.readFileToByteArray(downloadFile)); out.flush(); out.close(); } }
咱们的服务器在运行过程当中可能会出现各类异常,当出现异常的时候,根据Java的脾气,必定会打印堆栈信息,这个信息不能直接暴露给用户,一个缘由是打印的堆栈信息并非用户关心的内容,会影响用户体验;另外一方面,若是被黑客获取到堆栈信息,也是一种安全隐患。
因此咱们在编程过程当中,使用了不少try{ } catch{ },每当出现异常XxxException,能够根据异常的类型,返回给客户一个特定的异常页面。这个返回异常的部分若是直接写在业务代码中也是能够的,可是却不是推荐的。
Spring MVC提供了一个ExceptionResolver解析器,这个解析器能够为咱们作这么一个事情:根据咱们自定义的配置,当出现某种Exception的时候,就直接跳转到指定的页面,不须要在逻辑代码中进行处理。
举个例子:当服务端接收客户端上传的文件时,发现文件的大小超过了设置的最大值,此时,若是配置MultipartResolver时设置了上传文件的最大值,那么此时就会出现org.springframework.web.multipart.MaxUploadSizeExceededException,出现异常时,异常堆栈信息也会显示给客户端,此时就能够配置下ExceptionResolver,当出现这个错误,就跳转到uploadFailed.jsp中。
配置ExceptionResolver解析器的方式也很简单,只须要配置一个id为exceptionResolver的<bean>便可,class能够是ExceptionResolver的一个实现实现类。
<!-- 配置ExceptionResolver解析器 --> <bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <!-- 配置异常与跳转页面的对应关系 --> <property name="exceptionMappings"> <props> <prop key="org.springframework.web.multipart.MaxUploadSizeExceededException">/uploadFailed.jsp</prop> </props> </property> </bean>