Struts2-Action:
    搭建MyEclipse框架,在Window/Prefrence中设置Server/Tomcat的目录,然后设置java选项卡中JDK的路径。

Struts的运行机制:
    URL请求通过HTTP协议发送给TOMCAT(假设我们的url为http://localhost:8080/$webapplication的名字$/hello),
根据URL中请求的webapplication再交给对应的webapplication处理,然后参考其web.xml的配置,其中有:
...
<filter>
    <filter-name>struts2</filter-name>
    <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
...
被org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter接受,它又会参考struts.xml的namespace,再根据其下对应的action和result,
将请求转到对应的JSP文件。

struts的作用就是将请求和视图分开。

struts.xml解释:
<struts>

    <constant name="struts.devMode" value="true" />
    <package name="front" extends="struts-default" namespace="/front">    //package区分重名的情况;namespace不为空时必须用'/'开头,当想访问这个namespace中的action就需要在前面带上这个路径
        <action name="index">
            <result>/Namespace.jsp</result>
        </action>
    </package>
 
    <package name="main" extends="struts-default" namespace="">
        <action name="index">
            <result>/Namespace.jsp</result>
        </action>
    </package>

</struts>

例如要访问name="index"的action,则url为http://localhost:8080/$webapplication的名字$/front/index
namespace决定了action的访问路径,不写时默认为"",可以接收所有路径的action
namespace可以写为/,或者/xxx,或者/xxx/yyy,对应的action访问路径为/index.action,/xxx/index.action,或者/xxx/yyy/index.action.
namespace最好也用模块来进行命名。

    <constant name="struts.devMode" value="true" />
    <package name="front" extends="struts-default" namespace="/">
        <action name="index" class="com.bjsxt.struts2.front.action.IndexAction1">    //当请求这个action的时候,找到对应的class,执行它里面的execute()方法,返回值时String,就把他当成一个Action。
            <result name="success">/ActionIntroduction.jsp</result>
        </action>
    </package>

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

Struts1和Struts2的一个区别:Struts2的每一个Action都是新NEW的,而Struts1不是,故2解决了线程同步问题。

struts2中的路径问题是根据action的路径而不是jsp路径来确定,所以尽量不要使用相对路径。
虽然可以用redirect方式解决,但redirect方式并非必要。
解决办法非常简单,统一使用绝对路径。(在jsp中用request.getContextRoot方式来拿到webapp的路径)
或者使用myeclipse经常用的,指定basePath:
<%    //获取根目录路径
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<base href="<%=basePath%>" />    //设置当前页面下的链接的根路径

Action执行的时候并不一定要执行execute方法。
可以在配置文件中配置Action的时候用method=来指定执行哪个方法
也可以在url地址中动态指定(动态方法调用DMI)(推荐):!+方法名
前者会产生太多的action,所以不推荐使用。

使用通配符可以将配置降到最低,不过一定要遵守“约定优于配置”。视频14。

在action中传参数有三种方法。

值堆栈中每一个元素都有一个名字和一个值。

//用javascript指定这个form提交的action。
<input type="button" value="submit1" onclick="javascript:document.f.action='login/login1';document.f.submit();" />

----LoginAction1.java----
public class LoginAction1 extends ActionSupport {
    
    private Map request;
    private Map session;
    private Map application;
    
    public LoginAction1() {
        //利用这种方法发到request(类型为Map),session,application
        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; 
    }
前台页面:
...
    //利用<s:property value="#request.r1"/>访问,也可以用传统的方式<%=request.getAttribute("r1") %>来取值
    <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 />
...
----LoginAction2.java----
****最常用的方法****

package com.bjsxt.struts2.user.action;

import java.util.Map;

import org.apache.struts2.interceptor.ApplicationAware;
import org.apache.struts2.interceptor.RequestAware;
import org.apache.struts2.interceptor.SessionAware;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;

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() {
        //直接可以用(设计思想IoC或者DI),需要实现RequestAware,SessionAware, ApplicationAware借口
        request.put("r1", "r1");
        session.put("s1", "s1");
        application.put("a1", "a1");
        return SUCCESS; 
    }

    //利用setRequest(Map<String, Object> request)设置request
    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;
    }
    
    
}


在struts.xml中增加以下语句可以解决中文编码问题:
<constant name="struts.i18n.encoding" value="GBK" /> <!-- internationalization -->

<include file="login.xml" />    //用于包含另外一个.xml文件到struts.xml文件中

<default-action-ref name="index"><*default-action-ref>定义默认Action,当找不到指定Action(或者不指定Action)时,转到那个package下的Action

Action总结:
1.实现一个Action的最重用的方式:从ActionSupport继承
2.DMI动态方法调用+!
3.通配符:*asd*--{1}{2}
    *_*--{1}{2}
4.接受参数的方法(一般用属性或者DomainModel来接受)
5.简单参数验证addFieldError
    一般不适用Struts2的UI标签
6.访问Web元素
    Map类型
        loc(最常用)
        依赖Struts2
    原始类型
        loc
        依赖Struts2
7.包含文件配置
8.默认Action处理

result可以指定类型,默认为dispatcher(用服务器跳转到结果页面,不可以是Action),还有:
redirect(不可以跳转到Action),chain(跳转到一个Action),redirectAction(跳转到另外一个Action)。
以上四种最常用,前两中最最常用。还有freemarker,httpheader,stream,velocity,xsit,plaintext,tiles等类型。
客户端跳转和服务器端跳转--视频27
dispatcher和chain为服务器端跳转,而redirect和redirectAction为客户端跳转。

chain类型跳转到另一个Action要带参数:
<result type="chain">
    <param name="actionName">aasdafa</param>    //指定Action的名字
    <param name="namespace">/asdasd</param>        //指定Action的NameSpace
</result>

global-results用于处理包里的共有结果集,extend用于继承其他package中的global-results。

动态指定result:在Action实现类中可以指定字符串参数来指向JSP页面地址,如:
...
    private String r;

    public String execute() throws Exception {
        if(type == 1) r="/user_success.jsp";
        else if (type == 2) r="/user_error.jsp";
        return "success";
    }
...
在struts.xml中,
...
        <action name="user" class="com.bjsxt.struts2.user.action.UserAction">
            <result>${r}</result>
        </action>
...
来确定result的展示页面,因为Action中的参数都会存放在值堆栈中。
在index.jsp中直接用:
    <li><a href="user/user?type=1">返回success</a></li>
    <li><a href="user/user?type=2">返回error</a></li>
来给action实现类中的参数传递参数。


一次request中若有服务端跳转,则跳转前后的所有Action公用值堆栈,故各个Action之间不需要传递参数。
但若跳转到jsp页面所传递的参数不存放在值堆栈中,只能利用actioncantext中取值。
...
        <action name="user" class="com.bjsxt.struts2.user.action.UserAction">
            <result type="redirect">/user_success.jsp?t=${type}</result>
        </action>    
...

...
    from valuestack: <s:property value="t"/><br/>    //从值堆栈中取值
    from actioncontext: <s:property value="#parameters.t"/>    //从actioncantext中取值
...

OGNL(object grapg navigation language)表达式:
    必须为Action类传递参数,它才会构造(new)这个对象,此时必须有空的构造方法。
    也可以不传递参数而自己直接在类中构造。

访问静态方法需要在struts.xml中设置如下语句:
    <constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>
访问静态属性和静态方法:
    <s:property value="@com.bjsxt.struts2.ognl.S@s()"/>
    <s:property value="@com.bjsxt.struts2.ognl.S@STR"/>
"@类名@属性(方法)"
"@@方法(属性)"--只能访问Math的方法和属性

----ognl.jsp----

<?xml version="1.0" encoding="GB18030" ?>
<%@ page language="java" contentType="text/html; charset=GB18030"
    pageEncoding="GB18030"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=GB18030" />
<title>OGNL表达式语言学习</title>
</head>
<body>
    <ol>
        <li>访问值栈中的action的普通属性: username = <s:property value="username"/> </li>
        <li>访问值栈中对象的普通属性(get set方法):<s:property value="user.age"/> | <s:property value="user['age']"/> | <s:property value="user[\"age\"]"/> | wrong: <%--<s:property value="user[age]"/>--%></li>
        <li>访问值栈中对象的普通属性(get set方法): <s:property value="cat.friend.name"/></li>
        <li>访问值栈中对象的普通方法:<s:property value="password.length()"/></li>
        <li>访问值栈中对象的普通方法:<s:property value="cat.miaomiao()" /></li>
        <li>访问值栈中action的普通方法:<s:property value="m()" /></li>
        <hr />
        <li>访问静态方法:<s:property value="@com.bjsxt.struts2.ognl.S@s()"/></li>
        <li>访问静态属性:<s:property value="@com.bjsxt.struts2.ognl.S@STR"/></li>
        <li>访问Math类的静态方法:<s:property value="@@max(2,3)" /></li>
        <hr />
        <li>访问普通类的构造方法:<s:property value="new com.bjsxt.struts2.ognl.User(8)"/></li>
        <hr />
        <li>访问List:<s:property value="users"/></li>
        <li>访问List中某个元素:<s:property value="users[1]"/></li>
        <li>访问List中元素某个属性的集合:<s:property value="users.{age}"/></li>
        <li>访问List中元素某个属性的集合中的特定值:<s:property value="users.{age}[0]"/> | <s:property value="users[0].age"/></li>
        <li>访问Set:<s:property value="dogs"/></li>
        <li>访问Set中某个元素:<s:property value="dogs[1]"/></li>
        <li>访问Map:<s:property value="dogMap"/></li>
        <li>访问Map中某个元素:<s:property value="dogMap.dog101"/> | <s:property value="dogMap['dog101']"/> | <s:property value="dogMap[\"dog101\"]"/></li>
        <li>访问Map中所有的key:<s:property value="dogMap.keys"/></li>
        <li>访问Map中所有的value:<s:property value="dogMap.values"/></li>
        <li>访问容器的大小:<s:property value="dogMap.size()"/> | <s:property value="users.size"/> </li>
        <hr />
        <li>投影(过滤):<s:property value="users.{?#this.age==1}[0]"/></li>
        <li>投影:<s:property value="users.{^#this.age>1}.{age}"/></li>
        <li>投影:<s:property value="users.{$#this.age>1}.{age}"/></li>
        <li>投影:<s:property value="users.{$#this.age>1}.{age} == null"/></li>
        <hr />
        <li>[]:<s:property value="[0].username"/></li>
        
    </ol>
    
    <s:debug></s:debug>
</body>
</html>

投影(过滤):{?#this.age==1}、{^#this.age>1}、{$#this.age>1}为过滤条件。
^代表第一个,$代表末尾那个。
<s:property value="[0].username"/>代表从第0个一直到末尾的集合。在服务器端跳转时就会有多个Action。


Struts2的标签可以分为通用标签,控制标签,UI标签,AJAX标签,$#%的区别。

1.通用标签:
    a)property
    b)set
        i.默认为action scope,会将值放入request和ActionContext中
            ii.page、request、session、application
    c)bean
    d)include(对中文文件支持有问题,不建议使用,如需包含,改用jsp包含)
    e)param
    f)debug

2.控制标签
    a)if elseif else
    b)iterator
        i.collections map enumeration iterator array
    c)subset

3.UI标签
    a)theme
        i.simple xhtml(默认) css_xhtml ajax

4.AJAX标签
    a)补充

5.$ # %的区别
    a)$用于i18n和struts配置文件
    b)#取得ActionContext的值
    c)%将原本的文本属性解析为ognl,对于本来就是ognl的属性不起作用
        i. 参考<s:property 和 <s:include

命名规范: 1.数据库命名: 表命名(简单就是美): _表名,如: _Topic (使用驼峰标示,尽管数据库不区分大小写) 字段命名: 保持与属性名一致(尽量不要和数据库的命名冲突) 如:ID属性 id 外键 topicId 库名: 使用项目的名称 2.类和文件的命名: 有两种方式:1.先分模块再分层次2.先分层次再分模块 采用层次划分(包的命名都用小写): com.bjsxt.bbs.action.model.service Action类采用Action结尾,如:xxxAction.java JSP命名:*_* namespace:前台直接使用"/" 后台使用"/admin" package: 前台:aciton 后台:adminAction 项目开发顺序: 1.建立界面原型 2.建立Struts.xml a.确定namespace b.确定package c.确定Action的名称,空的方法 d.确定Rssult e.将界面原形页面进行修改,匹配现有设置 f.测试 g.做好规划 3.建立数据库(或者实体类) 4.建立Model层 5.建立Service层(hibernate) 使用Junit进行单元测试 6.着手开发 请求到来后被Filter过滤,调用特定的Action的特定方法,拦截器就是在调用的时候加东西。 (其实先调用拦截器,拦截器再调用Action,再返回给拦截器,又返回给Filter) I18N 在普通Editer直接写中文会乱码。 国际化文件可以用propertiesEditer插件,在这里面写的中文会转为UTF-8保存。 Struts2的国际化有三种方式: Action-Package-App级 主要用App,对整个项目有效。 struts2的实际执行过程: 1.Struts2Flter接受页面请求 2.调用Dispatcher的serviceAction()方法 3.Dispatcher创建一个ActionProxy对象,并调用它的execute()方法 4.execute()方法又会调用ActionInvocation的invoke()方法 5.invoke()方法又会调用第一个inerceptor对象的interceptor()方法 6.interceptor()方法又会调用ActionInvocation对象的invoke()方法 7.nvoke()方法又会调用下一个inerceptor对象的interceptor()方法 8.反复直到所有inerceptor调用完毕,ActionInvocation对象调用最中的Action类的execute()方法 传递多个相同参数的时候,可以使用集合容器,但是要使用泛型。 比如在action类中有属性: ...... List<interst>; //不用new ...... 使用token拦截器控制重复提交(很少用) 写自己的转换器: public class MyPointConverter extends DefaultTypeConverter{ @Override public Object convertValue(Object value, Class toType) { if(toType == Point.class) { Point p = new Point(); String[] strs = (String[])value; String[] xy = strs[0].split(","); p.x = Integer.parseInt(xy[0]); p.y = Integer.parseInt(xy[1]); return p; } if(toType == String.class) { return value.toString(); } return super.convertValue(value, toType); } } public class MyPointConverter extends StrutsTypeConverter{ @Override public Object convertFromString(Map context, String[] values, Class toClass) { Point p = new Point(); String[] strs = (String[])values; String[] xy = strs[0].split(","); p.x = Integer.parseInt(xy[0]); p.y = Integer.parseInt(xy[1]); return p; } @Override public String convertToString(Map context, Object o) { // TODO Auto-generated method stub return o.toString(); } } 三种注册方式: i.局部:XXXAction-conversion.properties   1.p(属性名称)= converter ii.全局:xwork-conversion.properties   1.com.xxx.XXX(类名)= converter iii.Annotation 如果遇到非常麻烦的映射转换   i.request.setAttribute();   ii.session

 

posted on 2014-07-01 23:50  mosquito_real  阅读(210)  评论(0编辑  收藏  举报