20120321struts
Struts2
1,<s:hidden>保存本页面其它控件的值(只能是字符串)。
<s:textfield name="loginInfo.loginId" label="Employee ID" labelposition="left" />
<s:hidden name="selectedPerson.personId" value="%{loginInfo.loginId}"/>
而如果要保存其它类型数据时会出错,如
<s:hidden name="LRId" value="leaveInfoTable.id"></s:hidden>,其中leaveInfoTable.id为int类型,出错:
java.lang.NumberFormatException: For input string: "leaveInfoTable.id"
at java.lang.NumberFormatException.forInputString(Unknown Source)
除非使用<s:hidden name="leaveInfoTable.id"></s:hidden>来直接传值(即只是用来连接两个action,而在jsp页面中不对改值进行修改),可以保持正确的数据类型。
2,struts2的autocompleter
首先,把struts2-json-plugin-2.3.1.jar拷贝到web-inf/lib下。
然后,jsp中添加:
<s:url var="olUrl" namespace="/autocompleter" action="getOlMg.action" />
<sx:autocompleter name="olGroup" keyName="leaveInfo.olManager"
label="Ol Manger" labelposition="left" href="%{#olUrl}" forceValidOption="true" />
(forceValidOption="true" 强制用户只能输入下拉列表中的列表项)
随后,添加相应action文件(AutoCOL.java),其中的执行方法为:
public Map<String, String> getOptions() {
Map<String, String> options = new HashMap<String, String>();
List pl = epService.getAutoComp("OL");
Iterator pit = pl.iterator();
while (pit.hasNext()) {
Object[] objs= (Object[])pit.next();
String sValue = (String)objs[0];
String sKey = (String)objs[1];
options.put(sValue, sKey);
}
return options;
}
public Map<String, String> getChoices() {
Map<String, String> choices = new HashMap<String, String>();
List pl = epService.getAutoComp("DM");
Iterator pit = pl.iterator();
while (pit.hasNext()) {
Object[] objs= (Object[])pit.next();
String sValue = (String)objs[0];
String sKey = (String)objs[1];
choices.put(sValue, sKey);
}
return choices;
}
最后,struts.xml中声明:
<package name="autocompleter" namespace="/autocompleter"
extends="json-default">
<action name="getOlMg" class="org.wed.action.AutoCOL">
<result type="json">
<param name="root">options</param>
</result>
</action>
<action name="getDeptMg" class="org.wed.action.AutoCOL">
<result type="json">
<param name="root">choices</param>
</result>
</action>
</package>
sx:autocompleter因为这个组件是分为两部分的,value为显示的内容,key为实际需要传递的值。所以当为这个组件设置
keyName(即普通组件的name)后,该属性的值将传递到这个sx:autocompleter的keyVallue(即普通组件的value)里,这个值是保存在一个隐藏域里的。而sx:autocompleter的文本框将不显示内容。只能通过选择更改为其它值,要转换成空值,必须先选中一个然后退格删掉。
用以下方法实现显示action传进来的初始值:
String olFullName = DisplayWrapper.sso2Fullname(olSso);
request.setAttribute("olFullName", olFullName);
在jsp页面中,设置该autoCompleter:
value="%{#request.olFullName}"
3,<s:if test="%{leaveRecord!=null}">的问题,测试条件总是为true。
应该用<s:if test="%{!leaveRecord.isEmpty()}">
4,sx:div的jsp片段里javascript不执行问题
首先把js放在要显示的jsp片段里,而在主页面的sx:div里设置executeScripts="true"后,还是出错,是j_security_check相关的错误,是JAAS验证出问题?哪个js文件进不来?
后来把jsp片段里需要用到的js放到主页面jsp里,能够运行了。但debug模式下会显示:Error running scripts from content:Syntax error
把executeScripts="true"去掉之后,Error running scripts from content:Syntax error错误消失了。
而在sx:head里加parseContent="true"与否没有什么关系。
5,table中对应不同列的参数值的传递(每一列的sx:a)
<table border="1em">
<s:iterator value="leaveRecord" id="record">
<s:url action="EpViewLR.action" var="url_d01" namespace="/ep">
<s:param name="LRId" value="#record.leaveId" />
</s:url>
<s:url action="EpEditLR.action" var="url_d02" namespace="/ep">
<s:param name="LRId" value="#record.leaveId" />
</s:url>
<tr>
<td><s:property value="#record.raiseDate" /></td>
<td>
<sx:a targets="divOne" href="%{url_d01}">View</sx:a>
<sx:a targets="divOne" href="%{url_d02}">Edit</sx:a>
</td>
</tr>
</s:iterator>
</table>
而在action中,用
HttpServletRequest request = ServletActionContext.getRequest();
String id = request.getParameter("LRId");
来获取该参数。
6,数据(例如一个Person类)从action到jsp,在该jsp的form提交后再到下一个action。如果在中间这个jsp的form中没有包含相关的属性(例如person.name),则这个属性将不会从原action传播到目标action。
于是采用<s:hidden name="leaveInfo.leaveId"></s:hidden>的方法来传递一些不需要显示的数据。
但是如果属性是类的话,如Person类的leaveInfo.requestor属性,直接用<s:hidden name="leaveInfo.requestor"></s:hidden>的话会报错。
对于类的key属性,要注意传递,否则无法用hibernate恢复持久化。
鉴于这种传递的复杂,决定在目标action里根据key重新载入LeaveInfo类对象,然后根据jsp中修改的数据进行修改,并保存。
7,<s:property>传值失败问题
<s:property value="#showRecord[#st.index].toD" />
改为
<s:property value="%{showRecord[#st.index].toD}" />
之后可以了。(在struts2标签内部要用%{}来取值)
8,<s:include value="EpNaviBar.jsp"></s:include>注意其中value值,同样要考虑路径问题,应该是相对于当前主页面的相对路径。
如主页面是WEB-INF/jsp/ep/main.jsp,而引入的是WEB-INF/jsp/in.jsp,则value应设置为value="../in.jsp"。
而如果主页面和引入页面在同一个文件夹下,则可以直接用文件名。
9,注意<result>中,type="redirectAction"和type="redirect"的区别。
<!-- Redirect to another namespace -->
<action name="login" class="...">
<result type="redirectAction">
<param name="actionName">dashboard</param>
<param name="namespace">/secure</param>
</result>
</action>
<-- Redirect to an action in the same namespace -->
<action name="dashboard" class="...">
<result>dashboard.jsp</result>
<result name="error" type="redirectAction">error</result>
</action>
<result name="success" type="redirect">
<param name="location">foo.jsp</param>
<param name="parse">false</param>
<param name="anchor">FRAGMENT</param>
</result>
10,<s:if test="%{xxx}">,其中xxx的表达式的值为true或false。
当表达式是对字符串的处理时,字符串用单引号(有提到单双引号位置交换,即外面单引号,里面双引号)。
<s:set name="sts" value="#tElement.status" />
<s:a href="%{url_d01}">View</s:a>
<s:if test="%{sts.contains('unsub')}">
<s:a href="%{url_d02}">Edit</s:a>
<s:a href="%{url_d03}">Delete</s:a>
</s:if>
<s:elseif test="%{sts.contains('waiting')}">
<s:a href="%{url_d03}">Delete</s:a>
</s:elseif>
11,sx和s的区别,sx可以直接使用dojo的消息发送接收模式。
12,使用visitor validation产生的错误
a
ERROR com.opensymphony.xwork2.validator.AnnotationActionValidatorManager.error:38 - Caught exception while loading file org/wed/action/CreateLRAction-validation.xml
www.opensymphony.com - [unknown location]
Reason for the above error is clear from http://www.opensymphony.com
Looking for an OpenSymphony project? Unfortunately, OpenSymphony has seen it's final days.
All the URLs to www.opensymphony.com including the URL for the DTD is now pointed to the home page. So the XML parser cannot retrieve the DTD to validate the workflow xml file. If you have a production app that uses osworkflow jar, what do you do to get the app working again?
解决方法:
将validation的xml文件中的声明
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.3//EN"
"http://www.opensymphony.com/xwork/xwork-validator-1.0.3.dtd">
改为
<!DOCTYPE validators PUBLIC
"-//Apache Struts//XWork Validator 1.0.3//EN"
"http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
(该出处在xwork的jar包里面的模板里)
b 必须要有<result name="input">。。。</result>,否则会报错。
不管是客户端检验还是服务器检验,不通过时都会跳转到input页面。
c 对于autocompleter这种复合组件,如果直接对其对应的属性(如leaveInfo.olManager进行校验,则由于该值对应的是一个隐藏域,所以错误信息不会显示)。但是如果在页面上显示添加<s:fielderror/>将可以显示该错误信息。
DatetimePicker可以直接校验其对应的属性值,校验错误会显示(因为其对应的属性值是和文本框,而不是和隐藏域相关联的)。
http://blog.csdn.net/jadyer/article/details/6176122
13,手动完成输入校验,重写validate();
validation()会自动免除对cancel的检验。
14,<s:head/>包含格式信息
15,表单中按钮点击不实现提交表单而是其他功能。
使用<s:submit type="button" onclick="flipDate()" />,还是不行,直接用<input>元素可以。
16,对于<sx:div id="divTwo" loadingText="loading..." showLoadingText="true" href="%{#url_01}"/>,其中的loadingText和showLoadingText设置是为加载href信息时呈现的。
为实现点击按钮时目标区域出现loadingText内容,要在submit中设置:
<sx:submit value="Search" targets="divTwo" showLoadingText="true" loadingText="loading..."/>
17,
使用<s:url action="OlEditLR.action" var="url_d01" namespace="/ol" method="edit">,
点击无法进入对应方法,报如下错误:
The requested resource (/Wednesday/ol/OlEditLR.action!edit) is not available.
Action中的method应该在struts.xml中对action进行声明时使用,如:
<action name="OlEditLR" class="org.wed.action.OlChooseLRAction" method="edit">。
或者是在如下情况时使用:
<s:form action="EditLRAction" namespace="/ol">
...
<s:submit value="Approve" align="center" method="approve" />
</s:form>
这可以进入对应方法。
18,从action到jsp到action的传值。<s:property>标签仅用于显示从action传到jsp中的值,而无法承担接着从本jsp传到下一个action的功能:<s:property value="dayRecordOld.annualDays" />
19,对于有targets的sx:submit按钮的表单进行校验时,出错的话会在targets所指定的div里显示input页面。
对于这种表单的服务器校验该怎么完成????
20,检测session中是否有用户信息的interceptor
<interceptors>
<interceptor name="SessIntcept" class="org.wed.action.SessionIntcept">
</interceptor>
<interceptor-stack name="myDefault">
<interceptor-ref name="defaultStack" />
<interceptor-ref name="SessIntcept" />
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="myDefault" />
<global-results>
<result name="tologin" type="redirectAction">
<param name="actionName">login.action</param>
<param name="namespace">/</param>
</result>
</global-results>
SessionIntcept.java文件
privatestaticfinal String TOLOGIN = "tologin";
privatestaticfinal Log logger = LogFactory.getLog(SessionIntcept.class);
public String intercept(ActionInvocation invocation) throws Exception {
logger.info("INTO SESSION-INTCEPT ...");
String result = "";
HttpServletRequest request = ServletActionContext.getRequest();
HttpSession sess = request.getSession();
boolean bt = sess.isNew();
//does UserInSession exist in session
boolean boolUserNull = (sess.getAttribute("userInSession")==null);
if (!boolUserNull) {
logger.info("USER EXISTS IN SESSION");
result = invocation.invoke();
} else {
logger.info("USER DOES NOT EXIST IN SESSION");
result = TOLOGIN;
}
return result;
}
如果session中不存在userInSession信息,则跳转去执行login.action(执行该action前会自动启动jaas验证,而login.action只是为了jaas验证之后在session里存储userInSession)。
21,在service层里设计edit函数时,应该将其返回值设为boolean,以便根据其执行的成功与否在web层进行相应的操作。(在这里用作多个HR操作LR的并发性处理)
22,客户端检验(dojo)
<script type="text/javascript">
dojo.event.topic.subscribe("/before", function(event, widget){
var fdt = dojo.widget.byId("fromdate").getValue();
var tdt = dojo.widget.byId("todate").getValue();
if(fdt>tdt){
alert('fromDate should not after toDate!');
event.cancel = true;
dojo.widget.byId("todate").setValue(fdt);
}
//event: set event.cancel = true, to cancel request
//widget: widget that published the topic
});
</script>
////
<sx:submit value="Search" targets="divOne" beforeNotifyTopics="/before"
showLoadingText="true" loadingText="loading..." />
23,在sx:div显示的内容(jsp片段)里要有js的问题
首先把js放在要显示的jsp片段里,而在主页面的sx:div里设置executeScripts="true"后,还是出错,是j_security_check相关的错误,是JAAS验证出问题?哪个js文件进不来?
后来把jsp片段里需要用到的js放到主页面jsp里,能够运行了。但debug模式下会显示:Error running scripts from content:Syntax error
把executeScripts="true"去掉之后,Error running scripts from content:Syntax error错误消失了。
而在sx:head里加parseContent="true"与否没有什么关系。
24,即使在同一个页面里,如果<s:a>或者<s:submit>不在form里的话,form里的参数是无法从jsp传到action里来的。
25,用struts的exception跳转页面来处理并发引起的错误。
<package name="ep" extends="struts-default" namespace="/ep">
<global-results>
<result name="transfalse">/WEB-INF/jsp/ep/EpHome.jsp</result>
</global-results>
<global-exception-mappings>
<exception-mapping result="transfalse" exception="java.lang.Exception" />
</global-exception-mappings>
... ...
</package>
两个hr同时操作LR的问题的解决,在对LR进行edit之前检查该LR的状态,若不存在报错则跟以上情况一样;若存在但状态已改变则不修改。
26,JAAS的form验证所用的两个页面()
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/WEB-INF/jsp/login.jsp</form-login-page>
<form-error-page>/WEB-INF/jsp/loginError.jsp</form-error-page>
</form-login-config>
</login-config>
都不能用struts2标签,否则会报错,因为不是由struts的dispatcher来跳转的。
27,表单中文本框输入的值怎么传到action里(在使用sx:a,非提交表格的情况下)
通过使用formId来实现:
<sx:a targets="checkDiv" href="%{url_id}" formId="tarr">Check ID</sx:a>
这样就能动态传递id为tarr的form里的值了。
28,json类型的result
为了返回两个object,一开始用:
<result type="json">
<param name="root">playera,playerb</param>
</result>
结果返回只有一个playera的数据,后来把<param name="root">playera,playerb</param>去掉,结果可以返回两个对象了。
在页面文件中取对应的数据:
$.ajax({
url : "myjson/startg",
success : function(data) {
var ainhand = data.playera.inhand;
}
……
29,通过.ajax函数从jsp向action传递数组时,出错:Malformed OGNL expression: relative[] [ognl.ParseException: Encountered " "]" "] ""。
http://www.iflym.com/index.php/code/201110110001.html
这个错误是因为,jquery在传递数组类参数时,将不再遵循1.3时如f=x&f=y的参数传递了,而是采用了像php一样,带中括号的参数传递。js值 {f:["x","y"]},将被转化成f[]=x&f[]=y,而这种参数形式传递到后台时,使用struts2.1.8版本时,就会出现以上的错误形式。
struts2一直能够识别的模式仅是f=x&f=y这样,当后台声明f为一个list或set时,就会把x,y分别加入到list或set中。而如果是f[]这种形式,则会报相应的转换错误。
解决此问题的方法很简单,在进行ajax请求时,追加一条以下语句即可:
$.ajaxSettings.traditional=true;
这是一个全局参数,故可以在引入jquery.js之后进行声明。此参数的意思在于,使用$.param时,将采用旧的jquery1.3版本的param生成方式进行处理。