您的位置:首页 > 编程语言 > Java开发

Struts2学习总结

2012-10-10 19:51 483 查看
目录

l
建立一个Struts2 工程
- 2 -
l
用Action的属性接收参数
- 10 -
l
使用Domain Model (实体模型) 接收参数
- 11 -
l
Struts2_2.1.6版本的中文问题
- 12 -
l
Struts模块包含
- 12 -
l
Struts简单数据验证
13
l
Struts ValueStack(值栈) Debug
15
Value Stack Contents
15
l
Struts2_访问Web元素
16
Stack Context
18
第二种方式(这种方式是最常用的,其他的都可以忘记)
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-Show View-other-navigatior



4.配置web.xml,参考struts自带的web.xml,把filter的配置拷过来
<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>


第一个示例程序Hello Struts
<struts>
<constant name="struts.devMode" value="true" />
<package name="default" namespace="/" extends="struts-default">
<action name="hello">
<result>/hello.jsp</result>
</action>
</package>
</struts>
http://localhost:8080/strust2_0100_Introduction/
http://localhost:8080/strust2_0100_Introduction/hello 或者 http://localhost:8080/strust2_0100_Introduction/hello.action 跳转到hello.jsp,第一个示例程序成功!




Struts2读源码
配置文件中的
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
</filter-class>
一看就应该知道它是对应一个类,在jar文件中找到对应的源码编译完的class文件,



查看源码: jar文件点右键---àproperties--àJava Source AttachmentàExternal Folder
(外部文件)
à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
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
配置:windows---preferences---catalog---。。。xml—xml Catalog—Add





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



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


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核心的本质就是解决了:把你的请求和最后的结果分开。


Struts的namespace
示例工程Struts2_0200_Namespace
Struts.xml
<struts>
<constant name="struts.devMode" value="true" />
<package name="front" extends="struts-default" namespace="/front">
<action name="index">
<result>/Namespace.jsp</result>
</action>
</package>
<package name="main" extends="struts-default" namespace="">
<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
public class IndexAction1 {
public String execute() {
return "success";
}
}
IndexAction2.java
public class IndexAction2 implements Action {
public String execute() {
return "success";
}
}
真正企业开发只用这第三种!另外两种忘记!
IndexAction3.java
public class 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">
<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页面上有链接<a href="index.jsp">index.jsp</a>虽然在webRoot上面index.jsp和
path.jsp同级,但是点击index.jsp却跳到http://localhost:8080/Struts2_0400_Path/path/index.jsp



如果改成<a href="/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 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">添加用户</a>
前者会产生太多的action,所以不推荐使用
</body>
<struts>
<constant name="struts.devMode" value="true" />
<package name="user" extends="struts-default" namespace="/user">

<action name="userAdd" class="com.bjsxt.struts2.user.action.UserAction" method="add">
<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
public class UserAction extends ActionSupport {
private String name;
private int age;
public String add() {
System.out.println("name=" + name);
System.out.println("age=" + age);
return SUCCESS;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void 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>
public class UserAction extends ActionSupport {
private User user;
//private UserDTO userDTO;
public String add() {
System.out.println("name=" + user.getName());
System.out.println("age=" + user.getAge());
return SUCCESS;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
public class User {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
一般来说,我们输入参数不一定刚好跟我们的域模型一致,比如说:用户有name跟password两个属性,但是你输入进来的应该还有个密码确认passwordconfiguration
这时候我们要么使用属性接收,要么用DTO,或者VO


Struts2_2.1.6版本的中文问题
根据Struts文档的规定:只要在Struts.xml中配置这段话就可以解决中文乱码问题
<constant name="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
</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
public class UserAction extends ActionSupport {
private String name;
public String add() {
if(name == null || !name.equals("admin")) {
this.addFieldError("name", "name is error");
this.addFieldError("name", "name is too long");
return ERROR;
}
return SUCCESS;
}
public String getName() {
return name;
}
public void 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:fielderror fieldName="name" theme="simple"/>
<br />
<s:property value="errors.name[0]"/>
<s:debug></s:debug>
</body>

这里调用addFieldError()之后在前面如何把它拿出来?
在这里我们用到struts2的标签
<s:fielderror fieldname=”name” theme=”simple”>
调用标签库的时候,必须这么写:
<%@taglib uri=”/struts-tags” 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

Value Stack Contents

Object
Property Name
Property Value
com.bjsxt.struts2.user.action.UserAction
texts
null
actionErrors
[]
errors
{name=[name is error, name is too long]}
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 value="errors.name[0]"/>

<s:property value="errors"/>
取到errors实际上是一个map:{name=[name is error, name is too long]}
那么我想取到map里面某一个key的内容:
<s:property value="errors.name"/>
[name is error, name is too long]
而这时候实际上value是一个数组,所以我要想去数组的第一项
<s:property value="errors.name[0]"/>
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" onclick="javascript:document.f.action='login/login1';document.f.submit();" />
<input type="button" value="submit2" onclick="javascript:document.f.action='login/login2';document.f.submit();" />
<input type="button" value="submit3" onclick="javascript:document.f.action='login/login3';document.f.submit();" />
<input type="button" value="submit4" onclick="javascript:document.f.action='login/login4';document.f.submit();" />
</form>
</body>
Strust.xml
<struts>
<constant name="struts.devMode" value="true" />
<package name="login" extends="struts-default" namespace="/login">
<action name="login*" class="com.bjsxt.struts2.user.action.LoginAction{1}">
<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();

public class LoginAction1 extends ActionSupport {
private Map request;
private Map session;
private Map application;
public LoginAction1() {

//取值

request = (Map)ActionContext.getContext().get("request");
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");
return SUCCESS;
}
}
request = (Map)ActionContext.getContext().get("request");
ActionContext.getContext()
Context直接翻译过来是:”上下文”,在西方人写的程序特别多,但是中国人很少用,因为不理解它是什么东西;Context就是当前执行的环境,就比如同学们在这里学习,实际上是有一个Context,代表了你周围的情况,机器的情况,空调的情况,等等,它会把周围环境帮你封转到Context这个对象里面,当你想访问这些东西的时候,通过Context去取。
原来学习过得ServletContext代表的就是servlet的运行环境,原来我们写程序就用ServletContext拿到各种各样的配置,ActionContext也就是Action周边运行的情况,Action运行的时候,首先接收到请求接收到request,response等等后面再接着调你的处理过程,Action处理的过程中,比如说那些配置怎么配的,执行环境怎么样等等都要通过ActionContext来拿。
原先我们在页面中都是通过HttpResquest,HttpResponse拿到我们的值,现在我们通过
request = (Map)ActionContext.getContext().get("request");
session = ActionContext.getContext().getSession();
application = ActionContext.getContext().getApplication();
拿到我们的request,response,application。
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") %>
<s:property value="#attr.a1"/>
<s:property value="#attr.s1"/>
<s:property value="#attr.r1"/>
<s:debug></s:debug>
</body>
我们的后台放了request,session,application但是这三个东西都是map,但是它反馈到前台之后居然用request,session,application可以拿到,所以struts2一定帮我们在Map和HttpRequest之间建立某种联系,对于我们自己设定的map类型的request这里面的属性在处理的过程中会全都复制到Http对象里边去。

第一种访问request里面的值:<%=request.getAttribute("r1") //原始的方式
第二种访问request里面的值:<s:property value="#request.r1"/>
第二种是用标签的方式取值,查看debug模式,

Stack Context

These items are available using the #key notation


。。。略
These items are available using the #key notation :下面的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;
public class LoginAction2 extends ActionSupport implements RequestAware,SessionAware, ApplicationAware {
//第二种方式区别于第一种方式的不同点是:第一种方式还要在构造函数中进行“取值”,第二种方式直接就能用了!!这个就是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");
return SUCCESS;
}
public void setRequest(Map<String, Object> request) {
this.request = request;
}
public void setSession(Map<String, Object> session) {
this.session = session;
}
public void setApplication(Map<String, Object> application) {
this.application = application;
}
}




Action总结

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

2. DMI动态方法调用

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

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

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

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 type="redirect">/r2.jsp</result>
</action>
<action name="r3">

<result type="chain">r1</result>
</action>
<action name="r4">

<result type="redirectAction">r2</result>
</action>
</package>
</struts>
Result类型

1. dispatcher

2. redirect

3. chain

4. redirectAction

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
public class OgnlAction extends ActionSupport {
private String password;
private String username;
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getPassword() {
return password;
}
public String getUsername() {
return username;
}
public void setPassword(String password) {
this.password = password;
}
public void setUsername(String username) {
this.username = username;
}
}
User.java
public class User {
private int age = 8;
public User() {
}
public User(int age) {
super();
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override//重写toString
public String toString() {
return "user" + age;
}
}
此时的url:http://localhost:8080/ognl_0100/ognl.action?username=u&password=p 值栈中的内容
<body>
<ol>
<li>访问值栈中的:username = <s:property value="username"/> </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
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 方法



Cat.java
public class Cat {
private Dog friend;
public Dog getFriend() {
return friend;
}
public void setFriend(Dog friend) {
this.friend = friend;
}
public String miaomiao() {
return "miaomiao";
}
}
Dog.java
public class Dog {
private String name;
public Dog() { }
public Dog(String name) {
super();
this.name = name;
}
Get,set方法……..
public String toString() {
return "dog: " + name;
}
}



为什么叫做OGNL对象图导航语言?比如说我们访问OgnlAction.java里面通过“user.age”
那么这时候如果我们想访问ognlAction里面的cat的dog该怎么写? 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()"/></li>

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

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


OGNL访问静态方法/属性:
访问静态方法/属性的语法:前面@+类名,后面@+方法名/前面@+类名,后面@+属性名
先写类S.java
public class S {
public static String STR="STATIC STRING ";
public static String s(){
return "Hello";
}
}
<body>

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



要在struts.xml中增加配置:
<constant name="struts.ognl.allowStaticMethodAccess" value="true">
</constant>
在Struts2中常量的值在:
struts2-core-2.1.8.1.jar-->org.apache.struts2-->default.properties中查:





<body>访问普通类的构造方法:
<s:property value="new com.bjsxt.struts2.ognl.User(8)"/>
</body>




OGNL访问集合
在OgnlAction.java中添加:

private List<User> users = new ArrayList<User>();
private Map<String, Dog> dogMap = new HashMap<String, Dog>();
private Set<Dog> dogs = new HashSet<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"/>

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

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

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

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

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

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

18.访问Map中某个元素:

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

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

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

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

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.{?#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}"/>
执行结果:



如果想取出集合中的第一个元素。
<s:property value="users.{?#this.age==1}[0]"/>
执行结果:


<s:property value="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]代表的是ognl的stack从上往下从第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">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>

public class TagsAction extends ActionSupport {
private String password;
private String username;
public TagsAction() {
}
public String execute() {
this.addFieldError("fielderror.test", "wrong!");
return SUCCESS;
}
Get,set方法。。。。
}
Property



<body>

<s:property value="username"/>

property取值为字符串 <s:property value="'username'"/>

property设定默认值 <s:property value="admin" default="管理员"/>
property设定HTML<s:property value="'<hr/>'" escape="false"/>
</body>
Value的属性值究竟是OGNL还是普通字符串,得去API查parameters!





Set



set设定adminName值(如果不设scope属性,默认为request和ActionContext)

<s:set var="adminName" value="username"/>
set从request取值<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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: