文件下載的核心思想便是將文件從一個地方拷貝到另外一個地方.html
1.傳統方式:java
在Action中加入大量servlet api 操做.優勢是好理解,缺點是耦合度高。git
2.stream方式:github
使用struts2中的stream攔截器進行操做web
我這裏用的是maven,貼出pom.xml:apache
<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>
DownloadAction.javaapi
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.xmlapp
<?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請求方式,那麼要注意中文亂碼的問題,這裏涉及到轉碼的問題,要作一個判斷,詳情可參考上面的代碼.
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源碼,其對應參數,看過源碼後就會發現其實下載和傳統方式差很少,就是將其優化了很多.
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包引入.
遇到的其它問題基本上只耐心查看提示,基本上都解決了,這裏感受細心真心重要.