现在的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>

网页显示结果:

    

posted on 2018-10-12 22:00  kindleheart  阅读(334)  评论(0编辑  收藏  举报