JSP的工作模式是请求/响应模式,具体运行过程如下:
接下来可以看看JSP的转化成果,我先写一个jsp文件,如下:
当客户端访问该jsp文件时,容器会把该文件转换成java文件,然后被编译成class文件。
打开index_jsp.java文件:
/*
* Generated by the Jasper component of Apache Tomcat
* Version: Apache Tomcat/8.0.53
* Generated at: 2019-10-09 13:55:40 UTC
* Note: The last modified time of this file was set to
* the last modified time of the source file after
* generation to assist with modification tracking.
*/
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {
private static final javax.servlet.jsp.JspFactory _jspxFactory =
javax.servlet.jsp.JspFactory.getDefaultFactory();
private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;
private static final java.util.Set<java.lang.String> _jspx_imports_packages;
private static final java.util.Set<java.lang.String> _jspx_imports_classes;
static {
_jspx_imports_packages = new java.util.HashSet<>();
_jspx_imports_packages.add("javax.servlet");
_jspx_imports_packages.add("javax.servlet.http");
_jspx_imports_packages.add("javax.servlet.jsp");
_jspx_imports_classes = null;
}
private volatile javax.el.ExpressionFactory _el_expressionfactory;
private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;
public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
return _jspx_dependants;
}
public java.util.Set<java.lang.String> getPackageImports() {
return _jspx_imports_packages;
}
public java.util.Set<java.lang.String> getClassImports() {
return _jspx_imports_classes;
}
public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
if (_el_expressionfactory == null) {
synchronized (this) {
if (_el_expressionfactory == null) {
_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
}
}
}
return _el_expressionfactory;
}
public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
if (_jsp_instancemanager == null) {
synchronized (this) {
if (_jsp_instancemanager == null) {
_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
}
}
}
return _jsp_instancemanager;
}
public void _jspInit() {
}
public void _jspDestroy() {
}
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("\n");
out.write("\n");
out.write("\n");
out.write(" \n");
out.write(" $Title$ \n");
out.write(" \n");
out.write(" \n");
out.write(" $END$\n");
out.write(" \n");
out.write("\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);
}
}
}
我们发现该文件的继承关系
打开HttpJspBase,发现它是继承Servlet的
这也证明这是一个Servlet,接下来再看index_jsp.java,
发现jsp文件中html的内容都是通过out.write(String str)方法输出的。
当将项目部署到tomcat下时,该jsp编译的Java源文件会存放于tomcat/work/Catalina目录下,当使用idea时,该文件在C盘-用户(user)-用户名-.IntelliJIdea下面。
我们如何在jsp文件中写Java代码的?
<% java代码 %>
在JSP Scriptlets中声明的便令时jsp页面的局部变量,调用JSP Scriptlets时会为局部变量分配内存空间,调用结束后,释放局部变量占有的内存空间。
<%! 定义的变量或方法 %>
别声明的Java代码江别编译到Servet的_jspService()方法之外,即在jsp声明语句中定义的都是成员方法、成员变量、静态变量、静态代码块等,在jsp声明语句中声明的方法在整个给jsp页面内有效。
<%= expression %>
<%-- 注释信息 --%>
Page指令为容器提供当前页面的使用说明。一个JSP页面可以包含多个page指令。
Page指令的语法格式:
<%@ page attribute="value" %>
下表列出与Page指令相关的属性:
属性 | 描述 |
---|---|
buffer | 指定out对象使用缓冲区的大小 |
autoFlush | 控制out对象的 缓存区 |
contentType | 指定当前JSP页面的MIME类型和字符编码 |
errorPage | 指定当JSP页面发生异常时需要转向的错误处理页面 |
isErrorPage | 指定当前页面是否可以作为另一个JSP页面的错误处理页面 |
extends | 指定servlet从哪一个类继承 |
import | 导入要使用的Java类 |
info | 定义JSP页面的描述信息 |
isThreadSafe | 指定对JSP页面的访问是否为线程安全 |
language | 定义JSP页面所用的脚本语言,默认是Java |
session | 指定JSP页面是否使用session |
isELIgnored | 指定是否执行EL表达式 |
isScriptingEnabled | 确定脚本元素能否被使用 |
<%@ include file="文件相对 url 地址" %>
<%@ taglib uri="uri" prefix="prefixOfTag" %>
uri属性确定标签库的位置,prefix属性指定标签库的前缀。
与JSP指令元素不同的是,JSP动作元素在请求处理阶段起作用。JSP动作元素是用XML语法写成的。
利用JSP动作可以动态地插入文件、重用JavaBean组件、把用户重定向到另外的页面、为Java插件生成HTML代码。
动作元素只有一种语法,它符合XML标准:
动作元素基本上都是预定义的函数,JSP规范定义了一系列的标准动作,它用JSP作为前缀,可用的标准动作元素如下:
语法 | 描述 |
---|---|
jsp:include | 在页面被请求的时候引入一个文件。 |
jsp:useBean | 寻找或者实例化一个JavaBean。 |
jsp:setProperty | 设置JavaBean的属性。 |
jsp:getProperty | 输出某个JavaBean的属性。 |
jsp:forward | 把请求转到一个新的页面。 |
jsp:plugin | 根据浏览器类型为Java插件生成OBJECT或EMBED标记。 |
jsp:element | 定义动态XML元素 |
jsp:attribute | 设置动态定义的XML元素属性。 |
jsp:body | 设置动态定义的XML元素内容。 |
jsp:text | 在JSP页面和文档中使用写入文本的模板 |
jsp:include动作元素用来包含静态和动态的文件。该动作把指定文件插入正在生成的页面。语法格式如下:
前面已经介绍过include指令,它是在JSP文件被转换成Servlet的时候引入文件,而这里的jsp:include动作不同,插入文件的时间是在页面被请求的时候。
以下是include动作相关的属性列表。
属性 | 描述 |
---|---|
page | 包含在页面中的相对URL地址。 |
flush | 布尔属性,定义在包含资源前是否刷新缓存区。 |
以下我们定义了两个文件 date.jsp 和 main.jsp,代码如下所示:
date.jsp文件代码:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
今天的日期是: <%= (new java.util.Date()).toLocaleString()%>
main.jsp 文件代码:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
菜鸟教程(runoob.com)
include 动作实例
现在将以上两个文件放在服务器的根目录下,访问main.jsp文件。显示结果如下:
include 动作实例
今天的日期是: 2016-6-25 14:08:17
JSP隐式对象是JSP容器为每个页面提供的Java对象,开发者可以直接使用它们而不用显式声明。JSP隐式对象也被称为预定义变量。
JSP所支持的九大隐式对象:
对象 | 描述 |
---|---|
request | HttpServletRequest 接口的实例 |
response | HttpServletResponse 接口的实例 |
out | JspWriter 类的实例,用于把结果输出至网页上 |
session | HttpSession 类的实例 |
application | ServletContext 类的实例,与应用上下文有关 |
config | ServletConfig 类的实例 |
pageContext | PageContext 类的实例,提供对JSP页面所有对象以及命名空间的访问 |
page | 类似于Java类中的this关键字 |
Exception | Exception 类的对象,代表发生错误的JSP页面中对应的异常对象 |
request对象是javax.servlet.http.HttpServletRequest 类的实例。每当客户端请求一个JSP页面时,JSP引擎就会制造一个新的request对象来代表这个请求。
request对象提供了一系列方法来获取HTTP头信息,cookies,HTTP方法等等。
response对象是javax.servlet.http.HttpServletResponse类的实例。当服务器创建request对象时会同时创建用于响应这个客户端的response对象。
response对象也定义了处理HTTP头模块的接口。通过这个对象,开发者们可以添加新的cookies,时间戳,HTTP状态码等等。
out对象是 javax.servlet.jsp.JspWriter 类的实例,用来在response对象中写入内容。
最初的JspWriter类对象根据页面是否有缓存来进行不同的实例化操作。可以在page指令中使用buffered='false’属性来轻松关闭缓存。
JspWriter类包含了大部分java.io.PrintWriter类中的方法。不过,JspWriter新增了一些专为处理缓存而设计的方法。还有就是,JspWriter类会抛出IOExceptions异常,而PrintWriter不会。
下表列出了我们将会用来输出boolean,char,int,double,String,object等类型数据的重要方法:
方法 | 描述 |
---|---|
out.print(dataType dt) | 输出Type类型的值 |
out.println(dataType dt) | 输出Type类型的值然后换行 |
out.flush() | 刷新输出流 |
session对象是 javax.servlet.http.HttpSession 类的实例。和Java Servlets中的session对象有一样的行为。
session对象用来跟踪在各个客户端请求间的会话。
application对象直接包装了servlet的ServletContext类的对象,是javax.servlet.ServletContext 类的实例。
这个对象在JSP页面的整个生命周期中都代表着这个JSP页面。这个对象在JSP页面初始化时被创建,随着jspDestroy()方法的调用而被移除。
通过向application中添加属性,则所有组成您web应用的JSP文件都能访问到这些属性。
config对象是 javax.servlet.ServletConfig 类的实例,直接包装了servlet的ServletConfig类的对象。
这个对象允许开发者访问Servlet或者JSP引擎的初始化参数,比如文件路径等。
以下是config对象的使用方法,不是很重要,所以不常用:
config.getServletName();
它返回包含在元素中的servlet名字,注意,元素在 WEB-INF\web.xml 文件中定义。
pageContext对象是javax.servlet.jsp.PageContext 类的实例,用来代表整个JSP页面。
这个对象主要用来访问页面信息,同时过滤掉大部分实现细节。
这个对象存储了request对象和response对象的引用。application对象,config对象,session对象,out对象可以通过访问这个对象的属性来导出。
pageContext对象也包含了传给JSP页面的指令信息,包括缓存信息,ErrorPage URL,页面scope等。
PageContext类定义了一些字段,包括PAGE_SCOPE,REQUEST_SCOPE,SESSION_SCOPE, APPLICATION_SCOPE。它也提供了40余种方法,有一半继承自javax.servlet.jsp.JspContext 类。
其中一个重要的方法就是removeArribute(),它可接受一个或两个参数。比如,pageContext.removeArribute(“attrName”)移除四个scope中相关属性,但是下面这种方法只移除特定scope中的相关属性:
pageContext.removeAttribute("attrName", PAGE_SCOPE);
这个对象就是页面实例的引用。它可以被看做是整个JSP页面的代表。
page 对象就是this对象的同义词。
exception 对象包装了从先前页面中抛出的异常信息。它通常被用来产生对出错条件的适当响应。
JSP四大作用域:page(作用范围最小)、request、session、application(作用范围最大)
JSP2.0规范中提供了EL表达式,它是一种简单的数据访问语言,用于简化JSP文件的书写。格式:${代码块}
。
算术运算符 | 说明 | 示例 | 结果 |
---|---|---|---|
+ | 加 | ${1 + 1} | 2 |
- | 减 | ${2 - 1} | 1 |
* | 乘 | ${2 * 3} | 6 |
/ | 除 | ${5 / 2} | 2.5 |
% | 取模 | ${5 % 2} | 1 |
逻辑运算符 | 说明 | 示例 | 结果 |
---|---|---|---|
== | 等于 | ${1 == 1} | true |
!= | 不等于 | ${1 != 1} | false |
< | 小于 | ${1 < 1} | false |
<= | 小于等于 | ${1 <=1 } | true |
> | 大于 | ${ 1>1 } | false |
>= | 大于等于 | ${ 1>=1 } | true |
关系运算符 | 说明 | 示例 | 结果 |
---|---|---|---|
&& | 与 | ${true && false} | false |
|| | 或 | ${true || false} | true |
! | 非 | ${! false} | true |
三元运算
${a < b ? "true" : "false"}
empty (比较对象是否为null;字符串是否为“ ”;集合长度是否为0)
${empty user}
${not empty user}
在EL表达式中,无需创建就可以使用的对象称为EL隐藏对象,在EL中一共有11个隐藏对象,分别是:
pageScope requestScope sessionScope applicationScope
header headerValues
param paramValues
pageContext
initParam
cookie
字符串
<%--定义字符串s,并将其放入pageContext域中--%>
<%
String s = "helloWorld";
pageContext.setAttribute("s"; s);
%>
<%--从域中获取s,第二种写法可在pageScope,requestScope sessionScope applicationScope查找,直到找到为止--%>
${pageScope.s}或者${s}
数组
<%
String[] arr = {"a","b","c","d"}
pageContext.setAttribute("arr"; arr);
%>
${arr}
${arr[0]}
集合
<%
List<String> list = new ArrayList<>();
list.put("a");
list.put("b");
pageContext.setAttribute("list"; list);
%>
${list}
${list[0]}
map
<%
Map<String, String> map = new HashMap<>();
map.put("a", "a");
map.put("b", "b");
map.put("c","c");
pageContext.setAttribute("map"; map);
%>
${map}
${map.a}
JSTL(Java server pages standarded tag library,即JSP标准标签库)是由[JCP](Java community Proces)所制定的标准规范,它主要提供给Java Web开发人员一个标准通用的标签库,并由Apache的Jakarta小组来维护。开发人员可以利用这些标签取代JSP页面上的Java代码,从而提高程序的可读性,降低程序的维护难度。
JSTL提供了5个子库:
标签库 | uri | 前缀 |
---|---|---|
core | http://java.sun.com/jsp/jstl/core | c |
i18n | http://java.sun.com/jsp/jstl/fmt | fmt |
sql | http://java.sun.com/jsp/jstl/sql | sql |
xml | http://java.sun.com/jsp/jstl/xml | x |
functions | http://java.sun.com/jsp/jstl/functions | fm |
若要在JSP中使用JSTL标签库,则需要引入相应的jar包,接下来以maven的方式引入
<dependency>
<groupId>jstlgroupId>
<artifactId>jstlartifactId>
<version>1.2version>
dependency>
<dependency>
<groupId>taglibsgroupId>
<artifactId>standardartifactId>
<version>1.1.2version>
dependency>
下面就尝试使用targlib指令导入标签库,例如导入核心标签库,其它也是类似。
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:if test="${salary > 2000}" var="flag" scope="session">
<p>我的工资为: <c:out value="${salary}"/><p>
</c:if>
<c:if test="${not flag}">
<p>我的工资为: <c:out value="${salary}"/><p>
</c:if>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<title>c:forEach 标签实例title>
head>
<body>
<%
String[] str={"1","2","3","4","5","6","7"};
request.setAttribute("str",str);
%>
<c:forEach items="${str}" var="s" begin="1" end="5">
<c:out value="${s}">c:out><br>
c:forEach>
body>
html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<title>c:choose 标签实例title>
head>
<body>
<c:set var="salary" scope="session" value="${2000*2}"/>
<p>你的工资为 : <c:out value="${salary}"/>p>
<c:choose>
<c:when test="${salary <= 0}">
太惨了。
c:when>
<c:when test="${salary > 1000}">
不错的薪水,还能生活。
c:when>
<c:otherwise>
什么都没有。
c:otherwise>
c:choose>
body>
html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<title>c:out 标签实例title>
head>
<body>
<h1><c:out> 实例h1>
<c:out value="<要显示的数据对象(未使用转义字符)>" escapeXml="true" default="默认值">c:out><br/>
<c:out value="<要显示的数据对象(使用转义字符)>" escapeXml="false" default="默认值">c:out><br/>
<c:out value="${null}" escapeXml="false">使用的表达式结果为null,则输出该默认值c:out><br/>
body>
html>