从原始的Servlet来实现文件的上传,代码如下:

采用的是Multipart/form-data的方式上传文件。针对Multipart/form-data方式的上传解释,参考如下文件:

下面为具体的实现方式:

1、通过getInputStream()取得上传文件。

注意:这种方式相当的原始,通过分析body中的字符,然后再进行硬编码切割出文件字节,再进行保存。

JSP:

文件1:
文件2:
文件3:
Text:

Servlet:

提示:使用了servlet3.0的标注免配置功能。

packageuploadtest;importjava.io.DataInputStream;importjava.io.File;importjava.io.FileOutputStream;importjava.io.IOException;importjava.text.SimpleDateFormat;importjava.util.Calendar;importjava.util.Date;importjavax.servlet.ServletException;importjavax.servlet.annotation.WebServlet;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;/*** Servlet implementation class UploadServlet*/@WebServlet("/UploadServlet")public class UploadServlet extendsHttpServlet {private static final long serialVersionUID = 1L;/***@seeHttpServlet#HttpServlet()*/

publicUploadServlet() {super();//TODO Auto-generated constructor stub

}/***@seeHttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)*/

protected void doGet(HttpServletRequest request, HttpServletResponse response) throwsServletException, IOException {//TODO Auto-generated method stub

}/***@seeHttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)*/

protected void doPost(HttpServletRequest request, HttpServletResponse response) throwsServletException, IOException {//TODO Auto-generated method stub

this.processRequest(request, response);

}//通过getInputStream()取得上传文件。循环多文件

/*** Processes requests for both HTTP

* POST methods.

*

*@paramrequest servlet request

*@paramresponse servlet response

*@throwsServletException if a servlet-specific error occurs

*@throwsIOException if an I/O error occurs*/

protected voidprocessRequest(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException {

response.setContentType("text/html;charset=UTF-8");//读取请求Body

byte[] body =readBody(request);//取得所有Body内容的字符串表示

String textBody = new String(body, "ISO-8859-1");//取得文件区段边界信息,并通过边界循环获取文件流

String contentType =request.getContentType();

String boundaryText= String.format("--%1$s", contentType.substring(contentType.lastIndexOf("=") + 1, contentType.length()));for(String tempTextBody : textBody.split(boundaryText)){//多文件循环

if(tempTextBody.length()>0){//取得上传的文件名称

String fileName =getFileName(tempTextBody);if(fileName.length()>0){//取得文件开始与结束位置

Position p =getFilePosition(tempTextBody);//输出至文件

writeTo(fileName, tempTextBody.getBytes("ISO-8859-1"), p);

}

}

}

}/*** 文件起始位置类

**/

classPosition {intbegin;intend;public Position(int begin, intend) {this.begin =begin;this.end =end;

}

}/*** 获取request的getInputStream,返回byte

*

*@paramrequest

*@return*@throwsIOException*/

private byte[] readBody(HttpServletRequest request) throwsIOException {//获取请求文本字节长度

int formDataLength =request.getContentLength();//取得ServletInputStream输入流对象

DataInputStream dataStream = newDataInputStream(request.getInputStream());byte body[] = new byte[formDataLength];int totalBytes = 0;while (totalBytes

totalBytes+=bytes;

}returnbody;

}/*** 获取文件起始位置

*

*@paramrequest

*@paramtextBody

*@return*@throwsIOException*/

private Position getFilePosition(String textBody) throwsIOException {//取得实际上传文件的起始与结束位置

int pos = textBody.indexOf("filename=\"");

pos= textBody.indexOf("\n", pos) + 1;

pos= textBody.indexOf("\n", pos) + 1;

pos= textBody.indexOf("\n", pos) + 1;int begin = ((textBody.substring(0, pos)).getBytes("ISO-8859-1")).length;int end = textBody.getBytes("ISO-8859-1").length;return newPosition(begin, end);

}/*** 获取文件名

*

*@paramrequestBody

*@return

*/

privateString getFileName(String requestBody) {try{

String fileName= requestBody.substring(requestBody.indexOf("filename=\"") + 10);

fileName= fileName.substring(0, fileName.indexOf("\n"));

fileName= fileName.substring(fileName.indexOf("\n") + 1,fileName.indexOf("\""));//取扩展名加随机数进行重命名

fileName = new SimpleDateFormat("yyyyMMddHHmmsssss").format(new Date())+java.util.UUID.randomUUID() + fileName.substring(fileName.lastIndexOf("."),fileName.length());returnfileName;

}catch(Exception e) {return "";

}

}/*** 写文件

*

*@paramfileName

*@parambody

*@paramp

*@throwsIOException*/

private void writeTo(String fileName, byte[] body, Position p) throwsIOException {

String filePath= this.getServletContext().getRealPath("")+"/Uploads/"+new SimpleDateFormat("yyyyMMdd").format(new Date())+"/";//初始化保存的位置

Tools.isExistDir(filePath);//看目录是否已经创建

FileOutputStream fileOutputStream = new FileOutputStream(filePath +fileName);

fileOutputStream.write(body, p.begin, (p.end-p.begin));

fileOutputStream.flush();

fileOutputStream.close();

}

}

2、通过getPart()、getParts()取得上传文件。

Servlet3.0中新增了getPart()和getParts()函数用来处理上传文件,getPart()用于上传单文件,getParts()用于上传多个文件。详细参考:http://blog.csdn.net/new_one_object/article/details/51373802

同样的,用此方法只支持multipart/form-data请求类型的文件上传。

还有一点,在Servlet上必须标注特性标记头@MultipartConfig,以表示是multipart/form-data类型的MIME。

JSP:

文件1:
文件2:
文件3:
Text:

Servlet:

提示:使用了servlet3.0的标注免配置功能。

packageuploadtest;importjava.io.FileNotFoundException;importjava.io.FileOutputStream;importjava.io.IOException;importjava.io.InputStream;importjava.io.OutputStream;importjava.text.SimpleDateFormat;importjava.util.Date;importjavax.servlet.ServletException;importjavax.servlet.annotation.MultipartConfig;importjavax.servlet.annotation.WebServlet;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjavax.servlet.http.Part;/*** Servlet implementation class UploadServlet*/@MultipartConfig

@WebServlet("/UploadServlet")public class UploadServlet extendsHttpServlet {private static final long serialVersionUID = 1L;/***@seeHttpServlet#HttpServlet()*/

publicUploadServlet() {super();//TODO Auto-generated constructor stub

}/***@seeHttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)*/

protected void doGet(HttpServletRequest request, HttpServletResponse response) throwsServletException, IOException {//TODO Auto-generated method stub

}/***@seeHttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)*/

protected void doPost(HttpServletRequest request, HttpServletResponse response) throwsServletException, IOException {//TODO Auto-generated method stub

this.processRequest(request, response);

}//通过getPart()、getParts()取得上传文件。单文件

/*** Processes requests for both HTTP

* POST methods.

*

*@paramrequest servlet request

*@paramresponse servlet response

*@throwsServletException if a servlet-specific error occurs

*@throwsIOException if an I/O error occurs*/

protected voidprocessRequest(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException {

Part part= request.getPart("file1");//参数就是input标签的name属性,且这个name必须是唯一的

String fileName =getFileName(part);

writeTo(fileName, part);

}//取得上传文件名

privateString getFileName(Part part) {

String header= part.getHeader("Content-Disposition");

String fileName= header.substring(header.indexOf("filename=\"") + 10, header.lastIndexOf("\""));//取扩展名加随机数进行重命名

fileName = new SimpleDateFormat("yyyyMMddHHmmsssss").format(new Date())+java.util.UUID.randomUUID() + fileName.substring(fileName.lastIndexOf("."),fileName.length());returnfileName;

}//存储文件

private void writeTo(String fileName, Part part) throwsIOException, FileNotFoundException {

InputStream in=part.getInputStream();

String filePath= this.getServletContext().getRealPath("")+"/Uploads/"+new SimpleDateFormat("yyyyMMdd").format(new Date())+"/";//初始化保存的位置

Tools.isExistDir(filePath);//看目录是否已经创建

OutputStream out = new FileOutputStream(filePath +fileName);byte[] buffer = new byte[1024];int length = -1;while ((length = in.read(buffer)) != -1) {

out.write(buffer,0, length);

}

in.close();

out.close();

}

}

通过上面的代码很明显的区别出这个方法简单明了,省去了切割字符串的问题。

接下来再升级简化一下流的写入,将用到@MultipartConfig特性中的location属性,这个属性将指定一个本地目录,然后调用wtite方法直接写入。不过这个也有一个不好的特点,路径是死的,没法按照自定义输出。

Servlet改造如下:

packageuploadtest;importjava.io.FileNotFoundException;importjava.io.FileOutputStream;importjava.io.IOException;importjava.io.InputStream;importjava.io.OutputStream;importjava.text.SimpleDateFormat;importjava.util.Date;importjavax.servlet.ServletException;importjavax.servlet.annotation.MultipartConfig;importjavax.servlet.annotation.WebServlet;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjavax.servlet.http.Part;/*** Servlet implementation class UploadServlet*/@MultipartConfig(location= "d:\\\\workspace")

@WebServlet("/UploadServlet3")public class UploadServlet3 extendsHttpServlet {private static final long serialVersionUID = 1L;/***@seeHttpServlet#HttpServlet()*/

publicUploadServlet3() {super();//TODO Auto-generated constructor stub

}/***@seeHttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)*/

protected void doGet(HttpServletRequest request, HttpServletResponse response) throwsServletException, IOException {//TODO Auto-generated method stub

}/***@seeHttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)*/

protected void doPost(HttpServletRequest request, HttpServletResponse response) throwsServletException, IOException {//TODO Auto-generated method stub

this.processRequest(request, response);

}//通过getPart()、getParts()取得上传文件。单文件

/*** Processes requests for both HTTP

* POST methods.

*

*@paramrequest servlet request

*@paramresponse servlet response

*@throwsServletException if a servlet-specific error occurs

*@throwsIOException if an I/O error occurs*/

protected voidprocessRequest(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException {

Part part= request.getPart("file1");//参数就是input标签的name属性,且这个name必须是唯一的

String fileName =getFileName(part);//将文件写入location指定的目录

part.write(fileName);

}//取得上传文件名

privateString getFileName(Part part) {

String header= part.getHeader("Content-Disposition");

String fileName= header.substring(header.indexOf("filename=\"") + 10, header.lastIndexOf("\""));//取扩展名加随机数进行重命名

fileName = new SimpleDateFormat("yyyyMMddHHmmsssss").format(new Date())+java.util.UUID.randomUUID() + fileName.substring(fileName.lastIndexOf("."),fileName.length());returnfileName;

}

}

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐