第四章 Struts2深入
4.1 Struts2架构
1、ActionMapper:
提供请求和Action之间的映射。根据请求查找是否存在对于的action,如有,翻译描述action映射的ActionMapping对象,没有,返回null
2、ActionMapping:
保存了调用action的映射信息,其中必须保存Action的命名空间信息和name属性
3、ActionProxy:
在XWork和真正的Action之间充当代理
4、ActionInvocation:
表示执行状态,它按顺序保存拦截器,Action,实例,由ActionProxy创建,通过调用invoke()方法开始Action的执行
5、Interceptor(拦截器):
是一种可以在请求处理之前或者之后执行的Struts2组件
4.2 Struts2拦截器
工作原理:
做一些Action执行前的预处理,可以准备,过滤,改变或者操作任何可以访问的数据,包括Action
调用ActionInvocation的invoke()方法将控制转交给后续的拦截器或者返回结果字符串终止执行,如果请求不应该继续,可以不调用invoke()方法
而是直接返回一个控制字符串,通过这种方式,可以停止后续的执行,并且决定哪个结果来呈现给客户端。
做一些Action执行之后的处理:此时拦截器依然可以改变可以访问的对象和数据,执行此时框架已经选择一个结果呈现给客户端了
拦截器的配置
1、通过<interceptor.../>元素来定义拦截器
2、通过<interceptor-ref.../>元素来使用拦截器
例:
<package name="default" extends="struts-default" namespace="/">
<interceptors>
定义拦截器
<interceptor name="interceptorName" class="interceptor.MyTimerInterceptor"/>
定义拦截器栈
<interceptor-stack name="interceptorStackName">
指定引用的拦截器
<interceptor-ref name="interceptorName | interceptorStackName"/>
</interceptor-stack>
</interceptors>
定义默认的拦截器引用
<default-interceptor-ref name="interceptorName | interceptorStackName"/>
<action name="actionName" class="interceptor.MyTimerAction">
为Action指定拦截器引用
<interceptor-ref name="interceptorName | interceptorStackName"/>
<result name="success">indexWelcom.jsp</result>
<result name="input">index.jsp</result>
</action>
</package>
内置拦截器
1、params拦截器:将请求中的数据设置到Action的属性上
2、staticParams拦截器:将在配置文件中通过action元素的子元素Param设置的参数设置到对应的Action属性中
3、servletConfig拦截器:提供了一种将源于Servlet API 的各种对象注入Action中的方法
获取ServletAPI对象的接口
接口 作用
ServletContextAware 设置ServletContext
ServletRequestAware 设置HttpServletRequest
ServletResponseAware 设置HttpServletResponse
ParameterAware 设置Map类型的请求参数
ResquestAware 设置Map类型的请求HttpServletRequest属性
SessionAware 设置Map类型的会话HttpSession属性
ApplicationAware 设置Map类型的应用程序作用域对象ServletContext
4、fileUpload拦截器:将文件和元数据从多重请求(multipart/form-data)转换为常规请求数据,以便于将他们设置在对于的Action上
5、validation拦截器:执行数据校验
6、workflow拦截器:提供当数据校验错误时终止执行流程的功能
7、exception拦截器:捕获异常
拦截器栈
<interceptor-stack name="defaultStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="il8n"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="debugging"/>
<interceptor-ref name="profiling"/>
<interceptor-ref name="scopedModelDriven"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="params">
<param name="excludeParams">dojo\..*</param>
</interceptor-ref>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
</interceptor-stack>
自定义拦截器
在Struts2中所有拦截器都直接或间接的实现接口om.opensymphony.xwork2.interceptor.Interceptor.
该接口提供了3各个方法:
void init():该拦截器初始化之后,在拦截器执行拦截之前,系统回调该方法,此方法只执行一次
void destroy():在拦截器实例被销毁之前,系统回调该方法
String intercept(ActionInvocation invocation) throws Exception:是用户需要实现的拦截动作,返回结果字符串
首先编写权限验证拦截器
public class AuthorizationInterceptor extends AbstractInterceptor { /** * 拦截器的拦截方法 */ @Override public String intercept(ActionInvocation invocation) throws Exception { //获取回话信息 @SuppressWarnings("rawtypes") Map session=invocation.getInvocationContext().getSession(); users user=(users) session.get("login"); if(user==null){ //终止执行,返回登录页面 return Action.LOGIN; }else{ //继续执行剩余的Action和拦截器 return invocation.invoke(); } } }
然后在配置文件中定义拦截器并引用
<package name="default" extends="struts-default" namespace="/"> <interceptors> <!-- 定义权限验证拦截器 --> <interceptor name="myAuthorization" class="interceptor.AuthorizationInterceptor"></interceptor> <interceptor-stack name="myStack"> <interceptor-ref name="defaultStack"/> <interceptor-ref name="myAuthorization"/> </interceptor-stack> </interceptors> <!-- 定义默认拦截器 --> <default-interceptor-ref name="myStack"/> <default-action-ref name="defaultAction"/> <!-- 定义全局结果 --> <global-results> <result name="login" type="redirect">login.jsp</result> </global-results> <action name="defaultAction" class="interceptor.MyTimerAction"> <result name="fail">fail.jsp</result> </action> <action name="house" class="interceptor.MyTimerAction"> <result name="success">guanli.jsp</result> <interceptor-ref name="myStack"></interceptor-ref> </action> </package>
4.3 实现文件上传
UploadAction.java
public class uploadAction extends ActionSupport{ //封装上传文件属性 private File upload; //封装上传文件类型 private String uploadContentType; //封装上传文件名称 private String uploadFileName; //封装上传文件的路径 private String savePath; @Override public String execute()throws Exception{ byte[] buffer=new byte[1024]; //读取文件 FileInputStream fis=new FileInputStream(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"; } //获取上传文件的保存路径 //通过读取存放目录获得保存路径 //省略get/set方法 public String getSavePath() { return ServletActionContext.getServletContext().getRealPath(savePath); } }
配置文件中定义uploadAction
<action name="download" class="interceptor.FileDownAction">
<param name="savePath">/upload</param>
<result name="success" type="stream">
<param name="contentType">application/octet-stream</param>
<param name="inputName">inputStream</param>
<param name="contentDisposition">attachment;filename="${fileName}"</param>
<param name="bufferSize">4096</param>
</result>
</action>
多文件上传
public class uploadActions extends ActionSupport{ //封装上传文件属性 private File[] upload; //封装上传文件类型 private String[] uploadContentType; //封装上传文件名称 private String[] uploadFileName; //封装上传文件的路径 private String savePath;
//省略get/set方法 @Override public String execute()throws Exception{ byte[] buffer=new byte[1024]; for (int i = 0; i < upload.length; i++) { //读取文件 FileInputStream fis=new FileInputStream(getUpload()[i]); //保存文件,设置保存目录路径 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"; } }
4.4文件下载
Stream结果类型
contentType 设置发送到浏览器的MIME类型
contentLength 设置文件大小
contentDisposition 设置响应的HTTP头信息中的content-Disposition参数的值
inputName 指定Action中提供的inputStream类型的属性名称
bufferSize 设置读取和下载文件是的缓冲区大小
FileDownAction.java
public class FileDownAction extends ActionSupport { //读取下载文件目录 private String inputPath; //下载文件的文件名 private String fileName; //读取下载文件的输入流 private InputStream inputStream; //下载文件类型 private String contentType; public String getInputPath() { return inputPath; } public void setInputPath(String inputPath) { this.inputPath = inputPath; } public String getFileName() { return fileName; } public void setFileName(String fileName) { this.fileName = fileName; } public InputStream getInputStream()throws FileNotFoundException { String path=ServletActionContext.getServletContext().getRealPath(inputPath); return new BufferedInputStream(new FileInputStream(path+"\\"+fileName)); } public void setInputStream(InputStream inputStream) { this.inputStream = inputStream; } public String getContentType() { return contentType; } public void setContentType(String contentType) { this.contentType = contentType; } @Override public String execute()throws Exception{ return "success"; } }
配置文件
<action name="download" class="interceptor.FileDownAction">
<param name="savePath">/upload</param>
<result name="success" type="stream">
<param name="contentType">application/octet-stream</param>
<param name="inputName">inputStream</param>
<param name="contentDisposition">attachment;filename="${fileName}"</param>
<param name="bufferSize">4096</param>
</result>
</action>
contentType对应的文件类型
Word application/msword
Execl Application/vnd.ms-excel
PPT Application/vnd.ms-powerpoint
图片 image/gif、image/bmp、image/jpeg
文本文件 text/plain
HTML网页 text/html
可执行文件 application/octet-stream