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>