一.关于文件下载:

文件下载的核心思想即是将文件从一个地方拷贝到另一个地方.

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入门学习---文件下载的二种方式的更多相关文章

  1. java struts2入门学习--防止表单重复提交.OGNL语言学习

    一.知识点回顾 防止表单重复提交核心思想: 客户端和服务器端和写一个token,比较两个token的值相同,则非重复提交;不同,则是重复提交. 1.getSession三种方式比较: request. ...

  2. java struts2入门学习---中文验证、对错误消息的分离、结果(result)类型细节配置

    一.需求 利用struts2实现中文验证并对错误消息的抽离. 详细需求:用户登录-->不填写用户名-->页面跳转到用户登录页面,提示用户名必填(以英文和中文两种方式提示)-->填写英 ...

  3. java struts2入门学习实例--将客户端IP地址和访问方式输出到浏览器

    实例1:实现客户端IP地址和访问方式输出到浏览器. IpAction.java package com.amos.web.action; import javax.servlet.http.HttpS ...

  4. java struts2入门学习--OGNL语言基本用法

    一.知识点学习 1.struts2中包含以下6种对象,requestMap,sessionMap,applicationMap,paramtersMap,attr,valueStack; 1)requ ...

  5. java struts2入门学习--基于xml文件的声明式验证

    一.知识点总结 后台验证有两种实现方式: 1 手工验证顺序:validateXxx(针对Action中某个业务方法验证)--> validate(针对Action中所有的业务方法验证) 2 声明 ...

  6. java struts2入门学习--OGNL语言常用符号和常用标签学习

    一.OGNL常用符号(接上一篇文章): 1.#号 1)<s:property value="#request.username"/> 作用于struts2的域对象,而不 ...

  7. java struts2入门学习---自定义类型转换

    自定义类型转换器的作用就是将struts无法识别的类型转换成自己所需要的. 比如输入:广东-东莞-虎门,对应的输出时能输出:广东省 东莞市 虎门(镇/区) 这里涉及到的知识点即是将String转换为任 ...

  8. java struts2入门学习---异常处理和类型转换

    一.struts2对异常的处理 1.自定义局部异常: <action> <exception-mapping result="sonException" exce ...

  9. java struts2入门学习---拦截器学习

    一.拦截器,拦截器栈 1.拦截器的作用 拦截器本质上和servlet的过滤器是一样的.在struts2中,拦截器能够对Action前后进行拦截,拦截器是一个可插拨的,你可以选择使用拦截器,也可以卸载拦 ...

随机推荐

  1. Android -- Dialog动画

    window_in.xml <?xml version="1.0" encoding="utf-8"?> <set xmlns:android ...

  2. Kafka:ZK+Kafka+Spark Streaming集群环境搭建(八)安装zookeeper-3.4.12

    如何搭建配置centos虚拟机请参考<Kafka:ZK+Kafka+Spark Streaming集群环境搭建(一)VMW安装四台CentOS,并实现本机与它们能交互,虚拟机内部实现可以上网.& ...

  3. 转: 一个程序员的Java和C++学习之路(整理)

    http://blog.csdn.net/ajian005/article/details/8003655 http://m.blog.csdn.net/xugangwen/article/detai ...

  4. log4j.xml写入数据库,只有SQL和参数,无其他信息

    <?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE log4j:configuration SY ...

  5. [UIView setShowsFPS:]: unrecognized selector sent to instance XXX

    今天在做sprite Kit game时遇到一个问题. 新建一个项目运行时发现就加了这几句代码无法运行.后来一查原来是storyboard uiview要改一下.改成SKview In your st ...

  6. JS获取当前/指定URL参数

    方法: 首先通过 document.location 获得当前访问网页的网址, 其次用 split 方法通过“?”把网址分为两部分. 如果网址中有参数(arrObj.length > 1) 再用 ...

  7. 微信小程序 - 提示消息组件

    配置挺简单的,也就不说明了,点击下载:alert

  8. C++ 第四课:ASCII 码表

    下面的 ASCII 码表包含数值在0-127之间的字符的十进制.八进制以及十六进制表示. 十进制 八进制 十六进制 字符 描述 0 0 00 NUL   1 1 01 SOH start of hea ...

  9. ES6学习笔记十一:编程风格技巧

    一:用let取代var 二:静态字符串一律使用单引号或反引号,不使用双引号.动态字符串(模版字符串)使用反引号. 三:解构赋值: 使用数组对变量赋值时,优先使用解构赋值: 函数的参数如果是对象的成员, ...

  10. Java多线程之CountDownLatch和CyclicBarrier同步屏障的使用

      转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6558349.html  一:CountDownLatch CountDownLatch是一个执行 完成任务 ...