一、JSP 概述
JSP:全称 Java Server Pages,是由 Sun 公司专门为了解决动态生成 HTML 文档的技术。
JSP 其实就是 Java 服务器页面。页面中既可以指定定义 html标签,也可以定义 Java 代码,但是只能运行在服务器(Web容器中)
作用:替代 Servlet 程序回传 HTML 页面的数据。
原因:因为 Servlet 程序回传 HTML 页面数据是一件非常繁琐的事情,开发成本和维护成本都极高,相比于Servlet,JSP更加善于处理显示页面,而Servlet跟擅长处理业务逻辑,两种技术各有专长,所以一般我们会将Servlet和JSP结合使用,Servlet负责业务,JSP负责显示。
二、JSP的本质
JSP 页面本质上就是一个 Servlet。
当第一次访问 JSP 页面的时候,Tomcat 服务器会帮我们把 jsp 页面翻译成一个 Java 源文件(Servlet),并且对它进行编译生成 .class 字节码程序。
其中 index_jsp.class 文件是 index_jsp 源文件编译后的字节码文件。
打开 index_jsp.java 文件查看里面的内容。
可以发现,生成的类继承与 HttpJspBase 类。这个是一个 jsp 文件生成 Servlet 程序要继承的基类!
关联源码,查看 HttpJspBase 类的内容,从源码的类注释说明中发现:
HttpJspBase 这个类就是所有 jsp 文件生成 Servlet程序需要去继承的基类,并且这个 HttpJspBase 类 继承了 HttpServlet 类。所以 JSP 也是一个 Servlet 小程序。
再去观察翻译后的 Servlet 程序的源代码,其底层实现,也是通过输入流,把 HTML 页面数据回传给客户端。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public void _jspService(final javax.servlet.http.HttpServletRequest request, final 2 javax.servlet.http.HttpServletResponse response) 3 throws java.io.IOException, javax.servlet.ServletException { 4 final java.lang.String _jspx_method = request.getMethod(); 5 if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) 6 && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET POST or 7 HEAD"); 8 return; 9 } 10 final javax.servlet.jsp.PageContext pageContext; 11 javax.servlet.http.HttpSession session = null; 12 final javax.servlet.ServletContext application; 13 final javax.servlet.ServletConfig config; 14 javax.servlet.jsp.JspWriter out = null; 15 final java.lang.Object page = this; 16 javax.servlet.jsp.JspWriter _jspx_out = null; 17 javax.servlet.jsp.PageContext _jspx_page_context = null; 18 try { 19 response.setContentType("text/html;charset=UTF-8"); 20 pageContext = _jspxFactory.getPageContext(this, request, response, 21 null, true, 8192, true); 22 _jspx_page_context = pageContext; 23 application = pageContext.getServletContext(); 24 config = pageContext.getServletConfig(); 25 session = pageContext.getSession(); 26 out = pageContext.getOut(); 27 _jspx_out = out; 28 out.write(" "); 29 out.write(" "); 30 out.write("<html> "); 31 out.write("<head> "); 32 out.write(" <title>Title</title> "); 33 out.write("</head> "); 34 out.write("<body> "); 35 out.write(" a.jsp 页面 "); 36 out.write("</body> "); 37 out.write("</html> "); 38 } catch (java.lang.Throwable t) { 39 if (!(t instanceof javax.servlet.jsp.SkipPageException)){ 40 out = _jspx_out; 41 if (out != null && out.getBufferSize() != 0) 42 try { 43 if (response.isCommitted()) { 44 out.flush(); 45 } else { 46 out.clearBuffer(); 47 } 48 } catch (java.io.IOException e) {} 49 if (_jspx_page_context != null) _jspx_page_context.handlePageException(t); 50 else throw new ServletException(t);} 51 } finally { 52 _jspxFactory.releasePageContext(_jspx_page_context); 53 } 54 }
原理示意图:
小结:
xxx.jsp 翻译成 Java 的全面是 xxx_jsp.java 文件;
xxx_jsp.java 文件就是一个 Servlet 程序,原来 jsp 中的 HTML 内容都被翻译到 Servlet 类的 service 方法中原样输出。
三、JSP 指令
1、jsp 头部的 page 指令
jsp 的 page 指令可以修改 jsp 页面的一些重要的属性或行为。
语法格式:
<%@ page 属性名1=属性值1 属性名2=属性值2 ... %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
常用属性:
① language 属性
表示 jsp 翻译后是什么语言文件,暂时支持 Java。
② contentType 属性
表示 jsp 返回的数据类型是什么,也是源码中 response.setContentType() 参数值
作用:设置响应体的 MIME类型以及字符集;
③ pageEncoding 属性
表示当前 jsp 页面文件本身的字符集
④ import 属性
和 Java 源代码中,用于导包、导类。
⑤ autoFlush 属性
设置当 out 输出流缓冲区满了之后,是否自动刷新缓冲区,默认是 true。
⑥ buffer 属性
设置 out 缓冲区的大小,默认是 8KB。
属性⑤和属性⑥ 都是给 out 输出流使用的。
缓冲区溢出错误:(如果设置autoFlush=false或buffer过小会报错)
⑦ errorPage 属性
设置当前 jsp 页面运行时出错,自动跳转去的错误页面路径。
注意:errorPage 表示错误后自动跳转去的路径,这个路径一般都是以斜杠打头, 它表示请求地址为 http://ip:port/工程路径/ ,映射到代码的 Web 目录
⑧ isErrorPage 属性
设置当前 jsp 页面是否是错误信息页面。默认是 false,如果是 true 可以获取异常信息
取值 true:是,可以使用内置对象 Exception
取值 false:否,默认值,不可以只使用 内置对象 Exception
⑨ session 属性
设置访问当前 jsp 页面,是否会创建 HttpSession对象。默认是 true
⑩ extends
设置 jsp 翻译出来的 java 类默认继承谁
2、include 指令
作用:该指令用于将目标页面包含到当前页面中,用于导入页面的资源文件。
特点:静态包含,被包含的文件不会被翻译和编译
语法格式:
<%@include file="top.jsp"%>
3、tablib 指令
作用:该指令用于导入标签库。
语法格式:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
prefiex 表示自定义的前缀
三、JSP 脚本
1、声明脚本(极少用)
作用:可以给 jsp 翻译出来的 java 类定义属性,全局变量,方法甚至是静态代码块、内部类等。
语法格式:
<%! 声明 java 代码 %>
Demo:
1 <%--1、 声明类属性--%>
2 <%!
3 private Integer id;
4 private String name;
5 private static Map<String,Object> map;
6 %>
7 <%--2、 声明 static 静态代码块--%>
8 <%!
9 static {
10 map = new HashMap<String,Object>();
11 map.put("key1", "value1");
12 map.put("key2", "value2");
13 map.put("key3", "value3");
14 }
15 %>
16 <%--3、 声明类方法--%>
17 <%!
18 public int abc(){
19 return 12;
20 }
21 %><%--4、 声明内部类--%>
22 <%!
23 public static class A {
24 private Integer id = 12;
25 private String abc = "abc";
26 }
27 %>
声明脚本代码翻译对照:
2、表达式脚本(常用)
作用:向 jsp页面上输出数据。(输出语句中可以定义什么,该脚本中就可以定义什么)
语法格式:
<%=表达式 %>
表达式脚本的特点:
① 所有的表达式脚本都会被翻译到 _jspService() 方法中;
② 表达式脚本都会被翻译成 out.print() 输出到页面上;
③ 由于表达式脚本翻译的内容都在_jspService() 方法中,所以_jspService()方法中的对象都可以直接使用;
④ 表达式脚本中的表达式不能以分号结束;
⑤ 可以输出任意类型
Demo:
1 <%=12 %> <br>
2 <%=12.12 %> <br>
3 <%="我是字符串" %> <br>
4 <%=map%> <br>
5 <%=request.getParameter("username")%
翻译对照:
3、代码脚本
作用:可以在 jsp 页面中,编写需要的功能(写的是Java代码,service方法中可以定义什么,该脚本中就可以定义什么,翻译到 _jspService() 中)
语法格式:
<%
java 语句
%>
代码脚本的特点是:
① 代码脚本翻译之后都在 _jspService() 方法中;
② 代码脚本由于翻译到_jspService()方法中, 所以在_jspService()方法中的现有对象都可以直接使用
③ 还可以由多个代码脚本块组合完成一个完整的 java 语句。
④ 代码脚本还可以和表达式脚本一起组合使用, 在 jsp 页面上输出数据
Demo:
1 <%--1.代码脚本----if 语句--%>
2 <%int i = 13 ;
3 if (i == 12) {
4 %>
5 <h1>国哥好帅</h1>
6 <%
7 } else {
8 %>
9 <h1>国哥又骗人了! </h1>
10 <%
11 }
12 %>
13 <br>
14 <%--2.代码脚本----for 循环语句--%>
15 <table border="1" cellspacing="0">
16 <%
17 for (int j = 0; j < 10; j++) {
18 %>
19 <tr>
20 <td>第 <%=j + 1%>行</td>
21 </tr>
22 <%
23 }
24 %>
25 </table>
26 <%--3.翻译后 java 文件中_jspService 方法内的代码都可以写--%>
27 <%
28 String username = request.getParameter("username");
29 System.out.println("用户名的请求参数值是: " + username);
30 %>
翻译对照:
四、JSP 中的三种注释
1、HTML 注释
格式:
<!-- 这是 html 注释 --> 只能注释 HTML代码片段
HTML 注释会被翻译到 Java 源代码中,在 _jspService() 方法里,以 out.writer 输出到客户端,但是不会在页面上显示。
2、Java 注释
格式:
<%
// 单行 java 注释
/* 多行 java 注释 */
%>
Java 注释会被翻译到 Java 源代码中,不会输出到客户端
3、jsp 注释
格式:
<%-- 这是 jsp 注释 --%>
jsp 注释可以注释掉 jsp 页面中所有的代码。但是这种注释是在服务器端的注释,不会把数据发送给浏览器的,通过源代码不能查看到。
JSP 中三种注释的比较:
|
JSP注释 |
Java注释 |
HTML注释 |
JSP页面 |
可见 |
可见 |
可见 |
Java代码 |
不可见 |
可见 |
可见 |
浏览器 |
不可见 |
不可见 |
可见 |
五、JSP 的内置对象
jsp 中的内置对象,是指 Tomcat 在翻译 jsp 页面称为 Servlet 源代码后,内部提供的 九大对象,称为 内置对象。
在 jsp 页面中不需要获取和创建,可以直接使用的对象。
jsp 一共有9个内置对象。
变量名 | 真实类型 | 作用 |
pageContext | PageContext | 当前页面共享数据,还可以获取其他八个内置对象(Servlet中没有此对象) |
request | HttpServletRequest | 一次请求访问的多个资源(转发) |
session | HttpSession | 一次会话的多个请求间 |
application | ServletContext(唯一) | 所有用户间共享数据 |
response | HttpServletResponse | 响应对象 |
page | Object | 当前页面(Servlet)的对象 this |
out | JspWriter | 输出对象,数据输出到页面上 |
config | ServletConfig | Servlet的配置对象 |
exception | Throwable | 异常对象 |
九大内置对象, 都是我们可以在【代码脚本】 中或【表达式脚本】 中直接使用的对象。
六、JSP 四大域对象
域对象是可以向 Map 一样存取数据的对象,四个域对象功能一样,不同的是它们对数据的存取范围。
四个域对象分别是:
域对象 | 真实类型 | 存取范围 |
pageContext | PageContextImpl类 | 当前 jsp 页面范围内有效(Servlet中没有) |
request | HttpServletRequest类 | 一次请求内有效 |
session | HttpSession类 |
一个会话范围内有效 (打开浏览器访问服务器,知道关闭浏览器) |
application | ServletContext类 |
整个Web 工程范围呢都有效 (只要Web工程不停止,数据就在) |
虽然四个域对象都可以存取数据,但是在使用上是有优先顺序的。
四个域在使用的时候,优先顺序分别是:它们从小到大的方位的顺序:
pageContext ====>>> request ====>>> session ====>>> application
七、JSP 中的 out 输出和 response.getWriter 输出的区别
response 表示响应,经常用于设置返回给客户端的内容(输出)
out 也是给用户做输出使用的。
两个缓冲流工作原理:
out 的 writer() 方法 和 print() 方法
由于 jsp 翻译之后, 底层源代码都是使用 out 来进行输出, 所以一般情况下,我们在 jsp 页面中统一使用 out 来进行输出,避免打乱页面输出内容的顺序。
response.getWriter()和out.write()的区别:
① 在 Tomcat 服务器真正给客户端做出响应之前,会先找 response 缓冲区数据,再找out缓冲区数据。
② response.getWriter()数据输出永远在out.write()之前
out.write() 输出字符串没有问题(出去其他如int,会先转化为char类型,可能乱码)
out.print() 输出任意数据都没有问题(都转换成为字符串后调用的 write 输出)
小结:在jsp 页面中,可以统一使用 out.print() 来进行输出。
八、jsp的常用标签
1、jsp 静态包含
作用:把其他的页面包含到当前页面中
格式:
<%@ include file=""%>
<%@ include file="/include/footer.jsp"%>
file 属性指定要包含的 jsp 页面的路径;
地址中第一个斜杠 / 表示为 http://ip:port/工程路径/ 映射到代码的 web 目录
静态包含的特点:
(1)静态包含不会翻译被包含的 jsp 页面。
(2)静态包含其实是把被包含的 jsp 页面的代码拷贝到包含的位置执行输出。
2、动态包含
作用:动态包含会把包含的 jsp 页面单独翻译成 servlet 文件, 然后在执行到时候再调用翻译的 servlet 程序。 并把计算的结果返回。
动态包含是在执行的时候,才会加载,所以叫动态包含。
格式:
<jsp:include page=""></jsp:include> 动态包含
page 属性是指定要包含的 jsp 页面的路径
动态包含也可以向静态包含一样,把被包含的内容执行输出到包含位置
动态包含的特点:
(1)动态包含会把包含的 jsp 页面也翻译成为 java 代码
(2)动态包含底层代码使用如下代码去调用被包含的 jsp 页面执行输出
JspRuntimeLibrary.include(request, response, "/include/footer.jsp", out, false);
(3)动态包含, 还可以传递参数
Demo:
1 <jsp:include page="/include/footer.jsp">
2 <jsp:param name="username" value="bbj"/>
3 <jsp:param name="password" value="root"/>
4 </jsp:include>
动态包含的底层原理:
两种包含的区别:
静态包含 | 动态包含 | |
是否生成 java 文件 | 不生成 | 生成 |
service 方法中的区别 | 把包含的内容原封拷贝到 service 中 | JspRuntimeLibrary.include 方法 |
是否可以传递参数 | 不能 | 可以 |
编译次数 | 1 | 包含的文件 + 1 |
适用范围 | 适用包含纯静态内容(CSS,HTML,JS), 或没有 非常耗时操作。 或大量 java 代码的 jsp |
包含需要传递参数。 含有大量 java代码 |
静态包含应用较多。
3、创建对象及赋值
<jsp:useBean id='people' class="com.njf.pojo.Person" scope="page"> #创建对象 <jsp:setProperty name='people' property='id' value='1'> # 给属性赋值
九、JSP 动作标签
JSP 动作标签是由 服务器(Tomcat)来运行的。
动作标签语法:
<jsp: 动作名称 属性=属性值></jsp:动作名称>
1、jsp 标签— 转发
作用:处理请求转发操作
不带参数格式:
<jsp:forward page="/scope2.jsp"></jsp:forward>
page 属性设置请求转发的路径。注意:开始标签与结束标签之间不能有任何内容。
带参数格式:
<jsp:forward page="NewFile.jsp">
<jsp:param value="18" name="age"/>
</jsp:forward>
上面的 <jsp:include> 也是一个动作标签。