Java 之 JSP
一、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 页面数据回传给客户端。
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("\r\n");
out.write("\r\n");
out.write("<html>\r\n");
out.write("<head>\r\n");
out.write(" <title>Title</title>\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n");
out.write(" a.jsp 页面\r\n");
out.write("</body>\r\n");
out.write("</html>\r\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);
}
}
原理示意图:
小结:
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、 声明类属性--%>
<%!
private Integer id;
private String name;
private static Map<String,Object> map;
%>
<%--2、 声明 static 静态代码块--%>
<%!
static {
map = new HashMap<String,Object>();
map.put("key1", "value1");
map.put("key2", "value2");
map.put("key3", "value3");
}
%>
<%--3、 声明类方法--%>
<%!
public int abc(){
return 12;
}
%><%--4、 声明内部类--%>
<%!
public static class A {
private Integer id = 12;
private String abc = "abc";
}
%>
声明脚本代码翻译对照:
2、表达式脚本(常用)
作用:向 jsp页面上输出数据。(输出语句中可以定义什么,该脚本中就可以定义什么)
语法格式:
<%=表达式 %>
表达式脚本的特点:
① 所有的表达式脚本都会被翻译到 _jspService() 方法中;
② 表达式脚本都会被翻译成 out.print() 输出到页面上;
③ 由于表达式脚本翻译的内容都在_jspService() 方法中,所以_jspService()方法中的对象都可以直接使用;
④ 表达式脚本中的表达式不能以分号结束;
⑤ 可以输出任意类型
Demo:
<%=12 %> <br>
<%=12.12 %> <br>
<%="我是字符串" %> <br>
<%=map%> <br>
<%=request.getParameter("username")%
翻译对照:
3、代码脚本
作用:可以在 jsp 页面中,编写需要的功能(写的是Java代码,service方法中可以定义什么,该脚本中就可以定义什么,翻译到 _jspService() 中)
语法格式:
<%
java 语句
%>
代码脚本的特点是:
① 代码脚本翻译之后都在 _jspService() 方法中;
② 代码脚本由于翻译到_jspService()方法中, 所以在_jspService()方法中的现有对象都可以直接使用
③ 还可以由多个代码脚本块组合完成一个完整的 java 语句。
④ 代码脚本还可以和表达式脚本一起组合使用, 在 jsp 页面上输出数据
Demo:
<%--1.代码脚本----if 语句--%>
<%int i = 13 ;
if (i == 12) {
%>
<h1>国哥好帅</h1>
<%
} else {
%>
<h1>国哥又骗人了! </h1>
<%
}
%>
<br>
<%--2.代码脚本----for 循环语句--%>
<table border="1" cellspacing="0">
<%
for (int j = 0; j < 10; j++) {
%>
<tr>
<td>第 <%=j + 1%>行</td>
</tr>
<%
}
%>
</table>
<%--3.翻译后 java 文件中_jspService 方法内的代码都可以写--%>
<%
String username = request.getParameter("username");
System.out.println("用户名的请求参数值是: " + username);
%>
翻译对照:
四、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:
<jsp:include page="/include/footer.jsp">
<jsp:param name="username" value="bbj"/>
<jsp:param name="password" value="root"/>
</jsp:include>
动态包含的底层原理:
两种包含的区别:
静态包含 | 动态包含 | |
是否生成 java 文件 | 不生成 | 生成 |
service 方法中的区别 | 把包含的内容原封拷贝到 service 中 | JspRuntimeLibrary.include 方法 |
是否可以传递参数 | 不能 | 可以 |
编译次数 | 1 | 包含的文件 + 1 |
适用范围 | 适用包含纯静态内容(CSS,HTML,JS), 或没有 非常耗时操作。 或大量 java 代码的 jsp |
包含需要传递参数。 含有大量 java代码 |
静态包含应用较多。
九、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> 也是一个动作标签。
最新文章
- Rxjava Subjects
- java线程与缓存
- log4php的配置
- 使用css实现全兼容tooltip提示框
- 【转】为什么C++编译器不能支持对模板的分离式编译
- EditPlus 配置 Java &; C/CPP 开发环境
- U盘量产的作用
- 第八十三节,CSS3动画效果
- SQL一次查出相关类容避免长时间占用表(下)
- 【锋利的jQuery】中全局事件ajaxStart、ajaxStop不执行
- Hibernate (二)
- https原理及实践
- 论文笔记:Progressive Neural Architecture Search
- odoo开发笔记--取消正在升级中模块
- [Android四大组件之二]——Service
- 【Tomcat】Tomcat配置与优化(内存、并发、管理)【自己配置】
- Python学习笔记(Django篇)——3、创建第一个数据库模型
- [Python]计算闰年时候出现的and和or优先级的问题以及短路逻辑
- xpath技术解析xm文件(php)
- github 初始化操作小记
热门文章
- Spring Web Flux 相关概念
- 使用CompletableFuture实现业务服务的异步调用实战代码
- Django入门2开发工具pycharm的配置
- Java13新特性 -- switch表达式动态CDS档案(动态类数据共享归档)
- 关于在windows平台下将应用制作成windows服务及服务依赖的感想
- Classic BAdi and New BAdi
- TransactionScope处理分布式事物时提示";事务已被隐式或显式提交,或已终止";
- HBase 详解
- git删除本地分支,远端分支
- [转载]ROS开发环境之Qt Creator