笔记内容:JSP介绍与简单使用
笔记日期:2017-11-26


JSP介绍与简单使用

  • JSP介绍
  • JSP的访问流程与原理
  • JSP指令
  • JSP内置对象
  • 错误页面


JSP介绍


JSP全名为Java Server Pages,中文名叫java服务器页面,其根本是一个简化的Servlet设计,它是由Sun Microsystems公司倡导、许多公司参与一起建立的一种动态网页技术标准。JSP技术有点类似ASP技术,它是在传统的网页HTML(标准通用标记语言的子集)文件(.htm,.html)中插入Java程序段(Scriptlet)和JSP标记(tag),从而形成JSP文件,后缀名为(*.jsp)。 用JSP开发的Web应用是跨平台的,既能在Linux下运行,也能在其他操作系统上运行。

Servlet是JSP的技术基础,而且大型的Web应用程序的开发需要Java Servlet和JSP配合才能完成。JSP具备了Java技术的简单易用,完全的面向对象,具有平台无关性且安全可靠,主要面向因特网的所有特点。通常在项目开发中,都是以JSP来编写展示层面,Servlet则编写逻辑层。

因为在JSP中可以写HTML代码,在Servlet中则不行,就是因为在Servlet中不能直接写HTML代码,所以我们想要生成一个页面相当麻烦,只能通过Java代码一行行的输出HTML代码。而JSP就是为了解决这种问题所发展出来的技术,在JSP中我们即可以编写HTML代码也可以编写Java代码,不过主要以页面代码为主,所以才说JSP用来写展示层而Servlet则编写逻辑层。从以上介绍就可以得知JSP与Servlet最大的区别就是:前者可以在页面代码中编写Java代码,而后者只能是在Java代码中编写页面代码。只需要想想页面代码多还是Java代码多,就知道为什么需要有JSP这个技术了233。


JSP的访问流程与原理


想要访问JSP文件很简单就好像访问HTML文件一样,直接在浏览器的地址栏上输入JSP文件的路径,一回车就可以访问了:
JSP介绍与简单使用_第1张图片


其实看似简单的背后,是需要经历好几个步骤的,下面我们就来看看JSP背后的运行流程原理:

首先打开Tomcat中的web.xml文件,可以找到以下配置语句:

   
        jsp
        org.apache.jasper.servlet.JspServlet
        
            fork
            false
        
        
            xpoweredBy
            false
        
        3
    

    ..........................省略中间的一大堆注释

    
        jsp
        *.jsp
        *.jspx
    

从以上这段配置信息,就可以知道,JSP其实就是个Servlet,.jsp和.jspx其实就只是个web访问名称,而映射的是JspServlet这个类。所以才说Servlet是JSP的技术基础,JSP背后就是一个Servlet。

以上示例使用浏览器访问jsp文件时,浏览器发送请求到服务器上,服务器会先去这个web.xml文件中找到jsp或jspx的访问映射,就会找到被映射的JspServlet类,然后这个JspServlet就会去JSP对象池中询问是否有与访问请求相对应的JSP对象,如果有的话就拿出来调用service方法,进入服务阶段。如果没有的话,就会去工程目录下找到被访问的jsp文件,然后就会以此文件为基础生成一个java源文件,接着会把这个源文件编译成class文件,并实例化此类的对象,实例化后将对象放进对象池里,最后再拿出对象调用service方法进入服务阶段。和Servlet一样,进入服务阶段也是执行完处理请求的逻辑代码,生成响应数据后,将响应数据返回给浏览器。而且整个生命周期中,JSP对象也是只有一个。

大致流程图:

JSP介绍与简单使用_第2张图片


我们来看看生成的java源文件,这个文件的所在的路径你可以在Tomcat服务器启动时,在控制台中的打印信息中找到,我这里的路径如下(可能和你的不一样):

E:\Java_WebTestProject.metadata.plugins\org.eclipse.wst.server.core\tmp0

然后此目录下有个work文件夹,在此文件夹中有很多子文件夹,你需要在里面找到你的web工程名称的文件夹,找到之后点击进入,也是会有几层目录,一直点进去就会找到 index_jsp.java 源文件和一个 index_jsp.class 文件(如果你的jsp文件名叫index.jsp的话),打开这个java源文件,内容如下:

/*
 * Generated by the Jasper component of Apache Tomcat
 * Version: Apache Tomcat/9.0.1
 * Generated at: 2017-11-27 13:45:29 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,
                 org.apache.jasper.runtime.JspSourceImports {

          ...............................以下代码省略

以上可以看到这个index_jsp 类继承了HttpJspBase,那么来看看HttpJspBase继承了谁:

package org.apache.jasper.runtime;

import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import javax.servlet.jsp.HttpJspPage;
import org.apache.jasper.compiler.Localizer;

public abstract class HttpJspBase extends HttpServlet
    implements HttpJspPage
{

         ...............................以下代码省略

从源码可以看到HttpJspBase继承了HttpServlet,所以实际上这个jsp就是继承了HttpServlet,只不过中间插了个HttpJspBase进来而已,因为这个HttpJspBase里面没什么代码,基本都是空的。从以上可以得知,jsp其实就是个Servlet,只不过是换了个形态的Servlet罢了,所以学JavaWeb的时候要先学Servlet,然后再学JSP的时候就简单多了。

既然知道jsp背后就是一个Servlet,那么我们来看看这个背后的Servlet是如何实现我们的页面代码的,从 index_jsp.java 文件中翻到差不多最后面,可以看到一段拼凑的HTML代码:

             ...............................以上代码省略

 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("\r\n");
      out.write("\r\n");
      out.write("\r\n");
      out.write("Insert title here\r\n");
      out.write("\r\n");
      out.write("\r\n");
      out.write("\t

Hello I'm JSP!

\r\n"); out.write("\r\n"); out.write(""); } 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文件中的内容:

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>




Insert title here


    

Hello I'm JSP!

对比这两个文件中的代码之后,就能明白是怎么实现页面代码的了,JSP的机制就是让我们苦逼写代码的轻松了一些,不再需要自己去手写拼凑这些页面代码,JSP的机制会自动帮我们生成这些代码,怕不是要写封感谢信给sun公司才行。

除了页面代码外,当我们在JSP文件中写的Java代码也会自动生成到此源文件中,至于如何在JSP文件中编写Java代码会在以下小节中介绍。


JSP指令


以上介绍完JSP之后,这一小节就是介绍如何在JSP文件中编写Java代码和JSP的指令。我们的Java代码就需要写在JSP指令里,因为需要通过指令来表明这是一段Java代码,而不能像HTML代码那样能直接编写在JSP文件中。JSP的指令分为两类,一类是页面指令,一类是代码指令,Java代码就需要写在代码指令里。

页面指令:

指令 作用 示例
<%@ page %> 用于设置页面上的参数,例如缓存、输出格式、编码格式等,
还能用于引入java的类包,这个指令是最常用的指令。
<%@ page contentType="text/html" %>
<%@ include %> 标签库指令taglib –标签库指令描述了要使用的JSP标签库。
该指令需要指定一个前缀prefix(和C++的命名空间很类似)和标签库的描述URI
<%@ taglib prefix="myprefix" uri="taglib/mytag.tld" %>
<%@ taglib %> 包含指令include –包含指令通知JSP编译器把另外一个文件完
全包含入当前文件中。效果就好像被包含文件的内容直接被粘贴到当前文件中一样。这个功能和C预处理器所提供的很类似。被包含文件的
扩展名一般都是"jspf"(即JSPFragment,JSP碎片)
<%@ include file="somefile.jsp" %>

下面简单的介绍一下<%@ page %>指令里的常见属性使用,因为其他两个几乎不使用,所以在这里就不做演示了:


<%@ page language="java" %>


<%@ contentType="text/html;charset=utf-8" %>


<%@ pageEncoding="utf-8" %>


<%@ page buffer="20kb" %>


<%@ page import="java.util.HashMap" %>


<%@ page session="false" %>


<%@ page isErrorPage="true" %>


<%@ page errorPage="error.jsp" %>


<%@ page info="database handler"%>


<%@ page isThreadSafe="true" %>


<%@ page extends="javax.servlet.http.HttpServlet" %>


<%@ page trimDirectiveWhitespaces="true" %>

指令是能够像以上示例一样写多行的,一些情况下分多几行写会提高可读性。

按照以上配置,重启服务器在浏览器中刷新之前所访问的jsp页面,可能会发生405错误,但是没关系,我们主要是看一下生成的java源文件与之前的源文件发生了什么样的变化:

package org.apache.jsp;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import java.util.HashMap;

public final class index_jsp extends javax.servlet.http.HttpServlet
    implements org.apache.jasper.runtime.JspSourceDependent,
                 org.apache.jasper.runtime.JspSourceImports {

  public java.lang.String getServletInfo() {
    return "database handler";
  }

        ...............................省略以上代码

try {
      response.setContentType("text/html; charset=utf-8");
      pageContext = _jspxFactory.getPageContext(this, request, response,
                null, false, 20480, true);

        ...............................省略以下代码

从以上的代码片段中,可以看到继承类变为了 HttpServlet,并且导入了 java.util.HashMap 包,而且还重写了Servlet中的getServletInfo方法,此方法返回的字符串也是我们在指令中使用info属性所定义的字符串。最后面那段代码可以看到一个20480的数字,这是缓存的大小,在指令中配置的是20kb,这里显示的是字节单位,在没有配置之前默认的是8192,也就是8kb。


代码指令:

指令 作用 示例
<% %> 脚本指令,可以在这个指令里编写Java代码 <% String str="test"; %>
<%! %> 声明指令,属性声明和方法声明都需要写在这个标签里 <%!
String name="lisi"
public void method(){
}
%>
<%= %> 表达式指令,可以进行数据的输出 <%="output data" %>

简单演示一下这些指令的使用方式,其中<% %>指令比较常用:

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>





Insert title here


    <%
        // 声明变量
        String str="test";
        if(str.equals("test")){
            // 这个输出是输出到页面上
            out.print(str+"
"); } %> <%! // 声明属性和方法 String name=null; public String getName(){ return name; } %> <%="test output" %>

运行结果:
JSP介绍与简单使用_第3张图片


JSP内置对象


JSP的内置对象共有以下九个,我们可以在JSP中通过内置对象来使用它里面的方法:

  • request :实际上就是HttpServletRequest对象,详细内容参考之前介绍HttpServletRequest对象的文章
  • response :实际上就是HttpServletResponse 对象,详细内容参考之前介绍HttpServletResponse 对象的文章
  • pageContext :这是一个隐含对象,此对象代表jsp页面的上下文关系,能够调用、存取其他隐含对象,使用该对象可以访问页面中的共享数据,在JSP开发中并不经常使用。
  • session :实际上就是HttpSession对象,详细内容参考之前介绍HttpSession对象的文章
  • application :实际上就是ServletContext 对象,详细内容参考之前介绍ServletContext 对象的文章
  • config :实际上就是ServletConfig对象,可以得到web.xml中的初使化参数,详细内容参考之前介绍ServletConfig对象的文章
  • out :此对象用于输出数据、字节流,以上的示例中也使用到了
  • page :此对象代表jsp这个实体本身,即当前页面有效,相当于java中的this
  • exception :这是异常对象,代表运行时的异常

实际上我们在生成的源文件里就可以找到这些内置对象的声明:

            ...............................省略以上代码

// request 和 response 对象在这里
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;

            ...............................省略以下代码

其中还有一个exception 对象没有被声明在这里,因为这个对象需要在接收错误的JSP页面上才能获得,这些内置对象并没有什么特别的,你在Servlet中怎么用在JSP中就怎么用。


错误页面


错误页面是一个专门用来接收JSP运行过程中所发生的错误,错误信息会转发到这个错误页面上。配置错误页面的方式也很简单,首先在错误页面中通过指令的isErrorPage属性定义当前是一个错误页面,然后再非错误页面中使用errorPage属性定义跳转的错误页面即可。示例:

定义跳转的错误页面:

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>

<%@ page errorPage="error.jsp" %>





Insert title here


    <%
        // 故意制造一个错误
        System.out.println(1 / 0);
    %>

定义错误页面:

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>

<%@ page isErrorPage="true" %>




error


    
    <%=exception.toString() %>

运行结果:
JSP介绍与简单使用_第4张图片

你也可以在JSP中使用 try-catch 语句去捕获运行时所发生的异常:

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>

<%@ page errorPage="error.jsp" %>





Insert title here


    <%
        // 故意制造一个错误
        try {
            System.out.println(1 / 0);
        } catch (ArithmeticException e) {
            out.print("发生 ArithmeticException 异常!");
        }
    %>

运行结果:
JSP介绍与简单使用_第5张图片