文件上传
一、对表单的一些要求
- 提交方法必须是post:
method="post"
。 - 编码属性必须是multipart/form-data,也就是“多组件的表单数据”,即
enctype="multipart/form-data"
。 - 表单中需要添加文件表单项,即
<input type="file" name="xxx" />
。
示例:
<body>
<h1>上传1</h1>
<form action="<c:url value='/Upload1Servlet'/>" method="post" enctype="multipart/form-data">
用户名:<input type="text" name="username" /><br>
照片:<input type="file" name="zhaopian" /><br>
<input type="submit" value="上传" />
</form>
</body>
二、对servlet的一些要求
我们回忆一下我们以前用来接收表单传递过来的参数,使用的request.getParameter("xxx")
,而这个方法在表单为enctype="multipart/form-data"
时,就作废了。它永远都会返回null。
那么我们应该使用什么样的方法呢?是request.getInputStream()
,返回值为ServletInputStream
类型,它会包含整个请求的体。
接下来我们研究一下多部件表单的体。
三、多部件表单请求体
- 分隔出多个部件,即一个表单项一个部件。
- 一个部件中自己包含请求头和空行,以及请求体。
- 普通表单项:
只有一个头:Content-Disposition:包含name=“xxxx”,即表单项名称。
体就是表单项的值
。 - 文件表单项:
有两个头:Content-Disposition
:包含name="xxxx"
,即表单项名称;还有一个filename="xxx"
,表示上传文件的名称Content-Type
:它是上传文件的MIME类型,例如:image/pjpeg,表示上传的是图片,其中是jpg扩展名的图片。
体就是上传文件的内容
。
四、使用servlet获取表单上传的数据
我们写一个相应的Servlet:
public class Upload1Servlet extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
ServletInputStream in = request.getInputStream();
String s = IOUtils.toString(in);
System.out.println(s);
}
}
然后我们在页面表单上输入一些内容,然后在后台查看会输出什么。
后台内容:
我们可以清楚的看到上传组件的部分构成。
五、commons-fileupload组件介绍
我们在上面的示例中获取了表单上传的数据,但是明显的是,我们上传的是一张图片,后台显示出来的是一堆字符乱码,这显然是没用的,我们就要想办法把它变成图片,这个时候应该怎么做呢?
我们通过观察,可以发现,请求体是有一定的固定格式的,我们很容易联想到我们采取字符串分割一步步得到我们想要的内容,但是这样有点太过于麻烦,这个时候我们应该怎么办呢?其实Apache已经帮我们提供了解析它的工具:commons-fileupload。
fileupload是由apache的commons组件提供的上传组件。它最主要的工作就是帮我们解析request.getInputStream()
。
fileupload组件需要的JAR包有:
- commons-fileupload.jar,核心包;
- commons-io.jar,依赖包。
这个小组件,它会帮我们解析request中的上传数据,解析后的结果是一个表单项数据封装到一个FileItem
对象中。我们只需要调用FileItem的方法即可!
fileupload的核心类有:DiskFileItemFactory
、ServletFileUpload
、FileItem
。
使用fileupload组件的步骤如下:
1). 创建工厂类DiskFileItemFactory对象:DiskFileItemFactory factory = new DiskFileItemFactory();
2). 使用工厂创建解析器对象:ServletFileUpload fileUpload = new ServletFileUpload(factory);
3). 使用解析器来解析request对象:List<FileItem> list = fileUpload.parseRequest(request);
我们重点介绍一下FileItem
类。一个FileItem对象对应一个表单项(表单字段)。一个表单中存在文件字段和普通字段,可以使用FileItem类的isFormField()
方法来判断表单字段是否为普通字段,如果不是普通字段,那么就是文件字段了。
-
String getName()
:获取文件字段的文件名称; -
String getString()
:获取字段的内容,如果是文件字段,那么获取的是文件内容,当然上传的文件必须是文本文件; -
String getFieldName()
:获取字段名称,例如:<input type=”text” name=”username”/>
,返回的是username; -
String getContentType()
:获取上传的文件的类型,例如:text/plain。 -
int getSize()
:获取上传文件的大小; -
boolean isFormField()
:判断当前表单字段是否为普通文本字段,如果返回false,说明是文件字段; -
InputStream getInputStream()
:获取上传文件对应的输入流; -
void write(File)
:把上传的文件保存到指定文件中。
六、上传的实例
接下来我们写一下上传的示例。
首先新建一个jsp,放入一个表单:
<body>
<h1>上传2</h1>
<form action="<c:url value='/Upload2Servlet'/>" method="post" enctype="multipart/form-data">
用户名:<input type="text" name="username" /><br>
照片:<input type="file" name="zhaopian" /><br>
<input type="submit" value="上传" />
</form>
</body>
接下来是我们的servlet:
public class Upload2Servlet extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
/*
* 上传的三步:
* 1.创建工厂类;
* 2.通过工厂类创建解析器;
* 3.解析request,得到FileItem集合
* 4.遍历FileItem集合,调用其API完成文件的保存
*/
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload sfu = new ServletFileUpload(factory);
try {
List<FileItem> fileItemList = sfu.parseRequest(request);
FileItem fi1 = fileItemList.get(0);
FileItem fi2 = fileItemList.get(1);
System.out.println("普通表单项演示:" + fi1.getFieldName() + "="
+ fi1.getString("UTF-8"));
System.out.println("文件表单项演示:");
System.out.println("Content-Type:" + fi2.getContentType());
System.out.println("size:" + fi2.getSize());
System.out.println("filename:" + fi2.getName());
// 保存文件
File destFile = new File("E:/test.jpg");
fi2.write(destFile);
} catch (FileUploadException e) {
throw new RuntimeException(e);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
我们在浏览器中打开网页,并且选择一张图片:
我们看一下后台出现了什么:
我们再看一下我们的E盘下有没有出现一个新的文件:
我们发现,功能全部符合我们的预期。
下一步,我们就要研究一下文件上传中的一些其他的细节问题。
END.