先简述下学习过程中碰到的一个问题:上传中文命名的文件成功后无法显示
解决办法:修改tomcat下的server.xml文件
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="1000"/>改成
<Connector port="8080" protocol="HTTP/1.1" URIEncoding="UTF-8" connectionTimeout="1000" />
一.上传
Struts2本身并没提供上传的组件,我们可以通过调用上传框架来实现文件的上传。
1、配置上传解析器
首先要配置项目的框架,也就是倒导入"struts2-core-2.2.1.jar"库文件,找到org.apache.struts2包下的default.porperties资源文件。如下 图;资源文件中给出了不同的strus2的默认配置,我们可看到struts2默认是jakarta作为其文件上传的解析器。
jakarta是Commo-FileUpload的框架。如果要使用Commo-FileUpload框架来上传文件,只需将"commons-fileupload-1.2.1.jar"和"commons-io-1.3.2.jar"两个jar复制到项目中的WEB-INF/lib目录下就可。
如果想要使用COS框架来上传文件,只需将“cos.jar”复制到项目中就可以,然后在修改struts.multipart.parser常量值。
修改常量值有两种方法,一是在"struts.xml"中修改,代码如下:
<constant name="struts.multipart.paeser" value="cos"></constant>
二是在struts.properties中修改,代码如下:
sruts.multipart.parser=cos
2..实现文件上传的Action
创建表单:upload.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>Struts2文件上传</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> <center> <h1>Struts 2完成上传</h1> <form action="upload.action" method="post" enctype="multipart/form-data"> <table> <tr> <td>用户名:</td> <td><input type="text" name="username" ></td> </tr> <tr> <td>上传文件:</td> <td><input type="file" name="myFile"></td> </tr> <tr> <td><input type="submit" value="上传"></td> <td><input type="reset"></td> </tr> </table> </form> </center> </body> </html>
完成上传Action
package net.hncu.struts2.action;
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; public class UploadAction extends ActionSupport { // username属性用来封装用户名 private String username; // myFile属性用来封装上传的文件 private File myFile; // myFileContentType属性用来封装上传文件的类型 private String myFileContentType; // myFileFileName属性用来封装上传文件的文件名 private String myFileFileName; //获得username值 public String getUsername() { return username; } //设置username值 public void setUsername(String username) { this.username = username; } //获得myFile值 public File getMyFile() { return myFile; } //设置myFile值 public void setMyFile(File myFile) { this.myFile = myFile; } //获得myFileContentType值 public String getMyFileContentType() { return myFileContentType; } //设置myFileContentType值 public void setMyFileContentType(String myFileContentType) { this.myFileContentType = myFileContentType; } //获得myFileFileName值 public String getMyFileFileName() { return myFileFileName; } //设置myFileFileName值 public void setMyFileFileName(String myFileFileName) { this.myFileFileName = myFileFileName; } public String execute() throws Exception { //基于myFile创建一个文件输入流 InputStream is = new FileInputStream(myFile); // 设置上传文件目录 String uploadPath = ServletActionContext.getServletContext() .getRealPath("/upload"); // 设置目标文件 File toFile = new File(uploadPath, this.getMyFileFileName()); // 创建一个输出流 OutputStream os = new FileOutputStream(toFile); //设置缓存 byte[] buffer = new byte[1024]; int length = 0; //读取myFile文件输出到toFile文件中 while ((length = is.read(buffer)) > 0) { os.write(buffer, 0, length); } System.out.println("上传用户"+username); System.out.println("上传文件名"+myFileFileName); System.out.println("上传文件类型"+myFileContentType); //关闭输入流 is.close(); //关闭输出流 os.close(); return SUCCESS; } }
配置上传Action
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <package name="struts2" extends="struts-default"> <action name="upload" class="net.hncu.struts2.action.UploadAction"> <result name="success">/result.jsp</result> <result name="input">/upload.jsp</result> </action> </package> <!-- Add packages here --> </struts>
3.文件过滤
简述下原理,具体方法很多
通过struts.xml配置文件配置允许上传的文件类型(即Action下面的param子元素),在Action里面定义一个属性接收写好的参数,在通过和uploadContentType属性进行比较,达到过滤的效果
当然也可以用拦截器过滤文件
通过struts.xml配置文件配置fileUpload拦截器(写在Action子元素里)并配置类型,大小等等(interceper-ref子元素里)从而达到过滤
4.国际化
对于手动过滤,自己指定国际化key
拦截器过滤:
文件太大的提示消息KEY是“struts.messages.error.file.too.large”
类型不允许提示消息KEY是“struts.messages.error.content.type.not.allowed”
可以google下文件上传的常量配置
二.下载
可能很多人会觉得,文件下载太简单,直接在页面上给出一个超级链接,该链接的href属性等于要下载文件的文件名,不就可以实现文件下载了吗?大部分时候的确可以实现文件下载,但如果该文件的文件名为中文文件名,则会导致下载失败;或者应用程序需要在让用户下载之前进行进一步检查,比如判断用户是否有足够权限来下载该文件等。
看下面的一个原始的下载页面代码片段:
<h1>原始的下载</h1>
<ul><li>
<!-- 包含中文文件名的下载链接 -->
下载Struts2的Logo:<a href="images/中.gif">下载图形文件</a>
</li><li>
下载Struts2的Logo的压缩文件:<a href="images/struts-gif.zip">下载压缩文件</a>
</li></ul>
上面页面的包含两个下载的超级链接,两个链接的资源都是存在的,但因为第一个资源文件的文件名是中文文件名,如果单击第一个超级链接,将出现如下图所示的页面。
从图中页面中椭圆形框包围的地方,我们看到被下载的文件名变成了包含大量%的字符串,很明显,这种文件名显然无法取得需要下载的文件。
为了解决这个问题,我们使用Struts2的文件下载支持来下载该文件。
Struts2的文件下载Action与普通的Action并没有太大的不同,仅仅是该Action需要提供一个返回InputStream流的方法,该输入流代表了被下载文件的入口。该Action类的代码如下:
public class FileDownloadAction implements Action
{
//该属性是依赖注入的属性,该属性可以在配置文件中动态指定该属性值
private String inputPath;
//依赖注入该属性值的setter方法
public void setInputPath(String value)
{
inputPath = value;
}
/*
下载用的Action应该返回一个InputStream实例,
该方法对应在result里的inputName属性值为targetFile
*/
public InputStream getTargetFile() throws Exception
{
return ServletActionContext.getServletContext().getResourceAsStream(inputPath);
}
//处理用户请求的execute方法,该方法返回success字符串
public String execute() throws Exception
{
return SUCCESS;
}
}
从上面的Action中看到,该Action中包含了一个getTargetFile()方法,该方法返回一个InputStream输入流,这个输入流返回的是下载目标文件的入口。该方法的方法名为getTargetFile,表明该Action有一个targetFile属性来返回下载文件。
一旦我们定义了该Action,就可通过该Action来实现文件下载。
3 配置Action
配置该文件下载的Action与配置普通的Action并没有太大的不同,需要在配置普通Action的基础之上,在加上额外的download的拦截器引用。
除此之外,关键是需要配置一个类型为stream的结果,配置stream类型的结果时需要指定如下四个属性:
contentType:指定被下载文件的文件类型。
inputName:指定被下载文件的入口输入流。
contentDisposition:指定下载的文件名。
bufferSize:指定下载文件时的缓冲大小。
因为stream结果类型的逻辑视图是返回给客户端一个输入流,因此无需指定location属性。
提示:配置stream类型的结果时,因为无需指定实际的显示的物理资源,所以无需指定location属性,只需要指定inputName属性,该属性指向被下载文件。
下面是配置该下载所用的Action类的配置文件片段:
<?xml version="1.0" encoding="GBK"?>
<!-- 指定Struts2配置文件的DTD信息 -->
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<!-- 配置Struts2国际化资源文件的baseName -->
<constant name="struts.custom.i18n.resources" value="globalMessages"/>
<!-- 配置Struts2应用的编码集 -->
<constant name="struts.i18n.encoding" value="GBK"/>
<package name="lee" extends="struts-default">
<!-- 配置下载的拦截器引用 -->
<default-action-ref name="download"/>
<action name="download" class="lee.FileDownloadAction">
<!-- 指定被下载资源的位置 -->
<param name="inputPath">\images\中.gif</param> =======服务器上文件的路径
<!-- 配置结果类型为stream的结果 -->
<result name="success" type="stream">
<!-- 指定下载文件的文件类型 -->
<param name="contentType">image/gif</param>
<!-- 指定下载文件的文件位置 -->
<param name="inputName">targetFile</param>
<param name="contentDisposition">filename="struts.gif"</param> ============下载时的文件名(用户看到的)
<!-- 指定下载文件的缓冲大小 -->
<param name="bufferSize">4096</param>
</result>
</action>
</package>
</struts>