JSP
JSP 的全换是 Java Server Pages ,Java 的服务器页面。
是由 Sun 公司专门为了解决动态生成 HTML 文档的技术。
JSP 的主要作用是代替 Servlet 程序回传 HTML 页面的数据。
因为 Servlet 程序回传 HTML 页面数据是一件非常繁锁的事情。开发成本和维护成本都极高。
JSP 的本质
JSP 页面本质上是一个 Servlet 程序。
当我们第一次访问 jsp 页面的时候。Tomcat 服务器会帮我们把 jsp 页面翻译成为一个 java 源文件。并且对它进行编译成为 .class 字节码程序。我们打开 java 源文件不难发现其里面的内容是:
我们跟踪原代码发现,HttpJspBase 类。它直接地继承了 HttpServlet 类。也就是说。jsp 翻译出来的 java 类,它间接了继承了 HttpServlet 类。也就是说,翻译出来的是一个 Servlet 程序
总结:通过翻译的 java 源代码我们就可以得到结果:jsp 就是 Servlet 程序。
可以去观察翻译出来的 Servlet 程序的源代码,不难发现。其底层实现,也是通过输出流。把 html 页面数据回传给客户端。
JSP 的三种语法
JSP 头部的 page 指令
jsp 的 page 指令可以修改 jsp 页面中一些重要的属性,或者行为。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
- language 属性
表示 jsp 翻译后是什么语言文件。暂时只支持 java。 - contentType 属性
表示 jsp 返回的数据类型是什么;也是源码中 response.setContentType() 参数值 - import 属性
跟java源代码中一样。用于导包,导类。 - autoFlush 属性
设置当 out 输出流缓冲区满了之后,是否自动刷新冲级区。默认值是 true。 - buffer 属性
设置 out 缓冲区的大小。默认是 8kb - errorPage 属性
设置当 jsp 页面运行时出错,自动跳转去的错误页面路径
这个路径一般都是以斜杠打头,它表示请求地址为 http://ip:port/工程路径/ - isErrorPage 属性
设置当前 jsp 页面是否是错误信息页面。默认是 false 如果是 true 可以获取异常信息 - session 属性
置访问当前jsp页面,是否会创建 HttpSession 对象。默认是 true - extends 属性
设置jsp翻译出来的java类默认继承谁
JSP 脚本
声明脚本
格式:<%! Java 声明代码 %>
可以给 jsp 翻译出来的 Java 类增加属性、方法、静态代码块、内部类等。
当第一次访问此 JSP 页面时,生成的 Java 类程序中:
表达式脚本
格式:<%= 表达式 %>
在 jsp 页面上输出数据
- 所有的表达式脚本都会被翻译到 _jspService() 方法中
- 表达式脚本都会被翻译成为 out.print() 输出到页面上
- 由于表达式脚本翻译的内容都在 _jspService() 方法中,所以 _jspService() 方法中的对象都可以直接使用
- 表达式脚本中的表达式不能以分号结束
表达式脚本的内容翻译到 Java 类中的 _jspService() 方法中:
代码脚本
格式:<% Java 语句 %>
可以在 jsp 页面中,编写我们自己需要的功能(写的是 java 语句)
- 代码脚本翻译之后都在 _jspService() 方法中
- 代码脚本由于翻译到 _jspService() 方法中,所以在 _jspService() 方法中的现有对象都可以直接使用
- 可以由多个代码脚本块组合完成一个完整的 java 语句
- 代码脚本还可以和表达式脚本一起组合使用,在 jsp 页面上输出数据
页面生成效果:
翻译出的 Java 类中的代码(实际上是原封不动的放到 _jspService() 方法中):
JSP 注释
HTM 注释
格式:<!-- html 注释 -->
html 注释会被翻译到 java 源代码中;在 _jspService() 方法里,以 out.writer 输出到客户端
Java 注释
格式:// 单行注释``/* 多行注释 */
java 注释会被翻译到 java 源代码中
JSP 注释
格式:<%-- jsp 注释 --%>
jsp 注释可以注释掉一切,包括 html 注释、Java 注释、jsp 脚本等;不会翻译到 Java 源代码中
翻译到 Java 代码中(除 jsp 注释外都会在源代码中看到):
JSP 九大内置对象
JSP 四大域对象
- PageContextImpl pageContext:当前 jsp 页面范围内有效
- HttpServletRequest request:一次请求内有效
- HttpSession session:一个会话范围内有效
- ServletContext application:整个 web 工程范围内都有效
如下两个 jsp 文件:
<h1>JSP域对象1.jsp</h1>
<%
pageContext.setAttribute("key", "pageContext");
request.setAttribute("key", "request");
session.setAttribute("key", "session");
application.setAttribute("key", "application");
%>
<%="pageContext 域:" + pageContext.getAttribute("key")%> <br>
<%="request 域:" + request.getAttribute("key")%> <br>
<%="session 域:" + session.getAttribute("key")%> <br>
<%="application 域:" + application.getAttribute("key")%> <br>
<%request.getRequestDispatcher("/JSP域对象2.jsp").forward(request, response);%>
<h1>JSP域对象2.jsp</h1>
<%="pageContext 域:" + pageContext.getAttribute("key")%> <br>
<%="request 域:" + request.getAttribute("key")%> <br>
<%="session 域:" + session.getAttribute("key")%> <br>
<%="application 域:" + application.getAttribute("key")%> <br>
第一次访问第一个 jsp 页面,4 个域对象都能得到数据:
打开第一个 jsp 页面的请求转发的注释,跳转到第二个 jsp 页面后,仅在 jsp 当前页面范围内有效的 pageContext 对象获取不到数据:
修改浏览器地址栏中的地址,直接访问第二个 jsp 页面(不关闭浏览器,此时还是一次会话),request 域就无法读取到数据:
关闭浏览器,再次访问第二个 jsp 页面,新的会话,所以 session 也无法访问到数据:
重启下 web 工程,再次访问第二个 jsp 对象,此时发现最后一个域对象也无法读取到数据:
jsp 中的 out 输出和 response.getWriter() 输出的区别
由于 jsp 翻译之后,底层源代码都是使用 out 来进行输出,所以一般情况下。我们在 jsp 页面中统一使用 out 来进行输出。避免打乱页面输出内容的顺序。
out.write() 输出字符串没有问题
out.print() 输出任意数据都没有问题(都转换成为字符串后调用的 write 输出)
常用标签
静态包含
格式:<%@ include file="/xxx"%>
file 属性指定要包含的 jsp 页面
- 静态包含不会翻译被包含的 jsp 页面
- 静态包含其实是把被包含的 jsp 页面的代码拷贝到包含的位置输出
动态包含
格式:<jsp:include page="/xxx">
page 属性指定要包含的 jsp 页面的路径
同静态包含,讲被包含的内容执行输出到包含位置
- 动态包含会把包含的 jsp 页面也翻译成 Java 代码
- 动态包含底层代码:
org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "/include/footer.jsp", out, false);
- 动态包含还可以传递参数
现在有两个 jsp 页面,一个首页,一个页脚:
在首页页面动态包含 jsp 页面时,可以设置请求参数,在页脚页面的 jsp 页面中可以使用 request 对象获取请求参数,在浏览器显示效果:
请求转发标签
格式:<jsp:forward page="/xxx"></jsp:forward>
效果等同于<% request.getDispatcher("/xxx").forward(request, response); %>
请求转发的使用
Listener 监听器
Listener 监听器它是 JavaWeb 的三大组件之一
JavaWeb 的三大组件分别是:Servlet 程序、Filter 过滤器、Listener 监听器
Listener 它是 JavaEE 的规范,就是接口
监听器的作用是,监听某种事物的变化。然后通过回调函数,反馈给客户(程序)去做一些相应的处理
ServletContextListener 接口
ServletContextListener 它可以监听 ServletContext 对象的创建和销毁
ServletContext 对象在 web 工程启动的时候创建,在 web 工程停止的时候销毁
监听到创建和销毁之后都会分别调用 ServletContextListener 监听器的方法反馈
public interface ServletContextListener extends EventListener {
// 在 ServletContext 对象创建之后马上调用,做初始化
public void contextInitialized(ServletContextEvent sce);
// 在 ServletContext 对象销毁之后调用
public void contextDestroyed(ServletContextEvent sce);
}
使用步骤:
- 创建一个类实现 ServletContextListener 接口
- 实现回调方法
- 在 web.xml 配置
public class MyFirstListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("ServletContext 对象被创建了,执行初始化...(此处省略一万行代码)");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("ServletContext 对象被销毁了,正在善后...(此处省略一万行代码)");
}
}
<listener>
<listener-class>work.jkfx.listener.MyFirstListener</listener-class>
</listener>