1.为什么需要JSP?
在很多动态网页中,绝大部分内容都是固定不变的,只有局部内容需要动态产生和改变。如果使用Servlet程序来输出只有局部内容需要改动的网页,其中所有的静态内容也需要程序员用java程序代码产生,整个Servlet程序的代码将非常臃肿,编写和维护都非常困难。对大量静态内容的美工设计和相关HTML语句的编写,并不是程序员所要做的工作,程序员对此也不一定在行。网页美工设计和制作人员不懂java编程,更是无法完成这样的工作。为了弥补Servlet的缺陷,SUN公司在Servlet的基础上推出了JSP技术作为解决方案。
2.什么是JSP?
JSP全称是Java Server Pages,它和servle技术一样,都是SUN公司定义的一种用于开发动态web资源的技术。JSP这门技术的最大的特点在于,写jsp就像在写html,但它相比html而言,html只能为用户提供静态数据,而Jsp技术允许在页面中嵌套java代码,为用户提供动态数据。
3.如何在MyEclipse中运行jsp文件?
jsp文件一般放在WebRoot文件夹下,可以在WebRoot目录下新建一个文件用来放jsp文件。例如如下的文件目录:
示例中新建了一个helloWorld.jsp文件,Jsp技术允许在页面中嵌套java代码,规定java代码写在<% %>内部,代码如下:
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'helloWorld.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<%
Date date=new Date();
System.out.println(date);
%>
</body>
</html>
.jsp文件放在WebRoot目录下的非WEB-INF文件夹下是不需要在web.xml中进行配置的。右击直接运行就可以。
为了减少风险,可以把jsp文件移到WEB-INF 目录下。基于Servlet的声明,WEB-INF不作为Web应用的公共文档树的一部分。因此,WEB-INF 目录下的资源不是为客户直接服务的。我们仍然可以使用WEB-INF目录下的JSP页面来提供视图给客户,客户却不能直接请求访问JSP。放在WEB-INF 目录下需要在web.xml中进行配置。配置方法与servlet的配置一样,只不过是将<servlet-class></servlet-class>标签改为<jsp-file></jsp-file>,标签内填的内容是“/jsp文件所在的文件夹名/jsp文件名”。配置后运行,右击jsp文件,Run As MyEclipse Server Application。运行后显示结果如下:
4.JSP原理
4.1 web服务器是如何调用并执行一个jsp页面的?
浏览器向服务器发请求,不管访问的是什么资源,其实都是在访问Servlet,所以当访问一个jsp页面时,其实也是在访问一个Servlet,服务器在执行jsp的时候,首先把jsp翻译成一个Servlet,所以我们访问jsp时,其实不是在访问jsp,而是在访问jsp翻译过后的那个Servlet,比如上面的helloWorld.jsp文件,当我们通过浏览器访问helloWorld.jsp时,服务器首先将helloWorld.jsp翻译成一个helloWorld.class,(文件路径可以参考:E:\MyEclipseWorkSpace\.metadata\.me_tcat85\work\Catalina\localhost\MyWebProject\org\apache\jsp\jspTest,其中MyEclipseWorkSpace为项目所在的工程目录),helloWorld.class的源代码文件helloWorld.java的代码如下:
/*
* Generated by the Jasper component of Apache Tomcat
* Version: Apache Tomcat/8.5.9
* Generated at: 2018-10-12 09:24:04 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.jspTest;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import java.util.*;
public final class helloWorld_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {
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 static final java.util.Set<java.lang.String> _jspx_imports_packages;
private static final java.util.Set<java.lang.String> _jspx_imports_classes;
static {
_jspx_imports_packages = new java.util.HashSet<>();
_jspx_imports_packages.add("javax.servlet");
_jspx_imports_packages.add("java.util");
_jspx_imports_packages.add("javax.servlet.http");
_jspx_imports_packages.add("javax.servlet.jsp");
_jspx_imports_classes = null;
}
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 java.util.Set<java.lang.String> getPackageImports() {
return _jspx_imports_packages;
}
public java.util.Set<java.lang.String> getClassImports() {
return _jspx_imports_classes;
}
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 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=ISO-8859-1");
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');
out.write('\n');
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
out.write("\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(" <base href=\"");
out.print(basePath);
out.write("\">\r\n");
out.write(" \r\n");
out.write(" <title>My JSP 'helloWorld.jsp' starting page</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<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("\t<!--\r\n");
out.write("\t<link rel=\"stylesheet\" type=\"text/css\" href=\"styles.css\">\r\n");
out.write("\t-->\r\n");
out.write("\r\n");
out.write(" <script>\"undefined\"==typeof CODE_LIVE&&(!function(e){var t={nonSecure:\"51550\",secure:\"51555\"},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=\"wc1-1\" data-genuitec-path=\"/MyWebProject/WebRoot/jspTest/helloWorld.jsp\">\r\n");
out.write(" ");
Date date=new Date();
System.out.println(date);
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);
}
}
}
我们可以看到,helloWorld_jsp这个类是继承 org.apache.jasper.runtime.HttpJspBase这个类的,通过查看Tomcat服务器的源代码,如下所示:
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jasper.runtime;
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.HttpJspPage;
import javax.servlet.jsp.JspFactory;
import org.apache.jasper.compiler.Localizer;
/**
* This is the super class of all JSP-generated servlets.
*
* @author Anil K. Vijendran
*/
public abstract class HttpJspBase
extends HttpServlet
implements HttpJspPage
{
protected HttpJspBase() {
}
public final void init(ServletConfig config)
throws ServletException
{
super.init(config);
jspInit();
_jspInit();
}
public String getServletInfo() {
return Localizer.getMessage("jsp.engine.info");
}
public final void destroy() {
jspDestroy();
_jspDestroy();
}
/**
* Entry point into service.
*/
public final void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
_jspService(request, response);
}
public void jspInit() {
}
public void _jspInit() {
}
public void jspDestroy() {
}
protected void _jspDestroy() {
}
public abstract void _jspService(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException;
}
HttpJspBase类是继承HttpServlet的,所以HttpJspBase类是一个Servlet,而helloWorld_jsp又是继承HttpJspBase类的,所以helloWorld_jsp类也是一个Servlet,所以当浏览器访问服务器上的helloWorld.jsp页面时,其实就是在访问helloWorld.jsp这个Servlet,helloWorld_jsp这个Servlet使用_jspService这个方法处理请求。
也就是说,web容器(Servlet引擎)接收到以.jsp为扩展名的URL的访问请求时,它将该访问请求交给JSP引擎去处理。每个JSP页面在第一次被访问时,JSP引擎将它翻译成一个Servlet源程序,接着再把这个Servlet源程序编译成Servlet的class文件,然后再用web容器(Servlet引擎)像调用普通的Servlet程序一样的方式来装载和解释执行这个由JSP页面翻译成的Servlet程序。
4.2 Jsp页面中的html排版标签是如何被发送到客户端的?
浏览器接受到的这些数据(右击该网页,点击查看网页源码):
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="http://localhost:8080/MyWebProject/">
<title>My JSP 'helloWorld.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
<script>"undefined"==typeof CODE_LIVE&&(!function(e){var t={nonSecure:"51550",secure:"51555"},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>
<body data-genuitec-lp-enabled="false" data-genuitec-file-id="wc1-1" data-genuitec-path="/MyWebProject/WebRoot/jspTest/helloWorld.jsp">
</body>
</html>
都是在_jspService方法中使用如下的代码输出给浏览器的:
out.write('\r');
out.write('\n');
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
out.write("\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(" <base href=\"");
out.print(basePath);
out.write("\">\r\n");
out.write(" \r\n");
out.write(" <title>My JSP 'helloWorld.jsp' starting page</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<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("\t<!--\r\n");
out.write("\t<link rel=\"stylesheet\" type=\"text/css\" href=\"styles.css\">\r\n");
out.write("\t-->\r\n");
out.write("\r\n");
out.write(" <script>\"undefined\"==typeof CODE_LIVE&&(!function(e){var t={nonSecure:\"51550\",secure:\"51555\"},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=\"wc1-1\" data-genuitec-path=\"/MyWebProject/WebRoot/jspTest/helloWorld.jsp\">\r\n");
out.write(" ");
Date date=new Date();
System.out.println(date);
out.write("\r\n");
out.write(" </body>\r\n");
out.write("</html>\r\n");
在jsp中编写的java代码和html代码都会被翻译到_jspService方法中去,在jsp中编写的java代码会原封不动地翻译成java代码,如<%out.print("Hello Jsp");%>直接翻译成out.print("Hello Jsp");,而HTML代码则会翻译成使用out.write("<html标签>\r\n");的形式输出到浏览器。在jsp页面中编写的html排版标签都是以out.write("<html标签>\r\n");的形式输出到浏览器,浏览器拿到html代码后才能够解析执行html代码。
4.3 Jsp页面中的java代码服务器是如何执行的?
在jsp中编写的java代码会被翻译到_jspService方法中去,当执行_jspService方法处理请求时,就会执行在jsp编写的java代码了,所以Jsp页面中的java代码服务器是通过调用_jspService方法处理请求时执行的。
微信搜索“程序员考拉”欢迎关注!