页面跳转到BackURL功能(基于struts2实现)
应用场景:
在查询用户列表/user!list.action时,点击新增用户,将跳转到/user!input.action
现在需要新增成功后跳转到/user!list.action
常规的做法是在UserAction里定义一个Result=RELOAD, location = "user!list.action", type = "redirect"
但是现在有这样的需求:
在查询用户列表/user!list.action,作了一些查询,分页的操作后,可能你的页面地址就变成了:
/user!list.action?page.no=5&page.size=20&searchParam=searchValue
如果此时你点击新增用户,需要新增完毕仍回到刚才操作过的页面,因为这个页面地址已经无法预料,你无法再Action里配置
所以现在需要实现这样的功能,能方便跳回之前操作的页面
目前实现的大致思路如下:
1.首先当跳转到新增页面时,一定要把跳回的URL地址带上,如:
/user!input.action?BackURL=/user!list.action?page.no=5&page.size=20&searchParam=searchValue
带上的地址为了不影响浏览器解析原地址,已改将BackURL的值URL Encode如下
/user!input.action?BackURL=%2Fuser%21list.action%3Fpage.no%3D5%26page.size%3D20%26searchParam%3DsearchValue
2.当新增页面提交时,要将BackURL一并提交给服务器,所以最简单的做法是在Form表单加上一个隐藏域:
<input type="hidden" name="BackURL" value="${param['BackURL']}">
或者提交表单时动态修改提交的URL为/user!save.action?BackURL=%2Fuser%21list.action%3Fpage.no%3D5%26page.size%3D20%26searchParam%3DsearchValue
3.新增用户页面/user!input.action会将请求提交给UserAciton的save方法处理
4.为了做到通用,一般web项目都会自定义一个类似AuthorityInterceptor来鉴权的拦截器
从request里提取backUrl的方法extractBackURL每个人实现都不太一样,我的实现是这样的:
到此跳转的基本功能都已实现,但是有几个问题,还需要更完善一下:
1.不是每个页面传了BackURL参数,你就需要给它跳回BackURL指定的页面,如
/user!input.action?BackURL=/user!list.action?page.no=5&page.size=20&searchParam=searchValue
当进入新增用户界面时,也会经过BackURLPreResultListener监听器处理。
而真正要处理的只是save方法执行后要跳转
所以我们还得为这段代码加一个开关,即什么时候执行,什么时候不执行,改造过后的代码如下:
即检查request里是否有Attribute,key为Const.ENABLE_BACK_URL,value为True,如果有,则视为当前action方法执行完后需要跳转
而在save方法里我们应该往request里给这个开关变量赋值True
save方法里返回RELOAD改不改都无所谓,因为后面BackURLPreResultListener会把这个执行结果改成NONE的
在此基本上整个功能都已实现完毕,但是还有一个小小的缺憾:
一般在save方法里,我们都会加如下代码:来让页面可以展示保存成功的消息:
addActionMessage("保存用户成功!");
因为Struts2里的MessageStoreInterceptor会将这些消息存在session里,等Reload的方法list执行完毕后才会清空,这样在list页面我们依然能取到save方法里放进去的提示消息
而MessageStoreInterceptor判断是否需要将消息存在session里的逻辑是
save方法返回的结果Result是否是redirect类型的,具体可以参考源代码逻辑:
所以我们知道struts2框架的部分运行逻辑后,可以很容易得出我们的解决方法:
即在struts.xml配置文件中,新增一个全局的result:
而此处${#request['backUrl']}的 表达式写法可以从request里拿出真正需要跳转的backUrl的地址
我们只要将BackURLPreResultListener修改如下,就可以让我们的跳转经过MessageStoreInterceptor处理
在查询用户列表/user!list.action时,点击新增用户,将跳转到/user!input.action
现在需要新增成功后跳转到/user!list.action
常规的做法是在UserAction里定义一个Result=RELOAD, location = "user!list.action", type = "redirect"
但是现在有这样的需求:
在查询用户列表/user!list.action,作了一些查询,分页的操作后,可能你的页面地址就变成了:
/user!list.action?page.no=5&page.size=20&searchParam=searchValue
如果此时你点击新增用户,需要新增完毕仍回到刚才操作过的页面,因为这个页面地址已经无法预料,你无法再Action里配置
所以现在需要实现这样的功能,能方便跳回之前操作的页面
目前实现的大致思路如下:
1.首先当跳转到新增页面时,一定要把跳回的URL地址带上,如:
/user!input.action?BackURL=/user!list.action?page.no=5&page.size=20&searchParam=searchValue
带上的地址为了不影响浏览器解析原地址,已改将BackURL的值URL Encode如下
/user!input.action?BackURL=%2Fuser%21list.action%3Fpage.no%3D5%26page.size%3D20%26searchParam%3DsearchValue
2.当新增页面提交时,要将BackURL一并提交给服务器,所以最简单的做法是在Form表单加上一个隐藏域:
<input type="hidden" name="BackURL" value="${param['BackURL']}">
或者提交表单时动态修改提交的URL为/user!save.action?BackURL=%2Fuser%21list.action%3Fpage.no%3D5%26page.size%3D20%26searchParam%3DsearchValue
3.新增用户页面/user!input.action会将请求提交给UserAciton的save方法处理
- public String save() throws Exception {
- //...
- userService.save(user);
- //...
- return RELOAD;
- }
4.为了做到通用,一般web项目都会自定义一个类似AuthorityInterceptor来鉴权的拦截器
- public class AuthorityInterceptor extends AbstractInterceptor {
- public String intercept(ActionInvocation invocation) throws Exception {
- //...
- //此处注册一个Action结果前处理监听器,action的方法执行完,在返回结果视图之前会调用此监听器
- //我们的核心逻辑都在这个监听器BackURLPreResultListener完成。
- invocation.addPreResultListener(new BackURLPreResultListener());
- String invokeResult = invocation.invoke();
- return invokeResult;
- }
- }
- public class BackURLPreResultListener implements PreResultListener {
- @Override
- public void beforeResult(ActionInvocation invocation, String resultCode) {
- // handle backUrl
- HttpServletRequest request = ServletActionContext.getRequest();
- String backURL = extractBackURL(request);
- ServletActionContext.getResponse().sendRedirect(backURL);
- invocation.setResultCode(Action.NONE);
- }
- }
从request里提取backUrl的方法extractBackURL每个人实现都不太一样,我的实现是这样的:
- /**
- * 上一次请求的地址
- * 1、先从request.parameter中查找BackURL
- * 2、先从request.attribute中查找BackURL
- * 3、先从request.Referer header中查找BackURL,即当前请求是从哪个页面触发的
- */
- private String extractBackURL(HttpServletRequest request) {
- String url = request.getParameter(Const.BACK_URL);
- if (url == null) {
- url = (String) request.getAttribute(Const.BACK_URL);
- }
- if (url == null) {
- url = (String) request.getHeader("Referer");
- }
- if (!StringUtils.isEmpty(url) && url.startsWith(request.getContextPath())) {
- url = getBasePath(request) + url;
- }
- return url;
- }
- private String getBasePath(HttpServletRequest req) {
- StringBuffer baseUrl = new StringBuffer();
- String scheme = req.getScheme();
- int port = req.getServerPort();
- baseUrl.append(scheme); // http, https
- baseUrl.append("://");
- baseUrl.append(req.getServerName());
- if ((scheme.equals("http") && port != 80) || (scheme.equals("https") && port != 443)) {
- baseUrl.append(':');
- baseUrl.append(req.getServerPort());
- }
- return baseUrl.toString();
- }
到此跳转的基本功能都已实现,但是有几个问题,还需要更完善一下:
1.不是每个页面传了BackURL参数,你就需要给它跳回BackURL指定的页面,如
/user!input.action?BackURL=/user!list.action?page.no=5&page.size=20&searchParam=searchValue
当进入新增用户界面时,也会经过BackURLPreResultListener监听器处理。
而真正要处理的只是save方法执行后要跳转
所以我们还得为这段代码加一个开关,即什么时候执行,什么时候不执行,改造过后的代码如下:
- public class BackURLPreResultListener implements PreResultListener {
- @Override
- public void beforeResult(ActionInvocation invocation, String resultCode) {
- // handle backUrl
- HttpServletRequest request = ServletActionContext.getRequest();
- if (Boolean.TRUE.equals(request.getAttribute(Const.ENABLE_BACK_URL))) {
- String backURL = extractBackURL(request);
- if (StringUtils.isNotBlank(backURL)) {
- ServletActionContext.getResponse().sendRedirect(backURL);
- invocation.setResultCode(Action.NONE);
- }
- }
- }
- }
即检查request里是否有Attribute,key为Const.ENABLE_BACK_URL,value为True,如果有,则视为当前action方法执行完后需要跳转
而在save方法里我们应该往request里给这个开关变量赋值True
- public String save() throws Exception {
- //...
- userService.save(user);
- //...
- ServletActionContext.getRequest().setAttribute(Const.ENABLE_BACK_URL, Boolean.TRUE);
- return RELOAD;
- }
save方法里返回RELOAD改不改都无所谓,因为后面BackURLPreResultListener会把这个执行结果改成NONE的
在此基本上整个功能都已实现完毕,但是还有一个小小的缺憾:
一般在save方法里,我们都会加如下代码:来让页面可以展示保存成功的消息:
addActionMessage("保存用户成功!");
因为Struts2里的MessageStoreInterceptor会将这些消息存在session里,等Reload的方法list执行完毕后才会清空,这样在list页面我们依然能取到save方法里放进去的提示消息
而MessageStoreInterceptor判断是否需要将消息存在session里的逻辑是
save方法返回的结果Result是否是redirect类型的,具体可以参考源代码逻辑:
- protected void after(ActionInvocation invocation, String result) throws Exception {
- String reqOperationMode = getRequestOperationMode(invocation);
- //result的类型是redirect时才会把actionMessage放入session里
- boolean isRedirect = invocation.getResult() instanceof ServletRedirectResult;
- if (STORE_MODE.equalsIgnoreCase(reqOperationMode) ||
- STORE_MODE.equalsIgnoreCase(operationMode) ||
- (AUTOMATIC_MODE.equalsIgnoreCase(operationMode) && isRedirect)) {
- Object action = invocation.getAction();
- if (action instanceof ValidationAware) {
- // store error / messages into session
- Map session = (Map) invocation.getInvocationContext().get(ActionContext.SESSION);
- LOG.debug("store action ["+action+"] error/messages into session ");
- ValidationAware validationAwareAction = (ValidationAware) action;
- session.put(actionErrorsSessionKey, validationAwareAction.getActionErrors());
- session.put(actionMessagesSessionKey, validationAwareAction.getActionMessages());
- session.put(fieldErrorsSessionKey, validationAwareAction.getFieldErrors());
- }
- else {
- LOG.debug("Action ["+action+"] is not ValidationAware, no message / error that are storeable");
- }
- }
- }
所以我们知道struts2框架的部分运行逻辑后,可以很容易得出我们的解决方法:
即在struts.xml配置文件中,新增一个全局的result:
- <global-results>
- ...
- <!-- 在此处定义redirect的backUrl主要是为了利用struts2拦截器MessageStoreInterceptor的便利,即重定向后,actionMessage里的数据都不会丢失 -->
- <result name="backUrl" type="redirect">${#request['backUrl']}</result>
- </global-results>
而此处${#request['backUrl']}的 表达式写法可以从request里拿出真正需要跳转的backUrl的地址
我们只要将BackURLPreResultListener修改如下,就可以让我们的跳转经过MessageStoreInterceptor处理
- public class BackURLPreResultListener implements PreResultListener {
- @Override
- public void beforeResult(ActionInvocation invocation, String resultCode) {
- // handle backUrl
- HttpServletRequest request = ServletActionContext.getRequest();
- if (Boolean.TRUE.equals(request.getAttribute(Const.ENABLE_BACK_URL))) {
- String backURL = extractBackURL(request);
- if (StringUtils.isNotBlank(backURL)) {
- //此处不使用response.sendRedirect来重定向,主要是为了利用struts2拦截器MessageStoreInterceptor的便利,即重定向后,actionMessage里的数据都不会丢失的功能
- //ServletActionContext.getResponse().sendRedirect(backURL);
- ServletActionContext.getRequest().setAttribute("backUrl", backURL);
- invocation.setResultCode("backUrl");
- }
- }
- }
- }
相关推荐
特别是在页面跳转方面,JS提供了多种方式来实现这一功能,这些方法各有特点,适用于不同的场景需求。下面将详细介绍几种常见的JS页面跳转技术及其应用场景。 ### 1. 使用`window.location.href` 这是最常用的一种...
在Web开发中,页面跳转是非常常见的操作,JavaScript提供了多种方式来实现页面跳转。在本文中,我们将总结多种JavaScript页面跳转代码,包括使用window.location.href、window.history.back、window.navigate、self....
### JavaScript 实现页面跳转的几种方式 在Web开发中,页面跳转是十分常见的操作之一。通过JavaScript,我们可以非常灵活地控制页面的导航逻辑,提高用户体验并优化应用性能。本文将详细介绍几种常用的JavaScript...
sp\button和submit的区别及使用js实现页面跳转的方式 Button和Submit是两个常用的HTML表单元素,它们都是用于提交表单的,但是它们之间存在着一些区别。 首先,Button类型的按钮仅仅是一个普通的按钮,点击它不会...
页面跳转在Web开发中是一项非常基础且重要的功能,它涉及到用户在不同页面之间的导航与交互。JavaScript提供了多种方式来实现页面跳转,每种方法都有其特点和适用场景。 1. **`window.location.href`** - **语法**...
JS 跳转页面方法是指使用 JavaScript 实现页面跳转的方法,这些方法可以在 Web 开发中广泛应用。下面将对 JS 跳转页面方法进行详细的介绍和分析,并提供相应的参考代码。 JS 跳转页面方法 1. 使用 `window....
### JavaScript 页面跳转...不同的方法适用于不同的场景,开发者应根据具体需求选择合适的方法来实现页面跳转功能。值得注意的是,对于废弃的方法(如`window.navigate()`),应避免使用以确保代码的兼容性和可维护性。
此段代码用于实现页面跳转功能。`window.location.href`属性可以用来获取或设置当前窗口的位置(URL)。在本例中,代码将当前页面URL作为参数追加到目标URL(`login.jsp`)之后,然后重新定向至新URL。这种方式常...
对于嵌套的页面结构,可以通过改变顶层窗口的 URL 来实现跳转。 ```javascript top.location = 'xx.jsp'; ``` #### 三、使用对话框进行确认或提示后跳转 ##### 1. 使用 `confirm` 这种方式会在跳转之前弹出一个...
本文将详细解释如何使用JavaScript控制页面跳转的五种方法,并展示如何使用JavaScript实现自动跳转到其他页面的功能。 首先,介绍五种使用JavaScript控制页面跳转的方法: 1. 使用window.location.href属性 window...
在Web开发过程中,页面跳转是一个常见的需求,而JavaScript提供了多种方式来实现页面之间的跳转。接下来,我们将详细介绍几种常用且具有代表...在选择页面跳转技术实现时,既要考虑功能性,也要兼顾用户体验和安全性。
在JavaScript中,页面跳转是常见的操作,通常用于导航用户到新的URL或执行回退操作。以下将详细介绍JS实现页面跳转的五种方法: 1. **使用`window.location.href`**: 这是最常见的方式,通过设置`window.location...
首先,我们来看第一种方式,通过`window.location.href`属性来实现跳转。这个方法是最常见也最直接的页面跳转方式。例如: ```javascript window.location.href = "login.jsp?backurl=" + window.location.href; ```...
本文实例总结了Javascript页面跳转常见实现方式。分享给大家供大家参考,具体如下: 概述 相信很多Web开发者都知道,在开发Web程序的时候,对于页面之间的跳转,有很多种,但是有效的跳转则事半功倍,下面就是我在...
在网页开发中,有时我们需要实现页面的自动跳转功能,以解决各种场景的需求,比如错误页重定向、页面更新提示等。本文将详细介绍如何利用HTML的`<meta>`标签和JavaScript来实现页面跳转,并讨论它们各自的优缺点。 ...
在JavaScript中,页面跳转是实现用户交互和页面动态导航的关键功能。以下是对标题和描述中涉及的各种JavaScript跳转方式的详细解释: 1. **利用`window.location.href`跳转**: 这是最常见的跳转方式,通过设置`...