[学习笔记] Struct2之拦截器

# 学习 # · 2021-03-25

Struts2架构分析

1、Struts2体系结构:

2、Struts2的核心接口和类:

(1)ActionMapper:根据请求的URI查找是否存在对应Action调用。

(2)ActionMapping:保存调用Action的映射信息,如namespace、name等。

(3)ActionProxy:在XWork和真正的Action之间充当代理。

(4)ActionInvocation:表示Action的执行状态,保存拦截器、Action实例。

(5)Interceptor:在请求处理之前或者之后执行的Struts 2组件。

3、Struts2的执行流程:

(1)客户端初始化一个指向Servlet容器的请求HttpServletRequest。

(2)请求经过一系列的过滤器Filter到达核心控制器FilterDispather。

(3)FilterDispather询问ActionMapper决定这个请求是否需要调用某个Action。

(4)如果ActionMapper决定需要调用某个Action,FilterDispather把请求的处理交给ActionProxy。

(5)ActionProxy通过ConfigurationManager(配置管理者)询问框架配置文件(Struts.xml),通过层层的拦截器找到需要调用的核心控制器Action类。

(6)ActionProxy创建一个ActionInvocation的实例。

(7)ActionInvocation实例使用命名模式来调用,在调用Action的过程前后涉及到相关拦截器Intercepter的调用。

(8)一旦Action执行完毕,ActionInvocation负责根据Struts.xml中的配置找到对应的返回结果。


Struts2的拦截器

1、为什么需要拦截器:

(1)早期MVC框架将一些通用操作硬编码在核心控制器中,致使框架灵活性不足、可扩展性降低。

(2)Struts 2将核心功能放到多个拦截器中实现,拦截器可自由选择和组合,增强了灵活性,有利于系统的解耦。

2、拦截器:

(1)Struts 2大多数核心功能是通过拦截器实现的,每个拦截器完成某项功能。

(2)拦截器方法在Action执行之前和之后执行。

(3)拦截器栈:从结构上看,拦截器栈相当于多个拦截器的组合;在功能上看,拦截器栈也是拦截器。

3、拦截器的工作原理:拦截器的执行过程是一个递归的过程。

(1) 第一周期:做一些Action执行前的预处理。

(2)第二周期:将控制交给后续拦截器或返回结果字符串。

(3)第三周期:做一些Action执行后的处理。

// 继承AbstractInterceptor,重写intercept()方法
public class MyTimerInterceptor extends AbstractInterceptor {

    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        //1、执行Action之前的工作:获取开始执行时间
        long startTime = System.currentTimeMillis();
        System.out.println("执行Action之前的工作,开始时间" + startTime);
        //2、 执行后续拦截器或ACtion
        String result = invocation.invoke();
        //3、执行Action之后的工作:计算并输出执行时间
        long endTime = System.currentTimeMillis();
        long execTime = endTime - startTime;
        System.out.println("执行Action后的,结束时间" + endTime);
        System.out.println("总共用时" + execTime);
        //返回结果字符串
        return result;
    }
}

4、拦截器配置:在struts.xml中定义和使用拦截器。

(1)定义拦截器:

<interceptors>
    <!-- interceptor:定义拦截器 -->
    <interceptor name="..." class="..."></interceptor>

    <!-- interceptor-stack:定义拦截器栈 -->
    <interceptor-stack name="...">
        <!-- interceptor-ref指定引用的拦截器 -->
        <interceptor-ref name="..."></interceptor-ref>
    </interceptor-stack>
</interceptors>

<!-- 定义默认的拦截器引用 -->
<default-interceptor-ref name="..."></default-interceptor-ref>

(2)使用拦截器:

<action name="MyTimer" class="com.aduo.action.MyTimerAction">
    <result>/index.jsp</result>
    <!-- interceptor-ref:指定引用的拦截器 -->
    <interceptor-ref name="..."></interceptor-ref>
    <interceptor-ref name="..."></interceptor-ref>
    <!-- 其他配置 -->
</action>

5、Struts2内置拦截器:

(1)params拦截器:负责将请求参数设置为Action属性。

(2)servletConfig拦截器:将源于Servlet API的各种对象注入到Action。

(3)fileUpload拦截器:对文件上传提供支持。

(4)exception拦截器:捕获异常,并且将异常映射到用户自定义的错误页面。

(5)validation拦截器:调用验证框架进行数据验证。

(6)workflow拦截器:调用Action类的validate(),执行数据验证。

(7)staticParams拦截器:将在配置文件中通过action元素的子元素param设置的参数设置到对应的Action的属性中。

6、Struts2内置拦截器栈:struts-default.xml中定义一个defaultStack拦截器栈,并将其指定为默认拦截器。只要在定义包的过程中继承struts-default包,那么defaultStack将是默认的拦截器。

7、自定义拦截器:

(1)方法一:实现Interceptor接口。

void init()    //初始化拦截器所需资源
void destroy()    //释放在init()中分配的资源
String intercept(ActionInvocation ai) throws Exception    //实现拦截器功能

(2)方法二:继承AbstractInterceptor类。

/**
 * 权限验证检查拦截器
 */
public class AuthorizationInterceptor extends AbstractInterceptor {

    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        // 获取用户会话信息
        Map<String, Object> session = invocation.getInvocationContext().getSession();
        User user = (User)session.get("user");
        if(user == null){
            // 终止执行,返回登录页面
            return Action.LOGIN;
        } else {
            // 继续执行剩余的拦截器和Action
            return invocation.invoke();
        }
    }

}

Struts2实现文件上传

1、前端页面:表单提交属性设置为multipart/form-data。

<s:form action="upload.action" enctype="multipart/form-data" method="post">
    文件一:<s:file name="upload" label="选择文件"/><br/>
    <s:submit name="submit" value="上传文件"/>
</s:form>

2、开发实现文件上传的Action:

public class UploadAction extends ActionSupport {
    // 封装上传文件属性
    private File upload;
    // 获取提交的文件类型
    private String uploadContentType;
    // 封装上传文件名称
    private String uploadFileName;
    // 获取文件上传的路径
    private String savePath;
    // 省略getter/setter

    public String getSavePath() {
        return ServletActionContext.getServletContext().getRealPath(savePath);
    }

    @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) {
            fos.write(buffer,0, length);
            length=fis.read(buffer);
        }
        fis.close();
        fos.flush();
        fos.close();
        return SUCCESS;
    }
}

(3)配置Action:

<action name="upload" class="com.aduo.action.UploadAction">
    <!-- 通过param参数设置保存目录的路径 -->
    <param name="savePath">/upload</param>
    <result name="success">/upload_success.jsp</result>
</action>

4、实现多文件上传:多文件上传表单提交时,会提交一个数组。

public class UploadAction extends ActionSupport {
    // 获取提交的多个文件
    private File[] upload;
    // 获取提交的文件类型
    private String[] uploadContentType;
    // 封装上传文件名称
    private String[] uploadFileName;
    // 获取文件上传的路径
    private String savePath;
    // 省略getter/setter

    public String getSavePath() {
        return ServletActionContext.getServletContext().getRealPath(savePath);
    }

    @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()[i]);
            int length=fis.read(buffer);
            while (length>0) {
                fos.write(buffer,0, length);
                length=fis.read(buffer);
            }
            fis.close();
            fos.flush();
            fos.close();
        }
        return SUCCESS;
    }
}

Struts2实现文件下载

1、stream结果类型:将文件数据(通过InputStream获取)直接写入响应流。

名称作用
contentType设置发送到浏览器的MIME类型
contentLength设置文件的大小
contentDisposition设置响应的HTTP头信息中的Content-Disposition参数的值
inputName指定Action中提供的inputStream类型的属性名称
bufferSize设置读取和下载文件时的缓冲区大小

2、contentType类型设置:

文件类型类型设置
Wordapplication/msword
Excelapplication/vnd.ms-excel
PPTapplication/vnd.ms-powerpoint
图片image/gif , image/bmp,image/jpeg
文本文件text/plain
html网页text/html
任意二进制数据application/octet-stream

3、实现文件下载:

(1)编写Action:

public class FileDownAction extends ActionSupport {
    // 读取下载文件的目录
    private String inputPath;
    // 下载文件的文件名
    private String fileName;
    // 读取下载文件的输入流
    private InputStream inputStream;
    // 下载文件的类型
    private String conetntType;
    // 省略getter/setter

    // 创建InputStream输入流
    public  InputStream getInputStream() throws FileNotFoundException{
        String path = ServletActionContext.getServletContext().getRealPath(inputPath);
        return new BufferedInputStream(new FileInputStream(path+"\\"+fileName));
    }

    @Override
    public String execute() throws Exception {
        return SUCCESS;
    }
}

(2)配置Action:

<action name="download" class="cn.houserent.action.FileDownAction">
    <param name="inputPath">/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>

(3)前端页面:

<a href="download.action?fileName=334.jpg">点击此处下载文档</a>
如无特殊说明,本博所有文章均为博主原创。

如若转载,请注明出处:一木林多 - https://www.l5v.cn/archives/275/

评论