1.Struts 2架构分析
- 下面我们开始介绍结构图中所涉及的对象:
(1.)ActionMapper:提供了在请求和Action调用的映射信息,ActionMapper根据请求的URL来查找是否存在对应的Action调用请求,如果有,则返回一个描述,Action映射的ActionMapping对象,如果没有找到匹配的Action调用请求,则返回null。
(2.)ActionMapping:ActionMapping保存了调用Action的映射信息,其中必须保存Action的命名空间信息和name属性信息。
(3.)ActionProxy:ActionProxy在XWork和正真的Action之间充当代理,在执行Action的过程中,因为使用代理而非直接操作对象,所以可以在Action执行前后执行额外的操作。
(4.)ActionInvocation:标示Action的执行状态,它保存拦截器(按配置顺序),Action实例。Actionlnvocation由ActionProxy创建,通过调用invoke()方法开始Action的执行,执行顺序为按配置顺序执行拦截器,拦截器执行完毕后执行Action,Action执行结束后返回结果字符串,匹配对应的Result后,再一次执行拦截器。
(5.)Interceptor(拦截器):拦截器是一种可以再请求处理之前或者之后执行的Struts 2组件。拦截器是Struts 2重要特性,Struts 2框架的绝大多数功能是通过拦截器完成的。 二:Struts 2的拦截器 - 为什么使用拦截器:
便于请求数据的封装,类型转换,数据效验,解析上传文件,防止表单多次提交等。
拦截器的方法在Action执行之前或者执行之后自动地执行,从而将通用的操作动态插入到Action执行的前后,这样有利于系统的解耦。
2.拦截器栈:
从结构上看,拦截器相当于多个拦截器的组合,拦截器栈也是拦截器同样可以和其他拦截器(或拦截器栈)一起组成更强大的拦截器栈。
3.拦截器的工作原理:
拦截器围绕着Action 和Result的执行而执行。从上图可以看出,struts 2拦截器的实现原理和Servlte Filter的实现原理差不多,以链试执行,对正真要执行的方法(execute())进行拦截。首先执行Action配置的拦截器,在Action和Result执行之后拦截器在一次执行(与先前调用相反的顺序)在此链式的执行过程中,任何一个拦截器都可以直接返回,从而终止余下的拦截器,Action及Result的执行。
当ActionInvocation的invoke()方法被调用时,开始配置Action配置的第一个拦截器,拦截器做出相应处理后再次调用ActionInvocation的invoke()方法,ActionInvocation对象负责跟踪执行过程的状态,并且把控制权交给合适的拦截器。ActionInvocation通过调用拦截器的intercept()方法将控制转交给拦截器,因此拦截器的执行可以看做一个递归的过程,后续拦截器继续执行,直到最后一个拦截器。
4.拦截器有一个三阶段的,有条件的执行周期:
(1.)做一下Action执行前的预处理。拦截器可以准备,过滤,改变或者操作任何可以访问的数据,包括Action。
(2.)调用ActionInvocation的invoke()方法将控制权转交给后续的拦截器或者返回字符串终止执行,如果拦截器决定请求的处理不应该继续,可以不调用invoke()方法,而不是直接返回一个控制字符串。通过这种方式,可以停在后续的执行,并且决定将那个结果呈现给客户端。
(3.)做一下Action执行后的处理。此时拦截器依然可以改变可以发访问的对象和数据,只是此时框架已经选择了一个结果呈现给客户端了。
示例如下:
public class MytimerInterceptor extends AbstractInterceptor{
@Override
public String intercept(ActionInvocation invocation) throws Exception {
// TODO Auto-generated method stub
//执行Action之后的工作,获取开始执行时间
long startTime=System.currentTimeMillis();
System.out.println("开始时间:"+startTime);
//2.执行后续拦截器
String result=invocation.invoke();
//3.执行action之后的工作,计算并输出时间
long endTime=System.currentTimeMillis();
long execTime=endTime-startTime;
System.err.println("结束时间:"+endTime);
System.err.println("总共用时:"+execTime);
return result;
}
}
三:拦截器的配置- 配置拦截器需要经过以下两个步骤:
- 通过<interceptor……./>元素定义拦截器。
-
通过<interceptor-ref…../>元素来使用拦截器。
示例代码如下 struts.xml文件中:
<package name="default" namespace="/" extends="struts-default">
<interceptors>
<interceptor name="myTimer"
class="cn.bdqn.interceptor.MytimerInterceptor">
</interceptor>
</interceptors><action name="invocation" class="cn.bdqn.action.Invocation" method="time"> <result name="success">/index.jsp</result> <interceptor-ref name="myTimer"></interceptor-ref> <!-- 引用默认拦截器栈 --> <interceptor-ref name="defaultStack"></interceptor-ref> </action>
</package>
- params 拦截器:
将请求中的数据设置到Action的属性上。 - staticParams拦截器:
在配置文件中通过<action >元素的子元素<param>设置的参数设置到对应的Action的属性中。 -
servletConfig拦截器:
提供了将一种源于Servlet API的各种对象注入,Action当中的简洁方法,Action必须实现相应对应的接口,servletConfig拦截器才能将对应的Servlet对象注入Action中。
ServletAPI对象的接口如下:
接口 作用
ServletContextAware 设置ServletContext
ServletRequestAware 设置HttpServletRequest
ServletResponseAware 设置HttpServletResponse
ParameterAware 设置Map类型的请求参数
RequestAware 设置Map类型的请求(HttpServletRequest)属性
SessionAware 设置Map类型的会话(HttpSession)属性
ApplicationAware 设置Map类型的应用程序作用域对象(ServletContext) - fileUpload拦截器:
拦截器将文件和元数据从多重要求(multipart/form-data)转换为常规的请求数据,以便将他们设置在对应的Action属性上,实现文件上传。 - validation拦截器:
该拦截器用于执行数据效验。 - work flow拦截器:
该拦截器提供当数据效验错误时终止执行流程的功能。 - exception拦截器:
该拦截器用于捕获异常,并且能够根据异常类型捕获的异常映射到用户自定义的错误页面。 五:自定义拦截器 - 改接口提供了三个方法:
Com.opensymphony.xwork2.interceptor.Interceptor
(1.)Void init();该拦截初始化后再改拦截器执行拦截之前,系统回调该方法。执行一次
(2.)void destroy();该方法跟init()方法对应。在拦截器销毁之前系统回调。
(3.)String intercept(ActionInvocation invocation)throws Exception:该方法是用户需要实现的拦截动作。该方法会返回一个字符串作为逻辑视图。
2.处此之外继承com.opensymphony.xwork2.interceptor.AbstractInterceptor类是更简单的一种实现拦截器的方式,AbstractInterceptor类提供了init()和destroy()方法的实现,这样我们只需要实现intercept()方法,就可以创建自己的拦截器了。 六:文件上传及下载:首先导入JAR架包:
package cn.bdqn.action;包中文件:
UploadAction 类:
package cn.bdqn.action;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;
public class UploadAction extends ActionSupport {
//封装文件标题属性
private String title;
//封装上传文件属性
private File upload; //upload 与jsp页面中 组件<<s:file >name属性值保持一致
//获取提交的文件类型
private String uploadContentType;// 命名规则 <s:file name=upload >name属性值开头
//封装上传文件名称
private String uploadFileName;//命名规则 <s:file name=upload>name属性值开头
//获取文件上传的路径
private String savePath; //上传路径
public String getUploadContentType() {
return uploadContentType;
}
public void setUploadContentType(String uploadContentType) {
this.uploadContentType = uploadContentType;
}
public String getUploadFileName() {
return uploadFileName;
}
public void setUploadFileName(String uploadFileName) {
this.uploadFileName = uploadFileName;
}
@Override
public String execute() throws Exception {
byte[] buffer=new byte[1024];
//读取配置文件
FileInputStream fis=new FileInputStream(this.getUpload());
//保存文件,并设置保存目录路径
FileOutputStream fos=new FileOutputStream(getSavePath()+"\\"+this.getUploadFileName());
int length=fis.read(buffer);
while (length>0) {
//每次写入length长度的内容
fos.write(buffer,0, length);
length=fis.read(buffer);
}
fis.close();
fos.flush();
fos.close();
return SUCCESS;
}
//获取上传文件的路径 通过读取保存目录获得保存路径
public String getSavePath() {
return ServletActionContext.getServletContext().getRealPath(savePath);
}
public void setSavePath(String savePath) {
this.savePath = savePath;
}
public File getUpload() {
return upload;
}
public void setUpload(File upload) {
this.upload = upload;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
ManyUploadAction 类:
package cn.bdqn.action;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;
public class ManyUploadAction extends ActionSupport {
//封装文件标题属性
private String title;
//封装上传文件属性
private File[] upload; //upload 与jsp页面中 组件<<s:file >name属性值保持一致
//获取提交的文件类型
private String[] uploadContentType;// 命名规则 <s:file name=upload >name属性值开头
//封装上传文件名称
private String[] uploadFileName;//命名规则 <s:file name=upload>name属性值开头
//获取文件上传的路径
private String savePath; //上传路径
@Override
public String execute() throws Exception {
byte[] buffer=new byte[4096];
for(int i=0;i<upload.length;i++){
//读取配置文件
FileInputStream fis=new FileInputStream(this.getUpload()[i]);
//保存文件,并设置保存目录路径
FileOutputStream fos=new FileOutputStream(getSavePath()+"\\"+this.getUploadFileName()[i]);
int length=fis.read(buffer);
while (length>0) {
//每次写入length长度的内容
fos.write(buffer,0, length);
length=fis.read(buffer);
}
fis.close();
fos.flush();
fos.close();
}
return SUCCESS;
}
//获取上传文件的路径 通过读取保存目录获得保存路径
public String getSavePath() {
return ServletActionContext.getServletContext().getRealPath(savePath);
}
public void setSavePath(String savePath) {
this.savePath = savePath;
}
public String[] getUploadContentType() {
return uploadContentType;
}
public void setUploadContentType(String[] uploadContentType) {
this.uploadContentType = uploadContentType;
}
public String[] getUploadFileName() {
return uploadFileName;
}
public void setUploadFileName(String[] uploadFileName) {
this.uploadFileName = uploadFileName;
}
public void setUpload(File[] upload) {
this.upload = upload;
}
public File[] getUpload() {
return upload;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
FileDownAction类:
package cn.bdqn.action;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;
public class FileDownAction extends ActionSupport {
private String inputPath; //下载文件的目录
public String getInputPath() {
return inputPath;
}
public void setInputPath(String inputPath) {
this.inputPath = inputPath;
}
//下载文件的文件名
private String fileName;
//读取下载文件的输入流
// private InputStream inputStream;
//下载文件的类型
private String conetntType;
public InputStream getInputStream() throws FileNotFoundException{
/*return ServletActionContext
.getServletContext()
.getResourceAsStream(inputPath + "\\" + fileName);*/
String path=ServletActionContext.getServletContext().getRealPath(inputPath);
return new BufferedInputStream(new FileInputStream(path+"\\"+fileName));
}
@Override
public String execute() throws Exception {
/ //创建一个File对象
File file=new File(fileName);
//通过读取File对象创建输入流
inoutStream=new FileInputStream(file) ;
//得到实际的文件名称
fileName=file.getName();
//
conetntType=this.getConetntType();/
return SUCCESS;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
/ public InputStream getInputStream() {
return inputStream;
}/
public String getConetntType() {
return conetntType;
}
// public void setInputStream(InputStream inputStream) {
// this.inputStream = inputStream;
// }
public void setConetntType(String conetntType) {
this.conetntType = conetntType;
}
}
Jsp页面示例代码如下
Filedown.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="/struts-tags" prefix="s"%>
<%
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>My JSP 'filedown.jsp' starting page</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>
<a href="download.action?fileName=1.jpg">点击此处下载文档</a>
</body>
</html>
fileinput.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="/struts-tags" prefix="s"%>
<%
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>文件上传</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>
<s:form action="upload.action" enctype="multipart/form-data" method="post">
文件一:<s:file name="upload" label="选择文件"></s:file><br/>
<%-- 文件二:<s:file name="upload" label="选择文件"/><br/>
--%>
<s:submit name="submit" value="上传文件"/>
</s:form>
</body>
</html>
manyfileinput.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="/struts-tags" prefix="s"%>
<%
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>文件上传</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>
<s:form action="mangUpload.action" enctype="multipart/form-data" method="post">
文件一:<s:file name="upload" label="选择文件"></s:file><br/>
文件二:<s:file name="upload" label="选择文件"/><br/>
<s:submit name="submit" value="上传文件"/>
</s:form>
</body>
</html>
manyupload_success.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="/struts-tags" prefix="s"%>
<%
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>文件上传</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>
您所上传的文件是:
<s:property value="uploadFileName" />
<br /> 文件类型:
<s:property value="uploadContentType" />
<br />
<s:iterator value="uploadFileName" status="i">
图片:<img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="<%=basePath%>upload/<s:property />" />
</s:iterator>
</body>
</html>
upload_success.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<%
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>文件上传</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>
您所上传的文件是:
<s:property value="uploadFileName" />
<br /> 文件类型:
<s:property value="uploadContentType" />
<br /> 图片:
<img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="<%=basePath%>upload/<s:property value='uploadFileName'/>" />
</body>
</html>
示例代码如下:struts.xml配置文件
<?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>
<constant name="struts.multipart.maxSize" value="10485760" />
<constant name="struts.i18n.encoding" value="UTF-8" />
<constant name="struts.ui.theme" value="simple" />
<package name="default" namespace="/" extends="struts-default">
<action name="upload" class="cn.bdqn.action.UploadAction">
<!-- param 标签的name值为action中定义的属性 -->
<param name="savePath">/upload</param>
<result name="success">/upload_success.jsp</result>
</action>
<!-- 多文件上传 -->
<action name="mangUpload" class="cn.bdqn.action.ManyUploadAction">
<!-- 通过设置参数方式保存路径 -->
<param name="savePath">/upload</param>
<result name="success">/manyupload_success.jsp</result>
</action>
<!-- 下载 注意事项,下载的文件必须提前存在upload文件中 -->
<action name="download" class="cn.bdqn.action.FileDownAction">
<!-- inputPath 为action 中 定义的下载文件目录 WebRoot下文件名upload -->
<param name="inputPath">/upload</param>
<result name="success" type="stream">
<!-- contentType 下载文件类型 此处配置通用的 -->
<param name="contentType">application/octet-stream</param>
<!-- inputName 固定命名,为action中定义的inputStream类型的属性名称 -->
<param name="inputName">inputStream</param>
<!--
attachment表示下载弹出对话框,filename下载文件名称 ${fileName}为读取action中下载文件名称
-->
<param name="contentDisposition">attachment;filename="${fileName}"</param>
<!-- 上传或下载的缓冲区 4k -->
<param name="bufferSize">4096</param>
</result>
</action>
</package>
</struts>
共同学习,写下你的评论
评论加载中...
作者其他优质文章