JavaWeb(9)之JSP-Java Server Page

JavaWeb(9)之JSP-Java Server Page

微信搜索 zze_coding 或扫描 👉 二维码关注我的微信公众号获取更多资源推送:

介绍

什么是 JSP ?
从用户角度看,JSP 就是一个网页。
从开发者角度看,它其实就是一个继承了 Servlet 的 Java 类,所以可以直接说 JSP 就是一个 Servlet。
为什么会有 JSP ?
HTML 通常情况下用来显示一成不变的静态内容,但实际上大部分我们需要的网页上是需要显示一些静态数据的,这些动作都涉及到了逻辑处理,这些都需要代码辅助完成。
HTML 中是不支持写 Java 代码的,而JSP 里面可以写 Java 代码。
查看 JSP 翻译后的文件示例:

// 例:
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("<html>\r\n");
      out.write("<head>\r\n");
      out.write("    <title>Title</title>\r\n");
      out.write("</head>\r\n");
      out.write("<body>\r\n");
      out.write("<h1>hhhh</h1>\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);
    }
  }
}

常用指令

page

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

作用:设置当前 JSP 页面的相关属性。
属性:

  • contentType:告知浏览器当前 JSP 的 MIME 类型和以何编码来解析该 JSP 返回的内容。
  • pageEncoding:指定 JSP 内容的编码。
  • extends:指定 JSP 翻译成 Java 文件后继承的类。
  • import:导包使用。
  • session:可选 truefalse,默认为 true。指定当前 JSP 能否直接使用 session 对象。

查看 JSP 翻译后的 Java 文件可以发现,session 如果指定为 true,在 _jspService 方法中就会声明一个 session 变量,并通过 pageContext.getSession() 赋值;如果 session 指定为 false,那么就不会声明这个变量,即后续不能直接使用 session。

  • errorPage:指定当前 JSP 出错时跳转到的页面。
  • isErrorPage:可选 truefalse,指定当前 JSP 是不是错误页,默认 false。如果指定为 true,在当前 JSP 中就可以直接使用 exception 对象。

include

<%@include file="page.jsp" %>

作用:将指定 JSP 文件包含到当前 JSP。
示例:

<!-- page1.jsp -->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>page1</title>
</head>
<body>
<% String str = "hello";%>
<%=str%>
<h1>这是 page1 的内容</h1>
</body>
</html>
<!-- page2.jsp -->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>page2</title>
</head>
<body>
<%@include file="page1.jsp" %>
<h1>这是 page2 的内容</h1>
</body>
</html>

image.png

// page2_jsp.java:page2翻译后的java文件
package org.apache.jsp;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;

public final class page2_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("/page1.jsp", Long.valueOf(1546590314039L));
  }

  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("<html>\r\n");
      out.write("<head>\r\n");
      out.write("    <title>page2</title>\r\n");
      out.write("</head>\r\n");
      out.write("<body>\r\n");
      out.write("\r\n");
      out.write("<html>\r\n");
      out.write("<head>\r\n");
      out.write("    <title>page1</title>\r\n");
      out.write("</head>\r\n");
      out.write("<body>\r\n");
 String str = "hello";
      out.write('\r');
      out.write('\n');
      out.print(str);
      out.write("\r\n");
      out.write("<h1>这是 page1 的内容</h1>\r\n");
      out.write("</body>\r\n");
      out.write("</html>\r\n");
      out.write("\r\n");
      out.write("<h1>这是 page2 的内容</h1>\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);
    }
  }
}

taglib

<%@ taglib prefix="" uri="" %>

作用:引入标签库。
属性:

  • prefix:别名。
  • uri:标签库地址。

动作标签

include

<jsp:include page="page1.jsp"></jsp:include>

作用:和 include 指令一样,也是将指定 JSP 页包含到当前 JSP 页中。
示例:

<!-- page1.jsp -->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>page1</title>
</head>
<body>
<% String str = "hello";%>

<h1>这是 page1 的内容</h1>

<%=str%>
</body>
</html>
<!-- page2.jsp -->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>page2</title>
</head>
<body>
<jsp:include page="page1.jsp"></jsp:include>
<h1>这是 page2 的内容</h1>
</body>
</html>

image.png

// page2_jsp.java:page2翻译后的java文件
package org.apache.jsp;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;

public final class page2_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("<html>\r\n");
      out.write("<head>\r\n");
      out.write("    <title>page2</title>\r\n");
      out.write("</head>\r\n");
      out.write("<body>\r\n");
      org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "page1.jsp", out, false);
      out.write("\r\n");
      out.write("<h1>这是 page2 的内容</h1>\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);
    }
  }
}

查看翻译后文件可以发现,与 include 指令不同的是:该标签是将指定 JSP 文件执行后返回的内容拿到当前 JSP 中直接输出,而不是将代码拿到当前 JSP 中执行。

forward

<jsp:forward page="page2.jsp"></jsp:forward>

作用:请求转发。
相当于执行如下代码:

request.getRequestDispatcher("page2.jsp").forward(request, response);

还可以搭配 param 标签传递参数:

<jsp:forward page="page2.jsp">
    <jsp:param name="name" value="zhangsan"></jsp:param>
    <jsp:param name="age" value="20"></jsp:param>
</jsp:forward>

示例:

<!-- page1.jsp -->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>page1</title>
</head>
<body>

<jsp:forward page="page2.jsp">
    <jsp:param name="name" value="zhangsan"></jsp:param>
    <jsp:param name="age" value="20"></jsp:param>
</jsp:forward>
<h1>这是 page1 的内容</h1>
</body>
</html>
<!-- page2.jsp -->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>page2</title>
</head>
<body>
<h1>这是 page2 的内容</h1>
<hr>
<%
    String name = request.getParameter("name");
    Integer age = Integer.parseInt(request.getParameter("age"));
%>
name:<%=name%> <br>
age:<%=age%>
</body>
</html>

image.png

// page1_jsp.java:page1翻译后的java文件
package org.apache.jsp;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;

public final class page1_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("<html>\r\n");
      out.write("<head>\r\n");
      out.write("    <title>page1</title>\r\n");
      out.write("</head>\r\n");
      out.write("<body>\r\n");
      out.write("\r\n");
      if (true) {
        _jspx_page_context.forward("page2.jsp" + "?" + org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode("name", request.getCharacterEncoding())+ "=" + org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode("zhangsan", request.getCharacterEncoding()) + "&" + org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode("age", request.getCharacterEncoding())+ "=" + org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode("20", request.getCharacterEncoding()));
        return;
      }
      out.write("\r\n");
      out.write("<h1>这是 page1 的内容</h1>\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);
    }
  }
}

可以看到,参数的携带实际上是将我们通过 param 标签指定的参数先 URL 编码,然后通过 ? 方式拼接到 URL 后面。

九大内置对象

所谓内置对象,就是我们可以直接在 JSP 中使用的已经创建好的对象,有九个如下:

application:它实际上就是 javax.servlet.ServletContext 类的实例。
request:它是 javax.servlet.http.HttpServletRequest 类的实例。
session:它是 javax.servlet.http.HttpSession 类的实例。
pageContext:它是 javax.servlet.jsp.PageContext 类的实例,当前 JSP 的上下文对象,其它几个内置对象也可以通过它获取到。

上面四个对象为四大域对象,因为它们都可以通过 setAttribute 方法存值,getAttribute 方法取值,只是作用的范围不同。

  • applicationServletContext 实例之前就说过,它在整个应用程序内被共享。
  • request 仅在一次请求内有效。
  • session 在一次会话内有效。
    而新引入的 pageContext 则只是在当前 JSP 范围内有效,即每个 JSP 都有它独立的 pageContext 对象。

config:它是 javax.servlet.ServletConfig 类的实例。
exception:它是 java.lang.Throwable 类的实例,JSP 报错时抛出的异常对象。

当 JSP 中 page 指令的 isErrorPage 参数值指定为 true 时,才可直接使用 exception 对象。

  • out:它是 javax.servlet.jsp.JspWriter 类的实例。
    示例:
// page.jsp
<%@ page contentType="text/html;charset=UTF-8" isErrorPage="true" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<%
    out.write("这是 out 输出的内容");
%>

<%
    response.getWriter().write("这是 response.getWriter() 输出的内容");
%>
</body>
</html>

image.png
可以看到在代码中 response.getWriter() 是后输出的,但是实际访问时它却是先输出的。这是因为 out 对象输出的内容会放到 response 的缓冲区中,response.getWriter() 的内容输出后才会接着输出 out 对象输出的内容。而通过查看 JSP 对应 Java 代码我们知道,JSP 页面内容就是使用 out 对象输出的,所以得出结论:当我们在 JSP 中使用 response.getWriter() 输出内容时,在浏览器渲染后 response.getWriter() 输出的内容会出现在页面的最顶部。

  • page:它是当前 JSP 翻译成 Java 类/ Servlet 类的实例。
  • response:它是 javax.servlet.http.HttpServletResponse 类的实例。

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可

Links: https://www.zze.xyz/archives/javaweb9.html

Buy me a cup of coffee ☕.