servlet普通方法实现文件上传
具体不详细介绍,有兴趣的可以研究一下,以下文章的第一种方法就是普通的方法实现的。
Servlet实现文件上传的几种方法
servlet引入jar包方式实现文件上传
当使用了enctype=”multipart/form-data”之后,普通输入框的内容,将无法使用getParameter获取
commons-fileupload-1.2.2.jar和commons-io-2.0.1.jar
由于项目环境是struts2,在使用servlet上传时会被struts2拦截,所以修改web.xml中的配置/为.action,不然获取的文件列表为空,并且加上jsp的过滤,不然jsp页面的struts2标签可能报错
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>*.action</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
servlet3 API 实现文件上传
注意:使用request.getParts()方法必须给servlet添加注解@MultipartConfig,否则虽然不会抛出异常,但是获取不到数据。
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
此时,文件上传不报错,但是request.getParts()无法获取数据,修改为
<web-app version="3.1"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_1.xsd">
即可
servlet实现的文件上传下载的代码
file.jsp代码
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>文件上传下载</title>
</head>
<body>
<form action="UploadServlet" method="post" enctype="multipart/form-data">
<input type="file" name="filename">
<input type="submit" value="上传">
</form>
<br>
上传文件.txt<a href="DownServlet?fileName=上传文件.txt">下载 </a><br>
</body>
</html>
UploadFile.java代码:
/**
*
*/
package servlet;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.Collection;
import java.util.List;
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;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.IOUtils;
/**
* @author Administrator
*
*/
@WebServlet(name = "UploadServlet", urlPatterns = "/UploadServlet")
@MultipartConfig // 标识Servlet支持文件上传
public class UploadFile extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
// 借助commons-fileupload-1.2.2.jar和commons-io-2.0.1.jar来实现文件上传功能
//upload(request, response);
// servlet3的接口实现的
uploadS3(request, response);
}
/**
* @param request
* @param response
*/
private void uploadS3(HttpServletRequest request, HttpServletResponse response) {
try {
boolean saveboolean = false;
// 存储路径
String savePath = request.getServletContext().getRealPath("/upload");
// 获取上传的文件集合
Collection<Part> parts = request.getParts();
System.out.println(parts);
// 上传单个文件
if (parts.size() == 1) {
// Servlet3.0将multipart/form-data的POST请求封装成Part,通过Part对上传的文件进行操作。
// Part part = parts[0];//从上传的文件集合中获取Part对象
Part part = request.getPart("filename");// 通过表单file控件(<input
// type="file"
// name="file">)的名字直接获取Part对象
// Servlet3没有提供直接获取文件名的方法,需要从请求头中解析出来
// 获取请求头,请求头的格式:form-data; name="file";
// filename="snmp4j--api.zip"
String header = part.getHeader("content-disposition");
// 获取文件名
String fileName = getFileName(header);
// 把文件写到指定路径
part.write(savePath + File.separator + fileName);
saveboolean = true;
System.out.println(savePath + File.separator + fileName);
} else {
// 一次性上传多个文件
for (Part part : parts) {// 循环处理上传的文件
// 获取请求头,请求头的格式:form-data; name="file";
// filename="snmp4j--api.zip"
String header = part.getHeader("content-disposition");
// 获取文件名
String fileName = getFileName(header);
// 把文件写到指定路径
part.write(savePath + File.separator + fileName);
saveboolean = saveboolean&true;
}
}
PrintWriter out;
out = response.getWriter();
if (saveboolean) {
out.println("上传成功");
} else {
out.println("上传失败");
}
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 根据请求头解析出文件名 请求头的格式:火狐和google浏览器下:form-data; name="file";
* filename="snmp4j--api.zip" IE浏览器下:form-data; name="file";
* filename="E:\snmp4j--api.zip"
*
* @param header
* 请求头
* @return 文件名
*/
public String getFileName(String header) {
/**
* String[] tempArr1 =
* header.split(";");代码执行完之后,在不同的浏览器下,tempArr1数组里面的内容稍有区别
* 火狐或者google浏览器下:tempArr1={form-data,name="file",filename="snmp4j--api.zip"}
* IE浏览器下:tempArr1={form-data,name="file",filename="E:\snmp4j--api.zip"}
*/
String[] tempArr1 = header.split(";");
/**
* 火狐或者google浏览器下:tempArr2={filename,"snmp4j--api.zip"}
* IE浏览器下:tempArr2={filename,"E:\snmp4j--api.zip"}
*/
String[] tempArr2 = tempArr1[2].split("=");
// 获取文件名,兼容各种浏览器的写法
String fileName = tempArr2[1].substring(tempArr2[1].lastIndexOf("\\") + 1).replaceAll("\"", "");
return fileName;
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
doGet(req, resp);
}
/**
* @param request
* @param response
*/
private void upload(HttpServletRequest request, HttpServletResponse response) {
try {
request.setCharacterEncoding("utf-8");
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
DiskFileItemFactory factory = new DiskFileItemFactory();// 1.创建DiskFileItemFactory工厂类
ServletFileUpload upload = new ServletFileUpload(factory);// 2.创建解析类,用于解析resquest
try {
List<FileItem> list = upload.parseRequest(request);// 3.解析内容,获取一个list,数据都存储在list中
System.out.println(list);
for (FileItem item : list) {
if (item.isFormField()) {// 判断是否是普通的表单内容
System.out.println(item.getFieldName());// 获取的是表单中name属性的值
System.out.println(item.getString());// 获取的是对应的表单的值
} else {// 为假,说明是上传项
// 获取流,进行处理
InputStream ism = item.getInputStream();
// System.out.println(" item.getString():" +
// item.getString("gbk"));
String path = getServletContext().getRealPath("\\upload\\");
File dirfile = new File(path);
if (!dirfile.exists()) {
dirfile.mkdirs();
}
String filename = item.getName();// 这里getName可以获取文件名
System.out.println(filename);
File file = new File(path + "\\" + filename);
System.out.println(file.getPath());
file.createNewFile();// 这里不做文件存在性和名字重复判断
OutputStream fos = new FileOutputStream(file);
// 这里直接借助commons.io来做io对接,不然需要做流的读取和写入
IOUtils.copy(ism, fos);// 把输入流的数据拷贝到输出
IOUtils.closeQuietly(ism);
IOUtils.closeQuietly(fos);
}
}
} catch (FileUploadException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
// 判断编码,待定的操作
public String parseCode(String sb) {
try {
String iso8859 = new String(sb.toString().getBytes("iso8859-1"));
String gbk = new String(sb.toString().getBytes("gbk"));
String utf8 = new String(sb.toString().getBytes("utf-8"));
if (iso8859.equals(sb.toString())) {
return "ios8859";
} else if (gbk.equals(sb.toString())) {
return "gbk";
} else if (utf8.equals(sb.toString())) {
return "utf-8";
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return "utf-8";
}
}
DownFile.java代码:
/**
*
*/
package servlet;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import sun.misc.BASE64Encoder;
/**
* @author Administrator
*
*/
@WebServlet(name = "DownServlet", urlPatterns = "/DownServlet")
public class DownFile extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 1531004603279372230L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
downStream(request, response);
}
/**
*
*/
private void downStream(HttpServletRequest request, HttpServletResponse response) {
try {
// path是指欲下载的文件的路径。
String fileName = request.getParameter("fileName");
String path = request.getServletContext().getRealPath("/upload") + File.separator + fileName;
File file = new File(path);
// 以流的形式下载文件。
InputStream fis = new BufferedInputStream(new FileInputStream(path));
byte[] buffer = new byte[fis.available()];
fis.read(buffer);
fis.close();
// 清空response
response.reset();
// 文件名处理
// 根据不同浏览器进行不同的编码
// 获得请求头中的User-Agent
String agent = request.getHeader("User-Agent");
String filenameEncoder = "";
if (agent.contains("MSIE")) {
// IE浏览器
filenameEncoder = URLEncoder.encode(fileName, "utf-8");
filenameEncoder = filenameEncoder.replace("+", " ");
} else if (agent.contains("Firefox")) {
// 火狐浏览器
BASE64Encoder base64Encoder = new BASE64Encoder();
filenameEncoder = "=?utf-8?B?" + base64Encoder.encode(fileName.getBytes("utf-8")) + "?=";
} else {
// 其它浏览器
filenameEncoder = URLEncoder.encode(fileName, "utf-8");
}
// 设置response的Header
response.addHeader("Content-Disposition", "attachment;filename=" + filenameEncoder);
response.addHeader("Content-Length", "" + file.length());
OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
response.setContentType("application/octet-stream");
toClient.write(buffer);
toClient.flush();
toClient.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
doGet(request, response);
}
}
struts2方式的文件上传下载
struts2底层也使用了commons-fileupload-1.2.2.jar和commons-io-2.0.1.jar,所以struts2的11个jar包中就包含这两个包
文件上传
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<s:form action="uploads.action" method="post" theme="simple" enctype="multipart/form-data">
输入帐号:<s:textfield name="uid"/><br>
选择文件:<s:file name="headFile"/><br>
选择文件:<s:file name="headFile"/><br>
<s:submit value="提交"/>
<s:fielderror/>
</s:form>
请下载文件:<a href="downLoad.action?downPath=上传文件.txt">文件</a><br>
请下载图片:<a href="downLoad.action?downPath=飞机地球.jpg">图片</a><br>
</body>
</html>
单个文件上传
/**
*
*/
package action;
import java.io.File;
import org.apache.commons.io.FileUtils;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.InterceptorRef;
import org.apache.struts2.convention.annotation.InterceptorRefs;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.Results;
import com.opensymphony.xwork2.ActionSupport;
import lombok.Getter;
import lombok.Setter;
/**
* @author Administrator
*
*/
@Namespace("/")
@Action(value = "upload")
//当文件过大时会返回input结果,如果没有定义这个结果会报错
@Results({ @Result(name = "input", location = "/fileaction.jsp"),@Result(name = "error", location = "/fileaction.jsp"), @Result(name = "success", location = "/upsuccess.jsp") })
@InterceptorRefs({
@InterceptorRef(value = "fileUpload", params = { "maximumSize", "65536", "allowedTypes",
"image/x-png,image/bmp,image/gif,image/jpeg,image/jpg,text/plain" }),
@InterceptorRef(value = "defaultStack") })
public class FileAction extends ActionSupport {
@Getter
@Setter
private String uid; // 封装帐号(uid)请求参数属性
@Getter
@Setter
private File headFile; // 封装上传文件域属性
@Getter
@Setter
private String headFileContentType; // 封装上传文件类型的属性
@Getter
@Setter
private String headFileFileName; // 封装上传文件名字
@Override
public String execute() {
try {
System.out.println("上传文件属性为:" + headFileContentType + "\n上传文件名字为:" + headFileFileName);
// 上传文件的保存位置在“/upload”,该位置在tomcat服务器的“webapps”之中
String realpath = ServletActionContext.getServletContext().getRealPath("/upload");
// 声明文件目录image,如果文件名不存在就建一个呗~
File file = new File(realpath);
if (!file.exists()) {
file.mkdirs();
}
// 实现文件上传,也就是做了一个方法调用~
FileUtils.copyFile(headFile, new File(file, headFileFileName));
return SUCCESS;
} catch (Exception e) {
e.printStackTrace();
return ERROR;
}
}
}
多个文件上传
/**
*
*/
package action;
import java.io.File;
import org.apache.commons.io.FileUtils;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.InterceptorRef;
import org.apache.struts2.convention.annotation.InterceptorRefs;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.Results;
import com.opensymphony.xwork2.ActionSupport;
import lombok.Getter;
import lombok.Setter;
/**
* @author Administrator
*
*/
@Namespace("/")
@Action(value = "uploads")
//当文件过大时会返回input结果,如果没有定义这个结果会报错
@Results({ @Result(name = "input", location = "/fileaction.jsp"),@Result(name = "error", location = "/fileaction.jsp"), @Result(name = "success", location = "/upsuccess.jsp") })
@InterceptorRefs({
@InterceptorRef(value = "fileUpload", params = { "maximumSize", "655360000", "allowedTypes",
"image/x-png,image/bmp,image/gif,image/jpeg,image/jpg,text/plain" }),
@InterceptorRef(value = "defaultStack") })
public class FilesAction extends ActionSupport {
@Getter
@Setter
private String uid; // 封装帐号(uid)请求参数属性
@Getter
@Setter
private File[] headFile; // 封装上传文件域属性
@Getter
@Setter
private String[] headFileContentType; // 封装上传文件类型的属性
@Getter
@Setter
private String[] headFileFileName; // 封装上传文件名字
@Override
public String execute() {
try {
System.out.println("上传文件属性为:" + headFileContentType + "\n上传文件名字为:" + headFileFileName);
// 上传文件的保存位置在“/upload”,该位置在tomcat服务器的“webapps”之中
String realpath = ServletActionContext.getServletContext().getRealPath("/upload");
// 声明文件目录image,如果文件名不存在就建一个呗~
File file = new File(realpath);
if (!file.exists()) {
file.mkdirs();
}
// 实现多文件下载代码如下:
for(int i = 0; i < headFile.length; i++){
File uploadFile = headFile[i];
FileUtils.copyFile(uploadFile,new File(file,headFileFileName[i]));
}
return SUCCESS;
} catch (Exception e) {
e.printStackTrace();
return ERROR;
}
}
}
在文件上传的特性中,一般有三个属性
1、File xxxx; // 封装上传文件域属性
2、String xxxxContentType //封装上传文件的类型
3、String xxxxFileName //封装上传文件的名字
当文件只有一个时是这样的,当多个文件上传时,只需将其都变为数组即可
1、File[] xxxx; // 封装上传文件域属性
2、String[] xxxxContentType //封装上传文件的类型
3、String[] xxxxFileName //封装上传文件的名字
然后一个文件上传改为多个
FileUtils.copyFile(headFile, new File(file, headFileFileName));
// 实现多文件下载代码如下:
for(int i = 0; i < headFile.length; i++){
File uploadFile = headFile[i];
FileUtils.copyFile(uploadFile,new File(file,headFileFileName[i]));
}
文件下载
/**
*
*/
package action;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.Results;
import com.opensymphony.xwork2.ActionSupport;
import lombok.Getter;
import lombok.Setter;
/**
* @author Administrator
*
*/
/*@Namespace("/")
@Action(value = "downLoad")
//当文件过大时会返回input结果,如果没有定义这个结果会报错
@Result(name = "download", type = "stream",
params = {
"contentType", "application/octet-stream",
"inputName","inputStream",
"contentDisposition", "attachment;filename=\"${filename}\"",
"bufferSize", "4096"
})*/
public class DownFileAction extends ActionSupport
{
@Getter
@Setter
private String downPath; // 下载文件的名字
@Getter
@Setter
private String contentType; // 保存文件类型
@Getter
private String filename; // 保存时的文件名
/*
*下载用的Action返回一个InputString实例,该方法对应Action配置
*里面的result的inputName参数,值为inputString
*
*/
public InputStream getInputStream() throws UnsupportedEncodingException{
//转换格式,否则中文不能显示。
this.filename=new String(filename.getBytes(),"iso-8859-1");
InputStream inputStream = ServletActionContext.getServletContext().getResourceAsStream(downPath);
return inputStream;
}
public String execute() throws IOException{
// 下载保存时的文件名和被下载的文件名一样
filename = downPath;
// 下载的文件路径,请在webapps目录下创建images
downPath = "upload/" + downPath;
// 保存文件的类型
System.out.println(downPath);
// 保存文件的类型
contentType = "application/octet-stream";
return SUCCESS;
}
/**
* @param filename the filename to set
* @throws UnsupportedEncodingException
*/
public void setFilename(String filename) throws UnsupportedEncodingException {
this.filename = new String(filename.getBytes("iso-8859-1"),"utf-8");
}
}
struts.xml
<action name="downLoad" class="action.DownFileAction">
<!--结果类型为String-->
<result type="stream">
<param name="contentType">${contentType}</param>
<!--默认就是inputStream,它将会指示StreamResult通过
inputName属性值的getter和setter方法,如这里就是
getInputStream()来获取下载文件的内容,意味着Action
要有这个方法
-->
<param name="inputName">inputStream</param>
<!--默认为inline(在线打开),设置为attachment将会告诉浏览器下载
该文件,filename指定下载文件时的文件名,若未指定将会以浏览器
页面名作为文件名,如:以download.action作为文件名
-->
<param name="contentDisposition">attachment;filename=${filename}</param>
<!--指定下载文件的缓冲大小-->
<param name="bufferSize">4096</param>
</result>
</action>
注意在action中有两个与编码相关的代码,我的项目环境是UTF-8编码,必须要这样写,不然要下载的文件中文名是空白
注意到inputName这个参数,获取的是action中getInputStream函数的返回值,也就是文件的流,当我们不存在这个方法时会提示错误
可以看到struts2的文件上传下载比普通的方法要简单
参考
servlet使用common-fileupload实现上传下载