Java中的文件上传(原始Servlet实现)
从原始的Servlet来实现文件的上传,代码如下:
参考:https://my.oschina.net/Barudisshu/blog/150026
采用的是Multipart/form-data的方式上传文件。针对Multipart/form-data方式的上传解释,参考如下文件:
http://www.onmpw.com/tm/xwzj/network_35.html
http://892848153.iteye.com/blog/1847467
http://blog.csdn.net/five3/article/details/7181521
下面为具体的实现方式:
1、通过getInputStream()取得上传文件。
注意:这种方式相当的原始,通过分析body中的字符,然后再进行硬编码切割出文件字节,再进行保存。
JSP:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<div>
<form action="UploadServlet" method="POST" enctype="multipart/form-data">
<table>
<tr>
<td><label for="file1">文件1:</label></td>
<td><input type="file" id="file1" name="file"></td>
</tr>
<tr>
<td><label for="file2">文件2:</label></td>
<td><input type="file" id="file2" name="file"></td>
</tr>
<tr>
<td><label for="file3">文件3:</label></td>
<td><input type="file" id="file3" name="file"></td>
</tr>
<tr>
<td><label for="file3">Text:</label></td>
<td><input type="text" id="text1" name="text1"></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="上传" name="upload"></td>
</tr>
</table>
</form>
</div>
</body>
</html>
Servlet:
提示:使用了servlet3.0的标注免配置功能。
package uploadtest; import java.io.DataInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date; import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; /**
* Servlet implementation class UploadServlet
*/
@WebServlet("/UploadServlet")
public class UploadServlet extends HttpServlet {
private static final long serialVersionUID = 1L; /**
* @see HttpServlet#HttpServlet()
*/
public UploadServlet() {
super();
// TODO Auto-generated constructor stub
} /**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
} /**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
this.processRequest(request, response);
} //通过getInputStream()取得上传文件。循环多文件
/**
* Processes requests for both HTTP
* <code>POST</code> methods.
*
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, 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);
}
}
}
} /**
* 文件起始位置类
*
*/
class Position { int begin;
int end; public Position(int begin, int end) {
this.begin = begin;
this.end = end;
}
} /**
* 获取request的getInputStream,返回byte
*
* @param request
* @return
* @throws IOException
*/
private byte[] readBody(HttpServletRequest request) throws IOException {
//获取请求文本字节长度
int formDataLength = request.getContentLength();
//取得ServletInputStream输入流对象
DataInputStream dataStream = new DataInputStream(request.getInputStream());
byte body[] = new byte[formDataLength];
int totalBytes = 0;
while (totalBytes < formDataLength) {
int bytes = dataStream.read(body, totalBytes, formDataLength);
totalBytes += bytes;
}
return body;
} /**
* 获取文件起始位置
*
* @param request
* @param textBody
* @return
* @throws IOException
*/
private Position getFilePosition(String textBody) throws IOException {
//取得实际上传文件的起始与结束位置
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 new Position(begin, end);
} /**
* 获取文件名
*
* @param requestBody
* @return
*/
private String 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());
return fileName;
} catch (Exception e) {
return "";
}
} /**
* 写文件
*
* @param fileName
* @param body
* @param p
* @throws IOException
*/
private void writeTo(String fileName, byte[] body, Position p) throws IOException {
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();
} }
测试工程:https://github.com/easonjim/5_java_example/tree/master/uploadtest/test1
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:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<div>
<form action="UploadServlet" method="POST" enctype="multipart/form-data">
<table>
<tr>
<td><label for="file1">文件1:</label></td>
<td><input type="file" id="file1" name="file1"></td>
</tr>
<tr>
<td><label for="file2">文件2:</label></td>
<td><input type="file" id="file2" name="file2"></td>
</tr>
<tr>
<td><label for="file3">文件3:</label></td>
<td><input type="file" id="file3" name="file3"></td>
</tr>
<tr>
<td><label for="file3">Text:</label></td>
<td><input type="text" id="text1" name="text1"></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="上传" name="upload"></td>
</tr>
</table>
</form>
</div>
</body>
</html>
Servlet:
提示:使用了servlet3.0的标注免配置功能。
package uploadtest; import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date; 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; /**
* Servlet implementation class UploadServlet
*/
@MultipartConfig
@WebServlet("/UploadServlet")
public class UploadServlet extends HttpServlet {
private static final long serialVersionUID = 1L; /**
* @see HttpServlet#HttpServlet()
*/
public UploadServlet() {
super();
// TODO Auto-generated constructor stub
} /**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
} /**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
this.processRequest(request, response);
} //通过getPart()、getParts()取得上传文件。单文件
/**
* Processes requests for both HTTP
* <code>POST</code> methods.
*
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Part part = request.getPart("file1");//参数就是input标签的name属性,且这个name必须是唯一的
String fileName = getFileName(part);
writeTo(fileName, part);
} //取得上传文件名
private String 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());
return fileName;
} //存储文件
private void writeTo(String fileName, Part part) throws IOException, 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改造如下:
package uploadtest; import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date; 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; /**
* Servlet implementation class UploadServlet
*/
@MultipartConfig(location = "d:\\\\workspace")
@WebServlet("/UploadServlet3")
public class UploadServlet3 extends HttpServlet {
private static final long serialVersionUID = 1L; /**
* @see HttpServlet#HttpServlet()
*/
public UploadServlet3() {
super();
// TODO Auto-generated constructor stub
} /**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
} /**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
this.processRequest(request, response);
} //通过getPart()、getParts()取得上传文件。单文件
/**
* Processes requests for both HTTP
* <code>POST</code> methods.
*
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Part part = request.getPart("file1");//参数就是input标签的name属性,且这个name必须是唯一的
String fileName = getFileName(part);
//将文件写入location指定的目录
part.write(fileName);
} //取得上传文件名
private String 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());
return fileName;
} }
对于@MultipartConfig更多的解释,参考:http://blog.csdn.net/chenqipc/article/details/50551450
测试工程(包含了多文件的实现):https://github.com/easonjim/5_java_example/tree/master/uploadtest/test2
Java中的文件上传(原始Servlet实现)的更多相关文章
- Java中实现文件上传下载的三种解决方案
第一点:Java代码实现文件上传 FormFile file=manform.getFile(); String newfileName = null; String newpathname=null ...
- Java中的文件上传和下载
文件上传原理: 早期的文件上传机制: 在TCP/IP中.最早出现的文件上传机制是FTP.他是将文件由客户端发送到服务器的标准机制. jsp中的文件上传机制: 在jsp编程中不能使用FTP的方法来上传文 ...
- Java中的文件上传2(Commons FileUpload:commons-fileupload.jar)
相比上一篇使用Servlet原始去实现的文件上传(http://www.cnblogs.com/EasonJim/p/6554669.html),使用组件去实现相对来说功能更多,省去了很多需要配置和处 ...
- java中的文件上传下载
java中文件上传下载原理 学习内容 文件上传下载原理 底层代码实现文件上传下载 SmartUpload组件 Struts2实现文件上传下载 富文本编辑器文件上传下载 扩展及延伸 学习本门课程需要掌握 ...
- Java中使用HttpPost上传文件以及HttpGet进行API请求(包含HttpPost上传文件)
Java中使用HttpPost上传文件以及HttpGet进行API请求(包含HttpPost上传文件) 一.HttpPost上传文件 public static String getSuffix(fi ...
- 【Java】JavaWeb文件上传和下载
文件上传和下载在web应用中非常普遍,要在jsp环境中实现文件上传功能是非常容易的,因为网上有许多用java开发的文件上传组件,本文以commons-fileupload组件为例,为jsp应用添加文件 ...
- javaWeb中的文件上传下载
在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用 ...
- javaWeb中,文件上传和下载
在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用 ...
- JavaWeb中的文件上传和下载功能的实现
导入相关支持jar包:commons-fileupload.jar,commons-io.jar 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用Servlet获取上 ...
随机推荐
- Python-S9——Day115-Flask Web框架
01 当日内容概要 1 当日内容概要 1.1 Flask基础: 1.2 Web框架包含的基础组件: 1.2.1 路由.视图函数.模板渲染: 1.3 Flask配置文件: 1.4 Flask的路由系统: ...
- php字符串 函数
strtolower()//字符串转化小写的字母 $str="abcdEfG";$s=strtolower($str); 输出:abcdefg; strtoupper();字符串转 ...
- 用nc+简单bat/vbs脚本+winrar制作迷你远控后门
前言 某大佬某天和我聊起了nc,并且提到了nc正反向shell这个概念. 我对nc之前的了解程度仅局限于:可以侦听TCP/UDP端口,发起对应的连接. 真正的远控还没实践过,所以决定写个小后门试一试. ...
- Python爬虫作业
题目如下: 请分析作业页面(https://edu.cnblogs.com/campus/hbu/Python2018Fall/homework/2420), 爬取已提交作业信息,并生成已提 ...
- [HTTPS]pfx转jks
keytool -importkeystore -srckeystore src.pfx -srcstoretype pkcs12 -destkeystore trg.jks -deststoret ...
- idea中将项目与github关联
© 版权声明:本文为博主原创文章,转载请注明出处 1.在github中创建一个账号:https://github.com/join?source=header-home 2.下载并安装git:http ...
- phpstrom换行的一个小坑
安装phpstrom后汉化会默认不是左边定格换行,而是会智能换行 苦找了许久了,终于知道在哪设置了,跟大家分享一下,希望不要走同样的坑 不勾选即可
- cf 843 D Dynamic Shortest Path [最短路+bfs]
题面: 传送门 思路: 真·动态最短路 但是因为每次只加1 所以可以每一次修改操作的时候使用距离分层的bfs,在O(n)的时间内解决修改 这里要用到一个小技巧: 把每条边(u,v)的边权表示为dis[ ...
- 【ubuntu】配置zsh
1. 修改默认shell为zsh chsh -s /bin/zsh echo $SHELL$ 2. 下载oh-my-zsh wget https://raw.github.com/robbyrusse ...
- Surface机制(SurfaceFlinger服务)
Android系统Surface机制的SurfaceFlinger服务的线程模型分析http://blog.csdn.net/luoshengyang/article/details/8062945