平时使用Struts2碰到的一些问题的解决方法。
Struts2使用Ajax
- 使用stream来进行服务端处理
action1
2
3
4
5
6
7
8
9
10
11public class TextResult extends ActionSupport {
private InputStream inputStream;
public InputStream getInputStream() {
return inputStream;
}
public String execute() throws Exception {
inputStream = new StringBufferInputStream("ok");
return SUCCESS;
}
}
struts.xml1
2
3
4
5
6<action name="text-result" class="actions.TextResult">
<result type="stream">
<param name="contentType">text/html </param>
<param name="inputName">inputStream </param>
</result>
</action>
- 将struts2的标签theme属性设置为ajax
这种方法要求是服务端不需要特殊处理,就像一个单纯的action处理一样,你只需要在action中进行处理,
并转向到一个jsp文件中,
在发送ajax的页面中使用 <s:a>标签,将theme属性设置为ajax,并设置接收服务器返回信息的控件id.1
2<s:a href="process.action" theme="ajax" targets="result" cssStyle="text-align:center;"/>
<div id="result"> </div>
java.util.MissingResourceException Can't find bundle for base name
解决方法:java.util.MissingResourceException Can’t find bundle for base name
这个问题的原因是MessageResource_zh_CN.properties
,这个配置文件没有放在classpath中,1
ResourceBundle config = ResourceBundle.getBundle("com.amaker.test.MessageResource");
要按照路径,把你的配置文件加入ClassPath中就可以了
解决java.lang.IllegalStateException
JSP文件或struts action(纯servlet应用中没发现此问题)中采用了,如下代码:1
2
3
4
5
6public void print2Screen(HttpServletResponse resp,String encodeString,String[] htmlCommands) throws IOException{
resp.setCharacterEncoding(encodeString);
ServletOutputStream httpOutput= resp.getOutputStream();
for(String temp:htmlCommands)
httpOutput.write(temp.getBytes());
}
深层原理:
- Servlet规范说明,不能既调用
response.getOutputStream()
,又调用response.getWriter()
,无论先调用哪一个,在调用第二个时候应会抛出IllegalStateException
. - servlet代码中有
out.write("")
,这个和JSP中缺省调用的response.getOutputStream()
产生冲突.因为在jsp中,out
变量是通过response.getWriter
得到的,在程序中既用了response.getOutputStream
,又用了out
变量,故出现以上错误。
解决方法
- 在JSP文件中,加入下面两句
1
2
3
4<%
out.clear();
out = pageContext.pushBody();
%>
此法的缺陷:
很多开发项目并不是JSP前端,如freemarker,velocity等
造成问题的response.getOutputStream()
并未被写在JSP里,而是写在servlet/action里
- 在action中,不要return 回具体的result文件,而是
return null
Struts2国际化
在src目录下添加两个资源文件,格式baseName_language_country.properties
例如message_zh_CN.properties
1
2
3
4login.title=请登录
login.username=用户名
login.password=密码
login.welcome=欢迎,{0}
message_en_US.properties
1
2
3
4login.title=Please login
login.username=Username
login.password=Password
login.welcome=Welcome,{0}
在jsp中使用1
2
3<s:text name="login.title"></s:text>
<s:textfield name="username" key="login.username"></s:textfield>
<s:textfield name="password" key="login.password"></s:textfield>
在action中使用1
2
3getText("login.username");
//使用占位符
getText("login.welcome", "user");
在jsp中实行中英文切换1
2<a href="login.action?request_locale=zh_CN">中文</a>
<a href="login.action?request_locale=en_US">English</a>
Struts2中不同namespace的重定向用法
简单的同一个包或者namespace中:1
<result name="success" type="redirectAction">xxx?a=1</result>
xxx 就是指你要重定向的action,?a=1 这个是参数的传递,你若是有参数的话可以这样传递
不同包或者不同namespace的1
2
3
4<result name="success" type="redirectAction">
<param name="actionName">xxx</param>
<param name="namespace">/xx</param>
</result>
xxx :重定向的action
/xx: xxx所在的namespace
struts2中 “#” “%” “$” 的区别和用法
表达式语言主要有以下几大好处:
- 避免
request.getAttribute()
和myBean.getMyProperty()
之类的语句,使页面更简洁; - 支持运算符(如+-*/),比普通的标志具有更高的自由度和更强的功能;
- 简单明了地表达代码逻辑,使用代码更可读与便于维护。
Struts2 中OGNL表达式的用法:
OGNL(Object-Graph Navigation Language),可以方便地操作对象属性的开源表达式语言;
“#”主要有三种用途:
- 用于过滤和投影(projecting)集合,如
books.{?#this.price<100};
- 构造Map,如
#{'foo1':'bar1', 'foo2':'bar2'}
。 - 访问OGNL上下文和Action上下文,#相当于
ActionContext.getContext();
下表有几个ActionContext中有用的属性:
名称 | 作用 | 例子 |
---|---|---|
parameters | 包含当前HTTP请求参数的Map | #parameters.id[0]作用相当于request.getParameter(“id”) |
request | 包含当前HttpServletRequest的属性(attribute)的Map | #request.userName相当于request.getAttribute(“userName”) |
session | 包含当前HttpSession的属性(attribute)的Map | #session.userName相当于session.getAttribute(“userName”) |
application | 包含当前应用的ServletContext的属性(attribute)的Map | #application.userName相当于application.getAttribute(“userName”) |
attr | 用于按request > session > application顺序访问其属性(attribute) | #attr.userName相当于按顺序在以上三个范围(scope)内读取userName属性,直到找到为止 |
“%”的用途是在标志的属性为字符串类型时,计算OGNL表达式的值。例如在Ognl.jsp中加入以下代码:1
2
3<h3>%的用途</h3>
<p><s:url value="#foobar['foo1']" /></p>
<p><s:url value="%{#foobar['foo1']}" /></p>
“$”有两个主要的用途 :
- 用于在国际化资源文件中,引用OGNL表达式
- 在Struts 2配置文件中,引用OGNL表达式,如
1
2
3
4<action name="AddPhoto" class="addPhoto">
<interceptor-ref name="fileUploadStack" />
<result type="redirect">ListPhotos.action?albumId=${albumId}</result>
</action>
Struts2 部分标签
iterator
标签
struts2中iterator标签的相关使用
struts2 的标签遍历:list<map<String,String>>
iterator
标签可以用来遍历数组,最简单的使用1
2
3
4
5List<String> days = ["Mon","Tue","Wed","Thu","Fri"];
<s:iterator value="days">
<s:property />
</s:iterator>
在iterator
中,top
可以表示当前元素,也可以携程[0].top
.[0]代表整个栈对象1
2
3
4
5<s:iterator value="days">
<s:if test="top!='Mon'">
<s:property />
</s:if>
</s:iterator>
iterator
的status
属性有如下方法:
count
: int - 返回当前迭代位置的计数(从1开始)index
: int - 返回当前迭代位置的编号(从0开始)first
: boolean - 如果当前迭代位置是第一位时返回truelast
: boolean - 如果当前迭代位置是最后一位时返回trueeven
: boolean - 如果当前迭代位置是偶数返回trueodd
: boolean - 如果当前迭代位置是奇数返回truemodulus(operand : int)
: int - 返回当前计数(从1开始)与指定操作数的模数
1 | <s:iterator value="days" status="day"> |
最后再来看下在iterator中调用value stack的用法。
假定countries是一个List对象,每一个country有一个name属性和一个citys List对象,并且每一个city也有一个name属性。那么我们想要在迭代citys时访问所属country的name属性就的用如下方式:1
2
3
4
5<s:iterator value="countries">
<s:iterator value="cities">
<s:property value="name"/>, <s:property value="[1].name"/><br>
</s:iterator>
</s:iterator>
- 这里的
<s:property value="name"/>
取的是ctiy.name;<s:property value="[1].name"/>
取得是country.name <s:property value="[1].name"/>
等价于<s:property value="[1].top.name"/>
- city处于当前栈,即top或者[0],而[1]指明了外层iterator对象,即country
- ‘[n]’标记引用开始位置为n的子栈(sub-stack),而不仅仅是位置n处的对象。因此’[0]’代表整个栈,而’[1]’是除top对象外所有的栈元素。
iterator
遍历:list<map<String,String>>1
2
3
4
5
6
7<s:iterator id="map" value="userList" status="user_state">
<s:iterator value="userList[#user_state.index]">
Key : <s:property value="key" />
Value : <s:property value="value" />
<br>
</s:iterator>
</s:iterator>
select
标签
headerKey headerValue
为设置缺省值listKey
为option的value,listValue
为option显示的选项
普通数组1
2
3
4
5<s:select list="{'aa','bb','cc'}"
theme="simple"
headerKey="00"
headerValue="00">
</s:select>
key-value映射1
2
3
4
5
6
7<s:select list="#{1:'aa',2:'bb',3:'cc'}"
label="abc"
listKey="key"
listValue="value"
headerKey="0"
headerValue="aabb">
</s:select>
1 | <% |
Struts2 s:checkboxlist 国际化
使用getText(key)
方法即可,key为国际化资源文件中的key值1
2
3<s:checkboxlist name="adminUserRoles"
theme="simple"
list="#{1:getText('aa'),2:getText('bb'),3:getText('cc')}" />
checkbox
标签
<s:checkbox>
有如下属性:id
: 标签idname
: 标签namevalue
:是否选中,值为true|false,类似checkbox中的checkedfieldValue
: 类似checkbox中的valuelabel
: 选框后面的显示描述
1 | <s:checkbox id="a" name="a" value="true" fieldValue="1" label="A" /> |