第10章 文件的上传和下载
10.1 了解文件上传原理
10.1.1 掌握表单数据的编码方式
- text/plain: 该编码方式指定了以文本形式发生请求
- application/x-www-form-urlencoded:这是默认的编码方式,该编码方式只处理表单域的value属性值,并将表单的值按照URL编码的方式处理。
- multipart/form-date:该编码方式以二进制的方式来处理表单中的数据,这种编码方式会把文件域所指定的文件内容也封装在请求中。
10.1.2 掌握application/x-www.form-urlencoded编码方式
- upload_app.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
Insert title here
- OutDataServlet.java
public class OutDataServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
InputStream is = request.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String requestData="";
String s="";
while((s=br.readLine())!=null){
requestData+=s;
}
//String tempStr=URLDecoder.decode(requestData,"UTF-8");
out.println(requestData);
}
}
- web.xml中servlet配置
OutDataServlet
com.hwp.OutDataServlet
OutDataServlet
/servlet/OutDataServlet
10.1.3 掌握multipart/form-data编码方式
- upload_multipart.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
Insert title here
- OutMultipartDataServlet.java
public class OutMultipartDataServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
InputStream is = request.getInputStream();
InputStreamReader isr = new InputStreamReader(is, "UTF-8");
BufferedReader br = new BufferedReader(isr);
String requestData="";
String s="";
Enumeration headers = request.getHeaderNames();
out.println("请求消息头
");
while(headers.hasMoreElements()){
String header=headers.nextElement();
out.println(header+":"+request.getHeader(header)+"
");
}
out.println("");
out.println("请求消息正文
");
while((s=br.readLine())!=null){
requestData=requestData+s+"
";
}
out.println(requestData);
}
}
- web.xml
OutMultipartDataServlet
com.hwp.OutMultipartDataServlet
OutMultipartDataServlet
/servlet/OutMultipartDataServlet
浏览器地址输入如下URL
http://localhost:8080/Struts2_upload1/upload_multipart.jsp
选择一个txt文件,输入框,填写中文请求参数
,提交后
请求消息头
host:localhost:8080
connection:keep-alive
content-length:76
cache-control:max-age=0
origin:http://localhost:8080
upgrade-insecure-requests:1
content-type:application/x-www-form-urlencoded
user-agent:Opera/9.80 (Windows NT 6.0) Presto/2.12.388 Version/12.14
sec-fetch-mode:navigate
sec-fetch-user:?1
accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3
sec-fetch-site:same-origin
referer:http://localhost:8080/Struts2_upload1/upload_multipart.jsp
accept-encoding:gzip, deflate, br
accept-language:zh-CN,zh;q=0.9
cookie:JSESSIONID=A7BA0B2EE035C9B42C4624D877D2BAD8; SL_G_WPT_TO=zh; SL_GWPT_Show_Hide_tmp=undefined; SL_wptGlobTipTmp=undefined
请求消息正文
file=mima.txt&request=%E4%B8%AD%E6%96%87%E8%AF%B7%E6%B1%82%E5%8F%82%E6%95%B0
10.2 使用Commons-FileUoload组件
10.2.1 下载和安装Commons-FileUoload组件
commons-fileupload-1.2.2.jar
commons-io-2.0.1.jar
10.2.2 实例:上传单个文件
- upload_servlet.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
Insert title here
- UploadServlet.java
public class UploadServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
try {
//设置处理请求参数的编码格式
request.setCharacterEncoding("UTF-8");
//设置ContentType
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
//建立FileItemFactory对象和ServletFileUpload对象
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
//分析请求,并得到上传文件的FileItem对象
List items = upload.parseRequest(request);
//从web.xml文件中的参数中得到上传文件所在服务端的路径
String uploadPath = getInitParameter("path");
//上传文件保存到服务器的文件名
String fileName="";
//当前上传文件的InputStream对象
InputStream is=null;
//循环处理上传文件
for(FileItem item:items){
//处理普通的表单域,获取文件名
if(item.isFormField())
{
if(item.getFieldName().equals("filename")){
//如果新文件不为空,将其保存在filename中
if(!item.getString().equals("")){
fileName=item.getString();
}
}
}
//处理上传文件,获取文件的输入流
else if(item.getName()!=null&&!item.getName().isEmpty()){
fileName=item.getName().substring(item.getName().lastIndexOf("\\")+1);
is=item.getInputStream();
}
}
fileName=uploadPath+fileName;
if(new File(fileName).exists()){
out.println("该文件已存在,请为文件指定一个新的文件名!");
}else if(!fileName.equals("")){
FileOutputStream fos = new FileOutputStream(fileName);
byte [] buffer=new byte[8192];
int count=0;
while((count=is.read(buffer))>0){
fos.write(buffer,0,count);
}
fos.close();
is.close();
out.println("文件上传成功!");
}
} catch (Exception e) {
// TODO: handle exception
}
}
}
- web.xml
UploadServlet
com.hwp.UploadServlet
path
d:\test\
UploadServlet
/servlet/UploadServlet
浏览器输入
http://localhost:8080/Struts2_upload1/upload_servlet.jsp
如果文件不存在,点击上传会输出文件上传成功
。如果文件存在,点击上传会输出该文件已存在,请为文件指定一个新的文件名!
。
Commons-FileUoload组件在处理上传文件的过程中,将每一个表单封装在一个FileItem对象中。这些表单域包括普通的表单域和文件域。FileItem接口还定义了如下几个方法来获得表单域中的信息。
- getFieldName:用于获取表单域的name属性值
- getString:用于获得表单value值,其中方法的参数用于设置value属性值的编码格式。
- getName:仅对文件域有效,用于返回上传文件的文件名。
- getContentType:仅对文件域有效,用于返回上传文件的文件类型。
- get:仅对文件域有效,用于返回上传文件的字节数组。
- getInputStream:仅对文件域有效,用于返回上传文件对应的输入流。
10.2.3 实例:上传任意多个文件
略
10.3 实例:通过Struts2实现文件上传
10.3.1 了解Struts2对上传文件的支持
Struts2支持3种上传文件组件,分别是jakarta(Commons-FileUpload)、cos和pell
需要在struts.properties文件中配置
#指定使用COS文件上传解析器
#struts.multipart.parser=cos
#指定使用pell文件上传解析器
#struts.multipart.parser=pell
#Struts2默认的文件上传解析器,实际上就是Commons-FileUpload上传组件
struts.mulipart.parser=jakarta
#设置保存上传文件的临时目录
struts.multipart.savaDir=
#设置上传文件总大小(以字节为单位),默认是2M
struts.mulipart.maxSize=2097152
10.3.2 编写上传文件的JSP页面
- upload_struts.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
上传单个文件
10.3.3 编写上传文件的Action类
- UploadAction.java,其中upload和filename要从表单中获取的,属性值要对应上,uploadPath从struts.xml中获取
public class UploadAction extends ActionSupport {
private File upload;
private String uploadContentType;
private String uploadFileName;
private String filename;
private String uploadPath;
private String result;
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
public File getUpload() {
return upload;
}
public void setUpload(File upload) {
this.upload = upload;
}
public String getUploadContentType() {
return uploadContentType;
}
public void setUploadContentType(String uploadContentType) {
this.uploadContentType = uploadContentType;
}
public String getUploadFileName() {
return uploadFileName;
}
public void setUploadFileName(String uploadFileName) {
this.uploadFileName = uploadFileName;
}
public String getUploadPath() {
return uploadPath;
}
public void setUploadPath(String uploadPath) {
this.uploadPath = uploadPath;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
@Override
public String execute() throws Exception {
String fn="";
if(filename.equals("")){
fn=uploadPath+uploadFileName;
}else{
fn=uploadPath+filename;
}
if(new File(fn).exists()){
result="该文件已经存在,请为文件指定一个新的文件名";
}else{
FileOutputStream fos=new FileOutputStream(fn);
InputStream is = new FileInputStream(upload);
byte [] buffer=new byte [8*1024];
int count=0;
while((count=is.read(buffer))>0){
fos.write(buffer, 0, count);
}
fos.close();
is.close();
result="文件上传成功";
}
return "result";
}
}
10.3.4 配置上传文件的Action类
- struts.xml
/result.jsp
D:\test\
*result.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
结果消息
浏览器输入
http://localhost:8080/Struts2_upload1/upload_struts.jsp
如果D:\test目录下没有同名的文件,并且上传文件的字节数小于2M,文件才能上传成功。
10.3.5 手工过滤上传文件的类型
略
10.3.6 用fileUpload拦截器过滤上传文件的类型
- allowedTypes: 该参数指定了允许上传的文件类型。
- maximumSize:该参数指定允许上传的文件大小(以字节为单位)。
- struts.xml
image/jpeg,image/png,image/gif
4096
/result.jsp
/uploadstruts.jsp
D:\test\
- error.properties(和UploadAction.java在同一个目录)
#定义上传文件类型错误的信息
struts.message.error.type.not.allowed=不允许上传该类型的文件!
#定义上传文件大小的错误信息
struts.message.error.file.too.laarge=上传的文件太大
- 显示错误的页面,uploadstruts.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
Insert title here
10.4 实例:通过Struts2实现上传多个文件
10.4.1 实例:用数组上传固定数目的文件
略
10.4.2 实例:用List上传任意数目的文件
略
10.5 学习文件下载
10.5.1 解决下载文件的中文问题
略
10.5.2 通过stream结果下载文件
stream结果是Struts2内建的结果之一。如果要使用stream结果,需要为其设置如下4个参数。
- contentType:该参数指定被下载文件的文龙类型,也就是HTTP响应消息头的Content-Type字段。
- inputName:该参数指定被下载文件的InputStream对象的Action属性名。
- contentDisposition:该参数指定被下载文件的文件名。也就是浏览器的下载对话框中显示的那个文件名。
- bufferSize:该参数指定下载文件时所使用的的缓冲区的大小。
10.5.3 控制下载文件的授权
由于下载文件需要先通过Action,因此可以再下载文件之前检查当前用户是否有权限下载该文件。如果用户未登录,或者登录用户没有下载权限下载该文件,则execute方法返回login,否则返回success。
实例代码
public class AuthorizationDownloadAction extends DownloadAction{
public String execute () throws Exception{
ActionContext ctx=ActionContext.getContext();
Map session=ctx.getSession();
String username=(String)session.get("username");
if(username!=null&&username.equals("mike)){
return SUCCESS;
}else{
return LOGIN;
}
}
}