(1)什么是jsp呢?为什么会出现jsp?
①jsp翻译过来就是java server page也就是java服务页面,是运行在服务器端的脚本。其是一个特殊的servlet类。至于为什么出现jsp技术,其实很简单在jsp没有出现之前页面都是用Servlet写出来的,对于程序员来说很麻烦,所以才出现了jsp技术。因为jsp被翻译成一个Servlet类,换而言之,jsp也是一个单例。当web服务器第一次调用jsp页面时,会将jsp页面翻译程一个Servlet类的.java文件,然后编译成.class文件加载到内存中,然后执行并且返回给浏览器端,所以第一次访问jsp资源速度比较慢。当第二次在请求jsp页面时,会直接请求内存中于jsp页面对应的.class文件并且响应给浏览器。如果jsp页面有修改后浏览器端请求该jsp页面,服务器则会重新将jsp翻译成Servlet类的.java文件然后编译程.class文件再次存放到内存中,并且执行响应给浏览器端。
②jsp这门技术最大的特点在于,写jsp就像是在写html和java代码一样。但是它相比html而言,html只能为用户提供静态数据,而jsp技术允许在页面中嵌入java代码,为用户提供动态数据。相比servlet而言,servlet很难对页面进行排版,而jsp除了可以用java代码产生动态数据的同时,也很容易实现页面的排版。
(2)jsp包括了哪些内容呢?
这里用一个表达式来表示:jsp=html+css+java片段+javascript+jsp语法
①服务器是如何将jsp中的html发送到客户端呢?
②服务器端是如何执行jsp中的java代码的?
要想深入连接这些问题首先我们写一个jsp页面来运行并且找到其翻译程的Servlet类就很容易明白了。
jsp代码如下index.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
int i=9;
int j=8;
%>
<h1>这是一个jsp页面</h1>
<%
out.println("i+j="+(i+j));
%>
</body>
</html>
翻译成的Servlet类index_jsp.java:
/*
* Generated by the Jasper component of Apache Tomcat
* Version: Apache Tomcat/7.0.67
* Generated at: 2016-12-19 08:08:25 UTC
* Note: The last modified time of this file was set to
* the last modified time of the source file after
* generation to assist with modification tracking.
*/
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent {
private static final javax.servlet.jsp.JspFactory _jspxFactory =
javax.servlet.jsp.JspFactory.getDefaultFactory();
private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;
private volatile javax.el.ExpressionFactory _el_expressionfactory;
private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;
public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
return _jspx_dependants;
}
public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
if (_el_expressionfactory == null) {
synchronized (this) {
if (_el_expressionfactory == null) {
_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
}
}
}
return _el_expressionfactory;
}
public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
if (_jsp_instancemanager == null) {
synchronized (this) {
if (_jsp_instancemanager == null) {
_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
}
}
}
return _jsp_instancemanager;
}
public void _jspInit() {
}
public void _jspDestroy() {
}
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
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\" \"http://www.w3.org/TR/html4/loose.dtd\">\r\n");
out.write("<html>\r\n");
out.write("<head>\r\n");
out.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\r\n");
out.write("<title>Insert title here</title>\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n");
out.write("\t");
int i=9;
int j=8;
out.write("\r\n");
out.write("\t<h1>这是一个jsp页面</h1>\r\n");
out.write("\t");
out.println("i+j="+(i+j));
out.write("\r\n");
out.write("</body>\r\n");
out.write("</html>");
} 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);
}
}
}
从上面的index_jsp.java可以看的出来翻译过后的Serlvet类有一个_jspService()方法,html部分的代码都被包含在_jspService()方法中通过响应对象的输出流响应给浏览器端的。,这个方法就相当于我们学习的Servlet类的service()方法。每次请求jsp页面都会执行_jspService()方法,来给浏览器端做响应处理。而且很容易看的出来<% %>中的java代码都被按照顺序直接翻译到了_jspService()方法中,所以理所当然jsp中可以包含java片段并且能够照常执行。
(3)jsp语法包括哪些呢?
①指令元素,指令元素主要包括两种
1.一个是<%@page %>叫做page指令,其有一下属性如图:
具体的用法这里就不过多的写了,大家可以直接尝试。
2.<%@include file="filename"%>称为引入指令。该指令用于引入一个文件(通常是jsp文件),jsp引擎会把两个jsp文件翻译成一个Servlet文件,因此也称为静态引入。特别需要注意的是静态引入jsp文件只需保留jsp文件中page指令和body里面的内容,html,body标签都需要删除,因为不删除jsp引擎在把两个jsp页面翻译成一个Servlet时就会有冲突。
具体的例子如下:
这是需要引入的jsp文件include1.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>我是引入文件的jsp</title>
</head>
<body>
<h1>你们好啊</h1>
<div>
<%@include file="include2.jsp" %>
</div>
</body>
</html>
这是被引入的页面include2.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<h2>我是被引入的jsp文件</h2>
可见jsp引擎将两个jsp翻译成了include1_jsp.java的Servlet类,jsp引擎并没有把include2.jsp也翻译成Servlet类,那么看一下其源码:
/*
* Generated by the Jasper component of Apache Tomcat
* Version: Apache Tomcat/7.0.67
* Generated at: 2016-12-19 08:40:30 UTC
* Note: The last modified time of this file was set to
* the last modified time of the source file after
* generation to assist with modification tracking.
*/
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
public final class include1_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent {
private static final javax.servlet.jsp.JspFactory _jspxFactory =
javax.servlet.jsp.JspFactory.getDefaultFactory();
private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;
static {
_jspx_dependants = new java.util.HashMap<java.lang.String,java.lang.Long>(1);
_jspx_dependants.put("/include2.jsp", Long.valueOf(1482136763459L));
}
private volatile javax.el.ExpressionFactory _el_expressionfactory;
private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;
public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
return _jspx_dependants;
}
public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
if (_el_expressionfactory == null) {
synchronized (this) {
if (_el_expressionfactory == null) {
_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
}
}
}
return _el_expressionfactory;
}
public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
if (_jsp_instancemanager == null) {
synchronized (this) {
if (_jsp_instancemanager == null) {
_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
}
}
}
return _jsp_instancemanager;
}
public void _jspInit() {
}
public void _jspDestroy() {
}
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
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\" \"http://www.w3.org/TR/html4/loose.dtd\">\r\n");
out.write("<html>\r\n");
out.write("<head>\r\n");
out.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\r\n");
out.write("<title>我是引入文件的jsp</title>\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n");
out.write("<h1>你们好啊</h1>\r\n");
out.write("<div>\r\n");
out.write("\r\n");
out.write("<h2>我是被引入的jsp文件</h2>");
out.write("\r\n");
out.write("</div>\r\n");
out.write("</body>\r\n");
out.write("</html>");
} 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);
}
}
}
从_jspService()方法可以很清晰的看的处理被引入的include2.jsp的内容被直接添加到include1.jsp中,并且在哪里被引入,内容就会被放到哪里。
②脚本元素,脚本元素主要有四个<% %>,<%=%>,<%! %>,<%----%>
举例说明一下四个脚本元素jsp页面script.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>用来说明脚本元素的</title>
</head>
<body>
<!-- 这里是html的注释 -->
<%--这里是用来做注释的 --%>
<%--这里是小脚本 --%>
<%
int i=9;
int j=9;
%>
<h1>这是用来说明jsp脚本元素的</h1>
<%
int b=i+j;
%>
<%--这里是表达式 --%>
<h2><%=b%></h2>
<h3><%=(b+i+j) %></h3>
<%--这里是申明一个变量 --%>
<%!String str="Hello";
String str2="World";
%>
<%--这里是申明一个方法 --%>
<h4><%=(str+str2) %></h4>
<%!
public int test(int a,int b){
return a+b;
}
%>
<h5><%=test(5,6) %></h5>
</body>
</html>
翻译成的Servlet类script_jsp.java如下:
/*
* Generated by the Jasper component of Apache Tomcat
* Version: Apache Tomcat/7.0.67
* Generated at: 2016-12-19 09:18:47 UTC
* Note: The last modified time of this file was set to
* the last modified time of the source file after
* generation to assist with modification tracking.
*/
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
public final class script_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent {
//这里是脚本元素申明的变量
String str="Hello";
String str2="World";
//这里是在脚本元素申明的方法
public int test(int a,int b){
return a+b;
}
private static final javax.servlet.jsp.JspFactory _jspxFactory =
javax.servlet.jsp.JspFactory.getDefaultFactory();
private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;
private volatile javax.el.ExpressionFactory _el_expressionfactory;
private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;
public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
return _jspx_dependants;
}
public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
if (_el_expressionfactory == null) {
synchronized (this) {
if (_el_expressionfactory == null) {
_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
}
}
}
return _el_expressionfactory;
}
public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
if (_jsp_instancemanager == null) {
synchronized (this) {
if (_jsp_instancemanager == null) {
_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
}
}
}
return _jsp_instancemanager;
}
public void _jspInit() {
}
public void _jspDestroy() {
}
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
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\" \"http://www.w3.org/TR/html4/loose.dtd\">\r\n");
out.write("<html>\r\n");
out.write("<head>\r\n");
out.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\r\n");
out.write("<title>用来说明脚本元素的</title>\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n");
out.write("\t");
out.write('\r');
out.write('\n');
out.write(' ');
out.write('\r');
out.write('\n');
out.write(' ');
int i=9;
int j=9;
out.write("\r\n");
out.write("\t<h1>这是用来说明jsp脚本元素的</h1>\r\n");
out.write("\t");
int b=i+j;
out.write('\r');
out.write('\n');
out.write(' ');
out.write("\r\n");
out.write("\t<h2>");
out.print(b);
out.write("</h2>\r\n");
out.write("\t<h3>");
out.print((b+i+j) );
out.write("</h3>\r\n");
out.write("\t");
out.write('\r');
out.write('\n');
out.write(' ');
out.write('\r');
out.write('\n');
out.write(' ');
out.write("\r\n");
out.write("\t<h4>");
out.print((str+str2) );
out.write("</h4>\r\n");
out.write("\t");
out.write("\r\n");
out.write("\t<h5>");
out.print(test(5,6) );
out.write("</h5>\r\n");
out.write("\t\r\n");
out.write("</body>\r\n");
out.write("</html>");
} 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);
}
}
}
运行结果如下:
从上面翻译的Servlet类很容易看出来:
1.<%%>小脚本元素,在小脚本里可以写我们的java逻辑代码,从上面翻译的Servlet能看的出来小脚本里的内容直接添加到_jspService()方法中。也真是因为小脚本里的内容是直接添加到_jspService()方法中的,所以
在小脚本中是不能申明一个方法的,因为java是不允许在方法中直接申明方法的。
2.<%=%>表达式,表达式里面可以写一个值或者一个表达式。
3.<%!%>申明,申明中可以定义一个变量也可以是一个方法,仔细看翻译过后的Servlet,在申明中定义的变量和方法都被定义成了Servlet类的成员方法和成员变量。
4.<%----%>注释,要说明的是用脚本元素进行注释的内容不会通过Servlet类输出,所以在页面中也找不到其任何的踪迹。而<!---->这种html注释方式则会被Servlet翻译并且输出。所以开发时用<%----%>进行
注释来节省宽带的消耗,如下图浏览器端的源码:
③动作元素主要有如下图:
其中重要和常用的就是<jsp:forward ><jsp:include>来实现页面之间的转发和request.getDispatcher("/web资源").forward(reqeust,response)方法效果一样。还有一点很重要的服务器保护机制WEB-INF
下的文件是不能通过浏览器直接访问的。只能在Servlet类中(jsp的动作元素forward也是可以的,因为jsp也是一个特殊的Servlet类)转发和重定向才能访问到WEB-INF目录下的web资源。
<jsp:include>的案例如下:
index.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>转发</title>
</head>
<body>
<div>
<jsp:include page="/a.jsp"></jsp:include>
</div>
</body>
</html>
a.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>a.jsp</title>
</head>
<body>
<h1>我是a.jsp</h1>
</body>
</html>
jsp引擎分别将index.jsp和a.jsp都翻译成了Servlet类,截图如下:
浏览器客户端的源码截图:
所以通过<jsp:include page="资源名“>称为动态引入,jsp引擎会将引入的文件也翻译成Servlet类,所以被引入的文件中就可以包含html,body等标签,当引入时服务器会自动做处理在响应给浏览器端。其和
指令元素的<%@include file="filename"%>的区别就在于此。