java struts2入门学习---文件下载的二种方式
一.关于文件下载:
文件下载的核心思想即是将文件从一个地方拷贝到另一个地方.
1.传统方式:
在Action中加入大量servlet api 操作.优点是好理解,缺点是耦合度高。
2.stream方式:
使用struts2中的stream拦截器进行操作
二.实例:
我这里用的是maven,贴出pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.amos</groupId>
<artifactId>struts2_learn</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>struts2_learn Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
<version>2.3.16</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.1.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
</dependencies>
<build>
<finalName>struts2_learn</finalName>
</build>
</project>
1.使用传统方式实现文件下载:
DownloadAction.java
package download; import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;
/**
* @ClassName: DownloadAction
* @Description: 文件下载
* @author: amosli
* @email:amosli@infomorrow.com
* @date Feb 13, 2014 1:22:23 AM
*/
public class DownloadAction extends ActionSupport {
private static final long serialVersionUID = -5609061774548242181L;
private String fileName;//文件名称
public void setFileName(String fileName) {
if (ServletActionContext.getRequest().getMethod().equals("GET")) {
try {
byte[] bytes = fileName.getBytes("ISO8859-1");//将get方式提交的中文进行处理,即将编码由ISO8859-1转为utf-8
fileName = new String(bytes, "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
this.fileName = fileName;
} // 下载
public String execute() throws Exception {
// 1.传统下载方式
// 取得HttpServletResponse对象
HttpServletResponse response = ServletActionContext.getResponse();
// 取得ServletContext对象
ServletContext context = ServletActionContext.getServletContext();
// 通知浏览器以下载方式打开文件
response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "utf-8"));
// 取得需要下载文件的根目录
String realPath = context.getRealPath("/WEB-INF/download");
// 构造子节输入流
InputStream is = new FileInputStream(realPath + "/" + fileName);
// 构造子节输出流
OutputStream os = response.getOutputStream();
byte[] b = new byte[1024];
int len = 0;
while ((len = is.read(b)) > 0) {
os.write(b, 0, len);
}
is.close();
os.close();
return SUCCESS;
}
}
download.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri='http://java.sun.com/jsp/jstl/core' prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
英文需要编码
<a href="/struts2_learn/DownloadAction?fileName=building.jpg"
style="text-decoration: none">
building.jpg
</a> <hr>
<%-- <c:url var="myURL" value="/DownloadAction">
<c:param name="fileName" value="建筑.jpg" />
</c:url>
<a href="${myURL}" style="text-decoration: none"> 建筑.jpg </a> --%>
</body>
</html>
download_struts.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<package name="download" extends="struts-default">
<action name="DownloadAction" class="download.DownloadAction" method="execute">
</action>
</package>
</struts>
struts.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd"> <struts>
<!--<include file="config/upload.xml"></include> -->
<!-- 加载其他配置文件 -->
<!-- <include file="config/upload-interceptor.xml"></include> -->
<!-- 加载属性文件-国际化 -->
<!-- <constant name="struts.custom.i18n.resources" value="message"></constant> --> <!-- 结果集 -->
<!-- <include file="config/result_struts.xml"></include> -->
<!-- 类型转换 -->
<!-- <include file="config/type_struts.xml"></include> -->
<!-- 文件下载 -->
<include file="config/download_struts.xml"></include>
</struts>
效果如下图所示,点击building.jpg即可开始下载:

代码运行顺序:
首先,项目启动,加载struts.xml--->download_struts.xml-->将对应的DownloadAction加载.
其次,用户访问download.jsp页面,点击超链接,即开始调用DownloadAction进行下载.
核心程序即为DownloadAction.java,将要下载的文件写入到输入流,FileInputStream,然后再将文件从输入流写入到输出流,即将文件从一个地方拷贝到另一个地方.HttpServletResponse,将文件回写给浏览器,以达到下载文件的目的.
最后,文件成功下载,文件被拷贝到指定的地方.
这里要注意的是如果是GET请求方式,那么要注意中文乱码的问题,这里涉及到转码的问题,要做一个判断,详情可参考上面的代码.
2.使用stream方式进行文件下载:
DownloadStreamAction.java
package download;
import java.io.InputStream;
import java.net.URLEncoder;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;
/**
* @ClassName: DownloadStreamAction
* @Description: 现代下载方式
* @author: amosli
* @email:amosli@infomorrow.com
* @date Feb 13, 2014 12:35:26 AM
*/
public class DownloadStreamAction extends ActionSupport {
private static final long serialVersionUID = -2747191035343710583L;
private String fileName;
public void setFileName(String fileName) throws Exception {
if(ServletActionContext.getRequest().getMethod().equals("GET")){
byte[] bytes = fileName.getBytes("ISO8859-1");
fileName=new String(bytes,"utf-8");
}
this.fileName = fileName;
}
public String getFileName() throws Exception {
return URLEncoder.encode(fileName, "utf-8");
}
public InputStream getImageStream() throws Exception {
InputStream inputStream = ServletActionContext.getServletContext().getResourceAsStream("/WEB-INF/download/"+fileName);
return inputStream;
}
}
download_struts.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<!-- <package name="download" extends="struts-default">
<action name="DownloadAction" class="download.DownloadAction" method="execute">
</action>
</package> -->
<package name="download" extends="struts-default">
<action name="DownloadAction" class="download.DownloadStreamAction" method="execute">
<!-- 以stream二进制流的方式打开 -->
<result name="success" type="stream">
<!-- 指明文件的下载类型 -->
<param name="contentType">image/jpeg</param>
<!-- 指明如果取得需要下载文件的InputStream输入流 -->
<param name="inputName">imageStream</param>
<!-- 指明让浏览器以下载框的方式打开 -->
<param name="contentDisposition">attachment;filename="building.jpg"</param>
<!--<param name="contentDisposition">attachment;filename=${fileName}</param>-->
<!-- 指明下载文件时的字符数组byte[]大小 -->
<param name="bufferSize">1024</param>
</result>
</action>
</package>
</struts>
这里如果仅仅看DownloadStreamAction,会发现代码简洁明了,少了很多,再看download_struts.xml,会发现之前我们自己做的事,都被struts代替了,比如字符数组的大小,这里以参数配置的形式出现,方便了许多.
注意:imageStream要和DownloadStreamAction中的getImageStream相对应,不可写错.
关于其具体实现可以查看org.apache.struts2.dispatcher.StreamResult源码,其对应参数,看过源码后就会发现其实下载和传统方式差不多,就是将其优化了不少.
3.实现过程中出现的问题
HTTP Status 500 - The absolute uri: http://java.sun.com/jsp/jstl/core cannot be resolved in either web.xml or the jar files deployed with this application type Exception report message The absolute uri: http://java.sun.com/jsp/jstl/core cannot be resolved in either web.xml or the jar files deployed with this application description The server encountered an internal error that prevented it from fulfilling this request. exception org.apache.jasper.JasperException: The absolute uri: http://java.sun.com/jsp/jstl/core cannot be resolved in either web.xml or the jar files deployed with this application
org.apache.jasper.compiler.DefaultErrorHandler.jspError(DefaultErrorHandler.java:56)
org.apache.jasper.compiler.ErrorDispatcher.dispatch(ErrorDispatcher.java:445)
org.apache.jasper.compiler.ErrorDispatcher.jspError(ErrorDispatcher.java:117)
org.apache.jasper.compiler.TagLibraryInfoImpl.generateTLDLocation(TagLibraryInfoImpl.java:311)
org.apache.jasper.compiler.TagLibraryInfoImpl.<init>(TagLibraryInfoImpl.java:152)
org.apache.jasper.compiler.Parser.parseTaglibDirective(Parser.java:410)
org.apache.jasper.compiler.Parser.parseDirective(Parser.java:475)
org.apache.jasper.compiler.Parser.parseElements(Parser.java:1427)
org.apache.jasper.compiler.Parser.parse(Parser.java:138)
org.apache.jasper.compiler.ParserController.doParse(ParserController.java:242)
org.apache.jasper.compiler.ParserController.parse(ParserController.java:102)
org.apache.jasper.compiler.Compiler.generateJava(Compiler.java:198)
org.apache.jasper.compiler.Compiler.compile(Compiler.java:373)
org.apache.jasper.compiler.Compiler.compile(Compiler.java:353)
org.apache.jasper.compiler.Compiler.compile(Compiler.java:340)
org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:646)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:357)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)
javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:96) note The full stack trace of the root cause is available in the Apache Tomcat/7.0.42 logs.
如上所示异常,困扰了很久,网上答案各异,这里最终解决方案是在pom.xml中填加如下内容:
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.1.2</version>
<scope>provided</scope>
</dependency>
上面的提示是说缺少jstl的jar包,这里也可以手动将jar包引入.
遇到的其它问题基本上只耐心查看提示,基本上都解决了,这里感觉细心真心重要.
本文源码链接:文件下载 https://github.com/amosli/strut2_learn
java struts2入门学习---文件下载的二种方式的更多相关文章
- java struts2入门学习--防止表单重复提交.OGNL语言学习
一.知识点回顾 防止表单重复提交核心思想: 客户端和服务器端和写一个token,比较两个token的值相同,则非重复提交;不同,则是重复提交. 1.getSession三种方式比较: request. ...
- java struts2入门学习---中文验证、对错误消息的分离、结果(result)类型细节配置
一.需求 利用struts2实现中文验证并对错误消息的抽离. 详细需求:用户登录-->不填写用户名-->页面跳转到用户登录页面,提示用户名必填(以英文和中文两种方式提示)-->填写英 ...
- java struts2入门学习实例--将客户端IP地址和访问方式输出到浏览器
实例1:实现客户端IP地址和访问方式输出到浏览器. IpAction.java package com.amos.web.action; import javax.servlet.http.HttpS ...
- java struts2入门学习--OGNL语言基本用法
一.知识点学习 1.struts2中包含以下6种对象,requestMap,sessionMap,applicationMap,paramtersMap,attr,valueStack; 1)requ ...
- java struts2入门学习--基于xml文件的声明式验证
一.知识点总结 后台验证有两种实现方式: 1 手工验证顺序:validateXxx(针对Action中某个业务方法验证)--> validate(针对Action中所有的业务方法验证) 2 声明 ...
- java struts2入门学习--OGNL语言常用符号和常用标签学习
一.OGNL常用符号(接上一篇文章): 1.#号 1)<s:property value="#request.username"/> 作用于struts2的域对象,而不 ...
- java struts2入门学习---自定义类型转换
自定义类型转换器的作用就是将struts无法识别的类型转换成自己所需要的. 比如输入:广东-东莞-虎门,对应的输出时能输出:广东省 东莞市 虎门(镇/区) 这里涉及到的知识点即是将String转换为任 ...
- java struts2入门学习---异常处理和类型转换
一.struts2对异常的处理 1.自定义局部异常: <action> <exception-mapping result="sonException" exce ...
- java struts2入门学习---拦截器学习
一.拦截器,拦截器栈 1.拦截器的作用 拦截器本质上和servlet的过滤器是一样的.在struts2中,拦截器能够对Action前后进行拦截,拦截器是一个可插拨的,你可以选择使用拦截器,也可以卸载拦 ...
随机推荐
- 深度学习哪家强?吴恩达、Udacity和Fast.ai的课程我们替你分析好了
http://www.jianshu.com/p/28f5473c66a3 翻译 | AI科技大本营(rgznai100) 参与 | reason_W 引言 过去2年,我一直积极专注于深度学习领域.我 ...
- 精确率、召回率、F1 值、ROC、AUC 各自的优缺点是什么?
https://www.52ml.net/19370.html 精度.召回.F1点直观理解 图片来自:http://blog.csdn.net/marising/article/details/654 ...
- 与IE的战斗
对第2版的改进,工作量几乎都在UI上,不断的写css,写js,还别说,总体挺愉快的.特别是把360浏览器用顺了之后,烦人的无法刷新问题也不能困扰我了,改了js或者css文件的话,只要清除一下缓存,就可 ...
- HTTP协议综合
1.用浏览器模拟各种User Agent 测试页面的时候经常需要不同的User Agent,Firefox.Chrome浏览器就可以完美的模拟出各种User Agent.User Agent Swit ...
- javascript学习网址
教程:JavaScript征途 http://www1.huachu.com.cn/read/readbook.asp?bookid=10109449 教程:JScript 参考 http://msd ...
- 使用electron+Js开发夸平台(Linux、Win、Mac)的桌面应用程序
一.开源地址: https://github.com/electron/electron 二.官方网站: https://electron.atom.io/ 三.案例
- 跟我学AngularJS:全局变量设置之value vs constant vs rootscope vs 服务[转]
林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 摘要:本文要讲讲Angular中value vs. constant以及全局变量的设置 本教程 ...
- Maven构建应用程序常用配置(转)
来自:http://shiyanjun.cn/archives/180.html 使用Maven来构建应用程序,可以非常方便地管理应用相关的资源.众所周知,应用程序中涉及到的一些依赖关系,如Java应 ...
- C# new和初始化
虽然知道使用new可以创建对象,但一直不是很理解初始化和new等知识的具体. 通过8个问题和需求,了解相关知识. 了解问题和需求 1.new 的三个步骤 2.初始化是什么意思. 3.变量声明后和变量赋 ...
- SpringMVC Controller配置方法有哪几种
第一种 URL对应Bean 如果要使用此类配置方式,需要在XML中做如下样式配置 <!-- 表示将请求的URL和Bean名字映射--> <bean class="org.s ...