文档章节

Struts2个人小结(主要依据传智播客的视频)

木子丰
 木子丰
发布于 2013/10/09 08:57
字数 12972
阅读 234
收藏 5
【Struts2是在WebWork2基础上发展而来的。和Struts1一样,也属于MVC框架。】

【搭建Struts2环境】
1、导入相关jar包
    struts2-core-2.x.x.jar:Struts2框架的核心类库
    xwork-2.x.x.jar:Xwork类库,Struts2在其基础上构建
    ongl-2.6.x.jar:对象图导航语言(Object Graph Navigation Language),Struts2框架通过其读写对象的属性
    freemarker-2.3.x.jar:Struts2的UI标签的模板使用FreeMarker编写
    commons-logging-1.1.x.jar:ASF出口的日志包,Struts2使用这个日志来支持Log4J和JDK1.4+的日志记录
    commons-fileupload-1.2.1.jar:文件上传组件,Struts2.1.6版本后必须加入此文件
2、编写Struts2的配置文件
    Struts2默认的配置文件是struts.xml,该文件需要存放在WEB-INF/classes下(开发时放在src目录下即可,因为src目录下的文件在项目部署时,java文件会被自动编译成字节码文件并放到WEB-INF/classes下,而其它如xml、properties配置文件会原样放到WEB-INF/classes下),该文件的配置模板如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
</struts>
3、在web.xml文件中加入Struts2 MVC框架启动配置。
    在Struts1中框架是通过Servlet启动的,在Struts2中是通过Filter启动的,在web.xml文件中的配置如下:
<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>
     【注】
     Struts2.1.3之前的版本中用的filter-class为:
<filter-class>
    org.apache.struts2.dispatcher.FilterDispatcher
</filter-class>
在StrutsPrepareAndExecuteFilter的init()方法中将会读取类路径下默认的配置文件struts.xml完成初始化操作。
struts2读取到struts.xml文件后,以javabean形式存放在内存中,以后struts2对用户的每次请求处理都将使用内存中的数据,而不是每次都读取struts.xml文件。

【struts.xml配置中包的介绍】
<package name="itcast" namespace="/test" extends="struts-default">
    <action name="helloworld" class="cn.itcast.action.HelloWorldAction" method="execute">
        <result name="success">/WEB-INF/page/hello.jsp</result>
    </action>
</package>
Struts2框架中通过包来管理一组业务功能相关的Action,可配置多个包。
【name】:可以任意取名,但要唯一,不同于java的类包,如果其它包要继承该,可以通过该属性进行引用
【namespace】:定义包的命名空间,是该包下Action的路径的一部分,如上面例子的Action的访问路径是:/test/helloworld.action。该属性也可不配置,这样就是默认的命名空间""(空字符串)
【extends】:包之间的继承;通常每个包都应该继承【struts-default】包,这样才能使用Struts2提供的核心功能。struts-default包是在struts2-core-2.x.x.jar文件中的struts-default.xml中定义。struts-default.xml也是Struts2的默认配置文件,每次启动都会自动加载该文件。
【abstract】:包还可以通过abstract="true"定义为抽象包,抽象包中不能包含action,而只能被其它包继承。
【action】:【name】是请求名称的一部分,请求由【class】指定的action类中的【method】指定的方向来处理。
【result】:【name】视图名称,标签之间内容为视图路径。
【注】在视图页面可直接通过EL表达式取出Action类中的属性
如:HelloWorldAction类中
package cn.itcast.action;

public class HelloWorldAction {
    private String message;
    
    public String execute() {
        message = "我的第一个Struts2应用";
        return "success";
    }

    public String getMessage() {
        return message;
    }
}
在视图页面就可以通过${message}来取出相应的值,前提Action中必须有getMessage()方法,与成员变量名称无关。成员变量也可以是private String msg;所以EL表达式取值时所用的名称是getter方法后面的首字母小写的名称(一般是这样,有特殊的)。

【struts.xml文件不提示的问题】
如果快捷键设置没问题且无冲突,那就是因为配置文件没有对应的DTD(Document Type Definition)约束文档
解决方法:【Window】——【Preferences】——【MyEclipse Enterprise Workbench】——【Files and Editors】——【XML】——【XML Catalog】点击【Add】:通过【Location】指定DTD文档,【Key Type】选URI,【Key】写http://struts.apache.org/dtds/struts-2.3.dtd

【Action名称的搜索】
例如url是:http://server/struts2/path1/path2/path3/test.action
寻找namespace为"/path1/path2/path3"的package,如果不存在则寻找namespace为"/path1/path2"的package,如果还不存在则寻找namespace为"/path1"的package,如果还不存在则寻找namespace为"/"的package,如果还不存在则寻找namespace为""的package……这样逐级向上查询,如果一直找不到则页面提示找不到action;
当然如果中间找到相应的package,则会在相应的package下寻找test的action,如果在相应的package中找不到则会去默认包(namespace为""或不指定namespace的package)中寻找,如果一直找不到则页面提示找不到action

【请求直接转向页面时,不用指定class、method】
<action name="addUI">
    <result>/WEB-INF/page/employee.jsp</result>
</action>
【Action类的编写】
有3种:
1、有public String execute()方法的任意Java类
2、实现Action接口,并实现public String execute()方法
3、继承ActionSupport类,并重写public String execute()方法
常用第3种,其实ActionSupport类就是Action的实现类,而且里面封装了许多有用的方法。

【Action配置中的各项默认值】
<package name="itcast" namespace="/test" extends="struts-default">
    <action name="helloworld" class="cn.itcast.action.HelloWorldAction" method="execute">
        <result name="success">/WEB-INF/page/hello.jsp</result>
    </action>
</package>
1、如果没有为acion指定class,默认是 ActionSupport
2、如果没有为acion指定method,默认执行action中的 execute()方法
3、如果没有指定result的name属性,默认值为 success

【默认action配置】
当我们请求一个项目,而不指定具体的action名称时,会由defautl-action来处理
<default-action-ref name="login" />
该标签放在<package>标签对中

【Action异常处理】
通过
<exception-mapping result="error" exception="java.sql.SQLException" />
配置来处理
result:出现异常时转向的视图
exception:所要针对处理的异常类的全名
<package name="itcast" namespace="/test" extends="struts-default">
    <action name="helloworld" class="cn.itcast.action.HelloWorldAction" method="execute">
        <result name="success">/WEB-INF/page/hello.jsp</result>
        <exception-mapping result="error" exception="java.sql.SQLException" />
        <result name="error">/error.jsp</result>
    </action>
</package>
当然也可以配置成全局的异常处理(与配置全局的视图方法一样。)
【Action中result的各种转发类型】
result标签有一个type属性,表示视图转发类型:一般有:dispatcher、chain、redirect、redirectAction、plainText
dispatcher:
    转发【默认值】,只能转发到jsm或html页面,不能转发到一个action
chain:
    转发到一个action
redirect:
    重定向到jsp或html页面,重定向的视图不能在WEB-INF路径下。
    视图url后可通过ongl表达式获取action类的属性,如:
<action name="list" class="cn.itcast.action.HelloWorldAction" method="execute">
    <result name="success" type="redirect">
        /employeeAdd.jsp?username=${username}
    </result>
</action>
    HelloWorldAction类中必须对应的username字段和getUsername(),这样在employeeAdd.jsp页面即可通过EL表达式${param.username}来获取传递过来的值
    当参数是中文时,需要在HelloWorldAction类中对其进行编码:
    username = URLEncoder.encode("中国", "utf-8");
    在视图页面通过
<%
    String name = request.getParameter("username");
    name = new String(name.getBytes("iso-8859-1"),"utf-8");
    name = URLDecoder.decode(name,"utf-8");
%>
<%=name%>
redirectAction:
    重定向到某个action
    result标签对中间的内容为所要重定向到的action标签的name属性值,如:
    <action name="list" class="cn.itcast.action.HelloWorldAction" method="execute">
        <result name="success" type="redirect">
            /employeeAdd.jsp?username=${username}
        </result>
    </action>
    <action name="redirectActionDemo">
        <result type="redirectAction">
            list
        </result>
    </action>
    当用户请求redirectActionDemo.action时会重定向到name属性为list的action,由其进行处理。

    当要重定向的action不在当前包中时的配置如下:
    <action name="redirectActionDemo">
        <result type="redirectAction">
            <param name="namespace">所要重定向的action所在包的namespace属性值</param>
            <param name="actionName">所要重定向的action的name属性值</param>
        </result>
    </action>
plainText:
    原样输出视图页面的代码,当我们想要显示jsp文件源代码时,可以用此类型。
    <action name="plainText">
        <result type="plainText">
            /index.jsp
        </result>
    </action>
    当视图页面有中文要显示时,需要在配置文件中注入location、charSet参数:
    <action name="plainText">
        <result type="plainText">
            <param name="location">/index.jsp</param>
            <param name="charSet">utf-8</param>
        </result>
    </action>

【全局视图的配置】
<global-results>
    <result name="message">/WEB-INF/page/message.jsp</result>
</global-results>
【注】该标签要放在packge标签对之间,且在action标签之前
转向全局视图的action中不需要再指定result
<action name="manage" class="cn.itcast.action.HelloWorldAction" method="add">
</action>
add方法返回到视图message
【这种配置中是实现了在某个包中的全局视图,如何实现在整个应用中的全局视图?】
可以单独定义一个包base存放全局视图,继承struts-default,再让其它包都继承base,如:
<package name="base" extends="struts-default">
    <global-results>
        <result name="message">/WEB-INF/page/message.jsp</result>
    </global-results>
</package>
<package name="itcast" extends="base">
    ......
</package>

【${}动态视图、url带参数视图】
视图指向页面由Action的属性值动态指定,如:
==============================================================================================
<action name="user" class="com.bjsxt.struts2.user.action.UserAction">
    <result>${r}</result>
</action>
==============================================================================================
${r}是从ValueStack中取出r对应的值
请求一个Action时,Struts2会自动创建对象并封装数据,并将该对象放入ValueStack中
UserAction的代码:
public class UserAction extends ActionSupport {
    private int type;
    private String r;
    //此处省去2个字段的getter,setter方法
    public String execute() {
        if (type==1) r = "/user_success.jsp";
        if (type==2) r = "/user_error.jsp";
        return "success";
    }
}
==============================================================================================
基于上面的思想,可以设置带有参数的视图,当然参数也是从ValueStack中的对象中取出
<action name="user" class="com.bjsxt.struts2.user.action.UserAction">
    <result>/user_success.jsp?type=${type}</result>
</action>
这样,我们在请求这个Action的时候得给它传递过去type值,或由Action经过一些逻辑判断自动生成值

另:一次请求涉及到的所有Action共用一个ValueStack
所以当一个Action_A的视图forward另一个Action_B时指向的视图要用Action_A中的值时,可以直接用,
而不用我们手动将值传给Action_B

多次请求之间就需要手动传递参数了,如redirect情况下
<action name="user" class="com.bjsxt.struts2.user.action.UserAction">
    <result type="redirect">/user_success.jsp?t=${type}</result>
</action>
这里redirect的目标是一个jsp而不是Action,所以这次请求后ValueStack是空的,
我们就不能通过<s:property value="t" />来取了,需要从ActionContext中的parameters对象中取
<s:property value="#parameters.t" />
==============================================================================================

【为Action的属性注入值】
在action标签对之间加入param标签,如下:
<param name="savepath">...value...</param>
name属性值是action类中的属性,必须有对应的setter方法,这样就可以给该属性指定值,而且也可以在其转发的页面中通过EL表达式${savepath}取出该值。
一些灵活变化的值可以通过该方法在配置文件中动态指定。

【指定需要Struts2处理的请求后缀】
一般都默认使用.action的后缀访问Action。其实默认后缀可以通过常量"struts.action.extension"
我们可以配置Struts2只处理以.do为后缀的请求路径:
<constant name="struts.action.extension" value="do" />
如果需要指定多个请求后缀,多个后缀之间用英文的分号隔开。如:
<constant name="struts.action.extension" value="action,do,go" />
【注】这样指定后缀以后,必须带上所指定的后缀访问,而不指定的话,可以加上.action也可不加

【细说常量定义】
常量可以在struts.xml或struts.properties中配置,建议在struts.xml中配置;
在struts.xml中的配置:
<constant name="struts.action.extension" value="do" />
在struts.properties中的配置:
struts.action.extension=do
常量可以在下面多个配置文件中进行定义,Struts2加载常量的搜索顺序:
struts-default.xml
struts-plugin.xml
struts.xml
struts-properties
web.xml
如果在多个配置文件中配置了同一个常量,则后一个会覆盖前面文件中配置的常量。

【常用常量介绍】
internationalization即 i18n
Struts2涉及的常量名可通过org.apache.struts2.deafult.properties文件获取
指定默认编码集,作用于HttpServletRequest的setCharacterEncoding方法和freemarker、velocity的输出
<constant name="struts.i18n.encoding" value="utf-8" />
指定请求后缀,多个后缀之间用英文的分号隔开。如:
<constant name="struts.action.extension" value="action,do,go" />
设置浏览器是否缓存静态内容,默认值为true(生产环境下使用)开发阶段最好关闭
<constant name="struts.serve.static.browserCache" value="false" />
设置当struts的配置文件修改后是否重新加载该文件,默认值为false(生产环境下使用)开发阶段最好打开
<constant name="struts.configuration.xml.reload" value="true" />
开发模式下使用可以打印出更详细的错误信息
<constant name="struts.devMode" value="true" />
默认的视图主题
<constant name="struts.ui.theme" value="simple" />
与Spring集成时,指定由Spring负责action对象的创建
<constant name="struts.objectFactory" value="spring" />
设置Struts2是否支持动态方法使用,该属性的默认值是true,设置为false则关闭动态方法的使用
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
上传文件的总的大小限制
<constant name="struts.multipart.maxSize" value="10701096" />
使用OGNL表达式访问静态方法的开关,默认为false
<constant name="struts.ognl.allowStaticMethodAccess" value="true" />


【Struts2的处理流程】
用户请求
——>StrutsPrepareAndExecuteFilter
——>Interceptor(Struts2内置的一些拦截器或用户自定义拦截器)
——>Action(用户编写的Action类,类似Struts1中的Action)
——>Result(类似Struts1中的forward)
——>Jsp/Html
——>响应
StrutsPrepareAndExecuteFilter是Struts2框架的核心控制器,它负责拦截由<url-pattern>/*</url-pattern>指定的所有用户请求,当用户请求到达时,该Filter会过滤用户的请求,默认情况下,如果用户请求的路径不带后缀或者后缀以.action结尾,这时请求将被转入Struts2框架处理,否则Struts2框架将略过该请求的处理。当请求转入Struts2框架处理时会先经过一系列的拦截器,然后再到Action。
与Struts1不同,Struts2对用户的每一次请求都会创建一个Action,所以Struts2中的Action是线程安全的。

【为应用指定多个struts配置文件】
在struts.xml文件中通过include标签元素指定多个配置文件:
<struts>
    <include file="struts-user.xml" />
    <include file="struts-order.xml" />
</struts>
一般我们不在struts.xml文件中指定action,都是包含相应的xml文件(就像main方法中不写详细代码,而只调用方法)

【动态方法调用】(在2.1版本之后就不推荐使用了)
当Action中存在多个方法时,我们可以通过【!+方法名】调用指定方法。如:
所请求的action的url路径为:http://localhost:8080/struts/test/helloworld.action
该action中有execute()、other()方法
默认调用的是execute(),如果要调用other(),则通过以下url:
http://localhost:8080/struts/test/helloworld!other.
可以通过
<constant name="struts.enable.DynamicMethodInvocation" value="false" />
关闭动态方法的使用

【使用通配符定义action】
<package name="itcast" namespace="/test" extends="struts-default">
    <action name="helloworld_*" class="cn.itcast.action.HelloWorldAction" method="{1}">
        <result name="success">/WEB-INF/page/hello.jsp</result>
    </action>
</package>
[name="helloworld_*"]:下划线可以不要[name="helloworld*"],这里只是方便查看
[method="{1}"]:{1}是与前面的*匹配,*可以有多个,所以通过序号来对应,{1}可以在action标签中的任意地方使用来动态改变相应内容,如/WEB-INF/page/hello{1}.jsp
如:请求/test/helloworld_other.action时,*对应other,{1}也就相当于other
或:请求/test/helloworldother.action时,*对应other,{1}也就相当于other

【接收请求参数】
一、采用基本类型接收请求参数(get/post)
    在Acion类中定义与请求参数同名的属性,Struts2通过反射调用与请求参数同名的属性的setter方法来给相应属性赋值。get/post方式均可,所以可以直接把表单提交的数据与Action类属性对应
    如Action类中有id,name属性,则
    <form action="...">
        ID:<input type="text" name="id" />
        name:<input type="text" name="name" />
    </form>
    这样提交的数据会自动封装到Action类相应的属性中。
二、采用复杂类型接收参数
    Action类中有一复杂属性private Person person,Person类有2个属性:id,name,则:
    <form action="...">
        ID:<input type="text" name="person.id" />
        name:<input type="text" name="person.name" />
    </form>
    在视图页面取出相应的值:${person.id}  ${person.name}
    如果我们不传递任何参数,那Action中的person属性将为null,
    如果传递了,则Struts2将会自动帮我们创建person对象,并封装数据

    Action中的Person对象可以通过传递参数让Struts2帮我们创建,也可以手动new,但Person
    类中一定要有无参的构造方法。
三、ModelDriven模式
    Action类实现ModelDriven<T>接口(Person类有2个属性:id,name)
    实现getModel()方法
    public class PersonAction extends ActionSupport implements ModelDriven<Person> {
        private Person person = new Person();//这里必须手动new出对象

        public Person getModel() {
            return person;
        }
        ……
    }
    <form action="...">
        ID:<input type="text" name="id" />
        name:<input type="text" name="name" />
    </form>
    这时,用这种简单的表单就能实现参数的接收。
    原理:请求该Action时,会调用getModel方法获取person对象,往person中封装相应数据

【中文乱码问题】
首先:在struts.xml文件中添加:
<constant name="struts.i18n.encoding" value="utf-8" />
get方式传递的中文数据,需要在Action类中进行编码:
URLEncoder.encode(name,"utf-8");
在视图端再解码:
URLDecoder.decode(request.getParameter("name"),"utf-8");

【自定义类型转换器】
继承DefaultTypeConverter(最好选com.opensymphony.xwork2.conversion.impl)
重写public Object convertValue(Map<String, Object> context, Object value, Class toType)

public class DateTypeConverter extends DefaultTypeConverter {

    @Override
    public Object convertValue(Map<String, Object> context, Object value,
            Class toType) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        try {
            if (toType == Date.class) {//字符串向Date类型转换
                String[] params = (String[]) value;
                return dateFormat.parse(params[0]);
            } else if (toType == String.class) {//Date向字符串类型转换
                Date date = (Date) value;
                return dateFormat.format(date);
            }
        } catch (ParseException e) {
        }
        return null;
    }
}
或继承StrutsTypeConverter(该类是DefaultTypeConverter的子类)
重写public Object convertFromString(Map context, String[] values, Class toType)
重写public Object convertToString(Map context, Object o)

一、局部
    在Action类所在包下放置ActionClassName-conversion.properties文件,
    ActionClassName是Action的类名,后面的-conversion.properties是固定写法,
    以HelloWorldAction为例,
    在HelloWorldAction包下放置HelloWorldAction-conversion.properties文件,内容为:
    birthday=cn.itcast.type.converter.DateTypeConverter
    左边是要转换的类的属性,右边是转换器的完整路径名
二、全局
    在WEB-INF/classes下(即src目录下)放置xwork-conversion.properties文件。内容:
    java.util.Date=cn.itcast.type.converter.DateTypeConverter
    左边是待转换的数据类型,右边是转换器的完整路径名

【获取Map类型的request/session/application属性】
方法一:通过ActionContext获取
public class HelloWorldAction {
    public String execute() {
        ActionContext ctx = ActionContext.getContext();
        Map<String, Object> application = ctx.getApplication();
        Map<String, Object> session = ctx.getSession();
        Map<String, Object> request = ctx.get("request");

        application.put("application","应用范围");
        session.put("session","session范围");
        request.put("request","request范围");
        return "message";
    }
}
在JSP页面就可以通过EL表达式获取相应作用域中的属性
${applicationScope.application}
${sessionScope.session}
${requestScope.request}
或通过
<s:property value="#application.application" />
<s:property value="#session.session" />
<s:property value="#request.request" />

方法二:(最常用的方法,最常用的是session)
DI(dependency injection)依赖注入 IoC(Inverse of Control)控制反转
实现指定接口,由struts框架运行时加入
public class HelloWorldAction implements RequestAware,SessionAware,ApplicationAware {
    private Map<String, Object> request;
    private Map<String, Object> session;
    private Map<String, Object> application;
    
    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;
    }
}

【获取HttpServleRequest、HttpSession、ServletContext、HttpServletResponse对象】
方法一:通过ServletActionContext类直接获取
public String rsa() throws Exception {
    HttpServletRequest request = ServletActionContext.getRequest();
    ServletContext sc = ServletActionContext.getServletContext();
    HttpSession session = request.getSession();
    HttpServletResponse response = ServletActionContext.getResponse();
    return "scope";
}
方法二:实现指定接口,由struts框架运行时加入
public class HelloWorldAction implements ServletRequestAware,ServletResponseAware,ServletContextAware {
    private HttpServletRequest request;
    private HttpServletResponse response;
    private ServletContext servletContext;
    //或只实现ServletRequestAware,由request对象再获取session,application
    //request.getSession();request.getServletContext();
    public void setServletRequest(HttpServletRequest request) {
        this.request = req;
    }

    public void setServletResponse(HttpServletResponse response) {
        this.response = res;
    }

    public void setServletContext(ServletContext servletContext) {
        this.servletContext = servletContext;
    }
}

【文件上传】
1、需要的jar包:commons-fileupload-1.2.1.jar、commons-io.1.3.2.jar
2、设置form表单的 enctype="multipart/form-data",如:
    <form enctype="multipart/form-data" action="${pageContext.request.contextPath}/xxx.action" method="post">
        <input type="file" name="uploadImage" />
    </form>
3、在对应的Action类中添加上传文件所对应的属性:示例:
public class HelloWorldAction {
    private File uploadImage;
    private String uploadImageContentType;
    private String uploadImageFileName;

    public String upload() throws Exception {
        String realpath = ServletActionContext.getServletContext().getRealPath("/images");
        File file = new File(realpath);
        if (uploadImage != null) {
            if (!file.exists()) {
                file.mkdirs();
            }
            FileUtils.copyFile(uploadImage,new File(file, uploadImageFileName));
            return "success";
        }
        return "failure";
    }
}
注意:1、表单中文件域的名称要和Action类中的属性名一致;
      2、Action中还要有文件的另外2个属性:类型、文件名,都是固定格式;类型:在属性名后加ContentType;文件名:在属性名后加FileName。
这里:表单中文件域的名称和Action类中的属性名为uploadImage,
Action类中的类型名为:uploadImageContentType、文件名为uploadImageFileName。
上传文件的总的大小限制的常量配置
<constant name="struts.multipart.maxSize" value="10701096" />

【多文件上传】
与单文件上传不同的是,在Action类中将文件属性定义为数组类型或List类型
public class HelloWorldAction {
    private File[] uploadImages;
    private String[] uploadImagesContentType;
    private String[] uploadImagesFileName;

    public String upload() throws Exception {
        String realpath = ServletActionContext.getServletContext().getRealPath("/images");
        File file = new File(realpath);
        if (uploadImages != null) {
            if (!file.exists()) {
                file.mkdirs();
            }
            for (int i=0; i<uploadImages.length; i++) {
                File uploadImage = uploadImages[i];
                FileUtils.copyFile(uploadImage,new File(file, uploadImagesFileName[i]));
                return "success";
            }
        }
        return "failure";
    }
}

【自定义拦截器】
要实现com.opensymphony.xwork2.interceptor.Interceptor接口。
并实现其中的3个方法:
public void destroy();
public void init();
public String interceptor(ActionInvocation invocation) throws Exception;
最主要的就是interceptor方法,这是对访问Action类中的方法的拦截
通过invocation.invoke()方法,可以使被拦截的方法正常执行,所以可以通过一些逻辑判断和条件限制,来对访问进行过滤拦截
代码示例:
import com.opensymphony.xwork2.interceptor.Interceptor;

public calss PermissionInterceptor implements Interceptor {
    public void destroy() {}
    public void init() {}
    public String interceptor(ActionInvocation invocation) throws Exception {
        ActionContext context = ActionContext.getContext();
        Object obj = context.getSession().get("user");
        if (user != null) {//如果用户登录了,就不对其请求进行拦截
            return invocation.invoke();//让所要处理请求的方法正常执行,且会返回到相应的视图
        } else {
            context.put("message", "你没有权限执行该操作!");//往request作用域中放置参数
            return "message";//返回出错的message视图。
        }
    }
}

【自定义拦截器注册信息的配置】
Action类使用了自定义的拦截器以后,就会失去Struts2核心的拦截器功能,所以配置信息的时候,应该配置一个拦截器堆,将Struts2核心的拦截器功能添加进去。Struts2的默认核心拦截器堆:defaultStack
配置时defaultStack应该在拦截堆中的第一个位置。

配置示例:
==============================================================================================
<package name="itcast" namespace="/control/employee" extends="struts-default">
    <interceptors>
        <interceptor name="permission"
            class="cn.itcast.interceptor.PermissionInterceptor">
        </interceptor>
        <interceptor-stack name="permissionStack">
            <interceptor-ref name="defaultStack"></interceptor-ref>
            <interceptor-ref name="permission"></interceptor-ref>
        </interceptor-stack>
    </interceptors>
        
    <action name="list*" class="cn.itcast.action.HelloWorldAction" method="{1}">
        <param name="savepath">/images</param>
        <result name="success">/WEB-INF/page/hello.jsp</result>
        <interceptor-ref name="permissionStack"></interceptor-ref>
    </action>
</package>
==============================================================================================
<interceptors>
    <interceptor name="permission"
        class="cn.itcast.interceptor.PermissionInterceptor">
    </interceptor>
    <interceptor-stack name="permissionStack">
        <interceptor-ref name="defaultStack"></interceptor-ref>
        <interceptor-ref name="permission"></interceptor-ref>
    </interceptor-stack>
</interceptors>
拦截器注册信息都写在interceptors标签对之间;下面还有两个标签对:
interceptor标签对:注册自定义的标签,name属性对应一个自定义名称,class属性对应其java类(带包名)
interceptor-stack标签对:拦截器堆,能定义多个拦截器,Action类可以关联拦截器堆,而使其中的每个
拦截器都作用于该Action类;
    其下面是interceptor-ref标签对:通过name属性与默认的、自定义的拦截器(堆)关联。
==============================================================================================
<action name="list*" class="cn.itcast.action.HelloWorldAction" method="{1}">
    <param name="savepath">/images</param>
    <result name="success">/WEB-INF/page/hello.jsp</result>
    <interceptor-ref name="permissionStack"></interceptor-ref>
</action>
拦截器注册好后,要在使用拦截器的Action中进行配置关联,通过interceptor-ref标签对进行关联
其name属性,应该是注册好的拦截器(堆)的name属性值。
==============================================================================================
如果希望包下的所有Action都使用自定义的拦截器,可以通过
<default-interceptor-ref name="permissionStack" />
把拦截器定义为默认的,而不必给每一个Action中都关联拦截器;
每个包只能定义一个默认的拦截器;
当然如果为某个Action专门指定了拦截器,那默认的拦截器将对其失效。
配置示例:
<package name="itcast" namespace="/control/employee" extends="struts-default">
    <interceptors>
        <interceptor name="permission"
            class="cn.itcast.interceptor.PermissionInterceptor">
        </interceptor>
        <interceptor-stack name="permissionStack">
            <interceptor-ref name="defaultStack"></interceptor-ref>
            <interceptor-ref name="permission"></interceptor-ref>
        </interceptor-stack>
    </interceptors>
    <default-interceptor-ref name="permissionStack" />
    <action name="list*" class="cn.itcast.action.HelloWorldAction" method="{1}">
        <param name="savepath">/images</param>
        <result name="success">/WEB-INF/page/hello.jsp</result>
    </action>
</package>
若要为某个Action额外增加拦截器,而又不想失去默认拦截器的功能:
可以把默认的拦截器在Action中再指定一次,之后再增加额外的拦截器。
==============================================================================================


【输入校验】
可以对Action的所有方法或指定方法进行校验。
有2种方法:
    1、手工编写代码实现
    2、基于XML配置文件实现

【手工编写代码对所有方法进行输入校验】
一、继承ActionSupport类并重写其public void validate()方法,
    该方法会校验Action中所有与execute方法签名相同的方法,当某个数据校验失败时,
    我们应该调用addFieldError(String fieldName, String errorMessage)方法
    往系统的fieldError添加校验失败信息。
二、为Action配置一个input视图返回原页面
    如果系统的fieldError包含失败信息,Struts2会将请求转发到名为input的result。
三、在result视图中可以通过<s:fielderror />显示失败信息。
    在JSP页面中引入相应的标签库:    <%@ taglib uri="/struts-tags" prefix="s"%>
    并在form表单前面使用:        <s:fielderror />
    【<s:fielderror>标签】
    <s:fielderror />会自动以列表形式把通过addFieldError方法加入的错误信息输出到页面上,不好
    的是,输出的时候已经指定了CSS样式,不便于页面样式的操作。
    <s:fielderror fieldName="fieldName" />也可只输出指定的字段的错误信息。
    可通过<s:property value="errors.fieldName[index]">取出指定的不带CSS的错误信息文本
    其中,errors.fielaName[index]是OGNL表达式
    errors是值栈ValueStack中的对象名,可通过它获取其值,它的值是以Map<fieldName,array>形式存放
    fieldName是通过addFieldError方法添加错误信息时指定的出错的fieldName。
    index是保存错误信息的数组array的下标,同一个字段可添加多个错误信息
    【通过<s:debug />可查看ValueStack详情】
代码示例:PersonAction类有两个属性:username、mobile
public void validate() {
    if (this.username == null || "".equals(this.username.trim())) {
        this.addFieldError("username", "用户名不能为空");
    }
        
    if (this.mobile == null || "".equals(this.mobile.trim())) {
        this.addFieldError("mobile", "手机号不能为空");
    } else {
        if (!Pattern.compile("^1[358]\\d{9}$").matcher(this.mobile).matches()) {
            this.addFieldError("mobile", "非法的手机号");
        }
    }
}

【手工编写代码对指定方法进行输入校验】
一、继承ActionSupport类(主要是为了使用addFieldError()方法),编写public void validateXxx()方法
    validateXxx()方法只会校验Action中方法名为xxx的方法,
    如:针对add()方法,编写validateAdd()方法
    当某个数据校验失败时,我们应该调用addFieldError(String fieldName, String errorMessage)
    方法往系统的fieldError添加校验失败信息。
二、为Action配置一个input视图返回原页面
    如果系统的fieldError包含失败信息,Struts2会将请求转发到名为input的result。
三、在result视图中可以通过<s:fielderror />显示失败信息。
    在JSP页面中引入相应的标签库:    <%@ taglib uri="/struts-tags" prefix="s"%>
    并在form表单前面使用:        <s:fielderror />
    

【输入校验的流程】
1、类型转换器对请求参数执行类型转换,并把转换后的值赋给Action类中的属性;
2、如果在执行类型转换的过程中出现异常,系统会将异常信息保存到ActionContext,conversionError拦截器
将异常信息封闭到fieldError里,不管类型转换是否出现异常,都会进入第3步;
3、系统通过反射技术先调用Action中的validateXxx()方法;
4、再调用validate()方法;
5、经过上面4步,如果系统中的fieldError存在错误信息(即存放错误信息的集合的siz>0),系统自动将请求转发
至名为input的视图。如果系统中的fieldError没有任何错误信息,系统将执行Action中的处理方法。

【基于XML文件配置实现对所有方法进行输入校验】
一、Action类继承ActionSupport类
二、提供校验文件,该文件和Action类在同一个包下,命名格式:ActionClassName-validation.xml
ActionClassName是Action类的名称,以UserAction类为例:UserAction-validation.xml
==============================================================================================
配置示例:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE validators PUBLIC
        "-//Apache Struts//XWork Validator 1.0.2//EN"
        "http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
<validators>
    <field name="username">
        <field-validator type="requiredstring">
            <param name="trim">true</param>
            <message key="requiredstring">用户名不能为空</message>
        </field-validator>
    </field>

    <field name="mobile">
        <field-validator type="requiredstring">
            <message>号码不能为空</message>
        </field-validator>
        <field-validator type="regex">
            <param name="regex"><![CDATA[^1[358]\d{9}$]]></param>
            <message>手机格式不正确</message>
        </field-validator>
    </field>
</validators>
==============================================================================================
<field>指定Action中要校验的属性,<field-validator>指定校验器,上面的校验器requiredstring是由
系统提供的,系统提供了能满足大部分验证需求的校验器,这些校验器的定义可以在xwork2-2.jar中的
com.opensymphony.xwork2.validator.validators下的default.xml中找到。
<message>为校验失败后的提示信息,如果需要国际化,可以为message指定key属性,key的值为资源文件中
的key。
在这个校验文件中,对Action中字符串类型的username属性进行校验,首先用trim方法去掉空格,再判断其
是否为空(注入默认值为true)。
==============================================================================================

【系统提供的校验器】
required    (必填校验器,要求field的值不能为null)
requiredstring    (必填字符串校验器,要求field的值不能为null,并且长度大于0,默认情况下会对字符串去前后空格)
stringlength    (字符串长度校验器,要求field的值必须在指定的范围内,否则校验失败,
        minLength参数指定最小长度,
        maxLength参数指定最大长度,
        trim参数指定校验field之前是否去除字符串前后的空格)
regex        (正则表达式校验器,检查被校验的field是否匹配一个正则表达式.
        expression参数指定正则表达式
        (实际操作中通过regex参数指定正则表达式成功,expression失败),
        caseSensitive参数指定进行正则表达式匹配时,是否区分大小写,默认值为true)
int        (整数校验器,要求field的整数值必须在指定范围内,min指定最小值,max指定最大值)
double        (双精度浮点数校验器,要求field的双精度浮点数必须在指定范围内,min指定最小值,max指定最大值)
fieldexpression    (字段OGNL表达式校验器,要求field满足一个ognl表达式,expression参数指定ognl表达式,该逻辑表达式基于            ValueStack进行求值,返回true时校验通过,否则不通过)
email        (邮件地址校验器,要求如果field的值非空,则必须是合法的邮件地址)
url        (网址校验器,要求如果field的值非空,则必须是合法的url地址)
date        (日期校验器,要求field的日期值必须在指定范围内,min指定最小值,max指定最大值)
conversion    (转换校验器,指定在类型转换失败时,提示的错误信息)
visitor        (用于校验action中的复合属性,它指定一个校验文件用于校验复合属性中的属性)
expression    (OGNL表达式校验器,expression参数指定ognl表达式,该逻辑表达式基于ValueStack进行求值,返回true时校验通            过,否则不通过,该校验器不可用在字段校验器风格的配置中)

【校验器的使用例子】
required  必填校验器
<field-validator type="required">
    <message>性别不能为空!</message>
</field-validator>

requiredstring  必填字符串校验器
<field-validator type="requiredstring">
    <param name="trim">true</param>
    <message>用户名不能为空!</message>
</field-validator>

stringlength:字符串长度校验器
<field-validator type="stringlength">
    <param name="maxLength">10</param>
    <param name="minLength">2</param>
    <param name="trim">true</param>
    <message><![CDATA[产品名称应在2-10个字符之间]]></message>
</field-validator>

email:邮件地址校验器
<field-validator type="email">
    <message>电子邮件地址无效</message>
</field-validator>

regex:正则表达式校验器
<field name="mobile">
    <field-validator type="requiredstring">
        <message>号码不能为空</message>
    </field-validator>
    <field-validator type="regex">
        <param name="regex"><![CDATA[^1[358]\d{9}$]]></param>
        <message>手机格式不正确</message>
    </field-validator>
</field>

int:整数校验器
<field-validator type="int">
    <param name="min">1</param>
    <param name="max">150</param>
    <message>年龄必须在1-150之间</message>
</field-validator>

字段OGNL表达式校验器
<field name="imagefile">
    <field-validator type="fieldexpression">
        <param name="expression"><![CDATA[imagefile.length() <= 0]]></param>
        <message>文件不能为空</message>
    </field-validator>
</field>

【基于XML文件配置实现对指定方法进行输入校验】
在对所有方法进行输入校验的基础上,把校验文件的名称更改为:
ActionClassName-ActionName-validation.xml
ActionClassName还是Action类的不带包的名称
ActionName是struts.xml文件中配置的action标签的name属性值
==============================================================================================
示例:
<action name="user_*" class="cn.itcast.action.Useraction" method="{1}">
    <result name="success">/WEB-INF/page/message.jsp</result>
    <result name="input">/WEB-INF/page/addUser.jsp</result>
</action>
UserAction中有以下两个处理方法:
public String add() throws Exception {}
public String update() throws Exception {}
要对add()方法实施验证,检验文件的名称更改为:UserAction-user_add-validation.xml
要对update()方法实施验证,检验文件的名称更改为:UserAction-user_update-validation.xml
==============================================================================================

【基于XML校验的一些特点】
当为某个Action提供了ActionClassName-validation.xml、ActionClassName-ActionName-validation.xml
两种规则的校验文件时,系统会按下面顺序寻找校验文件:
ActionClassName-validation.xml
ActionClassName-ActionName-validation.xml
把所有的校验规则汇总,有冲突的以后面文件的为准

当Action继承了另一个Action,父类的校验文件会被先搜索到,接下来是子类的,把校验规则汇总。

【国际化】
国际化资源文件的命名格式:
baseName_language_country.properties
baseName_language.properties
baseName.properties
其中baseName是资源文件的基本名,我们可以自定义,但language和country必须是java支持的语言和国家。如:
中国大陆: baseName_zh_CN.properties
美国: baseName_en_US.properties

现在为应用添加两个资源文件:
第一个存放中文:itcast_zh_CN.properties
内容为:welcome=欢迎来到传智播客
第二个存放英语(美国): itcast_en_US.properties
内容为: welcome=welcome to itcast

对于中文的属性文件,我们编写好后,应该使用jdk提供的native2ascii命令把文件转换为unicode编码的文件。
命令的使用方式如下:
native2ascii  源文件.properties  目标文件.properties

【配置全局资源与输出国际化信息】
当准备好资源文件之后,我们可以在struts.xml中
通过struts.custom.i18n.resources常量把资源文件定义为全局资源文件,如下:
<constant name="struts.custom.i18n.resources" value="itcast" />
itcast为资源文件的基本名。

后面我们就可以在页面或在action中访问国际化信息:
在JSP页面中使用<s:text name=""/>标签输出国际化信息:
<s:text name="user"/>,name为资源文件中的key
或:<s:property value="getText('name')" />

在Action类中,可以继承ActionSupport,
使用getText(String key)方法得到国际化信息,该方法的参数用于指定资源文件中的key。
在表单标签中,通过key属性指定资源文件中的key,如:
<s:textfield name="realname" key="user"/>

【国际化—输出带占位符的国际化信息】

资源文件中的内容如下:
welcome= {0},欢迎来到传智播客{1}

在jsp页面中输出带占位符的国际化信息
<s:text name="welcome">
    <s:param><s:property value="realname"/></s:param>
    <s:param>学习</s:param>
</s:text>

在Action类中获取带占位符的国际化信息,可以使用
getText(String key, String[] args)或getText(String aTextName, List args)方法。

【国际化—包范围资源文件】

在一个大型应用中,整个应用有大量的内容需要实现国际化,如果我们把国际化的内容都
放置在全局资源属性文件中,显然会导致资源文件变的过于庞大、臃肿,不便于维护,这
个时候我们可以针对不同模块,使用包范围来组织国际化文件。

方法如下:
在java的包下放置package_language_country.properties资源文件,package为固定写法,
处于该包及子包下的action都可以访问该资源。当查找指定key的消息时,系统会先从package
资源文件查找,当找不到对应的key时,才会从常量struts.custom.i18n.resources指定的资源文件中寻找。


【国际化—Action范围资源文件】

我们也可以为某个action单独指定资源文件,方法如下:
在Action类所在的路径,放置ActionClassName_language_country.properties资源文件,
ActionClassName为action类的简单名称。

当查找指定key的消息时,系统会先从ActionClassName_language_country.properties资
源文件查找,如果没有找到对应的key,然后沿着当前包往上查找基本名为package的资
源文件,一直找到最顶层包。如果还没有找到对应的key,最后会从常量
struts.custom.i18n.resources指定的资源文件中寻找

【国际化—JSP中直接访问某个资源文件】
struts2为我们提供了<s:i18n>标签,使用<s:i18n>标签我们可以在类路径下直接从某个资源
文件中获取国际化数据,而无需任何配置:
<s:i18n name="itcast">
    <s:text name="welcome"/>
</s:i18n>
itcast为类路径下资源文件的基本名。

如果要访问的资源文件在类路径的某个包下,可以这样访问:
<s:i18n name="cn/itcast/action/package">
    <s:text name="welcome">
        <s:param>小张</s:param>
    </s:text>
</s:i18n>
上面访问cn.itcast.action包下基本名为package的资源文件。

【动态国际化页】
通过页面上的选项来选择页面显示语言,
通过参数request_local来设定,我们在请求url后加上该参数也可以。
url?request_local=en_US

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

相对EL表达式,它提供了平时我们需要的一些功能,如:
支持对象方法调用(也支持对象级联调用),如xxx.sayHello();
    <s:property value="password.length()" />   调用属性对应的方法
    <s:property value="execute()" />       调用Action类中的普通方法
支持类静态方法调用和值访问,
表达式的格式为 @[类全名(包括包路径)]@[方法名 |  值名],
例如:@java.lang.String@format('foo %s', 'bar')或@cn.csdn.Constant@APP_NAME;
    @@mxa(2,3)只支持访问Math类中的静态方法
支持普通类的构造方法的调用:<s:property value="new cn.itcase.bean.User()"/>
    
操作集合对象。

Ognl 有一个上下文(Context)概念,说白了上下文就是一个MAP结构,它实现了java.utils.Map接口,在Struts2中上下文(Context)的实现为ActionContext,下面是上下文(Context)的结构示意图

        |--ValueStack(值栈,这是根对象)
        |--contextparameters
OGNL Context----|--request
        |--session
        |--application
        |--attr
Struts2中的OGNL Context实现者为ActionContext
当Struts2接受一个请求时,会迅速创建ActionContext,ValueStack,action。然后把action存进
ValueStack,所以action的实例变量可以被OGNL访问

访问上下文(Context)中的对象需要使用#符号标注命名空间,如#application、#session

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

在struts2中,根对象ValueStack的实现类为OgnlValueStack,该对象不是我们想像的只存放单个值,而是存放一组对象。在OgnlValueStack类里有一个List类型的root变量,就是使用他存放一组对象
        |--request  
        |--application  
context --------|--OgnlValueStack root变量[action, OgnlUtil, ... ]  
        |--session  
        |--attr  
        |--parameters

在root变量中处于第一位的对象叫栈顶对象。通常我们在OGNL表达式里直接写上属性的名称
即可访问root变量里对象的属性,搜索顺序是从栈顶对象开始寻找,如果栈顶对象不存在该
属性,就会从第二个对象寻找,如果没有找到就从第三个对象寻找,依次往下访问,直到找到为止。
注意:Struts2中,OGNL表达式需要配合Struts标签才可以使用。如:<s:property value="name"/>

由于ValueStack(值栈)是Struts 2中OGNL的根对象,如果用户需要访问值栈中的对象,
在JSP页面可以直接通过下面的EL表达式访问ValueStack(值栈)中对象的属性:
${foo} //获得值栈中某个对象的foo属性

如果访问其他Context中的对象,由于他们不是根对象,所以在访问时,需要添加#前缀。
application对象:用于访问ServletContext,例如#application.userName或者#application['userName'],相当于调用ServletContext的getAttribute("username")。

session对象:用来访问HttpSession,例如#session.userName或者#session['userName'],相当于调用session.getAttribute("userName")。

request对象:用来访问HttpServletRequest属性(attribute)的Map,例如#request.userName或者#request['userName'],相当于调用request.getAttribute("userName")。

parameters对象:用于访问HTTP的请求参数,例如#parameters.userName或者#parameters['userName'],相当于调用request.getParameter("username")。

attr对象:用于按page->request->session->application顺序访问其属性。

【为何使用EL表达式能够访问valueStack中对象的属性】

原因是Struts2对HttpServletRequest作了进一步的封装。简略代码如下:

 public class StrutsRequestWrapper extends HttpServletRequestWrapper {
       public StrutsRequestWrapper(HttpServletRequest req) {
           super(req);
       }
       public Object getAttribute(String s) {
        ......
        ActionContext ctx = ActionContext.getContext();
        Object attribute = super.getAttribute(s);//先从request范围获取属性值
        if (ctx != null) {
            if (attribute == null) {//如果从request范围没有找到属性值,即从ValueStack中查找对象的属性值
               ......
               ValueStack stack = ctx.getValueStack();
               attribute = stack.findValue(s);
               ......
            }
        }
        return attribute;
    }
 }

【采用OGNL表达式创建List/Map集合对象】
如果需要一个集合元素的时候(例如List对象或者Map对象),可以使用OGNL中同集合相关的表达式。
使用如下代码直接生成一个List对象:
<s:set name="list" value="{'zhangming','xiaoi','liming'}" />
<s:iterator value="#list" id="n">
    <!--value:赋给变量的值.如果没有设置该属性,则将ValueStack栈顶的值赋给变量。-->
    <s:property value="n"/><br>
</s:iterator>

生成一个Map对象:(数字不用加引号)
<s:set name="foobar" value="#{'foo1':'bar1', 'foo2':'bar2'}" />
<s:iterator value="#foobar" >
    <s:property value="key"/>=<s:property value="value"/><br>
</s:iterator>
<s:property value="#foobar.keys" />    获取Map中的所有key
<s:property value="#foobar.values" />    获取Map中的所有Value
<s:property value="#foobar.size()" />    获取Map的大小

Set标签用于将某个值放入指定范围。
scope:指定变量被放置的范围,该属性可以接受application、session、request、 page或action。
如果没有设置该属性,则默认放置在OGNL Context中,单独成为一个作用范围。
<s:iterator>的特点:会把当前迭代的对象放在ValueStack栈顶

<s:property value="[0]" />功能:访问ValueStack中从第1个开始的之后所有的对象
<s:property value="[1]" />功能:访问ValueStack中从第2个开始的之后所有的对象

【采用OGNL判断对象是否在集合中】
通过:in / not in 这两个元素符号
示例:
    in表达式
        <s:if test="'foo' in {'foo','bar'}">
            在
        </s:if>
        <s:else>
            不在
        </s:else>

    not in表达式
        <s:if test="'foo' not in {'foo','bar'}">
            在
        </s:if>
        <s:else>
            不在
        </s:else>

【OGNL的投影功能】(用的不多,一般都会在业务逻辑层筛选结果)
除了in和not in之外,OGNL还允许使用某个规则获得集合对象的子集,常用的有以下3个相关操作符。
?:获得所有符合逻辑的元素。
^:获得符合逻辑的第一个元素。
$:获得符合逻辑的最后一个元素。
例如代码:
<s:iterator value="books.{?#this.price > 35}"> //用于获取集合中价格大于35的书集合。
      <!--title price都是Book类的属性-->
      <s:property value="title" /> - $<s:property value="price" /><br>
</s:iterator>
在上面代码中,直接在集合后紧跟.{}运算符表明用于取出该集合的子集,
{}内的表达式用于获取符合条件的元素,this指的是为了从大集合books筛选数据到小集合public class BookAction extends ActionSupport {
private List<Book> books;
....
@Override
    public String execute() {
        books = new LinkedList<Book>();
        books.add(new Book("A735619678", "spring", 67));
books.add(new Book("B435555322", "ejb3.0",15));
}
}

【Struts2常用标签】
==============================================================================================
    <s:set>标签
Set标签用于将某个值放入指定范围。
scope:指定变量被放置的范围,该属性可以接受application、session、request、 page或action。
默认值为action,如果没有设置该属性,则默认放置在OGNL Context中,单独成为一个作用范围。
var:该属性是可选的,所要参考的ValueStack中的值的名称。指定该属性时,才会被放入OGNL context
id,name属性已经标注为过时
例如:
    <s:set var="adminPassword" value="password" />
取的时候:
    <s:property value="#adminPassword">
例如:
    <s:set var="adminPassword" value="password" scope="session" />
取的时候:
    <s:property value="#session.adminPassword">
==============================================================================================
    <s:property>标签
property标签的作用是输出指定值。
<s:set name="name" value="kk" />
<s:property value="#name" />
default:可选属性,如果需要输出的属性值为null,则显示该属性指定的值
escape:可选属性,指定是否格式化HTML代码,默认为true,不解析HTML代码,false时以HTML代码来解析
value:可选属性,指定需要输出的属性值,如果没有指定该属性,则默认输出值栈ValueStack栈顶的值。
id:可选属性,指定该元素的标识
==============================================================================================
    <s:bean>标签
作用:实例化JavaBeans
var:该属性是可选的,所要参考的ValueStack中的值的名称。指定该属性时,才会被放入OGNL context
name:要被实例化的JavaBean类的完整名称
<s:bean name="cn.itcast.bean.Book" var="book">
    <s:param name="name" value="'javaEE'"></s:param>
    <s:property value="name" /> 在bean内部可以这样使用
</s:bean>
在标签内,实例出的bean对象会被保存到值栈栈顶,还有OGNL context中(前提指定var),
标签结束后栈顶的对象会弹出。
所以在标签内部<s:property value="name" />可以取出值
在外面就需要:<s:property value="#book.name" />

    <s:param>标签
作用:给其它标签注入参数
name:参考目标的属性名
value:OGNL表达式,如果要写字符串,需要加单引号
==============================================================================================
    <s:iterator>标签
iterator标签用于对集合进行迭代,这里的集合包含List、Set和数组。
也可以对Map类型的对象进行迭代输出。
<s:set name="list" value="{"张三","李四","王五"}" />
<s:iterator value="#list" status="st">
    <font color=<s:if test="#st.odd">red</s:if><s:else>blue</s:else>>
        <s:property />
    </font>
    <br/>
</s:iterator>
value:可选属性,指定被迭代的集合,被迭代的集合通常都由OGNL表达式指定。
    如果没有指定该属性,则使用值栈栈顶的集合。
id:可选属性,指定集合里元素的id(已被标注为过时)
status:可选属性,指定迭代时的IteratorStatus实例,通过该实例可判断当前迭代元素的属性。该实例包含如下几个方法:
    int getCount():返回当前迭代了几个元素
    int getIndex():返回当前迭代元素的索引
    boolean isEven():返回当前迭代元素的索引是否是偶数
    boolean isOdd():返回当前迭代元素的索引是否是奇数
    boolean isFirst():返回当前迭代元素的索引是否是第一个元素
    boolean isLast():返回当前迭代元素的索引是否是最后一个元素
例如:
<table border="1" width="200">
    <s:iterator value="{'apple','orange','pear','banana'}" id="fruit" status="st">
        <tr <s:if test="#st.even">style="background-color:silver"</s:if>>
            <td>
                <s:property value="fruit"/>
            </td>
        </tr>
    </s:iterator>
</table>
==============================================================================================
    <s:if>/<s:elseif>/<s:else>标签
只有if标签可以单独使用,if标签可以与多个elseif标签结合使用,但只能与一个else标签使用。其用法格式如下:
<s:if test="表达式">
    ?标签体
</s:if>
<s:elseif test="表达式">
    标签体
</s:elseif>
    <!--允许出现多次elseif标签-->
...
<s:else>
    标签体
</s:else>
==============================================================================================
    <s:url>标签
<s:url action="helloworld_add" namespace="/test">
    <s:param name="personId" value="23" />
</s:url>
生成类似如下的路径:
contextName/test/helloworld_add.action?personId=23
<s:param>中value的值可以是OGNL表达式,当表达式无法解析时会原样输出

<s:url>标签的value属性是作为字符串类型处理的(所写的OGNL表达式会原样输出),
"%{ognl}"符号用来计算OGNL表达式的值:
<s:set name="myurl" value="http://www.baidu.com" />
<s:url value="#myurl" />
<s:url value="%{#myurl}" />
输出结果:
#myurl
http://www.baidu.com

一般与<a>标签结合使用:
<a href="<s:url namespace='' action='' />">一个链接</a>
链接会自动生成 当前应用名称、请求后缀
==============================================================================================
    <s:param>标签
param标签主要用于为其他标签提供参数,该标签有如下几个属性:
name:该属性是可选的,指定需要设置参数的参数名。
value:该属性是可选的,指定需要设置参数的参数值。
id:该属性是可选的,指定引用该元素的id。
==============================================================================================
    <s:checkboxlist>标签
为List:
<s:checkboxlist label="请选择你喜欢的水果" list="{'apple','oranger','pear','banana'}" name="fruit" value="{'apple','pear'}">
</s:checkboxlist>
name属性:生成复选框的名称
list属性:list集合,迭代集合生成复选框,若当前迭代值在value中标明,则生成checked属性
value属性:指定被checked的复选框
生成如下的HTML标签:
<input type="checkbox" name="fruit" value="apple" checked="checked" /><label>apple</label>
<input type="checkbox" name="fruit" value="oranger" /><label>oranger</label>
<input type="checkbox" name="fruit" value="pear" checked="checked" /><label>pear</label>
<input type="checkbox" name="fruit" value="banana" /><label>banana</label>

为Map:
<s:checkboxlist label="请选择你喜欢的水果" list="#{1:'apple',2:'oranger',3:'pear',4:'banana'}" name="fruit" value="{1,3}" listKey="key" listValue="value">
</s:checkboxlist>
listKey="key":指定Map的key为复选框中的value值,默认值可不写
listValue="value":指定Map的value为复选框外label标签对之间的值,默认值可不写
生成如下的HTML标签:
<input type="checkbox" name="fruit" value="1" checked="checked" /><label>apple</label>
<input type="checkbox" name="fruit" value="2" /><label>oranger</label>
<input type="checkbox" name="fruit" value="3" checked="checked" /><label>pear</label>
<input type="checkbox" name="fruit" value="4" /><label>banana</label>

【注意】使用<s:checkboxlist>标签,除了生成相应的复选框标签外,还会生成一些<td>标签,
因为Struts还有视图主题设置,我们可以取消主题设置,这样就不会生成多余的<td>标签:
设置常量:
<constant name="struts.ui.theme" value="simple">

集合中放的是javabean,Person类有两个属性:personid,name
<%
    Person p1 = new Person(1,"第一个");
    Person p2 = new Person(2,"第二个");
    List<Person> list = new ArrayList<Person>();
    list.add(p1);
    list.add(p2);
    request.setAttribute("persons",list);
%>
<s:checkboxlist name="beans" list="#request.persons" listKey="personid" listValue="name" />
生成的HTML代码如下:
<input type="checkbox" name="beans" value="1" /><label>第一个<label>
<input type="checkbox" name="beans" value="2" /><label>第二个<label>
==============================================================================================
    <s:radio>标签
<s:radio>与<s:checkboxlist>使用几乎一样
不同的是value属性的设置:不需要再用{},单选框嘛,只有一个预选值
<s:radio label="性别" list="{'男','女'}" name="sex" value="'男'" />
或者为Map:
<s:radio label="性别" list="#{1:'男',0:'女'}" name="sex" value="1" />
或者为javabean:
<s:radio name="beans" list="#request.books" listKey="id" listValue="name" />
==============================================================================================
    <s:select>标签
与<s:radio>使用一样
<s:select name="fruit" list="{'apple','oranger','pear','banana'}" label="请选择你喜欢的水果"/>
或者为Map:
<s:select name="fruit" list="#{1:'apple',2:'oranger',3:'pear',4:'banana'}" listKey="key" listValue="value"/>
或者为javabean:
<s:select name="beans" list="#request.books" listKey="id" listValue="name" />
==============================================================================================

    <s:action>标签
使用action标签可以允许在JSP页面中直接调用Action。
name:该属性是必选的,指定该标签调用哪个Action。
==============================================================================================
    <s:date>标签
date标签主要用于格式化输出一个日期。该标签有如下属性:
format:该属性是可选的,如果指定了该属性,将根据该属性指定的格式来格式化日期。
nice:该属性是可选的,指定是否输出指定日期和当前时刻之间的时差。默认为false。
name:属性是必选的,指定要格式化的日期值。
其用法为:
<s:date name="指定日期取值" format="日期格式"/><!-- 按指定日期格式输出 -->
<s:date name="指定日期取值" nice="true"/><!-- 输出时间差 -->
<s:date name="指定日期取值"/><!—默认格式输出-->
==============================================================================================
    <s:include>标签
include标签用于将一个JSP页面或一个Servlet包含到本页面中。
value:该属性是必选的,指定需要被包含的JSP页面或Servlet。
例如:<s:include value="JSP或Servlet文件" id="自定义名称"/>
==============================================================================================
    <s:append>标签
例如:<body>
<s:append id="newList">
<s:param value="{'apple','orange','pear','banana'}"/>
<s:param value="{'chinese','english','french'}"/>
</s:append>
<table border="1" width="200">
<s:iterator value="#newList" id="fruit" status="st">
<tr <s:if test="#st.even">style="background-color:silver"</s:if>>
<td><s:property value="fruit"/></td>
</tr>
</s:iterator>
</table>
</body>
==============================================================================================
    <s:merge>标签
与append标签作用相似,只是它们所拼接产生的新集合元素顺序不同,其中merge是每次分别在每一个集合取一个元素进行拼接。
==============================================================================================
    <s:combobox>标签
<s:combobox label="请选择你喜欢的水果" list="{'apple','oranger','pear','banana'}" name="fruit">
</s:combobox>
==============================================================================================
    <s:datetimepicker>标签
<s:form action="" method="">
?<s:datetimepicker name="date" label="请选择日期"></s:datetimepicker>
</s:form>
==============================================================================================

【<s:token/>标签防止重复提交】
第一步:在表单中加入<s:token />
<s:form action="helloworld_other" method="post" namespace="/test">
    <s:textfield name="person.name"/>
    <s:token />
    <s:submit />
</s:form>
第二步:给Action添加token拦截器、及invalid.token的视图
<action name="helloworld_*" class="cn.itcast.action.HelloWorldAction" method="{1}">
    <interceptor-ref name="defaultStack" />
    <interceptor-ref name="token" />
    <result name="invalid.token">/WEB-INF/page/message.jsp</result>
    <result>/WEB-INF/page/result.jsp</result>
</action>
这样token拦截器在会话的token与请求的token不一致时,将会直接返回invalid.token结果
token拦截器是Struts2自带的,不需要编写

【通过url传输List、Map类型的数据】
以http://localhost:8080/project/login.action为例
传输一个List<String> interests类型的数据
http://localhost:8080/project/login.action?interests=programming&interests=sport&interests=sleep
传输一个Map<String, String> users类型的数据
http://localhost:8080/project/login.action?users['a']=usera&users['b']=userb

© 著作权归作者所有

木子丰
粉丝 17
博文 236
码字总数 68754
作品 0
郑州
程序员
百度网盘分享

百度网盘视频教程分享 李炎恢 html5 百度网盘视频教程 struts2 视频分享 百度网盘 JAVA李清华视频教程 百度网盘 老男孩python百度云网盘 下载 老男孩mysql DBA高级运维系列教程(16部) 老男...

求索路
2016/12/28
91
0
优秀的 Android 开源项目

摘要 转载http://www.trinea.cn/android/android-open-source-projects-view/,方便大家找到自己合适的资料 目录[-] 一、ListView 二、ActionBar 三、Menu 四、ViewPager 、Gallery 五、Gri...

ljrapple
2015/04/06
0
1
Android的,iOS的,PHP的,大数据的,Java的,web前端的,C++,Python等干货分享

这是一些学习资源,里面有Android的,iOS的,PHP的,大数据的,Java的,web前端的,C++,Python的…. 有的来源地址是在一个公众号的群.感谢群主的分享.有的是我以前收集的.在此我也分享给大家.如果大...

月亮1987
2017/09/04
0
0
三大java技术牛人齐聚广州传智播客——超强师资,超低价格,超深课程,超真项目

三大java技术牛人齐聚广州传智播客——超强师资,超低价格,超深课程,超真项目 中国的软件教育已经坑害了不少软件工程师苗子,传智播客自成立之日起就立志于改变中国的软件教育。随着传智播...

传智播客java.net培训
2010/03/02
0
0
【学习笔记3】解决struts2配置文件无提示问题

在没有连接到互联网的情况下,编辑struts.xml文件时可能会没有代码提示,怎么解决呢?方法如下: 1、查看struts.xml,找到<!DOCTYPE>中对dtd的描写:http://struts.apache.org/dtds/struts-...

张超
2013/03/18
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

7 个致命的 Linux 命令

导读 如果你是一个 Linux 新手,在好奇心的驱使下,可能会去尝试从各个渠道获得的命令。以下是 7 个致命的 Linux 命令,轻则使你的数据造成丢失,重则使你的系统造成瘫痪,所以,你应当竭力避...

问题终结者
今天
0
0
设计模式:工厂方法模式(工厂模式)

工厂方法模式才是真正的工厂模式,前面讲到的静态工厂模式实际上不能说是一种真正意义上的设计模式,只是一种变成习惯。 工厂方法的类图: 这里面涉及到四个种类: 1、抽象产品: Product 2、...

京一
今天
0
0
区块链和数据库,技术到底有何区别?

关于数据库和区块链,总会有很多的困惑。区块链其实是一种数据库,因为他是数字账本,并且在区块的数据结构上存储信息。数据库中存储信息的结构被称为表格。但是,区块链是数据库,数据库可不...

HiBlock
今天
0
0
react native 开发碰到的问题

react-navigation v2 问题 问题: static navigationOptions = ({navigation, navigationOptions}) => ({ headerTitle: ( <Text style={{color:"#fff"}}>我的</Text> ), headerRight: ( <View......

罗培海
今天
0
0
Mac Docker安装流程

久仰Docker大名已久,于是今天趁着有空,尝试了一下Docker 先是从docker的官网上下载下来mac版本的docker安装包,安装很简易,就直接拖图标就好了。 https://www.docker.com/products/docker...

writeademo
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部