JavaWeb学习笔记(七)—— JSP

一、什么是JSP

  JSP全名是Java Server Pages,它是建立在Servlet规范之上的动态网页开发技术。在JSP文件中,HTML代码与Java代码共同存在,其中,HTML代码用来实现网页中静态内容的显示,Java代码用来实现网页中动态内容的显示。为了与传统HTML有所区别, JSP文件的扩展名为 ".jsp" 。

  

       JSP技术所开发的Web应用程序是基于Java的, 它可以用一种简捷的方法从Java程序生成Web页面, 在使用上具有以下一点的特征:

  • 跨平台: 由于JSP是基于Java语言的,他可以使用Java API, 所以他也是跨平台的, 可以应用于不同的系统中,如Windows, Linux 等. 当从一个平台移植到另一个平台时,JSP和JavaBean 的代码并不需要重新编译, 这是因为Java的字节码是与平台无关的(java的运行环境即jre),说跨平台其实也就是jre是跨平台的,java站在jre上,自然java也是跨平台的了. 举个栗子: jre就相当于一个多功能套街头,你java只要符合jre的规范,就能套上这个 多功能接头了.自然也就能跨平台了.
  • 业务代码相分离:  在使用JSP技术开发Web应用时,可以将界面的开发与应用程序的开发分离开,使用HTML 来设计界面,使用JSP标签和脚本来动态生成页面上的内容. 在服务器端,JSP容器(tomcat,jboss,weblogic等的服务器)负责解析JSP标签和脚本程序,生成所请求的内容,并将这执行结果以HTML页面的形式返回到浏览器.(这是jsp的初衷, 但是在前辈们的使用中发现jsp中会出现大量的业务代码,导致业务逻辑等不清楚,开发完成后维护起来也不容易,后来就尽量将业务逻辑写在后台了,使用 MVC模式 这样逻辑更加清晰)
  • 组件重用: JSP中可以使用JavaBean编写业务组件,也就是使用一个JavaBean类封装业务处理代码或者作为一个数据存储模型, 在JSP页面中, 甚至在整个项目中, 都可以重复使用这个JavaBean, 同时,JavaBean也可以应用到其他Java应用程序中.
  • 预编译: 预编译也就是在用户第一次通过浏览器访问JSP页面时,服务器将对JSP页面代码进行编译,并且仅执行一次编译.编译好的代码将被保存,在用户下一次访问时,会直接执行编译好的代码.这样不仅节约了服务器的CPU资源, 还大大的提升了客户端的访问速度。

二、JSP的基本语法

2.1 JSP脚本元素

  JSP脚本元素是指嵌套在<%和%>之中的一条或多条Java程序代码。通过JSP脚本元素可以将Java代码嵌入HTML页面中,所有可执行的Java代码,都可以通过JSP脚本来执行。(不建议在jsp页面中嵌入java代码)

  JSP脚本元素主要包含如下三种类型:

  • JSP Scriptlets:<%...%>在这个里面书写内容等同于在方法中书写代码
    Java语句;方法中能放什么,它就能放什么。如果在这个元素里面定义了一个变量,那么此时他就是一个局部变量!
  • JSP声明语句:<%!...%> 在这个里面书写内容等同于在类中书写代码
    Java定义类成员;没人会用它!有人会考它!定义类的成员!类能包含什么,它就可以包含什么。声明中没有9大内置对象!
  • JSP表达式:<%=…%>  里面的代码会被输出!
    Java表达式;等同与resopnse.getWriter().print()。写到这里的东西,都是用来输出的!

【JSP Scriptlets】

  JSP Scriptlets是一段代码段。当需要使用Java实现一些复杂操作或控制时,可以使用它。JSP Scriptlets的语法格式如下所示:

<% java代码(变量、方法、语句等)%>

  在JSP Scriptlets中声明的变量是JSP页面的局部变量,调用JSP Scriptlets时,会为局部变量分配内存空间,调用结束后,释放局部变量占有的内存空间。

【JSP声明语句】

  JSP的声明语句用于声明变量和方法,它以“<%!”开始,以“%>”结束,其语法格式如下所示:

<%!
    定义的变量或方法等
%>

  在上述语法格式中,被声明的Java代码将被编译到Servlet的_jspService()方法之外,即在JSP声明语句中定义的都是成员方法、成员变量、静态方法、静态变量、静态代码块等在JSP声明语句中声明的方法在整个JSP页面内有效
  在一个JSP页面中可以有多个JSP声明语句,单个声明中的Java语句可以是不完整的,但是多个声明组合后的结果必须是完整的Java语句。

【JSP表达式】

  JSP表达式(expression)用于将程序数据输出到客户端,它将要输出的变量或者表达式直接封装在以“<%=” 开头和以“%>”结尾的标记中,其基本的语法格式如下所示:

<%=expression %>

  在上述语法格式中,JSP表达式中的将“expression”表达式结果输出到浏览器。需要注意的是:

  • <%=”和“%>”标记之间插入的是表达式,不能插入语句。
  • “<%=”是一个完整的符号,“<%”和“=”之间不能有空格。
  •  JSP表达式中的变量或表达式后面不能有分号

2.2 JSP注释

  同其它各种编程语言一样,JSP也有自己的注释方式,其基本语法格式如下:

<%-- 注释内容 --%>

   需要注意的是,Tomcat将JSP页面编译成Servlet程序时,会忽略JSP页面中被注释的内容,不会将注释信息发送到客户端。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>JSP注释</title>
</head>
<body>
    <%--这是个JSP注释--%>
    <!--这是个HTML注释-->
</body>
</html> 

  上述代码中,包含HTML注释和JSP两种注释方式。启动tomcat服务器,访问该页面,可以看到该页面什么都不显示,接下来右键【查看页面源代码】:

  

  从图中可以看出,JSP的注释信息没有显示出来,而只显示出了HTML注释。这是因为Tomcat编译JSP文件时,会将HTML注释当成普通文本发送到客户端,而JSP页面中格式为"<%-- 注释信息 --%>"的内容则会被忽略,不会发送到客户端。

  JSP注释、Java注释、HTML注释对比:

<%--JSP注释--%>
<% //java注释 %>
<!--HTML注释-->

 

2.3 JSP运行原理

 【Web服务器是如何调用并执行一个jsp页面的?】

  浏览器向服务器发请求,不管访问的是什么资源,其实都是在访问Servlet,所以当访问一个jsp页面时,其实也是在访问一个Servlet,服务器在执行jsp的时候,首先把jsp翻译成一个Servlet,所以我们访问jsp时,其实不是在访问jsp,而是在访问jsp翻译过后的那个Servlet。

  JSP的运行过程具体如下:

  (1)客户端发出请求,请求访问JSP文件

  (2)JSP容器先将JSP文件转换成一个Java源文件(Java Servlet源程序),在转换过程中,如果发现JSP文件中存在任何语法错误,则中断转换过程,并向服务器和客户端返回出错信息

  (3)如果转换成功,则JSP容器将生成的Java源文件编译成响应的字节码文件*.class。该class文件就是一个Servlet,Servl容器会像处理其它Servlet一样处理它。

  以HelloWorld.jsp为例:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Hello World</title>
</head>
<body>
    <%
        out.print("Hello World");
    %>
</body>
</html>

  当用户第一次访问HelloWorld.jsp页面时,该页面会先被JSP容器转换为一个名称为HelloWorld_jsp.java的源文件,然后将源文件编译为一个名称为HelloWorld_jsp.class字节码文件。如果项目发布在Tomcat的webapps目录中,源文件和.class文件可以在Tomcat服务器的work\Catalina\localhost\项目名\org\apache\jsp目录下找到。而使用IDEA开发工具时,idea的web项目不是直接将webapp放在tomcat容器中。而是将生成的webapp与tomcat按照idea的“技术”形成连接,这样减少了很大的配置tomcat的时间,一次配置,一劳永逸。jsp编译后的class和java文件在C:/Users/登录名/.IntelliJIdea2017.2/system/tomcat/Tomcat-pure_工程名/work/Catalina/localhost/appcontext名称/org/apache/jsp目录下:

  从图中可以看出,HelloWorld.jsp已被转换为源文件和.class文件。打开HelloWorld_jsp.java文件,可查看转换后的源代码:

public final class HelloWorld_jsp extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent {
    ...
  public void _jspInit() {
    _el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
    _jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
  }

  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>Hello World</title>\r\n");
      out.write("</head>\r\n");
      out.write("<body>\r\n");
      out.write("    ");

        out.print("Hello World");
    
      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 { 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文件转换后的源文件m没有实现Servlet接口,但继承了org.apache.jasper.runtime.HttpJspBase类。在Tomcat源文件中查看HttpJspBase类的源代码

   

  

  从HeepJspBase的源码中可以看出,HttpJspBase类是HttpServlet的一个子类,由此可见,HelloWorld_jsp类就是一个Servlet。结论:JSP就是一个Servlet。

  当浏览器访问服务器上的HelloWorld.jsp页面时,其实就是在访问HelloWorld_jsp这个Servlet,index_jsp这个Servlet使用_jspService这个方法处理请求。

【jsp页面中的html排版标签是如何被发送到客户端的?】

  浏览器接收到的这些数据:

  

  都是在_jspService方法中使用如下的代码输出给浏览器的:

  在jsp中编写的java代码和html代码都会被翻译到_jspService方法中去,在jsp中编写的java代码会原封不动地翻译成java代码,如<%out.print("Hello World");%>直接翻译成out.print("Hello World");,而HTML代码则会翻译成使用out.write("<html标签>\r\n");的形式输出到浏览器。在jsp页面中编写的html排版标签都是以out.write("<html标签>\r\n");的形式输出到浏览器,浏览器拿到html代码后才能够解析执行html代码。

【jsp页面中的java代码服务器是如何执行的?】

  在jsp中编写的java代码会被翻译到_jspService方法中去,当执行_jspService方法处理请求时,就会执行在jsp编写的java代码了,所以Jsp页面中的java代码服务器是通过调用_jspService方法处理请求时执行的。

【Web服务器在调用jsp时,会给jsp提供一些什么java对象?】

  查看_jspService方法可以看到,Web服务器在调用jsp时,会给Jsp提供如下的8个java对象

 

  其中page对象,request和response已经完成了实例化,而其它5个没有实例化的对象通过下面的方式实例化

  

  这8个java对象在Jsp页面中是可以直接使用的,如下所示:

<%
        session.setAttribute("name", "session对象");//使用session对象,设置session对象的属性
        out.print(session.getAttribute("name")+"<br/>");//获取session对象的属性
        pageContext.setAttribute("name", "pageContext对象");//使用pageContext对象,设置pageContext对象的属性
        out.print(pageContext.getAttribute("name")+"<br/>");//获取pageContext对象的属性
        application.setAttribute("name", "application对象");//使用application对象,设置application对象的属性
        out.print(application.getAttribute("name")+"<br/>");//获取application对象的属性
        out.print("Hello Jsp"+"<br/>");//使用out对象
        out.print("服务器调用index.jsp页面时翻译成的类的名字是:"+page.getClass()+"<br/>");//使用page对象
        out.print("处理请求的Servlet的名字是:"+config.getServletName()+"<br/>");//使用config对象
        out.print(response.getContentType()+"<br/>");//使用response对象
        out.print(request.getContextPath()+"<br/>");//使用request对象
%>

  运行结果如下:

  

三、JSP三大指令

3.1 page指令

  在JSP页面中,经常需要对页面的某些特征进行描述,例如,页面的编码方式,JSP页面采用的语言等。这时,可以通过page指令来实现。page指令的具体语法格式如下所示:

<%@ page 属性名1=“属性值1” 属性名2=“属性名2”...%>

  在上面的语法格式中,page用于声明指令的名称,属性用来指定JSP页面的某些特征。page指令提供了一系列与JSP页面相关的属性:

【pageEncoding和contentType】

  pageEncoding指定当前JSP页面的编码!这个编码是给服务器看的,服务器需要知道当前JSP使用的编码,不然服务器无法正确把JSP编译成java文件。所以这个编码只需要与真实的页面编码一致即可!

  contentType属性与response.setContentType()方法的作用相同!它会完成两项工作,一是设置响应字符流的编码,二是设置content-type响应头。例如:<%@ contentType=”text/html;charset=utf-8”%>,它会使“真身”中出现response.setContentType(“text/html;charset=utf-8”)。

  无论是page指令的pageEncoding还是contentType,它们的默认值都是ISO-8859-1,我们知道ISO-8859-1是无法显示中文的,所以JSP页面中存在中文的话,一定要设置这两个属性。

【import属性】

  指定在JSP页面翻译成的Servlet源文件中导入的包或类。一个import属性可以引入多个类,中间用英文逗号隔开:

<%@page import=”java.net.*,java.util.*,java.sql.*%>

  import是唯一可以声明多次的page指令属性:

<%@page import=”java.util.*” import=”java.net.*” import=”java.sql.*%>

  但是,我们一般会使用多个page指令来导入多个包:

<%@ page import=”java.util.*%>
<%@ page import=”java.net.*%>
<%@ page import=”java.text.*%>

【errorPage和isErrorPage】

  我们知道,在一个JSP页面出错后,Tomcat会响应给用户错误信息(500页面)!如果你不希望Tomcat给用户输出错误信息,那么可以使用page指令的errorPage来指定错误页!也就是自定义错误页面,例如:<%@page errorPage=”xxx.jsp”%>。这时,在当前JSP页面出现错误时,会请求转发到xxx.jsp页面。

  a.jsp

<%@ page import="java.util.*" pageEncoding="UTF-8"%>
<%@ page  errorPage="b.jsp" %>
    <%
        if(true)
            throw new Exception("哈哈~");
    %>

  b.jsp

<%@ page pageEncoding="UTF-8"%>
<html>
  <body>
   <h1>出错啦!</h1>
  </body>
</html>

  在上面代码中,a.jsp抛出异常后,会请求转发到b.jsp。在浏览器的地址栏中还是a.jsp,因为是请求转发!

  而且客户端浏览器收到的响应码为200,表示请求成功!如果希望客户端得到500,那么需要指定b.jsp为错误页面。

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ page  isErrorPage="true"  %>
<html>
  <body>
   <h1>出错啦!</h1>
    <%=exception.getMessage() %>
  </body>
</html>

  注意,当isErrorPage为true时,说明当前JSP为错误页面,即专门处理错误的页面。那么这个页面中就可以使用一个内置对象exception了。其他页面是不能使用这个内置对象的!而且,一旦转发到错误页,那么Tomcat会把状态码设置为500,而不再是200了。

【autFlush和buffer】

  buffer表示当前JSP的输出流(out隐藏对象)的缓冲区大小,默认为8kb

  authFlush表示在out对象的缓冲区满时如果处理!当authFlush为true时,表示缓冲区满时把缓冲区数据输出到客户端;当authFlush为false时,表示缓冲区满时,抛出异常。authFlush的默认值为true

  这两个属性一般我们也不会去特意设置,都是保留默认值!

【isELIgnored】

  isElIgnored属性表示当前JSP页面是否忽略EL表达式,默认值为false,表示不忽略(即支持)。

【language】:只能是Java

【session】:默认为true,表示当前JSP页面可以使用session对象,如果为false表示当前JSP页面不能使用session对象;

需要注意的是:page指令对整个页面都有效,而与其书写的位置无关,但是习惯上把page指令写在JSP页面的最前面。

3.2 include指令

  include指令表示静态包含!即目的是把多个JSP合并成一个JSP文件!

  include指令只有一个属性:file,指定要包含的页面,例如:<%@include file=”b.jsp”%>。

  静态包含:当hel.jsp页面包含了lo.jsp页面后,在编译hel.jsp页面时,需要把hel.jsp和lo.jsp页面合并成一个文件,然后再编译成Servlet(Java文件)。

  

  很明显,在lo.jsp中使用username变量,而这个变量在hel.jsp中定义的,所以只有这两个JSP文件合并后才能使用。通过include指定完成对它们的合并!

3.2 taglib指令

  在JSP页面中使用第三方的标签库时,需要使用taglib指令来“导包”。例如:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

   其中prefix表示标签的前缀,这个名称可以随便起。uri是由第三方标签库定义的,所以你需要知道第三方定义的uri。

四、JSP九大内置对象

  在JSP页面中,有一些对象需要频繁使用,如果每次都重新创建这些对象则会非常麻烦。为了简化Web应用程序的开发,JSP2.0规范中提供了9个隐式(内置)对象,它们是JSP默认创建的,可以直接在JSP页面中使用 。

名称

类型

描述

pageContext

javax.servlet.jsp.PageContext

JSP的页面容器

request

javax.servlet.http.HttpServletRequest

得到用户的请求

response

javax.servlet.http.HttpServletResponse

服务器向客户端的回应信息

session

javax.servlet.http.HttpSession

用来保存用户的信息

application

javax.servlet.ServletContext

所有用户的共享信息

config

javax.servlet.ServletConfig

服务器配置,可以获得初始化参数

out

javax.servlet.jsp.JspWriter

用于页面输出

page

java.lang.Object

指当前页面转换后的Servlet类的实例

exception

java.lang.Throwable

表示JSP页面所发送的异常,在错误页中才起作用

  request,response,session,application,config这些对象在前面都已经作了详细的介绍,而page对象在JSP页面中很少被用到。所以这里重点介绍一下剩下的pageContext对象,out对象。

4.1 pageContext对象

  在JavaWeb中一共四个域对象,其中Servlet中可以使用的是request、session、application三个对象,而在JSP中可以使用pageContext、request、session、application四个域对象。JSP这四个域的范围为:

PageContext常量名

描述

作用域名称

域对象类型

PageScope

当前页面中有效

pageContext

PageContext

RequestScope

一次请求范围

request

HttpServletRequest

SessionScope

一次会话范围

session

HttpSession

ApplicationScope

应用范围

application

ServletContext

  • page:表示当前页,通常没用。jsp标签底层使用。
  • request:表示一次请求。通常一次请求就一个页面,但如果使用请求转发,可以涉及多个页面。
  • session:表示一次会话。可以在多次请求之间共享数据。
  • application:表示一个web应用(项目)。可以整个web项目共享,多次会话共享数据。

  在JSP页面中,使用pageContext对象可以获取JSP的其他8个隐式对象。pageContext对象是javax.servlet.jsp.PageContext类的实例对象,它代表当前JSP页面的运行环境,并提供了一系列用于获取其他隐式对象的方法:

方法名

功能描述

JspWriter getOut()

获取out内置对象

ServletConfig getServletConfig()

获取config内置对象

Object getPage()

获取page内置对象

ServletRequest getRequest()

获取request内置对象

ServletResponse getResponse()

获取response内置对象

HttpSession getSession()

获取session内置对象

ServletContext getServletContext()

获取application内置对象

Exception getException()

获取exception内置对象

  上表中列举了pageContext获取其他隐式对象的方法,这样,当传递一个pageContext对象后,就可以通过这些方法轻松地获取到其他8个隐式对象了。

  pageContext对象不仅提供了获取隐式对象的方法,还提供了存储数据的功能。pageContext对象存储数据是通过操作属性来实现的:

方法名称

功能描述

void setAttribute(String name, Object value, int scope)

在指定范围中添加数据

Object getAttribute(String name, int scope)

获取指定范围的数据

void removeAttribute(String name, int scope)

移除指定范围的数据

Object findAttribute(String name)

从4个域对象中查找名称为name的属性

  上表列举了pageContext对象操作属性的相关方法,其中,参数name指定的是属性名称,参数scope指定的是属性的作用范围。pageContext对象的作用范围有4个值,具体如下:

  • PageContext.PAGE_SCOPE :表示页面范围
  • PageContext.REQUEST_SCOPE:表示请求范围
  • PageContext.SESSION_SCOPE:表示会话范围
  • PageContext.APPLICATION_SCOPE:表示Web应用程序范围

  需要注意的是,当使用 findAttribute()方法查找名称为name的属性时,会按照page、request、session和application的顺序依次进行查找,如果找到就停止查找,并返回属性的名称,否则返回null。接下来通过一个案例来演示pageContext对象的使用:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>pageContext</title>
</head>
<body>
    <%
        // 获取request对象
        HttpServletRequest req = (HttpServletRequest) pageContext.getRequest();
        // 设置page范围内属性
        pageContext.setAttribute("str", "Java", pageContext.PAGE_SCOPE);
        // 设置request范围内属性
        req.setAttribute("str", "Java Web");
        // 获得page范围属性
        String str1 = (String) pageContext.getAttribute("str", pageContext.PAGE_SCOPE);
        // 获得request范围属性
        String str2 = (String) pageContext.getAttribute("str", pageContext.REQUEST_SCOPE);
    %>
    <%="page范围:"+str1%><br>
    <%="request范围:"+str2%>

</body>
</html>

   浏览器的显示结果如下:

  

  从显示结果可以看出,通过pageContext对象可以获取到request对象,并且还可以获取不同范围内的属性。

4.2 out对象

  out对象用于向客户端发送文本数据。 
  out对象是通过调用pageContext对象的getOut方法返回的,其作用和用法与ServletResponse.getWriter方法返回的PrintWriter对象非常相似,都是用来向客户端发送文本形式的实体内容。不同的是,out对象的类型为JspWriter,它相当于一种带缓存功能的PrintWriter。设置JSP页面的page指令的buffer属性可以调整它的缓存大小,甚至关闭它的缓存。 

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

  • 设置page指令的buffer属性关闭了out对象的缓存功能
  • out对象的缓冲区已满
  • 整个JSP页面结束

  接下来,通过一张图来描述JSP页面的out对象与Servlet引擎提供的缓冲区之间的工作关系:

  

  从图中可以看出,在JSP页面中,通过out隐式对象写入数据相当于将数据插入到JspWriter对象的缓冲区中,只有调用ServletResponse.getWriter()方法,缓冲区中的数据才能真正写入到Servlet引擎所提供的缓冲区中。为了验证上述说法是否正确,接下来通过一个具体的案例来演示out对象的使用。

  创建out.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>out</title>
</head>
<body>
    <%
        out.println("first line<br>");
        response.getWriter().println("second line<br>");
    %>
</body>
</html>

  启动服务器,访问该页面,显示如下:

  

  从图中可以看出,尽管out.println语句位于response.getWriter().println语句之前,但它的输出内容却在后面。由此可以说明,out对象通过print语句写入数据后,直到整个JSP页面结束,out对象中输入缓冲区的数据(即:first line)才真正写入到Servlet引擎提供的缓冲区中,而 response.getWriter().println语句则是直接把内容(即:second line)写入Servlet引擎提供的缓冲区中,Servlet引擎按照缓冲区中的数据存放顺序输出内容。

五、JSP动作标签

  JSP动作标签是用来控制JSP的行为,执行一些常用的JSP页面动作。通过动作标签可以实现使用多行Java代码能够实现的效果,如包含页面文件,实现请求转发等。 

5.1 jsp:include

  <jsp:include>标签的作用是用来包含其它JSP页面的!你可能会说,前面已经学习了include指令了,它们是否相同呢?虽然它们都是用来包含其它JSP页面的,但它们的实现的级别是不同的!

  include指令是在编译级别完成的包含,即把当前JSP和被包含的JSP合并成一个JSP,然后再编译成一个Servlet。

  include动作标签是在运行级别完成的包含,即当前JSP和被包含的JSP都会各自生成Servlet,然后在执行当前JSP的Servlet时完成包含另一个JSP的Servlet。它与RequestDispatcher的include()方法是相同的!

  hel.jsp

  <body>
    <h1>hel.jsp</h1>
    <jsp:include page="lo.jsp" />
  </body>

  lo.jsp

<%
    out.println("<h1>lo.jsp</h1>");
%>

 

5.2 jsp:forward

  forward标签的作用是请求转发!forward标签的作用与RequestDispatcher#forward()方法相同。

  hel.jsp

<body>
    <h1>hel.jsp</h1>
    <jsp:forward page="lo.jsp"/>
</body>

  lo.jsp

<%
    out.println("<h1>lo.jsp</h1>");
%>

  注意,最后客户端只能看到lo.jsp的输出,而看不到hel.jsp的内容。也就是说在hel.jsp中的<h1>hel.jsp</h1>是不会发送到客户端的。<jsp:forward>的作用是“别在显示我,去显示它吧!”。

5.3 jsp:param

  还可以在<jsp:include>和<jsp:forward>标签中使用<jsp:param>子标签,它是用来传递参数的。下面用<jsp:include>来举例说明<jsp:param>的使用。

  a.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>a.jsp</title>
</head>
<body>
    <h1>a.jsp</h1>
    <hr/>
    <jsp:include page="b.jsp">
        <%--给被包含的页面b.jsp传递参数。--%>
        <jsp:param name="username" value="zhangsan"/>
    </jsp:include>
</body>
</html>

  b.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>b.jsp</title>
</head>
<body>
    <h1>b.jsp</h1>
    <hr/>
    <%
        // 获取参数
        String username = request.getParameter("username");
        out.print("你好:" + username);
    %>
</body>
</html>

 

 

 

 

 

参考:https://www.cnblogs.com/xdp-gacl/p/3764991.html

posted @ 2019-03-06 19:20  yi0123  阅读(924)  评论(0编辑  收藏  举报