JavaWeb详解(第四篇)之JSP 简介

Posted 穆瑾轩

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaWeb详解(第四篇)之JSP 简介相关的知识,希望对你有一定的参考价值。

    JavaWeb详解(第四篇)之JSP 简介

1、JSP概述

1.1、什么是JSP

    JSP 全称是 Java Servlet Pages,它是和 servlet 技术一样,都是 SUN 公司定义的一种用于动态开发 web 资源的技术。

    JSP 这门技术最大的特点在于,写 JSP就像在写 html ,但:它相比 html 而言,html 只能为用户提供静态数据,而 JSP 技术允许在页面中嵌套 java 代码,为用户提供动态数据。

    jsp=html+css+javascript+java代码+jsp标签(servlet)

1.2、为什么需要JSP

    我们在之前的学习中,经常这样写:

    相比Servlet 而言,servlet 很难对数据进行排版(需要写很多的标签、换行等),而 JSP 出了可以用 java 代码产生动态数据的同时,也很容易对数据进行排版,JSP就是替代Servlet输出HTML的。

1.3、JSP的本质

    jsp页面本质上是一个Servlet程序。

    如果是第一次访问该 jsp 文件,web 服务器就会把 该 jsp 文件翻译成一个同名的 Servlet 文件,然后再把 class 加载进内存,如果是第二次(或者以后)访问,就直接访问内存中的实例,因此 jsp 也是单例,所以第一次访问 jsp 网站的速度比较慢。 如果这个 jsp 文件被修改了,就相当于重新访问该 jsp 文件。

例如:新建一个a.jsp如下

<%@ page contentType="text/html;charset=GBK" language="java" isErrorPage="true"%>
<!DOCTYPE html>
<html>
<head>
<title>a.jsp</title>
</head>
<body>
    <h1>我是a.jsp</h1>
    <%
       String s = "HelloWorld";
       out.println(s);
    %>
</body>
</html>

    当我第一次访问时,找到我们项目的部署位置:

    然后找到Catalina目录:..\\work\\Catalina\\localhost\\JspWeb\\org\\apache\\jsp

package org.apache.jsp;

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

public final class a_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("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;
  }
  //JSP也是Servlet,运行时只有一个实例
  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 {

    //9大内置对象
    final javax.servlet.jsp.PageContext pageContext;
    javax.servlet.http.HttpSession session = null;
    java.lang.Throwable exception = org.apache.jasper.runtime.JspRuntimeLibrary.getThrowable(request);
	//页面声明了isErrorPage="true"属性才会有
    if (exception != null) {
     response.setStatus(javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
    }
    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=GBK");
      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>\\r\\n");
      out.write("<html>\\r\\n");
      out.write("<head>\\r\\n");
      out.write("<title>a.jsp</title>\\r\\n");
      out.write("</head>\\r\\n");
      out.write("<body>\\r\\n");
      out.write("    <h1>我是a.jsp</h1>\\r\\n");
      out.write("    ");

       String s = "HelloWorld";
       out.println(s);
    
      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);
    }
  }
}

    我们发现有个叫a_jsp.java的文件,跟踪原代码看到它它继承了HttpJspBase 类。 HttpJspBase 类又继承了 HttpServlet 类。 也就是说。 jsp 翻译出来的 java 类, 它间接了继承了 HttpServlet 类。 也就是说, 翻译出来的是一个 Servlet 程序 。细心的人可能发现,输出跟我们手写的很像,是的jsp帮我们完成了这部分复杂的工作。

    JSP比Servlet更方便更简单的一个重要原因就是:内置了9个对象!内置对象有:out、session、response、request、config、page、application、pageContext、exception。

2、JSP的语法

2.1、JSP的指令

    JSP指令用来声明JSP页面的相关属性,用于从 JSP 发送一个信息到容器,比如设置全局变量,文字编码,引入包等。常用的指令如下:

<%@ page language="java" import="java.util.*" pageEncoding="GBK"%>
<%@ include file=" " %>
<%@ taglib prefix=" " uri=""  %>
指 令说 明
pagepage 指令用于定义 JSP 页面的各种属性。page 是最复杂的一个指令,它的属性很多,常用的属性有 import、language、pageEncoding 等。
include静态包含指令,用于引入其它 JSP 文件。使用 include 指令引入的其它 JSP 文件,JSP 引擎将把这两个 JSP 文件翻译成一个 servlet,所以将 include 称为静态包含。
taglib用于在 JSP 页面中导入标签库(JSP 标准标签库、第三方标签库、自定义标签库)。

2.1.1、jsp 头部的page指令

<%@ page contentType="text/html;charset=GBK" language="java" %>

page 指令中常用属性有:

属性描述
language="xx"JSP 中嵌入的代码是 xx ,暂时只支持 java
import="包.*,包.类名"在该 JSP 页面引入包或者某个具体类
session=[true|false]是否在 JSP 页面中获取 session 对象
buffer=[none|8k|指定大小]给out对象使用的缓冲区是多大,默认是8k
autoFlash=[true|false]当buffer 满后,是否自动刷新到浏览器
isThreadSafe=[true|false]默认 true 表示该 JSP 的线程安全是由程序员控制,false 则对应的 Servlet 将实现线程安全接口
errorPage=”相对 JSP 页面”当JSP 页面出现错误时,自动跳转到指定的 JSP 页面
isErrorPage=[true|false]指定该 JSP 页面是否专门用于作为error 页面,默认为 false,如果设为 true,则在该页面直接使用 Exception 内置对象
contentType="text/html; charset=GBK"指定页面以什么方式显示页面
pageEncoding="GBK"指定 Servlet 引擎以什么方式翻译 JSP——>Servlet ,并指定页面以什么方式显示页面
extends="包名.类名"继承其他类,可以在本jsp直接使用类中的方法

2.1.2、include指令

     注:被引入的 JSP 页面中,不能够存在与当前页面有冲突的变量。

语法:
<%@ include file=”文件路径” %>
案例:它会把b.jsp的内容都包含进来,再一起编译。
<%@ include file=”b.jsp” %>

2.1.3、taglib指令

    用来引入在JSP页面中使用到的第三方标签库。这个后面再详细介绍。

2.2、JSP常用脚本

    脚本元素就是 java页面中的java代码,也叫片段的scriplet。JSP脚本有三种方式:

    1)JSP声明:变量、方法和类的声明。语法: <%!声明变量、方法和类的代码%>

    2)JSP中嵌入Java代码(片段)。语法:<% java代码 %>

    3)JSP表达式。语法:<%=变量或可以返回值的方法或 Java 表达式%>

    注:函数不能在<% %>(java片段)中定义

2.3、JSP文件的注释

        三种方式:

    1)<!-- 注释的内容 --> html的注释方法,可以在 JSP 中使用

    2)<%-- 注释的内容 --%> jsp 专用的注释

    3)//单行注释 /*多行注释*/ /**文档注释*/java 注释

    区别:

    <!-- -->会在 servlet 中生成对应的 out.write(“<!-- -->”),这样在返回给浏览器的静态页面中也有<!-- --> ,只是用户看不到而已;

    <%-- --%> 则在 servlet 中没有任何输出,建议使用<%-- --%>

    java 注释,会被翻译到java源代码中!

2.4、JSP的动作

JSP动作(JSP Actions)是一组JSP内置的标签,只书写少量的标记代码就能够使用JSP提供丰富的功能,JSP行为是对常用的JSP功能的抽象和封装

    JSP Actions是使用 xml 语法写的,是 jsp 规定的一些列标准动作,在容器处理 jsp 时,当容器遇到动作元素时,就执行相应的操作。可能看完概念还是很抽象。

    常用的JSP动作有:

JSP Actions语法描述
include<jsp:include page="relativeURL|<%=expressicry%>"></jsp:include>动态引入另一个文件
forward<jsp:forward page="跳转的jsp页面"> [<jsp:param name="" value=""/>] [<jsp:param name="" value=""/>] </jsp:forward> 转发在开发jsp的过程中,我们通常把jsp放入WEB-INF目录,目的是为了防止用户直接访问这些jsp文件.在WebRoot下我们有一个入口页面,它的主要转发<jsp:forword file=”/WEB-INF/xx.jsp”></jsp:forword>
param<jsp:param name="" value=""/>给一个 JSP 设置参数,常常与<jsp:include>或者<jsp:forward>集合使用<jsp:include page=""> <jsp:param name="" value=""/> <jsp:param name="" value=""/></jsp:include>,也可以给Bean或Applet传递参数。
useBean<jsp:useBean class="" id=""> </jsp:useBean>创建一个 javaBean 实例
setProperty<jsp:setProperty name="对象" property="属性" value="属性值" scope="作用域"/>给一个 javaBean 实例属性赋值
getProperty<jsp:getProperty property="" name=""/>取得一个 javaBean 实例的成员变量
plugin<jsp:plugin code="" codebase="" type="bean"></jsp:plugin>使用插件
fallback<jsp:fallback></jsp:fallback>指定浏览器不支持或无法启动Bean或Applet时,在页面上打印输出信息
directive<jsp:directive.include file="head.jsp"></jsp:directive.include>替代指令<%@%>的语法的

2.4.1、include动作

    前面已经提及到了,include指令是静态包含,include动作是动态包含其实include行为就是封装了request.getRequestDispatcher(String url).include(request,response)。

    动态包含也可以像静态包含一样。 把被包含的内容执行输出到包含位置。而include动作和include指令的区别:

1)属性不同

    include 指令通过 file 属性来指定被包含的页面,该属性不支持任何表达式。

  <jsp:include> 动作是通过 page 属性来指定被包含页面的,该属性支持 JSP 表达式。

2)处理方式不同

    使用 include 指令包含文件时,被包含文件的内容会原封不动地插入到包含页中使用该指令的位置,然后 JSP 编译器再对这个合成的文件进行翻译,所以最终编译后的文件只有一个。(静态包含,被包含文件尽量不要使用<html></html><body></body>这种标记,还要避免变量冲突)

    而使用<jsp:include> 动作包含文件时,只有当该标记被执行时,才会引入被包含的的页面进行编译,再将译之后的视图再引入到当前页面,然后继续执行后面的代码。所以被引入的页面即使有与当前相同的Java变量也没影响。

(如果被包含的文件改变,则静态包含的主页面需要重新编译。而动态包含只须重新编译被包含的文件即可。)

注:动态包含的原理(使用如下代码去调用被包含的 jsp 页面)

org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "b.jsp", out, false);

2.4.2、forward动作

    前面我们学习servlet的时候,我们使用request.getRequestDispatcher(String url).forward(request,response),进行跳转,而使用forward动作其实是对他的封装。

使用案例1:

1)新建一个b.jsp

2)在a.jsp中加入

<%@ page contentType="text/html;charset=GBK" language="java"%>
<!DOCTYPE html>
<html>
<head>
<title>a.jsp</title>
</head>
<body>
    <h1>我是a.jsp</h1>
    <%
       String s = "HelloWorld";
       out.println(s);
    %>
    <jsp:forward page="b.jsp"></jsp:forward>
</body>
</html>

 3)案例效果

 

4)查看编译后的源码

if (true) {
    _jspx_page_context.forward("b.jsp");
    return;
}

 使用案例2:

1)在a.jsp中加入

<jsp:forward page="b.jsp">
         <jsp:param name="username" value="mjx"/>
         <jsp:param name="password" value="123"/>
</jsp:forward>

2)在b.jsp中使用

我获取到的参数:
<%
    String username = request.getParameter("username");
    String password = request.getParameter("password");
%><br>
用户名:<%=username %><br>
密码:<%=password %>

3)案例效果

 2.4.3、param动作

当使用<jsp:include></jsp:forword>时可以使用param动作向这个资源传递参数。上面的案例中已经使用到了,这里就不再演示了。

扩展:什么是javaBean

    在学习useBean动作之前我们先了解下,什么是javaBean?

1)什么是javaBean

    JavaBean是一个遵循特定写法的Java类,它通常具有如下特点:

    a)这个Java类必须具有一个无参的构造函数;

    b)属性必须私有化;

    c)私有化的属性必须通过public类型的方法暴露给其它程序,并且方法的命名也必须遵守一定的命名规范;

2)为什么需要javaBean

    Java语言欠缺属性、事件、多重继承功能。不像html的标签、js对象都有很多内置的属性。当我们在JSP页面嵌入大量的HTML 代码、JS 代码、CSS 代码、Java 代码,这就使得我们的页面结构很混乱。而且需要我们自己手写大量的胶水代码,重复的声明使用,javaBean正是编写这套胶水代码的惯用模式或约定,JavaBean 使得 JSP编程模式变得清晰,程序可读性强。JavaBean 将程序的业务逻辑封装成 Java 类,提高了程序的可维护性和代码的可重用性。

例如:

public class User {

	//------------------User类封装的私有属性---------------------------------------
	// 姓名 String类型
	private String name;
	// 性别 String类型
	private String sex;
	// 年龄 int类型
	private int age;
	
	//------------------User类的无参数构造方法---------------------------------------
	public User() {
		
	}

	//------------------User类对外提供的用于访问私有属性的public方法-----------------------
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
	
}

    在学useBean之前,我们要使用一个对象,可能会这样写:

<%@ page contentType="text/html;charset=GBK" language="java"%>
<%@ page import="com.cn.domain.User" %>

<!DOCTYPE html>
<html>
<head>
<title>a.jsp</title>
</head>
<body>
    <h1>我是a.jsp</h1>
    <%
        User u = new User();
        u.setName("mjx");
        u.setAge(18);
        u.setSex("男");
    %>
    <% String userInfo = "姓名:"+u.getName() +" 性别:"+u.getSex()+" 年龄:"+u.getAge();%>
    <%=userInfo %>
</body>
</html>

案例效果:

2.4.4、useBean动作

    <jsp:useBean>用于在指定的域范围内查找指定名称的JavaBean对象

    1)如果在指定的范围已经存在该 bean 实例,那么将使用这个实例,而不会重新创建。

    2)如果不存在则实例化一个新的JavaBean对象并将它以指定的名称存储到指定的域范围中。

语法一(常用):
<jsp:useBean id="实例化对象的名称" class="类的全名" scope="保存范围page|request|session|application" ></jsp:useBean>

语法二:
<jsp:useBean id="stu" class="com.Bean.StudentInfo" type="com.Bean.StudentBase(父类)" scope="session" />

使用案例:

<%@ page contentType="text/html;charset=GBK" language="java"%>

<!DOCTYPE html>
<html>
<head>
<title>a.jsp</title>
</head>
<body>
    <h1>我是a.jsp</h1>
    <jsp:useBean id="user" class="com.cn.domain.User" scope="page"/>
    <%
        user.setName("mjx");
        user.setAge(18);
        user.setSex("男");
    %>
    <% String userInfo = "姓名:"+user.getName() +" 性别:"+user.getSex()+" 年龄:"+user.getAge();%>
    <%=userInfo %>
</body>
</html>

案例编译部分源码:

com.cn.domain.User user = null;
user = (com.cn.domain.User) _jspx_page_context.getAttribute("user", javax.servlet.jsp.PageContext.PAGE_SCOPE);
if (user == null){
    //这里就是为什么需要一个无参构造了
    user = new com.cn.domain.User();
    _jspx_page_context.setAttribute("user", user, javax.servlet.jsp.PageContext.PAGE_SCOPE);
}
user.setName("mjx");
user.setAge(18);
user.setSex("男");
String userInfo = "姓名:"+user.getName() +" 性别:"+user.getSex()+" 年龄:"+user.getAge();

2.4.5、setProperty动作

    <jsp:setProperty> 动作标记通常与<jsp:useBean>动作标记一起使用,它以请求中的参数给创建的JavaBean中对应的属性赋值,通过调用 bean 中的 setXxx() 方法来完成。

使用案例1:

   以前我们可能会这样写:

1)修改b.jsp为

<%@ page contentType="text/html;charset=GBK" language="java"%>
<!DOCTYPE html>
<html>
<head>
<title>b.jsp</title>
</head>
<body>
    <form action="a.jsp" method="post">
        用户名:<input type="text" name="name"><br>
        性别:<input type="text" name="sex"><br>
        年龄:<input type="text" name="age"><br>
        <input type="submit" value="提交">
    </form>
</body>
</html>

2)修改a.jsp

<%@ page contentType="text/html;charset=GBK" language="java"%>

<!DOCTYPE html>
<html>
<head>
<title>a.jsp</title>
</head>
<body>
    <h1>我是a.jsp</h1>
    <jsp:useBean id="user" class="com.cn.domain.User" scope="page"/>
    <%
        String name = request.getParameter("name");
        String sex = request.getParameter("sex");
        int age = Integer.parseInt(request.getParameter("age"));
        user.setName(name);
        user.setSex(sex);
        user.setAge(age);
    %>
    <% String userInfo = "姓名:"+user.getName() +" 性别:"+user.getSex()+" 年龄:"+user.getAge();%>
    <%=userInfo %>
</body>
</html>

使用案例2:

<%@ page contentType="text/html;charset=GBK" language="java"%>

<!DOCTYPE html>
<html>
<head>
<title>a.jsp</title>
</head>
<body>
    <h1>我是a.jsp</h1>
    <%
      request.setCharacterEncoding("GBK");
    %>
    <jsp:useBean id="user" class="com.cn.domain.User" scope="page"/>
     <!--name:对象名称
         property:属性名称,如果指定为*号则自动匹配
         value:指定值
     -->
     <jsp:setProperty name:"user" property="name" value="自定义名字"/>
     <jsp:setProperty name="user" property="age"/>
     <jsp:setProperty name="user" property="sex" />
    <% 
        String userInfo = "姓名:"+user.getName() +" 性别:"+user.getSex()+" 年龄:"+user.getAge();
    %>
    <%=userInfo %>
</body>
</html>

案例使用原理:

org.apache.jasper.runtime.JspRuntimeLibrary.introspecthelper(_jspx_page_context.findAttribute("user"), "name", "自定义名字", null, null, false);
      out.write("\\r\\n");
      out.write("     ");
      org.apache.jasper.runtime.JspRuntimeLibrary.introspecthelper(_jspx_page_context.findAttribute("user"), "age", request.getParameter("age"), request, "age", false);
      out.write("\\r\\n");
      out.write("     ");
      org.apache.jasper.runtime.JspRuntimeLibrary.introspecthelper(_jspx_page_context.findAttribute("user"), "sex", request.getParameter("sex"), request, "sex", false);

    需要保持表单中的属性名和定义的javaBean属性名一致的原因就是,编译后是使用request.getParameter("sex")的值。并且,类型都会帮我们自动转换。

2.4.6、getProperty动作

   <jsp:getProperty>标记用来获得 bean中的属性,并将其转换为字符串,再在 JSP 页面中输出,该 bean 中必须具有 getXxx() 方法。

    在上面的案例中,我们虽然设置好了对象的值,但是还是手动获取的。有了这个动作之后,我们就可以使用这个动作获取了。

使用案例:

<%@ page contentType="text/html;charset=GBK" language="java"%>

<!DOCTYPE html>
<html>
<head>
<title>a.jsp</title>
</head>
<body>
    <h1>我是a.jsp</h1>
    <%
      request.setCharacterEncoding("GBK");
    %>
    <jsp:useBean id="user" class="com.cn.domain.User" scope="page"/>
    <%--自动匹配并设置值--%>
    <jsp:setProperty name="user" property="*"/>
    <%--自动匹配并设置值--%>
    姓名:<jsp:getProperty name="user" property="name"/> 性别:<jsp:getProperty name="user" property="sex"/> 年龄:<jsp:getProperty name="user" property="age"/>
</body>
</html>

案例效果:

3、JSP的内置对象

    前面我们发现,不管是request也好、out也好,我们都能在jsp页面中直接使用。在前面我们也提到过JPS内置了9大对象:

对象名类型作用域
request请求对象javax.servlet.ServletRequest的子类(如:HttpServletRequest)一次请求
session会话对象 javax.servlet.http.HttpSessionSession
application应用程序对象 javax.servlet.ServletContextapplication
response响应对象 javax.servlet.ServletResponse的子类(如:HttpServletResponse)Page
pageContext页面上下文对象 javax.servlet.jsp.PageContextPage
out输出对象 javax.servlet.jsp.JspWriterPage
config配置对象 javax.servlet.ServletConfigPage
page页面对象java.lang.Object thispage
exception异常对象 java.lang.ThrowablePage

3.1、request对象

    request对象是javax.servlet.HttpServletRequest类型的对象。该对象代表了客户端的请求信息,主要用于接受通过HTTP协议传送到服务器的数据。(包括头信息、系统信息、请求方式以及请求参数等)。request对象的作用域为一次请求。

    在介绍servlet一文中,已经介绍过HttpServletRequest,用法差不多,这里就不再详细介绍了。

3.2、response对象

    response对象是HttpServletResponse类型的对象,代表的是服务器对客户端的响应,主要是将JSP容器处理过的对象传回到客户端。response对象也具有作用域,它只在JSP页面内有效。

    在介绍servlet一文中,已经介绍过HttpServletResponse,用法差不多,这里就不再详细介绍了。

3.3、application对象

    application 对象是ServletContext类型的对象,用于保存应用程序的公用数据,服务器启动并自动创建 application 对象后,只要没有关闭服务器,application 对象就一直存在,所有用户共享 application 对象。

    在介绍servlet一文中,已经介绍过ServletContext,用法差不多,这里就不再详细介绍了。

3.4、session对象

    session对象是HttpSession类型的对象,作用域一次会话的所有页面之间,只要保持同一会话,把一个键值对设置到session中,无论跳转到哪个页面都可以取到session中的键值对。

    在介绍servlet会话技术一文中,已经介绍过HttpSession,用法差不多,这里就不再详细介绍了。

3.5、config对象

    config 对象是 javax.servlet.Servlet类的实例,表示 Servlet 的配置信息。

    在介绍servlet一文中,已经介绍过ServletConfig,用法差不多,这里就不再详细介绍了。

3.6、out对象

    out 对象是一个输出流,用来向客户端输出数据,可以是各种数据类型的内容,同时,它还可以管理应用服务器上的输出缓冲区,缓冲区的默认值是 8KB,可以通过页面指令 page 来改变默认大小。

    out 对象是一个继承自抽象类 javax.servlet.jsp.JspWriter 的实例,在实际应用中,out 对象会通过 JSP 容器变换为 java.io.PrintWriter 类的对象。(可以简单理解:JspWriter就是带缓存的PrintWrieter)

常用API:

方法说明
void print(各种数据类型)将指定类型的数据输出到 HTTP 流,不换行
void println(各种数据类型)将指定类型的数据输出到 HTTP 流,并输出一个换行符
int getBufferSize()得到缓存大小
int getRemaining()得到未使用缓存的大小
void flush()刷新缓冲区

3.6.1、jsp 中 out 和 response.getwriter()的区别

使用案例:

<%@ page contentType="text/html;charset=GBK" language="java"%>
<!DOCTYPE html>
<html>
<head>
<title>c.jsp</title>
</head>
<body>
    <h1>我是c.jsp</h1>
    <%
	    // out 输出
	    out.write("这是 out 的第一次输出<br/>");
	    // out flush 之后。 会把输出的内容写入 writer 的缓冲区中
	    out.flush();
	    // 最后一次的输出, 由于没有手动 flush, 会在整个页面输出到客户端的时候, 自动写入到 writer缓冲区
	    out.write("这是 out 的第二次输出<br/>");
	    // writer 的输出
	    response.getWriter().write("这是 writer 的第一次输出<br/>");
	    response.getWriter().write("这是 writer 的第二次输出<br/>");
    %>
</body>
</html>

案例效果:

    只有向out对象中写入了内容,且满足如下任何一个条件时,out对象才去调用ServletResponse.getWriter方法,并通过该方法返回的PrintWriter对象将out对象的缓冲区中的内容真正写入到Servlet引擎提供的缓冲区中

    1)设置page指令的buffer属性关闭了out对象的缓存功能(或主动调用flush()方法刷新缓冲区)

    2)out对象的缓冲区已满

    3)整个JSP页面结束

3.7、page对象

    page 对象是为了执行当前页面应答请求而设置的 Servlet类的实体,即显示 JSP页面自身,与类的 this 指针类似,使用它来调用 Servlet 类中所定义的方法,只有在本页面内才是合法的。它是 java.lang.Object 类的实例。

常用API:

方法说明
class getClass()返回当前 Object 的类
int hashCode返回 Object 的 hash 代码
String toString把 Object 对象转换成 String 类的对象
boolean equals(Object obj)比较对象和指定的对象是否相等
void copy (Object obj)把对象拷贝到指定的对象中
Object clone()复制对象(克隆对象)

3.8、exception对象

    java.lang.Throwable 的实例,该实例代表其他页面中的异常和错误。只有当页面是错误处理页面,即编译指令page 的isErrorPage 属性为true 时,该对象才可以使用。常用的方法有getMessage()和printStackTrace()等。

使用案例:

1)新建一个d.jsp

<%@ page contentType="text/html;charset=GBK" language="java" errorPage="error.jsp" %>
<html>
<head>
    <title></title>
</head>
<body>
<%--模拟空指针异常的错误--%>
<%
    String isnull = null;
    isnull.length();
%>
</body>
</html>

2)新建一个error.jsp

 

<%@ page language="java" contentType="text/html; charset=GBK"
    pageEncoding="GBK" isErrorPage="true"%>
<!--注意:isErrorPage="true"时才能使用exception-->
<!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; GBK">
<title>Insert title here</title>
</head>
<body>
    <%out.println("程序抛出了异常:" + exception); %>
</body>
</html>

3)案例效果

 3.9、pageContext对象

    pageContext对象是JSP技术中最重要的一个对象,它代表JSP页面的运行环境,这个对象不仅封装了对其它8大隐式对象的引用,它自身还是一个域对象,可以用来保存数据。并且,这个对象还封装了web开发中经常涉及到的一些常用操作,例如引入和跳转其它资源、检索其它域对象中的属性等。

官方文档上描述:

PageContext 为页面/组件作者和页面实现者提供了许多工具,其中包括:

  • 管理各种范围名称空间的单个 API

  • 许多便捷 API,用于访问各种公共对象

  • 获取 JspWriter 以供输出的机制

  • 通过页面管理会话使用的机制

  • 向脚本环境公开页面指令属性的机制

  • 将当前请求转发或包含到应用程序中其他活动组件的机制

  • 处理 errorpage 异常处理的机制

pageContext对象常用API:

方法说明
String findAttribute(String name)查找各个域的属性(page—>request->session->application)
void forward(String relativeUrlPath)把页面转发到另一个页面或者 Servlet组件上
Exception getException()返回当前页的 Exception 对象
ServletRequest getRequest()返回当前页的 request 对象
ServletResponse getResponse()返回当前页的 response 对象
ServletConfig getServletConfig()返回当前页的 ServletConfig 对象
HttpSession getSession()返回当前页的 session 对象
Object getPage()返回当前页的 page 对象
ServletContext getServletContext()返回当前页的 application 对象
public Object getAttribute(String name)获取属性值
Object getAttribute(String name,int scope)在指定的范围内获取属性值
void setAttribute(String name,Object attribute)设置属性及属性值
void setAttribute(String name,Object obj,int scope)在指定范围内设置属性及属性值
void removeAttribute(String name)删除某属性
void removeAttribute(String name,int scope)在指定范围内删除某属性
void invalidate()返回 servletContext 对象,全部销毁

使用案例:

1)新建e.jsp

<%@ page contentType="text/html;charset=GBK" language="java"%>
<!DOCTYPE html>
<html>
<head>
<title>e.jsp</title>
</head>
<body>
    <h1>我是e.jsp</h1>
    <%
		request.setAttribute("info","value of request scope");
		session.setAttribute("info","value of request scope");
		application.setAttribute("info","value of application scope");
	%>
	pageContext 查找各个范围内的值:查找顺序page—>request->session->application <br>
	输出:
	<%=pageContext.findAttribute("info") %>
	<hr>
	pageContext 取出以下范围内的值(方法一):<br>
	request 设定的值:<%=pageContext.getRequest().getAttribute("info") %> <br>
	session 设定的值:<%=pageContext.getSession().getAttribute("info") %> <br>
	application 设的值:<%=pageContext.getServletContext().getAttribute("info") %> <hr>
	pageContext取出以下范围内各值(方法二):<br>
	范围1(page)内的值:<%=pageContext.getAttribute("info",1) %> <br>
	范围2(request)内的值:<%=pageContext.getAttribute("info",2) %> <br>
	范围3(session)内的值:<%=pageContext.getAttribute("info",3) %> <br>
	范围4(application)内的值:<%=pageContext.getAttribute("info",4) %> <hr>
	pageContext 修改或删除某个范围内的值:
	1)修改 request 设定的值:<br>
	<% pageContext.setAttribute("info","value of request scope is modified by pageContext",2); %> <br>
	修改后的值:<%=pageContext.getRequest().getAttribute("info") %> <br>
	
	2)删除 session 设定的值:<% pageContext.removeAttribute("info"); %>
	删除后的值:<%=session.getAttribute("info") %>
</body>
</html>

2)案例效果 

 4、JSP的四大域对象

    域对象可以像Map一样存取数据对象。四个域对象的功能一样,不同的是它们对数据的存取范围。在使用上它们是有优先顺序的。

    四大域对象分别是:

域对象描述所属域
pageContext只在当前JSP页面范围内有效,跳转页面无效page域
requet只在一次请求中保存属性,服务器跳转有效,浏览器跳转无效request域
session在一个会话范围中保存属性,无论何种跳转均有效,关闭浏览器后无效session域
application在整个服务器中保存,所有用户都可以使用context域

    优先顺序(范围从小到大):

 使用案例:

1)新建scope.jsp

<%@ page contentType="text/html;charset=GBK" language="java"%>
<!DOCTYPE html>
<html>
<head>
<title>c.jsp</title>
</head>
<body>
    <h1>scope.jsp</h1>
    <%
        // 往四个域中都分别保存了数据
        pageContext.setAttribute("key", "pageContext");
        request.setAttribute("key", "request");
        session.setAttribute("key", "session");
        application.setAttribute("key", "application");
    %>
    pageContext 域是否有值: <%=pageContext.getAttribute("key")%> <br>
    request 域是否有值: <%=request.getAttribute("key")%> <br>
    session 域是否有值: <%=session.getAttribute("key")%> <br>
    application 域是否有值: <%=application.getAttribute("key")%> <br>
    
    <% 
        session.setAttribute("findKey", "session");
        application.setAttribute("findKey", "application");
    %><br>
    使用key去查找值:按作用域从小到大查<br>
    key:<%=pageContext.findAttribute("key")%><br>
    findKey:<%=pageContext.findAttribute("findKey")%>
</body>
</html>

2)案例效果

以上是关于JavaWeb详解(第四篇)之JSP 简介的主要内容,如果未能解决你的问题,请参考以下文章

JavaWeb详解(第五篇)之EL表达式简介

023JavaWeb面试题:JSP

JAVAWEB开发之JSPEL及会话技术(Cookie和Session)的使用详解

深入理解DOM节点类型第四篇——文档片段节点DocumentFragment

ELK总结——第四篇Kibana的简介

好玩的ES--第四篇之聚合查询和集群