JavaWeb学习笔记(十四)--JSP语法

1. JSP语法

JSP语法主要包含以下几类:

  • JSP模板元素
  • JSP脚本表达式
  • JSP脚本片段
  • JSP声明
  • JSP注释
  • JSP指令
  • JSP标签
  • JSP内置对象

2. JSP模板元素

JSP页面中的HTML内容称之为JSP的模板元素。

JSP模板元素定义了网页的基本骨架,即定义了页面的结构和外观。

3. JSP脚本表达式

JSP脚本表达式用于将程序数据输出到客户端

语法:

 

<%= 变量或表达式  %> 

例如:

<%= new Date()%>

JSP引擎在翻译脚本表达式时,会将程序数据转成字符串,然后在相应的位置用out.print()将数据输出给客户端,上面的的例子会翻译成out.print( new Date());。

JSP脚本表达式中的变量或者表达式后面不能有分号

4. JSP脚本片段

JSP脚本片段用于在JSP页面中编写多行Java代码。

语法:

 

<%
  多行java代码
%>

JSP脚本片段中只能出现Java代码,不能出现其他的模板元素,JSP引擎在翻译JSP页面时,会将JSP脚本片段的Java代码原封不动的放到翻译后的Servlet的_jspService方法中。

JSP脚本片段中的Java代码必须严格遵守Java语法。

在一个JSP页面中可以有多个脚本片段,在脚本片段之间可以嵌入文本、HTML标记和JSP元素。多个脚本片段中的代码可以相互访问,犹如将所有代码放在一对<% %>中,例如:

 <%
   int x = 10;
   out.print(x);
 %>
  <p>这是JSP页面文本</p>
  <%
    int y = 20;
    out.print(y);
    out.print("<br/>");
    out.print(x + y);  // 使用上一个脚本片段定义的变量x
  %>

单个脚本片段中的Java代码可以是不完整的,但是多个脚本片段组合的结果必须是完整的Java语句块,例如:

  <%
    for (int i = 0; i < 5; i++) {

  %>
  <h2>这个段标题输出5次</h2>
  <%
    }
  %>

5. JSP声明

JSP页面中编写的所有代码,默认回翻译到Servlet的_jspService方法中,而JSP声明的Java代码会被翻译到_jspService方法的外面。

语法:

<%!
  java代码
%>

JSP声明可用于定义JSP页面转换成的Servlet的静态代码块、成员变量和方法。

多个静态代码块、变量和函数可以定义在一个JSP声明中,也可以分别单独定义在多个JSP声明中。

JSP隐式对象的作用范围仅限于Servlet的_jspService方法,所以在JSP声明中不能使用这些隐式对象。

JSP声明举例:

<%!
    static {
      System.out.println("loading Servlet");
    }
    private int globalVar = 0;
    public void myFunction1() {
      System.out.println("myFunction1");
    }
  %>
  <%!
    public void myFunction2() {
      System.out.println("myFunction2");
    }
  %>

6. JSP注释

语法:

<%--
  注释信息
 --%>

JSP引擎在将JSP页面翻译成Servlet时,会忽略JSP页面中被注释的内容。

HTML的注释<!-- -->,用此注释,注释内容会发送给浏览器,只是浏览器不识别。JSP的注释不会发送给浏览器,并且脚本代码只能用JSP注释(因为服务器不识别HTML注释)。

 7. JSP指令

JSP指令是为JSP引擎(把JSP翻译成Servlet的程序)而设计的,它们并不直接产生任何可见的输出,而只是告诉引擎如何处理JSP页面的其余部分。在JSP2.0规范中共定义了3个指令:

  • page指令
  • include指令
  • taglib指令(自定义标签的时候再做说明)

7.1 JSP指令简介

JSP指令的基本语法格式:

<%@ 指令 属性名="" %>

举例:

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

如果一个指令有多个属性,这些属性可以卸载一个指令中,也可以分开写。

例如:

<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>

也可以写作:

<%@ page contentType="text/html;charset=UTF-8" language="java"   import="java.util.Date" %>

7.2 page指令

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

JSP 2.0规范中定义的page指令的常用属性:

<%@ page
        language="java"          JSP里面的代码语言
        extends="package.class"   翻译后的Servlet继承哪个类,一般不改
        import="package1.class, package2.class"  JSP页面导入的Java类
        session="true | false"   值为true会在翻译后的Servlet中创建session对象,在JSP页面中可以直接使用。默认值为true。
        buffer="8kb | none | sizekb"  设置JSP页面的缓冲,默认8kb
        autoFlush="true | false"   设置JSP页面缓冲满了是否自动刷新,默认为true,自动刷新
        errorPage="relative_url"   指定JSP页面的错误处理页面
        isErrorPage="false | true" 设置当前JSP页面是否是错误页面,默认值为false
        contentType="mimeType;charset=characterSet"  设置JSP页面类型,用于显示
        pageEncoding="characterSet"  设置JSP页面编码格式
        isELIgnored="false | true"  设置是否忽略EL表达式,默认是false,不忽略
%>

 7.2.1 import属性

JSP引擎会自动导入下面的包:

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

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

<%@ page contentType="text/html;charset=UTF-8" language="java"   import="java.util.Date, java.sql.*, java.io.*" %>

或者写成多条page指令的import属性分别导入:

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

7.2.2 errorPage属性

<%@ page errorPage="/error.jsp" %>

指定JSP的错误处理页面,就是JSP挂了会跳转的页面。errorPage的属性值设置必须使用相对路径,如果以“/”开头,表示相对于当前web应用程序的根目录,否则,表示相对于当前页面。例如:

<!-- division.jsp -->
<%@ page contentType="text/html;charset=UTF-8" language="java" errorPage="/WEB-INF/errors/divisorError.jsp"%>
<html>
<head>
    <title>division</title>
</head>
<body>
    <%
        int a = 1 / 0;
    %>
</body>
</html>
<!-- divisorError.jsp -->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>divisorError</title>
</head>
<body>
    除数不能为0!
</body>
</html>

当访问division.jsp时,由于除数为0,会抛异常。当指定了errorPage后,会跳转到对应的错误页面。

 

如果项目中的JSP文件比较多,对每个JSP都配置errorPage,会比较麻烦。这种情况可以使用<error-page>在web.xml中配置,<error-page>包含三个元素:

<error-code></error-code>    --配置错误码
<exception-type></exception-type> --配置错误类型
<location></location> --配置出错时跳转的页面

上面除数为0的例子,在web.xml中可以这么配置:

    <error-page>
        <exception-type>java.lang.ArithmeticException</exception-type>
        <location>/WEB-INF/errors/divisorError.jsp</location>
    </error-page>

对错误码进行处理,例如,在web.xml中配置404错误码,如果页面找不到,跳转到指定页面:

    <error-page>
        <error-code>404</error-code>
        <location>/WEB-INF/errors/notFound.jsp</location>
    </error-page>

添加一个404对应的提示页面:

<!-- notFound.jsp -->
<%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" pageEncoding="utf-8" %>
<html>
<head>
    <title>404</title>
</head>
<body>
您访问的页面不存在!
</body>
</html>

 

 如果某个JSP设置了errorPage属性,那么在web.xml中设置的将对该页面不起作用。可以通过此种方式对整个项目的JSP进行统一规划,对应特定的JSP页面进行微调。

7.2.3 isErrorPage属性

isErrorPage如果设置为true,则会在翻译后的Servlet中创建exception对象,可以在JSP页面中使用,用于输出异常信息等。

 

 7.3 include指令

语法:

<%@ include file="/xxx" %>

include是静态包含(编译时包含),它包含的所有JSP会统一翻译成一个Servlet。被包含的页面不要写html body页签,否则新的jsp页面格式会很混乱。

request.getRequestDispatcher("/xxx").include(request, response)是动态包含,会把包含的每一个JSP分别翻译成与之对应的Servlet。

开发中常用静态包含,所以尽量使用静态包含。

 举例:

<%-- body1.jsp --%>
<%@ include file="/WEB-INF/public/header1.jsp" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>include指令,静态页面包含</title>
</head>
<body>
    页面内容
</body>
</html>
<%@ include file="/WEB-INF/public/foot1.jsp" %>
<%-- body2.jsp --%>
<%
    request.getRequestDispatcher("/WEB-INF/public/header2.jsp").include(request, response);
%>
<%@ page contentType="text/html;charset=UTF-8" language="java" buffer="none" %>
<html>
<head>
    <title>动态包含</title>
</head>
<body>
    页面内容
</body>
<%
    request.getRequestDispatcher("/WEB-INF/public/foot2.jsp").include(request, response);
%>
</html>
<%-- foot1.jsp --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<br><h2 style="color: blue;" >这是页尾</h2>
<%-- header1.jsp --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<h2 style="color: blue;">这是页头</h2><br>

分别访问body1.jsp、body2.jsp,在翻译后的Servlet目录可以看到,body1翻译后的_jspService函数直接将其他两个jsp页面也写入了。而body2翻译后的则没有,但是把header2.jsp foot2.jsp也翻译成了Servlet

body1.jsp使用静态包含,所有JSP翻译成一个Servlet:

 

body2.jsp使用动态包含,多个JSP翻译成多个Servlet:

 

8. JSP标签

8.1 JSP标签

JSP标签也称之为JSP Action(JSP动作)元素,它用于在JSP页面提供业务逻辑功能,避免在JSP页面直接编写Java代码。

8.2 JSP常用标签

  • <jsp:include>

  • <jsp:forward>

  • <jsp:param>

 

<jsp:include>标签用于把另外的一个资源的输出内容插入进当前的JSP页面的输出内容中。此种方式是动态包含

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

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

语法:

<jsp:include page="url | <%=expression %>" flush="true|false"/>   <!--page属性用于指定引入资源的相对路径,也可以通过执行一个表达式获得。 flush属性指定在插入其他资源的输出内容时,是否先将当前JSP页面已输出的内容刷新到客户端  -->
<jsp:forward page="url | <%=expression %>" >
<jsp:forward page="url" >
    <jsp:param name="username" value="aaa" />
    <jsp:param name="password" value="123" />
</jsp:forward>

举例:

<%-- label.jsp --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>JSP标签</title>
</head>
<body>
<jsp:forward page="${pageContext.request.contextPath}/LoginServlet" >
    <jsp:param name="username" value="aaa" />
    <jsp:param name="password" value="123" />
</jsp:forward>
</body>
</html>
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet(name = "LoginServlet")
public class LoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("post method");

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("get method");
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.println("username = " + request.getParameter("username"));
        out.println("<br>");
        out.println("password = " + request.getParameter("password"));
    }
}

运行结果:

9. JSP九大隐式对象

9.1 JSP运行原理

每个JSP页面在第一次被访问时,Web容器斗湖吧请求交给JSP引擎(一个Java程序)去处理,JSP引擎先将JSP翻译成一个Servlet,然后按照Servlet的方式调用。

由于JSP第一次访问时会翻译成Servlet,所以第一次访问时通常会比较慢,但是第二次访问,JSP引擎发现JSP没有变化,就不在翻译,而是直接调用,程序的执行效率不会受到影响。

JSP引擎在调用JSP对应的Servlet时,会创建9个与Web开发相关的对象,供翻译后的Servlet使用,在JSP页面中可以直接使用这些对象的引用。

9.2 九大隐式对象

javax.servlet.http.HttpServletRequest request 
javax.servlet.http.HttpServletResponse response
javax.servlet.jsp.PageContext pageContext
javax.servlet.http.HttpSession session
java.lang.Throwable exception
javax.servlet.ServletContext application
javax.servlet.ServletConfig config
javax.servlet.jsp.JspWriter out
java.lang.Object page

其中request、response、session、exception、config这几个前面已经介绍过,不在赘述。page代表当前页面exception代表异常。下面主要介绍out和pageContext。

9.3 out隐式对象

out隐式对象用于向客户端发送文本数据。out对象是通过调用pageContext对象的getOut方法返回的,其作用和语法与ServletResponse.getWriter方法返回的PrintWriter对象非常相似。

JSP页面中的out隐式对象的类型为JspWriter,JspWriter相当于一种带缓存功能的PrintWriter,设置JSP页面的page指令的buffer属性可以调整它的缓存大小,甚至关闭它的缓存。

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

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

9.4 pageContext对象

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

9.4.1 通过pageContext获得其他对象

  • getException方法返回exception隐式对象
  • getPage方法返回page隐式对象
  • getRequest方法返回request隐式对象
  • getResponse方法返回response隐式对象
  • getServletConfig方法返回config隐式对象
  • getServletContext方法返回application隐式对象
  • getSession方法返回session隐式对象
  • getOut方法返回out隐式对象

pageContext封装其他8个内置对象的意义:

JSP应该只用来做数据输出,不应该出现Java代码,如果不可避免的需要写Java代码,可以使用自定义标签技术。实现自定义标签,需要针对自定义标签写一个Java类,如果要把JSP中的隐式对象都传给自定义标签的Java类,则需要传递8个对象。而有了pageContext则可以只传递一个对象,再通过它去获取其他8大隐式对象。

9.4.2 pageContext作为域对象

pageContext作为域对象,即page域,生命周期为当前的JSP页面。

pageContext对象方法:

public void setAttribute(String name, Object value)
public Object getAttribute(String name)
public void removeAttribute(String name)
public Object findAttribute(String name) // 重点,从各个域中查找属性,查找顺序为page,request,session,application,这个也是EL表达式的实现原理

 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

举例:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>pageContext举例</title>
</head>
<body>
    <%
        pageContext.setAttribute("aaa", "111", pageContext.PAGE_SCOPE);
        pageContext.setAttribute("bbb", "222", pageContext.REQUEST_SCOPE);
        pageContext.setAttribute("ccc", "333", pageContext.SESSION_SCOPE);
        pageContext.setAttribute("ddd", "444", pageContext.APPLICATION_SCOPE);
        out.println("aaa=" + pageContext.findAttribute("aaa") + "<br>");
        out.println("bbb=" + pageContext.findAttribute("bbb") + "<br>");
        out.println("ccc=" + pageContext.findAttribute("ccc") + "<br>");
        out.println("ddd=" + pageContext.findAttribute("ddd") + "<br>");
        out.println("eee=" + pageContext.findAttribute("eee") + "<br>");
    %>
    使用EL表达式:<br>
    aaa=${aaa}<br>
    eee=${eee}
</body>
</html>

运行结果:

findAttribute和EL表达式的效果差不多,唯一的区别是当查找的属性不存在时,findAttribute返回null,EL表达式返回空。我们用来展示数据一般都使用EL表达式。

9.4.3 引入和跳转到其他资源

pageContext类中定义了一个forword方法和两个include方法,分别用来简化和替代RequestDispatcher的forword方法和include方法。方法接受资源如果以“/”开头,“/”代表当前web应用。

pageContext.forword("/1.jsp");
pageContext.include("/header.jsp");

10. JSP映射

和Servlet一样JSP也可以和URL进行映射:

<servlet>
  <servlet-name>xxx</servlet-name>
  <jsp-file>/index.jsp</jsp-file>
</servlet>
<servlet-mapping>
  <servlet-name>xxx</servlet-name>
  <url-pattern>/sss</url-pattern>
</servlet-mapping>

 

posted @ 2019-05-20 21:15  暴躁的毛毛熊  阅读(261)  评论(0编辑  收藏  举报