好久没用struts2 一年多了吧。好多东西已经模糊忘记了。转篇博客恢复下记忆吧!
●开发准备
1.引入类库 直接从struts/apps/struts2-blank/WEB-INF/lib下拷贝
除junit和spring-test之外的所有jar包
2.复制一个struts.xml
直接从struts/apps/struts2-blank/WEB-INF/classes下拷贝struts.xml
3.对web.xml配置 同样从
struts/apps/struts2-blank/WEB-INF/web.xml中拷贝
<filter></filter>和<filter-mapping></filter-mapping>以及其中的全部内容
●Action
1.struts2的作用就是让用户请求和返回视图(servlet api)分离。
2.namespace决定了action的访问路径,默认为"",可以接收所有路径的action
namespace可以写为/,或者/xxx,或者/xxx/yyy,对应的action访问路径为/xxx.action
/xxx/xxx.action,或者/xxx/yyy/xxx.action
namespace最好也用模块来进行命名 比如用户模块 就用user
3.具体视图的返回可以由用户自己定义的Action来决定
具体的手段是根据返回的字符串找到对应的配置项,来决定视图的内容
具体Action的实现可以是一个普通的java类,里面有public String execute方法即可
或者实现Action接口
不过最常用的是从ActionSupport继承,好处在于可以直接使用Struts2封装好的方法
4.struts2中的路径问题是根据action的路径而不是jsp路径来确定,所以尽量不要使用相对路径。
虽然可以用redirect方式解决,但redirect方式并非必要。
解决办法非常简单,统一使用绝对路径。(在jsp中用request.getContextRoot方式来拿到webapp的路径)
或者使用myeclipse经常用的,指定basePath
5.Action执行的时候并不一定要执行execute方法
可以在配置文件中配置Action的时候用method=来指定执行哪个方法
也可以在url地址中动态指定(动态方法调用DMI)(推荐)
前者会产生太多的action,所以不推荐使用
6.使用通配符,将配置量降到最低
不过,一定要遵守"约定优于配置"的原则,即命名规则统一。
- <action name="Student*" class="com.bjsxt.struts2.action.StudentAction" method="{1}">
- <result>/Student{1}_success.jsp</result>
*代替字符串,{1}代表第一个*所匹配的字符串。
- <action name="*_*" class="com.bjsxt.struts2.action.{1}Action" method="{2}">
- <result>/{1}_{2}_success.jsp</result>
7.使用action属性接收参数,在URL地址中传的参数和action里的成员变量可以是一一对应的,
action初始化时,会自动将成员变量的值初始化成参数的值。(struts调set方法,所以set方法名
和url参数的名必须匹配而真正的成员变量名不一定非要匹配)
8.使用Domainmodel(领域模型)接收参数 action类中可以不写具体的属性而将其写入领域模型中,
然后action类中持有一个领域模型的对象的引用,在url中同样可以传参数直接对领域模型对象的属性赋值,
写法为 namespace/actionname!method?domainmodel.parameter=XXX&domainmodel.parameter=XXX,
(也可能是method?domainmodel.parameter.parameter.parameter=XXX,此时domainmodel成员变量为另一个对象,
另一个对象的成员变量为另另一个对象)
当领域模型与实际参数的属性不同时,如,password往往有确认password,则新建一个dataTransferObject类来接收参数并判断,再初始化领域模型。此时action类中持有的则是DTO的引用。
9.我们也可以使action类实现ModelDriven<User>接口,使用接口中的getmodle方法来使action自动获得领域模型,这样即使在action类中包含了领域模型的引用,同样可以在url中直接写 namespace/actionname!method?parameter=XXX¶meter=XXX.使用这个方法时,在action中要自己new一个模型。
10.
- <constant name="struts.i18n.encoding" value="GBK" />
struts.xml解决中文问题的标签,这些标签可以在struts2-core-2.1.6.jar中的org.apache.struts2中的default.properties中查询默认值。
在2.1.6之前,中文问题是个BUG,在2.1.7中已修正。
11.使用struts的标签来将程序中对用户的提示信息打印到前台页面:
在后台 使用
- this.addFieldError("name","name is error");
其中name为action中的属性,"name is error"为错误信息的提示
- <s:fielderror fieldName="name" />
将带有简单格式的提示信息打印到前台
首先,在前台页面中包含
- <%@taglib uri="/struts-tags" prefix="s" %>
在META-INF下struts-tag.tld中有标签详细信息 页面中使用<s:debug></s:debug>
可以观察ValueStack里保存的action中的属性。
属性都是存在map中的,有值,有名,而 值,是个数组,
所以我们用<s:property value="errors.name[0]">可以取到错误信息的具体字符串。
12.
一、
后台程序可以通过ActionSupport中的方法
- request = (Map)ActionContext.getContext().get("request");
- session = ActionContext.getContext().getSession();
- application = ActionContext.getContext().getApplication();
得到map类型的 request,session,application.
还可以通过put方法对这些名值对进行赋值。
在前台页面,可以通过
- <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 />
来拿到所设置的request、session、application.既用#key来访问或者用最原始的jsp语言来访问。
二(常用)、
同样设置三个成员变量 但使用范型
- private Map<String, Object> request;
- private Map<String, Object> session;
- private Map<String, Object> application;
然后设置set方法,由struts将页面元素对象自动设置进去(实现RequestAware,SessionAware,ApplicationAware),
然后调用put方法,往进写东西。
三、
同样设置三个成员变量 但类型不同
- private HttpServletRequest request;
- private HttpSession session;
- private ServletContext application;
然后初始化
- request = ServletActionContext.getRequest();
- session = request.getSession();
- application = session.getServletContext();
然后由request.setAttribute("r1", "r1")往进设置值。
四、
同样设置三个成员变量
- private HttpServletRequest request;
- private HttpSession session;
- private ServletContext application;
- //初始化
- public void setServletRequest(HttpServletRequest request) {
- this.request = request;
- this.session = request.getSession();
- this.application = session.getServletContext();
- }
- //然后由request.setAttribute("r1", "r1")设值。
13.模块包含
在struts.xml中可以将其他xml文档包含
- <include file="XXXX.xml" />
这样的好处是,多个模块可以同时开发,然后包含就可以协作工作。
14.默认action
在url的namespace后什么都不敲入或敲入不存在的action时,访问默认的action
- <default-action-ref name="index"></default-action-ref>
然后再jsp中使用
接受参数。
●result
15.result的type(类型)属性
·默认为dispatcher 运用jsp跳转(forward)到结果页面 不能跳转到action
·redirect 重定向到结果页面 不能跳转到action
·chain forward跳转到一个action
·redirectAction 重定向到一个action
·freemarker
·httpheader 发一个http的头信息
·stream 下载
·velocity
·xslt xml的修饰
·plaintext 页面源码
·tiles 页面分块后动态指定
假如chain forward跳转的action在某包内
则
- <result type="chain">
- <param name="actionName">adfadf</param>
- <param name="namespace">/XXXXXX</param>
- </reuslt>
在struts-2.2.1.1-docs/struts-2.2.1.1/docs/chain-result.html可查
16.global-results全局结果集在,同一个package中大家可以共用的结果视图
- <global-results>
- <result name="mainpage">/main.jsp</result>
- </global-results>
其他package中也想使用此package的result,则extends="packagename"
- <package name="admin" namespace="/admin" extends="user">
则此包内拥有user包的action
17.动态结果集 即<result>${r}</result>,此时r为action的成员变量 xml中${}可以读取valuestack里的内容
r的值可以动态指定为一个字符串,例如"/user_success.jsp"。
18.带参数的结果集。
由于forward服务器内跳转共享一个值栈,所以参数也共享,即没有必要传。
而再redirect客户端重定向的时候,值栈不共享,是两次request过程,
此时希望action向新定向到的页面传参数需要使用?paramname=${paramname}
即
- <result type="redirect">/user_success.jsp?t=${type}</result>
此时如果在user_success.jsp使用struts的<s:property value="t">
标签取值取不出,因为不是action没有值栈actionstack。
只能用<s:property value="#parameters.t">从actioncontext中取。
●ognl表达式
1.action中的成员变量为domainmodel对象引用时,可以在前台传参数来初始化这个对象,不传不构造,
也可以自己new。但是,如果要使用传参来初始化的时候domainmodel必须有一个空的构造方法。。
2.
访问值栈中的action的普通属性 <s:property value="username"/> 直接写属性名
访问值栈中对象的普通属性<s:property value="cat.friend.name"/> 对象名.成员变量名(是对象).成员变量名
访问值栈中对象的普通方法<s:property value="password.length()"/> 对象名.方法名()
访问值栈中action的普通方法<s:property value="m()"/> 直接写方法名()
3.
访问静态方法 <s:property value="@com.bjsxt.struts.ognl.S@s()"/> @类名@方法名()
在struts中要有一个设置<constant name="struts.ognl.allowStaticMethodAccess" value="true"><constant>
设置后才允许静态方法访问,这些在default.properties配置文件中可以查到
访问静态属性 <s:property value="@com.bjsxt.struts.ognl.S@STR"/> @类名@属性名
访问Math类的静态方法:<s:property value="@@max(2,3)" /> @@方法名
4.
访问普通类的构造方法:<s:property value="new com.bjsxt.struts2.ognl.User(8)"/> new 全类名(参数)
访问List中某个元素:<s:property value="users[1]"/> List名[下标]
访问List中元素某个属性的集合:<s:property value="users.{age}"/> 把users中每个user拿出来,
再把每个user的age拿出来组成一个新的List。 list名.{属性名}
访问List中元素某个属性的集合中的特定值:<s:property value="users.{age}[0]"/> 把users中每个user拿出来,
再把每个user的age拿出来组成一个新的List,取第0个。 list名.{属性名}[下标]
访问Set:<s:property value="dogs"/>
访问Set中某个元素:<s:property value="dogs[1]"/> 由于set是无序的所以取不到
访问Map:<s:property value="dogMap"/>
访问Map中某个元素:<s:property value="dogMap.dog101"/> map名.key名 或者dogMap['dog101']或者dogMap[/"dog101/"]
访问Map中所有的key:<s:property value="dogMap.keys"/> 拿到了key的集合
访问Map中所有的value:<s:property value="dogMap.values"/> 拿到了value的集合
访问容器的大小:<s:property value="dogMap.size()"/> | <s:property value="users.size"/>不加()也可以,
ognl认为它是个属性。
5.
投影(过滤):<s:property value="users.{?#this.age==1}[0]"/>
从users(list)中拿出age为1的user并将其放入集合,取第0个。
投影:<s:property value="users.{^#this.age>1}.{age}"/>
从users中拿出age大于1的 取开头那个 把年龄输出
投影:<s:property value="users.{$#this.age>1}.{age}"/>
从users中拿出age大于1的 取结尾那个 把年龄输出
投影:<s:property value="users.{$#this.age>1}.{age} == null"/>
从users中拿出age大于1的 取结尾那个的年龄 看是否为空
6.
用[]访问valuestack里面的元素 action永远在栈顶
[]:<s:property value="[0].username"/> 此时访问的是从0位置开始也就是从action的位置
开始往下的元素直到栈底。如果用到服务器端跳转,用到的action会挨个被压入valuestack中。
●Struts标签
首先,在前台页面中包含<%@taglib uri="/struts-tags" prefix="s" %>
1.property
- <s:property value="username"/>
将username属性的值打印出来
- <s:property value="'username'"/>
将username字符串打印出来
- <s:property value="admin" default="管理员"/>
为admin属性设置默认值,如果valuestack中没有则打印默认值
- <s:property value="'<hr/>'" escape="false"/>
默认为true,将标签转译成字符显示,而不是直接显示标签。
false时,不转译,即浏览器直接显示标签样式。
2.set 往指定或非指定范围内设定变量并指定值
常用于给actioncontext中的param中的变量命名
- <s:set var="adminName" value="username" />
将名为adminName的变量设置到request和ActionContext中
值为username的值,此时
- <s:property value="#request.adminName" />
- <s:property value="#adminName" />
都可以将adminName的值显示
- <s:set name="adminPassword" value="password" scope="page"/>
为adminPassword变量设定范围,name=这种写法已经被废弃
- <s:set var="adminPassword" value="password" scope="session"/>
上面代码显示,
当scope(范围)为session时,
在debug标签中看到actionContext中的session有值,
- <s:property value="#session.adminPassword"/>
所以必须从session中取而不能直接取值。
3.bean 创建name指定的类的对象并用var命名
不用var命名,会只在值栈中压入创建的对象,
标签结束时消除对象,所以标签外访问不到。
反之,则在stackcontext中,标签结束后同样可以取到。
- <s:bean name="com.bjsxt.struts2.tags.Dog" var="myDog">
- <s:param name="name" value="'oudy'"></s:param>
- </s:bean>
param属性为对象的成员变量设置值,name为名,value为值。
注意value为ognl所以字符串要加单引号。
4.include 包含英文文件(中文会出问题)
- <s:include value="/_include1.html"></s:include>
或者
- <s:set var="incPage" value="'/_include1.html'" />
- <s:include value="%{#incPage}"></s:include>
%{}的意思为将大括号中的内容强制当成ognl表达式
5.if elseif
url传参数后在actionContext中的parameters中会有对应参数和值
- <s:property value="#parameters.age[0]" /><!--可以查看参数age的值-->
- <s:if test="#parameters.age[0] < 0">wrong age!</s:if>
- <s:elseif test="#parameters.age[0] < 20">too young!</s:elseif>
- <s:else>yeah!</s:else>
6.iterator
- <s:iterator value="{1,2,3}">
- <s:property/>|
- </s:iterator>
ognl{}内为集合,iterator标签将集合中的内容遍历
由<s:property/>依次打印出来
- <s:iterator value="{'aaa', 'bbb', 'ccc'}" var="x">
- <s:property value="#x.toUpperCase()"/> |
- </s:iterator>
每次遍历将集合的元素赋予x,
在property标签中调用其转换大写方法转换为大写
- <s:iterator value="{'aaa', 'bbb', 'ccc'}" status="status">
- <s:property/> |
- 遍历过的元素总数:<s:property value="#status.count"/> |
- 遍历过的元素索引:<s:property value="#status.index"/> |
- 当前是偶数?:<s:property value="#status.even"/> |
- 当前是奇数?:<s:property value="#status.odd"/> |
- 是第一个元素吗?:<s:property value="#status.first"/> |
- 是最后一个元素吗?:<s:property value="#status.last"/>
- </s:iterator>
在iterator中有个状态标签status,有许多属性,如元素总数,索引,奇偶等,
- <s:iterator value="#{1:'a', 2:'b', 3:'c'}" >
- <s:property value="key"/> | <s:property value="value"/>
- </s:iterator>
ognl中的map写法为 键:值
用<s:property value="key">取键,value="value"取值
- <s:iterator value="#{1:'a', 2:'b', 3:'c'}" var="x">
- <s:property value="#x.key"/> | <s:property value="#x.value"/>
- </s:iterator>
用var=x代表其中一个条目,value=#x.key取这个条目的键,#x.value取这个条目的值
7.fielderror当action类中
this.addFieldError("fielderror.test", "wrong!");
前台可以用fielderror将其显示
- <s:fielderror fieldName="fielderror.test" theme="simple"></s:fielderror>
8.ui
疑问 struts.xml中的constant标签有哪些属性
- <constant name="struts.devMode" value="true"></constant> 开启热部署(开发模式)
- <constant name="struts.ognl.allowStaticMethodAccess" value="true"><constant> 允许访问静态方法
- <constant name="struts.i18n.encoding" value="GBK" />
解决中文问题
- <constant name="struts.custom.i18n.resource" value="XXXX">
- </constant>
国际化全局配置
9.struts Exception handling—声明式异常处理
在struts中 class中的方法可以在捕获异常后将其抛出,
这样可以支持struts的声明式处理任何异常。
在struts.xml中
- <global-results>
- <result name="error">/error.jsp</result>
- </global-results>
- <global-exception-mappings>
- <exception-mapping result="error"exception="java.lang.Exception">
- </exception-mapping>
- </global-exception-mappings>
必须把results写前面!
对异常做出映射,当发生java.lang.Exception时,返回error这个result.
10.struts <default-action-ref >的bug问题
该设置不会解析action的方法只会简单的将result返回BUG。
要想设置首页,目前只能在web.xml中配置
- <welcome-file-list>
- <welcome-file>index</welcome-file>
- </welcome-file-list>
11.i18n:支持程序国际化
1.i18n原理
a)ResourceBundle和Locale的概念
- ResourceBundle res = ResourceBundle.getBundle("app", Locale.CHINA);
- System.out.println(res.getString("welcome.msg" ));
b)资源文件
app_en_US.properties app_英语缩写_美国.properties
内容: welcome.msg=hello,sir
app_zh_CH.properties app_中华缩写_中国.properties
c)native2ascii jdk/bin/native2ascii 可以将中文转换成iso8859-1
2.Struts的资源文件
a)app级 见原理
b)propertiesEditor插件
i. 解压
ii. features plugin 覆盖到myeclipse中的eclipse目录里
3.Action级别国际化
a)jsp中
- <s:property value="getText('login.username')"/>
这里可以直接调用方法说明action中有这个方法
这个方法其实是Actionsupport中的方法
b)LoginAction_en_US.properties中
login.username=username:
login.password=password:
login.login=login
4.package级别国际化 在包内
package_en_US.propertiesss
5.全局级别国际化 (常用)
XXXX_en_US.properties 在src目录内
在struts.xml中配
- <constant name="struts.custom.i18n.resource" value="XXXX">
- </constant>
6.动态字符的国际化
properties中
welcome.msg=welcome:{0}
jsp文件中
- <s:text name="welcome.msg">
- <s:param value="username"></s:param>
- </s:text>
7.动态语言切换
struts中可以直接在url后传参数实现动态语言切换
"admin/lang?request_locale=en_US"
12.自定义拦截器
- <package name="test" namespace="/" extends="struts-default">
- <interceptors>
- <interceptor name="my" class="com.bjsxt.interceptor.MyInterceptor"> </interceptor>
- </interceptors>
-
- <action name="test" class="com.bjsxt.action.TestAction">
- <result>/test.jsp</result>
- <interceptor-ref name="my"></interceptor-ref>
- <interceptor-ref name="defaultStack"></interceptor-ref><!--这句话必须写否则没有系统子代的interceptor -->
- </action>
- </package>
13.使用struts的token拦截器
- <interceptor-ref name="defaultStack">
- </interceptor-ref>
- <interceptor-ref name="token">
- </interceptor-ref>
- <result name="invalid.token">/error.jsp</result>
最后一句写明当返回为invalid.token时的结果页面