• struts2第四天——拦截器和标签库


    一、拦截器(interceptor)概述

      struts2是个框架,里面封装了很多功能,封装的很多功能都是在拦截器里面。
      (属性封装、模型驱动等都是封装在拦截器里面)
      struts2里面封装了很多功能,有很多拦截器,每次执行一部分拦截器,比如一些默认拦截器等
      默认拦截器的位置在 core的jar包的struts-default.xml里边<interceptor>标签里边

    二、拦截器基本原理

      拦截器在什么时候执行:
        在action对象创建之后和action方法执行之前进行执行(使用在相关位置打断点,并使tomcat在debug处进行调试验证) 

      拦截器的底层原理:
        主要原理

            AOP思想:

             AOP (Aspect Oriented Programming)思想:面向切面编程      

              有基本功能,想拓展功能,不用修改源代码
              而是其他方式(增加配置文件等)来实现功能拓展)
              (例如,给基本的登陆功能增加权限判断,不修改源代码增加权限判断)
              这是第一个浅的层次:不修改源代码,增强、拓展功能
              更深层次见 spring

        所以AOP的本质是在一系列纵向的控制流程中,把那些相同的子流程提取成一个横向的面

                                                  

           责任链模式: ((诸多设计模式的一种,有点类似web阶段过滤链))     

              过滤链:每个请求可以有多个过滤器,只有每个过滤器放行了才能到下一个
              责任链模式:有多个操作:添加 修改 删除
              只有添加后做类似“放行”操作才能到修改,修改后再放行,才能到删除

        AOP思想和责任链模式如何运用到拦截器里:
          拦截器在action对象创建之后和action方法执行之前进行执行,执行过程使用AOP思想
          在action里面并没有直接调用拦截器的方法,而是通过配置文件进行操作执行
          要执行很多拦截器,需要用到责任链模式,拦截器1执行之后,放行;拦截器2执行,放行...action方法执行
          (拦截器有很多功能,要用到什么功能给什么功能)(类似做手术,每个助手拿着不同的器具,主治医生需要什么器具,助手递过去什么器具)

        可以通过查看源代码进一步理解上面的流程(看web.xml中过滤器那个类的源码)
        (1)执行action
        (2)创建action对象,使用动态代理
        (3)执行action的方法
        (4)执行很多拦截器 ,遍历执行 if(interceptors.hasNext())
        (5)类似于放行的方法 return invocation.invoke()

        重要的概念:
          过滤器和拦截器的区别(另外一个重要的概念是前一天的servlet 和 action的区别)
          (1)过滤器:理论上可以过滤任意资源(HTML ,JSP...)
          (2)拦截器:只会可以拦截action (是在action创建后方法执行前,故只能拦截action)

    三、自定义拦截器 

      1) 在struts2中有很多拦截器,struts2中封装了很多拦截器,可能存在我们需要而
        struts2中不存在的拦截器。
      2)  拦截器的结构:通过查看源码查看一下结构(例如modeDrivern)
        继承了 AbstractInterceptor(此抽象类实现了接口Interceptor)
      接口里有三个方法:
        init() ==初始化
        destroy() ==销毁
        interceptor() ==拦截操作
      可以通过自定义类继承抽象类实现
      实际开发中使用的是 继承 MethodFilterInterceptor类

      实现接口时必须实现所有方法,即使这个方法什么也不做;所以可以选择继承类来替代(当继承类和实现接口都可以时)
      可以让action里某个方法不进行拦截
      让自定义拦截器和action有关联,需要用到AOP思想;通过配置文件而不是调用方法的方式

      自定义登陆拦截器:
        1) 需求:实现只有登陆状态才能点击action的超链接,非登陆状态点击超链接跳转到登陆页面
            判断登陆状态是通过 session 实现:
            登陆成功后往session里放值,检查session里是否有值来进行判断
        2) 基本过程:
          继承类:MethodFilterInterceptor;
          重写方法;
          注册拦截器(让拦截器和action有关联);
            注册基本步骤:
              在action所在的包package里声明拦截器(可以找默认的拦截器借看声明格式)
              在具体的action标签里使用拦截器
              但是这样会出现 默认拦截器都不会执行的问题
              解决方案是把默认拦截器再手动使用一次:
              不会使用直接全部复制一份
              把拦截器中默认的那一份里
            <interceptor-stack name="defaultStack">
            <interceptor-ref name="exception"/>
            <interceptor-ref name="alias"/>
            <interceptor-ref name="servletConfig"/>
            <interceptor-ref name="i18n"/>
            <interceptor-ref name="prepare"/>
            ...
          把defaultStack 这个name引入即可
          <!-- 把默认拦截器再手动使用一次 -->
          <interceptor-ref name="defaultStack"></interceptor-ref>

    package cn.action.interceptor;
    
    import javax.interceptor.InvocationContext;
    import javax.servlet.http.HttpSession;
    
    import org.apache.struts2.ServletActionContext;
    
    import com.opensymphony.xwork2.ActionInvocation;
    import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
    
    /**
     * 自定义的登陆拦截器
     * @author jiangbei01
     *
     */
    public class LoginInterceptor extends MethodFilterInterceptor{
    
        //重写拦截的逻辑
        @Override
        protected String doIntercept(ActionInvocation invocation) throws Exception {
            HttpSession session = ServletActionContext.getRequest().getSession();
            String session_username = (String)session.getAttribute("username");
            if(session_username != null){
                //放行
                return invocation.invoke();
            }else{
                //到result标签里,找name匹配前往页面
                return "login";
            }
            
        }  
    }

    配置文件如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">
    <struts>
        <package name="demo1" extends="struts-default" namespace="/">
            <!-- 声明拦截器 -->
            <interceptors>
                <!-- 分别是拦截器名字和类的全路径 -->
                <interceptor name="logininterceptor" class="cn.action.interceptor.LoginInterceptor">
                </interceptor>
            </interceptors>
            <action name="login_*" class="cn.action.interceptor.LoginInterceptor" method="{1}">
                <!-- 使用拦截器,name出填上面的name即可 -->
                <interceptor-ref name="logininterceptor">
                    <!-- 设置某些方法不拦截,name值为excludeMethods,标签内容为方法不拦截名 -->
                    <param name="excludeMethods">login,regist</param>
                </interceptor-ref>
                <!-- 把默认拦截器再手动使用一次 -->
                <interceptor-ref name="defaultStack"></interceptor-ref>
                <result name="login">/login.jsp</result>
            </action>
        </package>
    </struts>    

    产生的问题是 登陆功能也进行拦截,此时登陆也检查session进行拦截,产生永远登陆不进去的问题
    解决的思路是让 login()方法不进行拦截
    方法是通过配置文件配置某些方法不拦截
    <!-- 设置某些方法不拦截,name值为excludeMethods,标签内容为方法不拦截名 -->
    <param name="excludeMethods">login,regist</param>

    四、struts2的标签库  

      注意标签库的引入!

      常用
        1. <s:propertiry> 和OGNL表达式在JSP页面中获取值栈数据
        2. <s:iterator> 获取值栈中list集合的数据
        3. <s:dubug> 可以查看值栈的结构和数据
        其它 <s:if> <s:else> <s:a>(超链接) 等相对不太常用的标签

      表单标签(会用):
        html表单回顾 form action method enctype
        <input .../>(详见HTML小结)
        select option
        textareas
        struts2对应html表单标签大多都有对应
      见案例:

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    <%@ taglib prefix="s" uri="/struts-tags" %>
    <%
    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 'struts2_tag.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>
        <!-- 对应form标签 -->
        <s:form name="" action="">
            <!-- 普通输入项,不能直接在前面写,否则不在同一行,
            应当使用label标签,查看源代码可以看到,是不在一个table里面
            代码在一个表格中,不用自己写<br/换行>
             -->
            <s:textfield name="username" label="用户名"></s:textfield>
            <!-- 密码输入项,冒号不用自己写 -->
            <s:password name="password" label="密码"></s:password>
            <!-- 单选框,将value值和显示值设置为一致 -->
            <s:radio list="{'女','男'}" name="sex" label="性别"></s:radio>
            <!-- 构建使value和显示值不一样,使用map方式 -->
            <s:radio list="#{'girl':'女','boy':'男' }"></s:radio>
            <!-- 复选框,注意是checkboxlist -->
            <s:checkboxlist list="{'吃饭','睡觉','打豆豆'}" name="love" label="爱好"></s:checkboxlist>
            <!-- 下拉框 -->
            <s:select list="{'学士','硕士','博士'}" name="xueli" label="学历"></s:select>
            <!-- 文件上传项 -->
            <s:file name="file" label="文件上传"></s:file>
            <!-- 隐藏项 -->
            <s:hidden name="hidden" value="隐藏项"></s:hidden>
            <!-- 提交 -->
            <s:submit value="提交"></s:submit>
            <!-- 重置 -->
            <s:reset value="重置"></s:reset>
            <!-- 文本域 -->
            <s:textarea cols="10" rows="5"></s:textarea>
        </s:form>
      </body>
    </html>

        小问题,提交和重置不在同一行,这是局限性(框架集问题见HTML小结

  • 相关阅读:
    JavaWeb的三大作用域
    软件工程最后一次作业
    软件工程第四次作业
    软件工程第三次作业
    软件工程第二次作业
    2020软件工程第一次作业
    新建Maven项目报错:Cannot resolve plugin org.apache.maven.plugins:maven-clean-plugin:x.x
    浅谈C++ STL
    C++中几种输入输出cin、cin.getline()、getline()、sscanf()、sprintf()、gets()等
    包含头文件的问题之1.7编程基础之字符串 24:单词的长度
  • 原文地址:https://www.cnblogs.com/jiangbei/p/6763703.html
Copyright © 2020-2023  润新知