一.关于文件下载:

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

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. WebView&HTML5-----使用WebView播放HTML5视频文件

    一.问题描述 HTML5提供了很多新的特性比如,视频播放.web本地存储.地理定位.应用缓存.Canvas等,但这些特性需要浏览器的支持,在Android应用中我们可以使用WebView构建Web应用 ...

  2. SAP ABAP编程 取得用户中文名称

    有时候我们知道SAP当前用户登录的ID,也就是SY-UNAME.能够取得用户中文名称.例如以下: ***取得用户中文名称 DATA: g_sheet_jsr TYPE string.  "用 ...

  3. 解决eclipse导出javadoc时的“错误: 编码GBK的不可映射字符”问题(转)

    http://blog.csdn.net/psy1100/article/details/51179342 今天要将自己的API接口和MODEL导出来一份java doc参考文档, 但是在导出的时候却 ...

  4. 我的四轴专用PID参数整定方法及原理---超长文慎入(转)

    给四轴调了好久的PID,总算是调好了,现分享PID参数整定的心得给大家,还请大家喷的时候手下留情. 首先说明一下,这篇文章的主旨并不是直接教你怎么调,而是告诉你这么调有什么道理,还要告诉大家为什么'只 ...

  5. Oracle整形转字符串to_char()

    使用to_char()将NUMBER转换为字符串: select to_char(AW_PROCESSSTATUS ) as PROCESSSTATUS from A

  6. Android 自定义 ListView 上下拉动“刷新最新”和“加载更多”歌曲列表

    本文内容 环境 测试数据 项目结构 演示 参考资料 本文演示,上拉刷新最新的歌曲列表,和下拉加载更多的歌曲列表.所谓"刷新最新"和"加载更多"是指日期.演示代码 ...

  7. Oracle聚合连接字符串

    问题需求 现有一个数据表,如下: ID    CODE    NAME 1    A    张三 2    A    李四 3    B    王五 4    C    赵六 5    C    孙七 ...

  8. ArcGIS10.3新体验

    自2012年ESRI更新10.2以后,终于在2014年12月8日,官方推出了10.3版本,前几天忙于抢票,今天终于可以在虚拟机中体验一把. 由于使用的是预览版,所有安装包只有800多M,包括桌面核心程 ...

  9. JAVA中动态编译的简单使用

    一.引用库 pom文件中申明如下: <dependencies> <!-- https://mvnrepository.com/artifact/junit/junit --> ...

  10. ios app性能分析

    苹果app的流畅性一般比安卓的要好的多.应该是和苹果系统的设计理念同样,早期的iphone4曾经是绝对单任务,仅仅能做一件事情,尽管添加了后台能够.音乐播放,定位等有限的服务.可是大多数普通应用切换到 ...