• struts2框架学习之第一天


    day01

    Struts2概述

    1 什么是框架

    试想一下,人与人之间不同之处多,还是相同之处多呢?当然是相同之处多,不同之处少!人都有头,而且头都在脖子上面!

    软件之间也是相同之处多,不同之处少,框架就是把软件中相同的部分抽取出来而形成的。开发人员在框架的基础之上进行开发,那么只需要给出软件独有部分即可。

    软件相同之处称之为应用组件,不同之处称之为业务组件。框架就是已经完成了应用组件这部分的半成品软件。

    应用框架应该具有如下特征:

    1)       已经知道它们在其它程序上工作的很好;(经过良好的测试)

    2)       它们随时可以在下一个项目中使用;(可重用)

    3)       它们可以被组织的其它团队使用;(可扩展)

    2 什么是Struts2框架

    Struts2是MVC框架!使用Struts2可以更好的实现MVC模式。你可能会说,没有Struts2我们在开发时也使用MVC了。没错,但是你想一想:

    l  JSP传递参数给Servlet时,你是不是需要自己把数据再封装到JavaBean中呢?

    l  你是不是在对表单参数进行校验时很不方便呢?

    l  请求参数都是String类型,你需要亲自把String转换成不同的类型;

    l  如果希望Servlet不再转发到a.jsp,而是b.jsp,这是不是需要修改Servlet源代码呢;

    l  你在完成国际化时,是不是感觉到很麻烦呢?

    这些问题由Struts2来帮你处理吧!

    我们已经知道,Struts2是MVC框架,而MVC和Java三层模式又使我们的Java软件分为:页面、控制层、业务层,以及数据层,而Struts2就是处于页面和控制层的框架。

    Struts2、Struts1、JSF、SpringMVC都是MVC框架!

    3 Struts2核心功能

    Struts1是Apache的开源免费框架,也是最早的MVC框架,当时可以说风靡全球!Struts1拥有大量的客户群但是Struts1有自己的缺陷,导致无法再进一步升级!最终Apache决定与WebWork框架合作,即使用WebWork的技术,使用Apache的名字,生成一个新框架,即Struts2!

    所以Struts2基本上与Struts1没有任何关系,Struts2就是一个新的框架,它的内核是WebWork,如果开发人员对WebWork很了解,那么对学习Struts2很有帮助,但如果开发人员只会Struts1,那么学习Struts2就等于学习一个新的框架一样。

    Struts2的内核是WebWork,而WebWork的内核是Xwork,可以在非WEB环境下使用的框架。它的核心功能也就是Struts2的核心了:

    l  类型转换;

    l  输入校验;

    l  上传下载;

    l  拦截器;

    l  国际化;

      Struts2 = Struts名称 + WebWork + 杂七杂八

    4 Struts2处理流程分析

    在JavaWeb中,页面发出请求,由Servlet来做处理。

     

    在所有的MVC框架(包括Struts2)中,都会使用“前端控制器”来接收所有的请求,它会完成所有请求中“共性”的部分(你可以把“共性”的部分想象成编码转换之类的操作),然后再由“前端控制器”通过框架配置文件把请求“分发”给“业务控制器”。

     

    在Struts2中,前端控制器是一个Filter,名为StrutsPrepareAndExecuteFilter。通常它会过滤所有请求,然后完成共性操作,再通过struts.xml文件把请求分发给Action,Action就是Struts2中的业务控制器,等同与JavaWeb中的Servlet。

    前端控制器会接收所有的请求,然后为所有的请求完成共性的部分,再把请求分发给不同的Action对象来处理请求。Action处理的部分是请求中个性的部分!

    前端控制器是怎么找到Action的呢?前端控制器通过请求的URL,去struts.xml配置文件中查找匹配的Action。

    在Struts2中,前端控制器就是一个Filter。我们都知道Filter需要在web.xml文件中进行配置!既然要让前端控制器接收所有请求,那么这个Filter的<url-pattern>就应该是“/*”。

        <filter>

            <filter-name>struts2</filter-name>

            <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>

        </filter>

        <filter-mapping>

            <filter-name>struts2</filter-name>

            <url-pattern>/*</url-pattern>

        </filter-mapping>

    5 下载Struts2

    这东西自己回去到http://struts.apache.org/去下载吧。我们已经下载了Sturts2的2.3.x版本,下面我们来了解一下struts2的目录结构。

    l  apps:官方的demo

    l  docs:文档

    l  lib:jar包

    l  src:源代码

    其实在开发中,我们不需要把lib下的所有jar包都导入到项目中。

    去apps目录下找到blank.war,然后使用解压缩软件打开它,把WEB-INFlib目录下的jar包copy出来,我们的项目中只需要这些jar包即可

    6 Hello Struts2
    1. 搭建Struts2项目的开发环境

    创建项目,把Struts2所需jar包导入到项目中。

    这里只需要专稿blank.war中的jar包即可。

     

    创建Struts2的配置文件,在src目录下创建struts.xml文件。

    因为配置文件都需要有一个头,即dtd等信息,所以我们最后去blank.war中找到classes下的struts.xml文件,把内容copy过来,然后再把其中的无用信息删除,只留下根元素<struts>,以及<package>元素。

    <?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="default" namespace="/" extends="struts-default">

        </package>

    </struts>

    1. 功能分析

    在index.jsp页面中访问hello.action(Struts2默认处理扩展名为action的请求)路径,转发到result.jsp页面。其中hello.action对应HelloAction类,再由HelloAction把请求转发到result.jsp页面。

    1. 创建index.jsp和result.jsp

      <body>

    <h1>主页</h1>

    <a href="<c:url value='/hello.action'/>">访问Struts2的Action</a>

      </body>

      <body>

    <h1>结果页面</h1>

      </body>

    1. 在web.xml文件中配置“前端控制器”

    前端控制器类是由Struts2提供的,它是一个Filter,我们只需要在web.xml文件中配置这个Filter即可,其他什么都不用做。

      <filter>

        <filter-name>struts</filter-name>

        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>

      </filter>

      <filter-mapping>

        <filter-name>struts</filter-name>

        <url-pattern>/*</url-pattern>

      </filter-mapping>

    1. 编写struts.xml配置文件

    前面我们已经讲过了,前端控制器会去完成“共性”的部分,然后通过struts.xml文件中的配置信息找到被请求的Action,然后把请求分发给这个Action来处理“个性”部分。

    <?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="default" namespace="/" extends="struts-default">

            <action name="hello" class="cn.itcast.demo1.action.HelloAction"></action>

        </package>

    </struts>

    在配置文件中,我们在<package>元素中添加一个<action>元素,我们需要指定<action>元素的两个属性:

    l  name:与访问路径对应,在index.jsp中的<a>元素中我们访问的是/hello.action路径,所以在name属性指定的值也要是hello.action,但这里不能带有扩展名,所以name=”hello”;

    l  class:指定用来处理请求的Action类。

    1. 编写请求处理类:HelloAction

    HelloAction不需要去继承或实现什么东西,但Struts要求Action必须要有请求处理方法,请求处理方法的格式为:public String execute(),即没有参数,返回值类型为String。返回逻辑视图,逻辑视图只是一个字符串,它需要有对应的物理视图。

    HelloAction.java

    package cn.itcast.demo1.action;

     

    public class HelloAction {

        public String execute() {

            System.out.println("Hello Sturts2...");

            return "succ ";

        }

    }

    1. 指定结果页面

    execute()方法的返回值可以随意给出,这里给出的返回值为“succ”,我们需要在struts.xml文件中把“succ”与返回的结果页面绑定到一起。

    <struts>

        <package name="default" namespace="/" extends="struts-default">

            <action name="hello" class="cn.itcast.demo1.action.HelloAction">

                <result name="succ">/result.jsp</result>

            </action>

        </package>

    </struts>

     这里定义了一个视图,其中succ是逻辑视图,与execute()方法的返回值相同。/result.jsp是物理视图,即真实的页面。

    OK,现在我们已经完成了这个Hello World项目。请在index.jsp页面中点击链接,查看结果吧。注意查看控制台上是否有输出。

    l  搭建环境:

    • 导包:struts2安装包appslank.warlib下所有包
    • 部署前端控制器:web.xml中配置过滤器:StrtusPrepareAndExecuteFilter
    • Struts2的配置文件:src下创建struts.xml

    l  请求三步

    • 超链接指向Action:要求请求URL的后缀是.action;
    • Action类的请求处理方法签名:public String execute();
    • struts.xml文件中配置请求url和Action的联系:<action name=”xxx” class=””/>;
    7 MyEclipse中配置Struts的DTD

      在使用MyEclipse开发环境时,我们在struts.xml文件中可以使用Alt+/来做补全,这是因为在xml文档中指定的DTD的原因。

    大家也可以看出来,这个dtd只有在连网时才能找到,如果你现在没有网可用,那么这个dtd可能就无法找到,这时你的alt + /可能就会“不听话”了。

    如果你需要在没有连网时也可以找到dtd文档,那么就需要在MyEclipse中进行配置。其实在我们下载的Struts2安装包的struts-2.3.7srccoresrcmain esourcesstruts-2.3.dtd路径下已经存在了这个DTD文档,我们只需要在MyEclipse中导入它即可。

     

    8 MyEclipse中导入Struts2源代码

    导入Struts2的源代码!

    选择一个Struts2中的类,然后点击

    点击Attach Source按钮

    点击External File,选中我们下载的Struts2安装包,然后点击OK按钮即可。

    9 Struts2流程图

     

    现在我们不需要把这张图全面了解了,我们现在只需要知道Struts2中完成请求的“共性”部分的组件是Interceptor(拦截器),它会在每个Action之前执行!

    Struts2中的系列拦截器我们会在后面来讲,今天先不讲,但你要知道,Interceptor就是对Action的增强。它是Struts2的核心部分!

    Struts2的基本配置

    1        Struts2的基本配置文件

    在学习Struts2时,你会感觉到Struts2的配置文件多的很!但其实真正重要的配置文件没有几个,现在对我们来说,只有一个配置文件很重要,它就是struts.xml。

    下面是Struts2配置文件,以优先级由低到高的顺序给出:

    l  default.properties:这个文件在struts-core.jarorg.apache.struts2default.properties位置,它内部是常量的默认值,我们不会去修改它;

    l  struts-default.xml:这个文件在struts-core.jarstruts-default.xml位置,它内部定义了拦截器、结果类型,以及bean。我们也不会去修改它;

    l  struts-plugin.xml:在安装插件时,插件的jar包中需要带有这个文件,我们也不会去修改它;

    struts.xml:这个文件不是默认存在的,而是需要我们自己在src目录下创建的,它是我们通常要编写的配置文件,最为重要!

    struts.properties:这个文件也不是默认存在的,也是需要在src目录下创建的,这个文件中用来配置常量,但是建议大家还是在strtus.xml文件中配置常量,而不是这个文件中,所以它也使用的比较少;

    web.xml:这个文件大家再熟悉不过了,也可以在这个文件中配置常量,但也不建议在这里去配置。但这个文件中配置的常量优先级最高!

    6个配置文件中前3个是配置自带的,我们不会去修改,后3个中2个是不建议去使用的,所以最为重要的就只有struts.xml文件一个。

    这里需要注意,后加载的文件优先级最高,也就是说在web.xml文件中配置的常量优先级最高。

    2        struts.xml入门
    <struts>
    
        <!--
    
        0~N个常量配置
    
        name: 常量名
    
        value: 常量值
    
        -->
    
        <constant name="struts.devMode" value="true" />
    
        <!--
    
        0~N个package
    
        name: 包名随便起,但必须是唯一名称
    
        namespace: 请求URL的前缀,例如当请求路径为/a/b/hello.action时,那么namespace应该为/a/b
    
        extends:指定父包!通常都是指定struts-default这个父包。父包中定义的东西等同于定义在当前包中。
    
         -->
    
        <package name="s1" namespace="/" extends="struts-default">
    
             <!--
    
            默认Action:在找不到请求的Action时,执行的Action。与404的友好页面相同
    
            name:指定<action>元素的name属性值。
    
             -->
    
             <default-action-ref name="error" />
    
            <!--
    
            默认Action处理类:对于<action>元素而言,它的class属性是可选的!
    
            在没有指定class时,执行的Action类为默认Action处理类。
    
            例如:<action name="xxx">时,其class默认为ActionSupport
    
            其实我们不指定<default-class-ref>默认也是ActionSupport,这是因为在
    
            父包struts-default中已经定义过<default-class-ref>元素了。
    
             -->
    
             <default-class-ref class="com.opensymphony.xwork2.ActionSupport" />
    
            <!--
    
            配置Action
    
            name:Action的配置名称,没有后缀.action。与namespace共同定位请求URL
    
            class:请求处理Action类。默认值由<default-class-ref>来指定。
    
            -->
    
            <action name="hello" class="cn.itcast.action.HelloAction">
    
                <!--
    
                结果处理类
    
                name:execute()方法返回的字符串匹配。默认值为success
    
                    内容:物理路径。即真实的页面路径!
    
                -->
    
                <result name="success">/demo1/hello.jsp</result>
    
             </action>
    
             <action name="error">
    
                <result>/error.jsp</result>
    
             </action>
    
        </package>
    
    </struts>

    2.1 <package>元素

    首先说一下struts.xml文件的基本结果,根元素是<struts>,在<struts>元素下可以有多个<package>元素,在<package>元素中可以配置多个<action>元素。

    对于<struts>元素,我们没有什么可说的,它就是struts.xml文件的根元素而已!

    <package>元素中可以存在多个<action>元素,在<package>元素中的配置会作用到它内部的所有<action>中,但你千万不要认为它与Java类中的package cn.itcast有什么关系!!!<package>只是一个XML元素,与Java类没什么关系。

    <package>中不只是可以<action>,还可以包含拦截器的定义,以及结果类型的定义!

    <package>元素有3个重要的属性:

    l  name:这个名字可以随便起,只要与其它<package>的name不相同即可;

    l  namespace:名称空间!通常该值为“/”,如果希望指定namespace也要以“/”开头。它与<action>的name属性共同决定访问路径。例如namespace的值为/admin,某个<action>的name为hello,那么在浏览器中访问这个Action时就需要使用/admin/hello.action来访问;

    l  extends:指定当前包的父包,用来继承父包中的东西。通常我们会去继承struts-default这个包,因为struts-default中定义了很多拦截器,以及结果类型,我们自定义的<package>就不用再去定义,而是直接继承过来。struts-default包在struts-default.xml文件中定义。

    2.2 <action>元素

    <action>元素最为重要的有两个属性:

    l  name:用来指定当前<action>的名字,它与<package>的namespace来共同决定当前Acton的访问路径;

    l  class:用来指定当前<action>的类型。

    <package namespace=”/” …>

      <action name=”foo” …/>

    <package>

    这个action foo的访问路径为:/foo.action;

    <package namespace=”/admin” …>

      <action name=”foo” …/>

    <package>

    这个action foo的访问路径为:/admin/foo.action

    当访问路径为/a/b/c/foo.action时,Struts2会按下面的顺序去查找Action

    l  查询namespace=”/a/b/c”,<actoin name=”foo”>的Action

    <package namespace=”/a/b/c” …>

      <action name=”foo” …/>

    <package>

    l  查询namespace=”/a/b”,<action name=”foo”>的Action

    <package namespace=”/a/b” …>

      <action name=”foo” …/>

    <package>

    l  查询namespace=”/a”,<action name=”foo”>的Action

    <package namespace=”/a” …>

      <action name=”foo” …/>

    <package>

    l  查询namespace=”/”,<action name=”foo”>的Action

    <package namespace=”/” …>

      <action name=”foo” …/>

    <package>

    l  查询namespace=””,<action name=”foo”>的Action

    <package namespace=”” …>

      <action name=”foo” …/>

    <package>

     <package>的namespace的默认值为””,在其它名称空间不存在时,会去””名称空间下去查找Action。

    2.3 <action>默认处理类

    <action>元素的class属性也有默认值:com.opensymphony.xwork2.ActionSupport,也就是说在没有给<action>元素指定class属性时,会执行ActionSupport类的execute()方法。也就是说,ActionSupport就是<action>的默认处理类!!!

    查看ActionSupport源代码可以知道,它的execute()方法返回值为”success”,所以这时你需要为<action>元素添加<result name=”success”>子元素!

    <action name=”hello”>

      <result name=”success”>/index.jsp</result>

    </aciton>

    其实每个<package>元素都可以指定一个<default-class-ref class=”…”/>元素,该元素的class指定的就是<action>的class的默认值。因为我们的<package>没有指定<default-class-ref>元素,所以是从父包sturts-default处继承而来,可以查看struts-default.xml文件中的<default-class-ref>元素的class指定的就是com.opensymphony.xwork2.ActionSupport。

    下面代码中,没有为<action>指定class属性值,但因为指定了Action默认值为HelloAction,所以就会访问HelloAction。

    <struts>

        <package name="b" namespace="/" extends="struts-default">

           <default-class-ref class="cn.itcast.demo1.action.HelloAction" />

            <action name="hello">

                <result name="succ">/result.jsp</result>

            </action>

        </package>

    </struts>

    2.4 默认<action>

    默认<action>需要<default-action-ref name="">来指定,通常用户在访问一个不存在的<action>时会报404,我们可以通过<default-action-ref name="">来指定默认的<action>,这样在用户访问不存在的路径时,就会去访问默认<action>。

    默认<action>是用来代替404页面的!

    <struts>

        <package name="b" namespace="/" extends="struts-default">

            <default-action-ref name="error"></default-action-ref>

            <action name="error">

                <result name="success">/404.jsp</result>

            </action>

        </package>

    </struts>

    注意,默认<action>与<action>默认处理类的区别:

    l  默认<action>:当用户访问一个不存在的路径时,会执行默认<action>;

    l  <action>默认处理类:当<action>没有指定class属性时,执行默认的处理类。

    2.5 <result>元素的name属性默认值

    <result>元素的name属性默认值为success,也就是说:

    <result>/index.jsp</result>

    等同于

    <result name=”success”>/index.jsp</result>

    3 Struts2常量

    Struts2常量就是给Struts2使用的一些参数,以键值对的形式出现。

    1. Struts2常量都配置在哪里?

    Struts2默认常量都是在default.properties中配置的,你可以打开这个文件看看!你会发现常量真的很多,我们不需要去背!

    1. 我们在哪里配置常量

    最佳位置:struts.xml文件中,在struts.xml文件中配置常量需要使用<constant>元素

    <struts>

        <constant name="struts.devMode" value="true" />

        …

    </struts>

    其次是struts.properites文件,你可以在src下创建struts.properites文件,在这里来创建常量,我们已经知道它的优先级高与struts.xml文件。

    最后的位置是web.xml文件中,即给<filter>元素添加<init-param>子元素,通常我们不会在这里配置常量。

    1. 常用常量了解一下:

    l  struts.i18n.encoding=UTF-8:相当于调用request.setCharacterEncoding(“utf-8”),即对POST请求做编码处理,但不包括GET请求;

    l  struts.action.extension=action,,:前端控制器会接收所有请求,但只有action后缀的请求才会分发给Action来处理,这时因为struts.action.extension指定了分发给action的后缀为action。也可以指定多种后缀名,然后用逗号分隔!大家仔细观察,struts.action.extension常量的值是“action,,”,后面有两个逗号,这表示后缀为action的请求,以及没有后缀的请求都会分发给action!如果你在struts.xml文件中指定:<constant name=” struts.action.extension” value=”action”/>,那么无后缀的请求就不会分发给actoin了;

    l  struts.serve.static.browserCache=false:该常量的值为false时,表示让浏览器不缓存,如果为true表示让浏览器缓存,在开发阶段,该常量通常设置为false;

    l  struts.devMode=true:该常量为true时,表示为开发模式,开发模式下Struts2会在修改了配置文件后无需重启Tomcat,而是自动加载,而且还会在出错时在页面提供详细的错误信息。

    4 Struts2配置文件分离

    在项目开发过程中,struts.xml文件的内容会越来越多,这时struts.xml就会变得勿阅读,这时我们希望可以把struts.xml文件分成多个配置文件!

    可以在struts.xml文件中使用<include>元素来包含其他配置文件:

    <struts>

        <include file="struts-part1.xml" />

        <include file="struts-part2.xml" />

        …

    </struts>


    Actoin处理请求

    1        Action的三种书写方式

    我们必须遵守Struts2对Action的要求,Struts2给出三种对Action的书写方法:

    l  无耦合(POJO);

    l  实现Action接口;

    l  继承ActionSupport。

    1.1 无耦合方式(POJO)

    Action可以是一个POJO,即不继承,也不实现类的普通Java类。但是要求Action必须要有一个execute()方法:

    l  访问修饰为public;

    l  返回值为String;

    l  名称为execute;

    l  没有参数的。

    这种方式用的很少,但我们要知道这种方式的存在!

    1.2 实现Action接口

    让我们的Action去实现com.opensymphony.xwork2.Action接口。

    package com.opensymphony.xwork2;

     

    public interface Action {

        public static final String SUCCESS = "success";

        public static final String NONE = "none";

        public static final String ERROR = "error";

        public static final String INPUT = "input";

        public static final String LOGIN = "login";

       

        public String execute() throws Exception;

    }

    这个类只给出一个方法,即execute()方法,这说明在实现Action接口后,如果没有给出execute()方法就会编译出错。这与第一种方式使用POJO不同,如果在使用POJO时没有给出execute()方法,那是不会编译出错的,而是在运行时会报错,说找不到execute()方法。

    Action接口中还提供了5个字符串常量,这5个常量用来作为execute()方法的返回值。这也是开发中最为常见的5种逻辑视图。

    l  SUCCESS:表示成功;

    l  NONE:不跳转,与return null相同;

    l  ERROR:表示出错,对应的物理视图应该是用来显示错误信息的;

    l  INPUT:表示表单数据的输入有错误,对应的物理视图应该是表单页面;

    l  LOGIN:表示访问了受限资源,需要登录后才能访问,对应的物理视图应该是登录页面。

      其实你不使用这些常量也一样,只要把<result>元素配置好即可。当然,这些Action常量地球人都认识,如果你的逻辑视图名称为a,它对应的物理视图为a.jsp,那么谁知道你是在表示什么啊。

      这种方式同样使用的很少,但我们要知道这种方式的存在!

    1.3 继承ActionSupport类

    这是最后一种编写Action的方式,也是我们最后最为常用的方式。让我们的Action类去继承com.opensymphony.xwork2.ActionSupport类。ActionSupport类实现了Action接口,我们的Action需要去覆盖ActionSupport的execute()方法。

    继承ActionSuppot类的好处:

    l  输入校验;

    l  错误信息的设置;

    l  获取国际化信息。

    2 Action的请求处理方法

    上面讲解了三种Action的书写方式,即Struts2如何找到Action类。下面要讲解的是Struts2如何找到Action中请求处理方法。

    2.1 指定请求处理方法名称

    上面我们已经了解到Action的请求处理方法名称为execute,其实这只是默认的请求处理方法的名称。也就是说Struts2允许我们来指定请求方法名称。这需要在<action>元素的method属性中指定请求处理方法的名称。

    当没有指定<action>元素的method属性时,那么请求处理方法名称为execute()。在指定method属性的值时,那么请求处理方法的名称就是method属性的值。

    但要注意,无论请求处理方法的名称是什么,返回值必须是String,而且不能有任何参数。

      <body>

        <a href="<c:url value='/Order_add.action'/>">添加订单</a><br/>

        <a href="<c:url value='/Order_mod.action'/>">修改订单</a><br/>

        <a href="<c:url value='/Order_del.action'/>">删除订单</a><br/>

      </body>

        <package name="s3" namespace="/" extends="struts-default">

            <action name="Order_add" class="cn.itcast.test.action.OrderAction" method="add[崔6] ">

                <result>/index.jsp</result>

            </action>

            <action name="Order_mod" class="cn.itcast.test.action.OrderAction" method="mod[崔7] ">

                <result>/index.jsp</result>

            </action>

            <action name="Order_del" class="cn.itcast.test.action.OrderAction" method="del[崔8] ">

                <result>/index.jsp</result>

            </action>

        </package>

    public class OrderAction extends ActionSupport {

        public String add() {

            System.out.println("add()");

            return SUCCESS;

        }

        public String mod() {

            System.out.println("mod()");

            return SUCCESS;

        }

        public String del() {

            System.out.println("del()");

            return SUCCESS;

        }

    }

    2.2 使用通配符减少<action>的配置

    通过指定<action>元素的method可以减少Action的个数,这样我们可以在一个Action中提供多个请求处理方法。但是,并没有减少<action>元素的配置个数。对每个请求我们都需要配置一个<action>元素。

    下面我们来使用通配符来减少<action>元素的配置。通配符就是“*”,它只能出现在<action>元素的name中。例如:

    <action name=”ABC*” …>

    这说明请求路径只要是以ABC开头,那么都会通过这个<action>。例如请求路径为:

    l  /ABChelllo.action,其中通配符匹配的是hello;

    l  /ABCworld.action,其中通配符匹配的是world;

    我们还可以在<action>元素的其他属性,或子元素中使用通配符匹配的文本,例如{!}表示通配符匹配的文本。

    <action name=”Order_*” class=”cn.itcast.action.OrderAction” method=”{1}”>

    当请求路径为“/Order_add.action”时,通配符匹配的文本就是add,而在method中的{1}表示通配符匹配的文本,即“add”。

    当请求路径为“/Order_mod.action”时,通配符匹配的文本就是mod,而在method中的{1}表示通配符匹配的文本,即“mod”。

    我们来修改2.1中的订单例子,只需要修改struts.xml文件中的配置,其他地方无需修改。

        <package name="s3" namespace="/" extends="struts-default">

            <action name="Order_*" class="cn.itcast.test.action.OrderAction" method="{1}">

                <result>/index.jsp</result>

            </action>

        </package>

    其中在<action>的name属性中可以使用多个通配符,即多个“*”,然后在method或class中可以使用{1}、{2}、…,其中{1}表示第一个通配符配置的文本,{2}表示第二个通配符配置的文本。

    我们再次来修改<action>的配置:

            <action name="*_*" class="cn.itcast.test.action.{1}Action" method="{2}">

                <result>/index.jsp</result>

            </action>

    当请求路径为“/Order_add.action”时,第一个通配符匹配的文本为Order,第二个通配符匹配的文本是add,所以{1}表示Order,而{2}表示add。即class指定的类为OrderAction,而method指定的方法是add方法。

    使用这种配置,我们甚至可以使用一个<action>就OK了!

    当请求路径为“/User_regist.action”时,第一个通配符匹配的文本是User,第二个通配符匹配的文本是regist,那么这就说明请求的是UserAction的regist方法。

    2.3 动态调用请求处理方法

    Struts2还提供了动态调用请求处理方法的方式,这种方式需要在请求路径中使用感叹号(!),然后在感叹号后给出要调用的方法:“/OrderAction!add.action”。这时在<action>元素中无需再指定method属性。

      <body>

        <a href="<c:url value='/OrderAction!add.action'/>">添加订单</a><br/>

        <a href="<c:url value='/OrderAction!mod.action'/>">修改订单</a><br/>

        <a href="<c:url value='/OrderAction!del.action'/>">删除订单</a><br/>

      </body>

            <action name="OrderAction" class="cn.itcast.test.action.OrderAction">

                <result>/index.jsp</result>

            </action>

    public class OrderAction extends ActionSupport {

        public String add() {

            System.out.println("add()");

            return SUCCESS;

        }

        public String mod() {

            System.out.println("mod()");

            return SUCCESS;

        }

        public String del() {

            System.out.println("del()");

            return SUCCESS;

        }

    }

    注意,这种方式需要开启动态请求调用对应的常量,这个常量的默认值可以在default.properties文件中找到:

      也就是说,默认Struts2是开启了动态请求方法调用的。

    Action与Servlet API

    1 Action中3种获取Servlet API方式

    l  ActionContext解耦方式获取Servlet API;

    l  通过感知接口获取Servlet API;

    l  ServletActionContext的静态方法获取Servlet API

    2 ActionContext解耦方式获取Servlet API

    首先需要获取ActionContext对象:ActionContext ac = ActionContext.getContext();

    1. 获取请求参数

    Map<String,Object> params = ac.getParameters();

    其中params中的数据就是请求参数,它等同与request.getParameterMap()。

    需要注意的是,返回的Map中键是字符串,而值其实是String[]类型。下面是获取参数username的值:

    String[] value = (String[])params.get(“username”);

    String username = value[0];

    1. 在request域中存取数据

    ac.put(“aa”, “aa”);//等同与request.setAttribute(“aa”,”aa”)

    String s = (String)ac.get(“aa”);//等同与request.getAttribute(“aa”)

    在页面中可以使用EL表达式来获取这个值:${requestScope.aa}

    1. 在session域中存取数据

    Map<String,Object> sessionMap = ac.getSesson();

    sessionMap.put(“aa”,”aa”);//等同与session.setAttribute(“aa”, “aa”);

    String s = (String)sessionMap.get(“aa”);//等同与session.getAttribute(“aa”)

    在页面中可以使用EL表达式${sessionScope.aa}来获取这个值

    1. 在application域存取数据

    Map<String,Object> appMap = ac.getApplication();

    appMap.put(“aa”,”aa”);//等同与application.setAttribute(“aa”,”aa”);

    String s = (String)appMap.get(“aa”);//等同与application.getAttribute(“aa”)

    在页面中可以使用EL表达式${applicationScope.aa}来获取这个值

      请注意,这种解耦方式只能对三个域对象进行存取数据的操作,如果你想调用request.getContextPath()方法,这是不可能的,也不能application.getRealPath()。如果你不知道使用这些操作,那么使用第一种方式是灰常理想的选择!因为你根本就看不到Servlet API,解耦已经到了最佳境界。

        public String execute() throws Exception {

            ActionContext ac = ActionContext.getContext();

           

            Map<String,Object> paramMap = ac.getParameters();

            String username = ((String[])paramMap.get("username"))[0];

            System.out.println(username);

           

            ac.put("aa", "aa");

            String s = (String) ac.get("aa");

            System.out.println(s);

           

            Map<String,Object> sessionMap = ac.getSession();

            sessionMap.put("aa", "aa");

            s = (String) sessionMap.get("aa");

            System.out.println(s);

           

            Map<String,Object> appMap = ac.getApplication();

            appMap.put("aa", "aa");

            s = (String) appMap.get("aa");

            System.out.println(s);

            return SUCCESS;

        }

    3 通过感知接口获取Servlet API

    Struts2提供了三个感知接口,Actoin可以去实现它们来获取Servlet API。

    l  ServletContextAware – setServletContext(ServletContext context);

    l  ServletRequestAware – setServletRequest(HttpServletRequest req);

    l  ServletResponseAware – setServletResponse(HttpServletResponse res)。

    当Action实现了感知接口后,Struts2会在创建Action对象后,调用感知方法把Servlet API传递给Action。也就是说,在请求处理方法执行之前,已经把Servlet API传递给了Action,所以在请求处理方法中使用Servlet API是没有问题的。

    public class AwareAction extends ActionSupport

            implements ServletContextAware,

            ServletRequestAware, ServletResponseAware {

        private ServletContext context;

        private HttpServletRequest request;

        private HttpServletResponse response;

     

        public void setServletContext(ServletContext context) {

            this.context = context;

        }

        public void setServletRequest(HttpServletRequest request) {

            this.request = request;

        }

        public void setServletResponse(HttpServletResponse response) {

            this.response = response;

        }

    }

      这种方式比较麻烦,所以很少被使用!

    4 ServletActoinContext获取Servlet API

    这种方式比较直接,可以直接通过ServletActionContext类的静态方法获取到Servlet API。当然,这种方式也会与Servlet API耦合在一起。

    HttpServletRequest request = ServletActionContext.getRequest();

    HttpServletResponse response = ServletActionContext.getResponse();

    ServletContext context = ServletActionContext.getServletContext();

      这种方式最为方便。所以也是最为常用的方式,第一种解耦方式也是很好,所以也很常用。

    Action返回值与<result>

    1 全局结果和局部结果

    在<action>中可以配置<result>元素,其中在<package>元素的<global-results>元素中也可以配置<result>。其中<action>中的<result>是局部结果,只有当前<action>自己可以使用,而在<global-results>中配置的<result>是全局结果,可以供当前<package>中所有的<action>使用。

        <package name="test" namespace="/" extends="struts-default">

        <global-results>

            <result name="a">/a.jsp</result>

        </global-results>

            <action name="MyAction1" class="cn.itcast.test.action.MyAction1">

                <result name="success">/my1/index.jsp</result>

            </action>

            <action name="MyAction2" class="cn.itcast.test.action.MyAction2">

                <result name="success">/my2/index.jsp</result>

            </action>

        </package>

      当局部和全局的<result>同名时,局部的<result>优先。

    2 结果类型

    <result>元素的type属性用来指定结果类型!如果没有指定type时,默认为dispatcher,下面介绍4种常用的结果类型:

    l  dispatcher:默认值,表示转发到页面;

    l  chain:表示转发到另一个Action,所以这时<result>元素的内容需要是另一个<action>的名字;

    l  redirect:表示重定向到页面;

    l  redirectAction:表示重定向到另一个Action。

    <result>/index.jsp</result>

    等同于

    <result type=”dispatcher”>/index.jsp</result>

    等同于

    <result type=”dispatcher” name=”success”>/index.jsp</result>

    其实结果类型都是在struts-default.xml文件中定义的。

    <result-types>

    <result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/>

    <result-type name="dispatcher" class="org.apache.struts2.dispatcher.ServletDispatcherResult" default="true"/>

    <result-type name="freemarker" class="org.apache.struts2.views.freemarker.FreemarkerResult"/>

    <result-type name="httpheader" class="org.apache.struts2.dispatcher.HttpHeaderResult"/>

    <result-type name="redirect" class="org.apache.struts2.dispatcher.ServletRedirectResult"/>

    <result-type name="redirectAction" class="org.apache.struts2.dispatcher.ServletActionRedirectResult"/>

    <result-type name="stream" class="org.apache.struts2.dispatcher.StreamResult"/>

    <result-type name="velocity" class="org.apache.struts2.dispatcher.VelocityResult"/>

    <result-type name="xslt" class="org.apache.struts2.views.xslt.XSLTResult"/>

    <result-type name="plainText" class="org.apache.struts2.dispatcher.PlainTextResult" />

    </result-types>

    登录练习

    1 页面

    /user/login.jsp

    /user/succ.jsp

    2 UserAction

    public String login()

    3 struts.xml
    4 需要用到的方法及标签

    ActionSupport方法介绍:

    l  addFieldError(String fieldName,String msg):添加字段错误信息;

    l  addActionError(String msg):添加Action错误信息;

    l  addActionMessage(String msg):添加Action信息。

    标签介绍:

    l  <s:fielderror>:获取字段错误信息;

    l  <s:actionerror>:获取Action错误信息;

    l  <s:actionmessage> :获取Action信息。


    在Struts2中,访问Action时,路径的扩展名默认为action。

    前端控制器过滤所有的请求。

    name属性的值必须与访问路径相同,但要去掉扩展名action。

    返回逻辑视图,逻辑视图只是一个字符串,它需要有对应的物理视图。

    这里定义了一个视图,其中succ是逻辑视图,与execute()方法的返回值相同。/result.jsp是物理视图,即真实的页面。

    请求处理方法名称为add

    请求处理方法名称为mod

    请求处理方法名称为del

  • 相关阅读:
    mingw-gcc-10.0.1-experimental-i686-posix-sjlj-20200202-0303907
    可以修改 QtScrcpy 窗口大小的小工具
    autosub 添加代理服务器参数 -P --proxy
    Python网络数据采集系列-------概述
    【刷题笔记】I'm stuck! (迷宫)-----java方案
    【刷题笔记】火车购票-----java方案
    mvc自定义全局异常处理
    使用html2canvas实现浏览器截图
    再谈Newtonsoft.Json高级用法
    Spire.Doc组件读取与写入Word
  • 原文地址:https://www.cnblogs.com/xyhero/p/9348681.html
Copyright © 2020-2023  润新知