Struts2笔记二之struts.xml
1、struts.xml中的package:
它就像java中的package一样,起打包的作用。避免重名的action起冲突,即重名的action分别放在两个package中就不会有冲突。
例如前台package有一个名为login的action后台也有一个名为login的action。还有一点就是,可以定义一个公共的package,里面定
义一些公共配置,之后的package继承这个package就不用重复定义那些配置了。它有三个属性name,namespace,extends。
name:必填属性,用来指定包的名字。
extends:可选属性,用来指定该包继承其他包。继承其它包,可以继承其它包中的Action定义、拦截器定义等。
namespace:可选属性,用来指定该包的命名空间。
2、struts.xml中的namespace:
namespace决定了action的访问路径,默认为"",可以接受所有路径的action,如果要访问index.action对应的路径可以为:
/index.action,/xxx/index.action,/xxx/yyy/index.action。即所有包含index.action的都可以。但是这样没有严格地规范毕竟不好
有时还会出错,所以定义namespace有必要。namespace可以写为"/","/xxx"或者"/xxx/yyy",对应的action访问路径为/index.action,
/xxx/index.action,/xxx/yyy/index.action。namespace最好用模块来进行命名。
3、struts.xml中的extends(继承):
继承一个已经定义好了的package,与java中的extends一样的含义。所有的package都需要继承"struts-default"
4、struts.xml中的result:
指定请求访问结束后的跳转路径可以为jsp等页面,也可以是另一个action,result的属性有name和type,name默认为success,
type在需要用时在指定。如:<result>/hello.jsp</result>。
5、struts.xml中的include:
在struts.xml中加入<include file="文件路径">,可以包含自定义的struts.xml,常用与多人开发中,每个人各自管理自己的
struts.xml,名字自取,然后上述请求就会被StrutsPrepareAndExecuteFilter接收到。包含在总的struts.xml中就行了。
6、struts.xml中的constant:
Struts2框架有两个核心配置文件,其中struts.xml文件主要负责管理应用中的Action映射, 及Action处理结果和物理资源之间的
映射关系。除此之外,Struts2框架还包含了一个struts.properties文件,该文件主义了Struts2框架的大量常量属性。但通常推荐也是在
struts.xml文件中来配置这些常量属性。如: <constant name="struts.custom.i18n.resources" value="messages"/>
7、Action三种写法:
1.不写Action类<action name="HelloWorld"><result>/hello.jsp</result></action>
2.自定义的Action类实现Action接口:HelloWorldAction implements Action
3.自定义的Action类继承ActionSupport类:HelloWorldAction extends ActionSupport
主要使用的还是第三种,ActionSupport还提供了一系列的封装好了的方法。如果在action中指定了类,却不指定方法,则默认执行的是execute
方法。方法名字可以自定义,只需要在action中配置method="方法名"就可以了。如果action不给其配置class,则Struts会执行默认的class-->:
ActionSupport这个class实现了Action接口,而Action接口中配置了几个常量:SUCCESS = "success"; NONE = "none"; ERROR = "error";
INPUT = "input"; LOGIN = "login";
8、Struts2很麻烦的一个问题就是Path路径问题。下面这个action配置:
<package name="path" extends="struts-default" namespace="/path">
<action name="path" class="com.edifier.struts2.path.action.PathAction">
<result name="path">/path.jsp</result>
</action>
</package>
我的tomcat端口号是8081,项目名称是Struts2Demo。我要通过path这个action访问path.jsp那么访问请求需要写成:
localhost:8081/Struts2Demo/path/path.jsp,之后在进入path.jsp页面以后,我想访问WebRoot根路径下的index.jsp时就要很讲究了:
因为之前的访问中有namespace。在path.jsp中有一个链接为<a href="index.jsp">index</a>,path.jsp与index.jsp位于同一级目录,
点击此链接会出现404的错误,因为访问请求为:localhost:8081/Struts2Demo/path/index.jsp了。如果写成../index.jsp,确实可以访问到
localhost:8081/Struts2Demo/index.jsp,但是如果path这个namespace变成/path1/path2那么这里又会出现404的错误所以这个方法还是不可取。
如果写成/index.jsp表示访问根目录,问题又来了,这次访问的是localhost:8081/index.jsp,这也不是我们要访问的页面。
解决办法是使用绝对路径,在jsp页面中插入:
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
request.getScheme() 对应http
request.getServerName() 对应localhost
request.getServerPort() 对应 8081端口
path 对应项目名称
这样basePath就等价于localhost:8081/Struts2Demo/,之后的路径就看我们怎么写了,这里访问index.jsp写的方法是:<%= basePath%>index.jsp。
另外一个办法就是在<head>里面加入<base href="<%=basePath%>" />, 它的意思是默认在当前页面所有连接的前面加上<%= basePath%>,
这样我们再访问index.jsp页面直接写index.jsp就可以了。
9、Struts中的动态方法调用(DMI)
<package name="user" extends="struts-default" namespace="/user">
<action name="userAdd" class="com.edifier.struts2.user.action.UserAction" method="add">
<result name="add">/user_add_success.jsp</result>
</action>
<action name="userDelete" class="com.edifier.struts2.user.action.UserAction" method="delete">
<result name="delete">/user_delete_success.jsp</result>
</action>
<action name="user" class="com.edifier.struts2.user.action.UserAction">
<result name="add">/user_add_success.jsp</result>
<result name="delete">/user_delete_success.jsp</result>
</action>
</package>
在正常访问中,我们想访问userAdd这个action,访问的请求为localhost:8081/Struts2Demo/user/userAdd,如果我还想访问userDelete这个action,
访问的请求为localhost:8081/Struts2Demo/user/userDelete,但是这样就需要写连个action了。但是动态方法调用可以帮助我们减少action的数量,一个
action配一个就可以了方法为在action中配置name和class,但是不指定method,在页面访问的时候动态指定方法具体为:
localhost:8081/Struts2Demo/user/user!add,这个访问name=user的action中的add这个方法,
localhost:8081/Struts2Demo/user/user!delete,这个访问name=user的action中的delete这个方法,
这就是动态方法调用(DMI)。
10、Struts通配符:
<package name="actions" extends="struts-default" namespace="/actions">
<action name="Student*" class="com.edifier.struts2.action.StudentAction" method="{1}">
<result>/Student{1}_success.jsp</result>
</action>
<action name="*_*" class="com.edifier.struts2.action.{1}Action" method="{2}">
<result>/{1}_{2}_success.jsp</result>
<!-- {0}_success.jsp -->
</action>
</package>
public class StudentAction extends ActionSupport {
public String add() {
return SUCCESS;
}
public String delete() {
return SUCCESS;
}
}
public class TeacherAction extends ActionSupport {
public String add() {
return SUCCESS;
}
public String delete() {
return SUCCESS;
}
}
这里我要访问StudentAction类中的add方法,请求是这样的localhost:8081/Struts2Demo/actions/Studentadd,Student后面的add匹配
action中Student后面的*,并且Struts给其编号为{1},于是这里的*就是{1}等于add.而这个{1}可以用在后面的method、result中。如果访问delete
方法请求就是请求是这样的localhost:8081/Struts2Demo/actions/Studentdelete,这里如果有2个*这就会有{1}和{2}对应每一个*,以此类推。
在TeacherAction中就可以看出他的用法,但是*与*之间特殊符号隔开。
11、Struts中参数的传递。
方法一:请求为localhost:8081/Struts2Demo/actions/Studentadd?name="Edifier"&age=24,这里向Action类中传递了两个参数name和age。
要想在Action中接收到这两个参数,除了用request以外,还可以在Action类中定义这两个参数的属性,private String name;private int age;同时配上
set方法。因为Struts就是用set将页面传递的参数赋值到Action类中对应的参数上的。
方法二:我们将接收到的参数直接赋值给对象如将页面传递的name和age直接赋值给user对象上,这里请求就需要这样写了(user.name用到了ognl表达式):
localhost:8081/Struts2Demo/actions/Useradd?user.name="Edifier"&user.age=24,在Action类中我们只需要定义这个User类的属性
private User user;然后配上public void setUser(User user){this.user = user}就可以了。
方法三:让Action类实现ModelDriven<对象类>。这里对象类用User写法如下:
public class UserAction extends ActionSupport implements ModelDriven<User>{
private User user = new User();
public String add() {
System.out.println("name=" + user.getName());
System.out.println("age=" + user.getAge());
return SUCCESS;
}
@Override
public User getModel() {
return user;
}
}
通过getModel方法获取封装了name和age的user对象。而user也不需要set方法了。而页面上请求的访问要写成:
localhost:8081/Struts2Demo/actions/Useradd?name=a&age=8
12、Struts中编码问题
第一要保证tomcat编码为UTF-8,页面编码也为UTF-8,之后就是可以在struts.xml中配置 <constant name="struts.i18n.encoding" value="UTF-8" />,
如果还不行,可以在web.xml中,在struts的filter之前加一个中文编码的filter,如果不加filter,那就只能在Action类中中自己转码了。
13、struts的数据校验
使用struts标签进行错误信息传递,在页面上要使用struts标签需要引入:<%@taglib uri="/struts-tags" prefix="s" %>,这样就可以了。
在Action类中传递信息的写法如下:
this.addFieldError("name", "name is error");
this.addFieldError("name", "name is too long");
信息校验页面接收信息的写法如下:
<!-- 这里的fieldName中的"name"对应this.addFieldError("name", "name is error");中的"name"
下面这种下发页面显示的效果为<ul class="errorMessage"><li><span>name is error</span></li>
</ul>这样用户体验不好-->
<s:fielderror fieldName="name" theme="simple"/><br />
<!-- 下面是另外一种获取后台传递的错误信息显示的效果就是一个字符串,我们可以自定义显示效果,errors取出来的对
象是一个Map,但是去的name确实一个数组,我们在后台添加5条信息就是大小为5的数组 -->
<!-- 我们在后台是将name is error加入到fielderror中去的,struts还有一种error是actionerror.
但是最后这两个error都会加入到errors中去,所以我们既可以在fielderror中取得name is error也可以
在errors中取得-->
<s:property value="errors.name[0]"/><!-- 显示的结果为:name is error -->
<s:property value="errors.name[1]"/><!-- 显示的结果为:name is too long -->
<!-- 在页面上显示的是一个Debug按钮,点击以后可以查看一些debug信息 -->
<s:debug></s:debug>
14、Struts2中request、session、application、HttpServletRequest、HttpSession、ServletContext的取法。
a).首先是request、session、application这三个的第一种取法,他们取的类型都是Map类型
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;
}
}
前台取:
<!-- struts标签取得方式 --> <!-- 最原始的取得方式 -->
<s:property value="#request.r1"/> | <%=request.getAttribute("r1") %> <br />
<s:property value="#session.s1"/> | <%=session.getAttribute("s1") %> <br />
<s:property value="#application.a1"/> | <%=application.getAttribute("a1") %> <br />
b).首先是request、session、application这三个的第二种取法,他们取的类型都是Map类型,分别需要实现RequestAware,SessionAware,
ApplicationAware接口这种方式是最常用的。request、session、application这三个,在struts中常用的就session对象,其他两个用的都很少。
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;
}
}
c).HttpServletRequest、HttpSession、ServletContext这三个的第一种取法,
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;
}
}
d).HttpServletRequest、HttpSession、ServletContext这三个的第二种取法,他们取的类型都是真实类型,需要实现ServletRequestAware接口
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();
}
}
如果在请求一个没有定义过的Action资源时,系统就会抛出404错误。这种错误不可避免,但这样的页面并不友好。我们可以使用
<default-action-ref>来指定一个默认的Action,如果系统没有找到指定的Action,就会指定来调用这个默认的Action。
<package name="default" namespace="/" extends="struts-default">
<!-- 设置访问改namespace下的默认action,即当请求中只有namespace而没有action时或者找不到对应的action时,
就会跳到这个默认的action.用处,当别人随意的输入网址,我们可以设置默认的跳到首页,或者登陆页面。-->
<default-action-ref name="index"></default-action-ref>
<action name="index">
<result>/default.jsp</result>
</action>
</package>
当我们在配置Action的时候,如果没有为某个Action指定具体的class值时,系统将自动引用<default-class-ref>标签中所指定的类。在Struts2框架中,
系统默认的class为ActionSupport,该配置我们可以在xwork的核心包下的xwork-default.xml文件中找到。有特殊需要时,可以手动指定默认的class。
<package name="default" extends="struts-default">
<!--指定默认class为DefaultClassRef-->
<default-class-ref class="com.edifier.action.DefaultClassRef"/>
<action name="test1">
<result>/index.jsp</result>
</action>
</package>
这两个标签都是用来配置发生异常时对应的视图信息的,只不过一个是Action范围的,一个是包范围的,当同一类型异常在两个范围都被配置时,Action范围的优先级要高于包范
围的优先级.这两个标签包含的属性也是一样的:
属性名称 | 是否必须 | 功能描述 |
name | 否 | 用来表示该异常配置信息 |
result | 是 | 指定发生异常时显示的视图信息,这里要配置为逻辑视图 |
exception | 是 | 指定异常类型 |
<package name="default" extends="struts-default">
<global-exception-mappings>
<exception-mapping result="逻辑视图" exception="异常类型"/>
</global-exception-mappings>
<action name="Action名称">
<exception-mapping result="逻辑视图" exception="异常类型"/>
</action>
</package>
18、struts.xml中的<global-results>
该标签用于设置包范围内的全局结果集。在多个Action返回相同逻辑视图的情况下,可以通过<global-results>标签统一配置这些物理视图所对应的逻辑视图。
<package name="error" extends="struts-default">
<global-results>
<result name="error">/error.jsp</result>
</global-results>
</package>
Struts的Action总结
1. 实现一个Action的最常用方式:从ActionSupport继承
2. DMI动态方法调用:"!"
3. 通配符配置*{1}{2}... *_*
4. 接收参数的方法(一般用属性或者DomainModel来接收)
5. 简单参数验证addFieldError
a) 一般不使用Struts2的UI标签
6. 访问web元素request,session、application
a) Map类型
1). IOC注入 (这是最常用的)
2). 依赖Struts2
b) 原始类型
1). IOC注入
2). 依赖Struts2
7. 包含文件配置
8. 默认action处理