一、文件上传的三要素
1、提供form表单,method必须是post
2、form表单的enctype必须是multipart/form-data
3、提供input type=“file”
二、enctype 的取值
1、application/x-www-form-urlencoded 普通表单方式
服务端使用request.getParameter("name");等方法可以获取普通字段的值
2、multipart/form-data 文件上传方式
服务端使用request.getParameter("name");等方法不可以获取普通字段的值
因为getParameter(String name)方法,获取的是字符流,但文件上传表单已经不再是字符内容,而是字节内容
需要使用第三方的插件:file-upload 链接:https://pan.baidu.com/s/1z02xCCZT7HpGpYk_y8Ur5w 密码:pmg3
fileupload:是由Apache 的commons组件提供的。主要工作是帮助我们解析request.getInputStream()
三、实现文件的上传
1、导入两个jar包: commons-fileupload-1.2.2 commons-io-2.2
2、fileUpload的核心类
- DiskFileItemFactory 创建工厂对象
- ServletFileUpload 使用工厂 创建解析器对象
- FileItem 使用解析器来解析request对象 : 可以获取普通标签和上传文件的标签
3、方法
- boolean isFormField() :判断当前的表单标签是否是普通标签 true 普通标签 false 文件上传标签
- String getFieldName() 获取 标签名
- String getString("编码集" ); 获取值并解决乱码
- String getName(); 获取上传域中添加的文件路径(绝对路径)
- void write(File) 把上传的文件保存在指定的文件中
文件上传时需要注意的问题:
A、限制文件的大小
- 为了项目的安全性考虑,设置文件的大小限制
- 设置单个的文件大小:SerlvetFileUpload.setFileSizeMax()
- 设置文件上传的总大小:ServletFIleUpload.setSizeMax()
B、设置临时文件
- DiskFileFactory.setRepository("设置临时文件的位置"):
- 如果上传的文件比较大,会产生一个临时文件,当文件上传成功,临时文件会被清理
- 注意:不要设置在系统盘,一般情况下,系统盘都有保护
- 临时文件:相当于缓存,缓存的大小是10kb,如果上传的文件大的话,就会出现临时文件,缓存数据
C、判断表单是否支持文件上传
- 判断表单是否设置了 enctype
- entype必须是multipart/form-data
- ServletFileUpload isMultipartContent(request) 支持true,不支持false
D、避免出现重名覆盖
- 文件名重组加上UUID.randomUUID()
E、避免同一个文件夹中文件过多 :打散目录
- 1、按照日期进行打散存储,当前日期/fileName
- 2、按照文件名 获取哈希值转成十六进制,创建文件夹 Integer.toHexString(hashcode);
F、解决中文乱码问题
- 1、解决上传框中的乱码 ServletFileUpload setHeaderEncoding("编码集")
- 2、解决普通文本框的乱码 FileItem getString("编码集")
G、截取文件名方式
- 1、第一种:fileName = fileName.substring(fileName.lastIndexOf("\\")+1);
- 2、第二种:fileName = FilenameUtils.getName(fileName);
H.文件存储路径映射
- 将文件存储在服务器硬盘上的绝对路径 无法通过浏览器访问?
- 在tomcat/conf/service.xml文件中<Host>标签添加一个
- <Context docBase="硬盘绝对路径" path="/访问地址" reloadable="true"/>
4、重要的代码:
upload.jsp
<form action="uploadServlet" method="post" enctype="multipart/form-data">
文件名:<input type="text" name="filename"/><br/>
文件描述:<input type="text" name="desc"><br/>
文件:<input type="file" name="upload"><br/>
<input type="submit" value="提交"><br/>
</form>
UploadServlet.java
@WebServlet("/uploadServlet")
public class UploadServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//C.判断表单是否支持文件上传
boolean flag = ServletFileUpload.isMultipartContent(req);
if(!flag){
throw new RuntimeException("你的表单不支持文件上传");
}
//1.创建工厂类对象
DiskFileItemFactory factory = new DiskFileItemFactory();
//B.设置临时文件 相当于是缓冲区
factory.setRepository(new File("d:\\"));
//2.创建解析器
ServletFileUpload upload = new ServletFileUpload(factory);
//F.解决中文乱码问题(上传框)
upload.setHeaderEncoding("utf-8");
//3.获取FileItem集合 解析请求 获取提交的表单元素的集合 包括普通标签 和 上传框
try {
//A限制文件大小
// upload.setFileSizeMax(1024*1024*2);//2m 设置单文件大小
// upload.setSizeMax(1024*1024*10);//10m 设置总大小
List<FileItem> items = upload.parseRequest(req);
for(FileItem item : items){
if(item.isFormField()){//判断表单元素 是普通 还是上传
//普通标签
processFormFile(item);
}else{
//上传标签
processUploadFile(item);
}
}
} catch(FileUploadBase.SizeLimitExceededException e){
System.out.println("文件过大 单文件不能超过2m ");
//作业1 当文件过大 将提示信息 显示在 upload.jsp上
}catch (FileUploadException e) {
e.printStackTrace();
}
}
//处理普通标签
private void processFormFile(FileItem item) {
// 获取标签名
String name = item.getFieldName();
//获取值
//F.解决普通标签中文乱码
String value ="";
try {
value = item.getString("utf-8");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(name+"::"+value);
}
//处理上传标签
private void processUploadFile(FileItem item) {
//1.在服务器上创建文件夹 来存储要上传的文件
String uploadPath = "D:\\web09_upload\\files\\";
//2.判断路径是否存在 如果不存在 就创建
File storePath = new File(uploadPath);
if(!storePath.exists()){
storePath.mkdirs();
}
//3.获取上传框中的文件
String fileName = item.getName();
//G.判断上传字段 是否有值
if(fileName!=null){
//D.避免文件名重复 覆盖现象 加上 UUID
fileName = UUID.randomUUID()+"_"+fileName;
//4.截取文件名 第一种
//fileName = fileName.substring(fileName.lastIndexOf("\\")+1);
//4.截取文件名 第二种
fileName = FilenameUtils.getName(fileName);
//E.打散目录 第一种方式 按照日期打散
//storePath = makeChildDir(storePath);
//E.打散目录 第二种方式 按照文件名 获取哈希值 转成16进制 打散目录
storePath = makeChildDir(storePath,fileName);
//5.将文件保存入文件夹
File file = new File(storePath, fileName);
try {
item.write(file);
} catch (Exception e) {
e.printStackTrace();
}
}
}
//方式1
private File makeChildDir(File storePath) {
// 按照日期创建文件夹
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
String dateDir = sdf.format(new Date());
File file = new File(storePath, dateDir);
if(!file.exists()){
file.mkdirs();
}
return file;
}
//方式2
private File makeChildDir(File storePath, String fileName) {
// 获取哈希码
int hashCode = fileName.hashCode();
// 转成16进制
String hex = Integer.toHexString(hashCode);
String s = hex.charAt(0)+File.separator+hex.charAt(1); // 7a --> 7/a
File file = new File(storePath, s);
if(!file.exists()){
file.mkdirs();
}
return file;
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}