Servlet3.0新增了request.getParts()/getPart(String filename) api,用于获取使用multipart/form-data格式传递的http请求的请求体,通常用于获取上传文件。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>图片上传</title>
<script>
window.onload = function(){
document.getElementById('fileUploader').onchange =
function(){
var file = document.getElementById('fileUploader').files[0];
var formData = new FormData(document.getElementById('imageForm'));
//formData.append("imageFile",file);
var httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = function(){
if(httpRequest.readyState == 4 && httpRequest.status == 200){
alert("结果: "+httpRequest.responseText);
}
};
httpRequest.open("post","http://localhost:8080/aos-maintain/imageProcess.jsp",true);
//httpRequest.setRequestHeader("Content-type","multipart/form-data");
httpRequest.send(formData);
}
};
</script>
</head>
<body>
<form id="imageForm" enctype="multipart/form-data" method="post">
<input id="fileUploader" name="fileUploader" type="file" multiple/>
</form>
</body>
</html>
上面的代码是一个上传文件的前台页面,选择文件后出发onchange事件,进行文件上传。
如图选择了三个文件,查看http请求体的格式,如下:
可见multipart/form-data格式的请求体将上传数据分成了多个结构相同的部分,“--”开头的一长串字符为浏览器生成的分隔符,请求体最后以两个“--”包裹的字符串作为结束标识,Content-Dispostion指明了当前part的数据对应的控件名,如果是文件,还会指出文件名。
package com.test.servlet;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
@MultipartConfig
@WebServlet("/imageProcess.jsp")
public class ImageProcessPrimitiveServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public ImageProcessPrimitiveServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("request.getContentType(): " + request.getContentType());
if(!request.getContentType().split(";")[0].equals("multipart/form-data"))
return;
Collection<Part> parts = request.getParts();
System.out.println(parts);
for(Part part:parts){
System.out.println(part);
FileProcess(part);
}
response.getWriter().print("end");
}
private void FileProcess(Part part) throws IOException {
System.out.println("part.getName(): " + part.getName());
if(part.getName().equals("fileUploader")){
String cd = part.getHeader("Content-Disposition");
String[] cds = cd.split(";");
String filename = cds[2].substring(cds[2].indexOf("=")+1).substring(cds[2].lastIndexOf("//")+1).replace("\"", "");
String ext = filename.substring(filename.lastIndexOf(".")+1);
System.out.println("filename:" + filename);
System.out.println("ext:" + ext);
InputStream is = part.getInputStream();
if(Arrays.binarySearch(ImageIO.getReaderFormatNames(),ext) >= 0)
imageProcess(filename, ext, is);
else{
commonFileProcess(filename, is);
}
}
}
private void commonFileProcess(String filename, InputStream is) {
FileOutputStream fos = null;
try{
fos=new FileOutputStream(new File(getClass().getResource("/").getPath()+filename));
int b = 0;
while((b = is.read())!=-1){
fos.write(b);
}
}catch(Exception e){
e.printStackTrace();
}finally{
try{
fos.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
private void imageProcess(String filename, String ext, InputStream is) throws IOException {
Iterator<ImageReader> irs = ImageIO.getImageReadersByFormatName(ext);
ImageReader ir = irs.hasNext()?irs.next():null;
if(ir == null)
return;
ir.setInput(ImageIO.createImageInputStream(is));//必须转换为ImageInputStream,否则异常
ImageReadParam rp = ir.getDefaultReadParam();
Rectangle rect = new Rectangle(0,0,200,200);
rp.setSourceRegion(rect);
int imageNum = ir.getNumImages(true);//allowSearch必须为true,否则有些图片格式imageNum为-1。
System.out.println("imageNum:" + imageNum);
for(int imageIndex = 0;imageIndex < imageNum;imageIndex++){
BufferedImage bi = ir.read(imageIndex,rp);
ImageIO.write(bi, ext, new File(getClass().getResource("/").getPath()+filename));
}
}
}
上面给出了servlet的处理过程,需要注意的是,使用request.getParts()方法必须给servlet添加注解@MultipartConfig,否则虽然不会抛出异常,但是获取不到数据。