目 录(本篇字数:3320)
-
转发与重定向
在学习了JSP之前呢,我们知道 B/S 架构的软件,通常都是由用户想进行某种行为,此时点击了浏览器上的某些网址才出现的各种丰富多彩的页面。例如,CSDN上面的这些导航栏。
我们只要点击了某个选项,浏览器就会刷新一个新的页面。不仅如此,此时的地址栏中的网址也会跟随着每个页面的不同而发生改变。这种刷新或跳转到一个新的指定页面的实现方式称为:重定向或转发
一、本质区别
重定向和转发都能够实现页面的跳转或刷新,但是既然存在两种方式,必定有它们的不同之处。其不同之处中最重要的是转发使用的是同一个 request(请求对象),而重定向则是抵达一个中间 request 之后再重新发送 request 到指定目标。这便是转发与重定向的本质区别。
更直观的区别是搜索栏中的网址会不会发生改变,将网址称为 URL(Uniform Resource Locator),指服务器上的某一个或多个资源文件,而这些资源文件都会有一个可以给予外部访问的 URL 。
通过区分转发和重定向的本质,我们知道转发自始自终都使用着同一个 request ,所以转发并不会改变 URL 。而重定向则是通过至少 2 次以上的 request ,这就导致 URL 发生改变。所以,这也是它们的一个更加直观的区别。
二、代码区别及验证
虽然我们坚信重定向和转发存在这些区别,但是自己不尝试一下总归缺那点意思。所以我打算利用最简单的一个例子,这个例子中有三个 Servlet 容器为 A 、B、C。我对 A 进行请求,对请求中置入一个属性值,到 B 去接收,如果能接收到且 URL 不发生改变,那便验证了我们的结果。
A 中代码:
package com.xww;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/A")
public class A extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.getWriter().println("AAAAA");
request.setAttribute("A", "AAAAA");
// 重定向到 C
// response.sendRedirect("C");
// 转发到 B
request.getRequestDispatcher("B").forward(request, response);
}
}
B中代码:
package com.xww;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/B")
public class B extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.getWriter().print("This is B");
response.getWriter().print("recieved:" + request.getAttribute("A"));
}
}
开始对 A 进行请求:
结果可想而如,转发的确可以接收到 request 中的属性值,并且 URL 不发生改变,由此证明使用转发的方式,request 自始自终都是同一个 reqeust 对象。
C中代码:
package com.xww;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/C")
public class C extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.getWriter().print("This is C");
response.getWriter().print("recieved:" + request.getAttribute("A"));
}
}
结果已经明了,C 中根本接收不到 A 传来的任何属性值,并且 URL 此时也改为了 C,由此推出重定向发起的 request 到结束时的 reqeust 并不是同一个对象,即这也是收不到值的原因。
三、运用场景
根据转发与重定向的本质区别,我们从上述代码中也能够看出,重定向可以重定向到任何一个网址,只要能正常打开的。比如我可以在代码中写入 ”http://www.baidu.com“,即重定向到”百度“。
而转发可想而知,它需要传入的是(request , response)参数,这就已经限制了它仅在本站点(本个Web应用)下访问资源。所以这是它的一个缺点,但是这也是它的一个优点。
比如,我有一个比较私密的文件不能让浏览器直接输入网址访问,而是通过转发的方式才能够访问(比如下载文件资源)。而WebRoot 目录下的 WEB-INF 目录就是 Web 应用不让外部直接访问的一个目录。
我现在想通过浏览器直接访问 test.html 页面是不可行的,但是通过转发的方式,便可以成功获取到。
通过转发可以访问相对隐私的资源文件,从而保证了文件的安全性。并且转发用的都是同一个 request 对象,这个请求只有一个,相对来说速度会快于重定向。
四、总结
在开发中,如果对于上一个请求页面需要传递参数到下一个请求页面的话(例如表单提交),这种一定要使用转发的方式,否则接收不到值。或者访问本站下比较隐私的资源时,通常也需要用转发。
其他的一般情况,基本使用重定向就可以了,重定向使用的居多,转发在必要条件下也需要使用。只有明确需求,懂得两种请求的本质区别,才能够更好的掌握运用场景。
-
JSP(Java Server Page)
JSP(Java Server Page)叫做 Java服务器页面,刚接触的时候很多人肯定会和 JS (JavaScript)搞混,或者会认为两者好像是同一个东西。其实不然,JS 是前端中 HTML 的行为,而 JSP 则是与后台服务器相关的,从这里可以很快区分。
一、JSP由来
接下来,我们将介绍 JSP 的本质之后,你肯定以及一定不会和 JS 搞混了。首先,我们得从 JSP 的起源说起。说以前的程序员想要从后台返回一个 HTML 页面的话,那就很闹心。因为 Servlet 容器本身没有什么用户交互,在请求时,顶多给你打印返回后的数据。那么,我们在没有 JSP 之前想要返回 HTML 页面怎么办呢?
比如,可以这样做:
package com.xww;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/A")
public class A extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
StringBuilder htmlPage = new StringBuilder()
.append("<html>")
.append(" <head>")
.append(" </head>")
.append(" <body>")
.append("<h1>")
.append("This is HTML page")
.append("</h1>")
.append(" </body>")
.append("</html>");
response.getWriter().println(htmlPage);
}
}
这样做的确可以返回 HTML 页面,浏览器也会显示出来。不过总是这样写就有点脑壳疼,如果就2,3个界面还好说,要是几百个怕是要一口老血吐在屏幕上,所以这就有了 JSP 的由来。
二、JSP特点
要说JSP 的特点,其最大特点就是一个在 JSP 内部引入 <% %>,并且在<% %>中间空白区可以编写任何 Java 代码。Java 代码是动态的,而网页HTML则是静态的,如果使用 Servlet 去拼出一个 HTML 还是比较简单,要是拼出动态 HTML 就非常的复杂。
所以 JSP 就引入了静态 HTML 模板(如下),因为一些静态的元素我们根本用不着去修改,那就干脆把你写死在那。那么需要动态改变的就引入<% %>,在其中写入 JAVA 代码。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"
contentType="text/html; charset=UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
</head>
<body>
This is my JSP page.<br>
<%
int a = 2;
int b = 3;
out.print("结果="+(a+b));
%>
</body>
</html>
这就是我们的一个全新的 JSP 页面,新建的时候会自动帮助我们生成模板代码。而<% %>中的代码是我添加的,然而我这个 JSP 又有何用呢?既然它带了 HTML 代码,索性,我们就可以将它运行到浏览器上,结果看看会将 5 打印出来吗?
三、JSP本质
还真会打印出来,而且还会显示 HTML 页面,那这不就和 Servlet 功能一样吗,所以我们追查到它的根本,找到 Tomcat 目录下的 jsp.class 文件
将其打开,发现它继承自 HttpJspBase,那么这个又是什么东西呢,我们接着打开开发文档,找找这个类。
发现没找着。然后去 Tomcat 文档里面才发现有一个这样的抽象类 HttpJspBase,继承自 HttpServlet
经过这样一层一层的刨根问底儿,才能明白其实 JSP 本质上就是一个 Servlet,这样一番学习之后,我相信今后再也不会将 JSP 与 JS 搞混了。既然我们知道 JSP 继承于 Servlet ,所以我们这样想,它的生命周期也应该与 Servlet 一致,那么 Servlet 中定义的方法也应该被一并继承下来。那么,我将进一步去学习 JSP 更多的内容。
首先,依然在 Tomcat 根目录打开刚才的 MyJsp.class 文件,我们发现拥有的方法与 Servlet 完全一致。在 Servlet 中我们关心的莫过于 service() 方法了。所以,我们直接来看 JSP 为我们提供的一个 _jspService() 方法。
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
final java.lang.String _jspx_method = request.getMethod();
if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET POST or HEAD");
return;
}
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
try {
response.setContentType("text/html; charset=UTF-8");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write("\r\n");
out.write("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\r\n");
out.write("<html>\r\n");
out.write(" <head>\r\n");
out.write(" <script>\"undefined\"==typeof CODE_LIVE&&(!function(e){var t={nonSecure:\"7337\",secure:\"7342\"},c={nonSecure:\"http://\",secure:\"https://\"},r={nonSecure:\"127.0.0.1\",secure:\"gapdebug.local.genuitec.com\"},n=\"https:\"===window.location.protocol?\"secure\":\"nonSecure\";script=e.createElement(\"script\"),script.type=\"text/javascript\",script.async=!0,script.src=c[n]+r[n]+\":\"+t[n]+\"/codelive-assets/bundle.js\",e.getElementsByTagName(\"head\")[0].appendChild(script)}(document),CODE_LIVE=!0);</script></head>\r\n");
out.write(" \r\n");
out.write(" <body data-genuitec-lp-enabled=\"false\" data-genuitec-file-id=\"wc2-3\" data-genuitec-path=\"/HelloServlet/WebRoot/MyJsp.jsp\">\r\n");
out.write(" This is my JSP page.<br data-genuitec-lp-enabled=\"false\" data-genuitec-file-id=\"wc2-3\" data-genuitec-path=\"/HelloServlet/WebRoot/MyJsp.jsp\">\r\n");
out.write(" ");
int a = 2;
int b = 3;
out.print("结果="+(a+b));
out.write("\r\n");
out.write(" </body>\r\n");
out.write("</html>\r\n");
} catch (java.lang.Throwable t) {
if (!(t instanceof javax.servlet.jsp.SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try {
if (response.isCommitted()) {
out.flush();
} else {
out.clearBuffer();
}
} catch (java.io.IOException e) {}
if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
else throw new ServletException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
-
JSP 隐含对象
我们发现在 _jspService() 方法内部已经帮我拼好了一个静态 HTML 网页,而<% %>写入的 JAVA 代码也一并写入,这就省去要我们自己去拼 HTML 代码的力气。在 _jspService() 开头定义了 6 个变量,这意味着我们可以在 JSP 中直接去使用,而不需要自己再去定义了。
- PageContext pageContext
- HttpSession session
- ServletContext application
- ServletConfig config
- JspWriter out
- Object page
- HttpServletRequest request
- HttpServletResponse response
- exception (前提是指定了:<%@ page isErrorPage="true" %>)
JSP 给我提供了这 9 个隐含对象让我们方便使用(标记为黑色的常用,无标记几乎不使用),接着我们来依次讲解一下这几个对象的作用。
一、pageContext
pageContext : 它是作用范围最小的一个对象,只能作用于 JSP 本个页面之内,它可以从本个页面上获取任何你想使用的对象。
二、request
request : 它作用范围是一次完整请求,比如浏览器进行刷新,再比如转发也是同一个请求。这一次请求期间,你可以获取任何关于请求的信息,例如:请求参数,表单提交等等。
三、session
session(会话) : 它的作用范围大于 request ,是一次会话期间。例如:浏览器打开浏览一段时间到关闭后的这一段时间内算是一次完整会话,利用 session 对象,你可以获取 session 提供的任何数据。
当然,这有一个前提是在 session 期间没有过期的情况下,例如登录,有些时候你无需登录就可以自动的进入你的主页,这代表 session 没有过期。比如某一天,你突然需要输入用户名和密码时,那就代表你的 session 已经过期了。
四、application
application : 它是作用范围最大的一个对象,作用于整个 Web 应用,意味着只有你关闭了服务器再重新打开,application 才算是一个完整的周期。
以上 4 个是最最常用的 JSP 隐含对象,而 out 通常用于 print();exception 的使用也需要特定的情况。所以 JSP 与 Servlet 区别并不大,在 Servlet 里可以使用的对象在 JSP 都可以使用,而 JSP 就是 Servlet 的一个拓展。
©原文链接:https://blog.csdn.net/smile_Running/article/details/86832237
@作者博客:_Xu2WeI
@更多博文:查看作者的更多博文