写在前边的一些话:
作为一个辅修专业的学习者,学到东西对我而言是最为重要的。JavaWeb老师给我留下了三道思考题,在此想和大家分享下我的解决问题的一个思路和方法(定义的自我重述+实例讲解,使用工具:Eclipse+Tomcat+Edge游览器)。
三个思考题
1.Request Dispatcher对象的forward方法与include方法的区别。
forward方法是指页面A得到服务器的请求B后将请求B通过forward方法提交到页面C,由页面C处理请求B,处理完后由页面C响应服务器。
Forward方法实例验证:
验证理论正确性的思路:创建两个Servlet文件,命名为A和B,文件A中需要有两种不同的输出内容,一种使用forward方法交给文件B输出,另一种由文件A输出,通过注释掉forward方法观察运行结果以形成对比。
文件A,文件B设计代码如下:
A.java
package Servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class A
*/
@WebServlet("/A")
public class A extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public A() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
request.setAttribute("string1", "forward方法,现在是文件B在处理!");
RequestDispatcher dispatcher=request.getRequestDispatcher("B");
dispatcher.forward(request, response);
PrintWriter out=response.getWriter();
out.print("现在是文件A在处理!");
}
}
B.Java
package Servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class B
*/
@WebServlet("/B")
public class B extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public B() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out=response.getWriter();
String string1=(String) request.getAttribute("string1");
out.print(string1);
}
}
此时运行文件A,可以看到以下运行结果:
接下来把文件A中的下列代码注释掉
request.setAttribute("string1", "forward方法,现在是文件B在处理!");
RequestDispatcher dispatcher=request.getRequestDispatcher("B");
dispatcher.forward(request, response);
再次运行A文件则会得到以下结果:
实际结果与理论推导相同,验证完毕。
include方法是指页面A得到服务器的请求B后将请求B通过include方法提交到页面C,待页面C处理完后,将结果反馈给页面A,最终由页面A响应服务器。
include方法实例验证:
验证理论正确性的思路:创建两个Servlet文件,命名为A和B,使用include方法将文件B包含在文件A中,运行文件A,观察结果是否与理论一致。
代码如下:
A.Java
package Servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class A
*/
@WebServlet("/A")
public class A extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public A() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
request.setAttribute("string1", "include方法,现在是文件B在处理!<br/>");
RequestDispatcher dispatcher=request.getRequestDispatcher("B");
dispatcher.include(request, response);
PrintWriter out=response.getWriter();
out.print("现在是文件A在处理!");
}
}
B.Java
package Servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class B
*/
@WebServlet("/B")
public class B extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public B() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out=response.getWriter();
String string1=(String) request.getAttribute("string1");
out.print(string1);
out.print("我已经做好了自己的工作,现在要返回文件A了!<br/>");
}
}
运行文件A得到如下结果:
2. Page指令中contentType与pageEnCoding的区别。
在说明区别之前,首先需要了解JSP文件的编译运行过程,以下提供一种理解方式:
将Jsp文件中的代码行:
<%@ page contentType="text/html;charest=UTF-8";pageEnCoding="UTF-8"%>
, 记为代码段A。令代码段A在前两次编译中保持不变。这只是一种假设以便于理解,并不考虑正确性。
(1)Jsp编译成Java文件。这时编译软件,即我们现在所使用的Eclipse会读取代码段A中的的pageEnCoding指定的编码形式(即UTF-8)进行转码编译,此时Jsp文件成功变为Java文件。
(2)Java文件编译成class文件。这时Javac即我们所安装的JDK,通过读取代码段A中的charset指定的编码形式(即UTF-8)进行转码编译,此时Java文件成功变为class文件。
(3)Tomcat将class文件运行展示给用户。这时服务器即我们所安装的Tomcat,读取代码段A中的ContentType指定的编码形式(即html页面的编码形式)进行转码编译,此时我们便可以看到成功编译后的Jsp文件了。
关于理论无法使用实例作证的思考:
我花费了一个下午来验证两者区别,但很可惜,我没能找到合适的例子,下边是我一个下午的思考和尝试.
思路:
这个问题是看出两者的区别,其核心就是保持两个指令的编码格式不同,从而有些字符的编码不同,因此在jsp文件编译后所产生的java文件于class文件就存在输入的字符乱码或不乱码的情况,以此形成对比,方能形象直观的看出两者的区别.
尝试:
第一次尝试:在同一jsp文件中令在第三阶段起作用的html页面编码格式为UTF-8,第一阶段起作用的pageEnCoding页面编码格式为IOS-8859-1,但这样做中文在第一阶段就出现了乱码,后边的编译更是乱码.
第二次尝试:交换编码格式,令第一阶段起作用的pageEnCoding页面编码格式为UTF-8,在第三阶段起作用的html页面编码格式为IOS-8859-1,按照原本的设想:这次交换后,java文件中文不乱码,class文件中文乱码,形成对比.
但是此时出现了新的问题,无论我用什么软件打开java文件,软件都会重新按照软件默认打开java文件的编码格式重新编码,但是大部分软件默认的编码模式都不是UTF-8.
想要解决这个问题我需要把esclipse的默认打开java文件的编码模式改成UTF-8.
但想要修改这个默认的编码模式,只能找到Eclipse的根目录进行修改.
在尝试根目录修改后,Eclipse不出所料的无法正常打开任何文件了,或许默认的编码模式不仅仅只在一处起关键作用,无奈只能改回默认编码,山穷水尽之后我彻底放弃了这个方法,不得不承认自己的能力确实有限,无法列举合适的实例.
3.Jsp中include指令与<jsp:include>
标签的区别(即静态包含与动态包含的区别)
静态包含是指指令<%@indude%>
:假设文件A中写有中<%@indude file="文件B"%>
,这就是文件A静态包含文件B,文件B的作用是:作为文件A的一部分,完善文件A的功能,无论文件B是否为Jsp文件。
当运行文件A时,只有文件A被编译,由于文件B是文件A的一部分,所以文件A与文件B的消息传递是在文件A中实现的。
include指令实例验证:
验证理论正确性的思路:设计三个文件,第一个为BB.jsp,第二个为AA.jsp,第三个为AB.html;接下来让BB使用include指令包含AA或者AB,通过观察Eclipse的work空间追踪编译BB文件产生的中间文件验证理论。
BB.jsp,AA.jsp,AB.html代码如下:
BB.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>静态包含</title>
</head>
<body>
这是静态包含实例!
<%@include file="AB.html" %>
</body>
</html>
AA.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>动态包含</title>
</head>
<body>
这是动态包含实例!
<jsp:include page="AB.html"></jsp:include>
</body>
</html>
AB.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
This a html file.
</body>
</html>
首先打开work空间:
可以看到当前work空间没有任何文件。
然后运行BB.jsp,同时观察work空间的变化:
可以看到BB.jsp文件编译产生的中间文件.java与.class,现在打开.java文件
可以明显看到有两个static数据,这就是文件AB作为文件BB的一部分在起作用。
现在清空work空间,将文件BB的include指令中的AB.html换成文件AA.jsp:
修改后的BB.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>静态包含</title>
</head>
<body>
这是静态包含实例!
<%@include file="AA.jsp" %>
</body>
</html>
运行文件BB观察work空间的变化:
和包含AB.html页面时一样也是只编译了BB.jsp文件,现在打开.java文件:
可以看到仍是两个static变量,include指令验证完毕。
动态包含是指标签<jsp:include>
:假设文件A中写有中<jsp:include page="文件B">
,这就是文件A动态包含文件B,文件B的作用是:作为文件A的帮手,协助文件A完成功能。
如果文件B是Jsp文件,当文件A运行时,文件A与文件B均被编译,两者之间通过request和response实现互相通信,共同工作。
如果文件B不是Jsp文件,当文件A运行时,虽然只有文件A被编译,但文件A与文件B仍是通过request和response实现互相通信,共同工作,而不是像include指令那样把文件B包含在文件A中使用,消息的传递在文件A中实现。
<jsp:inculde>
标签的实例验证:
验证理论正确性的思路:设计三个文件,第一个为AA.jsp,第二个为BB.jsp,第三个为AB.html;接下来让AA使用<jsp:include>
标签 包含BB或者AB,通过观察Eclipse的work空间追踪编译AA文件产生的中间文件验证理论。
AA.jsp,BB.jsp,AB.html代码如下:
AA.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>动态包含</title>
</head>
<body>
这是动态包含实例!
<jsp:include page="AB.html"></jsp:include>
</body>
</html>
BB.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>静态包含</title>
</head>
<body>
这是静态包含实例!
<%@include file="AB.html" %>
</body>
</html>
AB.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
This a html file.
</body>
</html>
清空work空间,运行AA.jsp文件:
可以看到动态包含html页面时仅编译了AA.jsp文件,接下来打开java文件:
可以看到只有一个static数据,这证明了<jsp:include>
标签和include指令的不同之处。
再次清空work空间,修改AA.jsp文件,使其动态包含BB.jsp文件:
修改后的AA.jsp文件代码:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>动态包含</title>
</head>
<body>
这是动态包含实例!
<jsp:include page="BB.jsp"></jsp:include>
</body>
</html>
运行文件AA,观察work空间的变化:
可以看到这次两个jsp文件均被编译,打开AA.java文件:
仍然是只有一个static数据.
结束语:
学习是一个永无止境的过程,正如钟南山院士所说:一个人什么时候停止了学习新知识,那他就真的老了。
学习新知识固然是痛苦的,但真正学会知识的那一刻,那股油然而发的自豪感和满足感才是我们最大的追求。
愿所有学习者都能不断超越自我!