文件上传
1. 文件上传的前提
- form表单的ectype属性(表单请求正文的类型)取值必须是
multipart/form-data
,默认值是application/x-www-form-urlencoded - method属性值为
post
- 提供文件选择域
<input type="file"/>
2. 文件上传的原理
ectype=application/x-www-form-urlencoded(默认值)
表单的正文内容
key=value&key=value&key=value...
注:ectype取值不是默认值后,request.getParameter()将失效
ectype=multipart/form-data
表单的正文内容
3. 文件上传的相关jar包及Maven坐标
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
4. SpringMVC实现传统方式文件上传
index.jsp
<%--
Created by IntelliJ IDEA.
User: 商务小本本
Date: 2022/3/3
Time: 23:27
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form method="post" enctype="multipart/form-data" action="test/testFileUpload">
<input type="file" name="upload">
<br>
<input type="submit" value="提交文件">
</form>
</body>
</html>
Controller
package cn.itcast.controller;
import cn.itcast.domain.User;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.util.List;
import java.util.UUID;
/**
* @author 商务小本本
*/
@Controller
@RequestMapping("/test")
public class HelloController {
@RequestMapping("/testFileUpload")
public String testFileUpload(HttpServletRequest request) throws Exception {
//设置上传到的目录
String path = request.getSession().getServletContext().getRealPath("/uploads/");
File file = new File(path);
//判断待上传的目录是否存在,如果不存在就创建
if (!file.exists()){
file.mkdirs();
}
//创建文件项工厂,用于创建文件项
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload fileUpload = new ServletFileUpload(factory);
//解析request,获取到所有项
List<FileItem> items = fileUpload.parseRequest(request);
for (FileItem item:items) {
//判断是否为普通表单项,如果是文件项就可实现上传文件
if (item.isFormField()){
}else {
String fileName = item.getName();
//解决重名文件上传的问题,加入uuid保证文件名唯一
String replace = UUID.randomUUID().toString().replace("-", "");
fileName = replace + "_" + fileName;
item.write(new File(path, fileName));
//删除临时文件,若上传的文件超过10kb,产生临时文件,需要删除;若上传的文件不到10kb,会在内存中生成缓存文件,不需要处理。
item.delete();
}
}
return "success";
}
}
5. SpringMVC实现文件上传
5.1 原理分析
5.2 配置文件解析器
<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver">
<property name="maxUploadSize" value="10485760"></property>
</bean>
5.3 实现
package cn.itcast.controller;
import cn.itcast.domain.User;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.util.List;
import java.util.UUID;
/**
* @author 商务小本本
*/
@Controller
@RequestMapping("/test")
public class HelloController {
@RequestMapping("/testFileUpload")
public String testFileUpload(MultipartFile upload, HttpServletRequest request) throws Exception {
//设置上传到的目录
String path = request.getSession().getServletContext().getRealPath("/uploads/");
File file = new File(path);
//判断待上传的目录是否存在,如果不存在就创建
if (!file.exists()){
file.mkdirs();
}
String fileName = upload.getOriginalFilename();
String replace = UUID.randomUUID().toString().replace("-", "");
fileName = replace + "_" + fileName;
upload.transferTo(new File(path, fileName));
// //创建文件项工厂,用于创建文件项
// DiskFileItemFactory factory = new DiskFileItemFactory();
// ServletFileUpload fileUpload = new ServletFileUpload(factory);
// //解析request,获取到所有项
// List<FileItem> items = fileUpload.parseRequest(request);
// for (FileItem item:items) {
// //判断是否为普通表单项,如果是文件项就可实现上传文件
// if (item.isFormField()){
//
// }else {
// String fileName = item.getName();
// String replace = UUID.randomUUID().toString().replace("-", "");
// fileName = replace + "_" + fileName;
// item.write(new File(path, fileName));
// //删除临时文件,若上传的文件超过10kb,产生临时文件,需要删除;若上传的文件不到10kb,会在内存中生成缓存文件,不需要处理。
// item.delete();
// }
// }
return "success";
}
}
6. 跨服务器文件上传
6.1 应用场景
当应用服务器向文件服务器请求上传文件时就要用到跨服务器的文件上传
6.2 相关的jar包和Maven坐标
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
<version>1.18.1</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.18.1</version>
</dependency>
6.3 环境部署
搭建本地测试环境时,由于一台机器上要跑两个服务器,HTTP port和JMX port需要单独配置,避免冲突
6.4 功能实现
package cn.itcast.controller;
import cn.itcast.domain.User;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.util.List;
import java.util.UUID;
/**
* @author 商务小本本
*/
@Controller
@RequestMapping("/test")
public class HelloController {
@RequestMapping("/testFileUploadServer")
public String testFileUploadServer(MultipartFile upload) throws Exception {
//目标文件服务器路径
String path = "http://localhost:8090/uploadserver_war/uploads/";
String fileName = upload.getOriginalFilename();
String replace = UUID.randomUUID().toString().replace("-", "");
fileName = replace + "_" + fileName;
//创建客户端对象
Client client = Client.create();
//连接文件服务器
WebResource webResource = client.resource(path + fileName);
//上传文件
webResource.put(upload.getBytes());
return "success";
}
}
6.5 可能出现的错误
-
com.sun.jersey.api.client.UniformInterfaceException: PUT http://localhost:8090/uploadserver_war/uploads/56834c683cc545afaa169a6640755a70_info.txt returned a response status of 405 Method Not Allowed
解决方法:
如果运行环境readonly(只读),则tomcat会拒绝所有的HTTP的修改方法(如put,delete),默认为true。
tomcat安装目录下的web.xml
参考网站:【错误处理】上传文件出错returned a response status of 405 Method Not Allowed,400 -
com.sun.jersey.api.client.UniformInterfaceException: PUT http://localhost:8090/uploadserver_war/uploads/a6f0e1ad00274947b7143fcfabb7053d_info.txt returned a response status of 409 Conflict
要上传的目标目录不存在导致的,在tomcat的部署目录创建目标目录即可