浅谈Servlet的页面跳转
来源:互联网 发布:无法触碰 知乎 编辑:程序博客网 时间:2024/04/29 16:53
注意:本文的观点立足于Java和Tomcat源码
在Servlet中页面的跳转有两种方式实现:转发和重定向。
举个工作中的常见例子,测试A发现了一个问题,去找码农B,然后把问题描述和B巴拉巴拉说了一通,然后B一想这问题还得码农C处理一部分问题的,B跑过去和C巴拉巴拉描述了这个问题。这个过程就是转发。如果B听完描述后对A说:这不是我负责的事情,你应该去找码农C,然后测试A找到C重新描述了一遍这个问题。这种场景就是转发。
转发:
转发的意义在于分工,用软件工程的术语就是”分而治之“。如果比较复杂的问题可能需要分成多个步骤处理,每个步骤负责解决其中的一部分。
可以通过ServletRequest的request.getRequestDispatcher("").forward(request, response);方法转发。也可以通过
ServletContext的.getRequestDispatcher("").forward(request, response);方式转发。都要获取一个javax.servlet.RequestDispatcher对象。
我们看Tomcat关于org.apache.catalina.core.ApplicationContext转发的代码实现:
/** * Return a <code>RequestDispatcher</code> instance that acts as a * wrapper for the resource at the given path. The path must begin * with a "/" and is interpreted as relative to the current context root. * * @param path The path to the desired resource. */ @Override public RequestDispatcher getRequestDispatcher(String path) { // Validate the path argument if (path == null) return (null); if (!path.startsWith("/")) throw new IllegalArgumentException (sm.getString ("applicationContext.requestDispatcher.iae", path)); // Get query string String queryString = null; String normalizedPath = path; int pos = normalizedPath.indexOf('?'); if (pos >= 0) { queryString = normalizedPath.substring(pos + 1); normalizedPath = normalizedPath.substring(0, pos); } normalizedPath = RequestUtil.normalize(normalizedPath); if (normalizedPath == null) return (null); pos = normalizedPath.length(); // Use the thread local URI and mapping data DispatchData dd = dispatchData.get(); if (dd == null) { dd = new DispatchData(); dispatchData.set(dd); } MessageBytes uriMB = dd.uriMB; uriMB.recycle(); // Use the thread local mapping data MappingData mappingData = dd.mappingData; // Map the URI CharChunk uriCC = uriMB.getCharChunk(); try { uriCC.append(context.getPath(), 0, context.getPath().length()); /* * Ignore any trailing path params (separated by ';') for mapping * purposes */ int semicolon = normalizedPath.indexOf(';'); if (pos >= 0 && semicolon > pos) { semicolon = -1; } uriCC.append(normalizedPath, 0, semicolon > 0 ? semicolon : pos); service.getMapper().map(context, uriMB, mappingData); if (mappingData.wrapper == null) { return (null); } /* * Append any trailing path params (separated by ';') that were * ignored for mapping purposes, so that they're reflected in the * RequestDispatcher's requestURI */ if (semicolon > 0) { uriCC.append(normalizedPath, semicolon, pos - semicolon); } } catch (Exception e) { // Should never happen log(sm.getString("applicationContext.mapping.error"), e); return (null); } Wrapper wrapper = mappingData.wrapper; String wrapperPath = mappingData.wrapperPath.toString(); String pathInfo = mappingData.pathInfo.toString(); mappingData.recycle(); // Construct a RequestDispatcher to process this request return new ApplicationDispatcher (wrapper, uriCC.toString(), wrapperPath, pathInfo, queryString, null); }这个对应的是ServletContext的实现方式。下面看ServletRequest的转发实现源码:
/** * Return a RequestDispatcher that wraps the resource at the specified * path, which may be interpreted as relative to the current request path. * * @param path Path of the resource to be wrapped */ @Override public RequestDispatcher getRequestDispatcher(String path) { if (context == null) return (null); // If the path is already context-relative, just pass it through if (path == null) return (null); else if (path.startsWith("/")) return (context.getServletContext().getRequestDispatcher(path)); // Convert a request-relative path to a context-relative one String servletPath = (String) getAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH); if (servletPath == null) servletPath = getServletPath(); // Add the path info, if there is any String pathInfo = getPathInfo(); String requestPath = null; if (pathInfo == null) { requestPath = servletPath; } else { requestPath = servletPath + pathInfo; } int pos = requestPath.lastIndexOf('/'); String relative = null; if (pos >= 0) { relative = requestPath.substring(0, pos + 1) + path; } else { relative = requestPath + path; } return (context.getServletContext().getRequestDispatcher(relative)); }
可以看出来org.apache.catalina.core.ApplicationHttpRequest的getRequestDispatcher方式将相对路径转换成了相对于根上下文的绝对路径。
所以通过Request获得的转发支持绝对路径和相对路径,而通过ServletContext获取的RequestDispatcher只支持绝对路径,并且绝对路径不要包含应用名。
重定向
重定向是服务器告诉浏览器去重新请求另外一个有效的URL。可以使用javax.servlet.http.HttpServletResponse.sendRedirect(String)方法实现。
区别:
首先转发是服务器端的行为而重定向是客户端的行为。转发只能发生在应用内而重定向可以跨站跨应用。服务器转发的时候浏览器客户端感知不到,而当浏览器重定向时,浏览器地址的URL也相对会变成新的URL。重定向一次其实浏览器发送了两次请求。
不积跬步无以致千里
1 0
- 浅谈Servlet的页面跳转
- Servlet的页面跳转
- Servlet的页面跳转
- Servlet的页面跳转
- servlet跳转页面的方法
- Servlet的页面跳转方式
- servlet的后台页面跳转和ajax的页面跳转
- Servlet几种页面跳转的区别
- servlet 跳转页面乱码的问题
- Servlet几种页面跳转的区别
- servlet跳转页面的几种方法
- servlet跳转页面的几种方法
- servlet跳转页面的几种方法
- Servlet页面跳转实现方法的区别
- Servlet几种页面跳转的区别
- Servlet几种页面跳转的区别
- Servlet页面跳转实现方法的区别
- Servlet页面跳转实现方法的区别
- Android Studio代码着色插件
- java线程之间通讯
- Composer安装说明
- HDU5692 Snacks(dfs序 + 线段树)
- 使用eclipse开发servlet
- 浅谈Servlet的页面跳转
- [Android] CircleView 仿小米空气净化器首页旋转UI
- 博客评论时间显示算法
- [SCU 4509] Snowdrop修长廊 (斜率DP)
- web服务器 java实现
- OnPress长按事件
- LeetCode 133. Clone Graph(克隆图)
- Apache Solr查询语法
- android开发中build文件删除不了的问题