Struts2 课程笔记(1)

来源:互联网 发布:手机打开mobi软件 编辑:程序博客网 时间:2024/06/05 04:27

Struts2课程笔记

一:struts2第一天

1:模拟struts2的底层转发原理servlet

第一步:创建web工程

第二步:定义test.jsp,我们的目的实现3URL链接的转发

第三步:创建一个Servlet测试地址的转发,在web.xml中定义

第四步:创建一个Servlet的类,处理转发到指定页面的操作

缺点:这样做的缺点就是是,每个URL都会在web容器中配置,能否实现在web容器中只配置一次,就可以实现以上3URL都可以跳转到指定的页面呢?

结论:可以使用过滤器实现

第一步:在web容器中定义过滤器

第二步:创建一个接口Action,用来实现对多个Action的多态

同时创建3Action的类,实现这个Action接口,可以操作同一个execute的方法

1UserAction

2HelloAction

3CustomerAction

 

这里大家注意:他们的类是UserActionHelloActionCustomerAction,对应的返回值分别是:successerroradd

第三步:创建一个过滤器实现,url链接和每个类之间的跳转,以及类的返回值跳转到指定页面的配置:

publicclass TestFilterimplements Filter {

   

    //使页面访问的路径找到对应的Action

    private Map<String, String> actionMap = new HashMap<String, String>();

    //使用Action类中返回值对应访问的页面

    private Map<String, String> returnMap = new HashMap<String, String>();

    /**web容器启动时初始化*/

    publicvoid init(FilterConfig config)throws ServletException {

        actionMap.put("/userAction.action","cn.itcast.action.UserAction");

        actionMap.put("/helloAction.action","cn.itcast.action.HelloAction");

        actionMap.put("/customerAction.action","cn.itcast.action.CustomerAction");

       

        returnMap.put("success","/success.jsp");

        returnMap.put("error","/error.jsp");

        returnMap.put("add","/add.jsp");

    }

   

    publicvoid doFilter(ServletRequest req, ServletResponse res,

            FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;

        HttpServletResponse response = (HttpServletResponse) res;

        //获取页面访问连接,

        String path = request.getServletPath();//--/userAction.action

        if(path!=null && path.equals("/test.jsp")){

            chain.doFilter(request, response);

            return;

        }

        try {

            //获取访问的Action类的路径

            String actionClass = actionMap.get(path);

            //使用Action类的路径,并用java反射机制,获取Action

            Action action = (Action) Class.forName(actionClass).newInstance();

            //执行Action类的方法

            String returnValue = action.execute();

            //利用Action类的返回值,获取所对应的页面

            String page = returnMap.get(returnValue);

            //转发到对应的页面

            request.getRequestDispatcher(page).forward(request, response);

        } catch (Exception e) {

            e.printStackTrace();

        }

    }

 

    publicvoid destroy() {

       

    }

 

}

 

 

总结:struts2的原理:

 

2struts2的概述

为什么要学习struts2呢?

Struts2 是一个用来开发 MVC应用程序的框架.提供了 Web 应用程序开发过程中的一些常见问题的解决方案:       

         页面导航活动进行管理

         对来自用户的输入数据进行合法性验证

         统一的布局

         可扩展性

         国际化和本地化

         支持Ajax

         表单的重复提交

        

附录:struts2相对于struts1的优点,大家学完struts2后可以了解下

 

struts1一样, Struts2也都是属于MVC框架。不过有一点大家需要注意的是:虽然Struts2struts1在名字上差别不大,但Struts2编码模式与struts1几乎可以说是不一样的。那么既然有了struts1,为何还要推出struts2。主要是因为struts2有以下优点:

1 >在软件设计上Struts2没有像struts1那样跟Servlet APIstruts API有着紧密的耦合,Struts2的应用可以不依赖于Servlet APIstruts API Struts2的这种设计属于无侵入式设计,而Struts1却属于侵入式设计。

public class OrderListAction extends Action {

       public ActionForward execute(ActionMapping mapping, ActionForm form,

              HttpServletRequest request, HttpServletResponse response)

                     throws Exception {

       }

}

2> Struts2提供了拦截器,利用拦截器可以进行AOP编程,实现如权限拦截等功能。

3> Strut2提供了类型转换器,我们可以把特殊的请求参数转换成需要的类型。在Struts1中,如果我们要实现同样的功能,就必须向Struts1的底层实现BeanUtil注册类型转换器才行。

4> Struts2提供支持多种表现层技术,如:JSPfreeMarkerVelocity

5> Struts2的输入校验可以对指定方法进行校验,解决了Struts1长久之痛。

6>提供了全局范围、包范围和Action范围的国际化资源文件管理实现

 

Struts2从本质上讲已不是从 Struts1 扩展而来, 说它是一个换了品牌标签的 WebWork更合适

Struts1升级到 Struts2:

l         Struts1 里使用 ActionServlet 作为控制器; Struts2 使用了一个过滤器作为控制器

l         Struts1 中每个 HTML 表单都对应一个 ActionForm实例. Struts2 , HTML表单将被直接映射到一个 POJO.

l         Struts1 的验证逻辑编写在 ActionForm ; Struts2 中的验证逻辑编写在 Action.

l         Struts1 , Action 类必须继承 org.apache.struts.action.Action; Struts2 中任何一个 POJO都可以是一个 Action .

l         Struts2 在页面里使用 OGNL来显示各种对象模型, 可以不再使用 EL JSTL

 

 

3struts2的入门

搭建struts2环境时,我们一般需要做以下几个步骤的工作:

第一步:创建javaweb工程

 

第二步:找到开发Struts2应用需要使用到的jar文件.

http://struts.apache.org/download.cgi#struts2014下载struts-2.x.x-all.zip,我们使用版本为2.3.3。下载完后解压文件,开发struts2应用需要依赖的jar文件在解压目录的lib文件夹下。不同的应用需要的JAR包是不同的。下面给出了开发Struts 2程序最少需要的JAR

   struts2-core-2.3.3.jarStruts 2框架的核心类库

   xwork-core-2.3.3.jarCommand模式框架,WebWorkStruts2都基于xwork

   ognl-3.0.5.jar             对象图导航语言(Object Graph Navigation Language),

                           struts2框架通过其读写对象的属性

   freemarker-2.3.19.jarStruts 2UI标签的模板使用FreeMarker编写

   commons-logging-1.1.x.jarASF出品的日志包,Struts 2框架使用这个日志

                             包来支持Log4JJDK 1.4+的日志记录。

   commons-fileupload-1.2.2.jar:文件上传组件,2.1.6版本后需要加入此文件

   commons-io-2.0.1.jar:传文件依赖的jar

   commons-lang3-3.1.jar:对java.lang包的增强

asm-3.3.jar:提供了字节码的读写的功能,包含了核心的功能,而其他的

                    jar包都是基于这个核心的扩展.

asm-commons-3.3.jar:提供了基于事件的表现形式。

asm-tree-3.3.jar:提供了基于对象的表现形式。

javassist-3.11.0.GA.jar:代码生成工具, struts2用它在运行时扩展 Java

 

如图:

 

第三步:创建jsp文件.

 

第四步:创建Action文件,用来控制页面和服务器之间的转发。

第五步:编写Struts2的配置文件,这个文件要求:

1)必须放置到src下(即项目的classpath的根路径下)

2)名称必须叫做struts.xml,不能叫做其他的名称

配置如下:

<?xmlversion="1.0"encoding="UTF-8"?>

<!DOCTYPEstruts PUBLIC

    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"

    "http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>

    <!--

        package

          * name:定义一个包的名称,用于包和包之间的继承

          * namespace:命名空间,默认值是/

          * extends:所有的struts2的操作都要继承struts-default(因为该包中包含拦截器和返回类型)

     -->

    <packagename="primer"namespace="/primer"extends="struts-default">

        <!--指定默认的action引用,如果该包下没有对应action配置,则启用该配置-->

        <default-action-refname="helloWorldAction"></default-action-ref>

   

        <!--

           action:页面的链接对应Action类的路径

             * name:连接的名称

             * class:访问Action类的路径

         -->

        <!--

            1:如果没有为action指定class,默认是com.opensymphony.xwork2.ActionSupport

              执行ActionSupport中的execute方法

            2:如果没有为action指定method,默认执行action中的execute()方法。

             ActionSupportexecute方法里面就一句话return "success";

         -->

        <action name="helloWorldAction"class="cn.itcast.a_primer.HelloWorldAction">

            <!--

               result:Action类的返回值对应跳转到的页面

                 * nameAction类方法的返回值的名称

                 * <result></result>中间的内容,即跳转的页面

            -->

            <!--

             3:如果没有指定resultname属性,默认值为success

            -->

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

        </action>

    </package>

</struts>

 

这里注意:

1)  <package name="primer">表示Struts2把各种 Action 分门别类地组织成不同的包.可以把包想象为一个模块. 一个典型的 struts.xml文件可以有一个或多个包

2)   <packagenamespace=”/primer”>表示,其中namespace属性是可选的, 如果它没有给出,则以 “/” 为默认值. namespace 有一个非默认值,则要想调用这个包里的Action, 就必须把这个属性所定义的命名空间添加到有关的 URI字符串里

3)   <packageextends="struts-default">表示package元素通常要对 struts-default.xml 文件里定义的 struts-default 包进行扩展.这么做了以后, 包里的所有功能就可以使用,这些功能包括在 struts-default.xml文件里的结果类型和拦截器

4)   <action name="helloWorldAction">表示:每个 action都必须有一个 name 属性,该属性和用户请求的servletPath 之间存在着一一对应关系,此时对应:

<a href="${pageContext.request.contextPath}/helloWorldAction.action">helloWorld</a><br>

5)  <action class="cn.itcast.a_primer.HelloWorldAction">表示:其中action元素的 class 属性是可选的.如果没有配置 class 属性, Struts将把 com.opensymphony.xwork2.ActionSupport作为其默认值如果配置了 class属性, 还可以使用 method属性配置该类的一个动作方法. method 属性的默认值为 execute

6)   <resultname="success">表示result元素的 name 属性建立 <result> Action 方法返回值之间的映射关系。name属性的默认值为 “success

7)   <resultname="success">/primer/success.jsp</result>表示result元素的 type 属性负责指定结果类型. type属性的值必须是在包含当前包或者是当前包的父包里注册过的结果类型. type属性的默认值为 dispatcher

8)  result 元素:<action>的一个子元素, 它告诉 struts在完成动作后把控制权转交到哪里. result 元素(name属性)对应着 Action方法的返回值. 因为动作方法在不同情况下可能返回不同的值,所以同一个 action 元素可能会有多个 result元素

9)    

在struts2框架中使用包来管理Action,包的作用和java中的类包是非常类似的,它主要用于管理一组业务功能相关的action。在实际应用中,我们应该把一组业务功能相关的Action放在同一个包下。

配置包时必须指定name属性,如果其他包要继承该包,必须通过该属性进行引用,注意:name名称是唯一 。包的namespace属性用于定义该包的命名空间。该属性可以不配置,如果不指定该属性,默认的命名空间为“/”

通常每个包都应该继承struts-default包, struts-default包是由struts内置的,它定义了struts2内部的众多拦截器和Result类型。而Struts2很多核心的功能都是通过这些内置的拦截器实现。如:从请求中把请求参数封装到action、文件上传和数据验证等等都是通过拦截器实现的。当包继承了struts-default包才能使用struts2为我们提供的这些功能。 struts-default包是在struts2-core-2.x.x.jar文件中的struts-default.xml中定义。 struts-default.xml也是Struts2默认配置文件。 Struts2每次都会自动加载 struts-default.xml文件。加载的过程通过过滤器实现的

包还可以通过abstract=“true”定义为抽象包,抽象包中不能包含action。

 

 

 

第六步:在web.xml中加入Struts2 MVC框架启动配置,过滤器,没有它struts2就不能启动struts.xmlstruts2的功能也就无法实现。

这里大家要知道

1)  struts1.x,struts框架是通过Servlet启动的,而在struts2中,struts框架是通过Filter启动的。

2)  StrutsPrepareAndExecuteFilterinit()方法中将会读取类路径下默认的配置文件struts.xml完成初始化操作。

3)  struts2读取到struts.xml的内容后,是将内容封装进javabean对象然后存放在内存中,以后用户的每次请求处理将使用内存中的数据,而不是每次请求都读取struts.xml文件。

4)  过滤器启动后加载:使用init方法,初始化struts的各种xml文件和属性文件

以上方法在org.apache.struts2.dispatcher.Dispatcher类中

4struts2的处理流程

以下是struts-defautl.xml中的拦截器

它实现了很多的功能,其中包括国际化,文件上传,类型转换,表单验证,都是在跳转到Action类处理之前就做好了,所有我们只需要在Action类中使用就可以了,大大方便了我们的开发

下面大家练习使用myeclipse的断点调试,看看拦截器的执行过程。

 

5struts2的基本配置

1struts2的访问连接url

struts1中,通过<action path=/primer/helloWorldAction.action>节点的path属性指定访问该actionURL路径。

struts2中,访问struts2actionURL路径由两部份组成:

      包的命名空间+action的名称

例如: 访问本例子HelloWorldActionURL路径为: /primer/helloWorldAction.action

 (注意:完整路径为:http://localhost:端口//内容路径primer/helloWorldAction.action)。另外我们也可以加上.action后缀访问此Action,对于struts2来说,默认是.action结尾,或者是什么都不加。

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

      <action name="helloWorldAction" class="cn.itcast.primer.HelloWorldAction">

        <result name="success" type="dispatcher">/success.jsp</result>

      </action>

 </package>

2struts2namespace

1).获得请求路径的URI,例如url:

      http://server/struts2/path1/path2/path3/test.action

2).首先寻找namespace/path1/path2/path3package

      如果存在这个package,则在这个package中寻找名字为testaction

      如果不存在这个package则转步骤3

3).寻找namespace/path1/path2package

      如果存在这个package,则在这个package中寻找名字为testaction

      如果不存在这个package,则转步骤4

4).寻找namespace/path1package

      如果存在这个package,则在这个package中寻找名字为testaction

5.如果仍然不存在这个package,就去默认的namaspacepackage下面去找名

      字为testaction(默认的命名空间为空字符串“/”),

     如果还是找不到,页面提示找不到action

3Action配置中的各项默认值

问题:如果没有为action指定class,默认是com.opensymphony.xwork2.ActionSupport

执行ActionSupport中的execute方法

 

 struts-default.xml文件中的以下代码

<default-class-ref class="com.opensymphony.xwork2.ActionSupport" />决定

以下代码:

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

          <action name="helloWorldAction" class="cn.itcast.primer.HelloWorldAction">

            <result name="success" type="dispatcher">/success.jsp</result>

          </action>

<action name="actionNoClass">

              <result>/success.jsp</result>

          </action>

</package>

1>如果没有为action指定class,默认是ActionSupport

2>如果没有为action指定method,默认执行action中的execute()方法。

  ActionSupportexecute方法里面就一句话return "success";

  如果为action指定method,就会按照method指定的方法,去执行Action类中的同名方法

3>如果没有指定resultname属性,默认值为success

4>问题:如果请求的路径查找不到action的情况下,程序运行会抛出异常 ,可以通过配置当找不到action的情况下,会执行默认的action

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

    <!--指定默认的action引用,如果该包下没有对应action配置,则启用该配置-->

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

 

     <action name="helloWorldAction" class="cn.itcast.primer.HelloWorldAction">

            <result name="success" type="dispatcher">/success.jsp</result>

      </action>

     <action name="actionNoClass">

          <result>/success.jsp</result>

     </action>

 </package>

 

4ActionSupport类详解

5struts2的请求后缀

StrutsPrepareAndExecuteFilterStruts 2框架的核心控制器,它负责拦截由<url-pattern>/*</url-pattern>指定的所有用户请求,当用户请求到达时,该Filter会过滤用户的请求。默认情况下,如果用户请求的路径不带后缀或者后缀以.action结尾,这时请求将被转入Struts 2框架处理,否则Struts 2框架将略过该请求的处理。

这是因为根据配置文件:struts2-core-2.3.3.jar包下的org.apache.struts2/default.properties文件定义的常量决定,

      struts.action.extension=action,,

默认处理的后缀是可以通过常量”struts.action.extension“进行修改的,如下面配置Struts 2只处理以.do为后缀的请求路径,可以在struts.xml中配置:

<struts>

    <constant name="struts.action.extension" value="do"/>

</struts>

这个配置会覆盖default.properties文件的配置。

如果用户需要指定多个请求后缀,则多个后缀之间以英文逗号(,)隔开。如:

 <constant name="struts.action.extension" value="do,go"/>

这里注意:

多学一招:常量可以在struts.xmlstruts.properties中配置,但是我们建议在struts.xml中配置,两种配置方式如下:

struts.xml文件中配置常量

<struts>

    <constant name="struts.action.extension" value="do"/>

</struts>

 

struts.properties中配置常量, (struts.properties文件放置在src)

struts.action.extension=do

 

因为常量可以在多个配置文件中进行定义,所以我们需要了解下struts2加载常量的搜索顺序:

1 struts-default.xml

2 struts-plugin.xml

3 struts.xml

4 struts.properties=

5 web.xml

如果在多个文件中配置了同一个常量,则后一个文件中配置的常量值会覆盖前面文件中配置的常量值.

6struts2常用的常量介绍:

指定默认编码集,作用于HttpServletRequestsetCharacterEncoding方法和freemarkervelocity的输出

<constant name="struts.i18n.encoding" value="UTF-8"/>

该属性指定需要Struts 2处理的请求后缀,该属性的默认值是action,即所有匹配*.action的请求都由Struts2处理。

  如果用户需要指定多个请求后缀,则多个后缀之间以英文逗号(,)隔开

<constant name="struts.action.extension" value="do"/>

 设置浏览器是否缓存静态内容,默认值为true(生产环境下使用),开发阶段最好关闭

<constant name="struts.serve.static.browserCache" value="false"/>

struts的配置文件修改后,系统是否自动重新加载该文件,默认值为false(生产环境下使用),开发阶段最好打开

<constant name="struts.configuration.xml.reload" value="true"/>

开发模式下使用,这样可以打印出更详细的错误信息,同时可以自动加载struts2的配置文件和资源文件

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

默认的视图主题,设置为simple表示简单主题,目的是去掉struts2提供的css样式,因为在开发中,css样式事由美工设计的

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

spring集成时,指定由spring负责action对象的创建,这里在spring整合struts2的时候会用到,大家可以先记住

<constant name="struts.objectFactory" value="spring" />

该属性设置Struts 2是否支持动态方法调用,该属性的默认值是true。如果需要关闭动态方法调用,则可设置该属性为 false

<constant name="struts.enable.DynamicMethodInvocation" value="false"/>

上传文件的大小限制

     <constant name="struts.multipart.maxSize" value=10701096"/>

 

7struts.xml可以指定多个xml文件

它的目的就是为了减轻struts.xml的数据加载负担

因为在大部分应用里,随着应用规模的增加,系统中Action的数量也会大量增加,导致struts.xml配置文件变得非常臃肿。为了避免struts.xml文件过于庞大、臃肿,提高struts.xml文件的可读性,我们可以将一个struts.xml配置文件分解成多个配置文件,然后在struts.xml文件中包含其他配置文件。下面的struts.xml通过<include>元素指定多个配置文件:

<struts>

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

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

</struts>

 

通过这种方式,我们就可以将Struts 2Action按模块添加在多个配置文件中。

 

 

6:与ServletAPI解耦

为了避免与 Servlet API耦合在一起, 方便 Action单元测试, Struts2 HttpServletRequest, HttpSession ServletContext 进行了封装,构造了 3 Map对象来替代这 3 个对象, Action 中可以直接使用 HttpServletRequest, HttpSession, ServletContext对应的 Map 对象来保存和读取数据。这里大家注意,struts1是没有提供与ServletAPI解耦的。

 

方法一:通过ServletActionContext类直接获取

l       ActionContext Action执行的上下文对象, ActionContext中保存了 Action 执行所需要的所有对象,包括 parameters, request, session, application.

l       获取 HttpServletRequest对应的 Map 对象:

public Object get(Object key): ActionContext类中没有提供类似 getRequest() 这样的方法来获取 HttpServletRequest对应的 Map 对象.要得到 HttpServletRequest 对应的 Map对象, 可以通过为 get()方法传递“request”参数实现

l       获取 HttpSession对应的 Map 对象:  

public Map getSession()

l       获取 ServletContext对应的 Map 对象:

public Map getApplication()

测试代码:获取requestresponsesessionapplication对象

 

方法二:实现指定接口,由struts框架运行时注入:

Action 类通过可以实现某些特定的接口,Struts2 框架在运行时向 Action实例注入 parameters, request, session application 对应的 Map对象:

 

测试代码::获取requestresponsesessionapplication对象

 

Jsp页面输出值:

struts.xml文件的配置:

7struts2的结果类型

l       每个 action方法都将返回一个 String 类型的值, Struts将根据这个值来决定响应什么结果.

l       每个 Action声明都必须包含有数量足够多的 result 元素,每个 result 元素分别对应着 action方法的一个返回值.

l       result 元素可以有下面两个属性

         name: 结果的名字, 必须与 Action方法的返回值相匹配, 默认值为 success

         type: 响应结果的类型. 默认值为 dispatcher

 

struts2的所有结果类型在struts2-core-2.3.3.jar文件struts-default.xml中配置

1dispatcher(转发)

l       dispatcher 结果类型是最常用的结果类型,也是 struts 框架默认的结果类型

l       该结果类型有一个 location参数, 它是一个默认参数

l       dispatcher 结果类型将把控制权转发给应用程序里的某个资源.

l       dispatcher 结果类型不能把控制权转发给一个外部资源.若需要把控制权重定向到一个外部资源, 应该使用 redirect结果类型

2redirect(重定向到页面)

l       redirect 结果类型将把响应重定向到另一个资源,而不是转发给该资源.

l       redirect 结果类型接受下面这些参数:

         location: 用来给出重定向的目的地

         param: 用来表明是否把 location参数的值视为一个 OGNL 表达式来解释. 默认值为 true

l       redirect 结果类型可以把响应重定向到一个外部资源

 

3redirectAction(重定向到Action

l       redirectAction 结果类型把响应重定向到另一个 Action

l       redirectAction 结果类型接受下面这些参数:

         actionName: 指定目的地动作的名字. 它是默认属性

         namespace: 用来指定目的地动作的命名空间. 如果没有配置该参数, Struts会把当前 Action 所在的命名空间作为目的地的命名空间

 

4chain(解决重定向request作用域失效)

解决request作用域传递值失效的问题。

方式一:

type=redirectAction,使用OGNL表达式,从request作用域中获取username的值,然后再使用username作为名称,传递给重定向的的Action

HelloWorldAction类中使用:

String username = ServletActionContext.getRequest().getParameter("username");

 

方式二:

type=chain,此时不需要传递username的值

HelloWorldAction类中使用:

String username = (String) ServletActionContext.getRequest().getAttribute("username");

 

测试Action类:

struts.xml文件的配置:

 

8:通配符和动态方法调用

1)通配符的概念

l       一个 Web应用可能有成百上千个 action 声明.可以利用 struts 提供的通配符映射机制把多个彼此相似的映射关系简化为一个映射关系

l       通配符映射规则

         若找到多个匹配,没有通配符的那个将胜出。

         若指定的动作不存在, Struts将会尝试把这个 URI 与任何一个包含着通配符* 的动作名及进行匹配  

         Struts找到的带有通配符的匹配不止一个, 最后一个匹配将胜出

         被通配符匹配到的 URI字符串的子串可以用 {1}, {2} 来引用. {1}匹配第一个子串, {2} 匹配第二个子串

         {0} 匹配整个 URI

         *可以匹配零个或多个字符, 但不包括 /字符. 如果想把 /字符包括在内, 需要使用 **.如果需要对某个字符进行转义, 需要使用 \.

2)通配符实例一:

1)页面:

2struts.xml文件的配置:

 

3)通配符实例二:

1)页面:

2struts.xml文件的配置

4)通配符实例三:

1)页面:

2struts.xml的配置:

5)动态方法调用

1)页面:

         动态方法调用:通过 url 动态调用 Action中的方法

如果Action中存在多个方法时,我们可以使用!+方法名调用指定方法

         默认情况下, Struts的动态方法调用处于激活状态, 若想禁用该功能,则可以在 struts.xml 文件中添加如下 constant元素:

<constant name="struts.enable.DynamicMethodInvocation" value="false"/>

2struts.xml的配置

3Action类的方法,要提供adddelete的方法

6)使用通配符定义action(项目中常用的方式)

1)页面:

2struts.xml的配置:

 

3Action类的代码,指定adddelete的方法

7)全局结果

1)页面:

2struts.xml的配置

这里注意:

当多个action中都使用到了相同result,这时我们应该把result定义为全局结果。struts1中提供了全局forwardstruts2中也提供了相似功能:

<package ....>

       <!—全局返回的页面-->

      <global-results>

             <result name="delete">/pattern/successGlobal.jsp </result>

      </global-results>

    <action name="BookAction_*" class="cn.itcast.d_pattern.BookAction" method="{1}">

                     <result name="add">/pattern/BookAction.jsp</result>

                     <!--局部覆盖全局 -->

                    <result name="delete">/pattern/success.jsp</result>

              </action>

</package>

 

这里注:局部的会覆盖全局的返回值

 

struts1中应用范围内action的实例 action是单实例(执行时,先在缓存中查找实例,如果有,就使用该实例,没有没有就创建新的实例)

struts2应用范围内action的实例,每个请求都会创建一个action实例

总结:

servletstruts1属于单实例多线程的应用,实例只在初始化时被加载

struts2属于多实例多应用,每次访问Action实例都会创建一个action实例

 

多实例比单实例的优点,不会产生并发问题,但执行速度不如单实例

 

二:struts2第二天

1:类型转换

数据从一个 HTML表单到一个 Action 对象,类型转换表示是从字符串到非字符串.

对于HTTP 没有类型的概念. 每一项表单输入只可能是一个字符串或一个字符串数组.在服务器端, 必须把 String转换为特定的数据类型,对于struts1servlet都是这样接收和操作数据的。

而在 struts2, 把请求参数映射到 action属性的工作由 Parameters 拦截器负责,它是默认的 defaultStack 拦截器中的一员. Parameters拦截器可以自动完成字符串和基本数据类型之间转换,这里再次验证了struts2的拦截器的强大。

1)采用基本类型接收参数

第一步:在页面中定义:

第二步:在struts.xml中配置:

第三步:在Action类中获取页面的3个参数的值

这个操作获取的值,相当于我们使用request.getParameter(“id”);获取页面的值,但是我们发现我们获取的值的类型已经实现类型转换,这里就是struts2的类型转换拦截器帮助我们进行的操作。

       但是,这里存在一个问题。

       java.util.Date类型的属性可以接收格式为2009-07-20的请求参数值。但如果我们需要接收格式为20090720的请求参数,我们必须定义类型转换器,否则struts2无法自动完成类型转换。自定义类型转换的目的是,帮助开发者获取自己需要的数据类型。

2)自定义类型转换

自定义类型转化器必须实现 ongl.TypeConverter接口或对这个接口的某种具体实现做扩展

1)配置自定义类型转换器

在应用程序里使用一个自定义的类型转换器之前,必须先对它进行配置.

这种配置既可以基于字段,也可以基于类

 

基于字段配置(局部):可以为某个动作的各个属性分别制定一个自定义的转换器.

1:创建一个属性文件: ActionClassName-conversion.properties,该文件需和相对应的动作类(Action)放在同一个目录下, ActionClassNameAction的类名,后面的-conversion.properties是固定写法.

properties文件中的内容为:属性名称=类型转换器的全类名

   2:对于本例而言,文件的名称应为UserAction- conversion.properties

编辑属性文件:

          createTime=cn.itcast.e_converter.MyDateConverter

基于类配置(全局):

1:在 WEB-INF/classes/目录下创建 xwork-conversion.properties文件.

properties文件中的内容为:待转换的类型=类型转换器的全类名

    2:对于本例而言, xwork-conversion.properties文件中的内容为:

      java.util.Date=cn.itcast.e_converter.MyDateConverter

通过拦截器我们可以看到:struts2加载的自定义类型转换的属性文件的名称

这里表示加载全局的配置文件。

这里表示加载局部的配置文件。

 

这里我们需要定义一个自定义类型转换的类MyDateConverter

2)配置自定义类型转换的类

publicclass MyDateConverterextends DefaultTypeConverter {

 

    /**

     * 参数:

     *  1Map context:表示OGNL值栈对象

     *  2Object value:页面表单中输入的值,获取的值是一个Object的数组对象,如果页面只有一个createTimeObject[0]能够获取值

     *  3Class toType:要转换的类型(本例:java.util.Date

     * 返回值:

     *  Object:表示要返回的值(本例:日期类型yyyyMMdd的值)

     */

    @Override

    public Object convertValue(Map context, Object value,Class toType) {

        if(value==null){

            //如果不需要转换就向后执行

            returnsuper.convertValue(context, value, toType);

        }

        if(toType!=java.util.Date.class){

            //如果不需要转换就向后执行

            returnsuper.convertValue(context, value, toType);

        }

        else{

            //此时处理类型转换

            //获取页面传递的值

            if(valueinstanceof java.lang.String[]){

               String [] arrays = (String[]) value;

               String createTime = arrays[0];

               Date date = null;//yyyyMMdd

               if("".equals(createTime)){

                   returnnull;

               }

               else{

                   //String类型转换成日期类型

                   SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");

                   try {

                       date = dateFormat.parse(createTime);

                   } catch (ParseException e) {

                       e.printStackTrace();

                       returnnull;

                   }

                   return date;

               }

            }

            else{

               //如果不需要转换就向后执行

               returnsuper.convertValue(context, value, toType);

            }

        }

    }

}

 

3)类型转换与复杂对象配合使用(javabean对象)

很多时候, 需要把表单字段映射到多个对象的不同属性上。form 标签可以被映射到一个属性的属性

第一步:在页面上定义:

第二步:在Action类中定义:

同时定义一个EduEmpjavabean的类

Edu.java

Emp.java

原理:Struts2首先通过反射技术调用Edu的默认构造器创建edu对象,然后再通过反射技术调用edu中与请求参数同名的属性的setter方法来获取请求参数值。

Struts2还允许填充 Collection里的对象, 这常见于需要快速录入批量数据的场合,即集合中存放javabean对象。

 

 

2:文件上传

1)文件上传的要求:

要想使用 HTML表单上传一个或多个文件, 必须把 HTML表单的 enctype 属性设置为multipart/form-data,把它的 method属性设置为 post

为了让用户能够选择一个文件进行上传,程序员必须提供一个 <input type=“file”> 字段。

例如:页面中需要定义:

 

2struts2对文件上传的支持

Struts2应用程序里, FileUpload 拦截器和 Jakarta Commons FileUpload组件可以完成文件的上传.

步骤:

1. Jsp页面的文件上传表单里使用 file 标签.如果需要一次上传多个文件, 就必须使用多个 file标签, 但它们的名字必须是相同的

2. Action中新添加 3 个和文件上传相关的属性. 3 个属性的名字必须是以下格式

private File uploadImage; //上传的文件

private String uploadImageContentType;  //上传的文件的类型

private String uploadImageFileName;     //上传文件的名称

其中:

uploadImage jsp页面上的 file 标签的名字.

          即页面上传文件:<input type="file"name="uploadImage">name的属性值。

l         如果是上传单个文件, uploadImage属性的类型就是 java.io.File,它代表被上传的文件, 第二个和第三个属性的类型是 String,它们分别代表上传文件的文件名和文件类型

定义方式是分别是jsp页面file组件的名称+ContentType,

                       jsp页面file组件的名称+FileName

l         如果上上传多个文件,可以使用数组或 List

 

3)单文件上传

 

第一步:在WEB-INF/lib下加入commons-fileupload-1.2.2.jarcommons-io-2.0.1.jar。这两个jar包,文件可以从http://commons.apache.org/下载。

 

第二步:jsp页面中定义:

第三步:在struts.xml中配置:

第四步:Action类中定义:实现文件上传

@SuppressWarnings("serial")

publicclass UploadActionextends ActionSupport {

   

    /**上传的文件*/

    private FileuploadImage;

    /**上传文件名称*/

    private StringuploadImageFileName;

    /**上传文件的格式类型*/

    private StringuploadImageContentType;

 

    public String getUploadImageFileName() {

        returnuploadImageFileName;

    }

 

    publicvoid setUploadImageFileName(String uploadImageFileName) {

        this.uploadImageFileName = uploadImageFileName;

    }

 

    public String getUploadImageContentType() {

        returnuploadImageContentType;

    }

 

    publicvoid setUploadImageContentType(String uploadImageContentType) {

        this.uploadImageContentType = uploadImageContentType;

    }

 

    public File getUploadImage() {

        returnuploadImage;

    }

 

    publicvoid setUploadImage(File uploadImage) {

        this.uploadImage = uploadImage;

    }

 

    public String saveFile(){

        System.out.println("欢迎访问UploadAction类的saveFile方法");

        System.out.println("上传的文件:"+this.uploadImage);

        System.out.println("上传的文件名称:"+this.uploadImageFileName);

        System.out.println("上传的文件类型:"+this.uploadImageContentType);

        //文件上传

        //获取上传文件夹uploadFile的路径

        String path = ServletActionContext.getServletContext().getRealPath("/uploadFile");

        //目标文件File

        File destFile = new File(path+"/"+uploadImageFileName);

        try {

            //将源文件复制到目标文件

            FileUtils.copyFile(uploadImage, destFile);

            //将源文件重新命名到目标文件

            //uploadImage.renameTo(destFile);

        } catch (Exception e) {

            e.printStackTrace();

        }

        return"success";

    }

}

 

4File Upload拦截器

l       FileUpload 拦截器负责处理文件的上传操作, 它是默认的 defaultStack 拦截器栈的一员.

l       FileUpload 拦截器有 3 个属性可以设置.

         maximumSize: 上传文件的最大长度(以字节为单位),默认值为 2 MB

         allowedTypes: 允许上传文件的类型, 各类型之间以逗号分隔

         allowedExtensions: 允许上传文件扩展名, 各扩展名之间以逗号分隔

         可以在 struts.xml文件中覆盖这 3 个属性

 

l         struts.xml中下<action>中定义:

l         struts.xml中下<package>中定义:

 

l       若用户上传的文件大小大于给定的最大长度,或其内容类型没有被列在 allowedTypes, allowedExtensions参数里, 将会显示一条出错消息.与文件上传有关的出错消息在

       struts-messages.properties文件里预定义(org.apache.struts2包下)

         文件中的配置如下:

struts.messages.error.uploading=Error uploading: {0}

struts.messages.error.file.too.large=File too large: {0} "{1}" "{2}" {3}

struts.messages.error.content.type.not.allowed=Content-Type not allowed: {0} "{1}" "{2}" {3}

struts.messages.error.file.extension.not.allowed=File extension not allowed: {0} "{1}" "{2}" {3}

 

{0}:<input type=file name=uploadImage>name属性的值

{1}:上传文件的名称

{2}:上传文件保存到临时目录的名称

{3}:上传文件的类型(struts.messages.error.file.too.large是上传文件的大小)

 

关于这些通配符,大家可以查看文件上传的拦截器

可以看到以下的配置

使用国际化显示错误资源文件信息:

第一步:在src下创建fileUpload.properties的属性文件,文件的内容如下:

struts.messages.error.uploading=\u6587\u4EF6\u4E0A\u4F20\u9519\u8BEF\: {0}

struts.messages.error.file.too.large=\u6587\u4EF6\u592A\u5927\: {0} "{1}"  {3}

struts.messages.error.content.type.not.allowed=\u6587\u4EF6\u7C7B\u578B\u4E0D\u5141\u8BB8\: {0} "{1}" {3}

struts.messages.error.file.extension.not.allowed=\u6587\u4EF6\u6269\u5C55\u540D\u4E0D\u5141\u8BB8\: {0} "{1}" {3}

 

这里:我们将提示出错的值显示成中文:

第二步:加载属性文件:

struts.xml添加配置:

<!--设置comonfileupload上传组件允许的文件大小才能测试出上传文件过大出现的错误信息,这个值在struts-default.xml文件中,默认是2M,所以上次的文件超过2M不能上次,但是我们可以在自己配置的struts.xml中修改这个配置 -->

      <constant name="struts.multipart.maxSize" value="86170804"/>

 

       <!--配置上传文件的出错信息的资源文件,如果资源文件有多个中间使用逗号分开 -->

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

 

 

l       可以在文件上传 Action相对应的资源文件中重新定义错误消息, 但需要在 struts.xml文件中配置使用 action 的消息:

 

改变文件上传拦截器中的属性,可以在struts.xml中进行修改:代码如下:

方式一:在<package name="upload" namespace="/upload" extends="struts-default"></package>

中间定义:

 

方式二:在<action name="uploadAction_*" class="cn.itcast.f_upload.UploadAction" method="{1}"></action>中定义:

 

 

 

5)多文件上传代码

 

第一步:在WEB-INF/lib下加入commons-fileupload-1.2.2.jarcommons-io-2.0.1.jar。这两个jar包,文件可以从http://commons.apache.org/下载。

 

第二步:jsp页面中定义:

第三步:在struts.xml中配置:

第四步:Action类中定义:实现文件上传

@SuppressWarnings("serial")

publicclass UploadsActionextends ActionSupport {

   

    /**上传的文件*/

    private File []uploadImages;

    /**上传文件名称*/

    private String []uploadImagesFileName;

    /**上传文件的格式类型*/

    private String []uploadImagesContentType;

 

    public File[] getUploadImages() {

        returnuploadImages;

    }

 

    publicvoid setUploadImages(File[] uploadImages) {

        this.uploadImages = uploadImages;

    }

 

    public String[] getUploadImagesFileName() {

        returnuploadImagesFileName;

    }

 

    publicvoid setUploadImagesFileName(String[] uploadImagesFileName) {

        this.uploadImagesFileName = uploadImagesFileName;

    }

 

    public String[] getUploadImagesContentType() {

        returnuploadImagesContentType;

    }

 

    publicvoid setUploadImagesContentType(String[] uploadImagesContentType) {

        this.uploadImagesContentType = uploadImagesContentType;

    }

 

    public String saveFiles(){

        System.out.println("欢迎访问UploadsAction类的saveFiles方法");

        System.out.println("上传的文件:"+this.uploadImages);

        System.out.println("上传的文件名称:"+this.uploadImagesFileName);

        System.out.println("上传的文件类型:"+this.uploadImagesContentType);

        //文件上传

        //获取上传文件夹uploadFile的路径

        String path = ServletActionContext.getServletContext().getRealPath("/uploadFile");

        //多文件的上传

        if(uploadImagesContentType!=null && uploadImagesContentType.length>0){

            for(int i=0;i<uploadImagesContentType.length;i++){

               String filename = uploadImagesFileName[i];

               //目标文件File

               File destFile = new File(path+"/"+filename);

               //源文件

               File srcFile = uploadImages[i];

               //将源文件复制到目标文件

               try {

                   FileUtils.copyFile(srcFile, destFile);

               } catch (Exception e) {

                   e.printStackTrace();

               }

            }

        }

        return"success";

    }

}

 

 

3:拦截器

Struts2 拦截器在访问某个 Action方法之前或之后实施拦截, Struts2 拦截器是可插拔的,拦截器是 AOP的一种实现

 

拦截器栈(Interceptor Stack):将拦截器按一定的顺序联结成一条链. 在访问被拦截的方法时, Struts2拦截器链中的拦截器就会按其之前定义的顺序被依次调用

 

大家可以查看struts-default.xml文件中定义的拦截器,不难发现:

每个拦截器都是实现了 com.opensymphony.xwork2.interceptor.Interceptor接口的 Java:

Init方法:该方法将在拦截器被创建后立即被调用,它在拦截器的生命周期内只被调用一次. 可以在该方法中对相关资源进行必要的初始化

Interecept方法:每拦截一个动作请求,该方法就会被调用一次.

Destroy方法:该方法将在拦截器被销毁之前被调用,它在拦截器的生命周期内也只被调用一次.

 

Interceptor接口

l                  Struts 会依次调用程序员为某个 Action而注册的每一个拦截器的 interecept方法.

l                  每次调用 interecept方法时, Struts 会传递一个ActionInvocation 接口的实例.

l                  ActionInvocation: 代表一个给定动作的执行状态, 拦截器可以从该类的对象里获得与该动作相关联的Action 对象和 Result对象. 在完成拦截器自己的任务之后,拦截器将调用 ActionInvocation 对象的 invoke 方法前进到 Action处理流程.

l                  还可以调用 ActionInvocation对象的 addPreResultListener 方法给 ActionInvocation 对象上一个或多个 PreResultListener 监听器. 该监听器对象可以在动作执行完毕之后,开始执行动作结果之前做些事情

l                  AbstractInterceptor类实现了 Interceptor 接口.并为 init, destroy 提供了一个空白的实现

以下是struts2提供的拦截器,红色的拦截器是我们要掌握的拦截器。

 

 

 

1)自定义拦截器

需求:我们这里使用拦截器来处理权限控制

当前用户登录后,会将用户信息存放到Session中,如果有Session可以操作系统,如果没有Session不能操作系统:

分析:拦截器的操作原理

第一步:页面中定义:

第二步:Action类的代码定义:

第三步:使用拦截器处理拦截Action类的操作

第四步:struts.xml中配置:这里定义了自定义拦截器的配置和加载过程

 

方式一:加载自定义拦截器:添加到<package></package>

 

方式二:加载自定义拦截器:添加到<package></package>

 

 

这里:如果有Session则跳转到success.jsp,如果没有Session则跳转到error.jsp,但是我们没有登录,所有url连接只能跳转到error.sjp

       我们这里执行index.jsp:内容如下:

index.jsp

重复上面的操作,这里就会跳转到success.jsp了。

 

注意:

因为struts2中如文件上传,数据验证,封装请求参数到action等功能都是由系统默认的defaultStack中的拦截器实现的,所以我们自定义的拦截器需要引用系统默认的defaultStack,这样应用才可以使用struts2框架提供的众多功能。

如果希望包下的所有action都使用自定义的拦截器,可以通过<default-interceptor-ref name=checkSessionStack”/>把拦截器定义为默认拦截器。注意:每个包只能指定一个默认拦截器。

另外,一旦我们为该包中的某个action显示指定了某个拦截器,而不追加到默认拦截器的后面,则默认拦截器不会起作用。

 

4struts2的表单验证

struts2校验有两种实现方法:

    1. 手工编写代码实现(基本验证)

    2. 基于XML配置方式实现(验证框架)

1)手工编写代码实现(基本验证)

第一步:jsp页面:

验证:

     * 用户名不能为null ,""

     * 密码不能为null, "" 并且密码的长度6-12之间

效果:

第二步:在Action类中定义:

Action

    1:要继承ActionSupport

    2:重写Validateable接口中的validate()方法 ,在该方法中完成验证

 * 步骤如下:

    * validate()方法在其他的业务方法之前执行

    * 验证出错转向的页面

        struts.xml配置<result name="input">/validate/login.jsp</result>  

        其中input转向是在action中已经定义好的.

        public static final String INPUT = "input";通过它如果验证出错,会跳转到错误页面。                

    * 什么时候表示验证出错(转向input所指向的页面)

           *  this.addFieldError("sss", "错误信息");方法指向的是一个集合

           *  如果当集合不为空时,转向错误页面

如果当集合为空是,转成成功页面.

   * 显示错误Jsp页面:

       这里要使用<s:fielderror/>显示错误消息

      

Action类中也可以使用:this.addActionError("错误信息");

       jsp页面中可以使用<s:actionerror/>

代码如下

publicclass ValidateActionextends ActionSupport {

   

    //用户名

    private Stringusername;

    //密码

    private Stringpsw;

 

    public String getUsername() {

        returnusername;

    }

 

    publicvoid setUsername(String username) {

        this.username = username;

    }

 

    public String getPsw() {

       returnpsw;

    }

 

    publicvoid setPsw(String psw) {

        this.psw = psw;

    }

 

    public String login(){

        System.out.println("欢迎访问ValidateActionlogin方法");

        return"success";

    }

   

    public String test(){

        System.out.println("欢迎访问ValidateActiontest方法");

        return"success";

    }

   

    /**

     * validate()方法在其他的业务方法之前执行

     *   * 如果校验正常,此时不会向this.addFieldError(fieldName, errorMessage)方法中添加错误信息

     *        * 如果没有错误信息:此时再跳转到login()方法执行

     *  

     *   * 如果校验不正常,此时就要向this.addFieldError(fieldName, errorMessage)方法中添加错误信息

     *        * 底层代码:

     *              final Map<String, List<String>> errors = internalGetFieldErrors();

                   List<String> thisFieldErrors = errors.get(fieldName);

           

                   if (thisFieldErrors == null) {

                       thisFieldErrors = new ArrayList<String>();

                       errors.put(fieldName, thisFieldErrors);

                   }

           

                   thisFieldErrors.add(errorMessage);

     *        * 如果errors集合中有值,如果有值,此时不会再跳转到login方法执行,

     *          通过struts.xml中定义的result type="input",用来指向错误页面,

     *          在错误页面中使用s:fielderror输出错误信息

     * */

    @Override

    publicvoid validate() {

        //用户名不能为null

        if(username==null ||"".equals(username.trim())){

            /**

            * 参数一:字段名(一般跟页面传递的表单属性名对应即可)

            * 参数二:错误信息

            */

            this.addFieldError("username","用户名不能为空");

        }

        //密码不能为null

        if(psw==null ||"".equals(psw.trim())){

            this.addFieldError("psw","密码不能为空");

        }

        else{

            psw = psw.trim();

            //验证密码的长度在612之间

            String regex = "^[0-9a-zA-Z]{6,12}$";

            //正则表达式编译需要匹配的结果

            Pattern pattern = Pattern.compile(regex);

            //与页面输入的值进行匹配

            Matcher matcher = pattern.matcher(psw);

            //匹配的结果

            if(!matcher.matches()){

               this.addFieldError("psw","密码的长度在612之间");

            }

        }

    }

}

这里:

validate()方法会校验action中所有与execute方法签名相同的方法。

如果要校验指定的方法通过重写validateXxx()方法实现, validateXxx()只会校验action

  方法名为Xxx的方法。其中Xxx的第一个字母要大写。

当某个数据校验失败时,调用addFieldError()方法往系统的fieldErrors添加校验失败

  信息(为了使用addFieldError()方法,action可以继承ActionSupport),如果系统

  fieldErrors包含失败信息,struts2会将请求转发到名为inputresult

input视图中可以通过<s:fielderror/>显示失败信息。

例如:validateXxx()方法使用例子:

public Stringadd() throws Exception{

       return "success";

}

对应的验证方法   

public voidvalidateAdd(){

          //验证代码

}

我们可以在ValidationInterceptor拦截器中可以看到以validate开始的方法

 

 

我们可以根据要求:如果只想针对Action类中的login方法进行校验,此时执行test()方法的时候,将不会校验。我们可以修改:

/**

     * 要校验指定的方法通过重写validateXxx()方法实现, validateXxx()只会校验action

        方法名为Xxx的方法。其中Xxx的第一个字母要大写。

     * */

    publicvoidvalidateLogin() {

        //用户名不能为null

        if(username==null ||"".equals(username.trim())){

            /**

            * 参数一:字段名(一般跟页面传递的表单属性名对应即可)

            * 参数二:错误信息

            */

            this.addFieldError("username","用户名不能为空");

        }

        //密码不能为null

        if(psw==null ||"".equals(psw.trim())){

            this.addFieldError("psw","密码不能为空");

        }

        else{

            psw = psw.trim();

            //验证密码的长度在612之间

            String regex = "^[0-9a-zA-Z]{6,12}$";

            //正则表达式编译需要匹配的结果

            Pattern pattern = Pattern.compile(regex);

            //与页面输入的值进行匹配

            Matcher matcher = pattern.matcher(psw);

            //匹配的结果

            if(!matcher.matches()){

               this.addFieldError("psw","密码的长度在612之间");

            }

        }

    }

 

第三步:在struts.xml文件中的配置:

<?xmlversion="1.0"encoding="UTF-8"?>

<!DOCTYPEstruts PUBLIC

    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"

    "http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>

    <packagename="validate"namespace="/validate"extends="struts-default">

        <!-- 手工校验 -->

        <action name="validateAction_*"class="cn.itcast.h_validate.ValidateAction"method="{1}">

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

            <!-- 使用type="input",指向错误页面(前提:要执行.addFieldError()方法),在错误页面可以使用s:fieldError输出信息 -->

            <result name="input">/validate/login.jsp</result>

        </action>

    </package>

</struts>

 

 

总结:手工编写输入校验的过程(面试时可以说)

1。类型转换器对请求参数执行类型转换,并把转换后的值赋给action中的属性。

2。如果在执行类型转换的过程中出现异常,系统会将异常信息保存到ActionContextconversionError拦截器将异常信息封装到fieldErrors里,然后执行第3步。如果类型转换没有出现异常,则直接进入第3步。

3。系统通过反射技术调用action中的validateXxx()方法,Xxx为方法名。

4。调用action中的validate()方法。

5。经过上面4步,如果系统中的fieldErrors存在错误信息(即存放错误信息的集合的size大于0),系统自动将请求转发至名称为input的视图。如果系统中的fieldErrors没有任何错误信息,系统将执行action中的处理方法。

 

2XML配置方式实现输入校验

第一步:jsp页面:

验证:

     * 用户名不能为null ,""

     * 密码不能为null, "" 并且密码的长度6-12之间

效果:

 

第二步:在Action类中定义:

Action

    1:要继承ActionSupport或者实现Validateable接口

Action类中定义:校验过程交给XML文件处理

@SuppressWarnings("serial")

publicclass ValidateXmlActionextends ActionSupport {

   

    //用户名

    private Stringusername;

    //密码

    private Stringpsw;

    //年龄

    private Integerage;

 

    public Integer getAge() {

        returnage;

    }

    publicvoid setAge(Integer age) {

        this.age = age;

    }

    public String getUsername() {

        returnusername;

    }

    publicvoid setUsername(String username) {

        this.username = username;

    }

    public String getPsw() {

        returnpsw;

    }

    publicvoid setPsw(String psw) {

        this.psw = psw;

    }

    public String login(){

        System.out.println("欢迎访问ValidateXmlActionlogin方法");

        return"success";

    }

    public String test(){

        System.out.println("欢迎访问ValidateXmlActiontest方法");

        return"success";

    }

}

 

第三步:struts.xml的配置:

验证出错转向的页面

        struts.xml配置<result name="input">/validate/loginxml.jsp</result>  

        其中input转向是在action中已经定义好的.

 

第四步:配置验证的xml文件

  * 验证的xml文件的规范在xwork-core-2.3.3.jar包下的:xwork-validator-1.0.3.dtd

  * 验证文件的命名

     *  在这个校验文件中,对action中字符串类型的username属性进行验证,

        首先要求调用trim()方法去掉空格,然后判断用户名是否为空。

     *  该文件需要和action类放在同一个包下,文件的取名应遵守

        ActionClassName-validation.xml规则,其中ActionClassNameaction的简单类名,-validation为固定写法。

        例如:如果Action类为cn.itcast.validate.ValidateXmlAction.那么该文件的取名应为:ValidateXmlAction-validation.xml

         ValidateXmlAction-validation.xml为文件的配置如下

 

其中:

<validators>:根元素

<field>:指定action中要校验的属性,name属性指定将被验证的表单字段的名字

<field-validator>:指定校验器, type指定验证规则

上面指定的校验器requiredstring是由系统提供的,系统提供了能满足大部分验证需求的校验器,这些校验器的定义可以在xwork-2.x.jar中的

com.opensymphony.xwork2.validator.validators下的default.xml中。

<param>:子元素可以向验证程序传递参数

<message>:子元素为校验失败后的提示信息,如果需要国际化,可以为message指定key属性,key的值为属性文件中的key

 

这里注意(1):

当校验文件的取名为ActionClassName-validation.xml时,会对 action中的所有处理方法实施输入验证。
    如果你只需要对action中的某个action方法实施校验,那么,校验文件的取名应为:ActionClassName-ActionName-validation.xml,其中ActionNamestruts.xmlaction的名称。例如:在实际应用中,常有以下配置:

<action name="validateXmlAction_*" class="cn.itcast.h_validate.ValidateXmlAction" method="{1}">

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

        <result name="input">/validate/loginxml.jsp</result>

</action>

ValidateXmlAction中有以下两个处理方法:

public String login() throws Exception{

   ....

}

public String test() throws Exception{

   ....

}

要对login ()方法实施验证,校验文件的取名为:

ValidateXmlAction-validateXmlAction_login-validation.xml

要对test()方法实施验证,校验文件的取名为:

ValidateXmlAction-validateXmlAction _test-validation.xml

注意(2

基于XML校验的一些特点

当为某个action提供了

ActionClassName-validation.xmlActionClassName-ActionName-validation.xml两种规则的校验文件时,这时系统按下面顺序寻找校验文件:

1AconClassName-validation.xml

2ActionClassName-ActionName-validation.xml

系统寻找到第一个校验文件时还会继续搜索后面的校验文件,当搜索到所有校验文件时,会把校验文件里的所有校验规则汇总,然后全部应用于处理方法的校验。如果两个校验文件中指定的校验规则冲突,则只使用后面文件中的校验规则。

 

action继承了另一个action,父类action的校验文件会先被搜索到。假设UserAction继承BaseActionUserActionstruts.xml的配置如下:

<action name="user" class="cn.itcast.action.UserAction" method="{1}">

       .....

</action>

访问上面名为useraction,系统先搜索到BaseAction-validation.xml BaseAction-user-validation.xml,接着搜索到UserAction-validation.xml UserAction-user-validation.xml。校验规则是这四个文件的总和。

 

 

 

 

3Struts2XML配置校验内建的验证程序:

校验器在com.opensymphony.xwork2.validator.validators包下的default.xml存在各个校验器的规则。

 

l       required: 确保某给定字段的值不是空值 null

l       requiredstring: 确保某给定字段的值既不是空值 null,也不是空白.

         trim 参数. 默认为 true,表示 struts 在验证该字段值之前先剔除前后空格.

l       stringlength: 验证一个非空的字段值是不是有足够的长度.

         minLength: 相关字段的最小长度. 若没有给出这个参数,该字段将没有最小长度限制

         maxLength:相关字段的最大长度. 若没有给出这个参数,该字段将没有最大长度限制

         trim: 在验证之前是否去除前后空格

l       int: 检查给定字段的值是否可以被转换为一个整数

         min: 相关字段的最小值. 若没给出这个参数,该字段将没有最小值限制

         max: 相关字段的最大值. 若没给出这个参数,该字段将没有最大值限制

l       date: 确保某给定日期字段的值落在一个给定的范围内

         max:相关字段的最大值. 若没给出这个参数,该字段将没有最大值限制

         min:相关字段的最小值. 若没给出这个参数,该字段将没有最小值限制

l       email: 检查给定 String 值是否是一个合法的 email

l       url: 检查给定 String 值是否是一个合法的 url

l       regex: 检查某给定字段的值是否与一个给定的正则表达式模式相匹配.

         expression: 用来匹配的正则表达式

         caseSensitive: 是否区分字母的大小写. 默认为 true

         trim: 是否去除前后空格. 默认为 true

l       conversion(转换校验器,指定在类型转换失败时,提示的错误信息)

l       visitor(用于校验action中的复合属性,它指定一个校验文件用于校验复合属性中的属性)

l       expression(OGNL表达式校验器,expression参数指定ognl表达式,该逻辑表达式基于ValueStack进行求值,返回true时校验通过,否则不通过,该校验器不可用在字段校验器风格的配置中)

l       double(双精度浮点数校验器,要求field的双精度浮点数必须在指定范围内,min指定最小值,max指定最大值)

 

使用这些验证程序在XML配置的案例

required 必填校验器

<field-validator type="required">

       <message>性别不能为空!</message>

</field-validator>

 

requiredstring 必填字符串校验器

<field-validator type="requiredstring">

       <param name="trim">true</param>

       <message>用户名不能为空!</message>

</field-validator>

 

stringlength:字符串长度校验器

<field-validator type="stringlength">

       <param name="maxLength">10</param>

       <param name="minLength">2</param>

       <param name="trim">true</param>

       <message><![CDATA[产品名称应在2-10个字符之间]]></message>

</field-validator>

int:整数校验器

<field-validator type="int">

       <param name="min">1</param>

       <param name="max">150</param>

       <message>年龄必须在1-150之间</message>

</field-validator>

 

字段OGNL表达式校验器

<field name="imagefile">

       <field-validator type="fieldexpression">

              <param name="expression"><![CDATA[imagefile.length() <= 0]]></param>

              <message>文件不能为空</message>

       </field-validator>

</field>

email:邮件地址校验器

<field-validator type="email">

       <message>电子邮件地址无效</message>

</field-validator>

 

regex:正则表达式校验器

<field-validator type="regex">

     <param name="expression"><![CDATA[^13\d{9}$]]></param>

     <message>手机号格式不正确!</message>

</field-validator>

 

 

 

4)自定义校验规则

       struts2提供的校验规则不能满足我们需求的时候,我们就要采用自定义校验规则。

第一步:jsp页面

需求:自定义一个 age的验证器, 使 age不能小于 0

jsp页面的表单中,添加:

第二步:在Action类中定义:

//年龄

    private Integerage;

 

    public Integer getAge() {

        returnage;

    }

    publicvoid setAge(Integer age) {

        this.age = age;

    }

这里使用age属性用来接收页面传递的参数。

第三步:添加自定义验证规则的类:这个类用来判断年龄不能小于0

publicclass AgeValidateextends FieldValidatorSupport {

 

    /**自定义校验规则要执行的方法*/

    publicvoid validate(Object object)throws ValidationException {

        String fieldName = getFieldName();//获取字段名:age

        Object value = this.getFieldValue(fieldName, object);//获取字段输入的值:-1

       

        if (!(valueinstanceof java.lang.Integer)) {

            addFieldError(fieldName, object);

        } else {

            Integer i = (Integer) value;

            if (i<0) {

               addFieldError(fieldName, object);

            }

        }

    }

 

}

第四步:在工程的src下新建validators.xml文件,在文件中增加如下内容:

    xml文件采用的约束规范在xwork-core-2.3.3.jar包下的xwork-validator-config-1.0.dtd

<?xmlversion="1.0"encoding="UTF-8"?>

<!DOCTYPEvalidators PUBLIC

        "-//Apache Struts//XWork Validator Definition 1.0//EN"

        "http://struts.apache.org/dtds/xwork-validator-definition-1.0.dtd">

<validators>

    <validatorname="age"class="cn.itcast.h_validate.AgeValidate"/>

</validators>

这里通过validators.xml文件的配置,去加载自定义校验规则的类。其中校验规则的名称为age

第五步:在ValidateXmlAction-validateXmlAction_login-validation.xml的配置文件(这里只验证login的方法)中,可以使用age自定义拦截器,去验证页面的age属性。

 

自定义验证规则的特点:

l       自定义验证程序必须实现 Validator 接口.

l       Validation 拦截器负责加载和执行各种验证程序. 在加载了一个验证程序之后, 这个拦截器将调用那个验证程序的 setValidatorContext方法, 把当前的 ValidatorContext对象传递给它, 这使程序员可以访问当前 Action.。接下来, Validation拦截器将调用 validate 方法并把需要验证的对象传递给它. validate方法是编写一个自定义的验证程序时需要覆盖的方法.

l       ValidatorSupport FieldValidatorSupport 实现了 Validator接口

         若需要普通的验证程序, 可以继承 ValidatorSupport

         若需要字段验证程序, 可以继承 FieldValidatorSupport

         若验证程序需要接受一个输入参数, 需要为这个参数增加一个相应的属性

l       注册验证程序: 自定义验证器需要在类路径里的某个validators.xml 文件里注册:验证框架首先在根目录src下找validators.xml文件,没找到validators.xml文件,验证框架将调用默认的验证设置,default.xml里面的配置信息.

l       位于com.opensymphony.xwork2.validator.validators包下

 

 

三:struts2第三天

1:国际化

1)应用程序国际化的概念

l       软件的本地化:一个软件在某个国家或地区使用时,采用该国家或地区的语言,数字,货币,日期等习惯。

l       软件的国际化:软件开发时,让它能支持多个国家和地区的本地化应用。使得应用软件能够适应多个地区的语言和文化风俗习惯。

l       资源文件和资源包
要用Struts2实现国际化和本地化,首先要定义资源文件的名称,这个文件会包含用默认语言编写的会在程序中出现的所有消息。这些消息以键-值对的形式存储,如下:
error.validation.localtion = The entered location is invalid
当对一个应用程序进行国际化处理时,所要用的各种语言版本的标签信息应该存放在不同的属性文件中,每一个这样的文件对应一种语言版本。所有属性文件合在一起称为资源包(Resource Bundle)。
属性文件的命名格式可分为以下两种:
   a)文件名前缀.properties
   
b)
文件名前缀_语言种类.properties
文件名后缀必须是properties,前缀可自由书写,其中语言种类字段必须是有效的ISO语言代码,如中文(zh_CN)、英文(en_US)。

l       文件名前缀.properties默认的形式,当其他属性文件找不到时,会默认的寻找此属性文件。

2)配置全局资源与输出国际化信息

1、准备资源文件

2 、在struts.xml中使用struts.custom.i18n.resources常量即可加载全局资源文件

     <constant name="struts.custom.i18n.resources"

                      value="cn.itcast.i18n.resource" />

     resource为资源文件的基本名。

3、在jsp页面获取国际化的资源文件的信息

     方法一:使用text标签:用来显示一条国际化消息的数据标签. 相当于从property标签调用 getText方法. 该标签包含如下属性:

    * name: 用来检索消息的键

    * var:用来引用压入 ContextMap栈的值的变量名

* 可以通过  param子标签向 text 标签传递参数

使用text标签传递参数:

  资源文件的信息

              item.test={0},欢迎来到传智播客{1}

    jsp页面

             <s:text name="item.test">

                    <s:param>用户名</s:param>      {0}

                    <s:param>密码</s:param>         {1}    

             </s:text>

 

  输出结果:

          用户名,欢迎来到传智播客密码


   例如:<s:text name="item.username"/>

  方法二:使用ognl表达式

    可以使用 property标签或是使用某个表单标签的 label 属性,来显示一条调用 getText()

    方法而得到的本地消息:

   例如:<s:textfield name="username" label="%{getText('item.username')}" />

   例如:<s:property value="%{getText('item.username')}" />

 

 

4:在action中获取资源文件的信息

l       ActionSupport 类实现了 TextProvider 接口, 该接口负责提供对各种资源包和它们的底层文本消息的访问机制.

l       当调用 getText()方法时, 它将按以下顺序搜索相关的属性文件.

         Action类的属性文件:该文件的名字与相关的动作类的名字一样, 并且和那个动作类存放在同一个目录下

         动作类所实现的各个接口的属性文件

         动作类的各个父类的属性文件

         动作类的各个父类所实现的各个接口的属性文件

         如果动作类实现了 ModelDriven接口, Struts 将调用 getModel()方法并从模型对象的类开始沿着类的继承关系进行一次上溯搜索

         默认的包的属性文件

         继承关系中的下个父包里的资源包

 

3)国际化—JSP中直接访问某个资源文件

i18n标签: 用来加载一个自定义的 ResourceBundle.不用做任何配置,

name:将被加载的资源集的 java 完全限定名

使用这样方式,我们就可以不用定义以下的配置加载

<constant name="struts.custom.i18n.resources"

 value="resource,cn.itcast.i18n.resource"></constant>

使用<s:i18n>标签

<s:i18n name=resource">

    <s:text name=item.username/>

</s:i18n>

resource为类路径下资源文件的基本名。

如果要访问的资源文件在类路径的某个包下,可以这样访问:

<s:i18n name=cn.itcast.i18n.resource">

      <s:text name=item.test">

             <s:param>小张</s:param>

      </s:text>

</s:i18n>

      上面访问cn.itcast.i18n包下基本名为resource的资源文件。

4)使用 native2ascii程序转换字符编码

l       JDK 中提供了一个 native2ascii 工具程序,它可以将某种本地字符集编码的字符转换成 Unicode转义序列的形式

l       DOS 下进入 test_cn_backup.properties文件所在目录,运行下面的命令后将在当前目录下生成一个名为 test_zh_CN.properites文件:

      native2ascii -encoding gb2312 源文件   目标文件.properites

例如:native2ascii -encoding gb2312  test_cn_backup.properties    test_zh_CN.properites

这里注意:如果编码格式UTF-8,需要改成UTF-8

5)测试国际化的代码

第一步:在包下创建resource.properties的文件

item.username=itemUsername

item.psw=itemPsw

item.submit=itemSubmit

item.test=welcome{0}come{1}study

第二步:在同目录下创建resource_en_US.properties

item.username=username

item.psw=psw

item.submit=submit

item.test=welcome{0}come{1}study

第三步:在同目录下创建resource_zh_CN.properties

item.username=\u7528\u6237\u540D

item.psw=\u5BC6\u7801

item.submit=\u63D0\u4EA4

item.test=\u6B22\u8FCE{0}\u6765{1}\u5B66\u4E60

 

这里该文件可以使用resource.txt的内容生成:

item.username=用户名

item.psw=密码

item.submit=提交

 

这里我们执行命令去将中文转换成我们需要的十六进制:

4:如何生成中文的资源文件

  (1)手工1个1个改,在属性文件中添加中文转换成十六进制

  (2)jdk工具,执行命令native2ascii.exe

     D:\workspaceStruts\itcastStruts2\src\cn\itcast\i18n>native2ascii -encoding utf-8 resource.txt resource_zh_CN.properties,生成

  (3):使用中文与Unicode码转换(十六进制).html转换

 

第四步:在struts.xml中加载国际化

加载国际化资源的配置:

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

    <!--加载自定义的国际化资源文件

          * 如果加载src下的properties文件,可以直接写文件名即可

          * 如果加载cn.itcast包下的fileUpload.properties文件,可以写成cn.itcast.fileUpload

          * 如果多个资源文件,使用逗号分开

     -->

    <constantname="struts.custom.i18n.resources"value="fileUpload,cn.itcast.i18n.resource,cn.itcast.model.token"></constant>

 

 

第五步:在jsp页面中定义国际化,实现页面的国际化

1login.jsp

<%@page language="java" pageEncoding="UTF-8"contentType="text/html; charset=utf-8"%>

<%@taglib uri="/struts-tags"prefix="s"%>

<html>

  <head>   

    <title>My JSP 'login.jsp' starting page</title>

  </head>

  <body>

  <br>

      <s:formname="loginForm"namespace="/i18n"method="post"action="loginAction_login.action"theme="simple">

         <table border="1">

           <tr>

             <td><s:property value="%{getText('item.username')}"/></td>

             <td> <s:textfield name="username" label="%{getText('item.username')}" /></td>

           </tr>

           <tr>

             <td><s:text name="item.psw"/></td>

             <td><s:passwordname="psw"/></td>

           </tr>

           <tr>

             <td>&nbsp;</td>

             <td><s:submit value="%{getText('item.submit')}"/></td>

           </tr>

         </table>

     </s:form>

  </body>

</html>

2testParam.jsp

<%@page language="java" pageEncoding="UTF-8"%>

<%@taglib uri="/struts-tags"prefix="s"%>

<html>

  <head>   

    <title>My JSP 'login.jsp' starting page</title>

  </head>

  <body>

  <br>

     <s:text name="item.username"/><br>

     <s:text name="item.test">

      <s:param>张三丰</s:param>

      <s:param>传智播客</s:param>

     </s:text>

  </body>

</html>

3i18n.jsp

<%@page language="java" pageEncoding="UTF-8"contentType="text/html; charset=utf-8"%>

<%@taglib uri="/struts-tags"prefix="s"%>

<html>

  <head>

    <title>My JSP 'login.jsp' starting page</title>

  </head>

  <body>

  <br>

     <s:i18n name="cn.itcast.i18n.resource">

       <s:text name="item.username"></s:text>

     </s:i18n>

    

      <s:i18n name="cn.itcast.i18n.resource">

       <s:text name="item.test">

          <s:param>用户名</s:param>

          <s:param>密码</s:param>

       </s:text>

     </s:i18n>

  </body>

</html>

 

 

第六步:在Action类中定义:

@SuppressWarnings("serial")

publicclass LoginActionextends ActionSupport {

   

    public String login(){

        System.out.println("欢迎访问LoginActionlogin方法");

        /**如何获取资源文件的信息*/

        String username = this.getText("item.username");

        System.out.println("username"+username);

       

        String test = this.getText("item.test",new String[]{"翠花","传智播客"});

        System.out.println("test:"+test);

        return"success";

    }

   

}

 

2OGNL表达式

OGNL表达式语言介绍

OGNLObject Graphic Navigation Language(对象图导航语言)的缩写,它是一个开源项目。 Struts2框架使用OGNL作为默认的表达式语言。

OGNL相对其它表达式语言具有下面几大优势:大家可以先了解下

   1、支持对象方法调用,如xxx.doSomeSpecial()

   2、支持类静态的方法调用和值访问,表达式的格式:@[类全名(包括包路径)]@[方法名 |  值名],例如:

             @java.lang.String@format('foo %s', 'bar')

             @tutorial.MyConstant@APP_NAME

   3、支持赋值操作和表达式串联,如price=100, discount=0.8,

        calculatePrice(),这个表达式会返回80

   4、访问OGNL上下文(OGNL context)和ActionContext

   5、操作集合对象。

Ognl 有一个上下文(Context)概念,说白了上下文就是一个MAP结构,它实现了java.utils.Map的接口.

1)理解Struts2中的 ValueStack

ValueStack实际是一个接口,Struts2中利用OGNL时,实际上使用的是实现了该接口的OgnlValueStack,这个类是Struts2利用OGNL的基础

 

ValueStack(值栈):贯穿整个 Action 的生命周期(每个 Action类的对象实例都拥有一个ValueStack 对象).相当于一个数据的中转站. 在其中保存当前Action对象和其他相关对象。

Struts框架把 ValueStack 对象保存在名为 “struts.valueStack”的请求属性中,request

l       ValueStack对象的内部有两个逻辑部分:

ObjectStack: Struts 把动作和相关对象压入 ObjectStack--List

ContextMap: Struts把各种各样的映射关系(一些 Map类型的对象)压入 ContextMap

Struts会把下面这些映射压入 ContextMap

parameters: Map中包含当前请求的请求参数

request: Map中包含当前 request 对象中的所有属性

session: Map中包含当前 session 对象中的所有属性

application: Map中包含当前 application  对象中的所有属性

attr: Map按如下顺序来检索某个属性: request, session, application

 

这里,我们可以使用断点执行:

如下代码:

//获取OGNL的值栈对象,方式一

ValueStack valueStack = ServletActionContext.getContext().getValueStack();

System.out.println("valueStack"+valueStack);

//获取OGNL的值栈对象,方式二

ValueStack valueStack2 = (ValueStack) ServletActionContext.getRequest().getAttribute("struts.valueStack");

System.out.println("valueStack2:"+valueStack2);

 

 

 

 

 

 

ObjectStack: Struts 把动作和相关对象压入 ObjectStack

publicclass OgnlValueStack implements ValueStack{  

      Map<String, Object> context;    

      CompoundRoot root;

}

publicclass OgnlContext  implements Map{

      private Object _root;

      private Map _values =new HashMap(23);

}

publicclass CompoundRoot extends ArrayList

ObjectStack: Struts 把动作和相关对象压入 ObjectStack

ContextMap: Struts把各种各样的映射关系(一些Map类型的对象)压入ContextMap. Struts会把下面这些映射压入ContextMap

parameters:Map中包含当前请求的请求参数

request: Map中包含当前request对象中的所有属性

session: Map中包含当前session对象中的所有属性

application:Map中包含当前application 对象中的所有属性

attr: Map按如下顺序来检索某个属性: request, session, application

 

 

 

总结:

l       OgnlValueStack 类包含两个重要的属性  一个root和一个context

       *   其中root本质上是一个ArrayList.

       *   context 是一个Map(更确切的说是一个OgnlContext对象)

l      在这个OgnlContext对象(context)中,有一个默认的顶层对象 _rootOGNL访问context中这个默认顶层对象中的元素时,是不需要#号的,直接通过元素的名称来进行访问,

l      而访问其他对象时,如 requestsessionattr等,则需要#号引用。

      :Struts2OgnlValueStackroot对象赋值给了OgnlContext中的_root对象,在OgnlValueStackroot对象中,保存着调用Action的实例,因此,在页面上通过Struts2标签访问Action的属性时,就不需要通过#号来引用

    总结:ognl Context包含 ObjectStack属性和ContextMap属性

 

OGNL Contextstruts2的数据中心   结构示意图如下:

1)测试代码

l         Jsp页面:

  测试值栈:<br>

        <ahref="${pageContext.request.contextPath}/ognl/valueStackAction_test.action?cid=10">test</a><br>

 

l         Action类定义:

publicclass ValueStackActionextends ActionSupport {

   

    private Stringcid;

 

    public String getCid() {

        returncid;

    }

 

    publicvoid setCid(String cid) {

        this.cid = cid;

    }

 

    public String test(){

        System.out.println("欢迎访问ValueStackActiontest方法");

        System.out.println("cid:"+cid);

        ServletActionContext.getRequest().setAttribute("username","request_username");

        ServletActionContext.getContext().getSession().put("username","session_username");

        ServletActionContext.getServletContext().setAttribute("username","application_username");

       

        //获取OGNL的值栈对象,方式一

        ValueStack valueStack = ServletActionContext.getContext().getValueStack();

        System.out.println("valueStack"+valueStack);

        //获取OGNL的值栈对象,方式二

        ValueStack valueStack2 = (ValueStack) ServletActionContext.getRequest().getAttribute("struts.valueStack");

        System.out.println("valueStack2:"+valueStack2);

       

        return"success";

    }

}

 

l         struts.xml

<struts>

    <packagename="ognl"namespace="/ognl"extends="struts-default">

        <!-- 测试值栈 -->

        <action name="valueStackAction_*"class="cn.itcast.ognl.ValueStackAction"method="{1}">

            <result name="success">/ognl/valueStack.jsp</result>

        </action>

</package>

</struts>

 

l         显示的jsp页面

<%@taglib uri="/struts-tags"  prefix="s"%>

<html>

  <head>

    <title>My JSP 'index.jsp' starting page</title>

    <metahttp-equiv="description"content="This is my page">

  </head>

  <body>

      ${requestScope.username }<br>

      ${sessionScope.username }<br>

      ${applicationScope.username }<br>

      ${param.cid }<br>

     <br>

     <br>

  </body>

</html>

2OGNL表达式语言

1):#号的用法(访问Context中的对象)

用法1:访问OGNL上下文和Action上下文,#相当ActionContext.getContext()

1 如果访问其他Context中的对象,由于他们不是根对象,所以在访问时,需要添加#前缀。

这里:也可写为#request[userName]#session[userName]#appliction[userName]

 

实例:

Action中代码:

 ServletActionContext.getRequest().setAttribute("username", "username_request");

 

 ServletActionContext.getServletContext().setAttribute("username", "username_application");

 

 ServletActionContext.getContext().getSession().put("username", "username_session");

 

 ValueStack valueStack=ServletActionContext.getContext().getValueStack();

 valueStack.set("username", "username_valueStack");

 //传递cid的属性值

 

Jsp页面:

    使用ognl表达式取值*****************************<br>

    request:<s:property value="#request.username"/><br>

    session:<s:property value="#session.username"/><br>

    application:<s:property value="#application.username"/><br>

    attr:<s:property value="#attr.username"/><br>

    valueStack:<s:property value="username"/><br>

parameters:<s:property value="#parameters.cid[0]"/><br>

获取的数据参考:

2):#号的用法(访问根对象Root

访问OGNL上下文和Action上下文,#相当ActionContext.getContext()

2OGNL会设定一个根对象(root对象),在Struts2中根对象就是ValueStack(值栈)。如果要访问根对象(即ValueStack)中对象的属性,则可以省略#命名对象,直接访问该对象的属性即可。

 

OgnlValueStack类里有一个List类型的root变量,他存放了一组对象,处于第一位的对象叫栈顶对象

通常我们在OGNL表达式里直接写上属性的名称即可访问root变量里对象的属性,

搜索顺序是从栈顶对象开始寻找,如果栈顶对象不存在该属性,就会从第二个对象寻找,如果没有找到就从第三个对象寻找,依次往下访问,直到找到为止。

例如:

 

3):#号的用法(集合的投影和过滤)(了解)

集合的投影(只输出部分属性)(过滤)

1、集合的投影(只输出部分属性)   

           collectionName.{expression }

 <s:iterator value="allList.{name}" var="person">

           <s:property/>  <br>

 </s:iterator>

2、集合的过滤(年龄大于19

1) 集合的过滤有以下三种方式:
     a.?#”:过滤所有符合条件的集合,如:users.{?#this.age > 19}
     b.^#”:过滤第一个符合条件的元素,如:users.{^#this.age > 19}
     c.$#”:过滤最后一个符合条件的元素,如:users.{$#this.age > 19} 
 .2) this   表示集合中的元素;

 <s:iterator value="allList.{?#this.age>25}" var="person">

        <s:property value="name"/>  xxxxxx  <s:property value="age"/> <br>

 </s:iterator>

 

3、集合的投影和过滤

投影(过滤)操作返回的是一个集合,可以使用索引取得集合中指定的元素,如:users.{?#this.age > 19}[0]

 <s:iterator value="allList.{?#this.age>25}.{name}" var="person">

        <s:property/><br>

    </s:iterator>

 

 <s:iterator value="allList.{?#this.age>25}[0]" var="person">

        <s:property/><br>

  </s:iterator>

4):#号的用法(构造map集合)

构造Map,如#{foo1:bar1,foo2:bar2}。这种方式常用在给radioselectcheckbox等标签赋值上 

Action中的代码:

       Map map=new HashMap();

       map.put("male", "");

       map.put("female", "");

       ServletActionContext.getRequest().setAttribute("map", map);

  jsp页面:

       <s:property value="#request.map.male"/><br>

       <s:property value="#request.map['female']"/><br>

 运行结果是

       

jsp页面:

      <s:radio list=“#{‘male’:‘’,‘female’:‘’}” name=“sex”  label=“性别” />

运行结果是

     <input type="radio" name="sex" id="sexmale" value="male"/>

     <input type="radio" name="sex" id="sexfemale" value="female"/>

 

 

5):%号的用法

“%”符号的用途是在标签的属性值被理解为字符串类型时,告诉执行环境%{}里的是OGNL表达式。

 

6):$号的用法

“$”有两个主要的用途

    * 用于在国际化资源文件中,引用OGNL表达式

    * Struts 2配置文件中,引用OGNL表达式

 

7):测试代码

l         Jsp页面

测试ognl<br>

        <ahref="${pageContext.request.contextPath}/ognl/ognlAction_test.action?cid=9&cid=10">test</a><br>

 

l         Action类定义:

@SuppressWarnings("serial")

publicclass OgnlActionextends ActionSupport {

   

    private String []cid;

   

    private Stringname="oname";

 

    public StringgetName() {

        returnname;

    }

 

    publicvoid setName(String name) {

        this.name = name;

    }

 

    public String [] getCid() {

        returncid;

    }

 

    publicvoid setCid(String [] cid) {

        this.cid = cid;

    }

 

    public String test(){

        System.out.println("欢迎访问OgnlActiontest方法");

//      System.out.println("cid:"+cid);//如果页面传递cid是一个数组的时候,此时用String获取,值之间用逗号分开,并且存在空格

        System.out.println(cid[0]+"       "+cid[1]);

        ServletActionContext.getRequest().setAttribute("username","request_username");

        ServletActionContext.getContext().getSession().put("username","session_username");

        ServletActionContext.getServletContext().setAttribute("username","application_username");

       

        //获取OGNL的值栈对象,方式一

        ValueStack valueStack = ServletActionContext.getContext().getValueStack();

        System.out.println("valueStack"+valueStack);

       

        valueStack.set("usernameStack","usernameStack");

       

        //向值栈中的root栈中添加数据

//      valueStack.getRoot().add(new Student());//最加到最后

//      valueStack.getRoot().add(new Employee());

        //放置到栈顶

        valueStack.getRoot().add(0, new Student());

        valueStack.getRoot().add(1, new Employee());

       

        //构造Map集合

       Map map=newHashMap();

       map.put("male", "");

       map.put("female","");

       ServletActionContext.getRequest().setAttribute("map", map);

        return"success";

    }

}

Student.java

publicclass Student {

    private Integerid=1;

    private Stringname="sname";

}

Employee.java

publicclass Employee {

    private Stringname="ename";

    private Doublesalary=3000d;

}

 

l         Struts.xml配置:

<struts>

    <packagename="ognl"namespace="/ognl"extends="struts-default">

        <!-- 测试OGNL表达式从值栈中放值和取值 -->

        <action name="ognlAction_*"class="cn.itcast.ognl.OgnlAction"method="{1}">

            <result name="success">/ognl/ognl.jsp?pusername=${#request.username}</result>

        </action>

   </package>

</struts>

l         定义ognl.properties文件,用来支持国际化

valueStackTag=${\#request.username}

l         显示ognl.jsp

<%@taglib uri="/struts-tags"  prefix="s"%>

<html>

  <head>

    <title>My JSP 'index.jsp' starting page</title>

    <metahttp-equiv="description"content="This is my page">

  </head>

  <body>

     <!-- 使用el表达式输出 -->

      ${requestScope.username }<br>

      ${sessionScope.username }<br>

      ${applicationScope.username }<br>

      ${param.cid }<br>

     <!-- 使用OGNL表达式,配合struts2的标签 -->

      <s:property value="#request.username"/>--------<s:propertyvalue="#request['username']"/><br>

      <s:property value="#session.username"/>--------<s:propertyvalue="#session['username']"/><br>

      <s:property value="#application.username"/>--------<s:propertyvalue="#application['username']"/><br>

      <s:property value="#parameters.cid"/>--------<s:propertyvalue="#parameters.cid[0]"/>------<s:propertyvalue="#parameters.cid[1]"/><br>

      <s:property value="cid[0]"/>-----------<s:propertyvalue="cid[1]"/>

      <hr>

      输出值栈中的对象<br>

      <s:property value="usernameStack"/><br>

      <hr>

      OGNL表达式语言(#号的用法)<br>

       用法1:访问OGNL上下文和Action上下文,#相当ActionContext.getContext()

      <br>

      attr:

      <s:property value="#attr.username"/><br>

      

      测试root栈的对象<br>

      <s:property value="id"/>--------<s:propertyvalue="name"/>--------<s:propertyvalue="salary"/><br>

     

     <hr>

     用法3:构造Map,如井{‘foo1’:‘bar1’, ‘foo2’:‘bar2’}<br>

    <s:radioname="sex"list="#{'man':'','women':''}"></s:radio>

    <hr>

    使用Action传递Map集合进行遍历<br>

    <s:propertyvalue="#request.map.male"/>---------<s:propertyvalue="#request.map.female"/><br>

    <s:propertyvalue="#request.map['male']"/>---------<s:propertyvalue="#request.map['female']"/><br>

    <s:radioname="sex1"list="#request.map"></s:radio>

    <hr>

    “%”符号的用途是在标签的属性值被理解为字符串类型时,告诉执行环境%{}里的是OGNL表达式。<br>

    %{}用法一:让%{}括号中间的内容是OGNL表达式<br>

    <s:propertyvalue="#request.username"/>------<s:propertyvalue="%{#request.username}"/><br>

    %{}用法二:{ }中值用 ’ 引起来,此时不再是ognl表达式,而是普通的字符串<br>

    <s:propertyvalue="%{'#request.username'}"/><br>

    <hr>

    “$”有两个主要的用途

    用法一:用于在国际化资源文件中,引用OGNL表达式<br>

    <s:i18nname="cn.itcast.ognl.ognl">

        <s:text name="valueStackTag"></s:text>

    </s:i18n>

    <br>

    用法二:在Struts 2配置文件中,引用OGNL表达式<br>

    <s:propertyvalue="#parameters.pusername"/>

     

      <s:debug/>

     <br>

  </body>

</html>

 

 

3OGNL标签

1property标签

property标签用于输出指定值:

<s:property value=#name"default="a default value" />    

     *  default:可选属性,如果需要输出的属性值为null,则显示该属性指定的值

     *  escape:可选属性,指定是否格式化HTML代码。

     *  value:可选属性,指定需要输出的属性值,如果没有指定该属性,则默认输出ValueStack栈顶的值。

例子:

    <s:property/>:输出栈顶的值

           输出: username=username_valueStack, msgxx=msg_valueStack

    <s:property value="%{'<hr> hr的使用'}"  escape="false"  />

           输出:<hr> hr的使用

           :escape=false”时,hr作为html标签使用

 

2set标签

set标签用于将某个值放入指定范围。

    var:变量的名字,name,idvar表达的含义是一样的,name,idvar替代

    scope:指定变量被放置的范围,该属性可以接受applicationsessionrequest pageaction。如果没有设置该属性,则默认放置在action中。

    value:赋给变量的值.如果没有设置该属性,则将ValueStack栈顶的值赋给变量。

例子:

      <s:set value="#request.username"  var="xxx scope=request /><br>

      <s:property value=#request.xxx" /><br>

 

     

      <s:set value="#request.username"  var="xxx" scope="page" /><br>

      <s:property value="#attr.xxx" /><br>

 

      <s:set value="#request.username"  var="xxx" /><br>

      <s:property value="xxx" /><br>

     或者:<s:property value=#xxx" /><br>

 

3push标签

push:将对象放入栈顶,不能放入其他范围,当标签结束,会从栈顶删除。

     value:要push到堆栈中的值

例子:    

   <s:push value="#request.username">

           <s:property/>

   </s:push>

   <br>

  测试删除: <s:property/>

4bean标签

bean标签:实例化一个符合JavaBeans规范的class,标签体内可以包含几个Param元素,用于调用setter方法给此class的属性赋值.

    name:要被实例化的class名字(必须符合JavaBeans规范)

    var:赋给变量的值.放置在request作用域中,如果没有设置该属性,则对象被放置到栈顶

例子:

<s:bean  name="cn.itcast.bean.Person" var="myperson">

       <s:param name="name" value="%{'zhang'}"></s:param>

       <s:param name="age" value="34"></s:param>

</s:bean><br>

 

<s:property value="#myperson.name"/>

 

5action标签

Action:通过指定命名空间和action名称,该标签允许在jsp页面直接调用Action

    name:action名字(不包括后缀,.action)

    namespace:action所在命名空间

    executeResult:Actionresult是否需要被执行,默认值是false不执行

例子:

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

        <action name="ognlAction_*" class="cn.itcast.ognl.OgnlAction" method="{1}">

           <result name="ognl">/ognl/ongl.jsp?msg=${msgxx}</result>

        </action>  

</package>  

 

<s:action name="ognlAction_test" namespace="/ognl" executeResult="true" />

 

6iterator标签

l         使用方式一:

Iterator:标签用于对集合进行迭代,这里的集合包含ListSet和数组。

value:可选属性,指定被迭代的集合,如果没有设置该属性,则使用ValueStack栈顶的集合。

var   可选属性,引用变量的名称.

status:可选属性,该属性指定迭代时的IteratorStatus实例。该实例包含如下几个方法:

       int getCount(),返回当前迭代了几个元素。

       int getIndex(),返回当前迭代元素的索引。

       boolean isEven(),返回当前被迭代元素的个数是否是偶数

       boolean isOdd(),返回当前被迭代元素的个数是否是奇数

       boolean isFirst(),返回当前被迭代元素是否是第一个元素。

       boolean isLast(),返回当前被迭代元素是否是最后一个元素。

例子:

Action类,组织allList集合

for(int i=0;i<10;i++){

Person p=new Person();

p.setId(i);

p.setName("tom"+i);

p.setAge(20+i);

allList.add(p);

}

ServletActionContext.getRequest().setAttribute("allList", allList);

 

    <s:iterator value="#request.allList var=person>

        <s:property value="name"/><br>

        <s:property value=#person.name/>

    </s:iterator>

  

   <s:iterator value="#request.allList" var="person" begin="2" end="7"  step="2">

        <s:property value="#person.name"/><s:property value="#person.age"/><br>

    </s:iterator>      

 

 

l         使用方式二:

st下的属性在:org.apache.struts2.views.jsp.IteratorStatus类下

例子:遍历表格,实现表格逐行变色

<style type="text/css"

   .odd{

           background-color: red;

   .even{

           background-color:blue;}

  </style>

<s:iterator value="allList" status="st">

        st.getCount():<s:property value="#st.count"/> &nbsp;&nbsp;

        st.getIndex():<s:property value="#st.index"/>  &nbsp;&nbsp;

        st.isEven():<s:property value="#st.even"/>&nbsp;&nbsp;

        st.isOdd():<s:property value="#st.odd"/>&nbsp;&nbsp;

        st.isFirst:<s:property value="#st.first"/>&nbsp;&nbsp;

        st.isLast():<s:property value="#st.last"/><br>

 </s:iterator> 

   

   <table border="1"> 

       <s:iterator value="allList" var="person" status="st">

          <tr class=<s:property value="#st.even?'even':'odd'"/>  >

             <td><s:property value="#person.name"/></td>

          </tr>

       </s:iterator> 

   </table>

 

7if/elseif/else标签

if/elseif/else 基本的流程控制.if’标签可单独使用也可以和‘else if’标签和()一个多个‘else’一起使用

<s:if test="#age==23">

       23

</s:if>

<s:elseif test="#age==21">

       21

</s:elseif>

<s:else>

      都不等

</s:else>

例子

<table border="1"> 

       <s:iterator value="allList" var="person">

          <tr>

             <td><s:property value="#person.name"/></td>

             <td><s:property value="#person.age"/></td>

             <td><s:if test="#person.age<24">少年</s:if>

                 <s:elseif test="#person.age<26">中年</s:elseif>

                 <s:else>老年</s:else>

             </td>

          </tr>

       </s:iterator> 

   </table>

 

8url标签

url:该标签用于创建url,可以通过"param"标签提供request参数.

     value:如果不提供就用当前action,使用value后缀必须加.action

     action:用来生成urlaction,如果没有则使用value

     namespace :命名空间

     var:引用变量的名称.

例子:

使用action<br>

    <s:url action="ognlTagAction_test" namespace="/ognl" var="myurl">

         <s:param name="name" value="%{'张老师'}"></s:param>

         <s:param name="id" value="12"></s:param>

    </s:url>

   注意:当使用url时,应配合使用struts2a标签

    <s:a href="%{#url}" >xxxx</s:a><br>   

   使用value<br>

    <s:url value="ognlTagAction_test.action" namespace="/ognl" var="myurl">

         <s:param name="id" value="12"></s:param>

         <s:param name="cnname" value="%{'zhang'}"></s:param>

    </s:url>

    <s:a href="%{#myurl}" >xxxx</s:a><br>   

比较:<a href=“<s:property value=‘%{#myurl}’/>”>链接</a><br>的不同

 

9ogln操作集合

l         使用ognl操作list和数组.

例子:

Action:

List<Person> allList = new ArrayList<Person>();

           for(int i=0;i<10;i++){

                  Person p=new Person();

                  p.setId(i);

                  p.setName("tom"+i);

                  p.setAge(20+i);

                  allList.add(p);

           }

           ServletActionContext.getRequest().setAttribute("allList", allList);

Jsp:

      集合的长度:<s:property value="allList.size"/>

输出第一个元素:<s:property value="allList[0]"/>~~

               <s:property value="allList[0].name"/>~~

               <s:property value="allList[0].age"/>

 

l         使用ognl操作list和数组.

        ognl也可直接创建集合对象.利用下拉列表框:

 

例子:

Jsp:

 <s:iterator value="{1,2,3,4}">

     <s:property/>   <br>

  </s:iterator>

  

  <s:iterator value="{'s1','s2','s3','s4'}" var="s">

     <s:property value="#s"/>  <br>

  </s:iterator>

 

l         使用ognl操作map

    ognl用多种方式使用#号,每种是不同的.动态map对于动态单选按扭组很有用,创建map与创建list语法很相似,不同的是map前需要加"#".

 

 

例子:

<s:iterator value="#{'key01':'value01','key02':'value02'}">

    <s:property/>   <br>

</s:iterator>

 

<s:iterator value="#{'key01':'value01','key02':'value02'}">

     key=<s:property value="key"/>   value=<s:property value="value"/> <br>

</s:iterator>

  

  

<s:iterator value="#{'key01':'value01','key02':'value02'}" var="map">

   key=<s:property value="#map.key"/>  value=<s:property value="#map.value"/> <br>

</s:iterator>

 

 

10)测试代码

l         Jsp页面

测试标签<br>

        <ahref="${pageContext.request.contextPath}/ognl/ognlTagAction_test.action?cid=9">test</a><br>

l         Action

publicclass OgnlTagActionextends ActionSupport {

   

    public String test(){

        System.out.println("欢迎访问OgnlTagActiontest方法");

        ServletActionContext.getRequest().setAttribute("username","request_username");

        ServletActionContext.getContext().getSession().put("username","session_username");

        ServletActionContext.getServletContext().setAttribute("username","application_username");

       

        //获取OGNL的值栈对象,方式一

        ValueStack valueStack = ServletActionContext.getContext().getValueStack();

        System.out.println("valueStack"+valueStack);

       

        valueStack.set("valueStack","valueStack");

       

       //构造List集合

        List<Person> allList =new ArrayList<Person>();

       for(int i=0;i<10;i++){

            Person p=new Person();

            p.setId(i);

            p.setName("tom"+i);

           p.setAge(20+i);

            allList.add(p);

       }

        ServletActionContext.getRequest().setAttribute("allList", allList);

        return"success";

    }

}

l         Struts.xml文件

<struts>

    <packagename="ognl"namespace="/ognl"extends="struts-default">

        <!-- 测试OGNL表达式在struts2的标签用法 -->

        <action name="ognlTagAction_*"class="cn.itcast.ognl.OgnlTagAction"method="{1}">

            <result name="success">/ognl/ognlTag.jsp</result>

        </action>

    </package>

</struts>

 

l         显示ognlTag.jsp页面

<%@page language="java"pageEncoding="utf-8"%>

<%@taglib uri="/struts-tags"  prefix="s"%>

<html>

  <head>

    <title>My JSP 'index.jsp' starting page</title>

    <metahttp-equiv="description"content="This is my page">

  </head>

  <styletype="text/css">

       .odd{

           background-color: red;}

       .even{

           background-color:blue;}

  </style>

  <body>

    

   

    <hr>

    property标签用于输出指定值:   <br>

     * default:可选属性,如果需要输出的属性值为null,则显示该属性指定的值<br>

     *  escape:可选属性,指定是否格式化HTML代码。默认值是true,不解析HTML标签<br>

     *  value   可选属性,指定需要输出的属性值,如果没有指定该属性,则默认输出ValueStack栈顶的值。<br>

   

    <s:propertyvalue="#request.usernamexxxxxx"default="<fontcolor='red'>abc</font>"escape="false"/><br>

    <s:property/><br>

    <hr>

    set标签用于将某个值放入指定范围,用来设置值。<br>

       var:变量的名字,name,idvar表达的含义是一样的,name,idvar替代<br>

       scope:指定变量被放置的范围,该属性可以接受applicationsessionrequest page

                      action。如果没有设置该属性,则默认放置在action中。<br>

       value:赋给变量的值.如果没有设置该属性,则将ValueStack栈顶的值赋给变量。<br>

    <s:setvalue="#request.username"var="vusername"></s:set>

    <s:propertyvalue="#vusername"/>-----<s:propertyvalue="vusername"/><br>

   

    <s:setvalue="%{#request.username}"var="rusername"scope="request"></s:set>

    <s:propertyvalue="#request.rusername"/><br>

    <hr>

    push:将对象放入栈顶,不能放入其他范围,当标签结束,会从栈顶删除。<br>

     value:要push到堆栈中的值<br>

    <s:pushvalue="%{#request.username}">

    <s:property/>

    </s:push>

    <hr>

    bean标签:实例化一个符合JavaBeans规范的class,标签体内可以包含几个Param元素,

                 用于调用setter方法给此class的属性赋值.<br>

       name:要被实例化的class名字(必须符合JavaBeans规范)<br>

       var赋给变量的值.放置在request作用域中<br>

                如果没有设置该属性,则对象被放置到栈顶<br>

    <s:bean name="cn.itcast.j_ognl.Person"var="myperson">

    <s:paramname="id"value="1"></s:param>

       <s:param name="name"value="%{'zhang'}"></s:param>

       <s:param name="age"value="34"></s:param>

    </s:bean><br>

    <s:propertyvalue="#myperson.id"/>-----<s:propertyvalue="#myperson.name"/>-----<s:propertyvalue="#myperson.age"/>

    <hr>

    Action:通过指定命名空间和action名称,该标签允许在jsp页面直接调用Action<br>

       name:action名字(不包括后缀,.action)<br>

       namespace:action所在命名空间   <br>

       executeResult:Actionresult是否需要被执行,默认值是false不执行<br>

    <s:actionname="valueStackAction_test"namespace="/ognl"executeResult="false">

   

    </s:action>

    <hr>

    Iterator:标签用于对集合进行迭代,这里的集合包含ListSet和数组。<br>

    value:可选属性,指定被迭代的集合,如果没有设置该属性,则使用ValueStack栈顶的集合。<br>

    var   可选属性,引用变量的名称. <br>

    status:可选属性,该属性指定迭代时的IteratorStatus实例。该实例包含如下几个方法:<br>

        int getCount(),返回当前迭代了几个元素。

        int getIndex(),返回当前迭代元素的索引。

        boolean isEven(),返回当前被迭代元素个数是否是偶数

        boolean isOdd(),返回当前被迭代元素个数是否是奇数

        boolean isFirst(),返回当前被迭代元素是否是第一个元素。

        boolean isLast(),返回当前被迭代元素是否是最后一个元素。<br>

    <s:iteratorvalue="#request.allList"var="person">

        <s:property value="id"/>----<s:propertyvalue="name"/>-----<s:propertyvalue="age"/><br>

        <s:property value="#person.id"/>----<s:propertyvalue="#person.name"/>-----<s:propertyvalue="#person.age"/><br>

    </s:iterator>

    <br>

    begin:从第几个值开始(默认是0 end:到哪个值结束 step:步长<br>

    <s:iteratorvalue="#request.allList"var="person"begin="2"end="7"step="2">

        <s:property value="#person.id"/>----<s:propertyvalue="#person.name"/>-----<s:propertyvalue="#person.age"/><br>

    </s:iterator>

    <br>

    st下的属性在:org.apache.struts2.views.jsp.IteratorStatus类下<br>

    <s:iteratorvalue="#request.allList"var="person"status="st">

        <s:property value="#st.count"/>---<s:propertyvalue="#st.index"/>---

        <s:property value="#st.even"/>---<s:propertyvalue="#st.odd"/>---

        <s:property value="#st.first"/>---<s:propertyvalue="#st.last"/><br>

    </s:iterator>

    <br>

    表格逐行变色

    <tableborder="1">

        <tr>

            <td>id</td>

            <td>name</td>

            <td>age</td>

        </tr>

        <s:iterator value="#request.allList"var="person"status="st">

            <tr class="<s:propertyvalue="#st.odd?'odd':'even'"/>">

               <td><s:propertyvalue="#person.id"/></td>

               <td><s:propertyvalue="#person.name"/></td>

               <td><s:propertyvalue="#person.age"/></td>

            </tr>

        </s:iterator>

    </table>

    <br>

    <hr>

    if/elseif/else 基本的流程控制.‘If’标签可单独使用也可以和‘Else If’标签和()一个多个‘Else’一起使用<br>

    <tableborder="1">

        <tr>

            <td>id</td>

            <td>name</td>

            <td>age</td>

            <td>年龄段</td>

        </tr>

        <s:iterator value="#request.allList"var="person"status="st">

            <tr class="<s:propertyvalue="#st.odd?'odd':'even'"/>">

               <td><s:propertyvalue="#person.id"/></td>

               <td><s:propertyvalue="#person.name"/></td>

               <td><s:propertyvalue="#person.age"/></td>

               <td>

                   <s:if test="%{#person.age>=20 && #person.age<=24}">

                       少年

                   </s:if>

                   <s:elseiftest="%{#person.age>=25 && #person.age<28}">

                       青年

                   </s:elseif>

                   <s:else>

                       老年

                   </s:else>

               </td>

            </tr>

        </s:iterator>

    </table>

    <br>

    <hr>

    url:该标签用于创建url,可以通过"param"标签提供request参数.<br>

     value:如果不提供就用当前action,使用value后缀必须加.action<br>

     action:用来生成urlaction,如果没有则使用value<br>

     namespace :命名空间<br>

     var:引用变量的名称.<br>

     s:url标签配合s:a使用,否则传递多个参数会有问题

    <s:urlaction="valueStackAction_test"namespace="/ognl"var="myurl">

    <s:paramname="username"value="%{'张三'}"></s:param>

    <s:paramname="age"value="30"></s:param>

    </s:url>

   

    <ahref="<s:propertyvalue="%{#myurl}"/>">错误连接</a>

    <s:ahref="%{#myurl}">正确连接</s:a>

    <hr>

    ognl操作集合<br>

    <s:propertyvalue="#request.allList.size"/><br>

    <s:propertyvalue="#request.allList[0].name"/><br>

    <s:propertyvalue="#request.allList[9].age"/><br>

    使用ognl操作list和数组.

        ognl也可直接创建集合对象.利用下拉列表框:

        使用{}指定list集合

        如果添加#号此时是一个map集合

    <br>

    <s:iteratorvalue="{1,2,3,4}">

        <s:property/>

    </s:iterator><br>

    <s:iteratorvalue="{'s1','s2','s3','s4'}"var="ss">

        <s:property/>----<s:propertyvalue="#ss"/><br>

    </s:iterator><br>

    <hr>

    使用ognl操作map<br>

    ognl用多种方式使用#号,每种是不同的.动态map对于动态单选按扭组很有用.

    创建map与创建list语法很相似,不同的是map前需要加"#".<br>

    <s:iteratorvalue="#{'man':'','women':''}">

    <s:propertyvalue="key"/>--------<s:propertyvalue="value"/>

    </s:iterator><br>

    <s:iteratorvalue="#{'man':'','women':''}"var="ms">

    <s:propertyvalue="key"/>--------<s:propertyvalue="value"/><br>

    <s:propertyvalue="#ms.key"/>--------<s:propertyvalue="#ms.value"/><br>

    </s:iterator><br>

    <hr>

    补充:<br>

    用法2:集合的投影(只输出部分属性)(过滤)

    1、集合的投影(只输出部分属性)   

           collectionName.{ expression }<br>

    <s:iteratorvalue="#request.allList.{name}">

        <s:property/><br>

    </s:iterator><br>

    用法2:集合的投影(过滤)

    2、集合的过滤(年龄大于19

     1)集合的过滤有以下三种方式:

         a.“?#”:过滤所有符合条件的集合,如:users.{?#this.age > 19}

         b.“^#”:过滤第一个符合条件的元素,如:users.{^#this.age > 19}

         c.“$#”:过滤最后一个符合条件的元素,如:users.{$#this.age > 19} 

     2) this   表示集合中的元素;<br>

    <s:iteratorvalue="#request.allList.{?#this.age>24}">

        <s:property value="id"/>---<s:propertyvalue="name"/>---<s:propertyvalue="age"/><br>

    </s:iterator><br>

   

    <s:iteratorvalue="#request.allList.{^#this.age>24}">

        <s:property value="id"/>---<s:propertyvalue="name"/>---<s:propertyvalue="age"/><br>

    </s:iterator><br>

   

    <s:iteratorvalue="#request.allList.{$#this.age>24}">

        <s:property value="id"/>---<s:propertyvalue="name"/>---<s:propertyvalue="age"/><br>

    </s:iterator><br>

   

    <br>

    用法2:集合的投影(过滤)(综合)

    3、集合的投影和过滤

         投影(过滤)操作返回的是一个集合,可以使用索引取得集合中指定的

         元素,如:users.{?#this.age > 19}[0]<br>

    <s:iteratorvalue="#request.allList.{?#this.age>24}.{name}">

        <s:property/><br>

    </s:iterator><br>

   

    <s:debug></s:debug>

  </body>

</html>

 

 

 

3UI标签

UI标签概述:

l       表单标签将在 HTML文档里被呈现为一个表单元素

l       使用表单标签的优点:

         表单回显

         对页面进行布局和排版

l       标签的属性可以被赋值为一个静态的值或一个 OGNL表达式. 如果在赋值时使用了一个 OGNL表达式并把它用 %{} 括起来, 这个表达式将会被求值.

 

表单标签的共同属性

 

这里注意:* 该属性只在没有使用 theme=simple 主题时才可以使用.

 

1form标签

 

默认情况下, form标签将被呈现为一个表格形式的 HTML表单. 嵌套在 form标签里的输入字段将被呈现为一个表格行. 每个表格行由两个字段组成,一个对应着行标, 一个对应着输入元素.提交按钮将被呈现为一个横跨两列单元格的行

例子:

<s:formid="form1"name="form1"namespace="/ui"action="uiTagAction_ui"method="post">

</s:from>

 

2textfield, password, hidden标签

textfield 标签将被呈现为一个输入文本字段, password标签将被呈现为一个口令字段, hidden 标签将被呈现为一个不可见字段.

password 标签扩展自 textfield标签, 多了一个 showPassword属性.该属性是布尔型.默认值为 false, 它决定着在表单回显时是否显示输入的密码. true显示密码

 

例子:

用户名:<s:textfieldname="username"id="username"label="用户名"value="张三"></s:textfield><br>

密码:<s:passwordname="password"id="password"value="123456"showPassword="true"></s:password><br>

隐藏域:<s:hiddenname="id"id="id"value="1"></s:hidden><br>

 

3submit标签

l       submit 标签将呈现为一个提交按钮. 根据其 type属性的值. 这个标签可以提供 3种呈现效果:

         input: <input type=submit value=“提交”…/>

         button: <input type=button value=“确定” …/>

         image: <input type=image value=“图片” src=“XX.jpg”/>

例子:

<s:submit type="input"value="提交1"></s:submit><br>

<s:submittype="button"value="提交2"></s:submit><br>

<s:submittype="image"src="button_ok.gif"value="提交3"></s:submit><br>

 

4reset标签

reset 标签将呈现为一个重置按钮.根据其 type 属性的值.

这个标签可以提供 2种呈现效果:

         input: <input type=reset value=“重置”…/>

         button: <input type=button value=“重置按键/>

例子:

<s:resettype="input"value="重置1"></s:reset><br>

<s:resettype="button"value="重置2"></s:reset><br>

 

5label标签

label 标签将呈现一个 HTML行标元素:

例子:

<s:labelvalue="123"></s:label>

 

6textarea标签

textarea 标签将呈现为一个 HTML文本域元素

例子:

<s:textareaname="remark"id="remark"cols="30"rows="10"value="学习struts2UI"></s:textarea>

 

7checkbox标签

l       checkbox 标签将呈现为一个 HTML 复选框元素.

l       与其他 HTML输入元素类似, 当包含着一个复选框的表单被提交时,这个单选框按钮在 HTTP 请求里增加一个请求参数.如果某个复选框被选中了, 它的值将为true, 如果该复选框未被选中,在请求中就不会增加一个请求参数. checkbox标签解决了这个局限性, 它采取的办法是为复选框元素创建一个配对的不可见字段

checkbox 标签有一个fieldValue 属性, 该属性指定的值将在用户提交表单时作为被选中的复选框的实际值发送到服务器. 如果没有使用 fieldValue 属性,复选框的值将为 true false.

 

例子:

足球:<s:checkboxname="ball"fieldValue="football"></s:checkbox>

篮球:<s:checkboxname="ball"fieldValue="basketball"></s:checkbox>

 

 

8checkboxlist标签

checkboxlist 标签将呈现一组多选框.

注意:checkboxlist标签被映射到一个字符串数组或是一个基本类型的数组. 若它提供的多选框一个也没有被选中, 相应的属性将被赋值为一个空数组而不是空值

例子

如果集合为list

<s:checkboxlist name="list" list="{'Java','.Net','RoR','PHP'}" value="{'Java','.Net'}"/>

生成如下html代码:

<input type="checkbox" name="list" value="Java" checked="checked"/><label>Java</label>

<input type="checkbox" name="list" value=".Net" checked="checked"/><label>.Net</label>

<input type="checkbox" name="list" value="RoR"/><label>RoR</label>

<input type="checkbox" name="list" value="PHP"/><label>PHP</label>

 

如果集合为MAP

<s:checkboxlist name="map" list="#{1:'瑜珈用品',2:'户外用品',3:'球类',4:'自行车'}" listKey="key" listValue="value" value="{1,2,3}"/>

生成如下html代码:

<input type="checkbox" name="map" value="1" checked="checked"/><label>瑜珈用品</label>

<input type="checkbox" name="map" value="2" checked="checked"/><label>户外用品</label>

<input type="checkbox" name="map" value="3" checked="checked"/><label>球类</label>

<input type="checkbox" name="map" value="4"/><label>自行车</label>

如果集合里存放的是javabeanjavabean中存在2个属性,分别是idname

 <%

  Person person1 = new Person(1,"第一个");

  Person person2 = new Person(2,"第二个");

  List<Person> list = new ArrayList<Person>();

  list.add(person1);

  list.add(person2);

  request.setAttribute("persons",list);

  %>

<s:checkboxlist name="beans" list="#request.persons" listKey="id" listValue="name"/>

idnamePerson的属性

 

生成如下html代码:

<input type="checkbox" name=beans" value="1"/><label>第一个</label>

<input type="checkbox" name=beans" value="2"/><label>第二个</label>

 

 

 

 

 

9radio标签

radio 标签将呈现为一组单选按钮,单选按钮的个数与程序员通过该标签的 list 属性提供的选项的个数相同.一般地,使用 radio 标签实现多选一”,对于/则该使用 checkbox 标签.

例子:

该标签的使用和checkboxlist复选框相同。

如果集合为list

<s:radio name="list" list="{'Java','.Net'}" value="'Java'"/>

生成如下html代码:

<input type="radio" name="list" checked="checked" value="Java"/><label>Java</label>

<input type="radio" name="list" value=".Net"/><label>.Net</label>

如果集合为MAP

<s:radio name="map" list="#{1:'瑜珈用品',2:'户外用品',3:'球类',4:'自行车'}" listKey="key" listValue="value value="1"/>

生成如下html代码:

<input type="radio" name="map" id="map1" value="1"/><label for="map1">瑜珈用品</label>

<input type="radio" name="map" id="map2" value="2"/><label for="map2">户外用品</label>

<input type="radio" name="map" id="map3" value="3"/><label for="map3">球类</label>

<input type="radio" name="map" id="map4" value="4"/><label for="map4">自行车</label>

如果集合里存放的是javabean(idnamePerson的属性)

<s:radio name="beans" list="#request.persons" listKey="personid" listValue="name"/>

生成如下html代码:

<input type="radio" name="beans" id="beans1" value="1"/><label>第一个</label>

<input type="radio" name="beans" id="beans2" value="2"/><label>第二个</label>

 

 

 

10select标签

select 标签将呈现一个select元素

 

例子:

如果集合为list

<s:select name="list" list="{'Java','.Net'}" value="'Java'"/>

生成如下html代码:

<select name="list" id="list">

    <option value="Java" selected="selected">Java</option>

    <option value=".Net">.Net</option>

</select>

如果集合为MAP

<s:select name="map" list="#{1:'瑜珈用品',2:'户外用品',3:'球类',4:'自行车'}" listKey="key" listValue="value" value="1"/>

生成如下html代码:

<select name="map" id="map">

    <option value="1" selected="selected">瑜珈用品</option>

    <option value="2">户外用品</option>

    <option value="3">球类</option>

    <option value="4">自行车</option>

</select>

如果集合里存放的是javabean(idnamePerson的属性)

<s:select name="beans" list="#request.persons" listKey="personid" listValue="name"/>

生成如下html代码:

<select name="beans" id="beans">

    <option value="1">第一个</option>

    <option value="2">第二个</option>

</select>

 

11UI主题

主题:为了让所有的 UI 标签能够产生同样的视觉效果而归集到一起的一组模板.风格相近的模板被打包为一个主题

    1simple: UI 标签翻译成最简单的 HTML对应元素, 而且会忽视行标属性

    2xhtml: xhtml是默认的主题. 这个主题的模板通过使用一个布局表格提供了一种自动化的排版机制.(默认值)

    3css_xhtml:这个主题里的模板与 xhtml 主题里的模板很相似,但它们将使用 css 来进行布局和排版

    4ajax:这个主题里的模板以 xhtml 主题里德模板为基础,但增加了一些 Ajax 功能.

 

修改主题:

A、通过 UI标签的 theme属性(只适用于当前的标签)

 <s:textfield name="username"  label="用户名theme="simple"></s:textfield>

B、在一个表单里,若没有给出某个 UI 标签的 theme属性, 它将使用这个表单的主题

     (适用于整个form标签)

    <s:form  action="" method="post" namespace="/ui"theme="simple">

C、修改 struts.properties文件中的 struts.ui.theme 属性. (适用整个环境)

    <!-- 设置ui标签的主题 -->

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

 

 

优先级:A>B>C

 

 

12)测试代码

第一步:在页面中定义:

<body>

      UI标签:<br>

        <ahref="${pageContext.request.contextPath}/ui/uiTagAction_ui.action">ui</a><br>

       

  </body>

 

第二步:在Action中定义:

publicclass UiTagActionextends ActionSupport {

 

    private Stringusername;

    private Stringpassword;

   

    publicString getUsername() {

        returnusername;

    }

 

    publicvoid setUsername(String username) {

        this.username = username;

    }

 

    public String getPassword() {

        returnpassword;

    }

 

    publicvoid setPassword(String password) {

        this.password = password;

    }

 

    public String ui(){

        System.out.println("欢迎访问UiTagActionui()方法");

        //表单回显测试,将属性usernamepassword的值放置到栈顶

        this.username="张三";

        this.password="123";

       

        //遍历集合

        List<Person> allList = new ArrayList<Person>();

        for(int i=1;i<=10;i++){

            Person p=new Person();

            p.setId(i);

            p.setName("tom"+i);

            p.setAge(20+i);

            allList.add(p);

        }

        ServletActionContext.getRequest().setAttribute("allList", allList);

        return"success";

    }

}

第三步:struts.xml文件的配置

<?xmlversion="1.0"encoding="UTF-8"?>

<!DOCTYPEstruts PUBLIC

    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"

    "http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>

    <!--设置UI主题,为简单主题,目的去掉struts2提供的样式 -->

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

    <packagename="ui"namespace="/ui"extends="struts-default">

         <action name="uiTagAction_*"class="cn.itcast.k_ui.UiTagAction"method="{1}">

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

         </action>

    </package>

   

</struts>

第四步:使用ui.jsp进行测试

<%@taglib uri="/struts-tags"  prefix="s"%>

<html>

  <head>

    <title>My JSP 'index.jsp' starting page</title>

    <metahttp-equiv="description"content="page">

  </head>

  <body>

    成功!<br>

    <s:formnamespace="/ui"action="uiTagAction_ui.action"name="form"id="form">

    <br>

    <!--

    textfield, password, hidden 标签

         textfield 标签将被呈现为一个输入文本字段, password标签将被

           呈现为一个口令字段, hidden标签将被呈现为一个不可见字段.

       

        生成的html标签

           用户名:<input type="text" name="username" value="张三" id="form_username"/><br>

        密码:<input type="password" name="password" value="123" id="form_password"/><br>

         <input type="hidden" name="id" value="" id="form_id"/><br>

    -->

    用户名:<s:textfieldname="username"label="用户名"></s:textfield><br>

    密码:<s:passwordname="password"label="密码"showPassword="true"></s:password><br>

    <s:hiddenname="id"label="隐藏域id"></s:hidden><br>

    <hr>

    <!--

         submit 标签将呈现为一个提交按钮.根据其 type 属性的值. 这个标签可以提供 3种呈现效果:

               input: <input type=“submit” value=“提交”…/>

               button: <input type=“button” value=“确定” …/>

               image: <input type=“image” value=“图片src=“XX.jpg” …/>

           生成的html标签

           <input type="submit" id="form_submit1" name="submit1" value="提交1"/>

         <button type="submit" id="form_submit2" name="submit2" value="提交2">提交2</button>

           <input type="image" alt="提交3"src="./button_ok.gif" id="form_submit3" name="submit3" value="提交3"/>

         -->

    <s:submittype="input"name="submit1"value="提交1"></s:submit>

    <s:submittype="button"name="submit2"value="提交2"></s:submit>

    <s:submittype="image"src="./button_ok.gif"name="submit3"value="提交3"></s:submit>

     <hr>

    <!--

         reset 标签将呈现为一个重置按钮.根据其 type 属性的值.

           这个标签可以提供 2 种呈现效果:

           input: <input type=“reset” value=“重置”…/>

           button: <input type=“button” value=“重置按键” …/>

        生成的HTML标签

           <input type="reset" value="重置"/>

         <button type="reset" value="重置">重置</button>

     -->

    <s:resettype="input"value="重置"></s:reset>

    <s:resettype="button"value="重置"></s:reset>

    <hr>

    <!--

         label 标签将呈现一个 HTML行标元素:

    生成html标签:

    <label id="form_">显示label标签</label>

     -->

    <s:labelvalue="显示label标签"></s:label>

    <hr>

    <!--

         textarea 标签将呈现为一个 HTML文本域元素

    生成html标签:

         <textarea name="remark" cols="50" rows="5" id="remark"></textarea>

     -->

    <s:textareaname="remark"cols="50"rows="5"id="remark"></s:textarea>

    <hr>

    <!--

         checkbox 标签将呈现为一个 HTML复选框元素.

         checkbox 标签有一个 fieldValue属性, 该属性指定的值将在用

                   户提交表单时作为被选中的单选框的实际值发送到服务器.如果

                   没有使用 fieldValue属性, 复选框的值将为 true false.

        

    生成html标签:

        添加value的属性:

            足球:<input type="checkbox" name="interest" value="true" id="form_interest"/>

                  <input type="hidden" id="__checkbox_form_interest" name="__checkbox_interest" value="true" />

            篮球:<input type="checkbox" name="interest" value="true" id="form_interest"/>

                  <input type="hidden" id="__checkbox_form_interest" name="__checkbox_interest" value="true" />

        添加fieldValue的属性:

             足球:<input type="checkbox" name="interest" value="足球" id="form_interest"/>

                  <input type="hidden" id="__checkbox_form_interest" name="__checkbox_interest" value="足球" />

             篮球:<input type="checkbox" name="interest" value="篮球" id="form_interest"/>

                  <input type="hidden" id="__checkbox_form_interest" name="__checkbox_interest" value="篮球" />

         -->

    足球:<s:checkboxname="interest"fieldValue="足球"></s:checkbox>

    篮球:<s:checkboxname="interest"fieldValue="篮球"></s:checkbox>

    <hr>

    <!--

         checkboxlist 标签将呈现一组多选框.

         checkboxlist 标签被映射到一个字符串数组或是一个基本类型的数组.

          若它提供的多选框一个也没有被选中,相应的属性将被赋值为一个空数组而不是空值

    生成html代码:

         <input type="checkbox" name="course" value="Java" id="course-1"  checked="checked"      />

           <label for="course-1" class="checkboxLabel">Java</label>

           <input type="checkbox" name="course" value=".Net" id="course-2"  checked="checked"      />

           <label for="course-2" class="checkboxLabel">.Net</label>

           <input type="checkbox" name="course" value="RoR" id="course-3"        />

           <label for="course-3" class="checkboxLabel">RoR</label>

           <input type="checkbox" name="course" value="PHP" id="course-4"        />

           <label for="course-4" class="checkboxLabel">PHP</label>

           

           <input type="hidden" id="__multiselect_form_course" name="__multiselect_course" value=""        />

        

     -->

    如果集合为list<br>

    <s:checkboxlistlist="{'Java','.Net','RoR','PHP'}"name="course"value="{'Java','.Net'}"></s:checkboxlist>

    <br>

    如果集合为MAP<br>

    <!--

         <input type="checkbox" name="interest" value="1" id="interest-1"  checked="checked"      />

           <label for="interest-1" class="checkboxLabel">瑜珈用品</label>

           <input type="checkbox" name="interest" value="2" id="interest-2"   checked="checked"     />

           <label for="interest-2" class="checkboxLabel">户外用品</label>

           <input type="checkbox" name="interest" value="3" id="interest-3"        />

           <label for="interest-3" class="checkboxLabel">球类</label>

           <input type="checkbox" name="interest" value="4" id="interest-4"        />

           <label for="interest-4" class="checkboxLabel">自行车</label>

           

           <input type="hidden" id="__multiselect_form_interest" name="__multiselect_interest" value=""        />

        

     -->

    <s:checkboxlistlist="#{1:'瑜珈用品',2:'户外用品',3:'球类',4:'自行车'}"name="interest"value="{1,3}"></s:checkboxlist>

    <br>

    如果集合里存放的是javabeanjavabean中存在3个属性,分别是idname<br>

    <!--

         <input type="checkbox" name="person" value="1" id="person-1"        />

           <label for="person-1" class="checkboxLabel">tom1</label>

           <input type="checkbox" name="person" value="2" id="person-2"        />

           <label for="person-2" class="checkboxLabel">tom2</label>

           <input type="checkbox" name="person" value="3" id="person-3"        />

           <label for="person-3" class="checkboxLabel">tom3</label>

        

     -->

    <s:checkboxlistlist="#request.allList"listKey="id"listValue="name"name="person"></s:checkboxlist>

    <hr>

    <!--

         radio 标签将呈现为一组单选按钮,单选按钮的个数与程序员通过该标签的 list属性提供的选项的个数相同.

           一般地, 使用 radio 标签实现多选一”,对于/则该使用 checkbox标签.

     -->

    <br>

    如果集合为list<br>

    <!--

         <input type="radio" name="courseradio" id="form_courseradioJava" value="Java"/><label for="form_courseradioJava">Java</label>

           <input type="radio" name="courseradio" id="form_courseradio.Net" value=".Net"/><label for="form_courseradio.Net">.Net</label>

           <input type="radio" name="courseradio" id="form_courseradioRoR" value="RoR" checked="checked"/><label for="form_courseradioRoR">RoR</label>

           <input type="radio" name="courseradio" id="form_courseradioPHP" value="PHP"/><label for="form_courseradioPHP">PHP</label>

        

     -->

    <s:radiolist="{'Java','.Net','RoR','PHP'}"name="courseradio"value="{'RoR'}"></s:radio>

    <br>

    如果集合为MAP<br>

    <!--

         <input type="radio" name="interestradio" id="form_interestradio1" value="1"/><label for="form_interestradio1">瑜珈用品</label>

            <input type="radio" name="interestradio" id="form_interestradio2" value="2"/><label for="form_interestradio2">户外用品</label>

           <input type="radio" name="interestradio" id="form_interestradio3" value="3"/><label for="form_interestradio3">球类</label>

           

           <input type="radio" name="interestradio" id="form_interestradio4" value="4"/><label for="form_interestradio4">自行车</label>

        

     -->

    <s:radiolist="#{1:'瑜珈用品',2:'户外用品',3:'球类',4:'自行车'}name="interestradio"value="3"></s:radio>

    <br>

    如果集合里存放的是javabean(idnamePerson的属性)<br>

    <!--

         <input type="radio" name="personradio" id="form_personradio1" value="1"/><label for="form_personradio1">tom1</label>

           <input type="radio" name="personradio" id="form_personradio2" value="2"/><label for="form_personradio2">tom2</label>

           <input type="radio" name="personradio" id="form_personradio3" value="3"/><label for="form_personradio3">tom3</label>

     -->

    <s:radiolist="#request.allList"listKey="id"listValue="name"name="personradio"value="5"></s:radio>

    <hr>

    如果集合为list<br>

    <!--

         <select name="courseselect" id="form_courseselect">

               <option value="Java">Java</option>

               <option value=".Net" selected="selected">.Net</option>

               <option value="RoR">RoR</option>

               <option value="PHP">PHP</option>

           

           </select>

        

     -->

    <s:selectlist="{'Java','.Net','RoR','PHP'}"name="courseselect"value="'.Net'"></s:select>

    <br>

    如果集合为Map<br>

    <!--

             <select name="interestselect" id="form_interestselect">

                   <option value="1">瑜珈用品</option>

               

                   <option value="2">户外用品</option>

                   <option value="3">球类</option>

                   <option value="4">自行车</option>

               

               </select>

        

         ---------------------

         <select name="interestselect" size="4" id="form_interestselect" multiple="multiple">

               <option value="1">瑜珈用品</option>

           

               <option value="2">户外用品</option>

               <option value="3" selected="selected">球类</option>

               <option value="4" selected="selected">自行车</option>

           

           

           </select>

        

     -->

    <s:selectlist="#{1:'瑜珈用品',2:'户外用品',3:'球类',4:'自行车'}"multiple="true"size="4"name="interestselect"value="{3,4}"></s:select>

    <br>

    如果集合里存放的是javabean(idnamePerson的属性)<br>

    <!--

              <select name="personselect" id="form_personselect">

                       <option value="0">请选择</option>

                       <option value="1">tom1</option>

                       <option value="2">tom2</option>

                       <option value="3">tom3</option>

                       <option value="4">tom4</option>

                   

                       <option value="5">tom5</option>

                       <option value="6">tom6</option>

                       <option value="7">tom7</option>

                       <option value="8">tom8</option>

                       <option value="9">tom9</option>

                       <option value="10">tom10</option>

                   

                   

                   </select>

        

     -->

    <s:selectlist="#request.allList"listKey="id"listValue="name"name="personselect"headerKey="0"headerValue="请选择"value="{5}"></s:select>

    <br>

   

    </s:form>

  </body>

</html>

 

 

 

四:struts2第四天

1:模型驱动(ModelDriven

在使用 Struts作为前端的企业级应用程序时把动作和模型清晰地隔离开是有必要的(即Model类和Action类分开):有些动作类不代表任何模型对象, 它们的功能仅限于提供图文显示服务

Struts2的这个功能是由ModelDriver拦截器实现的

l       情景:有一个用来处理客户的 CustomerAction , 该动作类实现了 ModelDriven接口.

l       当用户触发CustomerAction动作时, ModelDriven 拦截器将调用相关CustomerAction对象的 getModel() 方法,并把返回的模型(Customer实例)压入到 ValueStack栈的栈顶对象中. 接下来Parameters 拦截器将把表单字段映射到 ValueStack栈的栈顶对象的各个属性中. 因为此时 ValueStack栈的栈顶元素是刚被压入的模型(Customer)对象,所以该模型将被填充. 如果某个字段在模型里没有匹配的属性, Param拦截器将尝试 ValueStack 栈中的下一个对象.

l       一个模型类必须有一个不带任何参数的构造器,即对象被实例化.

l       Struts2的模型驱动将对象放置到栈顶。

 

1)使用模型驱动进行表单回显

方式一:

对模型驱动中的对象赋值

this.customer.setUsername("张三");

this.customer.setPsw("123");

this.customer.setTel("13212121212");

 

方式二:

//实例化javabean对象(Customer),放置栈顶

Customer c = new Customer();

c.setUsername("李四");

c.setPsw("11111");

c.setTel("88888888888");

 

//this.customer = c;

//获取值栈

ValueStack valueStack = ActionContext.getContext().getValueStack(); 

//删除栈顶的对象

valueStack.pop();

//放入新的对象到栈顶

valueStack.push(c);

 

2)测试代码:

l         jsp页面

test.jsp

<ahref="${pageContext.request.contextPath}/model/customerAction_add.action">客户信息录入</a><br>

<ahref="${pageContext.request.contextPath}/model/customerAction_edit.action?id=1">客户信息编辑</a><br>

add.jsp

<%@taglib uri="/struts-tags"  prefix="s"%>

<html>

  <head>

    <title>My JSP 'index.jsp' starting page</title>

    <metahttp-equiv="description"content="This is my page">

  </head>

  <body>

       <s:debug/>

       <s:form action="customerAction_save.action"method="post"

               namespace="/model"theme="simple">

          用户名:<s:textfieldname="username"/><br><s:token/>

          密码:<s:passwordname="psw"/><br>

          电话:<s:textfieldname="tel"/><br>

          <s:submit value="保存"/><br>

       </s:form>

  </body>

</html>

 

edit.jsp

<%@taglib uri="/struts-tags"  prefix="s"%>

<html>

  <head>

    <title>My JSP 'index.jsp' starting page</title>

    <metahttp-equiv="description"content="This is my page">

  </head>

  <body>

       <s:debug/>

       <s:form action="customerAction_update.action"method="post"namespace="/model"theme="simple">

         <!-- 使用struts2的标签来完成回显,栈顶对象中的属性值与struts2标签的name的属性值一致的话,并且有值,那么直接可以进行回显 -->

         <s:hidden name="id"/>

          <!--该标签解析时,自动通过name属性到栈顶查找对应的属性,找到了获取值显示,没有找到就是空值-->

          用户名:<s:textfieldname="username"/><br>

          密码:<s:passwordname="psw"showPassword="true"/><br>

          电话:<s:textfieldname="tel"/><br>

          <!-- jsp回显

          <input type="hidden" name="id" value="${id }"/><br>

          <input type="text" name="username" value="${username }"/><br>-->

          <s:submit value="保存"/><br>

       </s:form>

  </body>

</html>

 

success.jsp

<%@taglib uri="/struts-tags"  prefix="s"%>

<html>

  <head>

    <title>My JSP 'index.jsp' starting page</title>

    </head>

  <body>

  <s:debug></s:debug>

         成功!!!<br>

         <s:property value="username"/><br>

         <s:property value="psw"/><br>

         <s:property value="tel"/>

  </body>

</html>

 

l         struts.xml文件的配置

<?xmlversion="1.0"encoding="UTF-8"?>

<!DOCTYPEstruts PUBLIC

    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"

    "http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>

    <packagename="model"namespace="/model"extends="struts-default">

       

        <action name="customerAction_*"class="cn.itcast.model.CustomerAction"method="{1}">

            <result name="add">/model/add.jsp</result>

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

            <result name="edit">/model/edit.jsp</result>

        </action>

    </package>

</struts>

 

l         Action类文件的配置

publicclass CustomerActionextends ActionSupportimplements ModelDriven<Customer> {

 

    //模型驱动中必须要实例化对象

    private Customer customer = new Customer();

 

    public Customer getModel() {

       return customer;

    }

   

    /**跳转到新增页面*/

    public String add(){

        return"add";

    }

   

    /**保存客户信息*/

    public String save(){

        //获取页面的值

        System.out.println("username:"+customer.getUsername());

        System.out.println("psw:"+customer.getPsw());

        System.out.println("tel:"+customer.getTel());

        ValueStack valueStack = ServletActionContext.getContext().getValueStack();

        System.out.println("valueStack"+valueStack);

        //组织sql语句,执行保存

        return"success";

    }

   

    /**跳转到编辑页面,表单回显*/

    public String edit(){

        //获取id

        Integer id = customer.getId();

        //使用id查询数据库,返回惟一的对象,并放置到模型驱动中

//      customer.setUsername("张三");

//      customer.setPsw("123");

//      customer.setTel("12345678");

       

        Customer c = new Customer();

        c.setId(id);

        c.setUsername("张三");

        c.setPsw("123");

        c.setTel("12345678");

        //customer = c;//错误写法

       

        ServletActionContext.getContext().getValueStack().pop();//将旧的对象删除

        ServletActionContext.getContext().getValueStack().push(c);//将新的对象压入栈顶

       

        ValueStack valueStack = ServletActionContext.getContext().getValueStack();

        System.out.println("valueStack"+valueStack);

        return"edit";

    }

}

l         模型驱动Customer.javajavabean)中的配置

publicclass Customer {

 

    private Integerid;

    private Stringusername;

    private Stringpsw;

    private Stringtel;

}

 

 

2Token令牌(防止表单重复提交)

<s:token />标签防止重复提交,用法如下:

第一步:在表单中加入<s:token />

<s:form action="helloworld_other" method="post" namespace="/test">

  <s:textfield name="person.name"/><s:token/><s:submit/>

</s:form>

第二步:在struts.xml文件中,添加拦截器的配置

<action name="helloworld_*" class="cn.itcast.action.HelloWorldAction" method="{1}">

         <interceptor-ref name="defaultStack"/>

          <!--增加令牌拦截器 -->

          <interceptor-ref name="token">

                  <!--哪些方法被令牌拦截器拦截 -->

                  <param name=includeMethods">save</param>

          </interceptor-ref>   

         <!--当表单重复提交转向的页面 -->

       <result name="invalid.token">/WEB-INF/page/message.jsp</result>     

</action>

第三步:

     message.jsp提示表单提示的错误信息,使用<s:actionerror>,以上配置加入了“token”拦截器和“invalid.token”结果,因为“token”拦截器在会话的token与请求的token不一致时,将会直接返回“invalid.token”结果。

 

1)测试代码

l         Jsp页面

add.jsp

<%@page language="java"pageEncoding="utf-8"%>

<%@taglib uri="/struts-tags"  prefix="s"%>

<html>

  <head>

    <title>My JSP 'index.jsp' starting page</title>

    <metahttp-equiv="description"content="This is my page">

  </head>

  <body>

       <s:debug/>

       <s:form action="customerAction_save.action"method="post"

               namespace="/model"theme="simple">

          用户名:<s:textfieldname="username"/><br><s:token/>

          密码:<s:passwordname="psw"/><br>

          电话:<s:textfieldname="tel"/><br>

          <s:submit value="保存"/><br>

       </s:form>

  </body>

</html>

 

success.jsp

<%@page language="java"pageEncoding="utf-8"contentType="text/html; charset=utf-8"%>

<%@taglib uri="/struts-tags"  prefix="s"%>

<html>

  <head>

    <title>My JSP 'index.jsp' starting page</title>

    </head>

  <body>

  <s:debug></s:debug>

         成功!!!<br>

         <s:property value="username"/><br>

         <s:property value="psw"/><br>

         <s:property value="tel"/>

  </body>

</html>

 

message.jsp

<%@page language="java"pageEncoding="utf-8"contentType="text/html; charset=utf-8"%>

<%@taglib uri="/struts-tags"  prefix="s"%>

<html>

  <head>

    <title>My JSP 'index.jsp' starting page</title>

    </head>

  <body>

       <s:actionerror/><br>

         重复提交

  </body>

</html>

 

struts.xml文件的配置

<?xmlversion="1.0"encoding="UTF-8"?>

<!DOCTYPEstruts PUBLIC

    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"

    "http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>

    <packagename="model"namespace="/model"extends="struts-default">

        <!-- 添加token拦截器放置到默认栈中 -->

       <interceptors>

           <interceptor-stack name="defaultStack">

               <!-- 加载token拦截器 -->

               <interceptor-ref name="token">

                   <!-- 只对Action类中的save方法进行拦截 -->

                   <param name="includeMethods">save</param>

               </interceptor-ref>

               <!-- 重新执行默认栈 -->

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

           </interceptor-stack>

       </interceptors>

        <action name="customerAction_*"class="cn.itcast.model.CustomerAction"method="{1}">

            <result name="add">/model/add.jsp</result>

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

           <result name="edit">/model/edit.jsp</result>

            <!-- result定义name属性值为invalid.token,执行表单重复提交后的页面 -->

           <result name="invalid.token">/model/message.jsp</result>

        </action>

    </package>

</struts>

 

l         Action

publicclass CustomerActionextends ActionSupportimplements ModelDriven<Customer> {

 

    //模型驱动中必须要实例化对象

    private Customer customer =new Customer();

 

    public Customer getModel() {

        return customer;

    }

   

    /**跳转到新增页面*/

    public String add(){

        return"add";

    }

   

    /**保存客户信息,这里表单重复提交只对save有效*/

    public Stringsave(){

        //获取页面的值

        System.out.println("username:"+customer.getUsername());

        System.out.println("psw:"+customer.getPsw());

        System.out.println("tel:"+customer.getTel());

        ValueStack valueStack = ServletActionContext.getContext().getValueStack();

        System.out.println("valueStack"+valueStack);

        //组织sql语句,执行保存

        return"success";

    }

   

    /**跳转到编辑页面*/

    public String edit(){

        //获取id

        Integer id = customer.getId();

        //使用id查询数据库,返回惟一的对象,并放置到模型驱动中

//      customer.setUsername("张三");

//      customer.setPsw("123");

//      customer.setTel("12345678");

       

        Customer c = new Customer();

        c.setId(id);

        c.setUsername("张三");

        c.setPsw("123");

        c.setTel("12345678");

        customer = c;//错误写法

       

        ServletActionContext.getContext().getValueStack().pop();//将旧的对象删除

        ServletActionContext.getContext().getValueStack().push(c);//将新的对象压入栈顶

       

        ValueStack valueStack = ServletActionContext.getContext().getValueStack();

        System.out.println("valueStack"+valueStack);

        return"edit";

    }

}

 

实现国际化

l         Token.properties文件

struts.messages.invalid.token=\u60A8\u7684\u8868\u5355\u5DF2\u7ECF\u91CD\u590D\u63D0\u4EA4\u4E86\uFF0C\u4E0D\u8981\u518D\u641E\u7834\u574F

 

l         struts.xml文件中添加属性文件加载

<constantname="struts.custom.i18n.resources"value="fileUpload,cn.itcast.i18n.resource,cn.itcast.model.token"></constant>

 

 

 

 

0 0
原创粉丝点击