文件上传
准备:
1):上传控件所在的表单的method,必须是POST:
因为GET方式传入的数据大小不能超过2KB,而PSOT没有大小限制。
<form method="POST">
2):上传控件得使用type为file的类型
<input type="file" name="headImg" />
3) :表单的编码方式必须时二进制编码
<form enctype="multipart/form-data">
在API文档中找form标签下的enctype属性:
初步文件代码:
upload.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h3>文件上传</h3><br/>
<form action="/upload-download-i18n/upload" method="POST" enctype="multipart/form-data">
账号:<input type="text" name="username"/><br/>
邮箱:<input type="text" name="email"/><br/>
头像:<input type="file" name="headImg" accept="image/*"/><br/>
<input type="submit" value="朕要提交"/><br/>
</form>
</body>
</html>
uploadServlet.java
@WebServlet("/upload")
public class UploadServlet extends HttpServlet{
private static final long serialVersionUID = 1L;
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
System.out.println(req.getParameter("username"));
System.out.println(req.getParameter("email"));
System.out.println(req.getParameter("headImg"));
}
}
不同编码区别:
application/x-www-form-urlencoded(默认)编码:
*
*
网页输入数据并提交
eclipse中显示内容:
注意:这里显示的文件名称仅仅就是文件名称,没有内容。
multipart/form-data编码:
*
用此编码使每个参数分成了单独一块,其中文件、图片等直接将内容转码后上传不再仅仅传入一个文件名称。
但是这时候就不能在Servlet中使用request .setParameter(“key”);来获取对应的参数值。
解决multipart/form-data编码无法传参问题:
使用FileUpload组件
1):引入jar包
common-fileupload-xxxx.jar 下载
common-io-xxx.jar 下载
2):将上述的uploadServlet.java改为:
@WebServlet("/upload")
public class UploadServlet extends HttpServlet{
private static final long serialVersionUID = 1L;
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//解析和检查请求:请求方式是否是POST,请求编码是否是muitipart/form-data
boolean isMultipart = ServletFileUpload.isMultipartContent(req);
if(!isMultipart) {
return;
}
try {
//1.创建FileItemFactory对象
//FileItemFactory是用来创建FileItem对象的
//FileItem对象:form表单中的表单控件的封装
FileItemFactory factory = new DiskFileItemFactory();
//2.创建文件上传处理器
ServletFileUpload upload = new ServletFileUpload(factory);
//3.解析请求
List<FileItem> items = upload.parseRequest(req);
//4.迭代出每一个FileItem
for(FileItem item : items) {
String fieldName = item.getFieldName();//获取表单控件的name属性值(参数名)
if(item.isFormField()) {
//普通表单控件
String value = item.getString("UTF-8");
System.out.println(fieldName + "-" + value);
}else {
//表单上传控件
System.out.println(fieldName + "-" + item.getName());
item.write(new File("E:/JAVA/FileUpload/", item.getName()));//把二进制数据写到哪一个文件中
}
}
}catch(Exception e) {
e.printStackTrace();
}
}
}
注解:
1.先进行判断在upload.jsp中的请求方式是否为:POST,编码格式是否为:multipart/form-data
有一种不对相应就直接结束程序
if(!isMultipart) {
return;
}
2.创建一个FileItem工厂对象(FileItemFactory),再在工厂对象中创建文件上传处理器(ServletFileUpload)
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
3.使用List集合将响应中的所用FileItem存入集合中
List<FileItem> items = upload.parseRequest(req);
4.迭代出每一个FileItem对象
for(FileItem item : items)
5.判断每一个控件是普通控件还是上传控件
if(item.isFormField())
6.普通控件 ------ 读取参数值(如果参数值有汉字,需要使用UTF-8编码)
//普通表单控件
String value = item.getString("UTF-8");
System.out.println(fieldName + "-" + value);
7.上传控件-------读取参数值(方法参数为:目标路径 和 文件名称)
//表单上传控件
System.out.println(fieldName + "-" + item.getName());
item.write(new File("E:/JAVA/FileUpload/", item.getName()));//把二进制数据写到哪一个文件中
上传文件的名称问题
1):文件名处理
IE6问题:通过FileItem.getName方法获取上传文件的名称,此时会带有路径:
其他浏览器:c.png
IE6:c:/a/b/c.png
解决方案:
使用FilenameUtils.getName(path)
上传文件名称重复问题
给上传的文件起唯一的名称:使用UUID产生随机数,再加文件名
String fileName = UUID.randomUUID().toString()+"."+FilenameUtils.getExtension(item.getName());
**上传文件的保存路径:**一般的,把上传文件保存到应用里面
2):缓存大小和临时目录:
超过多少就不直接存放在内存中了(缓存大小):默认值是10KB.
在DiskFileItemFactory类中有:
不存在内存,放在临时目录中:默认Tomcat根/temp目录。 不建议修改。
注:判断文件是否在内存中方法
item.isInMemory();
3):文件类型约束:
方法一:
若判断是上传文件时,判断上传文件类型是否符合要求:
如果上传文件类型符合要求,则继续上传,否则返回错误信息到jsp文件中显示给用户
方法二:
判断上传文件的MIME类型:
String str = super.getServletContext().getMimeType(item.getName());
如:上传类型需要是图片就会以image开头,为:image/* 的格式,不同文件类型的MIME类型不同。
抽取文件上传工具方法:
自定义一个异常类(LogicException继承runtimeException)----接受文件类型异常
public class LogicException extends RuntimeException{
private static final long serialVersionUID = 1L;
public LogicException(String message, Throwable cause) {
super(message, cause);
}
public LogicException(String message) {
super(message);
}
}
其中的构造方法可自动生成:
空白处右键---->Source---->Generate Constructors from Superclass
选择
LogicException(String , Throwable )
LogicException(String )
两项即可:
工具类—上传文件方法:
public class FileUtil {
//允许接受上传的文件类型(如:图片)
private static final String ALLOWED_IMAGE_TYPE="png;gif;jpg;jpeg";
public static void upload(HttpServletRequest req){
//解析和检查请求:请求方式是否是POST,请求编码是否是muitipart/form-data
boolean isMultipart = ServletFileUpload.isMultipartContent(req);
if(!isMultipart) {
return;
}
try {
//1.创建FileItemFactory对象
//FileItemFactory是用来创建FileItem对象的
//FileItem对象:form表单中的表单控件的封装
DiskFileItemFactory factory = new DiskFileItemFactory();
//2.创建文件上传处理器
ServletFileUpload upload = new ServletFileUpload(factory);
//3.解析请求
List<FileItem> items = upload.parseRequest(req);
//4.迭代出每一个FileItem
for(FileItem item : items) {
String fieldName = item.getFieldName();//获取表单控件的name属性值(参数名)
if(item.isFormField()) {
//普通表单控件
String value = item.getString("UTF-8");
System.out.println(fieldName + "-" + value);
}else {
//----------------------------------------------------------
//上传文件的拓展名
String ext = FilenameUtils.getExtension(item.getName());
String[] allowedImageType = ALLOWED_IMAGE_TYPE.split(";");
//当前上传类型不再允许的范围内
if(!Arrays.asList(allowedImageType).contains(ext)) {
throw new LogicException("上传格式错误,请重新上传");
}
//----------------------------------------------------------
//表单上传控件
System.out.println("上传文件的名称:"+item.getName());
//文件名称
String fileName = UUID.randomUUID().toString()+"."
+FilenameUtils.getExtension(item.getName());
//目标的绝对路径"E:/JAVA/My_eclipseEE/upload-download-i18n/webapp/upload"
String dir = req.getServletContext().getRealPath("/upload");
//把二进制数据写到哪一个文件中
item.write(new File(dir, fileName));
}
}
}catch(LogicException e) {
throw e;//继续抛出异常类给该类调用者(UploadServlet)
}catch(Exception e) {
e.printStackTrace();
}
}
}
在工具类中定义上传文件类型、和上传方法;
在上传方法中判断是否符合文件类型,如果不符合就抛出LogicException异常,由于Exception接受所有异常并处理,使异常信息无法传到JSP文件显示给用户,所以在抛出Exception之前要先抛出LogicException异常,再在LogicException中抛出给调用者(UploadServlet)中处理。
UploadServlet.java(调用者)
@WebServlet("/upload")
public class UploadServlet extends HttpServlet{
private static final long serialVersionUID = 1L;
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
FileUtil.upload(req);
}catch(LogicException e) {
String errorMsg = e.getMessage();//获取异常信息
req.setAttribute("errorMsg",errorMsg);
req.getRequestDispatcher("/upload.jsp").forward(req, resp);
}
}
}
直接调用工具类中的上传文件的方法upload;
返回的异常信息是:如果上传的文件格式不符,则返回在upload方法中自定义的错误信息,通过在catch中获取异常信息,并传给jsp文件显示错误信息,让用户重新进行上传。
上传文件大小约束:
情况1:单个文件超过指定的大小。 upload.setFileSizeMax(102410242);//2M
情况2:该次请求的全部数据超过指定的大小。upload.setSizeMax(102410243);//3M
在java文件中增加文件大小限制:
注意:
catch中抛出的异常类是自定义的异常类(LogicException源码同上)
在JSP文件中增加一个上传文件:
上传失败:
注:
如果设置过后运行不会出现错误信息提示,直接网页报错,说明自定义设置的限制文件大小大于系统页面规定的的组件大小,如果组件大小超过系统规定,应该单独去写该组件。