Struts2--文件的上传下载、表单的重复提交、自定义拦截器--day11-12

本文详细介绍Struts2框架下文件上传下载的配置与实现,包括使用FileUpload拦截器、参数配置及错误消息定制。同时,探讨如何解决表单重复提交问题,并介绍自定义拦截器的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文件的上传下载

文件上传的配置

1)上传文件时表单前置条件

须把 HTML 表单的 enctype 属性设置为 multipart/form-data
须把 HTML 表单的method 属性设置为 post
需添加 字段.

2)Struts2的文件上需要使用FileUpload拦截器

上传一个文件示例

1.创建jsp展示页面

 <s:form action="testUpload.action" method="post" enctype="multipart/form-data">
  <s:file name="ppt" label="PPTFile"></s:file>
  <s:textfield name="pptDesc" label="PPTDesc"></s:textfield>
  <s:submit></s:submit>
 </s:form>

2.Struts2 的文件上传实际上使用的是 Commons FileUpload 组件, 所以需要导入
commons-fileupload-1.3.jar
commons-io-2.0.1.jar
3.创建actin类

public class UploadAction extends ActionSupport{
 /*省略get和set方法,还有构造器*/
 private static final long serialVersionUID = 1L;
 private File ppt;
 private String pptContentType;
 private String pptFileName;
 private String pptDesc;
 public String execute() throws Exception{
  System.out.println(ppt);
  System.out.println(pptContentType);
  System.out.println(pptFileName);
  System.out.println(pptDesc);
  ServletContext servletContext=ServletActionContext.getServletContext();
  String dir=servletContext.getRealPath("/files/"+pptFileName);
  System.out.println(dir);
  FileOutputStream out=new FileOutputStream(dir);
  FileInputStream in=new FileInputStream(ppt);
  
  byte[] buffer=new byte[1024];
  int len=0;
  while((len=in.read(buffer))!=-1) {
   out.write(buffer,0,len);
  }
  out.close();
  in.close();
  return super.execute();
 }
}

上传多个文件示例

1.action核心代码

public String execute() throws Exception{
  ServletContext servletContext=ServletActionContext.getServletContext();
  String dir=null;
  //servletContext.getRealPath("/files/"+pptFileName);
  System.out.println(dir);
  FileOutputStream out=null;
  //new FileOutputStream(dir);
  FileInputStream in=null;
  //new FileInputStream(ppt);
  byte[] buffer;
  Iterator<String> iterator = pptFileName.iterator();
  Iterator<File> iterator2 = ppt.iterator();
  while (iterator.hasNext()) { 
   dir=servletContext.getRealPath("/files/"+iterator.next());
   out=new FileOutputStream(dir);
   in=new FileInputStream(iterator2.next());
   buffer=new byte[1024];
   int len=0;
   while((len=in.read(buffer))!=-1) {
    out.write(buffer,0,len);
   }
   out.close();
   in.close();
  } 
  return super.execute();
 }

2.页面输入

<s:form action="testUpload.action" method="post" enctype="multipart/form-data">
  <s:file name="ppt" label="PPTFile"></s:file>
  <s:textfield name="pptDesc" label="PPTDesc"></s:textfield>
  <s:file name="ppt" label="PPTFile"></s:file>
  <s:textfield name="pptDesc[0]" label="PPTDesc"></s:textfield>
  <s:submit></s:submit>
 </s:form>

上传文件参数配置

可以通过配置 FileUploadInterceptor 拦截器的参数的方式来进行限制
maximumSize (optional) - 默认的最大值为 2M. 上传的单个文件的最大值
allowedTypes (optional) - 允许的上传文件的类型. 多个使用 , 分割
allowedExtensions (optional) - 允许的上传文件的扩展名. 多个使用 , 分割.
注意: 在 org.apache.struts2 下的 default.properties 中有对上传的文件总的大小的限制. 可以使用常量的方式来修改该限制

struts.multipart.maxSize=2097152

例子:

  <interceptors>
   <interceptor-stack name="atguigustack">
    <interceptor-ref name="defaultStack">
     <param name="fileUpload.maximumSize">2000</param>
     <param name="fileUpload.allowedTypes">text/html,text/xml</param>
     <param name="fileUpload.allowedExtensions">html,dtd,xml</param>
    </interceptor-ref>
   </interceptor-stack>
  </interceptors>
  <default-interceptor-ref name="atguigustack"></default-interceptor-ref>

定制错误消息

可以在国际化资源文件中定义如下的消息:
struts.messages.error.uploading - 文件上传出错的消息
struts.messages.error.file.too.large - 文件超过最大值的消息
struts.messages.error.content.type.not.allowed - 文件内容类型不合法的消息
struts.messages.error.file.extension.not.allowed - 文件扩展名不合法的消息
问题: 此种方式定制的消息并不完善. 可以参考 org.apache.struts2 下的 struts-messages.properties, 可以提供更多的定制信息.

文件的下载

1). Struts2 中使用 type=“stream” 的 result 进行下载即可
2). 具体使用细节参看 struts-2.3.15.3-all/struts-2.3.15.3/docs/WW/docs/stream-result.html
3). 可以为 stream 的 result 设定如下参数
contentType: 结果类型
contentLength: 下载的文件的长度
contentDisposition: 设定 Content-Dispositoin 响应头. 该响应头指定接应是一个文件下载类型, 一般取值为 attachment;filename=“document.pdf”.
inputName: 指定文件输入流的 getter 定义的那个属性的名字. 默认为 inputStream
bufferSize: 缓存的大小. 默认为 1024
allowCaching: 是否允许使用缓存
contentCharSet: 指定下载的字符集

文件下载示例

1.编写显示页面

<a href="testDownLoad.action">Down Load</a>

2.编写action方法

public class DownLoadAction extends ActionSupport{
 private static final long serialVersionUID = 1L;
 private String contentType;
 private long contentLength;
 private String contentDisposition;
 private InputStream inputStream;
 public String execute() throws Exception {
  contentType="text/html";
  contentDisposition="attachment;filename=hidden.html";
  ServletContext servletContext=ServletActionContext.getServletContext();
  String fileName=servletContext.getRealPath("/files/hidden.html");
  inputStream=new FileInputStream(fileName);
  contentLength=inputStream.available();
  return "sucess";
 }
}

3.struts.xml配置

<action name="testDownLoad" class="com.atguigu.struts2.upload.app.DownLoadAction" method="execute">
 <result name="sucess" type="stream">
  <param name="bufferSize">2048</param>
 </result>
</action>

表单的重复提交

在不刷新表单页面的前提下:
多次点击提交按钮
已经提交成功, 按 “回退” 之后, 再点击 “提交按钮”.
在控制器响应页面的形式为转发情况下,若已经提交成功, 然后点击 "刷新(F5)“

重复提交的缺点:
加重了服务器的负担
可能导致错误操作.

Struts2 解决表单的重复提交问题

I. 在 s:form 中添加 s:token 子标签

生成一个隐藏域
在 session 添加一个属性值
隐藏域的值和 session 的属性值是一致的.
若一致,移除session 的属性值

II. 使用 Token 或 TokenSession 拦截器.

这两个拦截器均不在默认的拦截器栈中, 所以需要手工配置一下
若使用 Token 拦截器, 则需要配置一个 token.valid 的 result
若使用 TokenSession 拦截器, 则不需要配置任何其它的 result

III. Token VS TokenSession

都是解决表单重复提交问题的
使用 token 拦截器会转到 token.valid 这个 result
使用 tokenSession 拦截器则还会响应那个目标页面, 但不会执行 tokenSession 的后续拦截器. 就像什么都没发生过一样!

IV. 可以使用 s:actionerror 标签来显示重复提交的错误消息.
该错误消息可以在国际化资源文件中覆盖. 该消息可以在 struts-messages.properties 文件中找到
struts.messages.invalid.token=^^The form has already been processed or no token was supplied, please try again.

示例代码

1.创建展示页面

 <s:form action="testToken.action">
  <s:token></s:token>
  <s:textfield name="username" label="Username"></s:textfield>
  <s:submit></s:submit>
 </s:form>

2.action代码如下:

public class TokenAction extends ActionSupport{
 private String username;
 private static final long serialVersionUID = 1L;
 public String execute() throws Exception {
  Thread.sleep(2000);
  return "sucess";
 }
}

3.struts.xml配置如下:

<action name="testToken" class="com.atguigu.struts2.upload.app.TokenAction" method="execute">
   <interceptor-ref name="token"></interceptor-ref>
   <interceptor-ref name="defaultStack"></interceptor-ref>
   <result name="sucess">/sucess.jsp</result>
   <result name="invalid.token">/token-error.jsp</result>
  </action>

4.输出返回配置如下:

 <s:actionerror/>

5.国际化返回配置:
struts.messages.invalid.token=The form has already been processed or no token was supplied, please try again.
TokenSession配置如下:

  <action name="testToken" class="com.atguigu.struts2.upload.app.TokenAction" method="execute">
   <interceptor-ref name="tokenSession"></interceptor-ref>
   <result name="sucess">/sucess.jsp</result>
  </action>

自定义拦截器

拦截器需要实现Interceptor接口,需要实现三个基本方法:
init: 该方法将在拦截器被创建后立即被调用, 它在拦截器的生命周期内只被调用一次. 可以在该方法中对相关资源进行必要的初始化
interecept: 每拦截一个请求, 该方法就会被调用一次.
destroy: 该方法将在拦截器被销毁之前被调用, 它在拦截器的生命周期内也只被调用一次.
I. 定义一个拦截器的类

可以实现 Interceptor 接口
继承 AbstractInterceptor 抽象类

II. 在 struts.xml 文件配置.
III. 注意: 在自定义的拦截器中可以选择不调用 ActionInvocation 的 invoke() 方法. 那么后续的拦截器和 Action 方法将不会被调用.
Struts 会渲染自定义拦截器 intercept 方法返回值对应的 result

配置示例

1.创建自定义拦截器

public class MyInterceptor extends AbstractInterceptor{
 private static final long serialVersionUID = 1L;
 @Override
 public String intercept(ActionInvocation invocation) throws Exception {
  System.out.println("before invocation.invoke...");
  String result=invocation.invoke();
  System.out.println(result);
  System.out.println("after invocation.invoke...");
  return result;
 }
}

2.配置文件

<interceptors>
 <interceptor name="hello" class="com.atguigu.struts2.upload.app.MyInterceptor"></interceptor>
</interceptors>
<action name="testToken" class="com.atguigu.struts2.upload.app.TokenAction" method="execute">
 <interceptor-ref name="hello"></interceptor-ref>
 <interceptor-ref name="tokenSession"></interceptor-ref>
 <result name="sucess">/sucess.jsp</result>
</action>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值