一. JSP入门
1.1 JSP技术介绍
(1)为什么会出现JSP(Java Server Pages)技术?
程序员在开发过程中,发现Servlet做界面非常不方便,所以产生了jsp技术。JSP其实是对Servlet进行了包装而已。
jsp + java类(service、javabean)+ servlet,就会构成mvc的开发模式,mvc模式是目前软件公司中相当通用的开发模式。
(2)JSP是什么?
1.jsp运行在服务器
2.jsp的基础是Servlet(相当于对Servlet进行了一个包装而已)
3.jsp是一个综合技术,如下公式:
jsp = html + java片段 + JSP标签(语法) + javascript(css)
(3)JSP的特点:
JSP的全称是Java Server Pages,它和Servlet技术一样,都是SUN公司定义的一种用于开发动态web资源的技术。
jsp这门技术的最大的特点在于,写jsp就像在写HTML,但:
- 它相对于html而言,html只能为用户提供静态数据,而jsp技术允许在页面中嵌套java代码,为用户提供动态数据。
- 相比Servlet而言,Servlet很难对数据进行排版,而jsp除了可以用java代码产生动态数据的同时,也很容易对数据进行排版。
1.2 快速入门
假设我们要用jsp技术显示当前的时间。
我们在MyEclipse中新建Web项目,名字为JSP1,然后在WebRoot文件夹下,也就是Web应用的根目录下新建jsp文件,命名为showTime.jsp,这个jsp的代码如下:
<%@page import="java.util.Date"%>
<%@page language="java" pageEncoding="UTF-8"%>
<!-- lanuage表示嵌在JSP的的片段语言是什么,pageEncoding表示本页面的编码方式是什么 -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>showTime</title>
<!-- 控制让浏览器不要缓存 -->
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<!-- keywords是让搜索引擎看的 -->
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
</head>
<body>
<%
// 在<% 之间可以写我们的Java代码,就和我们在Java文件中写Java代码是一样的
// 为什么可以直接使用out对象,因为out是jsp的内置对象
// 内置对象就是不需要我们创建就能使用的对象,jsp有9大内置对象
out.println("当前时间是:"+new Date().toLocaleString());
%>
</body>
</html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
可以看到我们在html的代码中,使用了<% %>
符号嵌入了java代码,并且使用了jsp中的out这个内置对象,在jsp中,内置对象就是不需要我们创建就能使用的对象,后面会介绍到jsp有9大内置对象。
【要注意的是】
- JSP无需配置,直接使用。如果你修改了JSP文件,或者在Web应用新添加了JSP文件,都不需要重新reload该Web应用。
- 访问方法:http://ip:8080/Web应用名/JSP文件路径
我们访问该jsp页面,可以看到运行结果:
1.3 原理细节分析
1.3.1 Web服务器是如何调用并执行一个jsp页面的?
我们要知道jsp只是对Servlet的一层封装。所以它肯定和Servlet的关系密切。而实际上,Jsp页面也正是先翻译成Servlet,然后再编译加载进内存的。看如下jsp的运行过程:
如果是第一次访问该jsp文件,web服务器就会把showTime.jsp翻译成一个Servlet:showTime_jsp.java,再将其编译成一个showTime_jsp.class,然后把class加载到内存。
如果是第二次或是以后访问,它就会直接访问内存中的实例了。
我们可以在Tomcat的安装目录下找到这个被服务器翻译成的Servlet:showTime_jsp.java。在Tomcat根目录下的work文件夹中,我们一层一层向下找,可以找到如下:
从这个文件夹中,我们可以看到showTime_jsp.java,并且也能看到它编译成的class文件。我们可以打开看一下这个文件的代码,比较复杂但是其实和我们之前写的Servlet差不多,它导入的包也都是servlet的包,然后加上我们用到的java.util.Date包,如下:
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import java.util.Date;
- 1
- 2
- 3
- 4
我们可以找到最关键的代码,也就是_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("\r\n");
out.write("<!-- lanuage表示嵌在JSP的的片段语言是什么,pageEncoding表示本页面的编码方式是什么 -->\r\n");
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(" <title>showTime</title>\r\n");
out.write(" <!-- 控制让浏览器不要缓存 -->\r\n");
out.write("\t<meta http-equiv=\"pragma\" content=\"no-cache\">\r\n");
out.write("\t<meta http-equiv=\"cache-control\" content=\"no-cache\">\r\n");
out.write("\t<meta http-equiv=\"expires\" content=\"0\"> \r\n");
out.write("\t<!-- keywords是让搜索引擎看的 --> \r\n");
out.write("\t<meta http-equiv=\"keywords\" content=\"keyword1,keyword2,keyword3\">\r\n");
out.write("\t<meta http-equiv=\"description\" content=\"This is my page\">\r\n");
out.write(" </head>\r\n");
out.write(" <body>\r\n");
out.write(" ");
// 在<% 之间可以写我们的Java代码,就和我们在Java文件中写Java代码是一样的
// 为什么可以直接使用out对象,因为out是jsp的内置对象
// 内置对象就是不需要我们创建就能使用的对象,jsp有9大内置对象
out.println("当前时间是:"+new Date().toLocaleString());
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);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
可以看到代码中的许多out.write()
正是我们所写的jsp页面的内容。这也就印证了我们上面所述的结论:jsp页面是先被服务器翻译成Servlet代码,之后再编译加载进内存运行的。
所以第一次访问一个JSP页面速度比较慢,之后就会变快了。
假设某个JSP文件被修改了,那么之后的再次访问就相当于第一次访问
【注意点】
这里要特别注意的是,因为我们的服务器真正运行的是这个showTime_jsp.java文件,所以如果在测试的时候报错了,是报的这个文件的错,报错指出的错误行也指的是showTime_jsp.java这个文件的错误行,而并不是showTime.jsp这个文件的错误行。这对于我们调试代码很重要!
1.3.2 Jsp页面中的Java代码服务器是如何执行的?
假设我们在一个jsp的文件中写如下代码:
<body>
<%
int i = 90;
int j = i + 100;
%>
<h1>测试</h1>
<%
out.println("i="+i+"<br>");
out.println("j="+j);
%>
</body>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
可以看到,我们使用了两个<% %>
符号嵌入了两段java代码,并且第二段java代码使用了第一段java代码中定义的变量,这样会报错吗?
【答案】:不会的,我们可以查看服务器翻译的对应于这个jsp文件的Servlet文件,找到那个最重要的_jspService
方法,就可以看到,这几句代码都在该方法中,而定义的 i 和 j 变量不过是该方法的两个局部变量,当然可以被之后的语句使用了。
【结论】:如果有多个<% %>
这样包含的java片段,其实是相当于一个大的java片段,在这中间定义的变量会成为_jspService
函数的局部变量。
1.3.3 Web服务器在调用Jsp时,会给Jsp提供一些什么Java对象?
9个内置对象,后面会介绍到。我们现在已经使用了out这个对象,它其实就是相当于Servlet中的PrintWriter对象。