从原始的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实现)的更多相关文章

  1. Java中实现文件上传下载的三种解决方案

    第一点:Java代码实现文件上传 FormFile file=manform.getFile(); String newfileName = null; String newpathname=null ...

  2. Java中的文件上传和下载

    文件上传原理: 早期的文件上传机制: 在TCP/IP中.最早出现的文件上传机制是FTP.他是将文件由客户端发送到服务器的标准机制. jsp中的文件上传机制: 在jsp编程中不能使用FTP的方法来上传文 ...

  3. Java中的文件上传2(Commons FileUpload:commons-fileupload.jar)

    相比上一篇使用Servlet原始去实现的文件上传(http://www.cnblogs.com/EasonJim/p/6554669.html),使用组件去实现相对来说功能更多,省去了很多需要配置和处 ...

  4. java中的文件上传下载

    java中文件上传下载原理 学习内容 文件上传下载原理 底层代码实现文件上传下载 SmartUpload组件 Struts2实现文件上传下载 富文本编辑器文件上传下载 扩展及延伸 学习本门课程需要掌握 ...

  5. Java中使用HttpPost上传文件以及HttpGet进行API请求(包含HttpPost上传文件)

    Java中使用HttpPost上传文件以及HttpGet进行API请求(包含HttpPost上传文件) 一.HttpPost上传文件 public static String getSuffix(fi ...

  6. 【Java】JavaWeb文件上传和下载

    文件上传和下载在web应用中非常普遍,要在jsp环境中实现文件上传功能是非常容易的,因为网上有许多用java开发的文件上传组件,本文以commons-fileupload组件为例,为jsp应用添加文件 ...

  7. javaWeb中的文件上传下载

    在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用 ...

  8. javaWeb中,文件上传和下载

    在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用 ...

  9. JavaWeb中的文件上传和下载功能的实现

    导入相关支持jar包:commons-fileupload.jar,commons-io.jar 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用Servlet获取上 ...

随机推荐

  1. .net core 项目加载提示项目文件不完整缺少预期导入的解决办法

    今天把在远端的仓库的代码在另一台电脑上拷贝下来,电脑上.net core 环境也已经安装了,但是发现有几个项目没有加载成功,然后重新加载项目,vs2017却提示 项目文件不完整,缺少预期导入 查看错误 ...

  2. 53、listview、expandableListview如何选中时保持高亮?

    一.listView被选中后保持高亮 70down voteaccepted To hold the color of listview item when you press it, include ...

  3. Appium的三种等待时间设置方法

    #三种appium设置等待时间的方法 #作者:Mr.Dantes  #参考了网上的资料,然后进行了梳理   #第一种 sleep(): 设置固定休眠时间. python 的 time 包提供了休眠方法 ...

  4. 基于web自动化测试框架的设计与开发(本科论文word)

  5. Visual C++ 经典的人脸识别算法源代码

    说明:VC++ 经典的人脸识别算法实例,提供人脸五官定位具体算法及两种实现流程. 点击下载

  6. Leetcode 652.寻找重复的子树

    寻找重复的子树 给定一棵二叉树,返回所有重复的子树.对于同一类的重复子树,你只需要返回其中任意一棵的根结点即可. 两棵树重复是指它们具有相同的结构以及相同的结点值. 下面是两个重复的子树: 因此,你需 ...

  7. Leetcode 640.求解方程

    求解方程 求解一个给定的方程,将x以字符串"x=#value"的形式返回.该方程仅包含'+',' - '操作,变量 x 和其对应系数. 如果方程没有解,请返回"No so ...

  8. Python脚本获取Linux系统信息

    # -*- coding:utf-8 -*- import os import subprocess import re import hashlib #对字典取子集 def sub_dict(for ...

  9. webpack & async await

    webpack & async await ES 7 // async function f() { // return 1; // } const f = async () => { ...

  10. BZOJ3309 DZY Loves Math 【莫比乌斯反演】

    题目 对于正整数n,定义f(n)为n所含质因子的最大幂指数.例如f(1960)=f(2^3 * 5^1 * 7^2)=3, f(10007)=1, f(1)=0. 给定正整数a,b,求sigma(si ...