Day46-Struts2 -04 - 拦截器 - struts的标签 - 国际化和扩展

一、拦截器 – interceptor

  • 什么是拦截器interceptor

    拦截器有点类似以前Servlet阶段的Filter(过滤器) , 能够在请求到达Action之前进行拦截操作, 可以在里面进行判断、校验。 典型的例子: 登录拦截.

  • 拦截器和过滤器的不同

    过滤器可以过滤servlet, 拦截器可以拦截Action , 过滤器除了可以过滤servlet之外,还可以过滤网络资源(html / jsp ) , 拦截器只能拦截Action

  • 拦截器底层实现原理:AOP切面编程+责任链模式

    拦截器的实现原理使用的是 AOP +责任链模式

AOP :
全称是面向切面编程, 其实就是在不改动原来代码基础上,我们需要额外加一些权限控制, 或者做一些日志输出。 那么我们可以在需要加的位置 切开,然后嵌入我们需要执行的逻辑代码即可。在struts里面,这一套机制都已经做好了,我们如果想在执行action之前加入我们自己的拦截器,只需在 struts.xml中配置即可。

责任链模式:
拦截器可以配置多个, 表示在到达某一个Action的时候需要经过这么多的拦截器。 struts里面把这个东西称之为拦截器栈。 也就是表示一组拦截器栈里面包含多个拦截器。只有A拦截器做出类似放行的操作,那么后续的拦截器才会执行,以此类推、直到Action的方法执行。
这里写图片描述

1. 自定义拦截器

  • 1.1)实现接口Interceptor

特点: 要实现三个方法,其中init 和 destroy ,平常我们都不太用。

        public class MyInterceptor implements Interceptor {

            @Override
            public void destroy() {
            }

            @Override
            public void init() {
            }
      @Override
      public String intercept(ActionInvocation arg0) throws Exception {
           System.out.println("拦截器test01执行了");
           return arg0.invoke();
      }
        }
  • 1.2)继承实现类 AbstractInterceptor
    好处就是使用复写一个interceptor的函数,坏处就是被拦截action里面的所有方法都被拦截了,无差别性。
    声明拦截器的类:
        public class MyInterceptor02 extends AbstractInterceptor {
      @Override
      public String intercept(ActionInvocation arg0) throws Exception {
           System.out.println("拦截器test02执行了");
           return arg0.invoke();
      }
        }
 struts.xml里面拦截器的配置
<!-- 配置action -->
<struts>
      <package name="demo" extends="struts-default" namespace="/">
           <interceptors>
                 <interceptor name="myInterceptortest02" class="com.itheima.interceptor.InterceptorTest02"></interceptor>
           </interceptors>
           <action name="demo_*" class="com.itheima.action.ActionInterceptor" method="{1}">
                 <interceptor-ref name="myInterceptortest02"></interceptor-ref>
                 <result name="success" type="redirect">/other.jsp</result>
           </action>
      </package>
</struts>
  • 1.3)继承MethodFilterInterceptor
> 可以精确的控制拦截或者不拦截哪一个方法
     Interceptor:
      public class MyInterceptor extends MethodFilterInterceptor {

          @Override
          protected String doIntercept(ActionInvocation arg0) throws Exception {
                System.out.println("来到了拦截器里面~~~");
                return arg0.invoke();
            }
        }
struts.xml中配置:

配置的时候, 使用 excludeMethods不拦截某些方法 或者 includeMethods拦截某些方法 来控制

<!-- 配置action -->
<struts>
      <package name="demo" extends="struts-default" namespace="/">
           <interceptors>
                 <interceptor name="myInterceptortest02" class="com.itheima.interceptor.InterceptorTest02"></interceptor>
                 <interceptor name="myInterceptortest03" class="com.itheima.interceptor.InterceptorTest03">
                      <param name="excludeMethods">test</param>
                 </interceptor>
           </interceptors>
           <action name="demo_*" class="com.itheima.action.ActionInterceptor" method="{1}">
                 <interceptor-ref name="myInterceptortest02"></interceptor-ref>
                 <interceptor-ref name="myInterceptortest03">
                 </interceptor-ref>
                 <result name="success" type="redirect">/other.jsp</result>
           </action>
      </package>
</struts>

2. 自定义拦截器入门 – 步骤

  1. 定义拦截器类
       public class MyInterceptor02 extends AbstractInterceptor {

            @Override
            public String intercept(ActionInvocation arg0) throws Exception {
                System.out.println("来到了拦截器里面~~~");
                //如果后面还有拦截器,就调用下一个拦截器, 如果没有了拦截器,就执行action的方法
                return arg0.invoke();
            }

        }
  1. 在struts.xml里面声明拦截器
        <!-- 配置拦截器以下代码,仅仅是声明了拦截器。写在package包下 -->
        <interceptors>
            <interceptor name="myInterceptor02" class="com.itheima.interceptor.MyInterceptor02"></interceptor>

            <interceptor name="myInterceptortest03" class="com.itheima.interceptor.InterceptorTest03">
                <!-- <param name="excludeMethods">test</param> -->
                <param name="includeMethods">test</param>
            </interceptor>

            <!-- 指定了的包含了多个拦截器,然后又声明一个名字 -->
            <!-- <interceptor-stack name=""></interceptor-stack> -->
        </interceptors>
  1. 在action里面使用拦截器
<action name="actionDemo_*" class="com.itheima.action.ActionDemo" method="{1}">

     <!-- 执行这个action,就必然要走名字叫做myInterceptor02的拦截器 -->
     <interceptor-ref name="myInterceptor02"></interceptor-ref>
</action>

3. 拦截器的处理结果

拦截器的处理结果,莫过于两种
一是放行: 如果后面还有拦截器就执行下一个拦截器,如果后面没有了拦截器,就执行action
一是拦截: 但是注意,拦截后也需要返回到一个具体的页面。 所以需要配置result标签

        @Override
        protected String doIntercept(ActionInvocation arg0) throws Exception {

            System.out.println("来到了拦截器里面~~~");
            //请求被拦截,要求现在立即回到页面去。
            //不想放行. 回到页面。
            return "login"; //这里的login要匹配result的name

        }
        <action name="actionDemo_*" class="com.itheima.action.ActionDemo" method="{1}">
            <!-- 执行这个action,就必然要走名字叫做myInterceptor02的拦截器 -->
            <interceptor-ref name="myInterceptor"></interceptor-ref>

            <result name="login">/index.jsp</result>
        </action>

4. 自定义拦截器的问题

一旦自定义了自己的拦截器,那么struts默认的哪一套 拦截器就不会走。 有点像有参构造和无参构造的关系。

  • struts默认的拦截器都有哪些呢?

在struts-default.xml里面有一个package 名字也叫作 struts-default 在这个包中定义了一个拦截器栈,名字叫做 defaultStack

        <interceptor-stack name="defaultStack">
                <interceptor-ref name="exception"/>
                <interceptor-ref name="alias"/>
                <interceptor-ref name="servletConfig"/>
                <interceptor-ref name="i18n"/>
                <interceptor-ref name="prepare"/>
                <interceptor-ref name="chain"/>
                <interceptor-ref name="scopedModelDriven"/>
                <interceptor-ref name="modelDriven"/>
                <interceptor-ref name="fileUpload"/>
                <interceptor-ref name="checkbox"/>
                <interceptor-ref name="datetime"/>
                <interceptor-ref name="multiselect"/>
                <interceptor-ref name="staticParams"/>
                <interceptor-ref name="actionMappingParams"/>
                <interceptor-ref name="params"/>
                <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-ref name="debugging"/>
                <interceptor-ref name="deprecation"/>
            </interceptor-stack>

然后下面有一个默认的拦截器引用

<default-interceptor-ref name="defaultStack"/>

如果我们给自己的action使用了自己定义的拦截器,那么上面默认的这些拦截器都不会生效了,失去了这些功能,如果还想使用默认的这些拦截器。那么可以在action里面再引用它即可。

<action name="actionDemo_*" class="com.itheima.action.ActionDemo" method="{1}">
            <!-- 执行这个action,就必然要走名字叫做myInterceptor02的拦截器 -->

            <!-- 使用自定义的拦截器 -->
            <interceptor-ref name="myInterceptor"></interceptor-ref>

            <!-- 使用默认的拦截器 -->
            <interceptor-ref name="defaultStack"></interceptor-ref>

            <result name="login">/index.jsp</result>
</action>

二、 struts标签

其实就是 类似 jstl标签 , 然后把基本的html标签改造…
1)普通标签
2)UI标签

  • struts标签分类

    1. 普通标签

      a)if 和 else标签
      jsp页面:

                <%
                    request.setAttribute("age", 10);
                %>


                <%-- 判断标签 --%>

                 <s:if test="#request.age > 19"> 大于19 </s:if>
                 <s:else>小于19</s:else>
 b)遍历 -- iterator标签
           <%
                List<User> list = new ArrayList<User>();

                list.add(new User("admin1","admin01"));
                list.add(new User("admin2","admin02"));
                list.add(new User("admin3","admin03"));
                list.add(new User("admin4","admin04"));

                request.setAttribute("list", list);
            %>

遍历方式一:

<br> 遍历出来的每一个对象,都放置在栈顶, 我们直接用属性取就可以了。 这里是放置list区域<br>
<s:iterator value="#request.list" >
      <s:property value="username"/>,<s:property value="password"/><br/>
</s:iterator>

遍历方式二:

<br> 遍历出来的每一个对象,都会在context区域放置一个对象 , user . 遍历第一次,这个user执行的对象就是01的对象。<br>
<s:iterator value="#request.list" var="user" >
      <s:property value="username"/>,<s:property value="password"/><br/>
</s:iterator>

<hr/>
<s:iterator value="#request.list"  var="user" status="status">
      <s:property value="#status.count"/>,<s:property value="username"/>,<s:property value="password"/><br/>
</s:iterator>

     c)取值 -- property标签

          <s:property value="username"/>,<s:property value="password"/><br/>
2. UI标签
<s:textfield name="username" label="用户名"/><br/>
<s:textarea name="text" label="个性签名"></s:textarea><br/>
<s:submit value="提交" ></s:submit>
<s:form method="post" action="aaa.ation" >---</s:form>

三、 关于struts的模板和主题

在struts里面的default.property里面,有一个默认的参数:
struts.ui.theme=xhtml
这是struts的主题,struts默认提供了四种主题:默认是xhtml的主体,其他三种是simple,css_xhtml和ajax,要修改主题就需要在struts.xml里面配置常量

<constant name="struts.ui.theme" value="simple"></constant>

四、拓展: 国际化 、文件下载

4.1)国际化 i18n(internationalization)
1)在src下新建两个properties文件 , login_zh_CN.properties , login_en_US.properties
命名规则是: 名字语言国家地区.properties
注意:名字必须一致,只是后面的语言 & 国家可以不同而已。
如何创建properties:建立一个Untitled Text File,然后创建的时候写上后缀名properties

如: login_zh_CN.properties(注意:空格符号的两端不能有空格符号,否则无法解析)

  login.username=用户名
  login.pwd=密码
  login.submit=登录

login_en_US.properties

  login.name=username
  login.pwd=password
  login.submit=submit

2)告诉struts框架,使用这个国际化文件 ,配置手法,可以在struts.properties里面配置
也可以在struts.xml里面配置常量,这里给出的是struts.xml中的配置样例。
struts.custom.i18n.resources这个常量名字可以在default.properties里面找得到

<constant name="struts.custom.i18n.resources" value="login"></constant>

假设我们的项目要对很多个国家都进行国际化,那么都放在src下面,就显得很乱
所以我们可以建一个文件夹来包含他们, 假设文件夹的名字叫做 i18n 那么 常量就应该写成

  <constant name="struts.custom.i18n.resources" value="i18n.login"></constant>
  1. 页面内容如下:
 <a href="demo_test?request_locale=zh_CN">中文</a>
  <a href="demo_test?request_locale=en_US">English</a>

这两个超链接是用来跳转到一个action,让struts 根据提交过去的request_locale 参数值来获取对应的properties文件内容
那个action里面没有什么实质性内容,只要返回success,然后还跳转到这个页面来即可。

  <s:form id="loginform" action="login" method="post">
  <s:textfield name="username" key="login.username"></s:textfield>
  <s:textfield name="psd" key="login.pwd" ></s:textfield>
  <s:submit key="login.submit"></s:submit>
  </s:form>

4.2)文件下载

action写法:

  private FileInputStream stream = null;

  public FileInputStream getStream() {
  return stream;
  }
  public void setStream(FileInputStream stream) {
  this.stream = stream;
  }

  public String download() throws Exception{
     resourceAsStream = ServletActionContext.getServletContext().getResourceAsStream("296822.jpg");
     return SUCCESS;
  }

struts.xml:

 <action name="file_*" class="com.itheima.action.FileAction" method="{1}">
  <result name="success" type="stream">
  <param name="contentType">image/jpeg</param>
  <param name="inputName">resourceAsStream</param>
  <param name="contentDisposition">attachment;filename="document.jpg"        </param>
  <param name="bufferSize">1024</param>
        </result>
  </action>

4.3)返回json数据
记得导入struts-json-plugin-xxx.jar

  public class JsonAction extends ActionSupport {

  private String json;
  public String getJson() {
       return json;
  }
  public void setJson(String json) {
       this.json = json;
  }
  public String register() throws Exception {

  User user = new User();
  user.setUsername("奥巴马");
  user.setPassword("123456");

  json = new Gson().toJson(user);
  return SUCCESS;
  }
  }
 <package name="json" extends="json-default" namespace="/">
  <action name="json_*" class="com.itheima.action.JsonAction" method="{1}">
  <result type="json">
       <param name="root">json</param>
   // 这里的name必须是root 至于这个json 是我们在action里面的成员 变量 json
  </result>
  </action>
  </package>

页面发起请求:

记得导入jquery的库

 <script type="text/javascript">
  $(function() {
  var url = "${pageContext.request.contextPath}/json_register";
  $.post(url , function(result){
  alert("result="+result)
  },"json");
  });
  </script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值