在SpringMVC中处理文件上传是一件很容易的事。在编写控制器方法处理文件上传之前,我们必须要配置一个multipart解析器,通过它来告诉DispatcherServlet该如何读取multipart请求。
DispatcherServlet没有实现解析multipart请求数据的功能。它将任务委托给Spring中MutipartResolver策略接口实现,通过这个实现类来解析multipart请求中的内容。Spring3.1后内置两个MultipartResolver的实现供我们选择:
一般来讲,这两者之间StandardServletMultipartResolver会是优选方案。它使用Servlet所提供的功能支持,并不需要任何其他的项目。如果我们需要将应用部署到Servlet3.0之前的容器中,或者还没有使用Spring3.1或更高版本,那么可能就需要CommonsMultipartResolver了。
@Bean
public MultipartResolver multipartResolver() throws IIOException
{
return new StandardServletMultipartResolver();
}
既然这个@Bean方法如此简单,那我们该如何限制StandardServletMultipartResolver的工作方式呢?
具体来讲,我们必须要在web.xml或Servlet初始化类中,将multipart的具体细节作为DispatcherServlet配置的一部分。
因为我们配置的DispatcherServlet的Servlet初始化类继承了AbstractAnnotationConfigDispatcherServletInitializer,我们需要在初始化类中通过重载customizeRegistration()方法来配置multipart的具体细节。
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { RootConfig.class }; //指定根配置类,例如:application.xml
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { WebConfig.class }; //ָ指定Web配置类,例如:springMVC.xml
}
@Override
protected String[] getServletMappings() { //将DispatcherServlet映射到"/"
return new String[] { "/" };
}
@Override
protected void customizeRegistration(Dynamic registration) {
registration.setMultipartConfig( //通过重载customizeRegistration()方法来配置multipart的具体细节
new MultipartConfigElement("/tmp/uploads",2097152,4194304,0));
//设置写入的临时路径
//上传文件的最大容量(字节为单位),默认无限制。
//整个multipart请求的最大容量(字节为单位),默认无限制。
//在上传的过程中,如果文件大小达到了一个指定的最大容量,将会写入到临时文件路劲中。默认为0,也就是上传的文件都会写入到磁盘上。
}
}
<form action="/JavaConfigSpringMVC/upload" method="post" enctype="multipart/form-data">
<label>upload picture </label>
<input type="file" name="profilePicture" accept="image/jpeg,image/png" />
<input type="submit" value="提交">
</form>
@RequestMapping(value="/upload")
public String processRegistration(
@RequestPart("profilePicture") byte[] profilePicture // 当表单提交的时候profilePicture属性将会给定一个Byte
//数组,这个数组中包含了请求中对应part的数据(通过@RequestPart指定)
)
{
}
使用上传文件的原始byte比较简单但是功能有限。因此,Spring还提供了MultipartFile接口,它为处理multipart提供了内容更为丰富的对象。
public abstract interface MultipartFile {
String getName();
String getOriginalFilename();
String getContentType();
boolean isEmpty();
long getSize();
byte[] getBytes() throws java.io.IOException;
InputStream getInputStream() throws java.io.IOException;
void transferTo(File arg0) throws IOException,IllegalStateException;
}
修改processRegistration()方法如下
@RequestMapping(value="/uploads")
public String processRegistration(
@RequestPart("profilePicture") MultipartFile profilePicture
) throws IllegalStateException, IOException
{
profilePicture.transferTo(new File(profilePicture.getOriginalFilename()));
//profilePicture.transferTo(new File(UploadPath));可指定上传的路径
System.out.println(profilePicture.getOriginalFilename());//获得上传文件的名字
System.out.println(profilePicture.getName());//获取对象的名字
System.out.println(profilePicture.getContentType());//获取文件的类型
System.out.println(profilePicture.getSize());//获取文件的大小
return "hello";
}
如果你需要将应用部署到Servlet3.0的 容器中,那么会有MultipartFile的一个替代方案。SpringMVC也能接受javax.servlet.http.Part作为控制器方法的参数。如果使用Part来替代MultipartFile的话,那么processRegistration()方法如下:
@RequestMapping(value="/uploadByPart")
public String processRegistration(
@RequestPart("profilePicture") Part profilePicture // Part形式
) throws IllegalStateException, IOException
{
profilePicture.write(profilePicture.getSubmittedFileName());
System.out.println(profilePicture.getSubmittedFileName());//获得上传文件的名字,对应于getOriginalFilename()
System.out.println(profilePicture.getName()); //获取对象的名字
System.out.println(profilePicture.getContentType()); //获取文件的类型
System.out.println(profilePicture.getSize()); //获取文件的大小
return "hello";
}
Part接口
public abstract interface javax.servlet.http.Part {
InputStream getInputStream() throws java.io.IOException;
String getContentType();
String getName();
String getSubmittedFileName();
long getSize();
void write(String arg0) throws java.io.IOException;
void delete() throws java.io.IOException;
String getHeader(String arg0);
Collection getHeaders(String arg0);
Collection getHeaderNames();
}
Part接口与MultipartFile并没有什么太大的区别。
如果我们需要将应用部署到Servlet3.0之前的容器中,或者还没有使用Spring3.1或更高版本,那么可能就需要CommonsMultipartResolver了。
@Bean
public MultipartResolver multipartResolver() throws IOException
{
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
//CommonsMultipartResolver不会强制要求设置临时文件路径。默认情况下,这个路径就是Servlet容器的临时目录,不过可以通过setUploadTempDir属性设置。
multipartResolver.setUploadTempDir(new FileSystemResource("D:\\uploads"));//需要绝对路径
//multipartResolver.setUploadTempDir(new FileSystemResource("/tmp/uploads"));
multipartResolver.setMaxInMemorySize(0);//最大内存大小
multipartResolver.setMaxUploadSize(2097152);//最大文件容量
return multipartResolver;
}
@RequestMapping("/load")
public ResponseEntity<byte[]> download(HttpServletRequest request,String filePath) throws IOException {
request.setCharacterEncoding("UTF-8");
//获取文件
File file = new File(filePath);
//获取文件名
String fileName = file.getName();
//解决文件名乱码
String fileName1 =new String(fileName.getBytes("UTF-8"),"iso-8859-1");
//读取二进制文件
byte[] body = null;
InputStream is = new FileInputStream("F:/Users/yd/Workspaces/MyEclipse 2017 CI/OnLineTest/"+file);
body = new byte[is.available()];
is.read(body);
HttpHeaders headers = new HttpHeaders();
//通知浏览器以attachment(下载方式)打开图片
headers.add("Content-Disposition", "attchement;filename=" + fileName1);
//application/octet-stream二进制流数据(最常见的文件下载)。
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
//文件下载的Http协议中的状态最好使用HttpStatus.OK。
HttpStatus statusCode = HttpStatus.OK;
ResponseEntity<byte[]> entity = new ResponseEntity<byte[]>(body, headers, statusCode);
return entity;
}
以上只是学习Spring实战所写的笔记,如有错误,请指正。谢谢