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_tcat85workCatalinalocalhostMyWebProjectorgapachejspjspTest,其中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(' '); out.write(' '); String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; out.write(" "); out.write(" "); out.write("<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> "); out.write("<html> "); out.write(" <head> "); out.write(" <base href=""); out.print(basePath); out.write(""> "); out.write(" "); out.write(" <title>My JSP 'helloWorld.jsp' starting page</title> "); out.write(" "); out.write(" <meta http-equiv="pragma" content="no-cache"> "); out.write(" <meta http-equiv="cache-control" content="no-cache"> "); out.write(" <meta http-equiv="expires" content="0"> "); out.write(" <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> "); out.write(" <meta http-equiv="description" content="This is my page"> "); out.write(" <!-- "); out.write(" <link rel="stylesheet" type="text/css" href="styles.css"> "); out.write(" --> "); out.write(" "); 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> "); out.write(" "); out.write(" <body data-genuitec-lp-enabled="false" data-genuitec-file-id="wc1-1" data-genuitec-path="/MyWebProject/WebRoot/jspTest/helloWorld.jsp"> "); out.write(" "); Date date=new Date(); System.out.println(date); out.write(" "); out.write(" </body> "); 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); } } }
我们可以看到,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(' '); out.write(' '); String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; out.write(" "); out.write(" "); out.write("<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> "); out.write("<html> "); out.write(" <head> "); out.write(" <base href=""); out.print(basePath); out.write(""> "); out.write(" "); out.write(" <title>My JSP 'helloWorld.jsp' starting page</title> "); out.write(" "); out.write(" <meta http-equiv="pragma" content="no-cache"> "); out.write(" <meta http-equiv="cache-control" content="no-cache"> "); out.write(" <meta http-equiv="expires" content="0"> "); out.write(" <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> "); out.write(" <meta http-equiv="description" content="This is my page"> "); out.write(" <!-- "); out.write(" <link rel="stylesheet" type="text/css" href="styles.css"> "); out.write(" --> "); out.write(" "); 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> "); out.write(" "); out.write(" <body data-genuitec-lp-enabled="false" data-genuitec-file-id="wc1-1" data-genuitec-path="/MyWebProject/WebRoot/jspTest/helloWorld.jsp"> "); out.write(" "); Date date=new Date(); System.out.println(date); out.write(" "); out.write(" </body> "); out.write("</html> ");
在jsp中编写的java代码和html代码都会被翻译到_jspService方法中去,在jsp中编写的java代码会原封不动地翻译成java代码,如<%out.print("Hello Jsp");%>直接翻译成out.print("Hello Jsp");,而HTML代码则会翻译成使用out.write("<html标签> ");的形式输出到浏览器。在jsp页面中编写的html排版标签都是以out.write("<html标签> ");的形式输出到浏览器,浏览器拿到html代码后才能够解析执行html代码。
4.3 Jsp页面中的java代码服务器是如何执行的?
在jsp中编写的java代码会被翻译到_jspService方法中去,当执行_jspService方法处理请求时,就会执行在jsp编写的java代码了,所以Jsp页面中的java代码服务器是通过调用_jspService方法处理请求时执行的。
wx搜索“程序员考拉”,专注java领域,一个伴你成长的公众号!