JSP技术(JavaWeb片段六)

JSP技术

JSP概述

JSP(Java Server Pages),建立在Servlet规范之上的动态网页开发技术。与HTML页面最大的不同是在JSP文件中,HTML代码与JAVA可以共同存在,Java代码可以实现页面动态内容的显示。

JSP运行原理

当客户端发送一个.jsp文件的请求时,容器如果找到相应的.jsp文件会将.jsp文件转化为java文件,最终生成一个Servlet实例响应给客户端,从jsp文件到servlet的转换是一个动态的过程,转化发生在第一次请求时,并不是容器一开始就会将.jsp文件转化为servlet实例,对jsp文件的访问本质上是一个对servlet实例的访问。

前面在学习tomcat目录结构的时候,work目录是用来存放运行时jsp文件编译的代码,接下来通过对.jsp编译后的文件进行分析。在idea中,每个tomcat都是一个主tomcat的副本,在idea的tomcat启动日志中,如下图示例,可以查看该副本所在的位置,从而可以找到work目录下。

index.jsp文件

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
    Hello,world!
  <%
    out.write("Change the world!");
  %>
  </body>
</html>

index_jsp.java类

可以看到,index_jsp这个类是继承子HttpJspBase的,而HttpJspBase类(可以在tomcat源码目录src\java\org\apache\jasper\runtime路径查看到)是继承HttpServlet的,所以HttpJspBase类是一个Servlet,而index_jsp又是继承HttpJspBase类的,所以index_jsp类也是一个Servlet,所以当浏览器访问服务器上的index.jsp页面时,其实就是在访问index_jsp这个Servlet,index_jsp这个Servlet使用_jspService这个方法处理请求。

public final class index_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;
  }

  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 java.lang.String _jspx_method = request.getMethod();
    if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
      response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET POST or HEAD");
      return;
    }

    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("\n");
      out.write("\n");
      out.write("<html>\n");
      out.write("  <head>\n");
      out.write("    <title>$Title$</title>\n");
      out.write("  </head>\n");
      out.write("  <body>\n");
      out.write("    Hello,world!\n");
      out.write("  ");

    out.write("Change the world!");
  
      out.write("\n");
      out.write("  </body>\n");
      out.write("</html>\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);
    }
  }
}

仔细观察源码,可以看到,index_jsp默认将三个常用的包前缀为javax.servlet包导入了jsp中,这也是为什么我们能够在jsp页面中使用servlet相关的对象而不用导包,另外web为jsp提供了9大内置对象,上面展示了8个,都已经定义并初始化了,这也是为什么能够使用域对象及获取到相应值的原因。类中所有对html代码的处理都是通过out.write()写出到浏览器中的。

在jsp中编写的java代码会原封不动地翻译成java代码,如<%out.print(“Hello,world!”);%>直接翻译成out.write(" Hello,world!\n");而HTML代码则会翻译成使用out.write("\r\n");的形式输出到浏览器。

JSP基础语法

JSP脚本元素是指嵌套在<%和%>之中的一条或多条Java语句。通过JSP脚本元素可以使Java代码嵌入到HTML页面中。

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

  • JSP脚本片段
  • JSP声明语句
  • JSP表达式

JSP表达式

JSP脚本表达式(expression)用于将程序数据输出到客户端
 语法:<%= 变量或表达式 %>
 举例:输出当前系统时间:

<%= new java.util.Date() %> 

JSP引擎在翻译脚本表达式时,会将程序数据转成字符串,然后在相应位置用out.print(…) 将数据输给客户端。
  JSP脚本表达式中的变量或表达式后面不能有分号(;)

JSP脚本片段

JSP脚本片断(scriptlet)用于在JSP页面中编写多行Java代码。语法:

<%

**多行Java代码**

%>

注意事项:

1)在<% %>中可以定义变量、编写语句,JSP脚本片段不能定义方法

2)JSP脚本片断中只能出现java代码,不能出现其它模板元素, JSP引擎在翻译JSP页面中,会将JSP脚本片断中的Java代码将被原封不动地放到Servlet的_jspService方法中

3)JSP脚本片断中的Java代码必须严格遵循Java语法,例如,每执行语句后面必须用分号(;)结束

4)在一个JSP页面中可以有多个脚本片断,在两个或多个脚本片断之间可以嵌入文本、HTML标记和其他JSP元素。

实例:单个脚本片断中的Java语句可以是不完整的。

<%
    int a = 10;
  %>
    hello,world!
  <%
    System.out.println(a);
  %>

JSP声明

JSP声明语句用于声明变量和方法,语法格式:

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

Jsp声明中的java代码被翻译到_jspService方法的外面,这也就决定了在JSP声明中不能使用隐式对象,因为JSP隐式对象的作用范围仅限于Servlet的_jspService方法。

JSP声明语句中定义的都是成员方法、成员变量、静态方法、静态变量、静态代码块等

JSP注释

在JSP中,注释有两大类:

显式注释:直接使用HTML风格的注释:<!--注释内容-->

隐式注释:直接使用JAVA的注释:///*..*/

JSP自己的注释:<%--注释内容--%>

这三种注释的区别

HTML的注释在浏览器中查看源文件的时候是可以看得到的,而JAVA注释和JSP注释在浏览器中查看源文件时是看不到注释的内容的,这就是这三种注释的区别。

JSP指令

JSP指令(directive)是为JSP引擎而设计的,它们并不直接产生任何可见输出,而只是告诉引擎如何处理JSP页面中的其余部分

在JSP 2.0规范中共定义了三个指令:

  • page指令
  • Include指令
  • taglib指令

JSP指令的基本语法格式:<%@ 指令 属性名="值" %>

例如:

<%@ page contentType="text/html;charset=gb2312"%>

如果一个指令有多个属性,这多个属性可以写在一个指令中,也可以分开写。
  例如:

<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.util.Date"%>

也可以写作:

<%@ page contentType="text/html;charset=gb2312" import="java.util.Date"%>

page指令

page指令用于定义JSP页面的各种属性,无论page指令出现在JSP页面中的什么地方,它作用的都是整个JSP页面,为了保持程序的可读性和遵循良好的编程习惯,page指令最好是放在整个JSP页面的起始位置。例如

JSP 2.0规范中定义的page指令的完整语法:

<%@ page
    [ language="java" ]
    [ extends="package.class" ]
    [ import="{package.class | package.*}, ..." ]
    [ session="true | false" ]
    [ buffer="none | 8kb | sizekb" ]
    [ autoFlush="true | false" ]
    [ isThreadSafe="true | false" ]
    [ info="text" ]
    [ errorPage="relative_url" ]
    [ isErrorPage="true | false" ]
    [ contentType="mimeType [ ;charset=characterSet ]" | "text/html ; charset=ISO-8859-1" ]
    [ pageEncoding="characterSet | ISO-8859-1" ]
    [ isELIgnored="true | false" ]
%>

1、page指令的import属性是唯一可以声明多次的属性,其他属性的声明只能出现一次

可以在一条page指令的import属性中引入多个类或包,其中的每个包或类之间使用逗号(,)分隔

在Jsp页面中,Jsp引擎会自动导入下面的包

  • java.lang.*
  • javax.servlet.*
  • javax.servlet.jsp.*
  • javax.servlet.http.*

例如:

<%@ page import="java.util.*,java.io.*,java.sql.*"%>

上面的语句也可以改写为使用多条page指令的import属性来分别引入各个包或类

例如:

<%@ page import="java.util.Date"%>
<%@ page import="java.io.*" %>
<%@ page import="java.sql.*" %>

2、page指令的errorPage属性

  • errorPage属性的设置值必须使用相对路径,如果以“/”开头,表示相对于当前Web应用程序的根目录(注意不是站点根目录),否则,表示相对于当前页面
  • 可以在web.xml文件中使用<error-page>元素为整个Web应用程序设置错误处理页面。
  • <error-page>元素有3个子元素,<error-code>、<exception-type>、<location>
  • <error-code>子元素指定错误的状态码,例如:<error-code>404</error-code>
  • <exception-type>子元素指定异常类的完全限定名,例如:<exception-type>java.lang.ArithmeticException</exception-type>
  • <location>子元素指定以“/”开头的错误处理页面的路径,例如:<location>/ErrorPage/404Error.jsp</location>
  • 如果设置了某个JSP页面的errorPage属性,那么在web.xml文件中设置的错误处理将不对该页面起作用。

使用page指令的的isErrorPage属性显式声明页面为错误页面

如果某一个jsp页面是作为系统的错误处理页面,那么建议将page指令的isErrorPage属性(默认为false)设置为**“true”**来显式声明这个Jsp页面是一个错误处理页面。

例如:将error.jsp页面显式声明为错误处理页面

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" isErrorPage="true"%>
<html>
  <head>
    <title>错误信息友好提示页面</title>
  </head>

  <body>
           对不起,出错了,请联系管理员解决!
  </body>
</html>

将error.jsp页面显式声明为错误处理页面后,有什么好处呢,好处就是Jsp引擎在将jsp页面翻译成Servlet的时候,在Servlet的 _jspService方法中会声明一个exception对象,然后将运行jsp出错的异常信息存储到exception对象中,如下所示:

img

由于Servlet的_jspService方法中声明了exception对象,那么就可以在error.jsp页面中使用exception对象,这样就可以在Jsp页面中拿到出错的异常信息了,如下:

img

如果没有设置isErrorPage=“true”,那么在jsp页面中是无法使用exception对象的,因为在Servlet的_jspService方法中不会声明一个exception对象,如下所示:

img

img

Jsp有9大内置对象,而一般情况下exception对象在Jsp页面中是获取不到的,只有设置page指令的isErrorPage属性为**“true”**来显式声明Jsp页面是一个错误处理页面之后才能够在Jsp页面中使用exception对象。

include指令

在JSP中对于包含有两种语句形式:

  1. @include指令
  2. <jsp:include>指令

@include可以包含任意的文件,当然,只是把文件的内容包含进来。

include指令用于引入其它JSP页面,如果使用include指令引入了其它JSP页面,那么JSP引擎将把这两个JSP翻译成一个servlet。所以include指令引入通常也称之为静态引入。

语法:<%@ include file=“relativeURL”%>,其中的file属性用于指定被引入文件的路径。路径以“/”开头,表示代表当前web应用。

include指令细节注意问题:

  1. 被引入的文件必须遵循JSP语法。
  2. 被引入的文件可以使用任意的扩展名,即使其扩展名是html,JSP引擎也会按照处理jsp页面的方式处理它里面的内容,为了见明知意,JSP规范建议使用.jspf(JSP fragments(片段))作为静态引入文件的扩展名。
  3. 由于使用include指令将会涉及到2个JSP页面,并会把2个JSP翻译成一个servlet,所以这2个JSP页面的指令不能冲突(除了pageEncoding和导包除外)。

使用@include可以包含任意的内容,文件的后缀是什么都无所谓。这种把别的文件内容包含到自身页面的@include语句就叫作静态包含,作用只是把别的页面内容包含进来,属于静态包含。

jsp:include指令

jsp:include指令为动态包含,如果被包含的页面是JSP,则先处理之后再将结果包含,而如果包含的是非*.jsp文件,则只是把文件内容静态包含进来,功能与@include类似。后面再具体介绍

JSP隐式对象

JSP运行原理

每个JSP 页面在第一次被访问时,WEB容器都会把请求交给JSP引擎(即一个Java程序)去处理。JSP引擎先将JSP翻译成一个_jspServlet(实质上也是一个servlet) ,然后按照servlet的调用方式进行调用。
  由于JSP第一次访问时会翻译成servlet,所以第一次访问通常会比较慢,但第二次访问,JSP引擎如果发现JSP没有变化,就不再翻译,而是直接调用,所以程序的执行效率不会受到影响。
  JSP引擎在调用JSP对应的_jspServlet时,会传递或创建9个与web开发相关的对象供_jspServlet使用。JSP技术的设计者为便于开发人员在编写JSP页面时获得这些web对象的引用,特意定义了9个相应的变量,开发人员在JSP页面中通过这些变量就可以快速获得这9大对象的引用。

9个内置对象

NO.内置对象类型
1pageContextjavax.servlet.jsp.PageContext
2requestjavax.servlet.http.HttpServletRequest
3responsejavax.servlet.http.HttpServletResponse
4sessionjavax.servlet.http.HttpSession
5applicationjavax.servlet.ServletContext
6configjavax.servlet.ServletConfig
7outjavax.servlet.jsp.JspWriter
8pagejava.lang.Object
9exceptionjava.lang.Throwable
9个隐式对象
	pageContext:可以通过成员方法得到其他内置对象
		getException方法返回exception
		getPage方法返回page
		getRequest方法返回request
		getResponse方法返回response
		getServletConfig方法返回config
		getServletContext方法返回application
		getSession方法返回session
		getOut方法返回out
	application
	config
	session
	request
	response
	page
	out
	exception

request,response,session,application,config这些对象在前面都已经作了详细的介绍,这里重点介绍一下剩下的pageContext对象,out对象,page对象。

page对象

当前页面转化为servlet的实例。可以理解为当前的页面对象,开发中不常用,了解即可。

out对象

out对象用于向客户端发送文本数据。out对象是通过调用pageContext对象的getOut方法返回的,其作用和用法与ServletResponse.getWriter方法返回的PrintWriter对象非常相似。
JSP页面中的out对象的类型为JspWriter,JspWriter相当于一种带缓存功能的PrintWriter,设置JSP页面的page指令的buffer属性可以调整它的缓存大小,甚至关闭它的缓存。
只有向out对象中写入了内容,且满足如下任何一个条件时,out对象才去调用ServletResponse.getWriter方法,并通过该方法返回的PrintWriter对象将out对象的缓冲区中的内容真正写入到Servlet引擎提供的缓冲区中:

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

out对象的工作原理:

pageContext对象

pageContext作为域对象

pageContext对象可以作为容器来使用,因此可以将一些数据存储在pageContext对象中。

pageContext对象的常用方法

public void setAttribute(String name,Object value);
public Object getAttribute(String name);
public void removeAttribute(String name);

/*
* Searches for the named attribute in page, request, session (if valid),
* and application scope(s) in order and returns the value associated or
* null.
*/
public Object findAttribute(java.lang.String name);

findAttribute(String name):当要查找某个属性时,findAttribute方法按照查找顺序==“page→request→session→application”==在这四个对象中去查找,只要找到了就返回属性值,如果四个对象都没有找到要查找的属性,则返回一个null。

实例:使用pageContext对象的findAttribute(String name)查找个域内的值

<%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
    <%
      pageContext.setAttribute("a", "AA");
      request.setAttribute("b", "BB");
      session.setAttribute("c", "CC");
      application.setAttribute("d", "DD");
    %>
  <%
    String a = (String) pageContext.findAttribute("a");
    String b = (String) pageContext.findAttribute("b");
    String c = (String) pageContext.findAttribute("c");
    String d = (String) pageContext.findAttribute("d");
    String e = (String) pageContext.findAttribute("e");
  %>
    <h1>pageContext.findAttribute方法查找到的属性值:</h1>
    <h3>a==><%=a%></h3>
    <h3>b==><%=b%></h3>
    <h3>c==><%=c%></h3>
    <h3>d==><%=d%></h3>
    <h3>e==>查找不存在的属性<%=e%></h3>
    <hr>
    <h1>使用EL表达式进行输出:</h1>
    <h3>a==>${a}</h3>
    <h3>b==>${b}</h3>
    <h3>c==>${c}</h3>
    <h3>d==>${d}</h3>
    <h3>e==>查找不存在的属性${e}</h3>
  </body>
</html>

EL表达式语句在执行时,会调用pageContext.findAttribute方法,用标识符为关键字,分别从page、request、 session、application四个域中查找相应的对象,找到则返回相应对象,找不到则返回”” (注意,不是null,而是空字符串)。

pageContext对象中封装了访问其它域的方法

public Object getAttribute(String name,int scope);
public void setAttribute(String name, Object value,int scope);
public void removeAttribute(String name,int scope);

代表各个域的常量

PageContext.APPLICATION_SCOPE
PageContext.SESSION_SCOPE
PageContext.REQUEST_SCOPE
PageContext.PAGE_SCOPE 

使用pageContext访问其他域对象里面的值

String a1 = (String) pageContext.getAttribute("b", PageContext.REQUEST_SCOPE);

除了上述介绍,pageContext还有引入和跳转到其他web资源的功能。

隐式对象属性范围

JSP中存在的4大范围对象:

pageContext(page)
request
session
application

他们四对象公有的方法是

Object getAttribute(String name);
void setAttribute(String key, Object value);
void removeAttribute(String name);

通过范围对象设置的属性值是否可以在另一个页面中可以取得,这就是属性的作用范围,或者说属性的作用域。

范围大小:

  • 当前页有效:一个属性只能在一个页面中取得,跳转到其他页面无法取得
  • 一次请求有效:一个页面中设置的属性,只要经过了服务器跳转,则跳转之后的页面可以继续取得
  • 一次会话有效:一个用户设置的内容,只要是与此用户相关的页面都可以访问(一个会话表示一个人,这个人设置的东西只要这个人不走,就依然有效)
  • 全局有效:在整个服务器上设置的属性,所有人都可以访问

JSP页面,如果出现EL表达式没有获取到request域中的值时,看看存放在域中的属性是否是二次请求了。

1、page属性范围(pageContext)

2、request属性范围

3、session属性范围

4、application属性范围

JSP动作元素

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

JSP动作元素包括:

  • <jsp:include>标签

  • <jsp:forward>标签

  • <jsp:param>标签

<jsp:include>标签

<jsp:include>标签用于把另外一个资源的输出内容插入进当前JSP页面的输出内容之中,这种在JSP页面执行时的引入方式称之为动态引入。
语法:

<jsp:include page="relativeURL | <%=expression%>" flush="true|false" />

page属性用于指定被引入资源的相对路径,它也可以通过执行一个表达式来获得。
flush属性指定在插入其他资源的输出内容时,是否先将当前JSP页面的已输出的内容刷新到客户端。

<jsp:include>标签与<%@ include ..%>指令的区别

  • <jsp:include>标签是动态引入<jsp:include>标签标签涉及到的2个JSP页面会翻译成2个servlet这2个servlet的内容在执行时进行合并

  • <%@ include ..%>指令是静态引入涉及到的2个JSP页面会翻译成1个servlet,其内容是是编译完成后进行合并,合并在同一个文件中。

下面看一个示例:

header文件中在JSP脚本段中定义了一个变量,index.jsp中也定义了相同的一个变量,当使用<%@ include ..%>指令引入header文件时,提示变量已经存在,出现这种错误的原因就是静态引入,<%@ include ..%>指令涉及的2个jsp会编译输出到一个文件中,而JSP脚本段的代码都会出现在_jspService()方法中,这样就会导致变量重复定义的问题。

而采用<jsp:include ..%>引入header.jsp就能解决上面这种问题,如下图

<jsp:include ..>是将2个jsp文件分别进行编译,输出两个servlet相关的类,然后在将结果进行合并。两个变量在不同的类中,所以不会存在<%@ include ..%>出现的错误。

<jsp:forward>标签

<jsp:forward>标签用于把请求转发给另外一个资源。

语法:
<jsp:forward page="relativeURL | <%=expression%>" />
page属性用于指定请求转发到的资源的相对路径,它也可以通过执行一个表达式来获得。

示例:index.jsp跳转到header.jsp,并且通过<jsp:param>传递参数,注意接受的时候使用request.getParamter,所以它不是放到域对象的属性中的。

<%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" %>
<html>
<head>
  <title>$Title$</title>
</head>
<body>
<jsp:forward page="header.jsp">
  <jsp:param name="info" value='<%=URLEncoder.encode("你好", "utf-8")%>'/>
</jsp:forward>
</body>

</html>

header.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>$Title$</title>
</head>
<body>
header.jsp
req:<%=URLDecoder.decode(request.getParameter("info"), "utf-8")%>
</body>
</html>

<jsp:param>标签

当使用<jsp:include>和<jsp:forward>标签引入或将请求转发给其它资源时,可以使用<jsp:param>标签向这个资源传递参数。

语法1:
<jsp:include page="relativeURL | <%=expression%>">
<jsp:param name="parameterName" value="parameterValue|<%= expression %>" />
</jsp:include>
语法2:
<jsp:forward page="relativeURL | <%=expression%>">
<jsp:param name="parameterName" value="parameterValue|<%= expression %>" />
</jsp:include>

<jsp:param>标签的name属性用于指定参数名,value属性用于指定参数值。在<jsp:include>和<jsp:forward>标签中可以使用多个<jsp:param>标签来传递多个参数。

JSTL标签库

JSTL标签库的使用是为弥补html标签的不足,规范自定义标签的使用而诞生的。使用JSLT标签的目的就是不希望在jsp页面中出现java逻辑代码。

JSTL的使用和EL表达式也是分不开的。

JSTL标签库的分类

  • 核心标签(用得最多)
  • 国际化标签(I18N格式化标签)
  • 数据库标签(SQL标签,很少使用)
  • XML标签(几乎不用)
  • JSTL函数(EL函数)

核心标签库

JSTL的核心标签库标签共13个,使用这些标签能够完成JSP页面的基本功能,减少编码工作。

从功能上可以分为4类:表达式控制标签、流程控制标签、循环标签、URL操作标签。
(1)表达式控制标签out标签、set标签、remove标签、catch标签。
(2)流程控制标签if标签、choose标签、when标签、otherwise标签
(3)循环标签forEach标签、forTokens标签
(4)URL操作标签import标签、url标签、redirect标签、param标签

在JSP页面引入核心标签库的代码为:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
表达式控制标签

<c:out>标签

<c:out>标签主要是用来输出数据对象(字符串、表达式)的内容或结果
  在使用Java脚本输出时常使用的方式为:<% out.println(“字符串”)%> 或者 <%=表达式%> ,在web开发中,为了避免暴露逻辑代码会尽量减少页面中的Java脚本,使用<c:out>标签就可以实现以上功能。

<c:out value=”字符串”>
<c:out value=”EL表达式”>

JSTL的使用是和EL表达式分不开的,EL表达式虽然可以直接将结果返回给页面,但有时得到的结果为空,<c:out>有特定的结果处理功能,EL的单独使用会降低程序的易读性,建议把EL的结果输入放入<c:out>标签中。

**<c:out>标签**标签的语法:

【语法1】:<c:out value=”要显示的数据对象” [escapeXml=”true|false”] [default=”默认值”]/>
【语法2】:<c:out value=”要显示的数据对象” [escapeXml=”true|false”]>默认值</c:out>
这两种方式没有本质的区别,只是格式上的差别。[escapeXml=”true|false”] [default=”默认值”]这些使用[]属性表示是不是必须的。
value :指定要输出的内容
escapeXml :是否将特殊字符进行html编码转换后输出
default :指定如果value属性的值为null时所输出的默认值

<c:set>标签的功能

<c:set>标签用于把某一个对象存在指定的域范围内,或者将某一个对象存储到Map或者JavaBean对象中。

语法格式:<c:set>标签的编写共有4种语法格式。

语法1:存值,把一个值放在指定的域范围内。
  <c:set value=”值1” var=”name1” [scope=”page|request|session|application”]/>
  含义:把一个变量名为name1值为“值1”的变量存储在指定的scope范围内。
  语法2:
  <c:set var=”name2” [scope=”page|request|session|application”]>
  值2
  </c:set>
  含义:把一个变量名为name2,值为值2的变量存储在指定的scope范围内。
  语法3:
  <c:set value=”值3” target=”JavaBean对象” property=”属性名”/>
  含义:把一个值为“值3”赋值给指定的JavaBean的属性名。相当与setter()方法。
  语法4:
  <c:set target=”JavaBean对象” property=”属性名”>
  值4
  </c:set>
  含义:把一个值4赋值给指定的JavaBean的属性名。

标签属性

流程控制标签

<c:if>标签:功能等同于编程语言中的if,实现条件控制

<c:if>标签的语法
【语法1】:没有标签体内容(body)
<c:if test="testCondition" var="varName" [scope="{page|request|session|application}"]/>
【语法2】:有标签体内容
<c:if test="testCondition" [var="varName"] [scope="{page|request|session|application}"]>
标签体内容
</c:if>
【参数说明】:
(1)test属性用于存放判断的条件,一般使用EL表达式来编写。
(2)var属性用来存放判断的结果,类型为true或false。
(3)scopes属性用来指定var属性存放的范围。

<c:choose>、<c:when>和<c:otherwise>标签实现if...else功能

<c:choose>、<c:when>和<c:otherwise>,这3个标签通常情况下是一起使用的,<c:choose>标签作为<c:when><c:otherwise>标签的父标签来使用。

语法
 <c:choose>
         <c:when test="条件1">
      //业务逻辑1
         <c:when>
   <c:when test="条件2">
      //业务逻辑2
         <c:when>
   <c:when test="条件n">
      //业务逻辑n
         <c:when>
         <c:otherwise>
      //业务逻辑
   </c:otherwise>
 </c:choose>
循环标签

<c:forEach>实现对集合的循环迭代。

<c:forEach var="name" items="collection"
	varStatus="statusName" begin="begin"
	end="end" step="step">
</c:forEach>
【参数解析】:
(1)var设定变量名用于存储从集合中取出元素。
(2)items指定要遍历的集合。
(3)varStatus设定变量名,该变量用于存放集合中元素的信息。    
(4)begin、end用于指定遍历的起始位置和终止位置(可选)。
(5)step指定循环的步长。
属性名称是否支持EL表达式属性类型是否必须默认值
varNOString
itemsYESArrays|Collection|Iterator|Enumeration|Map|String []
beginYESint0
endYESint集合中最后一个元素
stepYESint1
varStatusNOString
varStatus的4个状态
属性名类型说明
indexint当前循环的索引值
countint循环的次数
fristboolean是否为第一个位置
lastboolean是否为最后一个位置
URL操作标签

<c:param><c:url><c:redirect>

将value中的值放入var中的变量中,var中的变量根据scope存放到不同的域中,以便可以通过EL表达式直接使用。

EL表达式

EL 全名为Expression Language。EL主要作用:获取数据执行运算获取web域对象快速获取域对象中的属性

获取数据

EL表达式获取数据语法格式:${表达式}

EL表达式语句在执行时,会调用pageContext.findAttribute方法,用标识符为关键字,分别从page、request、session、application四个域中查找相应的对象,找到则返回相应对象,找不到则返回”” (注意,不是null,而是空字符串)。

EL表达式可以很轻松获取JavaBean的属性,或获取数组、Collection、Map类型集合的数据

示例:注意一下EL表达式如何取复合对象中的引用和Map对象。

<html>
  <head>
    <title>el表达式获取数据</title>
  </head>

  <body>
   
    <!-- 在jsp页面中,使用el表达式可以获取bean中引用的属性 -->
    <%
        Person person = new Person();
        Address address = new Address();
        person.setAddress(address);

        request.setAttribute("person",person);
    %>
       ${person.address.name}
     <hr>
    <!-- 在jsp页面中,使用el表达式获取list集合中指定位置的数据 -->
    <%
        Person p1 = new Person();
        p1.setName("孤傲苍狼");

        Person p2 = new Person();
        p2.setName("白虎神皇");

        List<Person> list = new ArrayList<Person>();
        list.add(p1);
        list.add(p2);

        request.setAttribute("list",list);
    %>

    <!-- 取list指定位置的数据 -->
    ${list[1].name}

    <!-- 迭代List集合 -->
    <c:forEach var="person" items="${list}">
        ${person.name}
    </c:forEach>
    <hr>
    <!-- 在jsp页面中,使用el表达式获取map集合的数据 -->
    <%
        Map<String,String> map = new LinkedHashMap<String,String>();
        map.put("a","aaaa");
        map.put("b","bbbb");
        map.put("c","cccc");
        map.put("1","1111");
        request.setAttribute("map",map);
    %>

    <!-- 根据关键字取map集合的数据 -->
      ${map.c}
      ${map["1"]}
      <hr>
      <!-- 迭代Map集合 -->
      <c:forEach var="me" items="${map}">
          ${me.key}=${me.value}<br/>
      </c:forEach>
    <hr>
  </body>
</html>

执行运算

EL中的运算符

1、关系运算符

注:与字符串的比较形式为: ${value == 'string'},引号包裹

2、逻辑运算符:

3、empty运算符:检查对象是否为null(空),结果为布尔类型

基本语法格式:${empty var} 或者 ${empty(var)}

4、二元表达式:${user!=null?user.name :""}

5、[ ] 和 . 号运算符

点运算符用于访问JSP页面中某些对象的属性,例如${bean.property}

[]运算也是运用访问JPS页面中某些对象的属性,但是当获取的属性中包含特殊符号,如“-”或“?”等非字母或数字的符号(因为不符合EL表达式标识符定义),就只能使用[]运算符来访问改属性,语法格式如下:

${user["my-name"]}
//或者在获取http请求头的时候,只能使用[]运算符
${header["Accept-Cookie"]}

示例:

23 mod 5 = ${23 mod 5}<br>

user是否为空:${user == null}<br>
user是否为空:${empty user}<br>

<%
  List<String> list = new ArrayList<String>();
  list.add("gacl");
  list.add("xdp");
  request.setAttribute("list",list);
%>
<c:if test="${!empty(list)}">
  <c:forEach var="item" items="${list}">
    ${item}
  </c:forEach>
</c:if>
<br/>
 <%
       List<String> emptyList = null;
   %>
 <%--使用empty运算符检查对象是否为null(空) --%>
 <c:if test="${empty(emptyList)}">
       对不起,没有您想看的数据
 </c:if><br/>
1+2 > 3: ${(1+2) gt 3 ? "成立":"不成立"}

EL隐式对象

EL表达式语言中定义了11个隐含对象,使用这些隐含对象可以很方便地获取web开发中的一些常见对象,并读取这些对象的数据。

隐式对象作用
pageContext对应于JSP页面中的pageContext对象
pageScope代表page域中用于保存属性的Map对象
requestScope代表request域中用于保存属性的Map对象
sessionScope代表session域中用于保存属性的Map对象
applicationScope代表application域中用于保存属性的Map对象
param表示一个保存了所有请求参数的Map对象
paramValues表示一个保存了所有请求参数的Map对象,它对于某个请求参数, 返回的是一个string类型数组
header表示一个保存了所有http请求头字段的Map对象
headerValues表示一个保存了所有http请求头字段的Map对象,返回string类型数组
cookie表示一个保存了所有cookie的Map对象
initParam表示一个保存了所有web应用初始化参数的map对象

EL隐式对象和JSP隐式对象的比较

jsp中的四大域对象不等于EL表达式中的四大域对象,或者说EL表达式没有域对象

request≠requestScope,session≠sessionScope…

**pageScope,requestScope…**只是代表了用于保存域对象属性的Map对象。但是可以通过EL中的pageContext拿到JSP中的四大域对象

在JSP中获取域对象有两种方法,一个是直接使用内置对象,二是通过pageContext.getXxx()方法获取。

在EL中获取JSP中的域对象只能通过pageContext.xxx方法

JSP:pageContext.getRequest()
||
EL:pageContext.request
JSP:pageContext.getSession()
||
EL:pageContext.session
...

转化方法:去掉JSP中的get、set方法,然后首字母小写

示例:

<%
  request.setAttribute("name", "Stronger");
%>
:从JSP四大域对象中查找
${name}<br>
${requestScope.name}

<br>characterEncoding:属性
${pageContext.request.characterEncoding}<br>
<br>requestScope.characterEncoding是不存在的,
requestScope并不代表域对象
${requestScope.characterEncoding}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值