Struts2简明教程
本教程整个过程中都以例子贯穿始终,辅助以解释说明.
1.web.xml中配置struts2
要在项目中使用struts首先要在web.xml中把struts2配置进来,而struts2是作为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>
2.设置开发模式<constant name="struts.devMode" value="true" />
对于开发阶段的项目来说,把struts设置为开发模式有很大的好处,这样就不需要每次修改了struts.xml文件之后重新启动容器了,容器会自动检测struts.xml文件的状态,有了修改之后容器会自动的从新加载
3.配置struts2的包名,命名空间
<package name="test" extends="struts-default" namespace="/test">
</package>
struts2的包名和命名空间实际上只是一个代表符号,尤其是package的name属性,其实完全可以不设置的,但是为了是文件看起来更加的规范化,更加的容易理解,我们一般都是按照Action所在的src下的包的名字来命名的,而实际上namespace也最好遵循同样的方式,这样无论何时,程序看起来都非常的规范,而且看到了包名我们就知道它的命名空间,就知道它在src目录下所对应的包的位置,这种良好的习惯在开发大型的系统的时候将会显示出巨大的好处,当然namespace并不是可有可无的,因为在你访问某一个Action的时候,你必须要指定namespace,否则容器哪里知道你要访问哪一个Action呢?
4.配置Action
<package name="front" extends="struts-default" namespace="/">
<action name="index" class="dada.test.FirstAction">
<result name="success">/success.jsp</result>
</action>
</package>
action的配置需要放在某一个package下面,这样做的目的是为了解决不同包下的Action命名冲突的问题,而配置Action需要指定名字,和class的位置,method为可选选项,class的配置是以src目录为根目录进行配置的比如src目录下有dada.test包,里有FirstAction的Action,那么你配置class的位置时就是:class="dada.test.FirstAction"为什么呢?为什么不把src给加进来呢?其实类似的问题还有就是webContent我们不用指明它是因为它们是被作为默认的位置的,程序找得时候就直接去它下面找的,这是一种大家都默认的规范,我们都遵循同样的标准,,要不然你配在项目里面再重新添加一个源码包,然后在里面添加Action,这个时候在你把这个Action配置到struts.xml里面的时候,你必须要把源码包的名字也带上,否则程序肯定检测不到,而且就返回结果来说它也是根据你Action里面所调用方法返回值进行匹配的,比如返回的是success那么就匹配success,实际上success不用配置,默认的没有name属性的result就是success
Action类的标准:
(1)具体视图的返回可以由用户自己定义的Action来决定
(1)具体的手段是根据返回的字符串找到对应的配置项,来决定视图的内容
(3)具体Action的实现可以是一个普通的java类,里面有public String execute方法即可,或者实现Action接口
(4)不过最常用的是从ActionSupport继承,好处在于可以直接使用Struts2封装好的方法<br />
5.Action的路径问题
struts2中的路径问题是根据action的路径而不是jsp路径来确定,所以尽量不要使用相对路径。
虽然可以用redirect方式解决,但redirect方式并非必要。
解决办法非常简单,统一使用绝对路径。
使用:String path = request.getContextPath();获取webapp的路径
使用:String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";获取基础路径
6.Action的方法指定
Action执行的时候并不一定要执行execute方法
(1)可以在配置文件中配置Action的时候用method="xxx"来指定执行哪个方法
<package name="front" extends="struts-default" namespace="/">
<action name="index" class="dada.test.FirstAction" method="add">
<result name="success">/success.jsp</result>
</action>
</package>
(2)也可以在url地址中动态指定(动态方法调用DMI)(推荐)
<a href="<%=context %>/user/user!add">添加用户</a>
前者会产生太多的action,所以不推荐使用
7.通配符配置
(1)使用一个通配符
<action name="Student*" class="dada.action.StudentAction" method="{1}">
<result>/Student{1}_success.jsp</result>
<result name="error">/Student{1}_error.jsp</result>
</action>
或者
<action name="*add" class="dada.action.{1}Action" method="add">
<result>/{1}_add_success.jsp</result>
<result name="error">/{1}_add_error.jsp</result>
</action>
这两种方式都是只使用了一个通配符,它们的好处在于:
->前者可以动态的指定方法
->后者可以动态指定Action
但是毕竟还是不能完全实现对Action和方法的双重的动态指定要实现就需要使用两个通配符
(2)使用两个通配符
<action name="*_*" class="com.bjsxt.struts2.action.{1}Action" method="{2}">
<result>/{1}_{2}_success.jsp</result>
<result name="error">/{1}_{2}_error.jsp</result>
</action>
当你使用两个或者更多个的时候,你就可以动态的指定Action的名字和方法的名字了,这种指定方式要求就是:
(1)所有的Action在同一个目录下面(因为不在同一包里面肯定不可以这么写的)
(2)所有的Action和返回的结果都要遵循同样的命名的方式,比如Action的名字拿本例子来说都要遵循的是名字的后半部分都要以Action结尾,而返回的结果都要使用两个"_"把动态指定的名字给分割开来,否则无法实现动态指定
(3)使用三个通配符
<action name="*_*_*" class="com.bjsxt.struts2.{1}.{2}Action" method="{3}">
<result>/{2}_{3}_success.jsp</result>
</action>
如果你使用三个通配符的话,你就可以实现对包的动态指定了,不过虽然很动态,但是问题是这样在真正使用的时候也会带来问题,就是我们在实际访问过程中要为每一个通配符指定对于的名称的时候就会变得非常的麻烦,容易让人晕头转向,实际上也没有什么反正从后往前推,第一个是包名,第二个是Action名,第三个是方法名,不过总体来看,使用两个通配符就已经够方便了,使用三个有可能会得不偿失.
8.Action类的自动装配
(1)一般属性装配,对于一般属性的装配,只需要在Action中提供被装配属性的get和set方法即可,在请求发送过来的时候,strust会自动帮我们把属性给赋值给Action里面的属性
请求URL写法:url="<%=request.getContextPath()%>/dada/User_add?name=dada&age=23"
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;
}
}
(2)对象属性装配,对于一般属性的装配,只需要在Action中提供被装配对象的get和set方法即可
注意Action对象属性类的要求:
只要是重写一个类的构造方法,就必须要为这个类保留空的构造方法
因为框架默认的都会去调用无参的空的构造方法
被装配对象(被装配对象里面的属性也需要提供get和set方法,其实就是一种链式的get和set方法调用):
请求URL写法:url=href="user/user!add?user.name=a&user.age=8"
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;
}
}
Action类
public class UserAction extends ActionSupport {
private User user;
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;
}
}
9.编码问题
<constant name="struts.i18n.encoding" value="UTF-8" />
使用这句话可以对编码进行处理,但是问题是如果jsp页面使用的是ISO-8859-1,就算你配置了这一句话也没有用,具体也许可以通过一种方式转换过来但是那毕竟还是麻烦,最简单的办法就是把所有用到了字符编码的地方全部都设置成为UTF-8这样你基本上就不会出现问题了.
10.简单的数据验证
Action类处理:
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;
}
}
jsp接受:
返回jsp的错误信息是以数组的形式返回过来的
(1)使用<s:property value=""/>标签直接的接受
<s:property value="errors.name[0]"/>
(2)使用<s:fielderror fieldName="name" theme="simple"/>标签对结果的展现形式进行美化
<s:fielderror fieldName="name" theme="simple">
<s:property value="errors.name[0]"/>
</s:fielderror>
11.Action中获取request,session,application的方式
(1)
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");
session.put("s1", "s1");
application.put("a1", "a1");
return SUCCESS;
}
}
(2)
public class LoginAction2 extends ActionSupport implements RequestAware,SessionAware, ApplicationAware {
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;
}
@Override
public void setRequest(Map<String, Object> request) {
this.request = request;
}
@Override
public void setSession(Map<String, Object> session) {
this.session = session;
}
@Override
public void setApplication(Map<String, Object> application) {
this.application = application;
}
}
(3)
public class LoginAction3 extends ActionSupport {
private HttpServletRequest request;
private HttpSession session;
private ServletContext application;
public LoginAction3() {
request = ServletActionContext.getRequest();
session = request.getSession();
application = session.getServletContext();
}
public String execute() {
request.setAttribute("r1", "r1");
session.setAttribute("s1", "s1");
application.setAttribute("a1", "a1");
return SUCCESS;
}
}
(4)
public class LoginAction4 extends ActionSupport implements ServletRequestAware {
private HttpServletRequest request;
private HttpSession session;
private ServletContext application;
public String execute() {
request.setAttribute("r1", "r1");
session.setAttribute("s1", "s1");
application.setAttribute("a1", "a1");
return SUCCESS;
}
@Override
public void setServletRequest(HttpServletRequest request) {
this.request = request;
this.session = request.getSession();
this.application = session.getServletContext();
}
}
12.把struts.xml中包含其他配置文件的方法
<struts>
<include file="login.xml" />
</struts>
13.配置默认的Action在你没有指定具体的Action的时候,程序自动跳转到的Action
<package name="default" namespace="/" extends="struts-default">
<default-action-ref name="index"></default-action-ref>
<action name="index">
<result>/default.jsp</result>
</action>
</package>
14.Action的返回类型
<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">r4</result>
</action>
<!-- chain和redirectAction的区别在于chain是服务器端的跳转而redirectAction是客户端跳转 -->
<action name="r4">
<result type="redirectAction">r2</result>
</action>
</package>
(1)结果类型中redirect和redirectAction的区别
redirect是在处理完当前Action之后,重定向到另外一个实际的物理资源
redirectAction也是重定向,但它重定向到的是另外一个Action
只要是重定向,那么之前凡是保存在request里面的东西就全都消失了
因为重定向实际是发送第二个请求,故请求中的东西也就不会出现在第二个请求里面了
也就是说重定向是不共享request的东西,重定向后的页面中无法接收request里的东西
另外dispatcher结果类型的default属性为TRUE,故<result-type/>缺省为dispatcher
所以如果没有设置type属性的话,那么默认的是请求转发,即浏览器显示的是*.action
但是在设置type="redirect"属性后,就可以重定向了,即浏览器显示的是/login2.jsp
(2)chain和redirectAction区别
Struts2的Action处理链
从一个Action跳转到另一个Action,有两种办法,即将type设置为chain或者redirectAction
chain结果类型表示将多个Action作为一个链来处理
而使用chain和redirectAction的好处就是:它会按照框架的默认后缀去自动匹配后缀
而chain和redirectAction的区别与dispatcher和redirect的区别是一样的
即同样是跳转到一个Action上,但chain是服务器跳转,而redirectAction是客户端跳转
服务器跳转的过程中,可以共享数据,这时后面的Action就可以接收前面Action中的属性信息进行二次处理
15.global-results
原理:它的作用就是在Action中返回了一个结果,可是这个结果却在对应的Action或者是package里面,没有定义,可是它还是要去找的,这个时候就需要向上去查找有没有这个结果的定义了,本Action没有向上一级,找,上一级没有就去继承的包里面找,如果一直找不到那就出错了
注意要使用:global-results需要把当前的包设置为:extends="struts-default",如果没有这句话,那么程序是不会去自动的去global-results里面去匹配的,而且包之间是可以进行继承的,子包可以使用父包里面的global-results里面的资源
<struts>
<constant name="struts.devMode" value="true" />
<package name="user" namespace="/user" extends="struts-default">
<global-results>
<result name="mainpage">/main.jsp</result>
</global-results>
<action name="index">
<result>/index.jsp</result>
</action>
<action name="user" class="dada.user.action.UserAction">
<result>/user_success.jsp</result>
<result name="error">/user_error.jsp</result>
</action>
</package>
<package name="admin" namespace="/admin" extends="user">
<action name="admin" class="dada.user.action.AdminAction">
<result>/admin.jsp</result>
</action>
</package>
</struts>
16.动态指定返回的结果
Action里面的操作
public class UserAction extends ActionSupport {
private int type;
private String r;
public String getR() {
return r;
}
public void setR(String r) {
this.r = r;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
@Override
public String execute() throws Exception {
if(type == 1) r="/user_success.jsp";
else if (type == 2) r="/user_error.jsp";
return "success";
}
}
配置文件里面的处理:
<package name="user" namespace="/user" extends="struts-default">
<!--这里使用的也是OGNL表达式来获取值的,而且这个时候就不需要你为它指定result的名字和类型了而是使用默认的success做为name-->
<result>${r}</result>
</action>
</package>
这里其实把变量r当做了一个属性,因为它是可以被设置和获取的,因此,当返回结果的时候,OGNL表达式就可以获取它的值,然后返回动态的结果
注意点:获取返回的结果时不要忘了"$"符号
17.三个路径的区别
<a href="/test/a1?type=1">path1</a>
浏览器中显示:http://localhost:8080/test/index.jsp
解释:"/"在url中代表的是当前的容器的路径,所以显示的路径里面就把当前项目的路径给丢掉了
<a href="test/a1?type=2">path2</a>
浏览器中显示:http://localhost:8080/Struts2_1700_DynamicResult_1/test/index.jsp
解释:当url前面没有"/"的时候默认的是加上当前的项目的根目录
<a href="<%=request.getContextPath() %>/test/a1?type=2">path3</a>
浏览器中显示:http://localhost:8080/Struts2_1700_DynamicResult_1/test/index.jsp
解释:<%=request.getContextPath() %>获取的是当前的项目所在的根目录,后边加上要访问的Action的namespace和Action的名字
struts.xml result返回页面的配置<result>/ognl.jsp</result>这个里面使用了"/"这里的"/"代表的是当前web应用的根目录
18.返回带参数的结果
后台Action:
public class UserAction extends ActionSupport {
private int type;
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
@Override
public String execute() throws Exception {
return "success";
}
}
struts.xml文件配置:
<struts>
<constant name="struts.devMode" value="true" />
<package name="user" namespace="/user" extends="struts-default">
<action name="user" class="com.bjsxt.struts2.user.action.UserAction">
<result type="redirect">/user_success.jsp?t=${type}</result>
</action>
</package>
</struts>
其实原理还是一样的,跟 16 中所讲述的动态指定返回结果是一样的道理,都是使用的OGNL表达式的取值方法不再累述
19.OGNL表达式的使用
要使用OGNL表达式调用方法就需要在struts.xml中配置如下常量
<struts>
<constant name="struts.enable.DynamicMethodInvocation" value="false" />
<constant name="struts.devMode" value="true" />
<constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>
<package name="ognl" extends="struts-default" namespace="/ognl">
<action name="ognlAction" class="com.dada.test.OgnlAction">
<result>/ognl.jsp</result>
</action>
<action name="test" class="com.dada.test.TestAction">
<result type="chain">ognlAction</result>
</action>
</package>
</struts>
使用OGNL表达式
<p>访问值栈中的Action的普通属性:username=<s:property value="username"/> </p>
<p>访问值栈中对象普通属性(get,set方法):<s:property value="user.age"/>|<s:property value="user['age']"/>|<s:property value="user[\"age\"]"/> </p>
<p>访问值栈中对象普通属性(get,set方法):<s:property value="cat.friend.name"/></p>
<p>访问值栈中对象普通方法:<s:property value="password.length()"/></p>
<p>访问值栈中对象普通方法:<s:property value="cat.miaomiao()"/></p>
<p>访问值栈中Action的普通方法:<s:property value="m()"/> </p>
<hr/>
<!--两个@之间的部分是类所在的位置第二个@后边表示的是静态的方法名字或者属性名-->
<p>访问静态方法:<s:property value="@com.dada.test.S@s"/> </p>
<p>访问静态属性:<s:property value="@com.dada.test.S@STR"/></p>
<!-- 这里之所以这么写是因为Math类在lang包里面,所以不需要引入类名字 -->
<p>访问Math类静态方法:<s:property value="@@max(2,3)"/></p>
<hr/>
<p>访问普通类的构造方法:<s:property value="new com.dada.test.Dog(\"dog created by jsp\")"/></p>
<hr/>
<p>访问List:<s:property value="users"/></p>
<p>访问List中的某一个元素:<s:property value="users[0]"/></p>
<p>访问List中的某一个属性集合:<s:property value="users.{age}"/></p>
<p>访问List中的某一个属性集合中的特定的值:<s:property value="users.{age}[0]"/>|<s:property value="users[0].age"/> </p>
<p>访问Set<s:property value="dogs"/> </p>
<p>访问Set中某一个元素:<s:property value="dogs[0].age"/>???好像这边是有问题的 </p>
<p>访问Map:<s:property value="dogMap"/></p>
<p>访问Map中的某一个元素:<s:property value="dogMap.d1"/></p>
<p>访问Map中的所有Key:<s:property value="dogMap.keys"/></p>
<p>访问Map中的所有Key:<s:property value="dogMap.values"/></p>
<p>访问Map容器大小:<s:property value="dogMap.size()"/>|<s:property value="users.size()"/> </p>
<hr/>
<p>投影(过滤)<s:property value="users.{?#this.age==1}[0]"/></p>
<p>投影:<s:property value="users.{^#this.age>0}.{age}"/></p>
<p>投影:<s:property value="users.{$#this.age>1}.{age}"/></p>
<p>投影:<s:property value="users.{$#this.age>1}.{age}==null"/></p>
a.“?#”:投影(过滤)所有符合条件的集合,如:users.{?#this.age > 19};
b.“^#”:投影(过滤)第一个符合条件的元素,如:users.{^#this.age > 19};
c.“$#”:投影(过滤)最后一个符合条件的元素,如:users.{$#this.age > 19} 。
<hr/>
<p>[]:<s:property value="[0].username"/> </p>
20.strust theme设置
(1).在struts.xml中控制theme,默认为xhtml,可以设置为:simple/css_html/ajax
<ol>
<li>
<s:form >
<div class="formFieldError">
<s:fielderror />
</div>
<s:textfield name='aaa'></s:textfield>
</s:form>
</li>
</ol>
(2).用CSS控制显示
<html>
<style type="text/css">
.formFieldError {
font-family: verdana, arial, helvetica, sans-serif;
font-size: 12px;
color: #FF3300;
vertical-align: bottom;
}
.formFieldError ul {
/*list-style-type: none*/
margin: 0px;
padding: 3px;
vertical-align: middle;
}
.formFieldError ul li{
list-style-type: none
}
</style>
</head>
<body>
<ol>
<li>
<s:form >
<div class="formFieldError">
<s:fielderror />
</div>
<s:textfield name='aaa'></s:textfield>
</s:form>
</li>
</ol>
</body>
</html>
(3).在struts.xml文件中指定
<struts>
<constant name="struts.ui.theme" value="simple" />
<package name="theme" extends="struts-default">
<action name="theme" class="com.bjsxt.struts2.theme.ThemeAction">
<result>/theme.jsp</result>
</action>
</package>
</struts>
(4).指定自己的css
<struts>
<constant name="struts.ui.theme" value="mytheme" />
<package name="theme" extends="struts-default">
<action name="theme" class="com.bjsxt.struts2.theme.ThemeAction">
<result>/theme.jsp</result>
</action>
</package>
</struts>
本教程整个过程中都以例子贯穿始终,辅助以解释说明.
1.web.xml中配置struts2
要在项目中使用struts首先要在web.xml中把struts2配置进来,而struts2是作为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>
2.设置开发模式<constant name="struts.devMode" value="true" />
对于开发阶段的项目来说,把struts设置为开发模式有很大的好处,这样就不需要每次修改了struts.xml文件之后重新启动容器了,容器会自动检测struts.xml文件的状态,有了修改之后容器会自动的从新加载
3.配置struts2的包名,命名空间
<package name="test" extends="struts-default" namespace="/test">
</package>
struts2的包名和命名空间实际上只是一个代表符号,尤其是package的name属性,其实完全可以不设置的,但是为了是文件看起来更加的规范化,更加的容易理解,我们一般都是按照Action所在的src下的包的名字来命名的,而实际上namespace也最好遵循同样的方式,这样无论何时,程序看起来都非常的规范,而且看到了包名我们就知道它的命名空间,就知道它在src目录下所对应的包的位置,这种良好的习惯在开发大型的系统的时候将会显示出巨大的好处,当然namespace并不是可有可无的,因为在你访问某一个Action的时候,你必须要指定namespace,否则容器哪里知道你要访问哪一个Action呢?
4.配置Action
<package name="front" extends="struts-default" namespace="/">
<action name="index" class="dada.test.FirstAction">
<result name="success">/success.jsp</result>
</action>
</package>
action的配置需要放在某一个package下面,这样做的目的是为了解决不同包下的Action命名冲突的问题,而配置Action需要指定名字,和class的位置,method为可选选项,class的配置是以src目录为根目录进行配置的比如src目录下有dada.test包,里有FirstAction的Action,那么你配置class的位置时就是:class="dada.test.FirstAction"为什么呢?为什么不把src给加进来呢?其实类似的问题还有就是webContent我们不用指明它是因为它们是被作为默认的位置的,程序找得时候就直接去它下面找的,这是一种大家都默认的规范,我们都遵循同样的标准,,要不然你配在项目里面再重新添加一个源码包,然后在里面添加Action,这个时候在你把这个Action配置到struts.xml里面的时候,你必须要把源码包的名字也带上,否则程序肯定检测不到,而且就返回结果来说它也是根据你Action里面所调用方法返回值进行匹配的,比如返回的是success那么就匹配success,实际上success不用配置,默认的没有name属性的result就是success
Action类的标准:
(1)具体视图的返回可以由用户自己定义的Action来决定
(1)具体的手段是根据返回的字符串找到对应的配置项,来决定视图的内容
(3)具体Action的实现可以是一个普通的java类,里面有public String execute方法即可,或者实现Action接口
(4)不过最常用的是从ActionSupport继承,好处在于可以直接使用Struts2封装好的方法<br />
5.Action的路径问题
struts2中的路径问题是根据action的路径而不是jsp路径来确定,所以尽量不要使用相对路径。
虽然可以用redirect方式解决,但redirect方式并非必要。
解决办法非常简单,统一使用绝对路径。
使用:String path = request.getContextPath();获取webapp的路径
使用:String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";获取基础路径
6.Action的方法指定
Action执行的时候并不一定要执行execute方法
(1)可以在配置文件中配置Action的时候用method="xxx"来指定执行哪个方法
<package name="front" extends="struts-default" namespace="/">
<action name="index" class="dada.test.FirstAction" method="add">
<result name="success">/success.jsp</result>
</action>
</package>
(2)也可以在url地址中动态指定(动态方法调用DMI)(推荐)
<a href="<%=context %>/user/user!add">添加用户</a>
前者会产生太多的action,所以不推荐使用
7.通配符配置
(1)使用一个通配符
<action name="Student*" class="dada.action.StudentAction" method="{1}">
<result>/Student{1}_success.jsp</result>
<result name="error">/Student{1}_error.jsp</result>
</action>
或者
<action name="*add" class="dada.action.{1}Action" method="add">
<result>/{1}_add_success.jsp</result>
<result name="error">/{1}_add_error.jsp</result>
</action>
这两种方式都是只使用了一个通配符,它们的好处在于:
->前者可以动态的指定方法
->后者可以动态指定Action
但是毕竟还是不能完全实现对Action和方法的双重的动态指定要实现就需要使用两个通配符
(2)使用两个通配符
<action name="*_*" class="com.bjsxt.struts2.action.{1}Action" method="{2}">
<result>/{1}_{2}_success.jsp</result>
<result name="error">/{1}_{2}_error.jsp</result>
</action>
当你使用两个或者更多个的时候,你就可以动态的指定Action的名字和方法的名字了,这种指定方式要求就是:
(1)所有的Action在同一个目录下面(因为不在同一包里面肯定不可以这么写的)
(2)所有的Action和返回的结果都要遵循同样的命名的方式,比如Action的名字拿本例子来说都要遵循的是名字的后半部分都要以Action结尾,而返回的结果都要使用两个"_"把动态指定的名字给分割开来,否则无法实现动态指定
(3)使用三个通配符
<action name="*_*_*" class="com.bjsxt.struts2.{1}.{2}Action" method="{3}">
<result>/{2}_{3}_success.jsp</result>
</action>
如果你使用三个通配符的话,你就可以实现对包的动态指定了,不过虽然很动态,但是问题是这样在真正使用的时候也会带来问题,就是我们在实际访问过程中要为每一个通配符指定对于的名称的时候就会变得非常的麻烦,容易让人晕头转向,实际上也没有什么反正从后往前推,第一个是包名,第二个是Action名,第三个是方法名,不过总体来看,使用两个通配符就已经够方便了,使用三个有可能会得不偿失.
8.Action类的自动装配
(1)一般属性装配,对于一般属性的装配,只需要在Action中提供被装配属性的get和set方法即可,在请求发送过来的时候,strust会自动帮我们把属性给赋值给Action里面的属性
请求URL写法:url="<%=request.getContextPath()%>/dada/User_add?name=dada&age=23"
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;
}
}
(2)对象属性装配,对于一般属性的装配,只需要在Action中提供被装配对象的get和set方法即可
注意Action对象属性类的要求:
只要是重写一个类的构造方法,就必须要为这个类保留空的构造方法
因为框架默认的都会去调用无参的空的构造方法
被装配对象(被装配对象里面的属性也需要提供get和set方法,其实就是一种链式的get和set方法调用):
请求URL写法:url=href="user/user!add?user.name=a&user.age=8"
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;
}
}
Action类
public class UserAction extends ActionSupport {
private User user;
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;
}
}
9.编码问题
<constant name="struts.i18n.encoding" value="UTF-8" />
使用这句话可以对编码进行处理,但是问题是如果jsp页面使用的是ISO-8859-1,就算你配置了这一句话也没有用,具体也许可以通过一种方式转换过来但是那毕竟还是麻烦,最简单的办法就是把所有用到了字符编码的地方全部都设置成为UTF-8这样你基本上就不会出现问题了.
10.简单的数据验证
Action类处理:
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;
}
}
jsp接受:
返回jsp的错误信息是以数组的形式返回过来的
(1)使用<s:property value=""/>标签直接的接受
<s:property value="errors.name[0]"/>
(2)使用<s:fielderror fieldName="name" theme="simple"/>标签对结果的展现形式进行美化
<s:fielderror fieldName="name" theme="simple">
<s:property value="errors.name[0]"/>
</s:fielderror>
11.Action中获取request,session,application的方式
(1)
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");
session.put("s1", "s1");
application.put("a1", "a1");
return SUCCESS;
}
}
(2)
public class LoginAction2 extends ActionSupport implements RequestAware,SessionAware, ApplicationAware {
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;
}
@Override
public void setRequest(Map<String, Object> request) {
this.request = request;
}
@Override
public void setSession(Map<String, Object> session) {
this.session = session;
}
@Override
public void setApplication(Map<String, Object> application) {
this.application = application;
}
}
(3)
public class LoginAction3 extends ActionSupport {
private HttpServletRequest request;
private HttpSession session;
private ServletContext application;
public LoginAction3() {
request = ServletActionContext.getRequest();
session = request.getSession();
application = session.getServletContext();
}
public String execute() {
request.setAttribute("r1", "r1");
session.setAttribute("s1", "s1");
application.setAttribute("a1", "a1");
return SUCCESS;
}
}
(4)
public class LoginAction4 extends ActionSupport implements ServletRequestAware {
private HttpServletRequest request;
private HttpSession session;
private ServletContext application;
public String execute() {
request.setAttribute("r1", "r1");
session.setAttribute("s1", "s1");
application.setAttribute("a1", "a1");
return SUCCESS;
}
@Override
public void setServletRequest(HttpServletRequest request) {
this.request = request;
this.session = request.getSession();
this.application = session.getServletContext();
}
}
12.把struts.xml中包含其他配置文件的方法
<struts>
<include file="login.xml" />
</struts>
13.配置默认的Action在你没有指定具体的Action的时候,程序自动跳转到的Action
<package name="default" namespace="/" extends="struts-default">
<default-action-ref name="index"></default-action-ref>
<action name="index">
<result>/default.jsp</result>
</action>
</package>
14.Action的返回类型
<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">r4</result>
</action>
<!-- chain和redirectAction的区别在于chain是服务器端的跳转而redirectAction是客户端跳转 -->
<action name="r4">
<result type="redirectAction">r2</result>
</action>
</package>
(1)结果类型中redirect和redirectAction的区别
redirect是在处理完当前Action之后,重定向到另外一个实际的物理资源
redirectAction也是重定向,但它重定向到的是另外一个Action
只要是重定向,那么之前凡是保存在request里面的东西就全都消失了
因为重定向实际是发送第二个请求,故请求中的东西也就不会出现在第二个请求里面了
也就是说重定向是不共享request的东西,重定向后的页面中无法接收request里的东西
另外dispatcher结果类型的default属性为TRUE,故<result-type/>缺省为dispatcher
所以如果没有设置type属性的话,那么默认的是请求转发,即浏览器显示的是*.action
但是在设置type="redirect"属性后,就可以重定向了,即浏览器显示的是/login2.jsp
(2)chain和redirectAction区别
Struts2的Action处理链
从一个Action跳转到另一个Action,有两种办法,即将type设置为chain或者redirectAction
chain结果类型表示将多个Action作为一个链来处理
而使用chain和redirectAction的好处就是:它会按照框架的默认后缀去自动匹配后缀
而chain和redirectAction的区别与dispatcher和redirect的区别是一样的
即同样是跳转到一个Action上,但chain是服务器跳转,而redirectAction是客户端跳转
服务器跳转的过程中,可以共享数据,这时后面的Action就可以接收前面Action中的属性信息进行二次处理
15.global-results
原理:它的作用就是在Action中返回了一个结果,可是这个结果却在对应的Action或者是package里面,没有定义,可是它还是要去找的,这个时候就需要向上去查找有没有这个结果的定义了,本Action没有向上一级,找,上一级没有就去继承的包里面找,如果一直找不到那就出错了
注意要使用:global-results需要把当前的包设置为:extends="struts-default",如果没有这句话,那么程序是不会去自动的去global-results里面去匹配的,而且包之间是可以进行继承的,子包可以使用父包里面的global-results里面的资源
<struts>
<constant name="struts.devMode" value="true" />
<package name="user" namespace="/user" extends="struts-default">
<global-results>
<result name="mainpage">/main.jsp</result>
</global-results>
<action name="index">
<result>/index.jsp</result>
</action>
<action name="user" class="dada.user.action.UserAction">
<result>/user_success.jsp</result>
<result name="error">/user_error.jsp</result>
</action>
</package>
<package name="admin" namespace="/admin" extends="user">
<action name="admin" class="dada.user.action.AdminAction">
<result>/admin.jsp</result>
</action>
</package>
</struts>
16.动态指定返回的结果
Action里面的操作
public class UserAction extends ActionSupport {
private int type;
private String r;
public String getR() {
return r;
}
public void setR(String r) {
this.r = r;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
@Override
public String execute() throws Exception {
if(type == 1) r="/user_success.jsp";
else if (type == 2) r="/user_error.jsp";
return "success";
}
}
配置文件里面的处理:
<package name="user" namespace="/user" extends="struts-default">
<!--这里使用的也是OGNL表达式来获取值的,而且这个时候就不需要你为它指定result的名字和类型了而是使用默认的success做为name-->
<result>${r}</result>
</action>
</package>
这里其实把变量r当做了一个属性,因为它是可以被设置和获取的,因此,当返回结果的时候,OGNL表达式就可以获取它的值,然后返回动态的结果
注意点:获取返回的结果时不要忘了"$"符号
17.三个路径的区别
<a href="/test/a1?type=1">path1</a>
浏览器中显示:http://localhost:8080/test/index.jsp
解释:"/"在url中代表的是当前的容器的路径,所以显示的路径里面就把当前项目的路径给丢掉了
<a href="test/a1?type=2">path2</a>
浏览器中显示:http://localhost:8080/Struts2_1700_DynamicResult_1/test/index.jsp
解释:当url前面没有"/"的时候默认的是加上当前的项目的根目录
<a href="<%=request.getContextPath() %>/test/a1?type=2">path3</a>
浏览器中显示:http://localhost:8080/Struts2_1700_DynamicResult_1/test/index.jsp
解释:<%=request.getContextPath() %>获取的是当前的项目所在的根目录,后边加上要访问的Action的namespace和Action的名字
struts.xml result返回页面的配置<result>/ognl.jsp</result>这个里面使用了"/"这里的"/"代表的是当前web应用的根目录
18.返回带参数的结果
后台Action:
public class UserAction extends ActionSupport {
private int type;
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
@Override
public String execute() throws Exception {
return "success";
}
}
struts.xml文件配置:
<struts>
<constant name="struts.devMode" value="true" />
<package name="user" namespace="/user" extends="struts-default">
<action name="user" class="com.bjsxt.struts2.user.action.UserAction">
<result type="redirect">/user_success.jsp?t=${type}</result>
</action>
</package>
</struts>
其实原理还是一样的,跟 16 中所讲述的动态指定返回结果是一样的道理,都是使用的OGNL表达式的取值方法不再累述
19.OGNL表达式的使用
要使用OGNL表达式调用方法就需要在struts.xml中配置如下常量
<struts>
<constant name="struts.enable.DynamicMethodInvocation" value="false" />
<constant name="struts.devMode" value="true" />
<constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>
<package name="ognl" extends="struts-default" namespace="/ognl">
<action name="ognlAction" class="com.dada.test.OgnlAction">
<result>/ognl.jsp</result>
</action>
<action name="test" class="com.dada.test.TestAction">
<result type="chain">ognlAction</result>
</action>
</package>
</struts>
使用OGNL表达式
<p>访问值栈中的Action的普通属性:username=<s:property value="username"/> </p>
<p>访问值栈中对象普通属性(get,set方法):<s:property value="user.age"/>|<s:property value="user['age']"/>|<s:property value="user[\"age\"]"/> </p>
<p>访问值栈中对象普通属性(get,set方法):<s:property value="cat.friend.name"/></p>
<p>访问值栈中对象普通方法:<s:property value="password.length()"/></p>
<p>访问值栈中对象普通方法:<s:property value="cat.miaomiao()"/></p>
<p>访问值栈中Action的普通方法:<s:property value="m()"/> </p>
<hr/>
<!--两个@之间的部分是类所在的位置第二个@后边表示的是静态的方法名字或者属性名-->
<p>访问静态方法:<s:property value="@com.dada.test.S@s"/> </p>
<p>访问静态属性:<s:property value="@com.dada.test.S@STR"/></p>
<!-- 这里之所以这么写是因为Math类在lang包里面,所以不需要引入类名字 -->
<p>访问Math类静态方法:<s:property value="@@max(2,3)"/></p>
<hr/>
<p>访问普通类的构造方法:<s:property value="new com.dada.test.Dog(\"dog created by jsp\")"/></p>
<hr/>
<p>访问List:<s:property value="users"/></p>
<p>访问List中的某一个元素:<s:property value="users[0]"/></p>
<p>访问List中的某一个属性集合:<s:property value="users.{age}"/></p>
<p>访问List中的某一个属性集合中的特定的值:<s:property value="users.{age}[0]"/>|<s:property value="users[0].age"/> </p>
<p>访问Set<s:property value="dogs"/> </p>
<p>访问Set中某一个元素:<s:property value="dogs[0].age"/>???好像这边是有问题的 </p>
<p>访问Map:<s:property value="dogMap"/></p>
<p>访问Map中的某一个元素:<s:property value="dogMap.d1"/></p>
<p>访问Map中的所有Key:<s:property value="dogMap.keys"/></p>
<p>访问Map中的所有Key:<s:property value="dogMap.values"/></p>
<p>访问Map容器大小:<s:property value="dogMap.size()"/>|<s:property value="users.size()"/> </p>
<hr/>
<p>投影(过滤)<s:property value="users.{?#this.age==1}[0]"/></p>
<p>投影:<s:property value="users.{^#this.age>0}.{age}"/></p>
<p>投影:<s:property value="users.{$#this.age>1}.{age}"/></p>
<p>投影:<s:property value="users.{$#this.age>1}.{age}==null"/></p>
a.“?#”:投影(过滤)所有符合条件的集合,如:users.{?#this.age > 19};
b.“^#”:投影(过滤)第一个符合条件的元素,如:users.{^#this.age > 19};
c.“$#”:投影(过滤)最后一个符合条件的元素,如:users.{$#this.age > 19} 。
<hr/>
<p>[]:<s:property value="[0].username"/> </p>
20.strust theme设置
(1).在struts.xml中控制theme,默认为xhtml,可以设置为:simple/css_html/ajax
<ol>
<li>
<s:form >
<div class="formFieldError">
<s:fielderror />
</div>
<s:textfield name='aaa'></s:textfield>
</s:form>
</li>
</ol>
(2).用CSS控制显示
<html>
<style type="text/css">
.formFieldError {
font-family: verdana, arial, helvetica, sans-serif;
font-size: 12px;
color: #FF3300;
vertical-align: bottom;
}
.formFieldError ul {
/*list-style-type: none*/
margin: 0px;
padding: 3px;
vertical-align: middle;
}
.formFieldError ul li{
list-style-type: none
}
</style>
</head>
<body>
<ol>
<li>
<s:form >
<div class="formFieldError">
<s:fielderror />
</div>
<s:textfield name='aaa'></s:textfield>
</s:form>
</li>
</ol>
</body>
</html>
(3).在struts.xml文件中指定
<struts>
<constant name="struts.ui.theme" value="simple" />
<package name="theme" extends="struts-default">
<action name="theme" class="com.bjsxt.struts2.theme.ThemeAction">
<result>/theme.jsp</result>
</action>
</package>
</struts>
(4).指定自己的css
<struts>
<constant name="struts.ui.theme" value="mytheme" />
<package name="theme" extends="struts-default">
<action name="theme" class="com.bjsxt.struts2.theme.ThemeAction">
<result>/theme.jsp</result>
</action>
</package>
</struts>