• Java Web(六) JSP


    现在的Java Web开发已经很少使用JSP脚本了,业务逻辑都交给Servlet处理,JSP只负责显示视图,所以接下来的内容就对JSP脚本不做叙述了。。。

    JSP概述

    JSP全名为Java Server Page,是为了简化Servlet的工作而出现的替代品。JSP是一种基于文本的程序,其特点是HTML与Java程序共同存在。执行时JSP会被Tomcat自动编译,编译后的JSP和HttpServlet一样,都是javax.servlet.Servlet接口的子类,因此JSP是另一种形式的Servlet。

    JSP工作原理

    JSP是一种Servlet,但是与HttpServlet的工作方式不太一样。HttpServlet是先由源代码编译为class文件后部署到服务器下的,先编译后部署。而JSP则是先部署源代码后编译为class文件的,先部署后编译。JSP会在客户端第一次请求JSP文件时被编译为HttpJspPage类(接口Servlet的一个子类)。该类会被服务器临时存放在服务器工作目录上面。以后客户端访问这个JSP时,服务器不再编译这个JSP文件,而是直接调用已有的class文件进行响应。所以客户端第一次请求时会感觉比较慢,因为JSP需要编译,而之后速度就快多了。但如果JSP被修改,或者class文件被删除,Tomcat能够检测到,Tomcat会在下一次请求时重新编译JSP,而不需要重启Tomcat。(这种自动检测功能是默认的,可以在web.xml中关闭)

    JSP生命周期

    JSP会被容器转译为Servlet源代码,自动编译为.class文件,载入.class文件,然后生成Servlet对象,如图:

      img

    JSP也是Servlet,运行时只有一个实例。和Servlet一样,JSP实例化,销毁时也会调用Servlet的init()方法与destroy()方法。另外JSP还有自己的初始化方法与销毁方法_jspInit()与_jspDestroy()。Servlet的init方法和destory()方法会相应的调用_jspInit()与_jspDestroy()方法。注意到这两个方法名称前有个下划线,表示这些方法时由容器转译时维护,所以你不能重写这些方法。如果你想对JSP做些初始化工作或收尾工作,你可以重写jspInit()方法或jspDestory方法。

    JSP指令

    JSP指令的主要目的,在于指示容器将JSP转译为Servlet源代码时,一些必须遵守的信息,JSP指令的语法如下所示:

    <%@ 指示类型 [属性="值"]* %>

    在JSP中有三种常见的指令:page、include 与 taglib。page指令告知容器如何转译目前的JSP网页。include指令告知容器将别的JSP页面包括进来进行转译。taglib指令告知容器如何转译这个页面中的标签库。

    1. page指令

      page指令是最常用的指令,可以声明JSP页面的属性等。JSP指令的多个属性可以写在一个page指令里,也可以写在多个page指令里。每个属性只能出现一次,否则出现编译错误。(import属性除外)。

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

      page指令的常见的属性:

      • language:指明解释该JSP时采用的语言。一般为Java语言。默认为Java语言。
      • import:指明编译该JSP时继承哪个类。
      • session:指明该JSP是否内置Session对象。true则内置,false不内置。默认为true。
      • autoFlush:是否允许缓存。如果为true,则使用out.println()等方法输出字符不会立刻到达服务器,而是暂时存在缓存里,缓存满时或者程序执行完毕或者执行out.flush()操作时才到客户端。默认为true。
      • buffer:指定缓存大小。当autoFlush设为true时才有效,例如:<%@ page buffer="10kb" %>。
      • isThreadSafe:指定是否线程安全。如果为true,则运行对个线程同时运行该JSP,否则只运行一个线程,其余线程等待。默认为false。
      • isErrorPage:指定该页面是否为错误处理页面。如果为true,则该JSP内置有一个Exception对象,可直接使用,否则没有,默认为false。
      • errorPage:指明一个错误显示页面。如果该JSP程序抛出了一个未捕捉的异常,则转到errorPage指定的页面。errorPage指定的页面通常是isErrorPage属性为true,且内置的Exception对象为未捕捉的异常。
      • contentType:客户端浏览器根据属性判断文档类型。
      • info:指明JSP的信息。该信息可以通过Servlet.getServletInfo()方法得到。
      • trimDirectiveWhitespaces:是否去掉指令前后的空白字符。默认为fasle。
    2. include指令

      include指令比较简单,只有一种形式:<%@ inlcude file="relativeURL" %>。relativeURL是另一个JSP文件或HTML文件的路径。例如,网站内所有网站均有一个统一风格的导航栏head.jsp与页脚版权的foot.jsp,就可以使用include指令。include指令可以实现页面的区块化。

      <%@include file="head.jsp"%>
      <h2>Hello World</h2>
      <%@include file="foot.jsp"%>
      
    3. taglib

      JSP支持标签技术,使用标签功能能够实现视图代码重用,很少量的代码就能够实现很复杂的显示效果。taglib指令用来指明JSP页面内使用的JSP标签库。taglib指令有两个属性,uri为类库的地址,prefix为便签的前缀。

      <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
      <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
      <html>
      <head>
          <title>book</title>
      </head>
      <body>
      <c:forEach var="book" items="books">
          <h2>${book.name}</h2>
      </c:forEach>
      </body>
      </html>
      

    JSP九大隐式对象

    Servlet和JSP中输出数据都需要使用out对象。Servlet中的out对象是通过response.getWriter()得到的。而JSP中没有定义out对象,却可以直接使用。这是因为out是JSP的内置对象。JSP中一共内置了9个内置对象,分别为out、request、response、config、session、application、page、pageContent、exception。

    • out为javax.servlet.jsp.JspWriter类的实例、服务器向客户端输出的字符内容可以通过out对象输出。
    • request为javax.servlet.ServletRequest类的实例,代表着客户端的请求。
    • response为javax.servlet.ServletResponse类的实例,代表着服务器的响应。
    • config是java.servlet.ServletConfig类的实例。ServletConfig封装了配置在web.xml中初始化JSP的参数。
    • session是java.servlet.http.HttpSession的实例。Session是记录客户会话状态的机制。
    • application是java.servlet.ServletContext的实例。application封装了JSP所在的Web应用程序的信息。
    • page是java.servlet.jsp.HttpJspPage类的实例、page对象代表当前JSP页面,是JSP编译后的Servlet类的对象。相当于java语言中的this。
    • pageContext为java.servlet.jsp.PageContext的实例,PageContext对象代表当前页面编译后的内容。通过PageContext对象能够得到JSP中的资源。  
    • exception为java.lang.Exception类的对象,Exception对象封装了JSP抛出的异常,要使用exception隐藏对象,需要设置<%@ isErrorPage="true" %>。exception通常用来处理错误页面。

    EL表达式

    JSP可以使用EL表达式从page、request、session、application域中获取属性,还可以进行简单的运算和判断,这样可以大大减少JSP页面上Scriptlet的使用。

    EL表达式的11个隐式对象

    • pageContext对应于JSP页面中的pageContext对象。
    • pageScope代表page域中保存属性的Map对象。
    • requestScope代表request域中保存属性的Map对象。
    • sessionScope代表session域中保寸属性的Map对象。
    • applicationScope代表application域中保存属性的Map对象。
    • param代表保持了所有请求参数的Map对象。
    • paramValues代表保存了所有请求参数的Map对象,他对于某个请求参数,返回的是一个String类型的数组。
    • header代表一个保存类所有头字段的Map对象。
    • headerValues代表一个保存类所有头字段的Map对象,返回String类型数组。
    • cookie表示类一个保存类所有cookie的Map对象。
    • initParam表示一个保存了所有Web应用初始化参数的Map对象。
    1. pageContext对象

      EL表达式中的pageContext隐式对象与JSP页面中的pageContext对象相对应,EL表达式可以通过pageContext隐式对象访问其它JSP隐式对象,如访问request、response对象属性时,可以使用表达式$ {pageContext.response.contentType}等。

    2. 代表特定域属性的隐式对象(共4个)

      EL表达式中的pageScope、requestScope、sessionScope和applicationScope四个隐式对象分别用于访问JSP页面的page、request、session、application四个域中的属性。在EL表达式中也可以不使用这些隐式对象来指定查找域,而是直接引用这些域中的属性名称。例如,表达式$ {userName}就会在page、request、session、application这四个作用域内按顺序依次查找userName属性,直到找到为止。

    3. 代表请求参数的隐式对象(2个)

      EL表达式中的隐式对象param和paramValues用于获取客户端访问JSP页面时传递的请求参数的值,由于HTTP协议允许使用一个请求参数名出现多次,即一个请求参数可能会有多个值,所以,EL表达式提供了param和paramValues这两个隐式对象来分别获取请求参数的某个值和所有值。Param隐式对象用于返回一个请求参数的某个值,如果同一个请求参数有多个值,则返回第一个参数的值。paramValues隐式对象用于返回一个请求参数的所有值,返回结果为该参数的所有值组成的字符串数组,例如表达式${paramValues.username[0]}用于返回数组中第一个元素的值。

    4. 代表HTTP请求消息的隐式对象(2个)

      EL表达式中的隐式对象header和headerValues用于获取客户端访问JSP页面时传递的请求头字段的值。由于HTTP协议允许一些请求头字段出现多次,即一个请求头字段可能会有多个值,所以,EL表达式提供了header和headerValues两个隐式对象分别用于获取请求头字段的某个值和所有值。header隐式对象返回一个请求头字段的某个值,如果同一个请求头字段有多个值,则返回第一个值,例如,使用表达式${header.referer}可以非常方便的获取referer请求头字段的值。headerValues隐式对象用于返回一个请求头字段所有值组成的字符串数组。

    5. cookie隐式对象

      EL表达式中的隐式对象cookie是一个代表所有Cookie信息的Map集合,Map集合中元素的关键字为各个Cookie的名称,值则为对应的Cookie对象。使用cookie隐式对象可以访问某个Cookie对象,这些Cookie对象则是通过调用HTTPServletRequest.getCookies()方法得到的,如果多个Cookie共用一个名称,则返回Cookie对象数组中的第一个Cookie对象。例如,要访问一个名为userName的Cookie对象,可以使用表达式${cookie.userName}。

    6. initParam隐式对象

      EL表达式中的initParam是一个代表Web应用程序中的所有初始化参数的Map对象,每个初始化参数的值是ServletContext.getInitParameter(String name)方法返回的字符串。

    EL表达式获取属性

    EL表达式默认是以page、request、session、application的顺序来寻找EL中指定的属性的。EL通过[ ]运算符和 . 运算符来获取指定的属性。

    • 如果使用 . 运算符,则左边可以是JavaBean、Map对象或自定义对象。
    • 如果使用[ ]运算符,则左边可以是JavaBean、Map、数组、List对象或自定义对象。

    简单来说就是有下标的使用[ ],没下标的都用 。

    ${book.name}
    

    EL表达式运算

    EL表达式支持简单的运算,包括加(+)、减(-)、乘(*)、除(/或者div)、取余(%或者mod)、三目运算符等,例如:

    ${1 + 2}<!--输出3-->
    ${1 == 2 ? 3 : 4}<!--输出4-->
    

    EL表达式支持简单的比较运算,包括大于(> 或 gt),小于(< 或 lt),等于(== 或 eq),不等于(!= 或 ne),大于等于(>= 或 ge),小于等于(<= 或 le)等,例如:

    ${1 < 2}<!--输出true-->
    ${5 >= 2}<!--输出false-->
    

    EL表达式还支持逻辑运算,且(&& 或 and),或(|| 或 or),否(! 或 not),例如:

    ${1 < 2 && 5 >= 2}<!--输出false-->
    

    还可以结合JSTL标签库判断域中某值是否为空,然后可以在界面上显示不同的信息,例如:

    <c:if test="${empty user}">
        <h3>请先登入</h3>
    </c:if>
    <c:if test="${not empty user}">
        <h3>${user.name},欢迎您</h3>
    </c:if>
    

    自定义EL函数

    支持自定义EL函数的功能,如果我们想使用EL表达式连接字符串,你可能会想到使用${ str1 + str2 },但是这是错的,因为EL表达式中的 + 只代表加法,要实现该功能,你可以自定义EL函数。

    第一步:编写类,这个函数必须是公开的(public)且是静态方法(static),例如:

    package Utils;
    
    public class Util {
        public static String strcat(String str1, String str2) {
            return str1 + str2;
        }
    }
    

    第二步:编写标签程序库描述(Tag Liabrary Descriptor)文件,这个文件是一个XML文件。

    <?xml version="1.0" encoding="utf-8"?>
    
    <taglib xmlns="http://java.sun.com/xml/ns/j2ee"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
            version="2.0">
    
        <tlib-version>1.0</tlib-version>
        <short-name>util</short-name>
        <uri>http://kindleheart.com/util</uri>
        <function>
            <name>strcat</name>
            <function-class>Utils.Util</function-class>
            <function-signature>
                java.lang.String strcat(java.lang.String,java.lang.String)
            </function-signature>
        </function>
    </taglib>
    

    第三步:直接使用该标签,例如:

    <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@taglib prefix="util" uri="http://kindleheart.com/util" %>
    <%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
    <html>
    <head>
        <title>自定义EL函数</title>
    </head>
    <body>
    <%
        String str1 = "今天天气";
        String str2 = "真好";
        request.setAttribute("str1", str1);
        request.setAttribute("str2", str2);
    %>
    ${util:strcat(requestScope.str1, requestScope.str2)}
    </body>
    </html>
    

    网页显示结果:

        

    作者:kindleheart
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    lua module
    lua require
    lua io
    lua table2
    lua table1
    【leetcode】魔术排列
    【leetcode】速算机器人
    【leetcode】黑白方格画
    【leetcode】根据数字二进制下 1 的数目排序
    【leetcode】插入区间
  • 原文地址:https://www.cnblogs.com/kindleheart/p/9780958.html
Copyright © 2020-2023  润新知