您的位置:首页 > 其它

登录后自动跳转与继续提交及有关ONGL的问题

2009-12-16 21:24 316 查看
花了很长的时间,一直在写BoardAction,除了,前面提到的hibernate的懒加载等问题外,另外一个就是登录后自动跳转与继续提交及有关ONGL的问题了.

先说登录后自动跳转:

如果用户直接进入登录页面,则登录成功后返回到欢迎页面.这个就是很普通的处理.

如果是因为在提交表单时,被权限控制拦截器,转到登录页面,则,我们希望

1:登录成功后,能够返回到先前的页面.或者:

2:登录成功后,将提交的内容继续提交.

在实际实现这个功能时,思路倒是很清晰,主要卡在了ONGL的应用.问题总结如下:

1、什么时候使用"#",这个struts文档和相关教程都讲得比较清楚:对于“Value Stack Contents”值栈里的内容可以不用,对于“Stack Context”里的内容要使用,在使用debug标签时,也有提示:These items are available using the #key notation 。

2、什么时候使用“%{}”,呵,这可是个问题,我很多时间都花在了这里。不断地加上,去掉,不断地重启Tom。到目前还搞不大清楚,英文能力又差,文档看了看,没发现在哪里写这个,手头的教程没说这事。对于property标签,他的value=不用%{},对于其他表单标签中的name/value等需要使用。

3、怎么把.jsp中的变量,放到struts标签当中。

在jsp中使用request.getHeader("Referer")是能很方便的得到来源网址的,但这个值,使用struts标签怎么也无法引用,因为使用#request取的值是Stack Context中的request, <s:property value="#request.getHeader('Referer')"/>没有显示任何内容,当然如果仅是显示,不需要使用struts标签。而无论是否使用%{}或#都会报错,今天在配置strtus.xml 中 注意到了<param/>这玩意。这会就可以这样实现了:

<s:textfield>

<s:param name="name">redir</s:param>
<s:param name="value"><%=url%></s:param>
</s:textfield>

而使用<s:textfield name="" value="" />怎么写,也没办法把url的值取出来。如果非得使用这样的格式写,并把url的值赋给这个textfield,那么也许只有先用set 标签把值放到值栈中再引用了,但在使用set 的标签时一样还是要使用param.

这点点的总结,花了好几天的时间呢。唉。。。。

好了,下面说如何跳转了,跳转时要注意一个namespace的问题,在测试中我把boardmanager.jsp放在/admin目录下,在原先的struts.xml配置中没有设置namespace,如果是先登录好,然后访问/admin/boardmanager.jsp提交更新等操作,正常。

但是如果未登录前访问/admin/boardmanager.jsp,权限拦截器换到login.jsp,登录成功后,会报错,大致就是这个namespace下没有相应的action.因此要设置好namespace,这个在设计前要有一个统一的规划。

由于登录有很多种,可以是在提交数据时被拦截到,要求登录,也可以是只访问一个jsp页面被拦截,还有就是直接访问登录页面。

因此要为不同的情况设置result ,在struts2进行动态设置,方法就是在login.action 新增成员变量redirect指定跳转到哪个页面。

在第一次做测试时,result 的type属性我也动态设置,结果老是报错404错说说是null result没指定什么的。也许是因为不同的返回类型它的参数是不一样的,因此不能用<param name="type">这种方法来动态指定。后来,我就直接在login.action中return不同的逻辑视图名,如果是要到welcome.jsp就返回SUCCESS,如果是要继续提交则返回"redirect"(可能这个语义是不合适,用chain可合适吧),然后设置<result name="redirect" type="chain" />并用<param>参数分别动态指定namespace 和 actionName。

如何取得登录前提交的数据和向谁提交呢?在使用<debug>标签后,我看到了Stack Context下的request里有“javax.servlet.forward.servlet_path”,它的值正是登录前,想要提交的方向。在Stack Context下的parameters里记录了登录前提交的数据。于是,把javax.servlet.forward.servlet_path的值赋给一个struts的form标签,实际应用中应使用hidden标签。parameters是一个HashMap,可以使用keySet()及iterator标签,迭代产生一系列的hidden,并把它们放置在form内,这样当submit时提交用户名和密码的,会把登录前提交的内容再交提交,并通过chain这种方式,传给目标action!

整个过程是这样的:

用户访问了一个页面--这个页面中有一个form--用户提交数据--拦截器发现用户尚未登录--要求用户登录--登录成功后继续提交数据。

看一下代码:

<action name="login" class="login">
<result name="redirect" type = "chain">
<param name="namespace">${namespace}</param>
<param name="actionName">${redirect}</param>
</result>
<result name="success">/welcome.jsp</result>
<result name="login">/login.jsp</result>
</action>

上面是配置,主要就是分别不同的逻辑视图设置type,并动态的指定namespace和actionName

public String execute() throws Exception { //login.action的execute
user = userService.findByLogin(user.getUserId(), user.getPassword());
if (user != null) {
ActionContext.getContext().getSession().put("user", user);
if (redirect == null) {
redirect = "/welcome.jsp";
return SUCCESS;
} else {
if (redirect.endsWith("action")) {
redirect = redirect.replaceAll(".action", ""); //注意:要把传过来的值的后面的.action去了,因为在struts中,action的name后面是没有.action的。
String s[] = redirect.split("/"); //从句起,是将namespace和action分离成两个变量。
StringBuffer stringBuffer = new StringBuffer();
System.out.println(redirect);
System.out.println(s.length);
if (s.length > 1) {
for (int i = 0; i < s.length - 1; i++)
stringBuffer.append(s[i]+"/");
redirect = s[s.length - 1];
namespace = stringBuffer.substring(0, stringBuffer.length()- 1);
}

}
System.out.println("namespace:" + namespace);
System.out.println("action:" + redirect);
return "redirect";
}
} else {
addFieldError("user.userID", "登录失败,请检查用户名或密码!");
return LOGIN;
}

}

如果跳转到一个jsp页面,而不是提交数据,相应的,也应当把前面的http://..../去了。

对于如何将登录前的请求继续提交,是否可以先把相应的内容放到session中,登录成功后,再从session中取,再转给相应的action呢?这个没试,感觉很麻烦,思路不如前面的方法清晰!

对于如果用户登录失败,跳转或继续提交,刚才测试失败了,当然,原因很简单,如果登录失败,来源网址及请求数据都发生了变化,因些,对登录失败的情况,还要做处理。

刚才看到一个网友写的教程,说:“%”符号的用途是在标志的属性为字符串类型时,计算OGNL表达式的值。

“#”主要有三种用途:
1. 访问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属性,直到找到为止
2. 用于过滤和投影(projecting)集合,如books.{?#this.price<100};
3. 构造Map,如#{'foo1':'bar1', 'foo2':'bar2'}。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: