马士兵尚学堂Struts2笔记——以及工作机制

目录

 

l   建立一个Struts2工程... -2 -

l   用Action的属性接收参数... -10 -

l   使用DomainModel (实体模型)接收参数... -11 -

l   Struts2_2.1.6版本的中文问题... -12 -

l   Struts模块包含... -12 -

l   Struts简单数据验证... 13

l   StrutsValueStack(值栈)Debug. 15

Value Stack Contents. 15

l   Struts2_访问Web元素... 16

Stack Context18

第二种方式(这种方式是最常用的,其他的都可以忘记)... 18

l   Action总结... 19

l   Struts2_结果类型... 20

l   OGNL. 22

Struts ValueStack Debug. 23

Value Stack Contents. 23

l   Struts投影... 28

 

 

 建立一个Struts2 工程

Ø  1在MyEclipse中新建web工程

Ø  2在struts-2.2.1.1-all\struts-2.2.1.1解压struts2-blank.war( 最基础的示例程序 )

Ø  3进入struts-2.2.1.1\apps\struts2-blank\WEB-INF\classes下把struts.xml拷到web工程的src下面,因为工程编译完它默认就把src下的文件放到class文件下面。

Ø  4.拷类库,在这个项目的lib文件下面拷

把jar放入lib后看不见jar文件,是因为MyEclipse默认视图是package Explorer,如果要看硬盘上对应的视图,应该打开windows-ShowView-other-navigatior

4.配置web.xml,参考struts自带的web.xml,把filter的配置拷过来

<filter>

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

    <filter-class>org.apache.struts2.dispatcher.ng.filter[U1] .StrutsPrepareAndExecuteFilter[U2] 

</filter-class>

 </filter>

 <filter-mapping>

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

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

</filter-mapping>

 

      

 

  第一个示例程序HelloStruts

<struts>

<constantname="struts.devMode" value="true" />[U3] 

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

        <action name="hello">

            <result>/hello.jsp</result>

        </action>

    </package>

</struts>

http://localhost:8080/strust2_0100_Introduction/[U4] 

http://localhost:8080/strust2_0100_Introduction/hello或者

http://localhost:8080/strust2_0100_Introduction/hello.action[U5] 

跳转到hello.jsp,第一个示例程序成功!

  Struts2读源码

配置文件中的

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

</filter-class>

一看就应该知道它是对应一个类,在jar文件中找到对应的源码编译完的class文件,

查看源码: jar文件点右键---àproperties--àJavaSource AttachmentàExternalFolder

(外部文件)

àstruts-2.2.1.1-all/struts-2.2.1.1/src/core/src/main/java

点击class文件可以查看源码了,假如想看它的doc文档,同样的方法

jar文件点右键---àproperties--àJavadoc Location-à导入doc就可以在源码中右键或者F1观察对应的文档了。

  敲尖括号不提示的问题

Struts.xml文件头定义了

<!DOCTYPE struts PUBLIC

    "-//ApacheSoftware Foundation//DTD Struts Configuration 2.0//EN"

"http://struts.apache.org/dtds/struts-2.0.dtd[U6] ">

配置:windows---preferences---catalog---。。。xml—xmlCatalog—Add

 

 

 

Add入本地定义当前xml的dtd文件:找到struts2-core-2.2.1.1.jar解压开找到struts-2.1.7.dtd[U7] 

 

完成,验证代码提示成功!


  Struts2的运行机制

当你在客户端敲http://localhost:8080/strust2_0100_Introduction/hello

首先找到:strust2_0100_Introduction这个web application,找到后去执行这个web application下的web.xml

Tomcat接收到请求之后,会发现这个web.xml下面,配了一个filter,而这个filter过滤所有的url地址,所以当我们在地址栏敲http://localhost:8080/strust2_0100_Introduction/hello后,会被StrutsPrepareAndExecuteFilter接收到

<filter>

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

<filter-class>

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

  </filter>

  <filter-mapping>

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

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

</filter-mapping>

StrutsPrepareAndExecuteFilter接收到后url情求后,它首先看namespace

Struts.xml

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

        <action name="hello">

            <result>/hello.jsp</result>

        </action>

</package>

查到“/”后面的hello,它就会去package下面查是否有name属性叫“hello”的action,有的话,找里面对应的result是谁--àhello.jsp

Struts的好处就是:我可以把“请求”和“视图展现”分开,而不是写死。分开的好处就是:如果要换成其他视图,配一下就好了,所以更加灵活。Struts核心的本质就是解决了:把你的请求和最后的结果分开。[U8] 


  Struts的namespace

示例工程Struts2_0200_Namespace

Struts.xml

<struts>

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

    <package [U9] name="front" extends="struts-default"namespace[U10] =[U11] "/front">

        <action name="index">

            <result>/Namespace.jsp</result>

        </action>

    </package>

     <package name="main" extends="struts-default" namespace=""[U12] >

        <action name="index">

            <result>/Namespace.jsp</result>

        </action>

    </package>

</struts>

所以namespace为空意味着:只要找到一个index.action,没有找到精确的对应的namespace,全部都交给namespace为空的这个package去处理,所以这个package囊括了其他所有package处理不了的action

 

  Struts自定义具体视图的返回

示例工程Struts2_0300_Action

 

  修改jsp模板字符编码:windows-preferences-  JSP 修改编码为UTF-8即可

 

IndexAction1.java

publicclass IndexAction1 {

    public String execute() {

       return"success";

    }

}

IndexAction2.java

publicclass IndexAction2 implements Action {

    public String execute() {

       return"success";

    }

}

真正企业开发只用这第三种!另外两种忘记!

IndexAction3.java

publicclass IndexAction3 extends ActionSupport {

    public String execute() {

       return"success";

    }

}

<struts>

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

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

       <action name="index" class="com.bjsxt.struts2.front.action.IndexAction1[U13] "[U14] >

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

        </action>

    </package>

</struts>

具体视图的返回可以由用户自己定义的Action来决定
具体的手段是根据返回的字符串找到对应的配置项,来决定视图的内容
具体Action的实现可以是一个普通的java类,里面有public String execute方法即可
或者实现Action接口
不过最常用的是从ActionSupport继承,好处在于可以直接使用Struts2封装好的方法

如果不配置class属性,默认执行xwork框架的ActionSupport这个action,这个action就有execute这个方法,return success。


  Struts路径问题

示例工程:Struts2_0400_Path

struts2中的路径问题是根据action的路径而不是jsp路径来确定,所以尽量不要使用相对路径。
虽然可以用redirect方式解决,但redirect方式并非必要。
解决办法非常简单,统一使用绝对路径。

(在jsp中用request.getContextRoot方式来拿到webapp的路径)
或者使用myeclipse经常用的,指定basePath

先点击链接http://localhost:8080/Struts2_0400_Path/path/path.action跳转到path.jsp 页面

在path.jsp页面上有链接<ahref="index.jsp">index.jsp</a>虽然在webRoot上面index.jsp和

path.jsp同级,但是点击index.jsp却跳到http://localhost:8080/Struts2_0400_Path/path/index.jsp

如果改成<ahref="/index.jsp">index.jsp</a>跳到http://localhost:8080/index.jsp

 因为JSP中“/”代表整个站点的根路径而不是应用的根路径。

解决方案是:永远使用绝对路径。

 <%

String path =request.getContextPath();

String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%>

<base [U15] href="<%=basePath%>"/>

request.getContextPath()会拿到webapplication的名称:Struts2_0400_Path

request.getScheme()拿到“http”字符串

request.getServerName()拿到“localhost

request.getServerPort()拿到“8080

  


  动态方法调用

<body>

Action执行的时候并不一定要执行execute方法

可以在配置文件中配置Action的时候用method=来指定执行哪个方法

也可以在url地址中动态指定(动态方法调用DMI)(推荐)

    <a href="<%=context %>/user/userAdd">添加用户</a>

    <a href="<%=context %>/user/user!add[MS16] ">添加用户</a>

前者会产生太多的action,所以不推荐使用

</body>

<struts>

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

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

    <actionname="userAdd"class="com.bjsxt.struts2.user.action.UserAction" method="add[MS17] ">

            <result>/user_add_success.jsp</result>

        </action>

      

 <action name="user"class="com.bjsxt.struts2.user.action.UserAction">

            <result>/user_add_success.jsp</result>

        </action>

    </package>

</struts>


 Action接收参数的方式

Action有三种接收参数的方式

1.       属性接收参数

2.      用DomainModel(实体模型)接收参数

3.      用ModelDriven接收参数不常用

 

  用Action的属性接收参数

Struts2_0700_ActionAttrParamInput

Index.jsp

<head>

<base href="<%=basePath %>"/>  </head>

使用action属性接收参数<a href="user/user!add?name=a&age=8">添加用户</a>

</body>

</html>

链接的意思是:执行user下面的user.action下面的add方法

怎么接受参数的呢?第一种方式.在自己的action下面定义两个属性,写好get,set方法,当new action的时候,会自动把这两个属性从参数里面拿过来,帮你设置好。

参数跟我们的成员变量一一对应,这时候它就会自动把我们的参数传递到我们成员变量里。这时候当我们调用add()方法时,它直接可以用了。

UserAction.java

publicclass UserAction extends ActionSupport {

    private String name;

    privateintage;

    public String add() {

       System.out.println("name=" + name);

       System.out.println("age=" + age);

       returnSUCCESS;

    }

    public String getName() {

       returnname;

    }

    publicvoid setName(String name) {

       this.name = name;

    }

    publicint getAge() {

       returnage;

    }

    publicvoid setAge(int age) {

       this.age = age;

    }

}

Struts.xml

<struts>

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

 <action name="user"class="com.bjsxt.struts2.user.action.UserAction">

            <result>/user_add_success.jsp</result>

        </action>

    </package>

</struts>

 使用Domain Model (实体模型) 接收参数

Struts2_0800_DomainModelParamInput

<html>

<body>使用Domain Model接收参数

<a href="user/user!add?user.name=a&user.age=8">添加用户</a>

</body>

</html>

publicclass UserAction extends ActionSupport {

    private User user;

    //private UserDTO userDTO;

    public String add() {

       System.out.println("name=" + user.getName());

       System.out.println("age=" + user.getAge());

       returnSUCCESS;

    }

    public User getUser() {

       returnuser;

    }

    publicvoid setUser(User user) {

       this.user = user;

    }

}

publicclass User{

    private String name;

    privateintage;

    public String getName() {

       returnname;

    }

    publicvoid setName(String name) {

       this.name = name;

    }

    publicint getAge() {

       returnage;

    }

    publicvoid setAge(int age) {

       this.age = age;

    }

一般来说,我们输入参数不一定刚好跟我们的域模型一致,比如说:用户有name跟password两个属性,但是你输入进来的应该还有个密码确认passwordconfiguration

这时候我们要么使用属性接收,要么用DTO,或者VO

 

 Struts2_2.1.6版本的中文问题

根据Struts文档的规定:只要在Struts.xml中配置这段话就可以解决中文乱码问题

    <constantname="struts.i18n.encoding" value="GBK" />

但是2..1.6版本中这是一个Bug,没法解决中文乱码问题

解决办法是:一:升级到2.1.7之后的版本;二是:使用spring的filter,在web.xml中配置过滤

三:在web.xml中配置2.0版本的filter

<filter>

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

<filter-class>org.apache.struts2.dispatcher.FilterDispatcher[MS18] 

</filter-class>

</filter>

Struts2文档的位置:

struts-2.1.8.1-all\struts-2.1.8.1\docs\docs

 

要知道Strust.xml中有哪些常量可以配置,可以进文档里面查看

例子:

struts.i18n.encoding=UTF-8       //表示默认字符集是UTF-8

struts.action.extension=action,,    //后缀名可以是“action”,或者是“”空也行。

 

 Struts模块包含

 

Struts.xml中:配

<include file=”login.xml”/>

 

相当于把文件login.xm内容l复制过来


 Struts简单数据验证

示例程序:Struts2_1100_SimpleDataValiation

UserAction.java

publicclass UserAction extends ActionSupport {

    private String name;

    public Stringadd() {

       if(name == null || !name.equals("admin")) {

           this.addFieldError("name", "name iserror");

           this.addFieldError("name", "name is toolong");

[U19]           returnERROR;[U20] 

       }

       returnSUCCESS;

    }

    public String getName() {

       returnname;

    }

    publicvoid setName(String name) {

       this.name = name;

    }

}

Struts.xml

<struts>

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

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

        <action name="user"class="com.bjsxt.struts2.user.action.UserAction">

            <result>/user_add_success.jsp</result>

            <result name="error">/user_add_error.jsp</result>

        </action>

    </package>

</struts>

登陆不成功的时候,该怎么样向前台传递信息呢? 这时候其实是个麻烦事,因为我们的userAction实际上是没有跟我们的Request, response属性绑在一起的;userAction访问不到我们的Request, response,ServletContext,这些都没有,在Struts2里面是采用另外一种机制。

This.addFieldError(“name”,”name is error”);

添加对于属性校验的错误信息的,错误信息的名字一般也是我们的属性名字叫做name,那么这个属性出错,后面是这个错误的具体信息:name is error!

 

 

 

 

 

user_add_error.jsp

<body>

    User Add Error!

    <s:fielderrorfieldName="name[U21] " theme="simple"/>

    <br />

    <s:propertyvalue="errors.name[0]"/>

    <s:debug></s:debug>

</body>

 

这里调用addFieldError()之后在前面如何把它拿出来?

在这里我们用到struts2的标签

<s:fielderror[U22]   fieldname=”name” theme=”simple”>

调用标签库的时候,必须这么写:

<%@taglib uri=”/struts-tags” [U23] prefix=”s”%>

Struts的标签定义是位于

 

 

如果我们去看源码的话会看到它把我们的错误信息封装成:

<url class=”errorMassage”>

       <li><span>name is error!</span></li>

</url>

指定成CSS修饰,这样就给我们带来不便,这是Struts2设计不太好的地方。所以Struts2展现的标签在企业开发中应用得不多,因为它都是强制要求你必须按照它的命名规则来去定义它的各种各样的展现。

那我们应该怎么样把我们的字符串拿出来?引出下一个标签,这个标签以后会很常用:

<s:debug></s:debug>

当你写了这个标签之后在页面就会默认显示这个标签 [Debug]

点开[Debug]

 Struts ValueStack(值栈) Debug

ValueStack [U24] Contents

Object

Property Name

Property Value

com.bjsxt.struts2.user.action.UserAction

texts

null

actionErrors

[]

errors

{name=[name is error, name is too long]}[U25] 

fieldErrors

{name=[name is error, name is too long]}

errorMessages

[]

name

a

locale

zh_CN

actionMessages

[]

com.opensymphony.xwork2.DefaultTextProvider

texts

null

首先:Struts2会把Action里面的属性挨着排给你放进Value Stack

专门有这个标签很常用s:property

<s:property[MS26] value="errors.name[0]"/>

 

<s:propertyvalue="errors"/>

取到errors实际上是一个map:{name=[name is error, name is too long]}

那么我想取到map里面某一个key的内容:

<s:propertyvalue="errors.name"/>

[name is error, name is too long]

而这时候实际上value是一个数组,所以我要想去数组的第一项

<s:property value="errors.name[0]"/>[MS27] 

name is error

 

 


 Struts2_访问Web元素

后台的Action跟我们前台的页面来通讯的时候,由于它拿不到request,session,servletContext比如当我们有人登陆了,我们要在session中设一个值,表示它登陆了,但是如果你Action访问不到session,你如何把相关的数据设到session里面,response不用访问它,因为我们的结果是通过result返回的。

<body>

取得Map类型request,session,application,真实类型HttpServletRequest, HttpSession, ServletContext的引用:

    <li>前三者:依赖于容器</li>

    <li>前三者:IOC</li> (只用这种)

    <li>后三者:依赖于容器</li>

    <li>后三者:IOC</li>

<form name="f"action="" method="post">

用户名:<input type="text" name="name"/>

密码:<input type="text" name="password"/>

<input type="button"value="submit1" οnclick="javascript:document.f.action='login/login1';document.f.submit();[U28] " />

<input type="button"value="submit2" οnclick="javascript:document.f.action='login/login2';document.f.submit();"/>

<input type="button"value="submit3"οnclick="javascript:document.f.action='login/login3';document.f.submit();"/>

<input type="button"value="submit4" οnclick="javascript:document.f.action='login/login4';document.f.submit();"/>

</form>

</body>

Strust.xml

<struts>

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

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

        <action name="login*[MS29] "class="com.bjsxt.struts2.user.action.LoginAction{1}[MS30] ">

           <result>/user_login_success.jsp</result>

        </action>

    </package>

</struts>

 

第一种方式:(忘记)

取值的方法:可以在构造方法LoginAction1里面取值,也可以在execute方法取值。

就是说:下面三行“取值”代码可以写在任意两个方法里面!

request = (Map)ActionContext.getContext().get("request");

       session = ActionContext.getContext().getSession();

       application = ActionContext.getContext().getApplication();

 

publicclass LoginAction1extends ActionSupport {

    private Map request;

    private Map session;

    private Map application;

    public LoginAction1() {

//取值

request = (Map)ActionContext.getContext().get("request")[U31] ;

       session = ActionContext.getContext().getSession();

       application = ActionContext.getContext().getApplication();

    }

    public String execute() {

        request.put("r1", "r1");//这里就不能用setAttribute()因为这里是Map类型的。用put

       session.put("s1", "s1");

       application.put("a1", "a1");

       returnSUCCESS;

    }

}

    request = (Map)ActionContext.getContext().get("request");

ActionContext.getContext()

Context直接翻译过来是:上下文,在西方人写的程序特别多,但是中国人很少用,因为不理解它是什么东西;Context就是当前执行的环境,就比如同学们在这里学习,实际上是有一个Context,代表了你周围的情况,机器的情况,空调的情况,等等,它会把周围环境帮你封转到Context这个对象里面,当你想访问这些东西的时候,通过Context去取。

原来学习过得ServletContext代表的就是servlet的运行环境,原来我们写程序就用ServletContext拿到各种各样的配置,ActionContext也就是Action周边运行的情况,Action运行的时候,首先接收到请求接收到requestresponse等等后面再接着调你的处理过程,Action处理的过程中,比如说那些配置怎么配的,执行环境怎么样等等都要通过ActionContext来拿。

原先我们在页面中都是通过HttpResquest,HttpResponse拿到我们的值,现在我们通过

request = (Map)ActionContext.getContext().get("request");

       session = ActionContext.getContext().getSession();

       application = ActionContext.getContext().getApplication()

拿到我们的requestresponseapplication

User_login_success.jsp

<body>

    User Login Success!u

<s:property value="#request.r1"/>| <%=request.getAttribute("r1") %>

<s:property value="#session.s1"/>| <%=session.getAttribute("s1") %>

<s:property value="#application.a1"/>| <%=application.getAttribute("a1") %>

[U32]    <s:property value="#attr.a1"/>[U33] 

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

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

    <s:debug></s:debug>

</body>

我们的后台放了requestsessionapplication但是这三个东西都是map,但是它反馈到前台之后居然用requestsessionapplication可以拿到,所以struts2一定帮我们在MapHttpRequest之间建立某种联系,对于我们自己设定的map类型的request这里面的属性在处理的过程中会全都复制到Http对象里边去。

 

第一种访问request里面的值:<%=request.getAttribute("r1") //原始的方式

第二种访问request里面的值:<s:property value="#request.r1"/>

第二种是用标签的方式取值,查看debug模式,

Stack Context

These items are available using the #keynotation

。。。略

These items are available using the #keynotation :下面的items是供你使用的,只要你用#key访问它,所以你用#request就可以访问到request

上面的Value Stack是可以直接拿的

ActionContext要拿的话加#就能拿。

 

第二种方式这种方式是最常用的,其他的都可以忘记

其实request我们也很少去拿它,因为我们Action的成员变量默认会起到request的作用,它自己会放到valueStack里面, valueStack本身就是放到request里面,所以根本不用去拿request.

import org.apache.struts2.interceptor.ApplicationAware;

import org.apache.struts2.interceptor.RequestAware;

import org.apache.struts2.interceptor.SessionAware;

publicclass LoginAction2extends ActionSupport implements RequestAware,SessionAware, ApplicationAware [U34] {

    //第二种方式区别于第一种方式的不同点是:第一种方式还要在构造函数中进行“取值”,第二种方式直接就能用了!!这个就是IOC(控制反转)的设计思想,依赖注入DI

private Map<String, Object> request;

    private Map<String, Object> session;

    private Map<String, Object> application;

        public String execute() {

        request.put("r1", "r1");

        session.put("s1", "s1");

        application.put("a1", "a1");

        returnSUCCESS;

    }

    publicvoid setRequest(Map<String, Object> request) {

        this.request = request;

    }

    publicvoid setSession(Map<String, Object> session) {

        this.session = session;

    }

    publicvoid setApplication(Map<String, Object> application) {

        this.application = application;

    }

}

[MS35] 

 

 Action总结

1.  实现一个Action最常用的方式,从ActionSupport继承

2.  DMI动态方法调用

3.  通配符*{1}{2}

4.  接收参数的方法(一般用属性或者DomainModel来接收)

5.  简单参数验证addFieldError   一般不使用Struts2UI标签

6.  访问Web元素

1)  Map类型

1.      IOC

2.      以来Struts2

2)  原始类型(忘记)

7.  包含文件配置

8.  默认action处理

 Struts2_结果类型                   

<struts>

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

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

        <action name="r1">

        <result type="dispatcher">/r1.jsp</result>

        </action>

        <action name="r2">

        <result[U36]  type="redirect">/r2.jsp</result>

        </action>

        <action name="r3">

        <result type="chain[U37] ">r1</result>

        </action>

        <action name="r4">

        <result type="redirectAction">r2</result>

        </action>

    </package>

</struts>

Result类型

  1. dispatcher [U38] 
  2. redirect[U39] 
  3. chain [U40] 
  4. redirectAction[U41] 
  5. freemarker
  6. httpheader
  7. stream
  8. velocity
  9. xslt
  10. plaintext
  11. tiles

前面四个要掌握,只要用前两个。

 

ResultType是chain的时候,跳转到一个Action那边去处理,如果Action是在另外一个包p1该怎么办呢?
查Struts2文档的路劲---guides----resultTypes-----chain---
例子:
<package name="public" extends="struts-default">
    <!-- Chain creatAccount to login, using the default parameter -->
    <action name="createAccount" class="...">
        <result type="chain">login</result>
    </action>
    <action name="login" class="...">
        <!-- Chain to another namespace -->
        <result type="chain">
            <param name="actionName">dashboard</param>
            <param name="namespace">/secure</param>
        </result>
    </action>
</package>

<param name="namespace">:指定要跳到的namespace

<param name="actionName">指定要跳到的Action

   OGNL

OGNL是Object-Graph Navigation Language(对象图导航语言)的缩写,它是一种功能强大的表达式语言(Expression Language,简称为EL),通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。它使用相同的表达式去存取对象的属性。

第一个例子

Index.jsp

<body>

    访问属性

<a href="<%=contextPath %>/ognl.action?username=u&password=p">ognl</a>

</body>

 

Ognl.xml

<struts>

    <package name="ognl" extends="struts-default">

        <action name="ognl"class="com.bjsxt.struts2.ognl.OgnlAction">

            <result>/ognl.jsp</result>

        </action>

    </package>

</struts>

OgnlAction.java[d42] 

publicclass OgnlAction extends ActionSupport {

    private String password;

    private String username;

    private User user;

    public User getUser() {

       returnuser;

    }

    publicvoid setUser(User user) {

       this.user = user;

    }

    public String getPassword() {

       returnpassword;

    }

    public String getUsername() {

       returnusername;

    }

    publicvoid setPassword(String password) {

       this.password = password;

    }

    publicvoid setUsername(String username) {

       this.username = username;

    }

}

User.java

publicclass User {

    privateintage = 8;

    public User() {

    }

    public User(int age) {

       super();

       this.age = age;

    }

    publicint getAge() {

       returnage;

    }

    publicvoid setAge(int age) {

       this.age = age;

    }

    @Override//重写toString

    public String toString() {

       return"user" + age;

    }

}

此时的urlhttp://localhost:8080/ognl_0100/ognl.action?username=u&password=p值栈中的内容

<body>

    <ol>

       <li>访问值栈中的:username = <s:property[d43] value="username[d44] "/>[d45] </li>

       <li>访问值栈中的:password=<s:property value="password"/></li>

    </ol>

    <s:debug></s:debug>

</body>

[Debug]

Struts ValueStack Debug

Value Stack Contents

Object

Property Name

Property Value

com.bjsxt.struts2.ognl.OgnlAction

password

p

locale

zh_CN

user

null[d46] 

errorMessages

[]

errors

{}

actionErrors

[]

username

u

texts

null

fieldErrors

{}

actionMessages

[]

com.opensymphony.xwork2.DefaultTextProvider

texts

null

http://localhost:8080/ognl_0100/ognl.action?username=u&password=p&user.age=9就出来了。

在OGNL表达式的里面传参的时候必须把user.xxx 传进去,Struts才能帮我们构造user方法

只有user.xxx 传,才会构造

1).能不能不在url中传user.xxx直接在Action中直接new 出来,能不能取到user的值呢?

Private User user=new User(10);

//原来初始值等于8

结论:也是可以的,因为我们new出Action,Action又new出User,当然就不为null了

2).把User()空的构造方法去掉,能不能取到user的值呢?

http://localhost:8080/ognl_0100/ognl.action?username=u&password=p&user.age=9

把User为空的构造方法去掉之后,它就没有默认为空的构造方法,别人要帮你初始化这个User的时候它确定不了应该调用哪个构造方法,所以取不到值。

java.lang.InstantiationException:com.bjsxt.struts2.ognl.User

实例化User出错,所以一般我们的Domain Model(领域模型)永远都要提供一个默认参数为空的方法;

结论:如果我的Domain Model,也就是User对象我自己没有new,也就是Action里面自己没有new,想让Struts2帮你new的时候必须要给domainModel传值,在它帮你new的过程中你的damainModel必须有一个默认为空的构造方法,否则它不知道new出哪一个。

 

 

  OGNL_2

在原来的OgnlAction.java中增加Cat属性和get set 方法

[U47] 

Cat.java

publicclass Cat {

    private Dog [U48] friend;[U49] 

    public Dog getFriend() {

       returnfriend;

    }

    publicvoid setFriend(Dog friend) {

       this.friend = friend;

    }

    public String miaomiao() {

       return"miaomiao";

    }

}

Dog.java

publicclass Dog {  

    private String name;

    public Dog() { }

    public Dog(String name) {

       super();

       this.name = name;

    }

    Getset方法……..

    public String toString() {

       return"dog: " + name;

    }

}

[U50] 

为什么叫做OGNL对象图导航语言?比如说我们访问OgnlAction.java里面通过“user.[U51] age

那么这时候如果我们想访问ognlAction里面的catdog该怎么写? Cat.friend.name

OGNL

1.  user.xxx只有传,才会构造,想初始化domain Model,可以自己new也可以传值,但这时候必须有默认为空的构造方法。

  OGNL访问

http://localhost:8080/ognl_0100/ognl.action?username=u&password=p&cat.friend.name=judi

值栈中的内容

<body>

<li>访问值栈中对象的普通属性(get set方法):

<s:property value="cat.friend.name"/></li>

<li>访问值栈中对象的普通方法:

<s:property value="password.length()[U52] "/></li>

<s:property value="cat[U53] .miaomiao()"/></li>

<li>访问值栈中action的普通方法:<s:property value="m()[U54] " /></li>

</body>

  OGNL访问静态方法/属性:

访问静态方法/属性的语法:前面@+类名,后面@+方法名/前面@+类名,后面@+属性名

先写类S.java

publicclass S {

    publicstatic String STR="STATICSTRING ";

    publicstatic String s(){

       return"Hello";

    }

}

<body>

访问静态方法:<s:property value="@com.bjsxt.struts2.ognl.S@s()[U55] "/>

</body>

[U56] 

要在struts.xml中增加配置:

<constant name="struts.ognl.allowStaticMethodAccess[U57] " value="true">

</constant>

Struts2中常量的值在:

struts2-core-2.1.8.1.jar-->org.apache.struts2-->default.properties中查:

        

<body>访问普通类的构造方法:

<s:propertyvalue="new com.bjsxt.struts2.ognl.User(8)"/>

</body>

[U58] 

 

  OGNL访问集合

OgnlAction.java中添加:

private List<User> users = newArrayList<User>();

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

    private Set<Dog> dogs = newHashSet<Dog>();

get方法。。。set方法。。。。()

public OgnlAction() {

       users.add(new User(1));

       users.add(new User(2));

       users.add(new User(3));

 

       dogs.add(new Dog("dog1"));

       dogs.add(new Dog("dog2"));

       dogs.add(new Dog("dog3"));

 

       dogMap.put("dog100", new Dog("dog100"));

       dogMap.put("dog101", new Dog("dog101"));

       dogMap.put("dog102", new Dog("dog102"));

    }

11.访问List:<s:property value="users[U59] "/>

12.访问List中某个元素:<s:property value="users[1][U60] "/>

13.访问List中元素某个属性的集合:<s:property value="users.{age}[U61] "/>

14.访问List中元素某个属性的集合中的特定值:<s:property value="users.{age}[0][U62] "/> | 第二种访问方式<s:property value="users[0].age"/>[U63] 

15.访问Set:<s:property value="dogs[U64] "/>

16.访问Set中某个元素:<s:property value="dogs[1][U65] "/>

17.访问Map:<s:property value="dogMap"/>

18.访问Map中某个元素:

第一种写法:<s:property value="dogMap.dog101"/> |

第二种写法:<s:property value="dogMap['dog101']"/>|  

第三种写法:<s:property value="dogMap[\"[U66] dog101\"]"/>

19.访问Map中所有的key:<s:property value="dogMap.keys[U67] "/>

20.访问Map中所有的value:<s:property value="dogMap.values"/>

21.访问容器的大小:

<s:property value="dogMap.size()"/> | <s:property value="users.size"/>

 Struts投影

投影,英文叫做projection,其实就是过滤器的意思,把符合条件的给过滤出来

<body>

投影(过滤)<s:property value="users[S68] .{?#this.age==1}.{age}"/>

        投影:<s:property value="users.{^#this.age>1}.{age}"/>

        投影:<s:property value="users.{$#this.age>1}.{age}"/>

        投影:<s:property value="users.{$#this.age>1}.{age} == null"/>

</body>

执行结果:         

如果去掉.{age}     <s:property value="users.{?#this.age==1}"/>

执行结果:            [S69] 

如果想取出集合中的第一个元素。

<s:propertyvalue="users.{?#this.age==1}[0]"/>

执行结果:        

<s:propertyvalue="users.{^#this.age>1}.{age}"/>

“^”(小尖号)代表开头,指的是:大于一的集合那些元素里头开头的第一个,它的age值的集合

<s:property value="users.{$#this.age>1}.{age}"/>

“$”[dolar]代表结尾,指的是: 大于一的集合那些元素里头结尾的那个,它的age值的集合

<s:property value="users.{$#this.age>1}.{age} ==null"/>

用来判断集合里面有没有元素。

用中括号访问元素

[]:<s:property value="[1]"/>

 

执行结果:

查看Debug这个ValueStack只有两个Object,我们刚刚访问的这个Action永远在栈顶,所以如果要访问Action对象,完全可以这样写:

[]:<s:property value="[0]"/>

中括号访问的OGNL这个栈里面从上往下数的第几个元素;

 

OGNL里面[0]代表的是ognlstack从上往下从第0个位置开始往下一直到栈底的集合

 

如果要访问ognl里面的某一个成员变量比如说username,这时候如果里面有两个Action的话,第一个Action没有,它会按顺序往下找第二个Action,什么情况下会有两个Action在里面呢?

<action name="ognl" class="com.bjsxt.struts2.ognl.OgnlAction">

            <result>/ognl.jsp</result>

       </action>

  <action name="test" class="com.bjsxt.struts2.ognl.TestAction">

            <result type="chain[S70] ">ognl</result>

       </action>

url访问: http://localhost:8080/Struts2_1900_OGNL/test.Action

说明了:首先栈里面被压入了test.action,其次被压入了ognl.action所以证明了如果用了服务器端跳转,它会把用到的action挨着排往里面压。

  Struts标签

Struts标签分为

1.通用标签 (重要)

2.控制标签 (重要)

3.UI标签 (重要)

4.AJAX标签 (不重要)

5.$,#,%区别

标签多动手就会用了,如果程序设计得比较好很多标签都很少用,所以只讲重要的常见的。

1.通用标签

A) property

B) set

C)

D)

E)

2.控制标签

       A)

B)

3.UI标签

      

5.$,#,%区别

-----------------------------------------------------------------------------------------------------------------

http://localhost:8080/Struts2_2000_StrutsTags/tags.action?username=u&password=p

 

Struts.xml

<action name="tags" class="com.bjsxt.struts2.tags.TagsAction">

           <result>/tags.jsp</result>

</action>

 

publicclass TagsActionextends ActionSupport {

   private String password;

   private String username;

   public TagsAction() {

   }

   public String execute() {

      this.addFieldError("fielderror.test", "wrong!");

      returnSUCCESS;

   }

   Getset方法。。。。

}


Property

<body>

<s:property value="username[S71] "/>

property取值为字符串<s:propertyvalue="'username'"[S72] />

property设定默认值<s:property value="admin"default="管理员"[S73] />

property设定HTML<s:property value="'<hr/>'"escape="false"/>

</body>

Value的属性值究竟是OGNL还是普通字符串,得去APIparameters!

Set

[S74] 

set设定adminName(如果不设scope属性,默认为requestActionContext)

 

<s:setvar="adminName" value="username"[S75] />

    setrequest取值<s:property value="#request.adminName"/>

    set ActionContext取值<s:property value="#adminName" />

set 设定var,范围为ActionContext:

<s:set var="adminPassword" value="password" scope="session"/>

set 使用#取值<s:property value="#adminPassword"/>

set 从相应范围取值<s:property value="#session.adminPassword"/>

 

request里面也能取到adminName的值,但是在debug标签下的request没有找到adminName变量,原因是:它还没来得及把这个值放到request里面debug已经形成了,

所以判定它有没有应该取出来看一下。

 

Bean

 

 


 [U1]Ng:nextgeneration下一代的filter,用的是2.1的;跟2.0有区别,

2.0用的filter用的是:org.apache.struts2.

dispatcher.FilterDispatcher

 [U2]通过这个名字可以看出跟2.0的区别,这里调用了两个filter,一个是prepare一个是execute filter.

 [U3]Struts常量的配置,struts.devMode开发模式,开发模式改为true之后,修改配置文件可以马上生效,不用重启服务器。

 [U4]这里的“/”对应namespace的“/”,因为action 的name属性为hello,所以敲

 [U5]默认的aciton是可以省略的

 [U6]在这个url这里定义了当前这篇xml语法的位置。可以这个位置每次它要去网上拿,所以不一定能生效。

 [U7]这就是我们写xml要参考的那个文件

 [U8]Important!面试!!

 [U9]Java的package给我们的类打包,避免类重名,java的package作用也是一样。比如我们有两个action都叫index,一个前台一个后台,就用package name=”front”

package name=”backgroud”

 [U10]namespace是什么,你想访问的action前面就应该加上什么。比如这里就是

/front/index.action

 [U11]Namespace是可以不写的,默认为空!

 [U12]Namespace不写等于Namespace为空,Namespace等于空,意味着:只要你在url敲index.action

不管你在哪里敲,路劲多么深,只有最后是“index.action”就可以访问这个action。

 [U13]假如没有配class这个属性,默认执行的是

Struts2自带的action:ActionSupport,在struts2里面没有ActionSupport这个类的源码,因为struts2用到了xwork这个框架,所以想看到ActionSupport的话,必须下载xwork的源码

 [U14]Class属性表示,当你访问index这个action的时候,它会去执行IndexAction1这个类里面的execute()方法.

 [U15]Base标签的意思是当前所有url链接前面都会自动加上base标签配置的href路径

 [MS16]重点只用这一种,叫做动态方法调用DMI.

 [MS17]用method参数指定执行的方法。默认是execute(),通过method参数可以改变,不过不推荐用,因为它会产生太多的action可以忘记。

 [MS18]2.0版本的filter

 [U19]可以对同一个名字加多个错误。

 [U20]如果校验出错,return ERROR,跳到

user_add_error.jsp

 [U21]这个name对应于

this.addFieldError("name", "name iserror");

的name

 [U22]:fielderror [U22]实际上就是说你可以把userAction里面addField()加进去的内容给取出来。

 [U23]Uri实际是在jar包里,META-INF下面的struts-tags.tld文件里面的<uri>struts-tags</uri>这部分内容

 [U24]Value Stack,中文翻译过来叫做”值栈”,首先它是一个栈,栈就是一个容器,栈有个特点就是”后进先出”,”值栈”就是我有一个栈,里面放的是一系列的值。

 [U25]因为定义了两个,所以这里name有两个值

这里去的时候

errors.name[0]=name is error

errors.name[1]=name is too long

 [MS26]s:property 就是请你取属性展现在这里,这个标签专门取ValueStack以及下面的ActionContext,取Value Stack的值直接写它的名字就可以。

 [MS27]这就是OGNL了

 [U28]document.f就取到form了,.action='login/login1'也就是把它的actionJavaScript动态地指定,然后当你按完这个按钮之后用document.f.submit()动态submint

 [MS29]Login1,2,3

 [MS30]对应loginAction1,LoginAction2,LoginAction3

 [U31]get("request") [U31]找到request这个key对应的值,而这个值是个map

 [U32]两种在前台页面取值的方法。等同于jsp的

request.getParameter

 [U33]“#attr.a1”,把属性a1拿出来,这种方法很少用!!忘记即可

 [U34]第二种方式实现了三个接口,这三个接口分别要求你一定要实现三个对应的方法。”aware”是”知道,得知”的意思,所以实现了这几个接口之后,你就应该知道request的存在了,既然知道存在了,就应该把它保存起来了。所以一定有人传递给你了,这里就体现了IOC依赖注入的设计模式。

1.       [MS35]一个请求过来Struts会new出一个Action出来;2.new完之后它会检查Action是否实现了RequestAware接口.3如果Action实现了RequestAware接口,就可以调用RequestAware接口的setRequest()方法.

Struts2是一个filter开始的,部署在servlet容器里的filter当然可以拿到HttpRequest对象,然后会把里面的内容拿出来放到一个Map,也起一个名字叫request。也就是把原始类型HttpRequest转成Map类型的request.

总结:现在的Request由容器管理了----IOC

这种方式是最常用的,其他的都可以忘记。而且其实request我们也很少去拿它,因为我们Action的成员变量默认会起到request的作用,它自己会放到valueStack里面, valueStack本身就是放到request里面,所以根本不用去拿request.

 [U36]Result可以指定它的type是什么,result如果不指定type,默认是dispatcherdispatche是服务器跳转到结果页面上去。

 [U37]跳转到一个Action那边去处理,如果Action是在另外一个包p1该怎么办呢?

 [U38]只能跳转到页面上去,不能跳转到Action。点击跳到url=http://localhost:8080/Struts2_1500_ResultType/r/r1。服务器端跳转。

 [U39]也一样只能跳转到视图,不能跳转到Action,

url=http://localhost:8080/Struts2_1500_ResultType/r2.jsp,客户端跳转。

 [U40]如果想forward到另外一个Action,用chain

 [U41]如果你想客户端跳转,用redirectAction

 [d42]两个属性,两个get,set方法

 [d43]s:property:标签

 [d44]Ognl表达式指的是value=“”里面的值。

 [d45]值栈中的内容可以直接访问

 [d46]有可能是我们没有往里面传值。

 [U47]OgnlAction中有Cat属性,Cat类里面有只Dog

 [U48]这就是传说中的引用类型?!!!

 [U49]Cat中有狗这个属性

 [U50]OgnlAction中包含Cat,Cat中包含Dog,这时候就可以结合第一个实验说明什么是OGNL了。

 [U51]通过“点”来访问成员变量

 [U52]从debug模式中知道password是一个值栈中对象,是String类型的,所以可以调String的length()方法;

 [U53]Cat中有个普通的方法miaomiao(),可以取出;

 [U54]在Action中添加一个普通方法m()返回”Hello”;这里就可以取出值”Hello”;

 

 [U55]这样就可以把静态方法s()返回的值”Hello”取出来了。

 [U56]为什么访问不到呢?因为在Struts2.0之后它修改了一些配置,要在strust.xml中增加一行配置。

 [U57]允许静态方法的访问,默认是false。

 [U58]可以在ognl中new对象,因为user重写了toString()方法了,所以是user8

 [U59]因为list的名字就叫users,所以可以直接从值栈中取出;

 [U60]访问list中下标值为1的元素;数组跟list的方式一模一样,所以不举例

 [U61]每个user都有age属性,但是users里面是没有age属性的,这里是把users里面每个元素取出来,然后把它的age组合到一起成为一个新的list,大括号在ognl里可以代表一个集合;这里表示user.age的集合

 [U62]第0个位置的值

 [U63]应该用第二种;

 [U64]Dog重写了toString()方法了;

 [U65]取不到值,因为set是没有顺序的,所以取第几个没有意义,不能取。

 [U66]如果写双引号就跟前面的双引号成一对了,不是我们要的,所以要转义。第一种最简单

 [U67]拿到keys的集合

 [S68]User是一个list

后面的过滤条件,只能有“?#”,“^#”,“$#”三种;在正则表达式中“^”代表开头(小尖号)“$代表结尾”
“?代表过滤条件(这个跟正则表达式不一样)”,“this表示循环过程中当前的那个对象,循环到第一个user了this就是这个user,循环到第二个个,this就是第二个user…..”

 [S69]为什么这里它加了中括号?加了中括号代表它是一个集合,因为user=1有可能不止一个,所以就有可能是集合.

 [S70]Chain是服务器端跳转,这里跳转到ognl.action

 [S71] Action里面的属性可以直接取; property这个标签专门取ValueStack以及下面的ActionContext,取Value Stack的值直接写它的名字就可以;取ActionContext的值“#+属性值”。

 [S72]Struts2用到标签的时候有个很容易混淆的:

标签的属性有的是字符串,有的是OGNL表达式, 查API!

Value这个属性是object类型的,凡是遇到Object类型的,所以Struts2会把username解析成OGNL表达式,这样它就会去valueStack里面去取这个username的值.

如果想把它当成一个字符串取,要双引号里面再加单引号。

 [S73]如果valueStack里面没有admin这个属性值,那么它就用这个默认值.

 [S74]查文档中set标签的value属性的类型是String,检验一下,

 [S75]这里set了变量为adminName的值,所以它会把这个变量设到StackValue和ActionContext里面。查看debug模式发现adminName的值等于U,所以struts文档写错了。Set的value类型应该是object

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值